The following changes since commit a3ebe7e079847413458b9d80bd7a4acc924d108b: smalloc: move to size_t for allocations (2012-11-02 16:47:03 +0100) are available in the git repository at: git://git.kernel.dk/fio.git master Jens Axboe (10): Add sample zipf distribution randomizer Merge branch 'master' of ssh://brick.kernel.dk/data/git/fio Add forgotten minmax.h include file Add pareto distribution randomizer zipf: needs inttypes.h Add t/genzipf to play with distribution settings t/genzipf update genzip updates Fix t/ieee754 link Move code around to satisfy t/stest linkage Makefile | 18 ++++++- examples/zipf | 10 ++++ fio.h | 16 ++++++ gettime-thread.c | 78 +++++++++++++++++++++++++++++ gettime.c | 101 ++++++++++++++++++------------------- gettime.h | 2 + init.c | 20 +++++++ io_u.c | 34 ++++++++++++- lib/zipf.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/zipf.h | 22 ++++++++ minmax.h | 11 ++++ options.c | 51 +++++++++++++++++++ parse.c | 5 +- parse.h | 8 +--- t/genzipf.c | 122 +++++++++++++++++++++++++++++++++++++++++++++ t/ieee754.c | 2 +- t/log.c | 13 +++++ t/stest.c | 6 ++ time.c | 66 ------------------------ 19 files changed, 598 insertions(+), 133 deletions(-) create mode 100644 examples/zipf create mode 100644 gettime-thread.c create mode 100644 lib/zipf.c create mode 100644 lib/zipf.h create mode 100644 minmax.h create mode 100644 t/genzipf.c --- Diff of recent changes: diff --git a/Makefile b/Makefile index ccfa802..88d397b 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ SOURCE := gettime.c fio.c ioengines.c init.c stat.c log.c time.c filesetup.c \ lib/num2str.c lib/ieee754.c $(wildcard crc/*.c) engines/cpu.c \ engines/mmap.c engines/sync.c engines/null.c engines/net.c \ memalign.c server.c client.c iolog.c backend.c libfio.c flow.c \ - json.c + json.c lib/zipf.c gettime-thread.c ifeq ($(UNAME), Linux) SOURCE += diskutil.c fifo.c blktrace.c helpers.c cgroup.c trim.c \ @@ -69,15 +69,24 @@ endif OBJS = $(SOURCE:.c=.o) T_SMALLOC_OBJS = t/stest.o -T_SMALLOC_OBJS += mutex.o smalloc.o t/log.o +T_SMALLOC_OBJS += gettime.o mutex.o smalloc.o t/log.o T_SMALLOC_PROGS = t/stest T_IEEE_OBJS = t/ieee754.o -T_IEEE_OBJS += ieee754.o +T_IEEE_OBJS += lib/ieee754.o T_IEEE_PROGS = t/ieee754 +T_ZIPF_OBS = t/genzipf.o +T_ZIPF_OBJS += t/log.o lib/ieee754.o lib/rand.o lib/zipf.o t/genzipf.o +T_ZIPF_PROGS = t/genzip + T_OBJS = $(T_SMALLOC_OBJS) T_OBJS += $(T_IEEE_OBJS) +T_OBJS += $(T_ZIPF_OBJS) + +T_PROGS = $(T_SMALLOC_PROGS) +T_PROGS += $(T_IEEE_PROGS) +T_PROGS += $(T_ZIPF_PROGS) ifneq ($(findstring $(MAKEFLAGS),s),s) ifndef V @@ -119,6 +128,9 @@ t/stest: $(T_SMALLOC_OBJS) t/ieee754: $(T_IEEE_OBJS) $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_IEEE_OBJS) $(LIBS) $(LDFLAGS) +t/genzipf: $(T_ZIPF_OBJS) + $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_ZIPF_OBJS) $(LIBS) $(LDFLAGS) + fio: $(OBJS) $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(LDFLAGS) diff --git a/examples/zipf b/examples/zipf new file mode 100644 index 0000000..fcfa38d --- /dev/null +++ b/examples/zipf @@ -0,0 +1,10 @@ +# Example job file for using a zipf distribution instead +# of a purely random workload where each block is read +# or written once. +[job] +ioengine=null +rw=randread +norandommap +size=1280m +bs=4k +random_distribution=zipf:0.5 diff --git a/fio.h b/fio.h index 139b938..7eb0abb 100644 --- a/fio.h +++ b/fio.h @@ -39,6 +39,7 @@ struct thread_data; #include "server.h" #include "stat.h" #include "flow.h" +#include "lib/zipf.h" #ifdef FIO_HAVE_GUASI #include <guasi.h> @@ -177,6 +178,10 @@ struct thread_options { unsigned int bs_unaligned; unsigned int fsync_on_close; + unsigned int random_distribution; + double zipf_theta; + double pareto_h; + unsigned int hugepage_size; unsigned int rw_min_bs; unsigned int thinktime; @@ -452,6 +457,11 @@ struct thread_data { struct frand_state __random_state; }; + /* + * Used for zipf random distribution + */ + struct zipf_state zipf; + struct timeval start; /* start of this loop */ struct timeval epoch; /* time job was started */ struct timeval last_issue; @@ -815,4 +825,10 @@ enum { FIO_OUTPUT_NORMAL, }; +enum { + FIO_RAND_DIST_RANDOM = 0, + FIO_RAND_DIST_ZIPF, + FIO_RAND_DIST_PARETO, +}; + #endif diff --git a/gettime-thread.c b/gettime-thread.c new file mode 100644 index 0000000..da40904 --- /dev/null +++ b/gettime-thread.c @@ -0,0 +1,78 @@ +#include <unistd.h> +#include <math.h> +#include <sys/time.h> +#include <time.h> + +#include "fio.h" +#include "smalloc.h" + +struct timeval *fio_tv; +int fio_gtod_offload = 0; +int fio_gtod_cpu = -1; +static pthread_t gtod_thread; + +void fio_gtod_init(void) +{ + fio_tv = smalloc(sizeof(struct timeval)); + assert(fio_tv); +} + +static void fio_gtod_update(void) +{ + gettimeofday(fio_tv, NULL); +} + +static void *gtod_thread_main(void *data) +{ + struct fio_mutex *mutex = data; + + fio_mutex_up(mutex); + + /* + * As long as we have jobs around, update the clock. It would be nice + * to have some way of NOT hammering that CPU with gettimeofday(), + * but I'm not sure what to use outside of a simple CPU nop to relax + * it - we don't want to lose precision. + */ + while (threads) { + fio_gtod_update(); + nop; + } + + return NULL; +} + +int fio_start_gtod_thread(void) +{ + struct fio_mutex *mutex; + pthread_attr_t attr; + int ret; + + mutex = fio_mutex_init(FIO_MUTEX_LOCKED); + if (!mutex) + return 1; + + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); + ret = pthread_create(>od_thread, &attr, gtod_thread_main, NULL); + pthread_attr_destroy(&attr); + if (ret) { + log_err("Can't create gtod thread: %s\n", strerror(ret)); + goto err; + } + + ret = pthread_detach(gtod_thread); + if (ret) { + log_err("Can't detatch gtod thread: %s\n", strerror(ret)); + goto err; + } + + dprint(FD_MUTEX, "wait on startup_mutex\n"); + fio_mutex_down(mutex); + dprint(FD_MUTEX, "done waiting on startup_mutex\n"); +err: + fio_mutex_remove(mutex); + return ret; +} + + diff --git a/gettime.c b/gettime.c index 5b49287..35d685e 100644 --- a/gettime.c +++ b/gettime.c @@ -19,11 +19,6 @@ static unsigned long last_cycles; static struct timeval last_tv; static int last_tv_valid; -static struct timeval *fio_tv; -int fio_gtod_offload = 0; -int fio_gtod_cpu = -1; -static pthread_t gtod_thread; - enum fio_cs fio_clock_source = FIO_PREFERRED_CLOCK_SOURCE; #ifdef FIO_DEBUG_TIME @@ -267,66 +262,68 @@ void fio_clock_init(void) calibrate_cpu_clock(); } -void fio_gtod_init(void) +unsigned long long utime_since(struct timeval *s, struct timeval *e) { - fio_tv = smalloc(sizeof(struct timeval)); - assert(fio_tv); + long sec, usec; + unsigned long long ret; + + sec = e->tv_sec - s->tv_sec; + usec = e->tv_usec - s->tv_usec; + if (sec > 0 && usec < 0) { + sec--; + usec += 1000000; + } + + /* + * time warp bug on some kernels? + */ + if (sec < 0 || (sec == 0 && usec < 0)) + return 0; + + ret = sec * 1000000ULL + usec; + + return ret; } -static void fio_gtod_update(void) +unsigned long long utime_since_now(struct timeval *s) { - gettimeofday(fio_tv, NULL); + struct timeval t; + + fio_gettime(&t, NULL); + return utime_since(s, &t); } -static void *gtod_thread_main(void *data) +unsigned long mtime_since(struct timeval *s, struct timeval *e) { - struct fio_mutex *mutex = data; + long sec, usec, ret; - fio_mutex_up(mutex); - - /* - * As long as we have jobs around, update the clock. It would be nice - * to have some way of NOT hammering that CPU with gettimeofday(), - * but I'm not sure what to use outside of a simple CPU nop to relax - * it - we don't want to lose precision. - */ - while (threads) { - fio_gtod_update(); - nop; + sec = e->tv_sec - s->tv_sec; + usec = e->tv_usec - s->tv_usec; + if (sec > 0 && usec < 0) { + sec--; + usec += 1000000; } - return NULL; + if (sec < 0 || (sec == 0 && usec < 0)) + return 0; + + sec *= 1000UL; + usec /= 1000UL; + ret = sec + usec; + + return ret; } -int fio_start_gtod_thread(void) +unsigned long mtime_since_now(struct timeval *s) { - struct fio_mutex *mutex; - pthread_attr_t attr; - int ret; - - mutex = fio_mutex_init(FIO_MUTEX_LOCKED); - if (!mutex) - return 1; - - pthread_attr_init(&attr); - pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); - ret = pthread_create(>od_thread, &attr, gtod_thread_main, NULL); - pthread_attr_destroy(&attr); - if (ret) { - log_err("Can't create gtod thread: %s\n", strerror(ret)); - goto err; - } + struct timeval t; + void *p = __builtin_return_address(0); - ret = pthread_detach(gtod_thread); - if (ret) { - log_err("Can't detatch gtod thread: %s\n", strerror(ret)); - goto err; - } + fio_gettime(&t, p); + return mtime_since(s, &t); +} - dprint(FD_MUTEX, "wait on startup_mutex\n"); - fio_mutex_down(mutex); - dprint(FD_MUTEX, "done waiting on startup_mutex\n"); -err: - fio_mutex_remove(mutex); - return ret; +unsigned long time_since_now(struct timeval *s) +{ + return mtime_since_now(s) / 1000; } diff --git a/gettime.h b/gettime.h index 87cc895..309ef21 100644 --- a/gettime.h +++ b/gettime.h @@ -15,4 +15,6 @@ extern void fio_gtod_init(void); extern void fio_clock_init(void); extern int fio_start_gtod_thread(void); +extern struct timeval *fio_tv; + #endif diff --git a/init.c b/init.c index 23be863..bf4aa03 100644 --- a/init.c +++ b/init.c @@ -382,6 +382,24 @@ static int fixed_block_size(struct thread_options *o) o->min_bs[DDIR_READ] == o->min_bs[DDIR_TRIM]; } +static void init_rand_distribution(struct thread_data *td) +{ + unsigned int range_size; + unsigned long nranges; + + if (td->o.random_distribution == FIO_RAND_DIST_RANDOM) + return; + + range_size = min(td->o.min_bs[DDIR_READ], td->o.min_bs[DDIR_WRITE]); + + nranges = (td->o.size + range_size - 1) / range_size; + + if (td->o.random_distribution == FIO_RAND_DIST_ZIPF) + zipf_init(&td->zipf, nranges, td->o.zipf_theta); + else + pareto_init(&td->zipf, nranges, td->o.pareto_h); +} + /* * Lazy way of fixing up options that depend on each other. We could also * define option callback handlers, but this is easier. @@ -592,6 +610,8 @@ static int fixup_options(struct thread_data *td) td->o.compress_percentage = 0; } + init_rand_distribution(td); + return ret; } diff --git a/io_u.c b/io_u.c index b049b61..688249b 100644 --- a/io_u.c +++ b/io_u.c @@ -157,8 +157,8 @@ static int get_next_free_block(struct thread_data *td, struct fio_file *f, return 1; } -static int get_next_rand_offset(struct thread_data *td, struct fio_file *f, - enum fio_ddir ddir, unsigned long long *b) +static int __get_next_rand_offset(struct thread_data *td, struct fio_file *f, + enum fio_ddir ddir, unsigned long long *b) { unsigned long long rmax, r, lastb; int loops = 5; @@ -234,6 +234,36 @@ ret: return 0; } +static int __get_next_rand_offset_zipf(struct thread_data *td, + struct fio_file *f, enum fio_ddir ddir, + unsigned long long *b) +{ + *b = zipf_next(&td->zipf); + return 0; +} + +static int __get_next_rand_offset_pareto(struct thread_data *td, + struct fio_file *f, enum fio_ddir ddir, + unsigned long long *b) +{ + *b = pareto_next(&td->zipf); + return 0; +} + +static int get_next_rand_offset(struct thread_data *td, struct fio_file *f, + enum fio_ddir ddir, unsigned long long *b) +{ + if (td->o.random_distribution == FIO_RAND_DIST_RANDOM) + return __get_next_rand_offset(td, f, ddir, b); + else if (td->o.random_distribution == FIO_RAND_DIST_ZIPF) + return __get_next_rand_offset_zipf(td, f, ddir, b); + else if (td->o.random_distribution == FIO_RAND_DIST_PARETO) + return __get_next_rand_offset_pareto(td, f, ddir, b); + + log_err("fio: unknown random distribution: %d\n", td->o.random_distribution); + return 1; +} + static int get_next_rand_block(struct thread_data *td, struct fio_file *f, enum fio_ddir ddir, unsigned long long *b) { diff --git a/lib/zipf.c b/lib/zipf.c new file mode 100644 index 0000000..28e8d77 --- /dev/null +++ b/lib/zipf.c @@ -0,0 +1,146 @@ +#include <math.h> +#include <string.h> +#include <inttypes.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include "ieee754.h" +#include "../log.h" +#include "zipf.h" +#include "../minmax.h" +#include "../os/os.h" + +struct fio_zipf_disk { + uint64_t ver_magic; + uint64_t nranges; + uint64_t zetan; +}; + +#define FIO_ZIPF_DISK_MAGIC 0x7a697066 +#define FIO_ZIPF_DISK_VER 1 +#define FIO_ZIPF_MAGIC ((FIO_ZIPF_DISK_MAGIC << 16) | FIO_ZIPF_DISK_VER) + +static void write_zipf(struct zipf_state *zs) +{ + struct fio_zipf_disk f; + char tmp[80]; + int fd; + + sprintf(tmp, "fio.zipf.%f.%llu", zs->theta, (unsigned long long) zs->nranges); + fd = open(tmp, O_CREAT | O_WRONLY, 0644); + if (fd == -1) + return; + + f.ver_magic = __cpu_to_le64(FIO_ZIPF_MAGIC); + f.nranges = __cpu_to_le64(zs->nranges); + f.zetan = __cpu_to_le64(fio_double_to_uint64(zs->zetan)); + if (write(fd, &f, sizeof(f)) != sizeof(f)) + unlink(tmp); + + close(fd); +} + +static void zipf_update(struct zipf_state *zs) +{ + unsigned int i; + + log_info("fio: generating zetan for theta=%f, ranges=%lu\n", zs->theta, zs->nranges); + + for (i = 0; i < zs->nranges; i++) + zs->zetan += pow(1.0 / (double) (i + 1), zs->theta); + + write_zipf(zs); +} + +static void zipf_load_gen_zeta(struct zipf_state *zs) +{ + struct fio_zipf_disk f; + char tmp[80]; + int fd; + + sprintf(tmp, "fio.zipf.%f.%llu", zs->theta, (unsigned long long) zs->nranges); + fd = open(tmp, O_RDONLY); + if (fd == -1) { +punt: + zipf_update(zs); + return; + } + + if (read(fd, &f, sizeof(f)) != sizeof(f)) { + close(fd); + goto punt; + } + + close(fd); + + f.ver_magic = le64_to_cpu(f.ver_magic); + f.nranges = le64_to_cpu(f.nranges); + f.zetan = le64_to_cpu(f.zetan); + + if (f.ver_magic != FIO_ZIPF_MAGIC) { + unlink(tmp); + goto punt; + } + + zs->zetan = fio_uint64_to_double(f.zetan); + zs->nranges = f.nranges; +} + +void zipf_init(struct zipf_state *zs, unsigned long nranges, double theta) +{ + unsigned int i; + + memset(zs, 0, sizeof(*zs)); + + zs->nranges = nranges; + zs->theta = theta; + + for (i = 1; i <= 2; i++) + zs->zeta2 += pow(1.0 / (double) i, zs->theta); + + init_rand(&zs->rand); + + zipf_load_gen_zeta(zs); +} + +unsigned long long zipf_next(struct zipf_state *zs) +{ + + double alpha, eta, rand_uni, rand_z; + unsigned long long n = zs->nranges; + unsigned long long val; + + 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_z = rand_uni * zs->zetan; + + if (rand_z < 1.0) + val = 1; + else if (rand_z < (1.0 + pow(0.5, zs->theta))) + val = 2; + else + val = 1 + (unsigned long long)(n * pow(eta*rand_uni - eta + 1.0, alpha)); + + return val - 1; +} + +void pareto_init(struct zipf_state *zs, unsigned long nranges, double h) +{ + memset(zs, 0, sizeof(*zs)); + + zs->nranges = nranges; + zs->pareto_pow = log(h) / log(1.0 - h); + + init_rand(&zs->rand); +} + +unsigned long long pareto_next(struct zipf_state *zs) +{ + double rand = (double) __rand(&zs->rand) / (double) FRAND_MAX; + unsigned long long n = zs->nranges - 1; + + return n * pow(rand, zs->pareto_pow); +} diff --git a/lib/zipf.h b/lib/zipf.h new file mode 100644 index 0000000..c66b064 --- /dev/null +++ b/lib/zipf.h @@ -0,0 +1,22 @@ +#ifndef FIO_ZIPF_H +#define FIO_ZIPF_H + +#include <inttypes.h> +#include "rand.h" + +struct zipf_state { + uint64_t nranges; + double theta; + double zeta2; + double zetan; + double pareto_pow; + struct frand_state rand; +}; + +void zipf_init(struct zipf_state *zs, unsigned long nranges, double theta); +unsigned long long zipf_next(struct zipf_state *zs); + +void pareto_init(struct zipf_state *zs, unsigned long nranges, double h); +unsigned long long pareto_next(struct zipf_state *zs); + +#endif diff --git a/minmax.h b/minmax.h new file mode 100644 index 0000000..e5c2f58 --- /dev/null +++ b/minmax.h @@ -0,0 +1,11 @@ +#ifndef FIO_MIN_MAX_H +#define FIO_MIN_MAX_H + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#endif diff --git a/options.c b/options.c index 380df36..ea1ffb1 100644 --- a/options.c +++ b/options.c @@ -728,6 +728,35 @@ static int str_sfr_cb(void *data, const char *str) } #endif +static int str_random_distribution_cb(void *data, const char *str) +{ + struct thread_data *td = data; + double val; + char *nr; + + if (td->o.random_distribution == FIO_RAND_DIST_ZIPF) + val = 1.1; + else if (td->o.random_distribution == FIO_RAND_DIST_PARETO) + val = 0.2; + else + return 0; + + nr = get_opt_postfix(str); + if (nr && !str_to_float(nr, &val)) { + log_err("fio: random postfix parsing failed\n"); + free(nr); + return 1; + } + + if (td->o.random_distribution == FIO_RAND_DIST_ZIPF) + td->o.zipf_theta = val; + else + td->o.pareto_h = val; + + free(nr); + return 0; +} + static int check_dir(struct thread_data *td, char *fname) { #if 0 @@ -1473,6 +1502,28 @@ static struct fio_option options[FIO_MAX_OPTS] = { .def = "0", }, { + .name = "random_distribution", + .type = FIO_OPT_STR, + .off1 = td_var_offset(random_distribution), + .cb = str_random_distribution_cb, + .help = "Random offset distribution generator", + .def = "random", + .posval = { + { .ival = "random", + .oval = FIO_RAND_DIST_RANDOM, + .help = "Completely random", + }, + { .ival = "zipf", + .oval = FIO_RAND_DIST_ZIPF, + .help = "Zipf distribution", + }, + { .ival = "pareto", + .oval = FIO_RAND_DIST_PARETO, + .help = "Pareto distribution", + }, + }, + }, + { .name = "nrfiles", .alias = "nr_files", .type = FIO_OPT_INT, diff --git a/parse.c b/parse.c index 1a686e4..0bbb0b3 100644 --- a/parse.c +++ b/parse.c @@ -14,6 +14,7 @@ #include "parse.h" #include "debug.h" #include "options.h" +#include "minmax.h" static struct fio_option *fio_options; extern unsigned int fio_get_kb_base(void *); @@ -220,7 +221,7 @@ static unsigned long long get_mult_bytes(const char *str, int len, void *data, /* * Convert string into a floating number. Return 1 for success and 0 otherwise. */ -static int str_to_float(const char *str, double *val) +int str_to_float(const char *str, double *val) { return (1 == sscanf(str, "%lf", val)); } @@ -505,7 +506,7 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, o->maxlen); return 1; } - if(!str_to_float(ptr, &uf)){ + if (!str_to_float(ptr, &uf)){ log_err("not a floating point value: %s\n", ptr); return 1; } diff --git a/parse.h b/parse.h index 71190ea..b2f9e5a 100644 --- a/parse.h +++ b/parse.h @@ -79,6 +79,7 @@ extern void options_free(struct fio_option *, void *); extern void strip_blank_front(char **); extern void strip_blank_end(char *); extern int str_to_decimal(const char *, long long *, int, void *); +extern int str_to_float(const char *str, double *val); /* * Handlers for the options @@ -90,13 +91,6 @@ typedef int (fio_opt_str_set_fn)(void *); #define td_var(start, offset) ((void *) start + (offset)) -#ifndef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#endif -#ifndef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#endif - static inline int parse_is_percent(unsigned long long val) { return val <= -1ULL && val >= (-1ULL - 100ULL); diff --git a/t/genzipf.c b/t/genzipf.c new file mode 100644 index 0000000..f286744 --- /dev/null +++ b/t/genzipf.c @@ -0,0 +1,122 @@ +/* + * Generate/analyze pareto/zipf distributions to better understand + * what an access pattern would look like. + * + * For instance, the following would generate a zipf distribution + * with theta 1.2, using 100,000 values and split the reporting into + * 20 buckets: + * + * t/genzipf zipf 1.2 100000 20 + * + * Only the distribution type (zipf or pareto) and spread input need + * to be given, if not given defaults are used. + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> + +#include "../lib/zipf.h" + +#define DEF_NR 1000000 +#define DEF_NR_OUTPUT 23 + +static int val_cmp(const void *p1, const void *p2) +{ + const unsigned long *v1 = p1; + const unsigned long *v2 = p2; + + return *v1 - *v2; +} + +int main(int argc, char *argv[]) +{ + unsigned long nranges, output_nranges; + unsigned long *vals; + unsigned long i, j, nr_vals, cur_vals, max_val, interval; + double *output, perc, perc_i; + struct zipf_state zs; + int use_zipf; + double val; + + if (argc < 3) { + printf("%s: {zipf,pareto} val values [output ranges]\n", argv[0]); + return 1; + } + + if (!strcmp(argv[1], "zipf")) + use_zipf = 1; + else if (!strcmp(argv[1], "pareto")) + use_zipf = 0; + else { + printf("Bad distribution type <%s>\n", argv[1]); + return 1; + } + + val = atof(argv[2]); + + nranges = DEF_NR; + output_nranges = DEF_NR_OUTPUT; + + if (argc >= 4) + nranges = strtoul(argv[3], NULL, 10); + if (argc >= 5) + output_nranges = strtoul(argv[4], NULL, 10); + + printf("Generating %s distribution with %f input and %lu ranges.\n", use_zipf ? "zipf" : "pareto", val, nranges); + + if (use_zipf) + zipf_init(&zs, nranges, val); + else + pareto_init(&zs, nranges, val); + + vals = malloc(nranges * sizeof(unsigned long)); + + max_val = nr_vals = 0; + for (i = 0; i < nranges; i++) { + if (use_zipf) + vals[nr_vals] = zipf_next(&zs); + else + vals[nr_vals] = pareto_next(&zs); + + if (vals[nr_vals] > max_val) + max_val = vals[nr_vals]; + nr_vals++; + } + + qsort(vals, nr_vals, sizeof(unsigned long), val_cmp); + + interval = (max_val + output_nranges - 1) / output_nranges; + + output = malloc(output_nranges * sizeof(double)); + + for (i = j = 0, cur_vals = 0; i < nr_vals; i++) { + if (vals[i] > interval) { + output[j] = (double) (cur_vals + 1) / (double) nr_vals; + output[j] *= 100.0; + j++; + cur_vals = 0; + interval += (max_val + output_nranges - 1) / output_nranges; + continue; + } + cur_vals++; + } + + if (cur_vals) { + output[j] = (double) (cur_vals + 1) / (double) nr_vals; + output[j] *= 100.0; + j++; + } + + perc_i = 100.0 / (double) output_nranges; + perc = 0.0; + for (i = 0; i < j; i++) { + printf("%6.2f%% -> %6.2f%%:\t%6.2f%%\n", perc, perc + perc_i, output[i]); + perc += perc_i; + } + + free(output); + free(vals); + return 0; +} diff --git a/t/ieee754.c b/t/ieee754.c index afc25f3..3898ab7 100644 --- a/t/ieee754.c +++ b/t/ieee754.c @@ -1,5 +1,5 @@ #include <stdio.h> -#include "../ieee754.h" +#include "../lib/ieee754.h" static double values[] = { -17.23, 17.23, 123.4567, 98765.4321, 0.0 }; diff --git a/t/log.c b/t/log.c index 7f1de27..ac02303 100644 --- a/t/log.c +++ b/t/log.c @@ -13,3 +13,16 @@ int log_err(const char *format, ...) return fwrite(buffer, len, 1, stderr); } + +int log_info(const char *format, ...) +{ + char buffer[1024]; + va_list args; + size_t len; + + va_start(args, format); + len = vsnprintf(buffer, sizeof(buffer), format, args); + va_end(args); + + return fwrite(buffer, len, 1, stdout); +} diff --git a/t/stest.c b/t/stest.c index c179484..0da8f2c 100644 --- a/t/stest.c +++ b/t/stest.c @@ -6,6 +6,8 @@ #include "../flist.h" FILE *f_err; +struct timeval *fio_tv = NULL; +unsigned int fio_debug = 0; #define MAGIC1 0xa9b1c8d2 #define MAGIC2 0xf0a1e9b3 @@ -82,3 +84,7 @@ int main(int argc, char *argv[]) scleanup(); return 0; } + +void __dprint(int type, const char *str, ...) +{ +} diff --git a/time.c b/time.c index 4af84bc..c4d1d4c 100644 --- a/time.c +++ b/time.c @@ -6,72 +6,6 @@ static struct timeval genesis; static unsigned long ns_granularity; -unsigned long long utime_since(struct timeval *s, struct timeval *e) -{ - long sec, usec; - unsigned long long ret; - - sec = e->tv_sec - s->tv_sec; - usec = e->tv_usec - s->tv_usec; - if (sec > 0 && usec < 0) { - sec--; - usec += 1000000; - } - - /* - * time warp bug on some kernels? - */ - if (sec < 0 || (sec == 0 && usec < 0)) - return 0; - - ret = sec * 1000000ULL + usec; - - return ret; -} - -unsigned long long utime_since_now(struct timeval *s) -{ - struct timeval t; - - fio_gettime(&t, NULL); - return utime_since(s, &t); -} - -unsigned long mtime_since(struct timeval *s, struct timeval *e) -{ - long sec, usec, ret; - - sec = e->tv_sec - s->tv_sec; - usec = e->tv_usec - s->tv_usec; - if (sec > 0 && usec < 0) { - sec--; - usec += 1000000; - } - - if (sec < 0 || (sec == 0 && usec < 0)) - return 0; - - sec *= 1000UL; - usec /= 1000UL; - ret = sec + usec; - - return ret; -} - -unsigned long mtime_since_now(struct timeval *s) -{ - struct timeval t; - void *p = __builtin_return_address(0); - - fio_gettime(&t, p); - return mtime_since(s, &t); -} - -unsigned long time_since_now(struct timeval *s) -{ - return mtime_since_now(s) / 1000; -} - /* * busy looping version for the last few usec */ -- To unsubscribe from this list: send the line "unsubscribe fio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html