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 <jaxboe@fusionio.com>
diff --git a/HOWTO b/HOWTO
index d4e7092..69b8cc6 100644
--- a/HOWTO
+++ b/HOWTO
@@ -348,6 +348,12 @@
 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
--- a/fio.1
+++ b/fio.1
@@ -214,6 +214,12 @@
 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
--- a/fio.h
+++ b/fio.h
@@ -34,6 +34,7 @@
 #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 @@
 	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 @@
 	 * 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
--- a/init.c
+++ b/init.c
@@ -482,6 +482,7 @@
 		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
--- a/io_u.c
+++ b/io_u.c
@@ -168,9 +168,16 @@
 		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 0681282..3b2d67a 100644
--- a/lib/rand.c
+++ b/lib/rand.c
@@ -43,20 +43,28 @@
 	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 */
+	__init_rand(state, 1);
+}
 
-	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);
+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 02e6858..f80c111 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 @@
 }
 
 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 55d11ae..28a17cf 100644
--- a/options.c
+++ b/options.c
@@ -1116,6 +1116,14 @@
 		.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,
 		.off1	= td_var_offset(norandommap),