fio.1 - escape the escape character so it shows up
[fio.git] / iolog.c
CommitLineData
ac9b9101
JA
1/*
2 * Code related to writing an iolog of what a thread is doing, and to
3 * later read that back and replay
4 */
5#include <stdio.h>
6#include <stdlib.h>
7#include <libgen.h>
8#include <assert.h>
aee2ab67
JA
9#ifdef CONFIG_ZLIB
10#include <zlib.h>
11#endif
12
ac9b9101
JA
13#include "flist.h"
14#include "fio.h"
15#include "verify.h"
16#include "trim.h"
243bfe19 17#include "filelock.h"
aee2ab67 18#include "tp.h"
ac9b9101
JA
19
20static const char iolog_ver2[] = "fio version 2 iolog";
21
aee2ab67
JA
22#ifdef CONFIG_ZLIB
23
24struct iolog_compress {
25 struct flist_head list;
26 void *buf;
27 size_t len;
28 unsigned int seq;
29};
30
31#define GZ_CHUNK 131072
32
33static struct iolog_compress *get_new_chunk(unsigned int seq)
34{
35 struct iolog_compress *c;
36
37 c = malloc(sizeof(*c));
38 INIT_FLIST_HEAD(&c->list);
39 c->buf = malloc(GZ_CHUNK);
40 c->len = 0;
41 c->seq = seq;
42 return c;
43}
44
45static void free_chunk(struct iolog_compress *ic)
46{
47 free(ic->buf);
48 free(ic);
49}
50
51#endif
52
ac9b9101
JA
53void queue_io_piece(struct thread_data *td, struct io_piece *ipo)
54{
55 flist_add_tail(&ipo->list, &td->io_log_list);
56 td->total_io_size += ipo->len;
57}
58
59void log_io_u(struct thread_data *td, struct io_u *io_u)
60{
61 const char *act[] = { "read", "write", "sync", "datasync",
62 "sync_file_range", "wait", "trim" };
63
64 assert(io_u->ddir <= 6);
65
66 if (!td->o.write_iolog_file)
67 return;
68
69 fprintf(td->iolog_f, "%s %s %llu %lu\n", io_u->file->file_name,
70 act[io_u->ddir], io_u->offset,
71 io_u->buflen);
72}
73
74void log_file(struct thread_data *td, struct fio_file *f,
75 enum file_log_act what)
76{
77 const char *act[] = { "add", "open", "close" };
78
79 assert(what < 3);
80
81 if (!td->o.write_iolog_file)
82 return;
83
84
85 /*
86 * this happens on the pre-open/close done before the job starts
87 */
88 if (!td->iolog_f)
89 return;
90
91 fprintf(td->iolog_f, "%s %s\n", f->file_name, act[what]);
92}
93
94static void iolog_delay(struct thread_data *td, unsigned long delay)
95{
96 unsigned long usec = utime_since_now(&td->last_issue);
30b18672 97 unsigned long this_delay;
ac9b9101
JA
98
99 if (delay < usec)
100 return;
101
102 delay -= usec;
103
104 /*
105 * less than 100 usec delay, just regard it as noise
106 */
107 if (delay < 100)
108 return;
109
30b18672
JA
110 while (delay && !td->terminate) {
111 this_delay = delay;
112 if (this_delay > 500000)
113 this_delay = 500000;
114
115 usec_sleep(td, this_delay);
116 delay -= this_delay;
117 }
ac9b9101
JA
118}
119
120static int ipo_special(struct thread_data *td, struct io_piece *ipo)
121{
122 struct fio_file *f;
123 int ret;
124
125 /*
126 * Not a special ipo
127 */
128 if (ipo->ddir != DDIR_INVAL)
129 return 0;
130
131 f = td->files[ipo->fileno];
132
133 switch (ipo->file_action) {
134 case FIO_LOG_OPEN_FILE:
135 ret = td_io_open_file(td, f);
136 if (!ret)
137 break;
138 td_verror(td, ret, "iolog open file");
139 return -1;
140 case FIO_LOG_CLOSE_FILE:
141 td_io_close_file(td, f);
142 break;
143 case FIO_LOG_UNLINK_FILE:
144 unlink(f->file_name);
145 break;
146 default:
147 log_err("fio: bad file action %d\n", ipo->file_action);
148 break;
149 }
150
151 return 1;
152}
153
154int read_iolog_get(struct thread_data *td, struct io_u *io_u)
155{
156 struct io_piece *ipo;
157 unsigned long elapsed;
3c3ed070 158
ac9b9101
JA
159 while (!flist_empty(&td->io_log_list)) {
160 int ret;
161
162 ipo = flist_entry(td->io_log_list.next, struct io_piece, list);
163 flist_del(&ipo->list);
164 remove_trim_entry(td, ipo);
165
166 ret = ipo_special(td, ipo);
167 if (ret < 0) {
168 free(ipo);
169 break;
170 } else if (ret > 0) {
171 free(ipo);
172 continue;
173 }
174
175 io_u->ddir = ipo->ddir;
176 if (ipo->ddir != DDIR_WAIT) {
177 io_u->offset = ipo->offset;
178 io_u->buflen = ipo->len;
179 io_u->file = td->files[ipo->fileno];
180 get_file(io_u->file);
181 dprint(FD_IO, "iolog: get %llu/%lu/%s\n", io_u->offset,
182 io_u->buflen, io_u->file->file_name);
183 if (ipo->delay)
184 iolog_delay(td, ipo->delay);
185 } else {
186 elapsed = mtime_since_genesis();
187 if (ipo->delay > elapsed)
188 usec_sleep(td, (ipo->delay - elapsed) * 1000);
ac9b9101
JA
189 }
190
191 free(ipo);
3c3ed070 192
ac9b9101
JA
193 if (io_u->ddir != DDIR_WAIT)
194 return 0;
195 }
196
197 td->done = 1;
198 return 1;
199}
200
201void prune_io_piece_log(struct thread_data *td)
202{
203 struct io_piece *ipo;
204 struct rb_node *n;
205
206 while ((n = rb_first(&td->io_hist_tree)) != NULL) {
207 ipo = rb_entry(n, struct io_piece, rb_node);
208 rb_erase(n, &td->io_hist_tree);
209 remove_trim_entry(td, ipo);
210 td->io_hist_len--;
211 free(ipo);
212 }
213
214 while (!flist_empty(&td->io_hist_list)) {
215 ipo = flist_entry(td->io_hist_list.next, struct io_piece, list);
216 flist_del(&ipo->list);
217 remove_trim_entry(td, ipo);
218 td->io_hist_len--;
219 free(ipo);
220 }
221}
222
223/*
224 * log a successful write, so we can unwind the log for verify
225 */
226void log_io_piece(struct thread_data *td, struct io_u *io_u)
227{
228 struct rb_node **p, *parent;
229 struct io_piece *ipo, *__ipo;
230
231 ipo = malloc(sizeof(struct io_piece));
232 init_ipo(ipo);
233 ipo->file = io_u->file;
234 ipo->offset = io_u->offset;
235 ipo->len = io_u->buflen;
da0a7bd2 236 ipo->numberio = io_u->numberio;
f9401285
JA
237 ipo->flags = IP_F_IN_FLIGHT;
238
239 io_u->ipo = ipo;
ac9b9101
JA
240
241 if (io_u_should_trim(td, io_u)) {
242 flist_add_tail(&ipo->trim_list, &td->trim_list);
243 td->trim_entries++;
244 }
245
246 /*
247 * We don't need to sort the entries, if:
248 *
249 * Sequential writes, or
250 * Random writes that lay out the file as it goes along
251 *
252 * For both these cases, just reading back data in the order we
253 * wrote it out is the fastest.
254 *
255 * One exception is if we don't have a random map AND we are doing
256 * verifies, in that case we need to check for duplicate blocks and
257 * drop the old one, which we rely on the rb insert/lookup for
258 * handling.
259 */
c4b6117b 260 if (((!td->o.verifysort) || !td_random(td) || !td->o.overwrite) &&
ac9b9101
JA
261 (file_randommap(td, ipo->file) || td->o.verify == VERIFY_NONE)) {
262 INIT_FLIST_HEAD(&ipo->list);
263 flist_add_tail(&ipo->list, &td->io_hist_list);
264 ipo->flags |= IP_F_ONLIST;
265 td->io_hist_len++;
266 return;
267 }
268
269 RB_CLEAR_NODE(&ipo->rb_node);
270
271 /*
272 * Sort the entry into the verification list
273 */
274restart:
275 p = &td->io_hist_tree.rb_node;
276 parent = NULL;
277 while (*p) {
278 parent = *p;
279
280 __ipo = rb_entry(parent, struct io_piece, rb_node);
281 if (ipo->file < __ipo->file)
282 p = &(*p)->rb_left;
283 else if (ipo->file > __ipo->file)
284 p = &(*p)->rb_right;
285 else if (ipo->offset < __ipo->offset)
286 p = &(*p)->rb_left;
287 else if (ipo->offset > __ipo->offset)
288 p = &(*p)->rb_right;
289 else {
885ac623
JA
290 dprint(FD_IO, "iolog: overlap %llu/%lu, %llu/%lu",
291 __ipo->offset, __ipo->len,
292 ipo->offset, ipo->len);
ac9b9101
JA
293 td->io_hist_len--;
294 rb_erase(parent, &td->io_hist_tree);
295 remove_trim_entry(td, __ipo);
296 free(__ipo);
297 goto restart;
298 }
299 }
300
301 rb_link_node(&ipo->rb_node, parent, p);
302 rb_insert_color(&ipo->rb_node, &td->io_hist_tree);
303 ipo->flags |= IP_F_ONRB;
304 td->io_hist_len++;
305}
306
890b6656
JA
307void unlog_io_piece(struct thread_data *td, struct io_u *io_u)
308{
309 struct io_piece *ipo = io_u->ipo;
310
311 if (!ipo)
312 return;
313
314 if (ipo->flags & IP_F_ONRB)
315 rb_erase(&ipo->rb_node, &td->io_hist_tree);
316 else if (ipo->flags & IP_F_ONLIST)
317 flist_del(&ipo->list);
318
319 free(ipo);
320 io_u->ipo = NULL;
321 td->io_hist_len--;
322}
323
324void trim_io_piece(struct thread_data *td, struct io_u *io_u)
325{
326 struct io_piece *ipo = io_u->ipo;
327
328 if (!ipo)
329 return;
330
331 ipo->len = io_u->xfer_buflen - io_u->resid;
332}
333
ac9b9101
JA
334void write_iolog_close(struct thread_data *td)
335{
336 fflush(td->iolog_f);
337 fclose(td->iolog_f);
338 free(td->iolog_buf);
339 td->iolog_f = NULL;
340 td->iolog_buf = NULL;
341}
342
343/*
344 * Read version 2 iolog data. It is enhanced to include per-file logging,
345 * syncs, etc.
346 */
347static int read_iolog2(struct thread_data *td, FILE *f)
348{
349 unsigned long long offset;
350 unsigned int bytes;
351 int reads, writes, waits, fileno = 0, file_action = 0; /* stupid gcc */
352 char *fname, *act;
353 char *str, *p;
354 enum fio_ddir rw;
355
356 free_release_files(td);
357
358 /*
359 * Read in the read iolog and store it, reuse the infrastructure
360 * for doing verifications.
361 */
362 str = malloc(4096);
363 fname = malloc(256+16);
364 act = malloc(256+16);
365
366 reads = writes = waits = 0;
367 while ((p = fgets(str, 4096, f)) != NULL) {
368 struct io_piece *ipo;
369 int r;
370
371 r = sscanf(p, "%256s %256s %llu %u", fname, act, &offset,
372 &bytes);
373 if (r == 4) {
374 /*
375 * Check action first
376 */
377 if (!strcmp(act, "wait"))
378 rw = DDIR_WAIT;
379 else if (!strcmp(act, "read"))
380 rw = DDIR_READ;
381 else if (!strcmp(act, "write"))
382 rw = DDIR_WRITE;
383 else if (!strcmp(act, "sync"))
384 rw = DDIR_SYNC;
385 else if (!strcmp(act, "datasync"))
386 rw = DDIR_DATASYNC;
387 else if (!strcmp(act, "trim"))
388 rw = DDIR_TRIM;
389 else {
390 log_err("fio: bad iolog file action: %s\n",
391 act);
392 continue;
393 }
033ace1e 394 fileno = get_fileno(td, fname);
ac9b9101
JA
395 } else if (r == 2) {
396 rw = DDIR_INVAL;
397 if (!strcmp(act, "add")) {
5903e7b7 398 fileno = add_file(td, fname, 0, 1);
ac9b9101
JA
399 file_action = FIO_LOG_ADD_FILE;
400 continue;
401 } else if (!strcmp(act, "open")) {
402 fileno = get_fileno(td, fname);
403 file_action = FIO_LOG_OPEN_FILE;
404 } else if (!strcmp(act, "close")) {
405 fileno = get_fileno(td, fname);
406 file_action = FIO_LOG_CLOSE_FILE;
407 } else {
408 log_err("fio: bad iolog file action: %s\n",
409 act);
410 continue;
411 }
412 } else {
413 log_err("bad iolog2: %s", p);
414 continue;
415 }
416
417 if (rw == DDIR_READ)
418 reads++;
419 else if (rw == DDIR_WRITE) {
420 /*
421 * Don't add a write for ro mode
422 */
423 if (read_only)
424 continue;
425 writes++;
426 } else if (rw == DDIR_WAIT) {
427 waits++;
428 } else if (rw == DDIR_INVAL) {
429 } else if (!ddir_sync(rw)) {
430 log_err("bad ddir: %d\n", rw);
431 continue;
432 }
433
434 /*
435 * Make note of file
436 */
437 ipo = malloc(sizeof(*ipo));
438 init_ipo(ipo);
439 ipo->ddir = rw;
440 if (rw == DDIR_WAIT) {
441 ipo->delay = offset;
442 } else {
443 ipo->offset = offset;
444 ipo->len = bytes;
42793d94 445 if (rw != DDIR_INVAL && bytes > td->o.max_bs[rw])
ac9b9101
JA
446 td->o.max_bs[rw] = bytes;
447 ipo->fileno = fileno;
448 ipo->file_action = file_action;
70afff59 449 td->o.size += bytes;
ac9b9101 450 }
3c3ed070 451
ac9b9101
JA
452 queue_io_piece(td, ipo);
453 }
454
455 free(str);
456 free(act);
457 free(fname);
458
459 if (writes && read_only) {
460 log_err("fio: <%s> skips replay of %d writes due to"
461 " read-only\n", td->o.name, writes);
462 writes = 0;
463 }
464
465 if (!reads && !writes && !waits)
466 return 1;
467 else if (reads && !writes)
468 td->o.td_ddir = TD_DDIR_READ;
469 else if (!reads && writes)
470 td->o.td_ddir = TD_DDIR_WRITE;
471 else
472 td->o.td_ddir = TD_DDIR_RW;
473
474 return 0;
475}
476
477/*
478 * open iolog, check version, and call appropriate parser
479 */
480static int init_iolog_read(struct thread_data *td)
481{
482 char buffer[256], *p;
483 FILE *f;
484 int ret;
485
486 f = fopen(td->o.read_iolog_file, "r");
487 if (!f) {
488 perror("fopen read iolog");
489 return 1;
490 }
491
492 p = fgets(buffer, sizeof(buffer), f);
493 if (!p) {
494 td_verror(td, errno, "iolog read");
495 log_err("fio: unable to read iolog\n");
496 fclose(f);
497 return 1;
498 }
499
500 /*
501 * version 2 of the iolog stores a specific string as the
502 * first line, check for that
503 */
504 if (!strncmp(iolog_ver2, buffer, strlen(iolog_ver2)))
505 ret = read_iolog2(td, f);
506 else {
507 log_err("fio: iolog version 1 is no longer supported\n");
508 ret = 1;
509 }
510
511 fclose(f);
512 return ret;
513}
514
515/*
516 * Set up a log for storing io patterns.
517 */
518static int init_iolog_write(struct thread_data *td)
519{
520 struct fio_file *ff;
521 FILE *f;
522 unsigned int i;
523
524 f = fopen(td->o.write_iolog_file, "a");
525 if (!f) {
526 perror("fopen write iolog");
527 return 1;
528 }
529
530 /*
531 * That's it for writing, setup a log buffer and we're done.
532 */
533 td->iolog_f = f;
534 td->iolog_buf = malloc(8192);
535 setvbuf(f, td->iolog_buf, _IOFBF, 8192);
536
537 /*
538 * write our version line
539 */
540 if (fprintf(f, "%s\n", iolog_ver2) < 0) {
541 perror("iolog init\n");
542 return 1;
543 }
544
545 /*
546 * add all known files
547 */
548 for_each_file(td, ff, i)
549 log_file(td, ff, FIO_LOG_ADD_FILE);
550
551 return 0;
552}
553
554int init_iolog(struct thread_data *td)
555{
556 int ret = 0;
557
558 if (td->o.read_iolog_file) {
d95b34a6
JA
559 int need_swap;
560
ac9b9101
JA
561 /*
562 * Check if it's a blktrace file and load that if possible.
563 * Otherwise assume it's a normal log file and load that.
564 */
d95b34a6
JA
565 if (is_blktrace(td->o.read_iolog_file, &need_swap))
566 ret = load_blktrace(td, td->o.read_iolog_file, need_swap);
ac9b9101
JA
567 else
568 ret = init_iolog_read(td);
569 } else if (td->o.write_iolog_file)
570 ret = init_iolog_write(td);
571
f01b34ae
JA
572 if (ret)
573 td_verror(td, EINVAL, "failed initializing iolog");
574
ac9b9101
JA
575 return ret;
576}
577
aee2ab67
JA
578void setup_log(struct io_log **log, struct log_params *p,
579 const char *filename)
ac9b9101
JA
580{
581 struct io_log *l = malloc(sizeof(*l));
582
b8bc8cba 583 memset(l, 0, sizeof(*l));
ac9b9101
JA
584 l->nr_samples = 0;
585 l->max_samples = 1024;
aee2ab67
JA
586 l->log_type = p->log_type;
587 l->log_offset = p->log_offset;
588 l->log_gz = p->log_gz;
ae588852 589 l->log = malloc(l->max_samples * log_entry_sz(l));
aee2ab67 590 l->avg_msec = p->avg_msec;
cb7e0ace 591 l->filename = strdup(filename);
aee2ab67
JA
592 l->td = p->td;
593
594 INIT_FLIST_HEAD(&l->chunk_list);
595
596 if (l->log_gz && !p->td)
597 l->log_gz = 0;
598 else if (l->log_gz) {
599 pthread_mutex_init(&l->chunk_lock, NULL);
600 p->td->flags |= TD_F_COMPRESS_LOG;
601 }
602
ac9b9101
JA
603 *log = l;
604}
605
2e802282
JA
606#ifdef CONFIG_SETVBUF
607static void *set_file_buffer(FILE *f)
608{
609 size_t size = 1048576;
610 void *buf;
611
612 buf = malloc(size);
613 setvbuf(f, buf, _IOFBF, size);
614 return buf;
615}
616
617static void clear_file_buffer(void *buf)
618{
619 free(buf);
620}
621#else
622static void *set_file_buffer(FILE *f)
623{
624 return NULL;
625}
626
627static void clear_file_buffer(void *buf)
628{
629}
630#endif
631
518dac09 632void free_log(struct io_log *log)
cb7e0ace
JA
633{
634 free(log->log);
635 free(log->filename);
636 free(log);
637}
638
aee2ab67
JA
639static void flush_samples(FILE *f, void *samples, uint64_t nr_samples,
640 int log_offset)
ac9b9101 641{
ae588852 642 uint64_t i;
ac9b9101 643
aee2ab67
JA
644 for (i = 0; i < nr_samples; i++) {
645 struct io_sample *s = __get_sample(samples, log_offset, i);
ac9b9101 646
aee2ab67 647 if (!log_offset) {
ae588852
JA
648 fprintf(f, "%lu, %lu, %u, %u\n",
649 (unsigned long) s->time,
650 (unsigned long) s->val,
651 s->ddir, s->bs);
652 } else {
653 struct io_sample_offset *so = (void *) s;
654
655 fprintf(f, "%lu, %lu, %u, %u, %llu\n",
656 (unsigned long) s->time,
657 (unsigned long) s->val,
658 s->ddir, s->bs,
659 (unsigned long long) so->offset);
660 }
ac9b9101 661 }
aee2ab67
JA
662}
663
664#ifdef CONFIG_ZLIB
665static int z_stream_init(z_stream *stream)
666{
667 stream->zalloc = Z_NULL;
668 stream->zfree = Z_NULL;
669 stream->opaque = Z_NULL;
670 stream->next_in = Z_NULL;
671
672 if (inflateInit(stream) != Z_OK)
673 return 1;
674
675 return 0;
676}
677
678struct flush_chunk_iter {
679 unsigned int seq;
680 void *buf;
681 size_t buf_size;
682 size_t buf_used;
683 size_t chunk_sz;
684};
685
686static void finish_chunk(z_stream *stream, int log_offset, FILE *f,
687 struct flush_chunk_iter *iter)
688{
689 uint64_t nr_samples;
690 int ret;
691
692 ret = inflateEnd(stream);
693 if (ret != Z_OK)
694 log_err("fio: failed to end log inflation (%d)\n", ret);
695
696 nr_samples = iter->buf_used / __log_entry_sz(log_offset);
697 flush_samples(f, iter->buf, nr_samples, log_offset);
698 free(iter->buf);
699 iter->buf = NULL;
700 iter->buf_size = iter->buf_used = 0;
701}
702
703static int flush_chunk(struct iolog_compress *ic, int log_offset, FILE *f,
704 z_stream *stream, struct flush_chunk_iter *iter)
705{
706 if (ic->seq != iter->seq) {
707 if (iter->seq)
708 finish_chunk(stream, log_offset, f, iter);
709
710 z_stream_init(stream);
711 iter->seq = ic->seq;
712 }
713
714 stream->avail_in = ic->len;
715 stream->next_in = ic->buf;
716
717 if (!iter->buf_size) {
718 iter->buf_size = iter->chunk_sz;
719 iter->buf = malloc(iter->buf_size);
720 }
721
722 while (stream->avail_in) {
723 int err;
724
725 stream->avail_out = iter->buf_size - iter->buf_used;
726 stream->next_out = iter->buf + iter->buf_used;
727
728 err = inflate(stream, Z_NO_FLUSH);
729 if (err < 0) {
730 log_err("fio: failed inflating log: %d\n", err);
731 break;
732 }
733
734 iter->buf_used += iter->buf_size - iter->buf_used - stream->avail_out;
735 }
736
737 free_chunk(ic);
738 return 0;
739}
740
741static void flush_gz_chunks(struct io_log *log, FILE *f)
742{
743 struct flush_chunk_iter iter = { .chunk_sz = log->log_gz, };
744 struct flist_head *node;
745 z_stream stream;
746
747 while (!flist_empty(&log->chunk_list)) {
748 struct iolog_compress *ic;
749
750 node = log->chunk_list.next;
751 ic = flist_entry(node, struct iolog_compress, list);
752 flist_del(&ic->list);
753 flush_chunk(ic, log->log_offset, f, &stream, &iter);
754 }
755
756 if (iter.seq) {
757 finish_chunk(&stream, log->log_offset, f, &iter);
758 free(iter.buf);
759 }
760}
761
762#else
763
764static void flush_gz_chunks(struct io_log *log, FILE *f)
765{
766}
767
768#endif
769
770void flush_log(struct io_log *log)
771{
772 void *buf;
773 FILE *f;
774
775 f = fopen(log->filename, "w");
776 if (!f) {
777 perror("fopen log");
778 return;
779 }
780
781 buf = set_file_buffer(f);
782
783 flush_gz_chunks(log, f);
784
785 flush_samples(f, log->log, log->nr_samples, log->log_offset);
ac9b9101
JA
786
787 fclose(f);
2e802282 788 clear_file_buffer(buf);
ac9b9101
JA
789}
790
cb7e0ace 791static int finish_log(struct thread_data *td, struct io_log *log, int trylock)
ac9b9101 792{
aee2ab67
JA
793 if (td->tp_data)
794 iolog_flush(log, 1);
795
243bfe19 796 if (trylock) {
cb7e0ace 797 if (fio_trylock_file(log->filename))
243bfe19
JA
798 return 1;
799 } else
cb7e0ace 800 fio_lock_file(log->filename);
243bfe19 801
aee2ab67 802 if (td->client_type == FIO_CLIENT_TYPE_GUI)
cb7e0ace 803 fio_send_iolog(td, log, log->filename);
aee2ab67
JA
804 else
805 flush_log(log);
243bfe19 806
cb7e0ace 807 fio_unlock_file(log->filename);
518dac09 808 free_log(log);
243bfe19 809 return 0;
ac9b9101
JA
810}
811
aee2ab67
JA
812#ifdef CONFIG_ZLIB
813
814struct iolog_flush_data {
815 struct tp_work work;
816 struct io_log *log;
817 void *samples;
818 uint64_t nr_samples;
819};
820
821static int gz_work(struct tp_work *work)
822{
823 struct iolog_flush_data *data;
824 struct iolog_compress *c;
825 struct flist_head list;
826 unsigned int seq;
827 z_stream stream;
828 size_t total = 0;
829 int ret;
830
831 INIT_FLIST_HEAD(&list);
832
833 data = container_of(work, struct iolog_flush_data, work);
834
835 stream.zalloc = Z_NULL;
836 stream.zfree = Z_NULL;
837 stream.opaque = Z_NULL;
838
839 if (deflateInit(&stream, Z_DEFAULT_COMPRESSION) != Z_OK) {
840 log_err("fio: failed to init gz stream\n");
841 return 0;
842 }
843
844 seq = ++data->log->chunk_seq;
845 stream.next_in = (void *) data->samples;
846 stream.avail_in = data->nr_samples * log_entry_sz(data->log);
847
848 do {
849 c = get_new_chunk(seq);
850 stream.avail_out = GZ_CHUNK;
851 stream.next_out = c->buf;
852 ret = deflate(&stream, Z_NO_FLUSH);
853 if (ret < 0) {
854 log_err("fio: deflate log (%d)\n", ret);
855 break;
856 }
857
858 c->len = GZ_CHUNK - stream.avail_out;
859 flist_add_tail(&c->list, &list);
860 total += c->len;
861 } while (stream.avail_in);
862
863 stream.next_out = c->buf + c->len;
864 stream.avail_out = GZ_CHUNK - c->len;
865
866 ret = deflate(&stream, Z_FINISH);
867 if (ret == Z_STREAM_END)
868 c->len = GZ_CHUNK - stream.avail_out;
869 else {
870 do {
871 c = get_new_chunk(seq);
872 stream.avail_out = GZ_CHUNK;
873 stream.next_out = c->buf;
874 ret = deflate(&stream, Z_FINISH);
875 c->len = GZ_CHUNK - stream.avail_out;
876 flist_add_tail(&c->list, &list);
877 } while (ret != Z_STREAM_END);
878 }
879
880 ret = deflateEnd(&stream);
881 if (ret != Z_OK)
882 log_err("fio: deflateEnd %d\n", ret);
883
884 free(data->samples);
885
886 if (!flist_empty(&list)) {
887 pthread_mutex_lock(&data->log->chunk_lock);
888 flist_splice_tail(&list, &data->log->chunk_list);
889 pthread_mutex_unlock(&data->log->chunk_lock);
890 }
891
892 if (work->wait) {
893 work->done = 1;
894 pthread_cond_signal(&work->cv);
895 } else
896 free(data);
897
898 return 0;
899}
900
901int iolog_flush(struct io_log *log, int wait)
902{
903 struct thread_data *td = log->td;
904 struct iolog_flush_data *data;
905 size_t sample_size;
906
907 data = malloc(sizeof(*data));
908 if (!data)
909 return 1;
910
911 data->log = log;
912
913 sample_size = log->nr_samples * log_entry_sz(log);
914 data->samples = malloc(sample_size);
915 if (!data->samples) {
916 free(data);
917 return 1;
918 }
919
920 memcpy(data->samples, log->log, sample_size);
921 data->nr_samples = log->nr_samples;
922 data->work.fn = gz_work;
923 log->nr_samples = 0;
924
925 if (wait) {
926 pthread_mutex_init(&data->work.lock, NULL);
927 pthread_cond_init(&data->work.cv, NULL);
928 data->work.wait = 1;
929 } else
930 data->work.wait = 0;
931
932 tp_queue_work(td->tp_data, &data->work);
933
934 if (wait) {
935 pthread_mutex_lock(&data->work.lock);
936 while (!data->work.done)
937 pthread_cond_wait(&data->work.cv, &data->work.lock);
938 pthread_mutex_unlock(&data->work.lock);
939 free(data);
940 }
941
942 return 0;
943}
944
945#else
946
947int iolog_flush(struct io_log *log, int wait)
948{
949 return 1;
950}
951
952#endif
953
cb7e0ace 954static int write_iops_log(struct thread_data *td, int try)
905e3d4f 955{
cb7e0ace 956 struct io_log *log = td->iops_log;
905e3d4f
JA
957
958 if (!log)
959 return 0;
960
cb7e0ace 961 return finish_log(td, log, try);
905e3d4f
JA
962}
963
964static int write_slat_log(struct thread_data *td, int try)
965{
cb7e0ace 966 struct io_log *log = td->slat_log;
905e3d4f 967
cb7e0ace
JA
968 if (!log)
969 return 0;
970
971 return finish_log(td, log, try);
905e3d4f
JA
972}
973
974static int write_clat_log(struct thread_data *td, int try)
975{
cb7e0ace 976 struct io_log *log = td->clat_log;
905e3d4f 977
cb7e0ace
JA
978 if (!log)
979 return 0;
980
981 return finish_log(td, log, try);
905e3d4f
JA
982}
983
984static int write_lat_log(struct thread_data *td, int try)
985{
cb7e0ace
JA
986 struct io_log *log = td->lat_log;
987
988 if (!log)
989 return 0;
905e3d4f 990
cb7e0ace 991 return finish_log(td, log, try);
905e3d4f
JA
992}
993
994static int write_bandw_log(struct thread_data *td, int try)
995{
cb7e0ace
JA
996 struct io_log *log = td->bw_log;
997
998 if (!log)
999 return 0;
905e3d4f 1000
cb7e0ace 1001 return finish_log(td, log, try);
905e3d4f
JA
1002}
1003
1004enum {
1005 BW_LOG_MASK = 1,
1006 LAT_LOG_MASK = 2,
1007 SLAT_LOG_MASK = 4,
1008 CLAT_LOG_MASK = 8,
1009 IOPS_LOG_MASK = 16,
1010
905e3d4f
JA
1011 ALL_LOG_NR = 5,
1012};
1013
1014struct log_type {
1015 unsigned int mask;
1016 int (*fn)(struct thread_data *, int);
1017};
1018
1019static struct log_type log_types[] = {
1020 {
1021 .mask = BW_LOG_MASK,
1022 .fn = write_bandw_log,
1023 },
1024 {
1025 .mask = LAT_LOG_MASK,
1026 .fn = write_lat_log,
1027 },
1028 {
1029 .mask = SLAT_LOG_MASK,
1030 .fn = write_slat_log,
1031 },
1032 {
1033 .mask = CLAT_LOG_MASK,
1034 .fn = write_clat_log,
1035 },
1036 {
1037 .mask = IOPS_LOG_MASK,
1038 .fn = write_iops_log,
1039 },
1040};
1041
1042void fio_writeout_logs(struct thread_data *td)
1043{
ea5409f9 1044 unsigned int log_mask = 0;
905e3d4f
JA
1045 unsigned int log_left = ALL_LOG_NR;
1046 int old_state, i;
1047
1048 old_state = td_bump_runstate(td, TD_FINISHING);
1049
1050 finalize_logs(td);
1051
1052 while (log_left) {
1053 int prev_log_left = log_left;
1054
1055 for (i = 0; i < ALL_LOG_NR && log_left; i++) {
1056 struct log_type *lt = &log_types[i];
1057 int ret;
1058
ea5409f9 1059 if (!(log_mask & lt->mask)) {
905e3d4f
JA
1060 ret = lt->fn(td, log_left != 1);
1061 if (!ret) {
1062 log_left--;
ea5409f9 1063 log_mask |= lt->mask;
905e3d4f
JA
1064 }
1065 }
1066 }
1067
1068 if (prev_log_left == log_left)
1069 usleep(5000);
1070 }
1071
1072 td_restore_runstate(td, old_state);
1073}