From: Jens Axboe Date: Thu, 25 Jul 2013 16:20:45 +0000 (-0600) Subject: Add support for randomness of any IO direction X-Git-Tag: fio-2.1.2~24 X-Git-Url: https://git.kernel.dk/?p=fio.git;a=commitdiff_plain;h=d94722713ebd7bbdbf8b284b7563f2dd17964e24 Add support for randomness of any IO direction sequential_random used to be applied to all of the IO directions, with no possibility of having different settings for reads, writes, and trims. Now it supports setting each of them individually. By default, if you do: sequential_random=50 it will still apply to all three. If you do: sequential_random=10,90,80 you would get reads 10% random, writes 90% random, and trims 80% random. Signed-off-by: Jens Axboe --- diff --git a/HOWTO b/HOWTO index a2de4706..8768b996 100644 --- a/HOWTO +++ b/HOWTO @@ -443,9 +443,11 @@ bs=int The block size used for the io units. Defaults to 4k. Values can be given for both read and writes. If a single int is given, it will apply to both. If a second int is specified after a comma, it will apply to writes only. In other words, - the format is either bs=read_and_write or bs=read,write. - bs=4k,8k will thus use 4k blocks for reads, and 8k blocks - for writes. If you only wish to set the write size, you + the format is either bs=read_and_write or bs=read,write,trim. + bs=4k,8k will thus use 4k blocks for reads, 8k blocks for + writes, and 8k for trims. You can terminate the list with + a trailing comma. bs=4k,8k, would use the default value for + trims.. If you only wish to set the write size, you can do so by passing an empty read size - bs=,8k will set 8k for writes and leave the read default value. @@ -773,12 +775,10 @@ percentage_random=int For a random workload, set how big a percentage should is fully random. It can be set from anywhere from 0 to 100. Setting it to 0 would make the workload fully sequential. Any setting in between will result in a random mix of sequential - and random IO, at the given percentages. + and random IO, at the given percentages. It is possible to + set different values for reads, writes, and trim. To do so, + simply use a comma separated list. See blocksize. -percentage_sequential=int See percentage_random. It is guaranteed that - they add up to 100. The later setting has priority, each - will adjust the other. - norandommap Normally fio will cover every block of the file when doing random IO. If this option is given, fio will just get a new random offset without looking at past io history. This diff --git a/cconv.c b/cconv.c index b06f60f4..9de4e25d 100644 --- a/cconv.c +++ b/cconv.c @@ -80,6 +80,8 @@ void convert_thread_options_to_cpu(struct thread_options *o, o->ratemin[i] = le32_to_cpu(top->ratemin[i]); o->rate_iops[i] = le32_to_cpu(top->rate_iops[i]); o->rate_iops_min[i] = le32_to_cpu(top->rate_iops_min[i]); + + o->perc_rand[i] = le32_to_cpu(top->perc_rand[i]); } o->ratecycle = le32_to_cpu(top->ratecycle); @@ -125,7 +127,6 @@ void convert_thread_options_to_cpu(struct thread_options *o, o->zipf_theta.u.f = fio_uint64_to_double(le64_to_cpu(top->zipf_theta.u.i)); o->pareto_h.u.f = fio_uint64_to_double(le64_to_cpu(top->pareto_h.u.i)); o->random_generator = le32_to_cpu(top->random_generator); - o->perc_rand = le32_to_cpu(top->perc_rand); o->hugepage_size = le32_to_cpu(top->hugepage_size); o->rw_min_bs = le32_to_cpu(top->rw_min_bs); o->thinktime = le32_to_cpu(top->thinktime); @@ -284,7 +285,6 @@ void convert_thread_options_to_net(struct thread_options_pack *top, top->zipf_theta.u.i = __cpu_to_le64(fio_double_to_uint64(o->zipf_theta.u.f)); top->pareto_h.u.i = __cpu_to_le64(fio_double_to_uint64(o->pareto_h.u.f)); top->random_generator = cpu_to_le32(o->random_generator); - top->perc_rand = cpu_to_le32(o->perc_rand); top->hugepage_size = cpu_to_le32(o->hugepage_size); top->rw_min_bs = cpu_to_le32(o->rw_min_bs); top->thinktime = cpu_to_le32(o->thinktime); @@ -371,6 +371,8 @@ void convert_thread_options_to_net(struct thread_options_pack *top, top->ratemin[i] = cpu_to_le32(o->ratemin[i]); top->rate_iops[i] = cpu_to_le32(o->rate_iops[i]); top->rate_iops_min[i] = cpu_to_le32(o->rate_iops_min[i]); + + top->perc_rand[i] = cpu_to_le32(o->perc_rand[i]); } memcpy(top->verify_pattern, o->verify_pattern, MAX_PATTERN_SIZE); diff --git a/fio.1 b/fio.1 index 62f7bb65..f6d08313 100644 --- a/fio.1 +++ b/fio.1 @@ -344,9 +344,10 @@ that is given). If \fBfilesize\fR is not specified, each created file is the same size. .TP .BI blocksize \fR=\fPint[,int] "\fR,\fB bs" \fR=\fPint[,int] -Block size for I/O units. Default: 4k. Values for reads and writes can be -specified separately in the format \fIread\fR,\fIwrite\fR, either of -which may be empty to leave that value at its default. +Block size for I/O units. Default: 4k. Values for reads, writes, and trims +can be specified separately in the format \fIread\fR,\fIwrite\fR,\fItrim\fR +either of which may be empty to leave that value at its default. If a trailing +comma isn't given, the remainder will inherit the last value set. .TP .BI blocksize_range \fR=\fPirange[,irange] "\fR,\fB bsrange" \fR=\fPirange[,irange] Specify a range of I/O block sizes. The issued I/O unit will always be a @@ -648,10 +649,8 @@ fio will disable use of the random map. For a random workload, set how big a percentage should be random. This defaults to 100%, in which case the workload is fully random. It can be set from anywhere from 0 to 100. Setting it to 0 would make the workload fully -sequential. -.TP -.BI percentage_sequential \fR=\fPint -See \fBpercentage_random\fR. +sequential. It is possible to set different values for reads, writes, and +trim. To do so, simply use a comma separated list. See \fBblocksize\fR. .TP .B norandommap Normally \fBfio\fR will cover every block of the file when doing random I/O. If diff --git a/fio.h b/fio.h index 8c67fccb..e7d5c27c 100644 --- a/fio.h +++ b/fio.h @@ -82,7 +82,9 @@ enum { FIO_RAND_FILE_SIZE_OFF, FIO_RAND_TRIM_OFF, FIO_RAND_BUF_OFF, - FIO_RAND_SEQ_RAND_OFF, + FIO_RAND_SEQ_RAND_READ_OFF, + FIO_RAND_SEQ_RAND_WRITE_OFF, + FIO_RAND_SEQ_RAND_TRIM_OFF, FIO_RAND_NR_OFFS, }; @@ -261,8 +263,8 @@ struct thread_data { * rand/seq mixed workload state */ union { - os_random_state_t seq_rand_state; - struct frand_state __seq_rand_state; + os_random_state_t seq_rand_state[DDIR_RWDIR_CNT]; + struct frand_state __seq_rand_state[DDIR_RWDIR_CNT]; }; /* diff --git a/init.c b/init.c index d808eb67..b0a7c35d 100644 --- a/init.c +++ b/init.c @@ -413,7 +413,7 @@ static int fixed_block_size(struct thread_options *o) static int fixup_options(struct thread_data *td) { struct thread_options *o = &td->o; - int ret = 0; + int i, ret = 0; #ifndef FIO_HAVE_PSHARED_MUTEX if (!o->use_thread) { @@ -701,7 +701,10 @@ static void td_fill_rand_seeds_os(struct thread_data *td) td->rand_seeds[FIO_RAND_BLOCK_OFF] = FIO_RANDSEED * td->thread_number; os_random_seed(td->rand_seeds[FIO_RAND_BLOCK_OFF], &td->random_state); - os_random_seed(td->rand_seeds[FIO_RAND_SEQ_RAND_OFF], &td->seq_rand_state); + + os_random_seed(td->rand_seeds[FIO_RAND_SEQ_RAND_READ_OFF], &td->seq_rand_state[DDIR_READ]); + os_random_seed(td->rand_seeds[FIO_RAND_SEQ_RAND_WRITE_OFF], &td->seq_rand_state[DDIR_WRITE]); + os_random_seed(td->rand_seeds[FIO_RAND_SEQ_RAND_TRIM_OFF], &td->seq_rand_state[DDIR_TRIM]); } static void td_fill_rand_seeds_internal(struct thread_data *td) @@ -723,7 +726,9 @@ static void td_fill_rand_seeds_internal(struct thread_data *td) td->rand_seeds[FIO_RAND_BLOCK_OFF] = FIO_RANDSEED * td->thread_number; init_rand_seed(&td->__random_state, td->rand_seeds[FIO_RAND_BLOCK_OFF]); - init_rand_seed(&td->__seq_rand_state, td->rand_seeds[FIO_RAND_SEQ_RAND_OFF]); + init_rand_seed(&td->__seq_rand_state[DDIR_READ], td->rand_seeds[FIO_RAND_SEQ_RAND_READ_OFF]); + init_rand_seed(&td->__seq_rand_state[DDIR_WRITE], td->rand_seeds[FIO_RAND_SEQ_RAND_WRITE_OFF]); + init_rand_seed(&td->__seq_rand_state[DDIR_TRIM], td->rand_seeds[FIO_RAND_SEQ_RAND_TRIM_OFF]); } void td_fill_rand_seeds(struct thread_data *td) diff --git a/io_u.c b/io_u.c index 865c5826..8401719c 100644 --- a/io_u.c +++ b/io_u.c @@ -191,23 +191,23 @@ static inline int should_sort_io(struct thread_data *td) return 1; } -static int should_do_random(struct thread_data *td) +static int should_do_random(struct thread_data *td, enum fio_ddir ddir) { unsigned int v; unsigned long r; - if (td->o.perc_rand == 100) + if (td->o.perc_rand[ddir] == 100) return 1; if (td->o.use_os_rand) { - r = os_random_long(&td->seq_rand_state); + r = os_random_long(&td->seq_rand_state[ddir]); v = 1 + (int) (100.0 * (r / (OS_RAND_MAX + 1.0))); } else { - r = __rand(&td->__seq_rand_state); + r = __rand(&td->__seq_rand_state[ddir]); v = 1 + (int) (100.0 * (r / (FRAND_MAX + 1.0))); } - return v <= td->o.perc_rand; + return v <= td->o.perc_rand[ddir]; } static int get_next_rand_offset(struct thread_data *td, struct fio_file *f, @@ -305,7 +305,7 @@ static int get_next_block(struct thread_data *td, struct io_u *io_u, if (rw_seq) { if (td_random(td)) { - if (should_do_random(td)) + if (should_do_random(td, ddir)) ret = get_next_rand_block(td, f, ddir, &b); else { io_u->flags |= IO_U_F_BUSY_OK; diff --git a/options.c b/options.c index 1c44f426..3da376e0 100644 --- a/options.c +++ b/options.c @@ -377,23 +377,6 @@ static int str_rwmix_write_cb(void *data, unsigned long long *val) return 0; } -static int str_perc_rand_cb(void *data, unsigned long long *val) -{ - struct thread_data *td = data; - - td->o.perc_rand = *val; - return 0; -} - -static int str_perc_seq_cb(void *data, unsigned long long *val) -{ - struct thread_data *td = data; - - td->o.perc_rand = 100 - *val; - return 0; -} - - static int str_exitall_cb(void) { exitall_on_terminate = 1; @@ -1669,10 +1652,12 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "percentage_random", .lname = "Percentage Random", .type = FIO_OPT_INT, - .cb = str_perc_rand_cb, + .off1 = td_var_offset(perc_rand[DDIR_READ]), + .off2 = td_var_offset(perc_rand[DDIR_WRITE]), + .off3 = td_var_offset(perc_rand[DDIR_TRIM]), .maxval = 100, .help = "Percentage of seq/random mix that should be random", - .def = "100", + .def = "100,100,100", .interval = 5, .inverse = "percentage_sequential", .category = FIO_OPT_C_IO, @@ -1681,13 +1666,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "percentage_sequential", .lname = "Percentage Sequential", - .type = FIO_OPT_INT, - .cb = str_perc_seq_cb, - .maxval = 100, - .help = "Percentage of seq/random mix that should be sequential", - .def = "0", - .interval = 5, - .inverse = "percentage_random", + .type = FIO_OPT_DEPRECATED, .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RANDOM, }, diff --git a/parse.c b/parse.c index d3eb2c4a..5e3573ea 100644 --- a/parse.c +++ b/parse.c @@ -788,6 +788,7 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, } case FIO_OPT_DEPRECATED: log_info("Option %s is deprecated\n", o->name); + ret = 1; break; default: log_err("Bad option type %u\n", o->type); diff --git a/server.h b/server.h index 46745aa2..2f41be09 100644 --- a/server.h +++ b/server.h @@ -38,7 +38,7 @@ struct fio_net_cmd_reply { }; enum { - FIO_SERVER_VER = 23, + FIO_SERVER_VER = 24, FIO_SERVER_MAX_FRAGMENT_PDU = 1024, diff --git a/thread_options.h b/thread_options.h index 45e22ae4..32677e2e 100644 --- a/thread_options.h +++ b/thread_options.h @@ -113,7 +113,7 @@ struct thread_options { unsigned int random_generator; - unsigned int perc_rand; + unsigned int perc_rand[DDIR_RWDIR_CNT]; unsigned int hugepage_size; unsigned int rw_min_bs; @@ -324,7 +324,7 @@ struct thread_options_pack { uint32_t random_generator; - uint32_t perc_rand; + uint32_t perc_rand[DDIR_RWDIR_CNT]; uint32_t hugepage_size; uint32_t rw_min_bs;