From f7cf63bf4d0488c1f47b8cb957ac881fd9ecec41 Mon Sep 17 00:00:00 2001 From: Venkat Ramesh Date: Sun, 7 Feb 2021 20:57:40 -0800 Subject: [PATCH] options: allow separate values for max_latency Adding the ability to specify max_latency limits separately for read, write, trim. Uses comma-separated values similar to blocksize, rate parameters etc. Also modifies the behavior for the one option only case for max_latency and latency_target by excluding syncs. This makes the latency limits similar to the rate checks, in that they only apply to reads, writes and trims. Extends the output printed on latency exceeded event, to display io_unit information using format similar to that iolog write. Signed-off-by: Venkat Ramesh --- HOWTO | 5 +++-- cconv.c | 6 ++++-- fio.1 | 5 +++-- init.c | 4 +++- io_u.c | 23 +++++++++++++++-------- options.c | 6 ++++-- server.h | 2 +- thread_options.h | 4 ++-- 8 files changed, 35 insertions(+), 20 deletions(-) diff --git a/HOWTO b/HOWTO index 52812cc7..1e5ebd5d 100644 --- a/HOWTO +++ b/HOWTO @@ -2663,11 +2663,12 @@ I/O latency true, fio will continue running and try to meet :option:`latency_target` by adjusting queue depth. -.. option:: max_latency=time +.. option:: max_latency=time[,time][,time] If set, fio will exit the job with an ETIMEDOUT error if it exceeds this maximum latency. When the unit is omitted, the value is interpreted in - microseconds. + microseconds. Comma-separated values may be specified for reads, writes, + and trims as described in :option:`blocksize`. .. option:: rate_cycle=int diff --git a/cconv.c b/cconv.c index b10868fb..aa06e3ea 100644 --- a/cconv.c +++ b/cconv.c @@ -143,6 +143,8 @@ void convert_thread_options_to_cpu(struct thread_options *o, o->rate_iops_min[i] = le32_to_cpu(top->rate_iops_min[i]); o->perc_rand[i] = le32_to_cpu(top->perc_rand[i]); + + o->max_latency[i] = le64_to_cpu(top->max_latency[i]); } o->ratecycle = le32_to_cpu(top->ratecycle); @@ -289,7 +291,6 @@ void convert_thread_options_to_cpu(struct thread_options *o, o->sync_file_range = le32_to_cpu(top->sync_file_range); o->latency_target = le64_to_cpu(top->latency_target); o->latency_window = le64_to_cpu(top->latency_window); - o->max_latency = le64_to_cpu(top->max_latency); o->latency_percentile.u.f = fio_uint64_to_double(le64_to_cpu(top->latency_percentile.u.i)); o->latency_run = le32_to_cpu(top->latency_run); o->compress_percentage = le32_to_cpu(top->compress_percentage); @@ -491,7 +492,6 @@ void convert_thread_options_to_net(struct thread_options_pack *top, top->sync_file_range = cpu_to_le32(o->sync_file_range); top->latency_target = __cpu_to_le64(o->latency_target); top->latency_window = __cpu_to_le64(o->latency_window); - top->max_latency = __cpu_to_le64(o->max_latency); top->latency_percentile.u.i = __cpu_to_le64(fio_double_to_uint64(o->latency_percentile.u.f)); top->latency_run = __cpu_to_le32(o->latency_run); top->compress_percentage = cpu_to_le32(o->compress_percentage); @@ -550,6 +550,8 @@ void convert_thread_options_to_net(struct thread_options_pack *top, top->rate_iops_min[i] = cpu_to_le32(o->rate_iops_min[i]); top->perc_rand[i] = cpu_to_le32(o->perc_rand[i]); + + top->max_latency[i] = __cpu_to_le64(o->max_latency[i]); } memcpy(top->verify_pattern, o->verify_pattern, MAX_PATTERN_SIZE); diff --git a/fio.1 b/fio.1 index 2c0d8348..b95a67ab 100644 --- a/fio.1 +++ b/fio.1 @@ -2403,10 +2403,11 @@ Used with \fBlatency_target\fR. If false (default), fio will find the highest queue depth that meets \fBlatency_target\fR and exit. If true, fio will continue running and try to meet \fBlatency_target\fR by adjusting queue depth. .TP -.BI max_latency \fR=\fPtime +.BI max_latency \fR=\fPtime[,time][,time] If set, fio will exit the job with an ETIMEDOUT error if it exceeds this maximum latency. When the unit is omitted, the value is interpreted in -microseconds. +microseconds. Comma-separated values may be specified for reads, writes, +and trims as described in \fBblocksize\fR. .TP .BI rate_cycle \fR=\fPint Average bandwidth for \fBrate\fR and \fBrate_min\fR over this number diff --git a/init.c b/init.c index eea6e546..e8530fec 100644 --- a/init.c +++ b/init.c @@ -961,7 +961,9 @@ static int fixup_options(struct thread_data *td) /* * Fix these up to be nsec internally */ - o->max_latency *= 1000ULL; + for_each_rw_ddir(ddir) + o->max_latency[ddir] *= 1000ULL; + o->latency_target *= 1000ULL; return ret; diff --git a/io_u.c b/io_u.c index 00a219c2..b421a579 100644 --- a/io_u.c +++ b/io_u.c @@ -1389,11 +1389,16 @@ static long set_io_u_file(struct thread_data *td, struct io_u *io_u) return 0; } -static void lat_fatal(struct thread_data *td, struct io_completion_data *icd, +static void lat_fatal(struct thread_data *td, struct io_u *io_u, struct io_completion_data *icd, unsigned long long tnsec, unsigned long long max_nsec) { - if (!td->error) - log_err("fio: latency of %llu nsec exceeds specified max (%llu nsec)\n", tnsec, max_nsec); + if (!td->error) { + log_err("fio: latency of %llu nsec exceeds specified max (%llu nsec): %s %s %llu %llu\n", + tnsec, max_nsec, + io_u->file->file_name, + io_ddir_name(io_u->ddir), + io_u->offset, io_u->buflen); + } td_verror(td, ETIMEDOUT, "max latency exceeded"); icd->error = ETIMEDOUT; } @@ -1888,11 +1893,13 @@ static void account_io_completion(struct thread_data *td, struct io_u *io_u, icd->error = ops->io_u_lat(td, tnsec); } - if (td->o.max_latency && tnsec > td->o.max_latency) - lat_fatal(td, icd, tnsec, td->o.max_latency); - if (td->o.latency_target && tnsec > td->o.latency_target) { - if (lat_target_failed(td)) - lat_fatal(td, icd, tnsec, td->o.latency_target); + if (ddir_rw(idx)) { + if (td->o.max_latency[idx] && tnsec > td->o.max_latency[idx]) + lat_fatal(td, io_u, icd, tnsec, td->o.max_latency[idx]); + if (td->o.latency_target && tnsec > td->o.latency_target) { + if (lat_target_failed(td)) + lat_fatal(td, io_u, icd, tnsec, td->o.latency_target); + } } } diff --git a/options.c b/options.c index e3b0c4ef..0791101e 100644 --- a/options.c +++ b/options.c @@ -3756,8 +3756,10 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "max_latency", .lname = "Max Latency (usec)", - .type = FIO_OPT_STR_VAL_TIME, - .off1 = offsetof(struct thread_options, max_latency), + .type = FIO_OPT_ULL, + .off1 = offsetof(struct thread_options, max_latency[DDIR_READ]), + .off2 = offsetof(struct thread_options, max_latency[DDIR_WRITE]), + .off3 = offsetof(struct thread_options, max_latency[DDIR_TRIM]), .help = "Maximum tolerated IO latency (usec)", .is_time = 1, .category = FIO_OPT_C_IO, diff --git a/server.h b/server.h index 74618ca7..b45b319b 100644 --- a/server.h +++ b/server.h @@ -48,7 +48,7 @@ struct fio_net_cmd_reply { }; enum { - FIO_SERVER_VER = 88, + FIO_SERVER_VER = 89, FIO_SERVER_MAX_FRAGMENT_PDU = 1024, FIO_SERVER_MAX_CMD_MB = 2048, diff --git a/thread_options.h b/thread_options.h index 88fd7ad9..5ecc72d7 100644 --- a/thread_options.h +++ b/thread_options.h @@ -207,7 +207,7 @@ struct thread_options { enum fio_memtype mem_type; unsigned int mem_align; - unsigned long long max_latency; + unsigned long long max_latency[DDIR_RWDIR_CNT]; unsigned int exit_what; unsigned int stonewall; @@ -629,7 +629,7 @@ struct thread_options_pack { uint64_t latency_target; uint64_t latency_window; - uint64_t max_latency; + uint64_t max_latency[DDIR_RWDIR_CNT]; uint32_t pad5; fio_fp64_t latency_percentile; uint32_t latency_run; -- 2.25.1