From: Jens Axboe Date: Mon, 9 Nov 2015 19:54:37 +0000 (-0700) Subject: Fixups for poisson rate X-Git-Tag: fio-2.2.12~21 X-Git-Url: https://git.kernel.dk/?p=fio.git;a=commitdiff_plain;h=e7b24047454305dd61c9b4f9f73628a03c240a9f;ds=sidebyside Fixups for poisson rate - Change name to poisson_rate, we could add other uses for this functionality (like depth, etc). - Add "rate" as option parent. - Ensure we convert the option for client/server, bump protocol version. - Add a separate rand state for poisson, so it becomes randomly controllable (through randrepeat). - Add random 0..1 helper. Signed-off-by: Jens Axboe --- diff --git a/HOWTO b/HOWTO index 81217b77..03a0060c 100644 --- a/HOWTO +++ b/HOWTO @@ -1064,6 +1064,9 @@ rate_iops_min=int If fio doesn't meet this rate of IO, it will cause the job to exit. The same format as rate is used for read vs write separation. +rate_poisson=bool When rate limited, try to simulate request flow under + Poisson process (instead of even distribution). Default: false. + latency_target=int If set, fio will attempt to find the max performance point that the given workload will run at while maintaining a latency below this target. The values is given in microseconds. diff --git a/backend.c b/backend.c index 7a030ebb..85a981dc 100644 --- a/backend.c +++ b/backend.c @@ -782,17 +782,18 @@ static long long usec_for_io(struct thread_data *td, enum fio_ddir ddir) bytes = td->rate_io_issue_bytes[ddir]; bps = td->rate_bps[ddir]; - if (td->o.poisson_request) { + if (td->o.poisson_rate) { iops = bps / td->o.bs[ddir]; - td->last_usec += (long long)(1000000 / iops) * - (-logf(((float)rand() + 1) / ((float)RAND_MAX + 1))); + td->last_usec += (int64_t) (1000000 / iops) * + -logf(__rand_0_1(&td->poisson_state)); return td->last_usec; } else if (bps) { secs = bytes / bps; remainder = bytes % bps; return remainder * 1000000 / bps + secs * 1000000; - } else - return 0; + } + + return 0; } /* diff --git a/cconv.c b/cconv.c index fde8c6de..26b90b93 100644 --- a/cconv.c +++ b/cconv.c @@ -254,6 +254,7 @@ void convert_thread_options_to_cpu(struct thread_options *o, o->per_job_logs = le32_to_cpu(top->per_job_logs); o->trim_backlog = le64_to_cpu(top->trim_backlog); + o->poisson_rate = le32_to_cpu(top->poisson_rate); for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) o->percentile_list[i].u.f = fio_uint64_to_double(le64_to_cpu(top->percentile_list[i].u.i)); @@ -474,6 +475,7 @@ void convert_thread_options_to_net(struct thread_options_pack *top, top->trim_backlog = __cpu_to_le64(o->trim_backlog); top->offset_increment = __cpu_to_le64(o->offset_increment); top->number_ios = __cpu_to_le64(o->number_ios); + top->poisson_rate = cpu_to_le32(o->poisson_rate); for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) top->percentile_list[i].u.i = __cpu_to_le64(fio_double_to_uint64(o->percentile_list[i].u.f)); diff --git a/fio.1 b/fio.1 index 2ecc3d33..99d9f9e0 100644 --- a/fio.1 +++ b/fio.1 @@ -963,8 +963,8 @@ size is used as the metric. If this rate of I/O is not met, the job will exit. The same format as \fBrate\fR is used for read vs write separation. .TP -.BI poisson \fR=\fPbool -When rate limited, try simulate request flow under Poisson process (instead +.BI rate_poisson \fR=\fPbool +When rate limited, try to simulate request flow under Poisson process (instead of even distribution). Default: false. .TP .BI ratecycle \fR=\fPint diff --git a/fio.h b/fio.h index 6bb1949f..7b198b21 100644 --- a/fio.h +++ b/fio.h @@ -95,6 +95,7 @@ enum { FIO_RAND_SEQ_RAND_TRIM_OFF, FIO_RAND_START_DELAY, FIO_DEDUPE_OFF, + FIO_RAND_POISSON_OFF, FIO_RAND_NR_OFFS, }; @@ -243,7 +244,8 @@ struct thread_data { unsigned long rate_blocks[DDIR_RWDIR_CNT]; unsigned long rate_io_issue_bytes[DDIR_RWDIR_CNT]; struct timeval lastrate[DDIR_RWDIR_CNT]; - unsigned long long last_usec; + int64_t last_usec; + struct frand_state poisson_state; /* * Enforced rate submission/completion workqueue diff --git a/init.c b/init.c index 242518cc..04b4a1e5 100644 --- a/init.c +++ b/init.c @@ -858,6 +858,7 @@ static void td_fill_rand_seeds_internal(struct thread_data *td, int use64) init_rand_seed(&td->file_size_state, td->rand_seeds[FIO_RAND_FILE_SIZE_OFF], use64); init_rand_seed(&td->trim_state, td->rand_seeds[FIO_RAND_TRIM_OFF], use64); init_rand_seed(&td->delay_state, td->rand_seeds[FIO_RAND_START_DELAY], use64); + init_rand_seed(&td->poisson_state, td->rand_seeds[FIO_RAND_POISSON_OFF], 0); if (!td_random(td)) return; diff --git a/lib/rand.h b/lib/rand.h index b99f618c..3d78115d 100644 --- a/lib/rand.h +++ b/lib/rand.h @@ -104,6 +104,19 @@ static inline uint64_t __rand(struct frand_state *state) return __rand32(&state->state32); } +static inline double __rand_0_1(struct frand_state *state) +{ + if (state->use64) { + uint64_t val = __rand64(&state->state64); + + return (double) val / (FRAND64_MAX + 1.0); + } else { + uint32_t val = __rand32(&state->state32); + + return (double) val / (FRAND32_MAX + 1.0); + } +} + extern void init_rand(struct frand_state *, int); extern void init_rand_seed(struct frand_state *, unsigned int seed, int); extern void __fill_random_buf(void *buf, unsigned int len, unsigned long seed); diff --git a/options.c b/options.c index 8198e6b4..ac41565c 100644 --- a/options.c +++ b/options.c @@ -2856,12 +2856,13 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .group = FIO_OPT_G_RATE, }, { - .name = "poisson", + .name = "rate_poisson", .lname = "simulate requests under Poisson process", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(poisson_request), - .help = "with rate limit, try simulate requests that follow Poisson process", + .off1 = td_var_offset(poisson_rate), + .help = "With rate limit, simulate requests that follow Poisson process", .def = "0", + .parent = "rate", .hide = 1, .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RATE, diff --git a/server.h b/server.h index eb29de78..6709b5fb 100644 --- a/server.h +++ b/server.h @@ -38,7 +38,7 @@ struct fio_net_cmd_reply { }; enum { - FIO_SERVER_VER = 47, + FIO_SERVER_VER = 48, FIO_SERVER_MAX_FRAGMENT_PDU = 1024, FIO_SERVER_MAX_CMD_MB = 2048, diff --git a/thread_options.h b/thread_options.h index 4c26dcb5..06707944 100644 --- a/thread_options.h +++ b/thread_options.h @@ -231,7 +231,7 @@ struct thread_options { unsigned int io_submit_mode; unsigned int rate_iops[DDIR_RWDIR_CNT]; unsigned int rate_iops_min[DDIR_RWDIR_CNT]; - unsigned int poisson_request; + unsigned int poisson_rate; char *ioscheduler; @@ -472,7 +472,7 @@ struct thread_options_pack { uint32_t io_submit_mode; uint32_t rate_iops[DDIR_RWDIR_CNT]; uint32_t rate_iops_min[DDIR_RWDIR_CNT]; - uint32_t poisson_request; + uint32_t poisson_rate; uint32_t padding_0; /* for alignment assert */ uint8_t ioscheduler[FIO_TOP_STR_MAX];