fio: provide an option for a startdelay range
authorChristian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
Thu, 20 Feb 2014 17:07:02 +0000 (09:07 -0800)
committerJens Axboe <axboe@fb.com>
Thu, 20 Feb 2014 17:10:52 +0000 (09:10 -0800)
This patch allows the specification of start delay as range.  With a
range each thread will chose an individual startdelay out of the range.

That solves an issue of startdelay being the same for each numjob clone
and that way spreads all kind of activities e.g. that all clones with
mixed r/w jobs switch r/w at the same time.  Also all kind of other
"thundering herd" issues can be softened by some time spread due to this
option.

Signed-off-by: Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
cconv.c
fio.1
fio.h
init.c
options.c
thread_options.h

diff --git a/cconv.c b/cconv.c
index 41ef6265d5695dfc6546ac8dd3b0dff110600e6b..fd8d0ad85142568b2d142948ea4b5f638f03b03f 100644 (file)
--- a/cconv.c
+++ b/cconv.c
@@ -166,6 +166,7 @@ void convert_thread_options_to_cpu(struct thread_options *o,
 
        o->verify_backlog = le64_to_cpu(top->verify_backlog);
        o->start_delay = le64_to_cpu(top->start_delay);
 
        o->verify_backlog = le64_to_cpu(top->verify_backlog);
        o->start_delay = le64_to_cpu(top->start_delay);
+       o->start_delay_high = le64_to_cpu(top->start_delay_high);
        o->timeout = le64_to_cpu(top->timeout);
        o->ramp_time = le64_to_cpu(top->ramp_time);
        o->zone_range = le64_to_cpu(top->zone_range);
        o->timeout = le64_to_cpu(top->timeout);
        o->ramp_time = le64_to_cpu(top->ramp_time);
        o->zone_range = le64_to_cpu(top->zone_range);
@@ -422,6 +423,7 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
        top->size = __cpu_to_le64(o->size);
        top->verify_backlog = __cpu_to_le64(o->verify_backlog);
        top->start_delay = __cpu_to_le64(o->start_delay);
        top->size = __cpu_to_le64(o->size);
        top->verify_backlog = __cpu_to_le64(o->verify_backlog);
        top->start_delay = __cpu_to_le64(o->start_delay);
+       top->start_delay_high = __cpu_to_le64(o->start_delay_high);
        top->timeout = __cpu_to_le64(o->timeout);
        top->ramp_time = __cpu_to_le64(o->ramp_time);
        top->zone_range = __cpu_to_le64(o->zone_range);
        top->timeout = __cpu_to_le64(o->timeout);
        top->ramp_time = __cpu_to_le64(o->ramp_time);
        top->zone_range = __cpu_to_le64(o->zone_range);
diff --git a/fio.1 b/fio.1
index a16d0398b2bc4c59a583dd805cacf6ba40b5aa03..2320ba341fc5efdf839afb350981f185a3906327 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -846,8 +846,12 @@ needed to be specified. For \fBprefer\fR, only one node is
 allowed. For \fBbind\fR and \fBinterleave\fR, \fBnodelist\fR allows
 comma delimited list of numbers, A-B ranges, or 'all'.
 .TP
 allowed. For \fBbind\fR and \fBinterleave\fR, \fBnodelist\fR allows
 comma delimited list of numbers, A-B ranges, or 'all'.
 .TP
-.BI startdelay \fR=\fPint
-Delay start of job for the specified number of seconds.
+.BI startdelay \fR=\fPirange
+Delay start of job for the specified number of seconds. Supports all time
+suffixes to allow specification of hours, minutes, seconds and
+milliseconds - seconds are the default if a unit is ommited.
+Can be given as a range which causes each thread to choose randomly out of the
+range.
 .TP
 .BI runtime \fR=\fPint
 Terminate processing after the specified number of seconds.
 .TP
 .BI runtime \fR=\fPint
 Terminate processing after the specified number of seconds.
diff --git a/fio.h b/fio.h
index cda4668601e88d6945c9f43e33cf85bbbaafc234..75ed804b0d3ee850f1ff37865e00df17032db2d2 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -85,6 +85,7 @@ enum {
        FIO_RAND_SEQ_RAND_READ_OFF,
        FIO_RAND_SEQ_RAND_WRITE_OFF,
        FIO_RAND_SEQ_RAND_TRIM_OFF,
        FIO_RAND_SEQ_RAND_READ_OFF,
        FIO_RAND_SEQ_RAND_WRITE_OFF,
        FIO_RAND_SEQ_RAND_TRIM_OFF,
+       FIO_RAND_START_DELAY,
        FIO_RAND_NR_OFFS,
 };
 
        FIO_RAND_NR_OFFS,
 };
 
@@ -164,6 +165,10 @@ struct thread_data {
                os_random_state_t trim_state;
                struct frand_state __trim_state;
        };
                os_random_state_t trim_state;
                struct frand_state __trim_state;
        };
+       union {
+               os_random_state_t delay_state;
+               struct frand_state __delay_state;
+       };
 
        struct frand_state buf_state;
 
 
        struct frand_state buf_state;
 
diff --git a/init.c b/init.c
index c3b33dccfaca2d538b39470532bc302be1544e5b..9d3c960870a89e0412094b5d5ee4ba6754462061 100644 (file)
--- a/init.c
+++ b/init.c
@@ -412,6 +412,26 @@ static int fixed_block_size(struct thread_options *o)
                o->min_bs[DDIR_READ] == o->min_bs[DDIR_TRIM];
 }
 
                o->min_bs[DDIR_READ] == o->min_bs[DDIR_TRIM];
 }
 
+
+static unsigned long long get_rand_start_delay(struct thread_data *td)
+{
+       unsigned long long delayrange;
+       unsigned long r;
+
+       delayrange = td->o.start_delay_high - td->o.start_delay;
+
+       if (td->o.use_os_rand) {
+               r = os_random_long(&td->delay_state);
+               delayrange = (unsigned long long) ((double) delayrange * (r / (OS_RAND_MAX + 1.0)));
+       } else {
+               r = __rand(&td->__delay_state);
+               delayrange = (unsigned long long) ((double) delayrange * (r / (FRAND_MAX + 1.0)));
+       }
+
+       delayrange += td->o.start_delay;
+       return delayrange;
+}
+
 /*
  * Lazy way of fixing up options that depend on each other. We could also
  * define option callback handlers, but this is easier.
 /*
  * Lazy way of fixing up options that depend on each other. We could also
  * define option callback handlers, but this is easier.
@@ -496,6 +516,9 @@ static int fixup_options(struct thread_data *td)
        if (!o->file_size_high)
                o->file_size_high = o->file_size_low;
 
        if (!o->file_size_high)
                o->file_size_high = o->file_size_low;
 
+       if (o->start_delay_high)
+               o->start_delay = get_rand_start_delay(td);
+
        if (o->norandommap && o->verify != VERIFY_NONE
            && !fixed_block_size(o))  {
                log_err("fio: norandommap given for variable block sizes, "
        if (o->norandommap && o->verify != VERIFY_NONE
            && !fixed_block_size(o))  {
                log_err("fio: norandommap given for variable block sizes, "
@@ -711,6 +734,7 @@ static void td_fill_rand_seeds_os(struct thread_data *td)
 
        os_random_seed(td->rand_seeds[FIO_RAND_FILE_SIZE_OFF], &td->file_size_state);
        os_random_seed(td->rand_seeds[FIO_RAND_TRIM_OFF], &td->trim_state);
 
        os_random_seed(td->rand_seeds[FIO_RAND_FILE_SIZE_OFF], &td->file_size_state);
        os_random_seed(td->rand_seeds[FIO_RAND_TRIM_OFF], &td->trim_state);
+       os_random_seed(td->rand_seeds[FIO_RAND_START_DELAY], &td->delay_state);
 
        if (!td_random(td))
                return;
 
        if (!td_random(td))
                return;
@@ -736,6 +760,7 @@ static void td_fill_rand_seeds_internal(struct thread_data *td)
 
        init_rand_seed(&td->__file_size_state, td->rand_seeds[FIO_RAND_FILE_SIZE_OFF]);
        init_rand_seed(&td->__trim_state, td->rand_seeds[FIO_RAND_TRIM_OFF]);
 
        init_rand_seed(&td->__file_size_state, td->rand_seeds[FIO_RAND_FILE_SIZE_OFF]);
        init_rand_seed(&td->__trim_state, td->rand_seeds[FIO_RAND_TRIM_OFF]);
+       init_rand_seed(&td->__delay_state, td->rand_seeds[FIO_RAND_START_DELAY]);
 
        if (!td_random(td))
                return;
 
        if (!td_random(td))
                return;
index 4a68c01bc9e4a0a11368b10ca9586e179c5ab0be..5b97ec413aae0ba43d8f911ccfda8dc24397553f 100644 (file)
--- a/options.c
+++ b/options.c
@@ -2018,6 +2018,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "Start delay",
                .type   = FIO_OPT_STR_VAL_TIME,
                .off1   = td_var_offset(start_delay),
                .lname  = "Start delay",
                .type   = FIO_OPT_STR_VAL_TIME,
                .off1   = td_var_offset(start_delay),
+               .off2   = td_var_offset(start_delay_high),
                .help   = "Only start job when this period has passed",
                .def    = "0",
                .category = FIO_OPT_C_GENERAL,
                .help   = "Only start job when this period has passed",
                .def    = "0",
                .category = FIO_OPT_C_GENERAL,
index 65eba7eebd2e02792b835161826d4bccdc390195..b7a88ed358f14f73e9933f859a5837c6362bdded 100644 (file)
@@ -130,6 +130,7 @@ struct thread_options {
        unsigned int fdatasync_blocks;
        unsigned int barrier_blocks;
        unsigned long long start_delay;
        unsigned int fdatasync_blocks;
        unsigned int barrier_blocks;
        unsigned long long start_delay;
+       unsigned long long start_delay_high;
        unsigned long long timeout;
        unsigned long long ramp_time;
        unsigned int overwrite;
        unsigned long long timeout;
        unsigned long long ramp_time;
        unsigned int overwrite;
@@ -352,6 +353,7 @@ struct thread_options_pack {
        uint32_t fdatasync_blocks;
        uint32_t barrier_blocks;
        uint64_t start_delay;
        uint32_t fdatasync_blocks;
        uint32_t barrier_blocks;
        uint64_t start_delay;
+       uint64_t start_delay_high;
        uint64_t timeout;
        uint64_t ramp_time;
        uint32_t overwrite;
        uint64_t timeout;
        uint64_t ramp_time;
        uint32_t overwrite;