Add option latency_run to continue enable latency_target
authorSong Liu <songliubraving@fb.com>
Mon, 18 May 2020 05:39:49 +0000 (22:39 -0700)
committerSong Liu <songliubraving@fb.com>
Tue, 19 May 2020 21:35:04 +0000 (14:35 -0700)
Currently, latency_target run will exist once fio find the highest queue
depth that meets latency_target. Add option latency_run. If set, fio will
continue running and try to meet latency_target by adusting queue depth.

Signed-off-by: Song Liu <songliubraving@fb.com>
HOWTO
cconv.c
fio.1
fio.h
io_u.c
options.c
server.h
thread_options.h

diff --git a/HOWTO b/HOWTO
index 430c7b62bff8e28c40065cb8ac877579c2325a99..f0b4ffe436d768e83f97a4a0fdbf16e7294ceffa 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -2551,6 +2551,13 @@ I/O latency
        defaults to 100.0, meaning that all I/Os must be equal or below to the value
        set by :option:`latency_target`.
 
+.. option:: latency_run=bool
+
+       Used with :option:`latency_target`. If false (default), fio will find
+       the highest queue depth that meets :option:`latency_target` and exit. If
+       true, fio will continue running and try to meet :option:`latency_target`
+       by adjusting queue depth.
+
 .. option:: max_latency=time
 
        If set, fio will exit the job with an ETIMEDOUT error if it exceeds this
diff --git a/cconv.c b/cconv.c
index 48218dc4adf86e29f410d91e34f75bea4ef4b2b3..449bcf7b1678bdd6443aafd760970c7f8d503795 100644 (file)
--- a/cconv.c
+++ b/cconv.c
@@ -288,6 +288,7 @@ void convert_thread_options_to_cpu(struct thread_options *o,
        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);
        o->compress_chunk = le32_to_cpu(top->compress_chunk);
        o->dedupe_percentage = le32_to_cpu(top->dedupe_percentage);
@@ -487,6 +488,7 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
        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);
        top->compress_chunk = cpu_to_le32(o->compress_chunk);
        top->dedupe_percentage = cpu_to_le32(o->dedupe_percentage);
diff --git a/fio.1 b/fio.1
index a2379f9816c2b0103191ff15338d9180527bf896..3a7a359b1a6cc4bbe7858795995bfff2462ae1ff 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -2275,6 +2275,11 @@ The percentage of I/Os that must fall within the criteria specified by
 defaults to 100.0, meaning that all I/Os must be equal or below to the value
 set by \fBlatency_target\fR.
 .TP
+.BI latency_run \fR=\fPbool
+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
 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
diff --git a/fio.h b/fio.h
index bbf057c104cd39ab79576bc1baf06725aaceeb61..7610026da3eb14274d34e38f0b9802479aa210a7 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -377,6 +377,7 @@ struct thread_data {
        unsigned int latency_qd_high;
        unsigned int latency_qd_low;
        unsigned int latency_failed;
+       unsigned int latency_stable_count;
        uint64_t latency_ios;
        int latency_end_run;
 
diff --git a/io_u.c b/io_u.c
index aa8808b8fe1294764ee3b6696cc5913521c29a3c..ae1438fd665673e3077cc41c8dae0e4ace1b01c4 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -1391,6 +1391,7 @@ static bool __lat_target_failed(struct thread_data *td)
                td->latency_qd_low--;
 
        td->latency_qd = (td->latency_qd + td->latency_qd_low) / 2;
+       td->latency_stable_count = 0;
 
        dprint(FD_RATE, "Ramped down: %d %d %d\n", td->latency_qd_low, td->latency_qd, td->latency_qd_high);
 
@@ -1440,6 +1441,21 @@ static void lat_target_success(struct thread_data *td)
 
        td->latency_qd_low = td->latency_qd;
 
+       if (td->latency_qd + 1 == td->latency_qd_high) {
+               /*
+                * latency_qd will not incease on lat_target_success(), so
+                * called stable. If we stick with this queue depth, the
+                * final latency is likely lower than latency_target. Fix
+                * this by increasing latency_qd_high slowly. Use a naive
+                * heuristic here. If we get lat_target_success() 3 times
+                * in a row, increase latency_qd_high by 1.
+                */
+               if (++td->latency_stable_count >= 3) {
+                       td->latency_qd_high++;
+                       td->latency_stable_count = 0;
+               }
+       }
+
        /*
         * If we haven't failed yet, we double up to a failing value instead
         * of bisecting from highest possible queue depth. If we have set
@@ -1459,7 +1475,7 @@ static void lat_target_success(struct thread_data *td)
         * Same as last one, we are done. Let it run a latency cycle, so
         * we get only the results from the targeted depth.
         */
-       if (td->latency_qd == qd) {
+       if (!o->latency_run && td->latency_qd == qd) {
                if (td->latency_end_run) {
                        dprint(FD_RATE, "We are done\n");
                        td->done = 1;
index b18cea3369a206b30e1e0aa1b0fcd5edf1171cfc..da401aed118c1b2b6e5da25be4ebab4268e3a242 100644 (file)
--- a/options.c
+++ b/options.c
@@ -3672,6 +3672,16 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_LATPROF,
        },
+       {
+               .name   = "latency_run",
+               .lname  = "Latency Run",
+               .type   = FIO_OPT_BOOL,
+               .off1   = offsetof(struct thread_options, latency_run),
+               .help   = "Keep adjusting queue depth to match latency_target",
+               .def    = "0",
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_LATPROF,
+       },
        {
                .name   = "invalidate",
                .lname  = "Cache invalidate",
index 279b691745bd1965ebdb34a2ccf2b4dcdf757409..de01a5c8e4b8939c066ca539f01aa503bbd61c42 100644 (file)
--- a/server.h
+++ b/server.h
@@ -48,7 +48,7 @@ struct fio_net_cmd_reply {
 };
 
 enum {
-       FIO_SERVER_VER                  = 82,
+       FIO_SERVER_VER                  = 83,
 
        FIO_SERVER_MAX_FRAGMENT_PDU     = 1024,
        FIO_SERVER_MAX_CMD_MB           = 2048,
index c78ed43de9867876ee0b6dbefdc6b09334d5167a..09ccd5b2259fc126812aa17b9eb23ad0deb99847 100644 (file)
@@ -324,6 +324,7 @@ struct thread_options {
        unsigned long long latency_target;
        unsigned long long latency_window;
        fio_fp64_t latency_percentile;
+       uint32_t latency_run;
 
        unsigned int sig_figs;
 
@@ -612,6 +613,7 @@ struct thread_options_pack {
        uint64_t latency_window;
        uint64_t max_latency;
        fio_fp64_t latency_percentile;
+       uint32_t latency_run;
 
        uint32_t sig_figs;