From 0c63576e14bc606f81441f20e58a5b6338a5e2d6 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 6 May 2015 14:19:20 -0600 Subject: [PATCH] blktrace: add support for scaling and aligning replays Signed-off-by: Jens Axboe --- HOWTO | 6 ++++++ blktrace.c | 27 ++++++++++++++++++++++++++- cconv.c | 4 ++++ fio.1 | 6 ++++++ options.c | 22 ++++++++++++++++++++++ thread_options.h | 6 ++++++ 6 files changed, 70 insertions(+), 1 deletion(-) diff --git a/HOWTO b/HOWTO index bb298264..0808cc3a 100644 --- 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. +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 diff --git a/blktrace.c b/blktrace.c index 2d4dc1b9..562e126b 100644 --- a/blktrace.c +++ b/blktrace.c @@ -208,6 +208,23 @@ 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); +} + +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. */ @@ -220,6 +237,9 @@ static void store_ipo(struct thread_data *td, unsigned long long offset, 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) @@ -275,6 +295,9 @@ static void handle_trace_discard(struct thread_data *td, 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; @@ -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 long delay; + unsigned long long delay = 0; 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)) diff --git a/cconv.c b/cconv.c index 976059cd..9c7e7185 100644 --- 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->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); @@ -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->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]); diff --git a/fio.1 b/fio.1 index a77c71c3..e54e419b 100644 --- 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 +.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 diff --git a/options.c b/options.c index 3de1248c..40b69ed9 100644 --- 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, }, + { + .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", diff --git a/thread_options.h b/thread_options.h index aa7f3f26..1c48bd83 100644 --- a/thread_options.h +++ b/thread_options.h @@ -265,6 +265,9 @@ struct thread_options { unsigned block_error_hist; unsigned int skip_bad; + + unsigned int replay_align; + unsigned int replay_scale; }; #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 replay_align; + uint32_t replay_scale; } __attribute__((packed)); extern void convert_thread_options_to_cpu(struct thread_options *o, struct thread_options_pack *top); -- 2.25.1