Add support for randomness of any IO direction
authorJens Axboe <axboe@kernel.dk>
Thu, 25 Jul 2013 16:20:45 +0000 (10:20 -0600)
committerJens Axboe <axboe@kernel.dk>
Thu, 25 Jul 2013 16:20:45 +0000 (10:20 -0600)
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 <axboe@kernel.dk>
HOWTO
cconv.c
fio.1
fio.h
init.c
io_u.c
options.c
parse.c
server.h
thread_options.h

diff --git a/HOWTO b/HOWTO
index a2de47067cdd11ba4ca541cae8e46910c083cda6..8768b99670a1a09e97b748bbfa6e4a6a0cab1a19 100644 (file)
--- 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 b06f60f4ad784692e734a6920184f5858623f9cc..9de4e25dbcf95eb5f03c9b9541e3d36df9c669b3 100644 (file)
--- 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 62f7bb65a4bdd90cf35debbd002b04e63129a5ff..f6d08313810aa84cd750416a4258d45e61194ea2 100644 (file)
--- 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 8c67fccb8d3dcea029ea3710874efb9c63e2876c..e7d5c27c8420de2fae7b25ed784e96e61336869e 100644 (file)
--- 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 d808eb679a5c31eb1c89897c21fa894216f6ab01..b0a7c35d95cece669387cc40b2dae986a25b05a6 100644 (file)
--- 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 865c58260d976b916cc2d526a84609c968ca5132..8401719c883035b4b7450b05823e75fc3620f17b 100644 (file)
--- 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;
index 1c44f426dcbde350f6bff5479e31aeee37b7702f..3da376e042aedd333bd8e7605c55b3795ae1d392 100644 (file)
--- 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 d3eb2c4af7d08d8dcdc7c63cbe85fd7300883bbe..5e3573ea646fcb52ca1b08d043712d2c89efb0c6 100644 (file)
--- 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);
index 46745aa2bbd158c966d0d257e4fb41fc8b085cdc..2f41be0923c0bde215919fd0f6220c441dad0855 100644 (file)
--- 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,
 
index 45e22ae45cd67fff8f662b6cc3a1b76208d04ee3..32677e2e3528d3d38734bc8ac401431fc647e9f7 100644 (file)
@@ -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;