Switch to using our internal Tausworthe based random generator for offsets
authorJens Axboe <jaxboe@fusionio.com>
Mon, 28 Mar 2011 07:35:09 +0000 (09:35 +0200)
committerJens Axboe <jaxboe@fusionio.com>
Mon, 28 Mar 2011 07:35:09 +0000 (09:35 +0200)
It's both faster and more exhaustive than what is available on
glibc on my test systems. So no downsides, and the upside of having
the same offset generator across all platforms.

This will change the random series, so could alter performance for
your workload since the pattern will be different in sequence. There's
an option to revert to the OS generator, you can add use_us_rand=1
on your job files to retain the old generator offsets.

Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
HOWTO
fio.1
fio.h
init.c
io_u.c
lib/rand.c
lib/rand.h
options.c

diff --git a/HOWTO b/HOWTO
index d4e7092..69b8cc6 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -348,6 +348,12 @@ kb_base=int        The base unit for a kilobyte. The defacto base is 2^10, 1024.
 randrepeat=bool        For random IO workloads, seed the generator in a predictable
                way so that results are repeatable across repetitions.
 
+use_os_rand=bool Fio can either use the random generator supplied by the OS
+               to generator random offsets, or it can use it's own internal
+               generator (based on Tausworthe). Default is to use the
+               internal generator, which is often of better quality and
+               faster.
+
 fallocate=bool By default, fio will use fallocate() to advise the system
                of the size of the file we are going to write. This can be
                turned off with fallocate=0. May not be available on all
diff --git a/fio.1 b/fio.1
index a8c0027..0ced604 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -214,6 +214,12 @@ reasons. Allow values are 1024 or 1000, with 1024 being the default.
 Seed the random number generator in a predictable way so results are repeatable
 across runs.  Default: true.
 .TP
+.BI use_os_rand \fR=\fPbool
+Fio can either use the random generator supplied by the OS to generator random
+offsets, or it can use it's own internal generator (based on Tausworthe).
+Default is to use the internal generator, which is often of better quality and
+faster. Default: false.
+.TP
 .BI fallocate \fR=\fPbool
 By default, fio will use fallocate() to advise the system of the size of the
 file we are going to write. This can be turned off with fallocate=0. May not
diff --git a/fio.h b/fio.h
index 08f1733..e5607bc 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -34,6 +34,7 @@ struct thread_data;
 #include "profile.h"
 #include "time.h"
 #include "lib/getopt.h"
+#include "lib/rand.h"
 
 #ifdef FIO_HAVE_GUASI
 #include <guasi.h>
@@ -206,6 +207,7 @@ struct thread_options {
        unsigned int do_disk_util;
        unsigned int override_sync;
        unsigned int rand_repeatable;
+       unsigned int use_os_rand;
        unsigned int write_lat_log;
        unsigned int write_bw_log;
        unsigned int norandommap;
@@ -416,6 +418,7 @@ struct thread_data {
         * State for random io, a bitmap of blocks done vs not done
         */
        os_random_state_t random_state;
+       struct frand_state __random_state;
 
        struct timeval start;   /* start of this loop */
        struct timeval epoch;   /* time job was started */
diff --git a/init.c b/init.c
index 327a3c5..2ae93a0 100644 (file)
--- a/init.c
+++ b/init.c
@@ -482,6 +482,7 @@ void td_fill_rand_seeds(struct thread_data *td)
                td->rand_seeds[4] = FIO_RANDSEED * td->thread_number;
 
        os_random_seed(td->rand_seeds[4], &td->random_state);
+       init_rand_seed(&td->__random_state, td->rand_seeds[4]);
 }
 
 /*
diff --git a/io_u.c b/io_u.c
index 5a3ca74..e9ce37e 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -168,9 +168,16 @@ static int get_next_rand_offset(struct thread_data *td, struct fio_file *f,
                goto ffz;
 
        do {
-               r = os_random_long(&td->random_state);
+               if (td->o.use_os_rand) {
+                       r = os_random_long(&td->random_state);
+                       *b = (lastb - 1) * (r / ((unsigned long long) OS_RAND_MAX + 1.0));
+               } else {
+                       r = __rand(&td->__random_state);
+                       *b = (lastb - 1) * (r / ((unsigned long long) FRAND_MAX + 1.0));
+               }
+
                dprint(FD_RANDOM, "off rand %llu\n", r);
-               *b = (lastb - 1) * (r / ((unsigned long long) OS_RAND_MAX + 1.0));
+
 
                /*
                 * if we are not maintaining a random map, we are done.
index 0681282..3b2d67a 100644 (file)
@@ -43,20 +43,28 @@ static inline int __seed(unsigned int x, unsigned int m)
        return (x < m) ? x + m : x;
 }
 
+static void __init_rand(struct frand_state *state, unsigned int seed)
+{
+       int cranks = 6;
+
+#define LCG(x, seed)  ((x) * 69069 ^ (seed))
+
+       state->s1 = __seed(LCG((2^31) + (2^17) + (2^7), seed), 1);
+       state->s2 = __seed(LCG(state->s1, seed), 7);
+       state->s3 = __seed(LCG(state->s2, seed), 15);
+
+       while (cranks--)
+               __rand(state);
+}
+
 void init_rand(struct frand_state *state)
 {
-#define LCG(x)  ((x) * 69069)   /* super-duper LCG */
-
-       state->s1 = __seed(LCG((2^31) + (2^17) + (2^7)), 1);
-       state->s2 = __seed(LCG(state->s1), 7);
-       state->s3 = __seed(LCG(state->s2), 15);
-
-       __rand(state);
-       __rand(state);
-       __rand(state);
-       __rand(state);
-       __rand(state);
-       __rand(state);
+       __init_rand(state, 1);
+}
+
+void init_rand_seed(struct frand_state *state, unsigned int seed)
+{
+       __init_rand(state, seed);
 }
 
 void __fill_random_buf(void *buf, unsigned int len, unsigned long seed)
index 02e6858..f80c111 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef FIO_RAND_H
 #define FIO_RAND_H
 
+#define FRAND_MAX      (-1U)
+
 struct frand_state {
        unsigned int s1, s2, s3;
 };
@@ -19,6 +21,7 @@ static inline unsigned int __rand(struct frand_state *state)
 }
 
 extern void init_rand(struct frand_state *);
+extern void init_rand_seed(struct frand_state *, unsigned int seed);
 extern void __fill_random_buf(void *buf, unsigned int len, unsigned long seed);
 extern unsigned long fill_random_buf(void *buf, unsigned int len);
 
index 55d11ae..28a17cf 100644 (file)
--- a/options.c
+++ b/options.c
@@ -1115,6 +1115,14 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                .def    = "1",
                .parent = "rw",
        },
+       {
+               .name   = "use_os_rand",
+               .type   = FIO_OPT_BOOL,
+               .off1   = td_var_offset(use_os_rand),
+               .help   = "Set to use OS random generator",
+               .def    = "0",
+               .parent = "rw",
+       },
        {
                .name   = "norandommap",
                .type   = FIO_OPT_STR_SET,