Add option to select how to service multiple files
authorJens Axboe <jens.axboe@oracle.com>
Fri, 23 Feb 2007 07:45:55 +0000 (08:45 +0100)
committerJens Axboe <jens.axboe@oracle.com>
Fri, 23 Feb 2007 07:45:55 +0000 (08:45 +0100)
Right now we just round robin the open files, but sometimes you
just want to randomly go through the files. Add a 'file_service'
option for that, default to round robin still.

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

diff --git a/fio.h b/fio.h
index 959e52f3d032f332a3f67f22287228fdac7b68fa..8c46b3f905b2d9eb5b320ca96d05e2b8117b8e8d 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -280,7 +280,10 @@ struct thread_data {
        struct fio_file *files;
        unsigned int nr_files;
        unsigned int nr_uniq_files;
-       unsigned int next_file;
+       union {
+               unsigned int next_file;
+               os_random_state_t next_file_state;
+       };
        int error;
        pid_t pid;
        char *orig_buffer;
@@ -340,6 +343,7 @@ struct thread_data {
        unsigned int rwmixread;
        unsigned int rwmixwrite;
        unsigned int nice;
+       unsigned int file_service_type;
 
        char *read_iolog_file;
        char *write_iolog_file;
@@ -436,6 +440,14 @@ struct thread_data {
        struct itimerval timer;
 };
 
+/*
+ * roundrobin available files, or choose one at random.
+ */
+enum {
+       FIO_FSERVICE_RANDOM     = 1,
+       FIO_FSERVICE_RR         = 2,
+};
+
 /*
  * 30 second per-io_u timeout, with 5 second intervals to avoid resetting
  * the timer on each queue operation.
diff --git a/init.c b/init.c
index c8f27ade76e7f2aafaef4e98320d189c2a26e347..01e615f92e90e1f37864e591279f037c8ddba55c 100644 (file)
--- a/init.c
+++ b/init.c
@@ -33,6 +33,7 @@ static int str_prioclass_cb(void *, unsigned int *);
 #endif
 static int str_exitall_cb(void);
 static int str_cpumask_cb(void *, unsigned int *);
+static int str_file_service_cb(void *, const char *);
 
 #define __stringify_1(x)       #x
 #define __stringify(x)         __stringify_1(x)
@@ -152,6 +153,14 @@ static struct fio_option options[] = {
                .help   = "Split job workload between this number of files",
                .def    = "1",
        },
+       {
+               .name   = "file_service_type",
+               .type   = FIO_OPT_STR,
+               .cb     = str_file_service_cb,
+               .help   = "How to select which file to service next",
+               .def    = "roundrobin",
+               .posval = { "random", "roundrobin" },
+       },
        {
                .name   = "fsync",
                .type   = FIO_OPT_INT,
@@ -841,7 +850,7 @@ err:
  */
 int init_random_state(struct thread_data *td)
 {
-       unsigned long seeds[4];
+       unsigned long seeds[5];
        int fd, num_maps, blocks, i;
        struct fio_file *f;
 
@@ -865,12 +874,13 @@ int init_random_state(struct thread_data *td)
        os_random_seed(seeds[0], &td->bsrange_state);
        os_random_seed(seeds[1], &td->verify_state);
        os_random_seed(seeds[2], &td->rwmix_state);
+       os_random_seed(seeds[3], &td->next_file_state);
 
        if (td->sequential)
                return 0;
 
        if (td->rand_repeatable)
-               seeds[3] = FIO_RANDSEED * td->thread_number;
+               seeds[4] = FIO_RANDSEED * td->thread_number;
 
        if (!td->norandommap) {
                for_each_file(td, f, i) {
@@ -882,7 +892,7 @@ int init_random_state(struct thread_data *td)
                }
        }
 
-       os_random_seed(seeds[3], &td->random_state);
+       os_random_seed(seeds[4], &td->random_state);
        return 0;
 }
 
@@ -1087,6 +1097,22 @@ static int str_cpumask_cb(void *data, unsigned int *val)
        return 0;
 }
 
+static int str_file_service_cb(void *data, const char *str)
+{
+       struct thread_data *td = data;
+
+       if (!strncmp(str, "random", 6)) {
+               td->file_service_type = FIO_FSERVICE_RANDOM;
+               return 0;
+       } else if (!strncmp(str, "roundrobin", 10)) {
+               td->file_service_type = FIO_FSERVICE_RR;
+               return 0;
+       }
+
+       log_err("fio: file_service= random, roundrobin\n");
+       return 1;
+}
+
 /*
  * This is our [ini] type file parser.
  */
diff --git a/io_u.c b/io_u.c
index ab85193d1c95166dfcbd4eeea45a28637c788d4c..6fb754e7f44701cbfddc628abe4f7164eeccd1aa 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -325,7 +325,27 @@ static void io_u_mark_latency(struct thread_data *td, unsigned long msec)
        td->io_u_lat[index]++;
 }
 
-static struct fio_file *get_next_file(struct thread_data *td)
+/*
+ * Get next file to service by choosing one at random
+ */
+static struct fio_file *get_next_file_rand(struct thread_data *td)
+{
+       long r = os_random_long(&td->next_file_state);
+       unsigned int fileno;
+       struct fio_file *f;
+
+       do {
+               fileno = (unsigned int) ((double) (td->nr_files - 1) * r / (RAND_MAX + 1.0));
+               f = &td->files[fileno];
+               if (f->fd != -1)
+                       return f;
+       } while (1);
+}
+
+/*
+ * Get next file to service by doing round robin between all available ones
+ */
+static struct fio_file *get_next_file_rr(struct thread_data *td)
 {
        unsigned int old_next_file = td->next_file;
        struct fio_file *f;
@@ -393,7 +413,11 @@ struct io_u *get_io_u(struct thread_data *td)
        if (io_u->file)
                goto out;
 
-       f = get_next_file(td);
+       if (td->file_service_type == FIO_FSERVICE_RR)
+               f = get_next_file_rr(td);
+       else
+               f = get_next_file_rand(td);
+
        if (!f) {
                put_io_u(td, io_u);
                return NULL;