From 23ed19b0e10749dca2389511f78d89db886c064a Mon Sep 17 00:00:00 2001 From: Christian Ehrhardt Date: Thu, 20 Feb 2014 09:07:02 -0800 Subject: [PATCH] fio: provide an option for a startdelay range 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 Signed-off-by: Jens Axboe --- cconv.c | 2 ++ fio.1 | 8 ++++++-- fio.h | 5 +++++ init.c | 25 +++++++++++++++++++++++++ options.c | 1 + thread_options.h | 2 ++ 6 files changed, 41 insertions(+), 2 deletions(-) diff --git a/cconv.c b/cconv.c index 41ef6265..fd8d0ad8 100644 --- 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->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); @@ -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->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); diff --git a/fio.1 b/fio.1 index a16d0398..2320ba34 100644 --- 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 -.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. diff --git a/fio.h b/fio.h index cda46686..75ed804b 100644 --- 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_START_DELAY, FIO_RAND_NR_OFFS, }; @@ -164,6 +165,10 @@ struct thread_data { 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; diff --git a/init.c b/init.c index c3b33dcc..9d3c9608 100644 --- 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]; } + +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. @@ -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->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, " @@ -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_START_DELAY], &td->delay_state); 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->__delay_state, td->rand_seeds[FIO_RAND_START_DELAY]); if (!td_random(td)) return; diff --git a/options.c b/options.c index 4a68c01b..5b97ec41 100644 --- 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), + .off2 = td_var_offset(start_delay_high), .help = "Only start job when this period has passed", .def = "0", .category = FIO_OPT_C_GENERAL, diff --git a/thread_options.h b/thread_options.h index 65eba7ee..b7a88ed3 100644 --- a/thread_options.h +++ b/thread_options.h @@ -130,6 +130,7 @@ struct thread_options { 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; @@ -352,6 +353,7 @@ struct thread_options_pack { 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; -- 2.25.1