blktrace: handle flush/sync replay
[fio.git] / blktrace.c
index 2d4dc1b9fbca3724e47c7285e7fcdab277b82bc3..b37a54e9e1cd36ec75dffb7e9a03bfbec8e3f886 100644 (file)
@@ -3,15 +3,14 @@
  */
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <linux/fs.h>
-#include <dirent.h>
 
 #include "flist.h"
 #include "fio.h"
+#include "blktrace.h"
 #include "blktrace_api.h"
-#include "lib/linux-dev-lookup.h"
+#include "oslib/linux-dev-lookup.h"
 
 #define TRACE_FIFO_SIZE        8192
 
@@ -208,6 +207,14 @@ out:
        return last_fileno;
 }
 
+static void t_bytes_align(struct thread_options *o, struct blk_io_trace *t)
+{
+       if (!o->replay_align)
+               return;
+
+       t->bytes = (t->bytes + o->replay_align - 1) & ~(o->replay_align - 1);
+}
+
 /*
  * Store blk_io_trace data in an ipo for later retrieval.
  */
@@ -215,11 +222,15 @@ static void store_ipo(struct thread_data *td, unsigned long long offset,
                      unsigned int bytes, int rw, unsigned long long ttime,
                      int fileno, unsigned int bs)
 {
-       struct io_piece *ipo = malloc(sizeof(*ipo));
+       struct io_piece *ipo;
 
+       ipo = calloc(1, sizeof(*ipo));
        init_ipo(ipo);
 
        ipo->offset = offset * bs;
+       if (td->o.replay_scale)
+               ipo->offset = ipo->offset / td->o.replay_scale;
+       ipo_bytes_align(td->o.replay_align, ipo);
        ipo->len = bytes;
        ipo->delay = ttime / 1000;
        if (rw)
@@ -258,10 +269,11 @@ static void handle_trace_discard(struct thread_data *td,
                                 unsigned long long ttime,
                                 unsigned long *ios, unsigned int *rw_bs)
 {
-       struct io_piece *ipo = malloc(sizeof(*ipo));
+       struct io_piece *ipo;
        unsigned int bs;
        int fileno;
 
+       ipo = calloc(1, sizeof(*ipo));
        init_ipo(ipo);
        fileno = trace_add_file(td, t->device, &bs);
 
@@ -271,10 +283,12 @@ static void handle_trace_discard(struct thread_data *td,
 
        td->o.size += t->bytes;
 
-       memset(ipo, 0, sizeof(*ipo));
        INIT_FLIST_HEAD(&ipo->list);
 
        ipo->offset = t->sector * bs;
+       if (td->o.replay_scale)
+               ipo->offset = ipo->offset / td->o.replay_scale;
+       ipo_bytes_align(td->o.replay_align, ipo);
        ipo->len = t->bytes;
        ipo->delay = ttime / 1000;
        ipo->ddir = DDIR_TRIM;
@@ -298,7 +312,13 @@ static void handle_trace_fs(struct thread_data *td, struct blk_io_trace *t,
 
        rw = (t->action & BLK_TC_ACT(BLK_TC_WRITE)) != 0;
 
-       if (t->bytes > rw_bs[rw])
+       /*
+        * Need to figure out why 0 byte writes end up here sometimes, for
+        * now just ignore them.
+        */
+       if (!t->bytes)
+               return;
+       else if (t->bytes > rw_bs[rw])
                rw_bs[rw] = t->bytes;
 
        ios[rw]++;
@@ -306,6 +326,25 @@ static void handle_trace_fs(struct thread_data *td, struct blk_io_trace *t,
        store_ipo(td, t->sector, t->bytes, rw, ttime, fileno, bs);
 }
 
+static void handle_trace_flush(struct thread_data *td, struct blk_io_trace *t,
+                              unsigned long long ttime)
+{
+       struct io_piece *ipo;
+       unsigned int bs;
+       int fileno;
+
+       ipo = calloc(1, sizeof(*ipo));
+       init_ipo(ipo);
+       fileno = trace_add_file(td, t->device, &bs);
+
+       ipo->delay = ttime / 1000;
+       ipo->ddir = DDIR_SYNC;
+       ipo->fileno = fileno;
+
+       dprint(FD_BLKTRACE, "store flush delay=%lu\n", ipo->delay);
+       queue_io_piece(td, ipo);
+}
+
 /*
  * We only care for queue traces, most of the others are side effects
  * due to internal workings of the block layer.
@@ -314,25 +353,35 @@ static void handle_trace(struct thread_data *td, struct blk_io_trace *t,
                         unsigned long *ios, unsigned int *bs)
 {
        static unsigned long long last_ttime;
-       unsigned long long delay;
+       unsigned long long delay = 0;
 
        if ((t->action & 0xffff) != __BLK_TA_QUEUE)
                return;
 
        if (!(t->action & BLK_TC_ACT(BLK_TC_NOTIFY))) {
-               if (!last_ttime || td->o.no_stall) {
-                       last_ttime = t->time;
+               if (!last_ttime || td->o.no_stall)
                        delay = 0;
-               } else {
+               else if (td->o.replay_time_scale == 100)
                        delay = t->time - last_ttime;
-                       last_ttime = t->time;
+               else {
+                       double tmp = t->time - last_ttime;
+                       double scale;
+
+                       scale = (double) 100.0 / (double) td->o.replay_time_scale;
+                       tmp *= scale;
+                       delay = tmp;
                }
+               last_ttime = t->time;
        }
 
+       t_bytes_align(&td->o, t);
+
        if (t->action & BLK_TC_ACT(BLK_TC_NOTIFY))
                handle_trace_notify(t);
        else if (t->action & BLK_TC_ACT(BLK_TC_DISCARD))
                handle_trace_discard(td, t, delay, ios, bs);
+       else if (t->action & BLK_TC_ACT(BLK_TC_FLUSH))
+               handle_trace_flush(td, t, delay);
        else
                handle_trace_fs(td, t, delay, ios, bs);
 }
@@ -483,10 +532,8 @@ int load_blktrace(struct thread_data *td, const char *filename, int need_swap)
                handle_trace(td, &t, ios, rw_bs);
        } while (1);
 
-       for (i = 0; i < td->files_index; i++) {
-               f = td->files[i];
+       for_each_file(td, f, i)
                trace_add_open_close_event(td, f->fileno, FIO_LOG_CLOSE_FILE);
-       }
 
        fifo_free(fifo);
        close(fd);