fio.1 - escape the escape character so it shows up
[fio.git] / iolog.c
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>
9 #ifdef CONFIG_ZLIB
10 #include <zlib.h>
11 #endif
12
13 #include "flist.h"
14 #include "fio.h"
15 #include "verify.h"
16 #include "trim.h"
17 #include "filelock.h"
18 #include "tp.h"
19
20 static const char iolog_ver2[] = "fio version 2 iolog";
21
22 #ifdef CONFIG_ZLIB
23
24 struct 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
33 static 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
45 static void free_chunk(struct iolog_compress *ic)
46 {
47         free(ic->buf);
48         free(ic);
49 }
50
51 #endif
52
53 void 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
59 void 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
74 void 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
94 static void iolog_delay(struct thread_data *td, unsigned long delay)
95 {
96         unsigned long usec = utime_since_now(&td->last_issue);
97         unsigned long this_delay;
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
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         }
118 }
119
120 static 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
154 int read_iolog_get(struct thread_data *td, struct io_u *io_u)
155 {
156         struct io_piece *ipo;
157         unsigned long elapsed;
158
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);
189                 }
190
191                 free(ipo);
192
193                 if (io_u->ddir != DDIR_WAIT)
194                         return 0;
195         }
196
197         td->done = 1;
198         return 1;
199 }
200
201 void 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  */
226 void 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;
236         ipo->numberio = io_u->numberio;
237         ipo->flags = IP_F_IN_FLIGHT;
238
239         io_u->ipo = ipo;
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          */
260         if (((!td->o.verifysort) || !td_random(td) || !td->o.overwrite) &&
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          */
274 restart:
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 {
290                         dprint(FD_IO, "iolog: overlap %llu/%lu, %llu/%lu",
291                                 __ipo->offset, __ipo->len,
292                                 ipo->offset, ipo->len);
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
307 void 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
324 void 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
334 void 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  */
347 static 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                         }
394                         fileno = get_fileno(td, fname);
395                 } else if (r == 2) {
396                         rw = DDIR_INVAL;
397                         if (!strcmp(act, "add")) {
398                                 fileno = add_file(td, fname, 0, 1);
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;
445                         if (rw != DDIR_INVAL && bytes > td->o.max_bs[rw])
446                                 td->o.max_bs[rw] = bytes;
447                         ipo->fileno = fileno;
448                         ipo->file_action = file_action;
449                         td->o.size += bytes;
450                 }
451
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  */
480 static 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  */
518 static 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
554 int init_iolog(struct thread_data *td)
555 {
556         int ret = 0;
557
558         if (td->o.read_iolog_file) {
559                 int need_swap;
560
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                  */
565                 if (is_blktrace(td->o.read_iolog_file, &need_swap))
566                         ret = load_blktrace(td, td->o.read_iolog_file, need_swap);
567                 else
568                         ret = init_iolog_read(td);
569         } else if (td->o.write_iolog_file)
570                 ret = init_iolog_write(td);
571
572         if (ret)
573                 td_verror(td, EINVAL, "failed initializing iolog");
574
575         return ret;
576 }
577
578 void setup_log(struct io_log **log, struct log_params *p,
579                const char *filename)
580 {
581         struct io_log *l = malloc(sizeof(*l));
582
583         memset(l, 0, sizeof(*l));
584         l->nr_samples = 0;
585         l->max_samples = 1024;
586         l->log_type = p->log_type;
587         l->log_offset = p->log_offset;
588         l->log_gz = p->log_gz;
589         l->log = malloc(l->max_samples * log_entry_sz(l));
590         l->avg_msec = p->avg_msec;
591         l->filename = strdup(filename);
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
603         *log = l;
604 }
605
606 #ifdef CONFIG_SETVBUF
607 static 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
617 static void clear_file_buffer(void *buf)
618 {
619         free(buf);
620 }
621 #else
622 static void *set_file_buffer(FILE *f)
623 {
624         return NULL;
625 }
626
627 static void clear_file_buffer(void *buf)
628 {
629 }
630 #endif
631
632 void free_log(struct io_log *log)
633 {
634         free(log->log);
635         free(log->filename);
636         free(log);
637 }
638
639 static void flush_samples(FILE *f, void *samples, uint64_t nr_samples,
640                           int log_offset)
641 {
642         uint64_t i;
643
644         for (i = 0; i < nr_samples; i++) {
645                 struct io_sample *s = __get_sample(samples, log_offset, i);
646
647                 if (!log_offset) {
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                 }
661         }
662 }
663
664 #ifdef CONFIG_ZLIB
665 static 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
678 struct 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
686 static 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
703 static 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
741 static 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
764 static void flush_gz_chunks(struct io_log *log, FILE *f)
765 {
766 }
767
768 #endif
769
770 void 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);
786
787         fclose(f);
788         clear_file_buffer(buf);
789 }
790
791 static int finish_log(struct thread_data *td, struct io_log *log, int trylock)
792 {
793         if (td->tp_data)
794                 iolog_flush(log, 1);
795
796         if (trylock) {
797                 if (fio_trylock_file(log->filename))
798                         return 1;
799         } else
800                 fio_lock_file(log->filename);
801
802         if (td->client_type == FIO_CLIENT_TYPE_GUI)
803                 fio_send_iolog(td, log, log->filename);
804         else
805                 flush_log(log);
806
807         fio_unlock_file(log->filename);
808         free_log(log);
809         return 0;
810 }
811
812 #ifdef CONFIG_ZLIB
813
814 struct iolog_flush_data {
815         struct tp_work work;
816         struct io_log *log;
817         void *samples;
818         uint64_t nr_samples;
819 };
820
821 static 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
901 int 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
947 int iolog_flush(struct io_log *log, int wait)
948 {
949         return 1;
950 }
951
952 #endif
953
954 static int write_iops_log(struct thread_data *td, int try)
955 {
956         struct io_log *log = td->iops_log;
957
958         if (!log)
959                 return 0;
960
961         return finish_log(td, log, try);
962 }
963
964 static int write_slat_log(struct thread_data *td, int try)
965 {
966         struct io_log *log = td->slat_log;
967
968         if (!log)
969                 return 0;
970
971         return finish_log(td, log, try);
972 }
973
974 static int write_clat_log(struct thread_data *td, int try)
975 {
976         struct io_log *log = td->clat_log;
977
978         if (!log)
979                 return 0;
980
981         return finish_log(td, log, try);
982 }
983
984 static int write_lat_log(struct thread_data *td, int try)
985 {
986         struct io_log *log = td->lat_log;
987
988         if (!log)
989                 return 0;
990
991         return finish_log(td, log, try);
992 }
993
994 static int write_bandw_log(struct thread_data *td, int try)
995 {
996         struct io_log *log = td->bw_log;
997
998         if (!log)
999                 return 0;
1000
1001         return finish_log(td, log, try);
1002 }
1003
1004 enum {
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
1011         ALL_LOG_NR      = 5,
1012 };
1013
1014 struct log_type {
1015         unsigned int mask;
1016         int (*fn)(struct thread_data *, int);
1017 };
1018
1019 static 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
1042 void fio_writeout_logs(struct thread_data *td)
1043 {
1044         unsigned int log_mask = 0;
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
1059                         if (!(log_mask & lt->mask)) {
1060                                 ret = lt->fn(td, log_left != 1);
1061                                 if (!ret) {
1062                                         log_left--;
1063                                         log_mask |= lt->mask;
1064                                 }
1065                         }
1066                 }
1067
1068                 if (prev_log_left == log_left)
1069                         usleep(5000);
1070         }
1071
1072         td_restore_runstate(td, old_state);
1073 }