iolog: punt freeing of data back to original thread
[fio.git] / iolog.c
diff --git a/iolog.c b/iolog.c
index baa4b855d6a709131be83c1c68173c7af317c713..27c14eb3630fda9179722d17bf0229374190e042 100644 (file)
--- a/iolog.c
+++ b/iolog.c
@@ -19,6 +19,7 @@
 #include "trim.h"
 #include "filelock.h"
 #include "smalloc.h"
+#include "blktrace.h"
 
 static int iolog_flush(struct io_log *log);
 
@@ -64,7 +65,7 @@ static void iolog_delay(struct thread_data *td, unsigned long delay)
 {
        uint64_t usec = utime_since_now(&td->last_issue);
        uint64_t this_delay;
-       struct timeval tv;
+       struct timespec ts;
 
        if (delay < td->time_offset) {
                td->time_offset = 0;
@@ -77,7 +78,7 @@ static void iolog_delay(struct thread_data *td, unsigned long delay)
 
        delay -= usec;
 
-       fio_gettime(&tv, NULL);
+       fio_gettime(&ts, NULL);
        while (delay && !td->terminate) {
                this_delay = delay;
                if (this_delay > 500000)
@@ -87,7 +88,7 @@ static void iolog_delay(struct thread_data *td, unsigned long delay)
                delay -= this_delay;
        }
 
-       usec = utime_since_now(&tv);
+       usec = utime_since_now(&ts);
        if (usec > delay)
                td->time_offset = usec - delay;
        else
@@ -109,6 +110,11 @@ static int ipo_special(struct thread_data *td, struct io_piece *ipo)
 
        switch (ipo->file_action) {
        case FIO_LOG_OPEN_FILE:
+               if (td->o.replay_redirect && fio_file_open(f)) {
+                       dprint(FD_FILE, "iolog: ignoring re-open of file %s\n",
+                                       f->file_name);
+                       break;
+               }
                ret = td_io_open_file(td, f);
                if (!ret)
                        break;
@@ -272,7 +278,7 @@ restart:
                        overlap = 1;
 
                if (overlap) {
-                       dprint(FD_IO, "iolog: overlap %llu/%lu, %llu/%lu",
+                       dprint(FD_IO, "iolog: overlap %llu/%lu, %llu/%lu\n",
                                __ipo->offset, __ipo->len,
                                ipo->offset, ipo->len);
                        td->io_hist_len--;
@@ -346,7 +352,7 @@ static int read_iolog2(struct thread_data *td, FILE *f)
        unsigned long long offset;
        unsigned int bytes;
        int reads, writes, waits, fileno = 0, file_action = 0; /* stupid gcc */
-       char *fname, *act;
+       char *rfname, *fname, *act;
        char *str, *p;
        enum fio_ddir rw;
 
@@ -357,7 +363,7 @@ static int read_iolog2(struct thread_data *td, FILE *f)
         * for doing verifications.
         */
        str = malloc(4096);
-       fname = malloc(256+16);
+       rfname = fname = malloc(256+16);
        act = malloc(256+16);
 
        reads = writes = waits = 0;
@@ -365,8 +371,12 @@ static int read_iolog2(struct thread_data *td, FILE *f)
                struct io_piece *ipo;
                int r;
 
-               r = sscanf(p, "%256s %256s %llu %u", fname, act, &offset,
+               r = sscanf(p, "%256s %256s %llu %u", rfname, act, &offset,
                                                                        &bytes);
+
+               if (td->o.replay_redirect)
+                       fname = td->o.replay_redirect;
+
                if (r == 4) {
                        /*
                         * Check action first
@@ -392,8 +402,14 @@ static int read_iolog2(struct thread_data *td, FILE *f)
                } else if (r == 2) {
                        rw = DDIR_INVAL;
                        if (!strcmp(act, "add")) {
-                               fileno = add_file(td, fname, 0, 1);
-                               file_action = FIO_LOG_ADD_FILE;
+                               if (td->o.replay_redirect &&
+                                   get_fileno(td, fname) != -1) {
+                                       dprint(FD_FILE, "iolog: ignoring"
+                                               " re-add of file %s\n", fname);
+                               } else {
+                                       fileno = add_file(td, fname, 0, 1);
+                                       file_action = FIO_LOG_ADD_FILE;
+                               }
                                continue;
                        } else if (!strcmp(act, "open")) {
                                fileno = get_fileno(td, fname);
@@ -407,7 +423,7 @@ static int read_iolog2(struct thread_data *td, FILE *f)
                                continue;
                        }
                } else {
-                       log_err("bad iolog2: %s", p);
+                       log_err("bad iolog2: %s\n", p);
                        continue;
                }
 
@@ -421,6 +437,8 @@ static int read_iolog2(struct thread_data *td, FILE *f)
                                continue;
                        writes++;
                } else if (rw == DDIR_WAIT) {
+                       if (td->o.no_stall)
+                               continue;
                        waits++;
                } else if (rw == DDIR_INVAL) {
                } else if (!ddir_sync(rw)) {
@@ -437,7 +455,12 @@ static int read_iolog2(struct thread_data *td, FILE *f)
                if (rw == DDIR_WAIT) {
                        ipo->delay = offset;
                } else {
-                       ipo->offset = offset;
+                       if (td->o.replay_scale)
+                               ipo->offset = offset / td->o.replay_scale;
+                       else
+                               ipo->offset = offset;
+                       ipo_bytes_align(td->o.replay_align, ipo);
+
                        ipo->len = bytes;
                        if (rw != DDIR_INVAL && bytes > td->o.max_bs[rw])
                                td->o.max_bs[rw] = bytes;
@@ -451,7 +474,7 @@ static int read_iolog2(struct thread_data *td, FILE *f)
 
        free(str);
        free(act);
-       free(fname);
+       free(rfname);
 
        if (writes && read_only) {
                log_err("fio: <%s> skips replay of %d writes due to"
@@ -620,6 +643,7 @@ void setup_log(struct io_log **log, struct log_params *p,
                l->log_gz = 0;
        else if (l->log_gz || l->log_gz_store) {
                mutex_init_pshared(&l->chunk_lock);
+               mutex_init_pshared(&l->deferred_free_lock);
                p->td->flags |= TD_F_COMPRESS_LOG;
        }
 
@@ -674,7 +698,7 @@ void free_log(struct io_log *log)
        sfree(log);
 }
 
-inline unsigned long hist_sum(int j, int stride, unsigned int *io_u_plat,
+unsigned long hist_sum(int j, int stride, unsigned int *io_u_plat,
                unsigned int *io_u_plat_last)
 {
        unsigned long sum;
@@ -714,7 +738,7 @@ static void flush_hist_samples(FILE *f, int hist_coarseness, void *samples,
        for (i = 0; i < nr_samples; i++) {
                s = __get_sample(samples, log_offset, i);
 
-               entry = (struct io_u_plat_entry *) s->val;
+               entry = s->data.plat_entry;
                io_u_plat = entry->io_u_plat;
 
                entry_before = flist_first_entry(&entry->list, struct io_u_plat_entry, list);
@@ -753,16 +777,16 @@ void flush_samples(FILE *f, void *samples, uint64_t sample_size)
                s = __get_sample(samples, log_offset, i);
 
                if (!log_offset) {
-                       fprintf(f, "%lu, %lu, %u, %u\n",
+                       fprintf(f, "%lu, %" PRId64 ", %u, %u\n",
                                        (unsigned long) s->time,
-                                       (unsigned long) s->val,
+                                       s->data.val,
                                        io_sample_ddir(s), s->bs);
                } else {
                        struct io_sample_offset *so = (void *) s;
 
-                       fprintf(f, "%lu, %lu, %u, %u, %llu\n",
+                       fprintf(f, "%lu, %" PRId64 ", %u, %u, %llu\n",
                                        (unsigned long) s->time,
-                                       (unsigned long) s->val,
+                                       s->data.val,
                                        io_sample_ddir(s), s->bs,
                                        (unsigned long long) so->offset);
                }
@@ -1065,7 +1089,7 @@ void flush_log(struct io_log *log, bool do_append)
                cur_log = flist_first_entry(&log->io_logs, struct io_logs, list);
                flist_del_init(&cur_log->list);
                
-               if (log == log->td->clat_hist_log)
+               if (log->td && log == log->td->clat_hist_log)
                        flush_hist_samples(f, log->hist_coarseness, cur_log->log,
                                           log_sample_sz(log, cur_log));
                else
@@ -1121,6 +1145,42 @@ size_t log_chunk_sizes(struct io_log *log)
 
 #ifdef CONFIG_ZLIB
 
+static bool warned_on_drop;
+
+static void iolog_put_deferred(struct io_log *log, void *ptr)
+{
+       if (!ptr)
+               return;
+
+       pthread_mutex_lock(&log->deferred_free_lock);
+       if (log->deferred < IOLOG_MAX_DEFER) {
+               log->deferred_items[log->deferred] = ptr;
+               log->deferred++;
+       } else if (!warned_on_drop) {
+               log_err("fio: had to drop log entry free\n");
+               warned_on_drop = true;
+       }
+       pthread_mutex_unlock(&log->deferred_free_lock);
+}
+
+static void iolog_free_deferred(struct io_log *log)
+{
+       int i;
+
+       if (!log->deferred)
+               return;
+
+       pthread_mutex_lock(&log->deferred_free_lock);
+
+       for (i = 0; i < log->deferred; i++) {
+               free(log->deferred_items[i]);
+               log->deferred_items[i] = NULL;
+       }
+
+       log->deferred = 0;
+       pthread_mutex_unlock(&log->deferred_free_lock);
+}
+
 static int gz_work(struct iolog_flush_data *data)
 {
        struct iolog_compress *c = NULL;
@@ -1153,7 +1213,8 @@ static int gz_work(struct iolog_flush_data *data)
                                data->log->filename);
        do {
                if (c)
-                       dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq, c->len);
+                       dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq,
+                               (unsigned long) c->len);
                c = get_new_chunk(seq);
                stream.avail_out = GZ_CHUNK;
                stream.next_out = c->buf;
@@ -1190,7 +1251,7 @@ static int gz_work(struct iolog_flush_data *data)
        total -= c->len;
        c->len = GZ_CHUNK - stream.avail_out;
        total += c->len;
-       dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq, c->len);
+       dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq, (unsigned long) c->len);
 
        if (ret != Z_STREAM_END) {
                do {
@@ -1201,7 +1262,8 @@ static int gz_work(struct iolog_flush_data *data)
                        c->len = GZ_CHUNK - stream.avail_out;
                        total += c->len;
                        flist_add_tail(&c->list, &list);
-                       dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq, c->len);
+                       dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq,
+                               (unsigned long) c->len);
                } while (ret != Z_STREAM_END);
        }
 
@@ -1211,7 +1273,7 @@ static int gz_work(struct iolog_flush_data *data)
        if (ret != Z_OK)
                log_err("fio: deflateEnd %d\n", ret);
 
-       free(data->samples);
+       iolog_put_deferred(data->log, data->samples);
 
        if (!flist_empty(&list)) {
                pthread_mutex_lock(&data->log->chunk_lock);
@@ -1222,7 +1284,7 @@ static int gz_work(struct iolog_flush_data *data)
        ret = 0;
 done:
        if (data->free)
-               free(data);
+               sfree(data);
        return ret;
 err:
        while (!flist_empty(&list)) {
@@ -1323,7 +1385,7 @@ int iolog_cur_flush(struct io_log *log, struct io_logs *cur_log)
 {
        struct iolog_flush_data *data;
 
-       data = malloc(sizeof(*data));
+       data = smalloc(sizeof(*data));
        if (!data)
                return 1;
 
@@ -1337,6 +1399,9 @@ int iolog_cur_flush(struct io_log *log, struct io_logs *cur_log)
        cur_log->log = NULL;
 
        workqueue_enqueue(&log->td->log_compress_wq, &data->work);
+
+       iolog_free_deferred(log);
+
        return 0;
 }
 #else