From a6ccc7be771650f903ea77ace2a1af593622c0f4 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 2 Jun 2006 10:14:15 +0200 Subject: [PATCH] [PATCH] Add support for specifying read/write mix workloads better Added options: - rwmixcycle=x, use x msecs as the cycle period for read/write switches - rwmixread=x, x% of ios will be reads - rwmixwrite=x, x% of ios will be writes Last given of the latter two will override the first. --- README | 7 +++++++ fio-ini.c | 37 +++++++++++++++++++++++++++++------- fio.c | 56 ++++++++++++++++++++++--------------------------------- fio.h | 6 ++++++ 4 files changed, 65 insertions(+), 41 deletions(-) diff --git a/README b/README index 8b84a08a..3d59337d 100644 --- a/README +++ b/README @@ -41,6 +41,13 @@ The format is as follows: directory=x Use 'x' as the top level directory for storing files rw=x 'x' may be: read, randread, write, randwrite, rw (read-write mix), randrw (read-write random mix) + rwmixcycle=x Base cycle for switching between read and write + in msecs. + rwmixread=x 'x' percentage of rw mix ios will be reads. If + rwmixwrite is also given, the last of the two will + be used if they don't add up to 100%. + rwmixwrite=x 'x' percentage of rw mix ios will be writes. See + rwmixread. size=x Set file size to x bytes (x string can include k/m/g) ioengine=x 'x' may be: aio/libaio/linuxaio for Linux aio, posixaio for POSIX aio, sync for regular read/write io, diff --git a/fio-ini.c b/fio-ini.c index f5297576..0fec342d 100644 --- a/fio-ini.c +++ b/fio-ini.c @@ -36,6 +36,8 @@ #define DEF_FILE_SIZE (1024 * 1024 * 1024UL) #define DEF_ZONE_SIZE (0) #define DEF_ZONE_SKIP (0) +#define DEF_RWMIX_CYCLE (500) +#define DEF_RWMIX_READ (50) static char fio_version_string[] = "fio 1.3"; @@ -282,7 +284,7 @@ err: int init_random_state(struct thread_data *td) { - unsigned long seed; + unsigned long seeds[4]; int fd, num_maps, blocks; fd = open("/dev/urandom", O_RDONLY); @@ -291,7 +293,7 @@ int init_random_state(struct thread_data *td) return 1; } - if (read(fd, &seed, sizeof(seed)) < (int) sizeof(seed)) { + if (read(fd, seeds, sizeof(seeds)) < (int) sizeof(seeds)) { td_verror(td, EIO); close(fd); return 1; @@ -299,14 +301,15 @@ int init_random_state(struct thread_data *td) close(fd); - srand48_r(seed, &td->bsrange_state); - srand48_r(seed, &td->verify_state); + srand48_r(seeds[0], &td->bsrange_state); + srand48_r(seeds[1], &td->verify_state); + srand48_r(seeds[2], &td->rwmix_state); if (td->sequential) return 0; if (repeatable) - seed = DEF_RANDSEED; + seeds[3] = DEF_RANDSEED; blocks = (td->io_size + td->min_bs - 1) / td->min_bs; num_maps = blocks / BLOCKS_PER_MAP; @@ -314,7 +317,7 @@ int init_random_state(struct thread_data *td) td->num_maps = num_maps; memset(td->file_map, 0, num_maps * sizeof(long)); - srand48_r(seed, &td->random_state); + srand48_r(seeds[3], &td->random_state); return 0; } @@ -640,7 +643,7 @@ static int str_iolog_cb(struct thread_data *td, char *file) int parse_jobs_ini(char *file) { - unsigned int prioclass, prio, cpu, global; + unsigned int prioclass, prio, cpu, global, il; unsigned long long ull; unsigned long ul1, ul2; struct thread_data *td; @@ -781,6 +784,24 @@ int parse_jobs_ini(char *file) fgetpos(f, &off); continue; } + if (!check_int(p, "rwmixcycle", &td->rwmixcycle)) { + fgetpos(f, &off); + continue; + } + if (!check_int(p, "rwmixread", &il)) { + if (il > 100) + il = 100; + td->rwmixread = il; + fgetpos(f, &off); + continue; + } + if (!check_int(p, "rwmixwrite", &il)) { + if (il > 100) + il = 100; + td->rwmixread = 100 - il; + fgetpos(f, &off); + continue; + } if (!check_range(p, "bsrange", &ul1, &ul2)) { if (ul1 > ul2) { td->max_bs = ul1; @@ -914,6 +935,8 @@ static int fill_def_thread(void) def_thread.stonewall = DEF_STONEWALL; def_thread.numjobs = DEF_NUMJOBS; def_thread.use_thread = DEF_USE_THREAD; + def_thread.rwmixcycle = DEF_RWMIX_CYCLE; + def_thread.rwmixread = DEF_RWMIX_READ; #ifdef FIO_HAVE_DISK_UTIL def_thread.do_disk_util = 1; #endif diff --git a/fio.c b/fio.c index 51cd1535..c5e4f3c0 100644 --- a/fio.c +++ b/fio.c @@ -545,44 +545,32 @@ static void fill_md5(struct verify_header *hdr, void *p, unsigned int len) memcpy(hdr->md5_digest, md5_ctx.hash, sizeof(md5_ctx.hash)); } -unsigned int hweight32(unsigned int w) -{ - unsigned int res = w - ((w >> 1) & 0x55555555); - - res = (res & 0x33333333) + ((res >> 2) & 0x33333333); - res = (res + (res >> 4)) & 0x0F0F0F0F; - res = res + (res >> 8); - - return (res + (res >> 16)) & 0x000000FF; -} - -unsigned long hweight64(unsigned long long w) +static int get_rw_ddir(struct thread_data *td) { -#if __WORDSIZE == 32 - return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w); -#elif __WORDSIZE == 64 - unsigned long long v = w - ((w >> 1) & 0x5555555555555555ul); + if (td_rw(td)) { + struct timeval now; + unsigned long elapsed; - v = (v & 0x3333333333333333ul) + ((v >> 2) & 0x3333333333333333ul); - v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0Ful; - v = v + (v >> 8); - v = v + (v >> 16); + gettimeofday(&now, NULL); + elapsed = mtime_since_now(&td->rwmix_switch); - return (v + (v >> 32)) & 0x00000000000000FFul; -#else -#error __WORDSIZE not defined -#endif -} + /* + * Check if it's time to seed a new data direction. + */ + if (elapsed >= td->rwmixcycle) { + unsigned long v; + long r; -static int get_rw_ddir(struct thread_data *td) -{ - /* - * perhaps cheasy, but use the hamming weight of the position - * as a randomizer for data direction. - */ - if (td_rw(td)) - return hweight64(td->last_pos) & 1; - else if (td_read(td)) + lrand48_r(&td->random_state, &r); + v = 100UL * r / (unsigned long) (RAND_MAX + 1.0); + if (v < td->rwmixread) + td->rwmix_ddir = DDIR_READ; + else + td->rwmix_ddir = DDIR_WRITE; + memcpy(&td->rwmix_switch, &now, sizeof(now)); + } + return td->rwmix_ddir; + } else if (td_read(td)) return DDIR_READ; else return DDIR_WRITE; diff --git a/fio.h b/fio.h index 4f87fb77..dbf476e9 100644 --- a/fio.h +++ b/fio.h @@ -151,6 +151,8 @@ struct thread_data { os_cpu_mask_t cpumask; unsigned int jobnum; unsigned int iolog; + unsigned int rwmixcycle; + unsigned int rwmixread; char iolog_file[256]; @@ -222,6 +224,10 @@ struct thread_data { unsigned int do_disk_util; unsigned int override_sync; + struct drand48_data rwmix_state; + struct timeval rwmix_switch; + int rwmix_ddir; + struct list_head io_hist_list; struct list_head io_log_list; }; -- 2.25.1