options: allow separate values for max_latency
authorVenkat Ramesh <venkatraghavan@fb.com>
Mon, 8 Feb 2021 04:57:40 +0000 (20:57 -0800)
committerVenkat Ramesh <venkatraghavan@fb.com>
Wed, 10 Mar 2021 03:01:41 +0000 (19:01 -0800)
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 <venkatraghavan@fb.com>
HOWTO
cconv.c
fio.1
init.c
io_u.c
options.c
server.h
thread_options.h

diff --git a/HOWTO b/HOWTO
index 52812cc7de37e7d5d95c34c45e757c8126643709..1e5ebd5df9188cf606adb4b1b2733b49dc9348cc 100644 (file)
--- 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 b10868fb3de6b2dd0844799ab36fd145ff68448e..aa06e3ea6ee7004cc4b65d99839a83f492766d9c 100644 (file)
--- 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 2c0d83487bfca54238c03a01ac69f353d91fa8b3..b95a67ab681a3641274413fe7eb1f2539e26375b 100644 (file)
--- 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 eea6e54692b177036dce001134f8ed1baeb62ca8..e8530fec2c4da8a961692eaed7a046a357dab0e9 100644 (file)
--- 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 00a219c2e85922906dd859583ef6f1ae31ad29c0..b421a579bd0a1aaa594692a21731a2774de77cea 100644 (file)
--- 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);
+                       }
                }
        }
 
index e3b0c4effe9c2e38bf94ebe62b94d156fb8913c0..0791101e8f41f5343421faa1863bb6660553521c 100644 (file)
--- 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,
index 74618ca7fcf951ee30655dcb65e768a6f1bec74a..b45b319ba2013e56ecc87056e8e0b6ca1aaec6e2 100644 (file)
--- 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,
index 88fd7ad97001f7026c3353067cc851b81cdd52de..5ecc72d7b590c37615d3625bff10a0ea907a5f1d 100644 (file)
@@ -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;