Merge branch 'master' of https://github.com/celestinechen/fio
[fio.git] / iolog.c
diff --git a/iolog.c b/iolog.c
index 51aecd4325e31e62e83dfff629331b376fda3659..96af4f33e186dd4ec1a02b851a1c7ae4c0b1eaeb 100644 (file)
--- a/iolog.c
+++ b/iolog.c
@@ -47,10 +47,10 @@ void log_io_u(const struct thread_data *td, const struct io_u *io_u)
                return;
 
        fio_gettime(&now, NULL);
-       fprintf(td->iolog_f, "%lu %s %s %llu %llu\n", utime_since_now(&td->io_log_start_time),
-                                               io_u->file->file_name,
-                                               io_ddir_name(io_u->ddir),
-                                               io_u->offset, io_u->buflen);
+       fprintf(td->iolog_f, "%llu %s %s %llu %llu\n",
+               (unsigned long long) utime_since_now(&td->io_log_start_time),
+               io_u->file->file_name, io_ddir_name(io_u->ddir), io_u->offset,
+               io_u->buflen);
 
 }
 
@@ -73,16 +73,17 @@ void log_file(struct thread_data *td, struct fio_file *f,
                return;
 
        fio_gettime(&now, NULL);
-       fprintf(td->iolog_f, "%lu %s %s\n", utime_since_now(&td->io_log_start_time),
-                                               f->file_name, act[what]);
+       fprintf(td->iolog_f, "%llu %s %s\n",
+               (unsigned long long) utime_since_now(&td->io_log_start_time),
+               f->file_name, act[what]);
 }
 
 static void iolog_delay(struct thread_data *td, unsigned long delay)
 {
        uint64_t usec = utime_since_now(&td->last_issue);
        unsigned long orig_delay = delay;
-       uint64_t this_delay;
        struct timespec ts;
+       int ret = 0;
 
        if (delay < td->time_offset) {
                td->time_offset = 0;
@@ -96,13 +97,15 @@ static void iolog_delay(struct thread_data *td, unsigned long delay)
        delay -= usec;
 
        fio_gettime(&ts, NULL);
-       while (delay && !td->terminate) {
-               this_delay = delay;
-               if (this_delay > 500000)
-                       this_delay = 500000;
 
-               usec_sleep(td, this_delay);
-               delay -= this_delay;
+       while (delay && !td->terminate) {
+               ret = io_u_queued_complete(td, 0);
+               if (ret < 0)
+                       td_verror(td, -ret, "io_u_queued_complete");
+               if (td->flags & TD_F_REGROW_LOGS)
+                       regrow_logs(td);
+               if (utime_since_now(&ts) > delay)
+                       break;
        }
 
        usec = utime_since_now(&ts);
@@ -438,7 +441,7 @@ static bool read_iolog(struct thread_data *td)
        unsigned long long offset;
        unsigned int bytes;
        unsigned long long delay = 0;
-       int reads, writes, waits, fileno = 0, file_action = 0; /* stupid gcc */
+       int reads, writes, trims, waits, fileno = 0, file_action = 0; /* stupid gcc */
        char *rfname, *fname, *act;
        char *str, *p;
        enum fio_ddir rw;
@@ -460,7 +463,7 @@ static bool read_iolog(struct thread_data *td)
        rfname = fname = malloc(256+16);
        act = malloc(256+16);
 
-       syncs = reads = writes = waits = 0;
+       syncs = reads = writes = trims = waits = 0;
        while ((p = fgets(str, 4096, td->io_log_rfile)) != NULL) {
                struct io_piece *ipo;
                int r;
@@ -491,17 +494,25 @@ static bool read_iolog(struct thread_data *td)
                         */
                        if (!strcmp(act, "wait"))
                                rw = DDIR_WAIT;
-                       else if (!strcmp(act, "read"))
+                       else if (!strcmp(act, "read")) {
+                               if (td->o.replay_skip & (1u << DDIR_READ))
+                                       continue;
                                rw = DDIR_READ;
-                       else if (!strcmp(act, "write"))
+                       } else if (!strcmp(act, "write")) {
+                               if (td->o.replay_skip & (1u << DDIR_WRITE))
+                                       continue;
                                rw = DDIR_WRITE;
-                       else if (!strcmp(act, "sync"))
+                       } else if (!strcmp(act, "sync")) {
+                               if (td->o.replay_skip & (1u << DDIR_SYNC))
+                                       continue;
                                rw = DDIR_SYNC;
-                       else if (!strcmp(act, "datasync"))
+                       else if (!strcmp(act, "datasync"))
                                rw = DDIR_DATASYNC;
-                       else if (!strcmp(act, "trim"))
+                       else if (!strcmp(act, "trim")) {
+                               if (td->o.replay_skip & (1u << DDIR_TRIM))
+                                       continue;
                                rw = DDIR_TRIM;
-                       else {
+                       else {
                                log_err("fio: bad iolog file action: %s\n",
                                                                        act);
                                continue;
@@ -543,6 +554,13 @@ static bool read_iolog(struct thread_data *td)
                        if (read_only)
                                continue;
                        writes++;
+               } else if (rw == DDIR_TRIM) {
+                       /*
+                        * Don't add a trim for ro mode
+                        */
+                       if (read_only)
+                               continue;
+                       trims++;
                } else if (rw == DDIR_WAIT) {
                        if (td->o.no_stall)
                                continue;
@@ -619,19 +637,22 @@ static bool read_iolog(struct thread_data *td)
                {
                        io_u_quiesce(td);
                        free_io_mem(td);
-                       init_io_u_buffers(td);
+                       if (init_io_u_buffers(td))
+                               return false;
                }
                return true;
        }
 
-       if (!reads && !writes && !waits)
+       if (!reads && !writes && !waits && !trims)
                return false;
-       else if (reads && !writes)
-               td->o.td_ddir = TD_DDIR_READ;
-       else if (!reads && writes)
-               td->o.td_ddir = TD_DDIR_WRITE;
-       else
-               td->o.td_ddir = TD_DDIR_RW;
+
+       td->o.td_ddir = 0;
+       if (reads)
+               td->o.td_ddir |= TD_DDIR_READ;
+       if (writes)
+               td->o.td_ddir |= TD_DDIR_WRITE;
+       if (trims)
+               td->o.td_ddir |= TD_DDIR_TRIM;
 
        return true;
 }
@@ -793,6 +814,8 @@ bool init_iolog(struct thread_data *td)
        if (!ret)
                td_verror(td, EINVAL, "failed initializing iolog");
 
+       init_disk_util(td);
+
        return ret;
 }
 
@@ -843,6 +866,13 @@ void setup_log(struct io_log **log, struct log_params *p,
                l->log_ddir_mask = LOG_OFFSET_SAMPLE_BIT;
        if (l->log_prio)
                l->log_ddir_mask |= LOG_PRIO_SAMPLE_BIT;
+       /*
+        * The bandwidth-log option generates agg-read_bw.log,
+        * agg-write_bw.log and agg-trim_bw.log for which l->td is NULL.
+        * Check if l->td is valid before dereferencing it.
+        */
+       if (l->td && l->td->o.log_max == IO_LOG_SAMPLE_BOTH)
+               l->log_ddir_mask |= LOG_AVG_MAX_SAMPLE_BIT;
 
        INIT_FLIST_HEAD(&l->chunk_list);
 
@@ -969,7 +999,7 @@ static void flush_hist_samples(FILE *f, int hist_coarseness, void *samples,
 void flush_samples(FILE *f, void *samples, uint64_t sample_size)
 {
        struct io_sample *s;
-       int log_offset, log_prio;
+       int log_offset, log_prio, log_avg_max;
        uint64_t i, nr_samples;
        unsigned int prio_val;
        const char *fmt;
@@ -980,17 +1010,32 @@ void flush_samples(FILE *f, void *samples, uint64_t sample_size)
        s = __get_sample(samples, 0, 0);
        log_offset = (s->__ddir & LOG_OFFSET_SAMPLE_BIT) != 0;
        log_prio = (s->__ddir & LOG_PRIO_SAMPLE_BIT) != 0;
+       log_avg_max = (s->__ddir & LOG_AVG_MAX_SAMPLE_BIT) != 0;
 
        if (log_offset) {
-               if (log_prio)
-                       fmt = "%lu, %" PRId64 ", %u, %llu, %llu, 0x%04x\n";
-               else
-                       fmt = "%lu, %" PRId64 ", %u, %llu, %llu, %u\n";
+               if (log_prio) {
+                       if (log_avg_max)
+                               fmt = "%" PRIu64 ", %" PRId64 ", %" PRId64 ", %u, %llu, %llu, 0x%04x\n";
+                       else
+                               fmt = "%" PRIu64 ", %" PRId64 ", %u, %llu, %llu, 0x%04x\n";
+               } else {
+                       if (log_avg_max)
+                               fmt = "%" PRIu64 ", %" PRId64 ", %" PRId64 ", %u, %llu, %llu, %u\n";
+                       else
+                               fmt = "%" PRIu64 ", %" PRId64 ", %u, %llu, %llu, %u\n";
+               }
        } else {
-               if (log_prio)
-                       fmt = "%lu, %" PRId64 ", %u, %llu, 0x%04x\n";
-               else
-                       fmt = "%lu, %" PRId64 ", %u, %llu, %u\n";
+               if (log_prio) {
+                       if (log_avg_max)
+                               fmt = "%" PRIu64 ", %" PRId64 ", %" PRId64 ", %u, %llu, 0x%04x\n";
+                       else
+                               fmt = "%" PRIu64 ", %" PRId64 ", %u, %llu, 0x%04x\n";
+               } else {
+                       if (log_avg_max)
+                               fmt = "%" PRIu64 ", %" PRId64 ", %" PRId64 ", %u, %llu, %u\n";
+                       else
+                               fmt = "%" PRIu64 ", %" PRId64 ", %u, %llu, %u\n";
+               }
        }
 
        nr_samples = sample_size / __log_entry_sz(log_offset);
@@ -1004,20 +1049,37 @@ void flush_samples(FILE *f, void *samples, uint64_t sample_size)
                        prio_val = ioprio_value_is_class_rt(s->priority);
 
                if (!log_offset) {
-                       fprintf(f, fmt,
-                               (unsigned long) s->time,
-                               s->data.val,
-                               io_sample_ddir(s), (unsigned long long) s->bs,
-                               prio_val);
+                       if (log_avg_max)
+                               fprintf(f, fmt,
+                                       s->time,
+                                       s->data.val.val0,
+                                       s->data.val.val1,
+                                       io_sample_ddir(s), (unsigned long long) s->bs,
+                                       prio_val);
+                       else
+                               fprintf(f, fmt,
+                                       s->time,
+                                       s->data.val.val0,
+                                       io_sample_ddir(s), (unsigned long long) s->bs,
+                                       prio_val);
                } else {
                        struct io_sample_offset *so = (void *) s;
 
-                       fprintf(f, fmt,
-                               (unsigned long) s->time,
-                               s->data.val,
-                               io_sample_ddir(s), (unsigned long long) s->bs,
-                               (unsigned long long) so->offset,
-                               prio_val);
+                       if (log_avg_max)
+                               fprintf(f, fmt,
+                                       s->time,
+                                       s->data.val.val0,
+                                       s->data.val.val1,
+                                       io_sample_ddir(s), (unsigned long long) s->bs,
+                                       (unsigned long long) so->offset,
+                                       prio_val);
+                       else
+                               fprintf(f, fmt,
+                                       s->time,
+                                       s->data.val.val0,
+                                       io_sample_ddir(s), (unsigned long long) s->bs,
+                                       (unsigned long long) so->offset,
+                                       prio_val);
                }
        }
 }
@@ -1217,7 +1279,7 @@ int iolog_file_inflate(const char *file)
        void *buf;
        FILE *f;
 
-       f = fopen(file, "r");
+       f = fopen(file, "rb");
        if (!f) {
                perror("fopen");
                return 1;
@@ -1299,10 +1361,21 @@ void flush_log(struct io_log *log, bool do_append)
        void *buf;
        FILE *f;
 
+       /*
+        * If log_gz_store is true, we are writing a binary file.
+        * Set the mode appropriately (on all platforms) to avoid issues
+        * on windows (line-ending conversions, etc.)
+        */
        if (!do_append)
-               f = fopen(log->filename, "w");
+               if (log->log_gz_store)
+                       f = fopen(log->filename, "wb");
+               else
+                       f = fopen(log->filename, "w");
        else
-               f = fopen(log->filename, "a");
+               if (log->log_gz_store)
+                       f = fopen(log->filename, "ab");
+               else
+                       f = fopen(log->filename, "a");
        if (!f) {
                perror("fopen log");
                return;
@@ -1573,14 +1646,14 @@ void iolog_compress_exit(struct thread_data *td)
  * Queue work item to compress the existing log entries. We reset the
  * current log to a small size, and reference the existing log in the
  * data that we queue for compression. Once compression has been done,
- * this old log is freed. If called with finish == true, will not return
- * until the log compression has completed, and will flush all previous
- * logs too
+ * this old log is freed. Will not return until the log compression
+ * has completed, and will flush all previous logs too
  */
 static int iolog_flush(struct io_log *log)
 {
        struct iolog_flush_data *data;
 
+       workqueue_flush(&log->td->log_compress_wq);
        data = malloc(sizeof(*data));
        if (!data)
                return 1;
@@ -1845,9 +1918,7 @@ void td_writeout_logs(struct thread_data *td, bool unit_logs)
 
 void fio_writeout_logs(bool unit_logs)
 {
-       struct thread_data *td;
-       int i;
-
-       for_each_td(td, i)
+       for_each_td(td) {
                td_writeout_logs(td, unit_logs);
+       } end_for_each();
 }