The following changes since commit 8d916c942bb088204ab5c0438c297903c9160698: Catch the case where size= is less than the minimum block size (2013-04-25 10:11:41 -0600) are available in the git repository at: git://git.kernel.dk/fio.git master Jens Axboe (3): Add support for modifying the randomness of a workload Get rid of td->o.perc_seq Ensure that stat outputs are serialized Vincent Kang Fu (1): Add log_info_flush() HOWTO | 11 +++++++++++ backend.c | 2 ++ cconv.c | 2 ++ fio.1 | 9 +++++++++ fio.h | 9 +++++++++ init.c | 2 ++ io_u.c | 32 +++++++++++++++++++++++++++++--- log.c | 8 ++++++++ log.h | 1 + options.c | 43 +++++++++++++++++++++++++++++++++++++++++++ stat.c | 40 ++++++++++++++++++++++++++++++++++++---- stat.h | 3 +++ thread_options.h | 4 ++++ 13 files changed, 159 insertions(+), 7 deletions(-) --- Diff of recent changes: diff --git a/HOWTO b/HOWTO index 6445348..8211c3b 100644 --- a/HOWTO +++ b/HOWTO @@ -766,6 +766,17 @@ random_distribution=str:float By default, fio will use a completely uniform random_distribution=zipf:1.2 as the option. If a non-uniform model is used, fio will disable use of the random map. +percentage_random=int For a random workload, set how big a percentage should + be random. This defaults to 100%, in which case the workload + is fully random. It can be set from anywhere from 0 to 100. + Setting it to 0 would make the workload fully sequential. Any + setting in between will result in a random mix of sequential + and random IO, at the given percentages. + +percentage_sequential=int See percentage_random. It is guaranteed that + they add up to 100. The later setting has priority, each + will adjust the other. + norandommap Normally fio will cover every block of the file when doing random IO. If this option is given, fio will just get a new random offset without looking at past io history. This diff --git a/backend.c b/backend.c index 4d4e8ef..89ffee1 100644 --- a/backend.c +++ b/backend.c @@ -1895,6 +1895,7 @@ int fio_backend(void) return 1; set_genesis_time(); + stat_init(); create_disk_util_thread(); cgroup_list = smalloc(sizeof(*cgroup_list)); @@ -1924,5 +1925,6 @@ int fio_backend(void) fio_mutex_remove(startup_mutex); fio_mutex_remove(writeout_mutex); fio_mutex_remove(disk_thread_mutex); + stat_exit(); return exit_value; } diff --git a/cconv.c b/cconv.c index 57c76e3..b06f60f 100644 --- a/cconv.c +++ b/cconv.c @@ -125,6 +125,7 @@ void convert_thread_options_to_cpu(struct thread_options *o, o->zipf_theta.u.f = fio_uint64_to_double(le64_to_cpu(top->zipf_theta.u.i)); o->pareto_h.u.f = fio_uint64_to_double(le64_to_cpu(top->pareto_h.u.i)); o->random_generator = le32_to_cpu(top->random_generator); + o->perc_rand = le32_to_cpu(top->perc_rand); o->hugepage_size = le32_to_cpu(top->hugepage_size); o->rw_min_bs = le32_to_cpu(top->rw_min_bs); o->thinktime = le32_to_cpu(top->thinktime); @@ -283,6 +284,7 @@ void convert_thread_options_to_net(struct thread_options_pack *top, top->zipf_theta.u.i = __cpu_to_le64(fio_double_to_uint64(o->zipf_theta.u.f)); top->pareto_h.u.i = __cpu_to_le64(fio_double_to_uint64(o->pareto_h.u.f)); top->random_generator = cpu_to_le32(o->random_generator); + top->perc_rand = cpu_to_le32(o->perc_rand); top->hugepage_size = cpu_to_le32(o->hugepage_size); top->rw_min_bs = cpu_to_le32(o->rw_min_bs); top->thinktime = cpu_to_le32(o->thinktime); diff --git a/fio.1 b/fio.1 index 401d956..5082bf8 100644 --- a/fio.1 +++ b/fio.1 @@ -641,6 +641,15 @@ If you wanted to use zipf with a theta of 1.2, you would use random_distribution=zipf:1.2 as the option. If a non-uniform model is used, fio will disable use of the random map. .TP +.BI percentage_random \fR=\fPint +For a random workload, set how big a percentage should be random. This defaults +to 100%, in which case the workload is fully random. It can be set from +anywhere from 0 to 100. Setting it to 0 would make the workload fully +sequential. +.TP +.BI percentage_sequential \fR=\fPint +See \fBpercentage_random\fR. +.TP .B norandommap Normally \fBfio\fR will cover every block of the file when doing random I/O. If this parameter is given, a new offset will be chosen without looking at past diff --git a/fio.h b/fio.h index 5438b76..965d7d9 100644 --- a/fio.h +++ b/fio.h @@ -81,6 +81,7 @@ enum { FIO_RAND_FILE_SIZE_OFF, FIO_RAND_TRIM_OFF, FIO_RAND_BUF_OFF, + FIO_RAND_SEQ_RAND_OFF, FIO_RAND_NR_OFFS, }; @@ -256,6 +257,14 @@ struct thread_data { unsigned int ddir_seq_nr; /* + * rand/seq mixed workload state + */ + union { + os_random_state_t seq_rand_state; + struct frand_state __seq_rand_state; + }; + + /* * IO history logs for verification. We use a tree for sorting, * if we are overwriting. Otherwise just use a fifo. */ diff --git a/init.c b/init.c index aba7671..7246bd8 100644 --- a/init.c +++ b/init.c @@ -701,6 +701,7 @@ static void td_fill_rand_seeds_os(struct thread_data *td) td->rand_seeds[FIO_RAND_BLOCK_OFF] = FIO_RANDSEED * td->thread_number; os_random_seed(td->rand_seeds[FIO_RAND_BLOCK_OFF], &td->random_state); + os_random_seed(td->rand_seeds[FIO_RAND_SEQ_RAND_OFF], &td->seq_rand_state); } static void td_fill_rand_seeds_internal(struct thread_data *td) @@ -722,6 +723,7 @@ static void td_fill_rand_seeds_internal(struct thread_data *td) td->rand_seeds[FIO_RAND_BLOCK_OFF] = FIO_RANDSEED * td->thread_number; init_rand_seed(&td->__random_state, td->rand_seeds[FIO_RAND_BLOCK_OFF]); + init_rand_seed(&td->__seq_rand_state, td->rand_seeds[FIO_RAND_SEQ_RAND_OFF]); } void td_fill_rand_seeds(struct thread_data *td) diff --git a/io_u.c b/io_u.c index 19ef7b9..d03049e 100644 --- a/io_u.c +++ b/io_u.c @@ -191,6 +191,25 @@ static inline int should_sort_io(struct thread_data *td) return 1; } +static int should_do_random(struct thread_data *td) +{ + unsigned int v; + unsigned long r; + + if (td->o.perc_rand == 100) + return 1; + + if (td->o.use_os_rand) { + r = os_random_long(&td->seq_rand_state); + v = 1 + (int) (100.0 * (r / (OS_RAND_MAX + 1.0))); + } else { + r = __rand(&td->__seq_rand_state); + v = 1 + (int) (100.0 * (r / (FRAND_MAX + 1.0))); + } + + return v <= td->o.perc_rand; +} + static int get_next_rand_offset(struct thread_data *td, struct fio_file *f, enum fio_ddir ddir, uint64_t *b) { @@ -285,9 +304,16 @@ static int get_next_block(struct thread_data *td, struct io_u *io_u, b = offset = -1ULL; if (rw_seq) { - if (td_random(td)) - ret = get_next_rand_block(td, f, ddir, &b); - else + if (td_random(td)) { + if (should_do_random(td)) + ret = get_next_rand_block(td, f, ddir, &b); + else { + io_u->flags |= IO_U_F_BUSY_OK; + ret = get_next_seq_offset(td, f, ddir, &offset); + if (ret) + ret = get_next_rand_block(td, f, ddir, &b); + } + } else ret = get_next_seq_offset(td, f, ddir, &offset); } else { io_u->flags |= IO_U_F_BUSY_OK; diff --git a/log.c b/log.c index d481edf..4822c33 100644 --- a/log.c +++ b/log.c @@ -71,6 +71,14 @@ int log_info(const char *format, ...) return fwrite(buffer, len, 1, f_out); } +int log_info_flush(void) +{ + if (is_backend || log_syslog) + return 0; + + return fflush(f_out); +} + int log_err(const char *format, ...) { char buffer[1024]; diff --git a/log.h b/log.h index 25f92f9..a885be7 100644 --- a/log.h +++ b/log.h @@ -12,6 +12,7 @@ extern int log_info(const char *format, ...) __attribute__ ((__format__ (__print extern int log_local(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2))); extern int log_valist(const char *str, va_list); extern int log_local_buf(const char *buf, size_t); +extern int log_info_flush(void); enum { FIO_LOG_DEBUG = 1, diff --git a/options.c b/options.c index 1219803..7a4e7b5 100644 --- a/options.c +++ b/options.c @@ -376,6 +376,23 @@ static int str_rwmix_write_cb(void *data, unsigned long long *val) return 0; } +static int str_perc_rand_cb(void *data, unsigned long long *val) +{ + struct thread_data *td = data; + + td->o.perc_rand = *val; + return 0; +} + +static int str_perc_seq_cb(void *data, unsigned long long *val) +{ + struct thread_data *td = data; + + td->o.perc_rand = 100 - *val; + return 0; +} + + static int str_exitall_cb(void) { exitall_on_terminate = 1; @@ -1643,6 +1660,32 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .group = FIO_OPT_G_RANDOM, }, { + .name = "percentage_random", + .lname = "Percentage Random", + .type = FIO_OPT_INT, + .cb = str_perc_rand_cb, + .maxval = 100, + .help = "Percentage of seq/random mix that should be random", + .def = "100", + .interval = 5, + .inverse = "percentage_sequential", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_RANDOM, + }, + { + .name = "percentage_sequential", + .lname = "Percentage Sequential", + .type = FIO_OPT_INT, + .cb = str_perc_seq_cb, + .maxval = 100, + .help = "Percentage of seq/random mix that should be sequential", + .def = "0", + .interval = 5, + .inverse = "percentage_random", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_RANDOM, + }, + { .name = "nrfiles", .lname = "Number of files", .alias = "nr_files", diff --git a/stat.c b/stat.c index 7ff7ad4..b386188 100644 --- a/stat.c +++ b/stat.c @@ -14,6 +14,8 @@ #include "lib/getrusage.h" #include "idletime.h" +static struct fio_mutex *stat_mutex; + void update_rusage_stat(struct thread_data *td) { struct thread_stat *ts = &td->ts; @@ -1141,7 +1143,7 @@ void init_thread_stat(struct thread_stat *ts) ts->groupid = -1; } -void show_run_stats(void) +static void __show_run_stats(void) { struct group_run_stats *runstats, *rs; struct thread_data *td; @@ -1354,10 +1356,18 @@ void show_run_stats(void) show_idle_prof_stats(FIO_OUTPUT_NORMAL, NULL); } + log_info_flush(); free(runstats); free(threadstats); } +void show_run_stats(void) +{ + fio_mutex_down(stat_mutex); + __show_run_stats(); + fio_mutex_up(stat_mutex); +} + static void *__show_running_run_stats(void fio_unused *arg) { struct thread_data *td; @@ -1392,7 +1402,7 @@ static void *__show_running_run_stats(void fio_unused *arg) td->update_rusage = 0; } - show_run_stats(); + __show_run_stats(); for_each_td(td, i) { if (td_read(td) && td->io_bytes[DDIR_READ]) @@ -1404,6 +1414,7 @@ static void *__show_running_run_stats(void fio_unused *arg) } free(rt); + fio_mutex_up(stat_mutex); return NULL; } @@ -1416,8 +1427,14 @@ void show_running_run_stats(void) { pthread_t thread; - pthread_create(&thread, NULL, __show_running_run_stats, NULL); - pthread_detach(thread); + fio_mutex_down(stat_mutex); + + if (!pthread_create(&thread, NULL, __show_running_run_stats, NULL)) { + pthread_detach(thread); + return; + } + + fio_mutex_up(stat_mutex); } static int status_interval_init; @@ -1700,3 +1717,18 @@ void add_iops_sample(struct thread_data *td, enum fio_ddir ddir, fio_gettime(&td->iops_sample_time, NULL); } + +void stat_init(void) +{ + stat_mutex = fio_mutex_init(FIO_MUTEX_UNLOCKED); +} + +void stat_exit(void) +{ + /* + * When we have the mutex, we know out-of-band access to it + * have ended. + */ + fio_mutex_down(stat_mutex); + fio_mutex_remove(stat_mutex); +} diff --git a/stat.h b/stat.h index b1bf5dc..541b77e 100644 --- a/stat.h +++ b/stat.h @@ -199,6 +199,9 @@ struct jobs_eta { uint8_t run_str[]; }; +extern void stat_init(void); +extern void stat_exit(void); + extern void show_thread_status(struct thread_stat *ts, struct group_run_stats *rs); extern void show_group_stats(struct group_run_stats *rs); extern int calc_thread_status(struct jobs_eta *je, int force); diff --git a/thread_options.h b/thread_options.h index f25988a..45e22ae 100644 --- a/thread_options.h +++ b/thread_options.h @@ -113,6 +113,8 @@ struct thread_options { unsigned int random_generator; + unsigned int perc_rand; + unsigned int hugepage_size; unsigned int rw_min_bs; unsigned int thinktime; @@ -322,6 +324,8 @@ struct thread_options_pack { uint32_t random_generator; + uint32_t perc_rand; + uint32_t hugepage_size; uint32_t rw_min_bs; uint32_t thinktime; -- 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