blktrace: add support for scaling and aligning replays
authorJens Axboe <axboe@fb.com>
Wed, 6 May 2015 20:19:20 +0000 (14:19 -0600)
committerJens Axboe <axboe@fb.com>
Wed, 6 May 2015 20:19:20 +0000 (14:19 -0600)
Signed-off-by: Jens Axboe <axboe@fb.com>
HOWTO
blktrace.c
cconv.c
fio.1
options.c
thread_options.h

diff --git a/HOWTO b/HOWTO
index bb29826428574a77f0352e279155c4b6adb2cea0..0808cc3a07e0f53a62c3476b6789f47426917829 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -1433,6 +1433,12 @@ replay_redirect=str While replaying I/O patterns using read_iolog the
                independent fio invocations.  Unfortuantely this also breaks
                the strict time ordering between multiple device accesses.
 
                independent fio invocations.  Unfortuantely this also breaks
                the strict time ordering between multiple device accesses.
 
+replay_align=int       Force alignment of IO offsets and lengths in a trace
+               to this power of 2 value.
+
+replay_scale=int       Scale sector offsets down by this factor when
+               replaying traces.
+
 write_bw_log=str If given, write a bandwidth log of the jobs in this job
                file. Can be used to store data of the bandwidth of the
                jobs in their lifetime. The included fio_generate_plots
 write_bw_log=str If given, write a bandwidth log of the jobs in this job
                file. Can be used to store data of the bandwidth of the
                jobs in their lifetime. The included fio_generate_plots
index 2d4dc1b9fbca3724e47c7285e7fcdab277b82bc3..562e126b428389af6db707b5fffde18cc922efb9 100644 (file)
@@ -208,6 +208,23 @@ out:
        return last_fileno;
 }
 
        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);
+}
+
+static void ipo_bytes_align(struct thread_options *o, struct io_piece *ipo)
+{
+       if (!o->replay_align)
+               return;
+
+       ipo->offset &= ~(o->replay_align - 1);
+}
+
+
 /*
  * Store blk_io_trace data in an ipo for later retrieval.
  */
 /*
  * Store blk_io_trace data in an ipo for later retrieval.
  */
@@ -220,6 +237,9 @@ static void store_ipo(struct thread_data *td, unsigned long long offset,
        init_ipo(ipo);
 
        ipo->offset = offset * bs;
        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, ipo);
        ipo->len = bytes;
        ipo->delay = ttime / 1000;
        if (rw)
        ipo->len = bytes;
        ipo->delay = ttime / 1000;
        if (rw)
@@ -275,6 +295,9 @@ static void handle_trace_discard(struct thread_data *td,
        INIT_FLIST_HEAD(&ipo->list);
 
        ipo->offset = t->sector * bs;
        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, ipo);
        ipo->len = t->bytes;
        ipo->delay = ttime / 1000;
        ipo->ddir = DDIR_TRIM;
        ipo->len = t->bytes;
        ipo->delay = ttime / 1000;
        ipo->ddir = DDIR_TRIM;
@@ -314,7 +337,7 @@ 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 *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 & 0xffff) != __BLK_TA_QUEUE)
                return;
@@ -329,6 +352,8 @@ static void handle_trace(struct thread_data *td, struct blk_io_trace *t,
                }
        }
 
                }
        }
 
+       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))
        if (t->action & BLK_TC_ACT(BLK_TC_NOTIFY))
                handle_trace_notify(t);
        else if (t->action & BLK_TC_ACT(BLK_TC_DISCARD))
diff --git a/cconv.c b/cconv.c
index 976059cde61ab1c298f6ca41949b054c686c2d5f..9c7e718593046068244fcc1917cc016b99a92ddc 100644 (file)
--- a/cconv.c
+++ b/cconv.c
@@ -244,6 +244,8 @@ void convert_thread_options_to_cpu(struct thread_options *o,
        o->compress_percentage = le32_to_cpu(top->compress_percentage);
        o->compress_chunk = le32_to_cpu(top->compress_chunk);
        o->dedupe_percentage = le32_to_cpu(top->dedupe_percentage);
        o->compress_percentage = le32_to_cpu(top->compress_percentage);
        o->compress_chunk = le32_to_cpu(top->compress_chunk);
        o->dedupe_percentage = le32_to_cpu(top->dedupe_percentage);
+       o->replay_align = le32_to_cpu(top->replay_align);
+       o->replay_scale = le32_to_cpu(top->replay_scale);
 
        o->trim_backlog = le64_to_cpu(top->trim_backlog);
 
 
        o->trim_backlog = le64_to_cpu(top->trim_backlog);
 
@@ -407,6 +409,8 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
        top->compress_percentage = cpu_to_le32(o->compress_percentage);
        top->compress_chunk = cpu_to_le32(o->compress_chunk);
        top->dedupe_percentage = cpu_to_le32(o->dedupe_percentage);
        top->compress_percentage = cpu_to_le32(o->compress_percentage);
        top->compress_chunk = cpu_to_le32(o->compress_chunk);
        top->dedupe_percentage = cpu_to_le32(o->dedupe_percentage);
+       top->replay_align = cpu_to_le32(o->replay_align);
+       top->replay_scale = cpu_to_le32(o->replay_scale);
 
        for (i = 0; i < DDIR_RWDIR_CNT; i++) {
                top->bs[i] = cpu_to_le32(o->bs[i]);
 
        for (i = 0; i < DDIR_RWDIR_CNT; i++) {
                top->bs[i] = cpu_to_le32(o->bs[i]);
diff --git a/fio.1 b/fio.1
index a77c71c3f3adaf9a306e0ac12ac2ce46ffcba058..e54e419b2f5852733c7312a44defcf0345be7591 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -1265,6 +1265,12 @@ is to replay the IOPS onto the major/minor device that each IOP was recorded
 from.  Setting \fBreplay_redirect\fR causes all IOPS to be replayed onto the
 single specified device regardless of the device it was recorded from.
 .TP
 from.  Setting \fBreplay_redirect\fR causes all IOPS to be replayed onto the
 single specified device regardless of the device it was recorded from.
 .TP
+.BI replay_align \fR=\fPint
+Force alignment of IO offsets and lengths in a trace to this power of 2 value.
+.TP
+.BI replay_scale \fR=\fPint
+Scale sector offsets down by this factor when replaying traces.
+.TP
 .BI write_bw_log \fR=\fPstr
 If given, write a bandwidth log of the jobs in this job file. Can be used to
 store data of the bandwidth of the jobs in their lifetime. The included
 .BI write_bw_log \fR=\fPstr
 If given, write a bandwidth log of the jobs in this job file. Can be used to
 store data of the bandwidth of the jobs in their lifetime. The included
index 3de1248cce9ef44da252ec41b4578a09b6e39da8..40b69ed9877af50e979eb24683a61d5a7710b118 100644 (file)
--- a/options.c
+++ b/options.c
@@ -2661,6 +2661,28 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_IOLOG,
        },
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_IOLOG,
        },
+       {
+               .name   = "replay_scale",
+               .lname  = "Replace offset scale factor",
+               .type   = FIO_OPT_INT,
+               .off1   = td_var_offset(replay_scale),
+               .parent = "read_iolog",
+               .def    = "1",
+               .help   = "Align offsets to this blocksize",
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_IOLOG,
+       },
+       {
+               .name   = "replay_align",
+               .lname  = "Replace alignment",
+               .type   = FIO_OPT_INT,
+               .off1   = td_var_offset(replay_align),
+               .parent = "read_iolog",
+               .help   = "Scale offset down by this factor",
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_IOLOG,
+               .pow2   = 1,
+       },
        {
                .name   = "exec_prerun",
                .lname  = "Pre-execute runnable",
        {
                .name   = "exec_prerun",
                .lname  = "Pre-execute runnable",
index aa7f3f2657c8c985e94ec1449e01a34b5fed1ce5..1c48bd83d394577b463ecb9ec5b4572b05123747 100644 (file)
@@ -265,6 +265,9 @@ struct thread_options {
 
        unsigned block_error_hist;
        unsigned int skip_bad;
 
        unsigned block_error_hist;
        unsigned int skip_bad;
+
+       unsigned int replay_align;
+       unsigned int replay_scale;
 };
 
 #define FIO_TOP_STR_MAX                256
 };
 
 #define FIO_TOP_STR_MAX                256
@@ -495,6 +498,9 @@ struct thread_options_pack {
 
        uint32_t block_error_hist;
        uint32_t skip_bad;
 
        uint32_t block_error_hist;
        uint32_t skip_bad;
+
+       uint32_t replay_align;
+       uint32_t replay_scale;
 } __attribute__((packed));
 
 extern void convert_thread_options_to_cpu(struct thread_options *o, struct thread_options_pack *top);
 } __attribute__((packed));
 
 extern void convert_thread_options_to_cpu(struct thread_options *o, struct thread_options_pack *top);