From 720e84ad8292ab7b3a8e264fb00db71d796600d1 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 21 Apr 2009 08:29:55 +0200 Subject: [PATCH] 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 --- HOWTO | 9 +++++++ fio.h | 4 +-- io_u.c | 6 ++--- options.c | 80 +++++++++++++++++++++++++++++++++++++------------------ 4 files changed, 68 insertions(+), 31 deletions(-) diff --git a/HOWTO b/HOWTO index 999f7778..15f576d2 100644 --- 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 ff0068ca..f5786ea6 100644 --- 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 71089390..d92d9405 100644 --- 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; diff --git a/options.c b/options.c index 97001109..21de222f 100644 --- 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) -- 2.25.1