Add support for different weights for reads and writes with bssplit
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>
diff --git a/HOWTO b/HOWTO
index 999f777..15f576d 100644
--- a/HOWTO
+++ b/HOWTO
@@ -367,6 +367,15 @@
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
--- a/fio.h
+++ b/fio.h
@@ -432,8 +432,8 @@
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
--- a/io_u.c
+++ b/io_u.c
@@ -248,7 +248,7 @@
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 @@
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;
diff --git a/options.c b/options.c
index 9700110..21de222 100644
--- a/options.c
+++ b/options.c
@@ -40,21 +40,16 @@
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 @@
/*
* 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 @@
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 @@
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 @@
* 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)