Add support for different weights for reads and writes with bssplit
authorJens Axboe <jens.axboe@oracle.com>
Tue, 21 Apr 2009 06:29:55 +0000 (08:29 +0200)
committerJens Axboe <jens.axboe@oracle.com>
Tue, 21 Apr 2009 06:29:55 +0000 (08:29 +0200)
You can now do:

bssplit=4k/20:8k/80,1k/50:4k/50

To have 20% 4k reads and 80% 8k reads, while having 50% 1k writes
and 50% 4k writes. This is identical to how the bs= option treats
reads and writes.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
HOWTO
fio.h
io_u.c
options.c

diff --git a/HOWTO b/HOWTO
index 999f777..15f576d 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -367,6 +367,15 @@ bssplit=str        Sometimes you want even finer grained control of the
                always add up to 100, if bssplit is given a range that adds
                up to more, it will error out.
 
+               bssplit also supports giving separate splits to reads and
+               writes. The format is identical to what bs= accepts. You
+               have to separate the read and write parts with a comma. So
+               if you want a workload that has 50% 2k reads and 50% 4k reads,
+               while having 90% 4k writes and 10% 8k writes, you would
+               specify:
+
+               bssplit=2k/50:4k/50,4k/90,8k/10
+
 blocksize_unaligned
 bs_unaligned   If this option is given, any byte size value within bsrange
                may be used as a block range. This typically wont work with
diff --git a/fio.h b/fio.h
index ff0068c..f5786ea 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -432,8 +432,8 @@ struct thread_options {
        unsigned int ba[2];
        unsigned int min_bs[2];
        unsigned int max_bs[2];
-       struct bssplit *bssplit;
-       unsigned int bssplit_nr;
+       struct bssplit *bssplit[2];
+       unsigned int bssplit_nr[2];
 
        unsigned int nr_files;
        unsigned int open_files;
diff --git a/io_u.c b/io_u.c
index 7108939..d92d940 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -248,7 +248,7 @@ static unsigned int get_next_buflen(struct thread_data *td, struct io_u *io_u)
                buflen = minbs;
        else {
                r = os_random_long(&td->bsrange_state);
-               if (!td->o.bssplit_nr) {
+               if (!td->o.bssplit_nr[ddir]) {
                        buflen = 1 + (unsigned int) ((double) maxbs *
                                        (r / (OS_RAND_MAX + 1.0)));
                        if (buflen < minbs)
@@ -257,8 +257,8 @@ static unsigned int get_next_buflen(struct thread_data *td, struct io_u *io_u)
                        long perc = 0;
                        unsigned int i;
 
-                       for (i = 0; i < td->o.bssplit_nr; i++) {
-                               struct bssplit *bsp = &td->o.bssplit[i];
+                       for (i = 0; i < td->o.bssplit_nr[ddir]; i++) {
+                               struct bssplit *bsp = &td->o.bssplit[ddir][i];
 
                                buflen = bsp->bs;
                                perc += bsp->perc;
index 9700110..21de222 100644 (file)
--- a/options.c
+++ b/options.c
@@ -40,21 +40,16 @@ static int bs_cmp(const void *p1, const void *p2)
        return bsp1->perc < bsp2->perc;
 }
 
-static int str_bssplit_cb(void *data, const char *input)
+static int bssplit_ddir(struct thread_data *td, int ddir, char *str)
 {
-       struct thread_data *td = data;
-       char *fname, *str, *p;
+       struct bssplit *bssplit;
        unsigned int i, perc, perc_missing;
        unsigned int max_bs, min_bs;
        long long val;
+       char *fname;
 
-       p = str = strdup(input);
-
-       strip_blank_front(&str);
-       strip_blank_end(str);
-
-       td->o.bssplit_nr = 4;
-       td->o.bssplit = malloc(4 * sizeof(struct bssplit));
+       td->o.bssplit_nr[ddir] = 4;
+       bssplit = malloc(4 * sizeof(struct bssplit));
 
        i = 0;
        max_bs = 0;
@@ -68,10 +63,9 @@ static int str_bssplit_cb(void *data, const char *input)
                /*
                 * grow struct buffer, if needed
                 */
-               if (i == td->o.bssplit_nr) {
-                       td->o.bssplit_nr <<= 1;
-                       td->o.bssplit = realloc(td->o.bssplit,
-                                               td->o.bssplit_nr
+               if (i == td->o.bssplit_nr[ddir]) {
+                       td->o.bssplit_nr[ddir] <<= 1;
+                       bssplit = realloc(bssplit, td->o.bssplit_nr[ddir]
                                                  * sizeof(struct bssplit));
                }
 
@@ -98,19 +92,19 @@ static int str_bssplit_cb(void *data, const char *input)
                if (val < min_bs)
                        min_bs = val;
 
-               td->o.bssplit[i].bs = val;
-               td->o.bssplit[i].perc = perc;
+               bssplit[i].bs = val;
+               bssplit[i].perc = perc;
                i++;
        }
 
-       td->o.bssplit_nr = i;
+       td->o.bssplit_nr[ddir] = i;
 
        /*
         * Now check if the percentages add up, and how much is missing
         */
        perc = perc_missing = 0;
-       for (i = 0; i < td->o.bssplit_nr; i++) {
-               struct bssplit *bsp = &td->o.bssplit[i];
+       for (i = 0; i < td->o.bssplit_nr[ddir]; i++) {
+               struct bssplit *bsp = &bssplit[i];
 
                if (bsp->perc == (unsigned char) -1)
                        perc_missing++;
@@ -120,7 +114,7 @@ static int str_bssplit_cb(void *data, const char *input)
 
        if (perc > 100) {
                log_err("fio: bssplit percentages add to more than 100%%\n");
-               free(td->o.bssplit);
+               free(bssplit);
                return 1;
        }
        /*
@@ -128,24 +122,58 @@ static int str_bssplit_cb(void *data, const char *input)
         * them.
         */
        if (perc_missing) {
-               for (i = 0; i < td->o.bssplit_nr; i++) {
-                       struct bssplit *bsp = &td->o.bssplit[i];
+               for (i = 0; i < td->o.bssplit_nr[ddir]; i++) {
+                       struct bssplit *bsp = &bssplit[i];
 
                        if (bsp->perc == (unsigned char) -1)
                                bsp->perc = (100 - perc) / perc_missing;
                }
        }
 
-       td->o.min_bs[DDIR_READ] = td->o.min_bs[DDIR_WRITE] = min_bs;
-       td->o.max_bs[DDIR_READ] = td->o.max_bs[DDIR_WRITE] = max_bs;
+       td->o.min_bs[ddir] = min_bs;
+       td->o.max_bs[ddir] = max_bs;
 
        /*
         * now sort based on percentages, for ease of lookup
         */
-       qsort(td->o.bssplit, td->o.bssplit_nr, sizeof(struct bssplit), bs_cmp);
+       qsort(bssplit, td->o.bssplit_nr[ddir], sizeof(struct bssplit), bs_cmp);
+       td->o.bssplit[ddir] = bssplit;
+       return 0;
+
+}
+
+static int str_bssplit_cb(void *data, const char *input)
+{
+       struct thread_data *td = data;
+       char *str, *p, *odir;
+       int ret = 0;
+
+       p = str = strdup(input);
+
+       strip_blank_front(&str);
+       strip_blank_end(str);
+
+       odir = strchr(str, ',');
+       if (odir) {
+               ret = bssplit_ddir(td, DDIR_WRITE, odir + 1);
+               if (!ret) {
+                       *odir = '\0';
+                       ret = bssplit_ddir(td, DDIR_READ, str);
+               }
+       } else {
+               char *op;
+
+               op = strdup(str);
+
+               ret = bssplit_ddir(td, DDIR_READ, str);
+               if (!ret)
+                       ret = bssplit_ddir(td, DDIR_WRITE, op);
+
+               free(op);
+       }
 
        free(p);
-       return 0;
+       return ret;
 }
 
 static int str_rw_cb(void *data, const char *str)