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 d4e70923facf5b0b3ed322a551bee9a445fc3046..69b8cc6766850b6ceab07a0c15ea7e872142838e 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 a8c0027b15ff3a1cac220a94bf7b750009b481af..0ced604de4f82b0fadb7345b34e61735d46a0b01 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 08f17331d081ef6e086c34f9615fb6d3dfe8d225..e5607bc7a7ec9d7b034e9d05d5f51dde3366c02a 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 327a3c5edc6a78e171f9a2cdeb50613f75db2d01..2ae93a026f2aad21025ea3eae8bfc1491646062b 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 5a3ca7444946751f4e208a32affdad5fb98051b9..e9ce37ef6804670371d86e4833181c6cbc6abc64 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 06812823994d45cfe744351095af015d5858fbae..3b2d67ad6e9ebc4a242b24c162f94aa667a11743 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 02e68585420b942fb7805375308a2f1d77ef91c8..f80c111a53f9083d19ad0c972920732cb7a51bef 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 55d11ae719aaf0e3c4af957b99df3a9d3948be63..28a17cf4a20870f6e86c44b68d591e576cbc967e 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,