Skip to contentSkip to conversation

Recent changes (master)

PATCH Jens Axboe 1 participant 1 message May 30, 2015 Library code

lore
Share & tools
lore

Jens Axboe

author
#0 lore raw

The following changes since commit 68d96e515825185b232bbc8d2e5b5136b90514be:

treat error in addr conversion to string as non-fatal (2015-05-26 15:12:46 -0400)

are available in the git repository at:

git://git.kernel.dk/fio.git master

for you to fetch changes up to 37fbd7e9dd4f041b858507b3db06753614083770:

filesetup: print warning if chosen random generator can't cover range (2015-05-29 19:40:21 -0600)

----------------------------------------------------------------
Jens Axboe (3):
Add Intel rdrand support
rand: add 64-bit tausworthe variant with a 2^258 cycle
filesetup: print warning if chosen random generator can't cover range

 HOWTO                  |  2 +
 arch/arch-x86-common.h | 33 ++++++++++-------
 arch/arch-x86_64.h     | 30 +++++++++++++++
 backend.c              |  5 ++-
 crc/test.c             |  2 +-
 filesetup.c            | 14 ++++++-
 fio.1                  |  3 ++
 fio.h                  |  1 +
 init.c                 | 41 +++++++++++++--------
 io_u.c                 | 31 +++++++++++-----
 lib/gauss.c            |  4 +-
 lib/rand.c             | 42 +++++++++++++++++----
 lib/rand.h             | 92 ++++++++++++++++++++++++++++++++++++++++++----
 lib/zipf.c             |  6 +--
 options.c              |  5 +++
 server.c               |  4 +-
 server.h               |  2 +-
 trim.c                 |  4 +-
 verify.c               | 99 +++++++++++++++++++++++++++++++++++++++++---------
 verify.h               | 39 +++++++++++++++++---
 20 files changed, 369 insertions(+), 90 deletions(-)

---

Diff of recent changes:

HOWTO +2 -0
index ab0250c..291327d 100644
@@ -961,6 +961,8 @@ random_generator=str	Fio supports the following engines for generating
 
 		tausworthe	Strong 2^88 cycle random number generator
 		lfsr		Linear feedback shift register generator
+		tausworthe64	Strong 64-bit 2^258 cycle random number
+				generator
 
 		Tausworthe is a strong random number generator, but it
 		requires tracking on the side if we want to ensure that
arch/arch-x86-common.h +19 -14
index 31aa79f..cbf66b8 100644
@@ -15,8 +15,9 @@ static inline void cpuid(unsigned int op,
 #define ARCH_HAVE_INIT
 
 extern int tsc_reliable;
+extern int arch_random;
 
-static inline int arch_init_intel(unsigned int level)
+static inline void arch_init_intel(unsigned int level)
 {
 	unsigned int eax, ebx, ecx = 0, edx;
 
@@ -26,47 +27,51 @@ static inline int arch_init_intel(unsigned int level)
 	eax = 1;
 	do_cpuid(&eax, &ebx, &ecx, &edx);
 	if (!(edx & (1U << 4)))
-		return 0;
+		return;
 
 	/*
 	 * Check for constant rate and synced (across cores) TSC
 	 */
 	eax = 0x80000007;
 	do_cpuid(&eax, &ebx, &ecx, &edx);
-	return edx & (1U << 8);
+	tsc_reliable = (edx & (1U << 8)) != 0;
+
+	/*
+	 * Check for FDRAND
+	 */
+	eax = 0x1;
+	do_cpuid(&eax, &ebx, &ecx, &edx);
+	arch_random = (ecx & (1U << 30)) != 0;
 }
 
-static inline int arch_init_amd(unsigned int level)
+static inline void arch_init_amd(unsigned int level)
 {
 	unsigned int eax, ebx, ecx, edx;
 
 	cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
 	if (eax < 0x80000007)
-		return 0;
+		return;
 
 	cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
-	if (edx & (1 << 8))
-		return 1;
-
-	return 0;
+	tsc_reliable = (edx & (1U << 8)) != 0;
 }
 
-static inline int arch_init(char *envp[])
+static inline void arch_init(char *envp[])
 {
 	unsigned int level;
 	char str[13];
 
+	arch_random = tsc_reliable = 0;
+
 	cpuid(0, &level, (unsigned int *) &str[0],
 			 (unsigned int *) &str[8],
 			 (unsigned int *) &str[4]);
 
 	str[12] = '\0';
 	if (!strcmp(str, "GenuineIntel"))
-		tsc_reliable = arch_init_intel(level);
+		arch_init_intel(level);
 	else if (!strcmp(str, "AuthenticAMD"))
-		tsc_reliable = arch_init_amd(level);
-
-	return 0;
+		arch_init_amd(level);
 }
 
 #endif
arch/arch-x86_64.h +30 -0
index 61ac75e..8f33fc5 100644
@@ -60,4 +60,34 @@ static inline unsigned long long get_cpu_clock(void)
 #define ARCH_HAVE_SSE4_2
 #define ARCH_HAVE_CPU_CLOCK
 
+#define RDRAND_LONG	".byte 0x48,0x0f,0xc7,0xf0"
+#define RDSEED_LONG	".byte 0x48,0x0f,0xc7,0xf8"
+#define RDRAND_RETRY	100
+
+static inline int arch_rand_long(unsigned long *val)
+{
+	int ok;
+
+	asm volatile("1: " RDRAND_LONG "\n\t"
+		     "jc 2f\n\t"
+		     "decl %0\n\t"
+		     "jnz 1b\n\t"
+		     "2:"
+		     : "=r" (ok), "=a" (*val)
+		     : "0" (RDRAND_RETRY));
+
+	return ok;
+}
+
+static inline int arch_rand_seed(unsigned long *seed)
+{
+	unsigned char ok;
+
+	asm volatile(RDSEED_LONG "\n\t"
+			"setc %0"
+			: "=qm" (ok), "=a" (*seed));
+
+	return 0;
+}
+
 #endif
backend.c +3 -2
index ef5003e..2aa8840 100644
@@ -1878,11 +1878,12 @@ static int fio_verify_load_state(struct thread_data *td)
 
 	if (is_backend) {
 		void *data;
+		int ver;
 
 		ret = fio_server_get_verify_state(td->o.name,
-					td->thread_number - 1, &data);
+					td->thread_number - 1, &data, &ver);
 		if (!ret)
-			verify_convert_assign_state(td, data);
+			verify_convert_assign_state(td, data, ver);
 	} else
 		ret = verify_load_state(td, "local");
 
crc/test.c +1 -1
index dbc5653..05ea73e 100644
@@ -306,7 +306,7 @@ int fio_crctest(const char *type)
 	}
 
 	buf = malloc(CHUNK);
-	init_rand_seed(&state, 0x8989);
+	init_rand_seed(&state, 0x8989, 0);
 	fill_random_buf(&state, buf, CHUNK);
 
 	for (i = 0; t[i].name; i++) {
filesetup.c +13 -1
index cf8ae94..51efdf7 100644
@@ -267,11 +267,13 @@ error:
 static unsigned long long get_rand_file_size(struct thread_data *td)
 {
 	unsigned long long ret, sized;
+	uint64_t frand_max;
 	unsigned long r;
 
+	frand_max = rand_max(&td->file_size_state);
 	r = __rand(&td->file_size_state);
 	sized = td->o.file_size_high - td->o.file_size_low;
-	ret = (unsigned long long) ((double) sized * (r / (FRAND_MAX + 1.0)));
+	ret = (unsigned long long) ((double) sized * (r / (frand_max + 1.0)));
 	ret += td->o.file_size_low;
 	ret -= (ret % td->o.rw_min_bs);
 	return ret;
@@ -1065,6 +1067,16 @@ int init_random_map(struct thread_data *td)
 
 		blocks = fsize / (unsigned long long) td->o.rw_min_bs;
 
+		if (blocks > FRAND32_MAX &&
+		    td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE &&
+		    !fio_option_is_set(&td->o, random_generator)) {
+			log_err("fio: file %s exceeds 32-bit tausworthe "
+				 "random generator. Use lfsr or "
+				 "tausworthe64.\n", f->file_name);
+			td_verror(td, EINVAL, "init file random");
+			return 1;
+		}
+
 		if (td->o.random_generator == FIO_RAND_GEN_LFSR) {
 			unsigned long seed;
 
fio.1 +3 -0
index 36f80d6..1657082 100644
@@ -843,6 +843,9 @@ Strong 2^88 cycle random number generator
 .B lfsr
 Linear feedback shift register generator
 .TP
+.B tausworthe64
+Strong 64-bit 2^258 cycle random number generator
+.TP
 .RE
 .P
 Tausworthe is a strong random number generator, but it requires tracking on the
fio.h +1 -0
index 6659e28..4e2532f 100644
@@ -686,6 +686,7 @@ enum {
 enum {
 	FIO_RAND_GEN_TAUSWORTHE = 0,
 	FIO_RAND_GEN_LFSR,
+	FIO_RAND_GEN_TAUSWORTHE64,
 };
 
 enum {
init.c +25 -16

81 lines not on this page · raw message

io_u.c +21 -10
index e67149d..63a176f 100644
@@ -89,18 +89,20 @@ static int __get_next_rand_offset(struct thread_data *td, struct fio_file *f,
 {
 	uint64_t r;
 
-	if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE) {
-		uint64_t lastb;
+	if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE ||
+	    td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE64) {
+		uint64_t frand_max, lastb;
 
 		lastb = last_block(td, f, ddir);
 		if (!lastb)
 			return 1;
 
+		frand_max = rand_max(&td->random_state);
 		r = __rand(&td->random_state);
 
 		dprint(FD_RANDOM, "off rand %llu\n", (unsigned long long) r);
 
-		*b = lastb * (r / ((uint64_t) FRAND_MAX + 1.0));
+		*b = lastb * (r / ((uint64_t) frand_max + 1.0));
 	} else {
 		uint64_t off = 0;
 
@@ -195,7 +197,8 @@ static inline int should_sort_io(struct thread_data *td)
 		return 0;
 	if (td->runstate != TD_VERIFYING)
 		return 0;
-	if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE)
+	if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE ||
+	    td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE64)
 		return 0;
 
 	return 1;
@@ -203,14 +206,16 @@ static inline int should_sort_io(struct thread_data *td)
 
 static int should_do_random(struct thread_data *td, enum fio_ddir ddir)
 {
+	uint64_t frand_max;
 	unsigned int v;
 	unsigned long r;
 
 	if (td->o.perc_rand[ddir] == 100)
 		return 1;
 
+	frand_max = rand_max(&td->seq_rand_state[ddir]);
 	r = __rand(&td->seq_rand_state[ddir]);
-	v = 1 + (int) (100.0 * (r / (FRAND_MAX + 1.0)));
+	v = 1 + (int) (100.0 * (r / (frand_max + 1.0)));
 
 	return v <= td->o.perc_rand[ddir];
 }
@@ -439,6 +444,7 @@ static unsigned int __get_next_buflen(struct thread_data *td, struct io_u *io_u,
 	int ddir = io_u->ddir;
 	unsigned int buflen = 0;
 	unsigned int minbs, maxbs;
+	uint64_t frand_max;
 	unsigned long r;
 
 	assert(ddir_rw(ddir));
@@ -458,12 +464,13 @@ static unsigned int __get_next_buflen(struct thread_data *td, struct io_u *io_u,
 	if (!io_u_fits(td, io_u, minbs))
 		return 0;
 
+	frand_max = rand_max(&td->bsrange_state);
 	do {
 		r = __rand(&td->bsrange_state);
 
 		if (!td->o.bssplit_nr[ddir]) {
 			buflen = 1 + (unsigned int) ((double) maxbs *
-					(r / (FRAND_MAX + 1.0)));
+					(r / (frand_max + 1.0)));
 			if (buflen < minbs)
 				buflen = minbs;
 		} else {
@@ -475,7 +482,7 @@ static unsigned int __get_next_buflen(struct thread_data *td, struct io_u *io_u,
 
 				buflen = bsp->bs;
 				perc += bsp->perc;
-				if ((r <= ((FRAND_MAX / 100L) * perc)) &&
+				if ((r <= ((frand_max / 100L) * perc)) &&
 				    io_u_fits(td, io_u, buflen))
 					break;
 			}
@@ -521,11 +528,12 @@ static void set_rwmix_bytes(struct thread_data *td)
 
 static inline enum fio_ddir get_rand_ddir(struct thread_data *td)
 {
+	uint64_t frand_max = rand_max(&td->rwmix_state);
 	unsigned int v;
 	unsigned long r;
 
 	r = __rand(&td->rwmix_state);
-	v = 1 + (int) (100.0 * (r / (FRAND_MAX + 1.0)));
+	v = 1 + (int) (100.0 * (r / (frand_max + 1.0)));
 
 	if (v <= td->o.rwmix[DDIR_READ])
 		return DDIR_READ;
@@ -992,6 +1000,7 @@ static struct fio_file *get_next_file_rand(struct thread_data *td,
 					   enum fio_file_flags goodf,
 					   enum fio_file_flags badf)
 {
+	uint64_t frand_max = rand_max(&td->next_file_state);
 	struct fio_file *f;
 	int fno;
 
@@ -1001,7 +1010,7 @@ static struct fio_file *get_next_file_rand(struct thread_data *td,
 
 		r = __rand(&td->next_file_state);
 		fno = (unsigned int) ((double) td->o.nr_files
-				* (r / (FRAND_MAX + 1.0)));
+				* (r / (frand_max + 1.0)));
 
 		f = td->files[fno];
 		if (fio_file_done(f))
@@ -1892,6 +1901,7 @@ void io_u_queued(struct thread_data *td, struct io_u *io_u)
  */
 static struct frand_state *get_buf_state(struct thread_data *td)
 {
+	uint64_t frand_max;
 	unsigned int v;
 	unsigned long r;
 
@@ -1902,8 +1912,9 @@ static struct frand_state *get_buf_state(struct thread_data *td)
 		return &td->buf_state;
 	}
 
+	frand_max = rand_max(&td->dedupe_state);
 	r = __rand(&td->dedupe_state);
-	v = 1 + (int) (100.0 * (r / (FRAND_MAX + 1.0)));
+	v = 1 + (int) (100.0 * (r / (frand_max + 1.0)));
 
 	if (v <= td->o.dedupe_percentage)
 		return &td->buf_state_prev;
lib/gauss.c +2 -2
index 1bb6c41..afd0490 100644
@@ -15,7 +15,7 @@ static int gauss_dev(struct gauss_state *gs)
 		return 0;
 
 	r = __rand(&gs->r);
-	vr = gs->stddev * (r / (FRAND_MAX + 1.0));
+	vr = gs->stddev * (r / (FRAND32_MAX + 1.0));
 
 	return vr - gs->stddev / 2;
 }
@@ -45,7 +45,7 @@ void gauss_init(struct gauss_state *gs, unsigned long nranges, double dev,
 		unsigned int seed)
 {
 	memset(gs, 0, sizeof(*gs));
-	init_rand_seed(&gs->r, seed);
+	init_rand_seed(&gs->r, seed, 0);
 	gs->nranges = nranges;
 
 	if (dev != 0.0) {
lib/rand.c +35 -7

64 lines not on this page · raw message

lib/rand.h +85 -7

114 lines not on this page · raw message

lib/zipf.c +3 -3
index c691bc5..d8e72b1 100644
@@ -35,7 +35,7 @@ static void shared_rand_init(struct zipf_state *zs, unsigned long nranges,
 	memset(zs, 0, sizeof(*zs));
 	zs->nranges = nranges;
 
-	init_rand_seed(&zs->rand, seed);
+	init_rand_seed(&zs->rand, seed, 0);
 	zs->rand_off = __rand(&zs->rand);
 }
 
@@ -59,7 +59,7 @@ unsigned long long zipf_next(struct zipf_state *zs)
 	alpha = 1.0 / (1.0 - zs->theta);
 	eta = (1.0 - pow(2.0 / n, 1.0 - zs->theta)) / (1.0 - zs->zeta2 / zs->zetan);
 
-	rand_uni = (double) __rand(&zs->rand) / (double) FRAND_MAX;
+	rand_uni = (double) __rand(&zs->rand) / (double) FRAND32_MAX;
 	rand_z = rand_uni * zs->zetan;
 
 	if (rand_z < 1.0)
@@ -81,7 +81,7 @@ void pareto_init(struct zipf_state *zs, unsigned long nranges, double h,
 
 unsigned long long pareto_next(struct zipf_state *zs)
 {
-	double rand = (double) __rand(&zs->rand) / (double) FRAND_MAX;
+	double rand = (double) __rand(&zs->rand) / (double) FRAND32_MAX;
 	unsigned long long n = zs->nranges - 1;
 
 	return (__hash_u64(n * pow(rand, zs->pareto_pow)) + zs->rand_off) % zs->nranges;
options.c +5 -0
index 7f9075b..96b8b68 100644
@@ -1897,6 +1897,11 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
 			    .oval = FIO_RAND_GEN_LFSR,
 			    .help = "Variable length LFSR",
 			  },
+			  {
+			    .ival = "tausworthe64",
+			    .oval = FIO_RAND_GEN_TAUSWORTHE64,
+			    .help = "64-bit Tausworthe variant",
+			  },
 		},
 		.category = FIO_OPT_C_IO,
 		.group	= FIO_OPT_G_RANDOM,
server.c +2 -2
index 519a7ee..b4137d1 100644
@@ -1410,7 +1410,7 @@ void fio_server_send_start(struct thread_data *td)
 }
 
 int fio_server_get_verify_state(const char *name, int threadnumber,
-				void **datap)
+				void **datap, int *version)
 {
 	struct thread_io_list *s;
 	struct cmd_sendfile out;
@@ -1458,7 +1458,7 @@ fail:
 	 * the header, and the thread_io_list checksum
 	 */
 	s = rep->data + sizeof(struct verify_state_hdr);
-	if (verify_state_hdr(rep->data, s))
+	if (verify_state_hdr(rep->data, s, version))
 		goto fail;
 
 	/*
server.h +1 -1
index 9944719..e4da882 100644
@@ -197,7 +197,7 @@ extern void fio_server_send_ts(struct thread_stat *, struct group_run_stats *);
 extern void fio_server_send_gs(struct group_run_stats *);
 extern void fio_server_send_du(void);
 extern void fio_server_idle_loop(void);
-extern int fio_server_get_verify_state(const char *, int, void **);
+extern int fio_server_get_verify_state(const char *, int, void **, int *);
 
 extern int fio_recv_data(int sk, void *p, unsigned int len);
 extern int fio_send_data(int sk, const void *p, unsigned int len);
trim.c +3 -1
index 95c433b..4345541 100644
@@ -70,13 +70,15 @@ int get_next_trim(struct thread_data *td, struct io_u *io_u)
 int io_u_should_trim(struct thread_data *td, struct io_u *io_u)
 {
 	unsigned long long val;
+	uint64_t frand_max;
 	unsigned long r;
 
 	if (!td->o.trim_percentage)
 		return 0;
 
+	frand_max = rand_max(&td->trim_state);
 	r = __rand(&td->trim_state);
-	val = (FRAND_MAX / 100ULL);
+	val = (frand_max / 100ULL);
 
 	val *= (unsigned long long) td->o.trim_percentage;
 	return r <= val;
verify.c +81 -18

155 lines not on this page · raw message

verify.h +34 -5
index 43de887..d4d6012 100644
@@ -88,10 +88,22 @@ extern void fio_verify_init(struct thread_data *td);
 extern int verify_async_init(struct thread_data *);
 extern void verify_async_exit(struct thread_data *);
 
-struct thread_rand_state {
+struct thread_rand32_state {
 	uint32_t s[4];
 };
 
+struct thread_rand64_state {
+	uint64_t s[6];
+};
+
+struct thread_rand_state {
+	uint64_t use64;
+	union {
+		struct thread_rand32_state state32;
+		struct thread_rand64_state state64;
+	};
+};
+
 /*
  * For dumping current write state
  */
@@ -105,12 +117,23 @@ struct thread_io_list {
 	uint64_t offsets[0];
 };
 
+struct thread_io_list_v1 {
+	uint64_t no_comps;
+	uint64_t depth;
+	uint64_t numberio;
+	uint64_t index;
+	struct thread_rand32_state rand;
+	uint8_t name[64];
+	uint64_t offsets[0];
+};
+
 struct all_io_list {
 	uint64_t threads;
 	struct thread_io_list state[0];
 };
 
-#define VSTATE_HDR_VERSION	0x01
+#define VSTATE_HDR_VERSION_V1	0x01
+#define VSTATE_HDR_VERSION	0x02
 
 struct verify_state_hdr {
 	uint64_t version;
@@ -125,12 +148,18 @@ extern void verify_save_state(void);
 extern int verify_load_state(struct thread_data *, const char *);
 extern void verify_free_state(struct thread_data *);
 extern int verify_state_should_stop(struct thread_data *, struct io_u *);
-extern void verify_convert_assign_state(struct thread_data *, struct thread_io_list *);
-extern int verify_state_hdr(struct verify_state_hdr *, struct thread_io_list *);
+extern void verify_convert_assign_state(struct thread_data *, void *, int);
+extern int verify_state_hdr(struct verify_state_hdr *, struct thread_io_list *,
+				int *);
+
+static inline size_t __thread_io_list_sz(uint64_t depth)
+{
+	return sizeof(struct thread_io_list) + depth * sizeof(uint64_t);
+}
 
 static inline size_t thread_io_list_sz(struct thread_io_list *s)
 {
-	return sizeof(*s) + le64_to_cpu(s->depth) * sizeof(uint64_t);
+	return __thread_io_list_sz(le64_to_cpu(s->depth));
 }
 
 static inline struct thread_io_list *io_list_next(struct thread_io_list *s)