From 4e991c23d2d06484f581eb5e2105bc102cb35941 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 15 Mar 2007 11:41:11 +0100 Subject: [PATCH 1/1] Support for setting rated based on IOPS Signed-off-by: Jens Axboe --- HOWTO | 11 ++++++++++- fio.c | 45 +++++++++++++++++++++++++++++++++++---------- fio.h | 3 +++ init.c | 16 ++++++++++++++-- log.c | 15 +++++++-------- options.c | 14 +++++++++++++- time.c | 2 +- 7 files changed, 83 insertions(+), 23 deletions(-) diff --git a/HOWTO b/HOWTO index c8a84ae9..c1403931 100644 --- a/HOWTO +++ b/HOWTO @@ -418,7 +418,16 @@ thinktime_blocks rate=int Cap the bandwidth used by this job to this number of KiB/sec. ratemin=int Tell fio to do whatever it can to maintain at least this - bandwidth. + bandwidth. Failing to meet this requirement, will cause + the job to exit. + +rate_iops=int Cap the bandwidth to this number of IOPS. Basically the same + as rate, just specified independently of bandwidth. If the + job is given a block size range instead of a fixed value, + the smallest block size is used as the metric. + +rate_iops_min=int If fio doesn't meet this rate of IO, it will cause + the job to exit. ratecycle=int Average bandwidth for 'rate' and 'ratemin' over this number of milliseconds. diff --git a/fio.c b/fio.c index b5fada89..478ef28a 100644 --- a/fio.c +++ b/fio.c @@ -103,13 +103,14 @@ static void sig_handler(int sig) static int check_min_rate(struct thread_data *td, struct timeval *now) { unsigned long long bytes = 0; + unsigned long iops = 0; unsigned long spent; unsigned long rate; /* * No minimum rate set, always ok */ - if (!td->ratemin) + if (!td->ratemin && !td->rate_iops_min) return 0; /* @@ -118,32 +119,55 @@ static int check_min_rate(struct thread_data *td, struct timeval *now) if (mtime_since(&td->start, now) < 2000) return 0; - if (td_read(td)) + if (td_read(td)) { + iops += td->io_blocks[DDIR_READ]; bytes += td->this_io_bytes[DDIR_READ]; - if (td_write(td)) + } + if (td_write(td)) { + iops += td->io_blocks[DDIR_WRITE]; bytes += td->this_io_bytes[DDIR_WRITE]; + } /* * if rate blocks is set, sample is running */ - if (td->rate_bytes) { + if (td->rate_bytes || td->rate_blocks) { spent = mtime_since(&td->lastrate, now); if (spent < td->ratecycle) return 0; - if (bytes < td->rate_bytes) { - log_err("%s: min rate %u not met\n", td->name, td->ratemin); - return 1; + if (td->rate) { + /* + * check bandwidth specified rate + */ + if (bytes < td->rate_bytes) { + log_err("%s: min rate %u not met\n", td->name, td->ratemin); + return 1; + } else { + rate = (bytes - td->rate_bytes) / spent; + if (rate < td->ratemin || bytes < td->rate_bytes) { + log_err("%s: min rate %u not met, got %luKiB/sec\n", td->name, td->ratemin, rate); + return 1; + } + } } else { - rate = (bytes - td->rate_bytes) / spent; - if (rate < td->ratemin || bytes < td->rate_bytes) { - log_err("%s: min rate %u not met, got %luKiB/sec\n", td->name, td->ratemin, rate); + /* + * checks iops specified rate + */ + if (iops < td->rate_iops) { + log_err("%s: min iops rate %u not met\n", td->name, td->rate_iops); return 1; + } else { + rate = (iops - td->rate_blocks) / spent; + if (rate < td->rate_iops_min || iops < td->rate_blocks) { + log_err("%s: min iops rate %u not met, got %lu\n", td->name, td->rate_iops_min, rate); + } } } } td->rate_bytes = bytes; + td->rate_blocks = iops; memcpy(&td->lastrate, now, sizeof(*now)); return 0; } @@ -666,6 +690,7 @@ static int clear_io_state(struct thread_data *td) td->this_io_bytes[0] = td->this_io_bytes[1] = 0; td->zone_bytes = 0; td->rate_bytes = 0; + td->rate_blocks = 0; td->last_was_sync = 0; diff --git a/fio.h b/fio.h index b7657181..a6adcb7b 100644 --- a/fio.h +++ b/fio.h @@ -431,9 +431,12 @@ struct thread_data { unsigned int rate; unsigned int ratemin; unsigned int ratecycle; + unsigned int rate_iops; + unsigned int rate_iops_min; unsigned long rate_usec_cycle; long rate_pending_usleep; unsigned long rate_bytes; + unsigned long rate_blocks; struct timeval lastrate; unsigned long long io_size; diff --git a/init.c b/init.c index 2fc7f072..15e96aac 100644 --- a/init.c +++ b/init.c @@ -135,7 +135,7 @@ static void put_job(struct thread_data *td) * Lazy way of fixing up options that depend on each other. We could also * define option callback handlers, but this is easier. */ -static void fixup_options(struct thread_data *td) +static int fixup_options(struct thread_data *td) { if (!td->rwmixread && td->rwmixwrite) td->rwmixread = 100 - td->rwmixwrite; @@ -221,6 +221,17 @@ static void fixup_options(struct thread_data *td) if (td->open_files > td->nr_files || !td->open_files) td->open_files = td->nr_files; + + if ((td->rate && td->rate_iops) || (td->ratemin && td->rate_iops_min)) { + log_err("fio: rate and rate_iops are mutually exclusive\n"); + return 1; + } + if ((td->rate < td->ratemin) || (td->rate_iops < td->rate_iops_min)) { + log_err("fio: minimum rate exceeds rate\n"); + return 1; + } + + return 0; } /* @@ -380,7 +391,8 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num) } } - fixup_options(td); + if (fixup_options(td)) + goto err; for_each_file(td, f, i) { if (td->directory && f->filetype == FIO_TYPE_FILE) { diff --git a/log.c b/log.c index 50caf3d4..df2edc6b 100644 --- a/log.c +++ b/log.c @@ -189,14 +189,9 @@ int setup_rate(struct thread_data *td) int nr_reads_per_msec; unsigned int bs; - if (!td->rate) + if (!td->rate && !td->rate_iops) return 0; - if (td->rate < td->ratemin) { - log_err("min rate larger than nominal rate\n"); - return -1; - } - if (td_rw(td)) bs = td->rw_min_bs; else if (td_read(td)) @@ -204,8 +199,12 @@ int setup_rate(struct thread_data *td) else bs = td->min_bs[DDIR_WRITE]; - rate = td->rate; - nr_reads_per_msec = (rate * 1024 * 1000) / bs; + if (td->rate) { + rate = td->rate; + nr_reads_per_msec = (rate * 1024 * 1000) / bs; + } else + nr_reads_per_msec = td->rate_iops * 1000; + if (!nr_reads_per_msec) { log_err("rate lower than supported\n"); return -1; diff --git a/options.c b/options.c index abd02c8c..f502247d 100644 --- a/options.c +++ b/options.c @@ -637,7 +637,19 @@ static struct fio_option options[] = { .name = "ratemin", .type = FIO_OPT_INT, .off1 = td_var_offset(ratemin), - .help = "The bottom limit accepted", + .help = "Job must meet this rate or it will be shutdown", + }, + { + .name = "rate_iops", + .type = FIO_OPT_INT, + .off1 = td_var_offset(rate_iops), + .help = "Limit IO used to this number of IO operations/sec", + }, + { + .name = "rate_iops_min", + .type = FIO_OPT_INT, + .off1 = td_var_offset(rate_iops_min), + .help = "Job must meet this rate or it will be shutdown", }, { .name = "ratecycle", diff --git a/time.c b/time.c index 45a415cb..c5b67ff1 100644 --- a/time.c +++ b/time.c @@ -114,7 +114,7 @@ void rate_throttle(struct thread_data *td, unsigned long time_spent, unsigned long usec_cycle; unsigned int bs; - if (!td->rate) + if (!td->rate && !td->rate_iops) return; if (td_rw(td)) -- 2.25.1