[PATCH] Add seperate read/write block size options
authorJens Axboe <jens.axboe@oracle.com>
Fri, 3 Nov 2006 07:58:08 +0000 (08:58 +0100)
committerJens Axboe <jens.axboe@oracle.com>
Fri, 3 Nov 2006 07:58:08 +0000 (08:58 +0100)
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
HOWTO
filesetup.c
fio.c
fio.h
init.c
io_u.c
log.c
time.c

diff --git a/HOWTO b/HOWTO
index 79d31dffde05e8002397b0771f2c87193f293c09..78a9be037839b1692bdca1e64f6283daaa3aad4c 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -220,11 +220,21 @@ size=siint        The total size of file io for this job. This may describe
 
 bs=siint       The block size used for the io units. Defaults to 4k.
 
+read_bs=siint
+write_bs=siint If the workload is a mixed read-write workload, you can use
+               these options to set seperate block sizes.
+
 bsrange=irange Instead of giving a single block size, specify a range
                and fio will mix the issued io block sizes. The issued
                io unit will always be a multiple of the minimum value
                given (also see bs_unaligned).
 
+read_bsrange=irange
+write_bsrange=irange
+               If the workload is a mixed read-write workload, you can use
+               one of these options to set separate block size ranges for
+               reads and writes.
+
 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
                direct IO, as that normally requires sector alignment.
index 0b9564044d14135d662363219471c674c2670714..a1633827fe8eca63017bb8a2d91b731dd9854b73 100644 (file)
@@ -49,12 +49,12 @@ static int create_file(struct thread_data *td, struct fio_file *f)
                goto err;
        }
 
-       b = malloc(td->max_bs);
-       memset(b, 0, td->max_bs);
+       b = malloc(td->max_bs[DDIR_WRITE]);
+       memset(b, 0, td->max_bs[DDIR_WRITE]);
 
        left = f->file_size;
        while (left && !td->terminate) {
-               bs = td->max_bs;
+               bs = td->max_bs[DDIR_WRITE];
                if (bs > left)
                        bs = left;
 
diff --git a/fio.c b/fio.c
index 76710e19fba08166902c52cdb8218cda45235928..011c13a31a6e2cabea1ea4254d69b9a16604726d 100644 (file)
--- a/fio.c
+++ b/fio.c
@@ -436,7 +436,7 @@ static void do_io(struct thread_data *td)
                gettimeofday(&e, NULL);
                usec = utime_since(&s, &e);
 
-               rate_throttle(td, usec, icd.bytes_done[td->ddir]);
+               rate_throttle(td, usec, icd.bytes_done[td->ddir], td->ddir);
 
                if (check_min_rate(td, &e)) {
                        if (rate_quit)
@@ -495,6 +495,7 @@ static void fill_rand_buf(struct io_u *io_u, int max_bs)
 static int init_io_u(struct thread_data *td)
 {
        struct io_u *io_u;
+       unsigned int max_bs;
        int i, max_units;
        char *p;
 
@@ -506,7 +507,8 @@ static int init_io_u(struct thread_data *td)
        else
                max_units = td->iodepth;
 
-       td->orig_buffer_size = td->max_bs * max_units + MASK;
+       max_bs = max(td->max_bs[DDIR_READ], td->max_bs[DDIR_WRITE]);
+       td->orig_buffer_size = max_bs * max_units + MASK;
 
        if (allocate_io_mem(td))
                return 1;
@@ -517,9 +519,9 @@ static int init_io_u(struct thread_data *td)
                memset(io_u, 0, sizeof(*io_u));
                INIT_LIST_HEAD(&io_u->list);
 
-               io_u->buf = p + td->max_bs * i;
+               io_u->buf = p + max_bs * i;
                if (td_write(td) || td_rw(td))
-                       fill_rand_buf(io_u, td->max_bs);
+                       fill_rand_buf(io_u, max_bs);
 
                io_u->index = i;
                list_add(&io_u->list, &td->io_u_freelist);
diff --git a/fio.h b/fio.h
index 6a68ec8dc674b0af8b074faba0627ef9940e82ab..53e174e1b525808674143ef667960de6aad34dbd 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -205,9 +205,10 @@ struct thread_data {
        unsigned int norandommap;
        unsigned int bs_unaligned;
 
-       unsigned int bs;
-       unsigned int min_bs;
-       unsigned int max_bs;
+       unsigned int bs[2];
+       unsigned int min_bs[2];
+       unsigned int max_bs[2];
+       unsigned int rw_min_bs;
        unsigned int thinktime;
        unsigned int fsync_blocks;
        unsigned int start_delay;
@@ -364,7 +365,7 @@ extern struct thread_data *threads;
 #define td_rw(td)              ((td)->iomix != 0)
 
 #define BLOCKS_PER_MAP         (8 * sizeof(long))
-#define TO_MAP_BLOCK(td, f, b) ((b) - ((f)->file_offset / (td)->min_bs))
+#define TO_MAP_BLOCK(td, f, b) ((b) - ((f)->file_offset / (td)->rw_min_bs))
 #define RAND_MAP_IDX(td, f, b) (TO_MAP_BLOCK(td, f, b) / BLOCKS_PER_MAP)
 #define RAND_MAP_BIT(td, f, b) (TO_MAP_BLOCK(td, f, b) & (BLOCKS_PER_MAP - 1))
 
@@ -417,6 +418,9 @@ struct io_completion_data {
 #ifndef min
 #define min(a, b)      ((a) < (b) ? (a) : (b))
 #endif
+#ifndef max
+#define max(a, b)      ((a) > (b) ? (a) : (b))
+#endif
 
 /*
  * Log exports
@@ -454,7 +458,7 @@ extern unsigned long time_since_now(struct timeval *);
 extern unsigned long mtime_since_genesis(void);
 extern void __usec_sleep(unsigned int);
 extern void usec_sleep(struct thread_data *, unsigned long);
-extern void rate_throttle(struct thread_data *, unsigned long, unsigned int);
+extern void rate_throttle(struct thread_data *, unsigned long, unsigned int, int);
 
 /*
  * Init functions
diff --git a/init.c b/init.c
index 3532c49d968a7436699b8c9a3e75d9d5ed0d2a2e..616c51f27ff738e7d2d2bd3eddbf7c924d693c3b 100644 (file)
--- a/init.c
+++ b/init.c
@@ -139,7 +139,17 @@ static struct fio_option options[] = {
        {
                .name   = "bs",
                .type   = FIO_OPT_STR_VAL,
-               .off1   = td_var_offset(bs),
+               .off1   = td_var_offset(bs[DDIR_READ]),
+       },
+       {
+               .name   = "read_bs",
+               .type   = FIO_OPT_STR_VAL,
+               .off1   = td_var_offset(bs[DDIR_READ]),
+       },
+       {
+               .name   = "write_bs",
+               .type   = FIO_OPT_STR_VAL,
+               .off1   = td_var_offset(bs[DDIR_WRITE]),
        },
        {
                .name   = "offset",
@@ -164,8 +174,20 @@ static struct fio_option options[] = {
        {
                .name   = "bsrange",
                .type   = FIO_OPT_RANGE,
-               .off1   = td_var_offset(min_bs),
-               .off2   = td_var_offset(max_bs),
+               .off1   = td_var_offset(min_bs[DDIR_READ]),
+               .off2   = td_var_offset(max_bs[DDIR_READ]),
+       },
+       {
+               .name   = "read_bsrange",
+               .type   = FIO_OPT_RANGE,
+               .off1   = td_var_offset(min_bs[DDIR_READ]),
+               .off2   = td_var_offset(max_bs[DDIR_READ]),
+       },
+       {
+               .name   = "write_bsrange",
+               .type   = FIO_OPT_RANGE,
+               .off1   = td_var_offset(min_bs[DDIR_WRITE]),
+               .off2   = td_var_offset(max_bs[DDIR_WRITE]),
        },
        {
                .name   = "nrfiles",
@@ -484,10 +506,19 @@ static void fixup_options(struct thread_data *td)
        if (td_read(td) || td_rw(td))
                td->overwrite = 1;
 
-       if (!td->min_bs)
-               td->min_bs = td->bs;
-       if (!td->max_bs)
-               td->max_bs = td->bs;
+       if (td->bs[DDIR_READ] != DEF_BS)
+               td->bs[DDIR_WRITE] = td->bs[DDIR_READ];
+       if (!td->min_bs[DDIR_READ])
+               td->min_bs[DDIR_READ]= td->bs[DDIR_READ];
+       if (!td->max_bs[DDIR_READ])
+               td->max_bs[DDIR_READ] = td->bs[DDIR_READ];
+       if (!td->min_bs[DDIR_WRITE])
+               td->min_bs[DDIR_WRITE]= td->bs[DDIR_READ];
+       if (!td->max_bs[DDIR_WRITE])
+               td->max_bs[DDIR_WRITE] = td->bs[DDIR_READ];
+
+       td->rw_min_bs = min(td->min_bs[DDIR_READ], td->min_bs[DDIR_WRITE]);
+
        if (td_read(td) && !td_rw(td))
                td->verify = 0;
 
@@ -626,7 +657,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num)
                        if (td->io_ops->flags & FIO_CPUIO)
                                fprintf(f_out, "%s: ioengine=cpu, cpuload=%u, cpucycle=%u\n", td->name, td->cpuload, td->cpucycle);
                        else
-                               fprintf(f_out, "%s: (g=%d): rw=%s, odir=%d, bs=%d-%d, rate=%d, ioengine=%s, iodepth=%d\n", td->name, td->groupid, ddir_str[ddir], td->odirect, td->min_bs, td->max_bs, td->rate, td->io_ops->name, td->iodepth);
+                               fprintf(f_out, "%s: (g=%d): rw=%s, odir=%d, bs=%d-%d/%d-%d, rate=%d, ioengine=%s, iodepth=%d\n", td->name, td->groupid, ddir_str[ddir], td->odirect, td->min_bs[DDIR_READ], td->max_bs[DDIR_READ], td->min_bs[DDIR_WRITE], td->max_bs[DDIR_WRITE], td->rate, td->io_ops->name, td->iodepth);
                } else if (job_add_num == 1)
                        fprintf(f_out, "...\n");
        }
@@ -694,7 +725,7 @@ int init_random_state(struct thread_data *td)
 
        if (!td->norandommap) {
                for_each_file(td, f, i) {
-                       blocks = (f->file_size + td->min_bs - 1) / td->min_bs;
+                       blocks = (f->file_size + td->rw_min_bs - 1) / td->rw_min_bs;
                        num_maps = (blocks + BLOCKS_PER_MAP-1)/ BLOCKS_PER_MAP;
                        f->file_map = malloc(num_maps * sizeof(long));
                        f->num_maps = num_maps;
@@ -958,9 +989,10 @@ static int fill_def_thread(void)
         */
        def_thread.ddir = DDIR_READ;
        def_thread.iomix = 0;
-       def_thread.bs = DEF_BS;
-       def_thread.min_bs = 0;
-       def_thread.max_bs = 0;
+       def_thread.bs[DDIR_READ] = DEF_BS;
+       def_thread.bs[DDIR_WRITE] = DEF_BS;
+       def_thread.min_bs[DDIR_READ] = def_thread.min_bs[DDIR_WRITE] = 0;
+       def_thread.max_bs[DDIR_READ] = def_thread.max_bs[DDIR_WRITE] = 0;
        def_thread.odirect = DEF_ODIRECT;
        def_thread.ratecycle = DEF_RATE_CYCLE;
        def_thread.sequential = DEF_SEQUENTIAL;
diff --git a/io_u.c b/io_u.c
index 3000ea7a96c1c93f11969836b35718d9375c4c7d..7698e84581c3399eb771d9ecf1f5df472d688311 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -27,10 +27,13 @@ static int random_map_free(struct thread_data *td, struct fio_file *f,
 static void mark_random_map(struct thread_data *td, struct fio_file *f,
                            struct io_u *io_u)
 {
-       unsigned long long block = io_u->offset / (unsigned long long) td->min_bs;
-       unsigned int blocks = 0;
+       unsigned int min_bs = td->min_bs[io_u->ddir];
+       unsigned long long block;
+       unsigned int blocks;
 
-       while (blocks < (io_u->buflen / td->min_bs)) {
+       block = io_u->offset / (unsigned long long) min_bs;
+       blocks = 0;
+       while (blocks < (io_u->buflen / min_bs)) {
                unsigned int idx, bit;
 
                if (!random_map_free(td, f, block))
@@ -46,8 +49,8 @@ static void mark_random_map(struct thread_data *td, struct fio_file *f,
                blocks++;
        }
 
-       if ((blocks * td->min_bs) < io_u->buflen)
-               io_u->buflen = blocks * td->min_bs;
+       if ((blocks * min_bs) < io_u->buflen)
+               io_u->buflen = blocks * min_bs;
 }
 
 /*
@@ -60,7 +63,7 @@ static int get_next_free_block(struct thread_data *td, struct fio_file *f,
 
        *b = 0;
        i = 0;
-       while ((*b) * td->min_bs < f->file_size) {
+       while ((*b) * td->rw_min_bs < f->file_size) {
                if (f->file_map[i] != -1UL) {
                        *b += ffz(f->file_map[i]);
                        return 0;
@@ -79,13 +82,13 @@ static int get_next_free_block(struct thread_data *td, struct fio_file *f,
  * the last io issued.
  */
 static int get_next_offset(struct thread_data *td, struct fio_file *f,
-                          unsigned long long *offset)
+                          unsigned long long *offset, int ddir)
 {
        unsigned long long b, rb;
        long r;
 
        if (!td->sequential) {
-               unsigned long long max_blocks = td->io_size / td->min_bs;
+               unsigned long long max_blocks = td->io_size / td->min_bs[ddir];
                int loops = 50;
 
                do {
@@ -93,7 +96,7 @@ static int get_next_offset(struct thread_data *td, struct fio_file *f,
                        b = ((max_blocks - 1) * r / (unsigned long long) (RAND_MAX+1.0));
                        if (td->norandommap)
                                break;
-                       rb = b + (f->file_offset / td->min_bs);
+                       rb = b + (f->file_offset / td->min_bs[ddir]);
                        loops--;
                } while (!random_map_free(td, f, rb) && loops);
 
@@ -102,30 +105,30 @@ static int get_next_offset(struct thread_data *td, struct fio_file *f,
                                return 1;
                }
        } else
-               b = f->last_pos / td->min_bs;
+               b = f->last_pos / td->min_bs[ddir];
 
-       *offset = (b * td->min_bs) + f->file_offset;
+       *offset = (b * td->min_bs[ddir]) + f->file_offset;
        if (*offset > f->file_size)
                return 1;
 
        return 0;
 }
 
-static unsigned int get_next_buflen(struct thread_data *td)
+static unsigned int get_next_buflen(struct thread_data *td, int ddir)
 {
        unsigned int buflen;
        long r;
 
-       if (td->min_bs == td->max_bs)
-               buflen = td->min_bs;
+       if (td->min_bs[ddir] == td->max_bs[ddir])
+               buflen = td->min_bs[ddir];
        else {
                r = os_random_long(&td->bsrange_state);
-               buflen = (1 + (double) (td->max_bs - 1) * r / (RAND_MAX + 1.0));
+               buflen = (1 + (double) (td->max_bs[ddir] - 1) * r / (RAND_MAX + 1.0));
                if (!td->bs_unaligned)
-                       buflen = (buflen + td->min_bs - 1) & ~(td->min_bs - 1);
+                       buflen = (buflen + td->min_bs[ddir] - 1) & ~(td->min_bs[ddir] - 1);
        }
 
-       if (buflen > td->io_size - td->this_io_bytes[td->ddir]) {
+       if (buflen > td->io_size - td->this_io_bytes[ddir]) {
                /*
                 * if using direct/raw io, we may not be able to
                 * shrink the size. so just fail it.
@@ -133,7 +136,7 @@ static unsigned int get_next_buflen(struct thread_data *td)
                if (td->io_ops->flags & FIO_RAWIO)
                        return 0;
 
-               buflen = td->io_size - td->this_io_bytes[td->ddir];
+               buflen = td->io_size - td->this_io_bytes[ddir];
        }
 
        return buflen;
@@ -202,15 +205,14 @@ static int fill_io_u(struct thread_data *td, struct fio_file *f,
                return 0;
        }
 
+       io_u->ddir = get_rw_ddir(td);
+
        /*
         * No log, let the seq/rand engine retrieve the next position.
         */
-       if (!get_next_offset(td, f, &io_u->offset)) {
-               io_u->buflen = get_next_buflen(td);
-
+       if (!get_next_offset(td, f, &io_u->offset, io_u->ddir)) {
+               io_u->buflen = get_next_buflen(td, io_u->ddir);
                if (io_u->buflen) {
-                       io_u->ddir = get_rw_ddir(td);
-
                        /*
                         * If using a write iolog, store this entry.
                         */
diff --git a/log.c b/log.c
index b151164760a40042e403bfc422245fe83afdab68..a112a31ac8fa065b23544acdd7fc0883606ef27b 100644 (file)
--- a/log.c
+++ b/log.c
@@ -125,9 +125,9 @@ static int init_iolog_read(struct thread_data *td)
                INIT_LIST_HEAD(&ipo->list);
                ipo->offset = offset;
                ipo->len = bytes;
-               if (bytes > td->max_bs)
-                       td->max_bs = bytes;
                ipo->ddir = rw;
+               if (bytes > td->max_bs[rw])
+                       td->max_bs[rw] = bytes;
                list_add_tail(&ipo->list, &td->io_log_list);
        }
 
@@ -195,7 +195,7 @@ int setup_rate(struct thread_data *td)
                return -1;
        }
 
-       nr_reads_per_sec = (td->rate * 1024) / td->min_bs;
+       nr_reads_per_sec = (td->rate * 1024) / td->min_bs[DDIR_READ];
        td->rate_usec_cycle = 1000000 / nr_reads_per_sec;
        td->rate_pending_usleep = 0;
        return 0;
diff --git a/time.c b/time.c
index ad5ee3fe51773c9019067f593834428afad8fc9b..5d3dee20e8b6337109005efe507b96c549708ace 100644 (file)
--- a/time.c
+++ b/time.c
@@ -99,14 +99,14 @@ void usec_sleep(struct thread_data *td, unsigned long usec)
 }
 
 void rate_throttle(struct thread_data *td, unsigned long time_spent,
-                  unsigned int bytes)
+                  unsigned int bytes, int ddir)
 {
        unsigned long usec_cycle;
 
        if (!td->rate)
                return;
 
-       usec_cycle = td->rate_usec_cycle * (bytes / td->min_bs);
+       usec_cycle = td->rate_usec_cycle * (bytes / td->min_bs[ddir]);
 
        if (time_spent < usec_cycle) {
                unsigned long s = usec_cycle - time_spent;