From 2615cc4b28e7d0e436a625dff92e6a71ccc6c49b Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 28 Mar 2011 09:35:09 +0200 Subject: [PATCH] Switch to using our internal Tausworthe based random generator for offsets 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 --- HOWTO | 6 ++++++ fio.1 | 6 ++++++ fio.h | 3 +++ init.c | 1 + io_u.c | 11 +++++++++-- lib/rand.c | 32 ++++++++++++++++++++------------ lib/rand.h | 3 +++ options.c | 8 ++++++++ 8 files changed, 56 insertions(+), 14 deletions(-) diff --git a/HOWTO b/HOWTO index d4e70923..69b8cc67 100644 --- 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 a8c0027b..0ced604d 100644 --- 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 08f17331..e5607bc7 100644 --- 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 @@ -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 327a3c5e..2ae93a02 100644 --- 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 5a3ca744..e9ce37ef 100644 --- 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. diff --git a/lib/rand.c b/lib/rand.c index 06812823..3b2d67ad 100644 --- a/lib/rand.c +++ b/lib/rand.c @@ -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) diff --git a/lib/rand.h b/lib/rand.h index 02e68585..f80c111a 100644 --- a/lib/rand.h +++ b/lib/rand.h @@ -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); diff --git a/options.c b/options.c index 55d11ae7..28a17cf4 100644 --- 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, -- 2.25.1