From: Jens Axboe <axboe@kernel.dk>
To: fio@vger.kernel.org
Subject: Recent changes (master)
Date: Wed, 5 Feb 2020 06:00:02 -0700 (MST) [thread overview]
Message-ID: <20200205130002.3E8491BC017F@kernel.dk> (raw)
The following changes since commit ab45cf076766ce1ed49d28380c059343305cde4a:
Merge branch 'stat-averaging-interval-start-fix' of https://github.com/maciejsszmigiero/fio (2020-01-28 14:15:35 -0700)
are available in the Git repository at:
git://git.kernel.dk/fio.git master
for you to fetch changes up to f4cd67d8dc96ca947b294f6a5c9fdced2b64215d:
Merge branch 'latency-rebase-again' of https://github.com/vincentkfu/fio (2020-02-04 10:05:09 -0700)
----------------------------------------------------------------
Jens Axboe (2):
Merge branch 'filestat2' of https://github.com/kusumi/fio
Merge branch 'latency-rebase-again' of https://github.com/vincentkfu/fio
Tomohiro Kusumi (1):
engines/filestat: change "lstat" bool option to "stat_type" str option
Vincent Fu (10):
fio: groundwork for adding slat, lat percentiles
fio: report percentiles for slat, clat, lat
gfio: display slat, clat, and lat percentiles
docs: updates for slat, clat, lat percentile reporting
stat: make priority summary statistics consistent with percentiles
fio: better distinguish between high and low priority
stat: fix high/low prio unified rw bug
t/latency_percentiles: test latency percentile reporting
t/run-fio-tests: add latency_percentiles.py
t/run-fio-tests: increase time allowed for tests to pass
HOWTO | 30 +-
cconv.c | 2 +
client.c | 14 +-
engines/filestat.c | 53 +-
fio.1 | 28 +-
gclient.c | 27 +-
init.c | 19 +-
options.c | 31 +-
server.c | 14 +-
server.h | 2 +-
stat.c | 440 +++++++--------
stat.h | 22 +-
t/latency_percentiles.py | 1324 ++++++++++++++++++++++++++++++++++++++++++++++
t/run-fio-tests.py | 14 +-
thread_options.h | 11 +-
15 files changed, 1672 insertions(+), 359 deletions(-)
create mode 100755 t/latency_percentiles.py
---
Diff of recent changes:
diff --git a/HOWTO b/HOWTO
index f19f9226..430c7b62 100644
--- a/HOWTO
+++ b/HOWTO
@@ -2261,9 +2261,10 @@ with the caveat that when used on the command line, they must come after the
multiple paths exist between the client and the server or in certain loopback
configurations.
-.. option:: lstat=bool : [filestat]
+.. option:: stat_type=str : [filestat]
- Use lstat(2) to measure lookup/getattr performance. Default is 0.
+ Specify stat system call type to measure lookup/getattr performance.
+ Default is **stat** for :manpage:`stat(2)`.
.. option:: readfua=bool : [sg]
@@ -3346,27 +3347,28 @@ Measurements and reporting
Disable measurements of throughput/bandwidth numbers. See
:option:`disable_lat`.
+.. option:: slat_percentiles=bool
+
+ Report submission latency percentiles. Submission latency is not recorded
+ for synchronous ioengines.
+
.. option:: clat_percentiles=bool
- Enable the reporting of percentiles of completion latencies. This
- option is mutually exclusive with :option:`lat_percentiles`.
+ Report completion latency percentiles.
.. option:: lat_percentiles=bool
- Enable the reporting of percentiles of I/O latencies. This is similar
- to :option:`clat_percentiles`, except that this includes the
- submission latency. This option is mutually exclusive with
- :option:`clat_percentiles`.
+ Report total latency percentiles. Total latency is the sum of submission
+ latency and completion latency.
.. option:: percentile_list=float_list
- Overwrite the default list of percentiles for completion latencies and
- the block error histogram. Each number is a floating number in the
- range (0,100], and the maximum length of the list is 20. Use ``:`` to
- separate the numbers, and list the numbers in ascending order. For
+ Overwrite the default list of percentiles for latencies and the block error
+ histogram. Each number is a floating point number in the range (0,100], and
+ the maximum length of the list is 20. Use ``:`` to separate the numbers. For
example, ``--percentile_list=99.5:99.9`` will cause fio to report the
- values of completion latency below which 99.5% and 99.9% of the observed
- latencies fell, respectively.
+ latency durations below which 99.5% and 99.9% of the observed latencies fell,
+ respectively.
.. option:: significant_figures=int
diff --git a/cconv.c b/cconv.c
index 04854b0e..48218dc4 100644
--- a/cconv.c
+++ b/cconv.c
@@ -271,6 +271,7 @@ void convert_thread_options_to_cpu(struct thread_options *o,
o->trim_zero = le32_to_cpu(top->trim_zero);
o->clat_percentiles = le32_to_cpu(top->clat_percentiles);
o->lat_percentiles = le32_to_cpu(top->lat_percentiles);
+ o->slat_percentiles = le32_to_cpu(top->slat_percentiles);
o->percentile_precision = le32_to_cpu(top->percentile_precision);
o->sig_figs = le32_to_cpu(top->sig_figs);
o->continue_on_error = le32_to_cpu(top->continue_on_error);
@@ -469,6 +470,7 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
top->trim_zero = cpu_to_le32(o->trim_zero);
top->clat_percentiles = cpu_to_le32(o->clat_percentiles);
top->lat_percentiles = cpu_to_le32(o->lat_percentiles);
+ top->slat_percentiles = cpu_to_le32(o->slat_percentiles);
top->percentile_precision = cpu_to_le32(o->percentile_precision);
top->sig_figs = cpu_to_le32(o->sig_figs);
top->continue_on_error = cpu_to_le32(o->continue_on_error);
diff --git a/client.c b/client.c
index 4aed39e7..b7575596 100644
--- a/client.c
+++ b/client.c
@@ -944,7 +944,7 @@ static void convert_io_stat(struct io_stat *dst, struct io_stat *src)
static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
{
- int i, j;
+ int i, j, k;
dst->error = le32_to_cpu(src->error);
dst->thread_number = le32_to_cpu(src->thread_number);
@@ -969,6 +969,7 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
dst->majf = le64_to_cpu(src->majf);
dst->clat_percentiles = le32_to_cpu(src->clat_percentiles);
dst->lat_percentiles = le32_to_cpu(src->lat_percentiles);
+ dst->slat_percentiles = le32_to_cpu(src->slat_percentiles);
dst->percentile_precision = le64_to_cpu(src->percentile_precision);
for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) {
@@ -991,9 +992,10 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
for (i = 0; i < FIO_IO_U_LAT_M_NR; i++)
dst->io_u_lat_m[i] = le64_to_cpu(src->io_u_lat_m[i]);
- for (i = 0; i < DDIR_RWDIR_CNT; i++)
- for (j = 0; j < FIO_IO_U_PLAT_NR; j++)
- dst->io_u_plat[i][j] = le64_to_cpu(src->io_u_plat[i][j]);
+ for (i = 0; i < FIO_LAT_CNT; i++)
+ for (j = 0; j < DDIR_RWDIR_CNT; j++)
+ for (k = 0; k < FIO_IO_U_PLAT_NR; k++)
+ dst->io_u_plat[i][j][k] = le64_to_cpu(src->io_u_plat[i][j][k]);
for (j = 0; j < FIO_IO_U_PLAT_NR; j++)
dst->io_u_sync_plat[j] = le64_to_cpu(src->io_u_sync_plat[j]);
@@ -1035,10 +1037,10 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
for (i = 0; i < DDIR_RWDIR_CNT; i++) {
for (j = 0; j < FIO_IO_U_PLAT_NR; j++) {
dst->io_u_plat_high_prio[i][j] = le64_to_cpu(src->io_u_plat_high_prio[i][j]);
- dst->io_u_plat_prio[i][j] = le64_to_cpu(src->io_u_plat_prio[i][j]);
+ dst->io_u_plat_low_prio[i][j] = le64_to_cpu(src->io_u_plat_low_prio[i][j]);
}
convert_io_stat(&dst->clat_high_prio_stat[i], &src->clat_high_prio_stat[i]);
- convert_io_stat(&dst->clat_prio_stat[i], &src->clat_prio_stat[i]);
+ convert_io_stat(&dst->clat_low_prio_stat[i], &src->clat_low_prio_stat[i]);
}
dst->ss_dur = le64_to_cpu(src->ss_dur);
diff --git a/engines/filestat.c b/engines/filestat.c
index 6c87c4c2..68a340bd 100644
--- a/engines/filestat.c
+++ b/engines/filestat.c
@@ -19,17 +19,39 @@ struct fc_data {
struct filestat_options {
void *pad;
- unsigned int lstat;
+ unsigned int stat_type;
+};
+
+enum {
+ FIO_FILESTAT_STAT = 1,
+ FIO_FILESTAT_LSTAT = 2,
+ /*FIO_FILESTAT_STATX = 3,*/
};
static struct fio_option options[] = {
{
- .name = "lstat",
- .lname = "lstat",
- .type = FIO_OPT_BOOL,
- .off1 = offsetof(struct filestat_options, lstat),
- .help = "Use lstat(2) to measure lookup/getattr performance",
- .def = "0",
+ .name = "stat_type",
+ .lname = "stat_type",
+ .type = FIO_OPT_STR,
+ .off1 = offsetof(struct filestat_options, stat_type),
+ .help = "Specify stat system call type to measure lookup/getattr performance",
+ .def = "stat",
+ .posval = {
+ { .ival = "stat",
+ .oval = FIO_FILESTAT_STAT,
+ .help = "Use stat(2)",
+ },
+ { .ival = "lstat",
+ .oval = FIO_FILESTAT_LSTAT,
+ .help = "Use lstat(2)",
+ },
+ /*
+ { .ival = "statx",
+ .oval = FIO_FILESTAT_STATX,
+ .help = "Use statx(2)",
+ },
+ */
+ },
.category = FIO_OPT_C_ENGINE,
.group = FIO_OPT_G_FILESTAT,
},
@@ -60,17 +82,24 @@ static int stat_file(struct thread_data *td, struct fio_file *f)
if (do_lat)
fio_gettime(&start, NULL);
- if (o->lstat)
- ret = lstat(f->file_name, &statbuf);
- else
+ switch (o->stat_type){
+ case FIO_FILESTAT_STAT:
ret = stat(f->file_name, &statbuf);
+ break;
+ case FIO_FILESTAT_LSTAT:
+ ret = lstat(f->file_name, &statbuf);
+ break;
+ default:
+ ret = -1;
+ break;
+ }
if (ret == -1) {
char buf[FIO_VERROR_SIZE];
int e = errno;
- snprintf(buf, sizeof(buf), "%sstat(%s)",
- o->lstat ? "l" : "", f->file_name);
+ snprintf(buf, sizeof(buf), "stat(%s) type=%u", f->file_name,
+ o->stat_type);
td_verror(td, e, buf);
return 1;
}
diff --git a/fio.1 b/fio.1
index a58632b4..1db12c2f 100644
--- a/fio.1
+++ b/fio.1
@@ -2032,8 +2032,9 @@ on the client site it will be used in the rdma_resolve_add()
function. This can be useful when multiple paths exist between the
client and the server or in certain loopback configurations.
.TP
-.BI (filestat)lstat \fR=\fPbool
-Use \fBlstat\fR\|(2) to measure lookup/getattr performance. Default: 0.
+.BI (filestat)stat_type \fR=\fPstr
+Specify stat system call type to measure lookup/getattr performance.
+Default is \fBstat\fR for \fBstat\fR\|(2).
.TP
.BI (sg)readfua \fR=\fPbool
With readfua option set to 1, read operations include the force
@@ -3000,23 +3001,24 @@ Disable measurements of submission latency numbers. See
Disable measurements of throughput/bandwidth numbers. See
\fBdisable_lat\fR.
.TP
+.BI slat_percentiles \fR=\fPbool
+Report submission latency percentiles. Submission latency is not recorded
+for synchronous ioengines.
+.TP
.BI clat_percentiles \fR=\fPbool
-Enable the reporting of percentiles of completion latencies. This option is
-mutually exclusive with \fBlat_percentiles\fR.
+Report completion latency percentiles.
.TP
.BI lat_percentiles \fR=\fPbool
-Enable the reporting of percentiles of I/O latencies. This is similar to
-\fBclat_percentiles\fR, except that this includes the submission latency.
-This option is mutually exclusive with \fBclat_percentiles\fR.
+Report total latency percentiles. Total latency is the sum of submission
+latency and completion latency.
.TP
.BI percentile_list \fR=\fPfloat_list
-Overwrite the default list of percentiles for completion latencies and the
-block error histogram. Each number is a floating number in the range
+Overwrite the default list of percentiles for latencies and the
+block error histogram. Each number is a floating point number in the range
(0,100], and the maximum length of the list is 20. Use ':' to separate the
-numbers, and list the numbers in ascending order. For example,
-`\-\-percentile_list=99.5:99.9' will cause fio to report the values of
-completion latency below which 99.5% and 99.9% of the observed latencies
-fell, respectively.
+numbers. For example, `\-\-percentile_list=99.5:99.9' will cause fio to
+report the latency durations below which 99.5% and 99.9% of the observed
+latencies fell, respectively.
.TP
.BI significant_figures \fR=\fPint
If using \fB\-\-output\-format\fR of `normal', set the significant figures
diff --git a/gclient.c b/gclient.c
index d8dc62d2..d2044f32 100644
--- a/gclient.c
+++ b/gclient.c
@@ -1097,10 +1097,9 @@ static struct graph *setup_clat_graph(char *title, unsigned long long *ovals,
static void gfio_show_clat_percentiles(struct gfio_client *gc,
GtkWidget *vbox, struct thread_stat *ts,
- int ddir)
+ int ddir, uint64_t *io_u_plat,
+ unsigned long long nr, const char *type)
{
- uint64_t *io_u_plat = ts->io_u_plat[ddir];
- unsigned long long nr = ts->clat_stat[ddir].samples;
fio_fp64_t *plist = ts->percentile_list;
unsigned int len, scale_down;
unsigned long long *ovals, minv, maxv;
@@ -1128,10 +1127,7 @@ static void gfio_show_clat_percentiles(struct gfio_client *gc,
base = "nsec";
}
- if (ts->clat_percentiles)
- sprintf(tmp, "Completion percentiles (%s)", base);
- else
- sprintf(tmp, "Latency percentiles (%s)", base);
+ sprintf(tmp, "%s latency percentiles (%s)", type, base);
tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
ge->clat_graph = setup_clat_graph(tmp, ovals, plist, len, 700.0, 300.0);
@@ -1285,8 +1281,21 @@ static void gfio_show_ddir_status(struct gfio_client *gc, GtkWidget *mbox,
gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
}
- if (ts->clat_percentiles)
- gfio_show_clat_percentiles(gc, main_vbox, ts, ddir);
+ if (ts->slat_percentiles && flags & GFIO_SLAT)
+ gfio_show_clat_percentiles(gc, main_vbox, ts, ddir,
+ ts->io_u_plat[FIO_SLAT][ddir],
+ ts->slat_stat[ddir].samples,
+ "Submission");
+ if (ts->clat_percentiles && flags & GFIO_CLAT)
+ gfio_show_clat_percentiles(gc, main_vbox, ts, ddir,
+ ts->io_u_plat[FIO_CLAT][ddir],
+ ts->clat_stat[ddir].samples,
+ "Completion");
+ if (ts->lat_percentiles && flags & GFIO_LAT)
+ gfio_show_clat_percentiles(gc, main_vbox, ts, ddir,
+ ts->io_u_plat[FIO_LAT][ddir],
+ ts->lat_stat[ddir].samples,
+ "Total");
free(io_p);
free(bw_p);
diff --git a/init.c b/init.c
index dca44bca..b5315334 100644
--- a/init.c
+++ b/init.c
@@ -944,24 +944,12 @@ static int fixup_options(struct thread_data *td)
ret |= 1;
}
- if (fio_option_is_set(o, clat_percentiles) &&
- !fio_option_is_set(o, lat_percentiles)) {
- o->lat_percentiles = !o->clat_percentiles;
- } else if (fio_option_is_set(o, lat_percentiles) &&
- !fio_option_is_set(o, clat_percentiles)) {
- o->clat_percentiles = !o->lat_percentiles;
- } else if (fio_option_is_set(o, lat_percentiles) &&
- fio_option_is_set(o, clat_percentiles) &&
- o->lat_percentiles && o->clat_percentiles) {
- log_err("fio: lat_percentiles and clat_percentiles are "
- "mutually exclusive\n");
- ret |= 1;
- }
-
if (o->disable_lat)
o->lat_percentiles = 0;
if (o->disable_clat)
o->clat_percentiles = 0;
+ if (o->disable_slat)
+ o->slat_percentiles = 0;
/*
* Fix these up to be nsec internally
@@ -1509,6 +1497,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
td->ts.clat_percentiles = o->clat_percentiles;
td->ts.lat_percentiles = o->lat_percentiles;
+ td->ts.slat_percentiles = o->slat_percentiles;
td->ts.percentile_precision = o->percentile_precision;
memcpy(td->ts.percentile_list, o->percentile_list, sizeof(o->percentile_list));
td->ts.sig_figs = o->sig_figs;
@@ -1520,7 +1509,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
td->ts.bw_stat[i].min_val = ULONG_MAX;
td->ts.iops_stat[i].min_val = ULONG_MAX;
td->ts.clat_high_prio_stat[i].min_val = ULONG_MAX;
- td->ts.clat_prio_stat[i].min_val = ULONG_MAX;
+ td->ts.clat_low_prio_stat[i].min_val = ULONG_MAX;
}
td->ts.sync_stat.min_val = ULONG_MAX;
td->ddir_seq_nr = o->ddir_seq_nr;
diff --git a/options.c b/options.c
index 287f0435..4714a3a1 100644
--- a/options.c
+++ b/options.c
@@ -1408,13 +1408,20 @@ static int str_gtod_reduce_cb(void *data, int *il)
struct thread_data *td = cb_data_to_td(data);
int val = *il;
- td->o.disable_lat = !!val;
- td->o.disable_clat = !!val;
- td->o.disable_slat = !!val;
- td->o.disable_bw = !!val;
- td->o.clat_percentiles = !val;
- if (val)
+ /*
+ * Only modfiy options if gtod_reduce==1
+ * Otherwise leave settings alone.
+ */
+ if (val) {
+ td->o.disable_lat = 1;
+ td->o.disable_clat = 1;
+ td->o.disable_slat = 1;
+ td->o.disable_bw = 1;
+ td->o.clat_percentiles = 0;
+ td->o.lat_percentiles = 0;
+ td->o.slat_percentiles = 0;
td->ts_cache_mask = 63;
+ }
return 0;
}
@@ -4312,7 +4319,6 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
.off1 = offsetof(struct thread_options, clat_percentiles),
.help = "Enable the reporting of completion latency percentiles",
.def = "1",
- .inverse = "lat_percentiles",
.category = FIO_OPT_C_STAT,
.group = FIO_OPT_G_INVALID,
},
@@ -4323,7 +4329,16 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
.off1 = offsetof(struct thread_options, lat_percentiles),
.help = "Enable the reporting of IO latency percentiles",
.def = "0",
- .inverse = "clat_percentiles",
+ .category = FIO_OPT_C_STAT,
+ .group = FIO_OPT_G_INVALID,
+ },
+ {
+ .name = "slat_percentiles",
+ .lname = "Submission latency percentiles",
+ .type = FIO_OPT_BOOL,
+ .off1 = offsetof(struct thread_options, slat_percentiles),
+ .help = "Enable the reporting of submission latency percentiles",
+ .def = "0",
.category = FIO_OPT_C_STAT,
.group = FIO_OPT_G_INVALID,
},
diff --git a/server.c b/server.c
index a5af5e74..248a2d44 100644
--- a/server.c
+++ b/server.c
@@ -1463,7 +1463,7 @@ static void convert_gs(struct group_run_stats *dst, struct group_run_stats *src)
void fio_server_send_ts(struct thread_stat *ts, struct group_run_stats *rs)
{
struct cmd_ts_pdu p;
- int i, j;
+ int i, j, k;
void *ss_buf;
uint64_t *ss_iops, *ss_bw;
@@ -1499,6 +1499,7 @@ void fio_server_send_ts(struct thread_stat *ts, struct group_run_stats *rs)
p.ts.majf = cpu_to_le64(ts->majf);
p.ts.clat_percentiles = cpu_to_le32(ts->clat_percentiles);
p.ts.lat_percentiles = cpu_to_le32(ts->lat_percentiles);
+ p.ts.slat_percentiles = cpu_to_le32(ts->slat_percentiles);
p.ts.percentile_precision = cpu_to_le64(ts->percentile_precision);
for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) {
@@ -1521,9 +1522,10 @@ void fio_server_send_ts(struct thread_stat *ts, struct group_run_stats *rs)
for (i = 0; i < FIO_IO_U_LAT_M_NR; i++)
p.ts.io_u_lat_m[i] = cpu_to_le64(ts->io_u_lat_m[i]);
- for (i = 0; i < DDIR_RWDIR_CNT; i++)
- for (j = 0; j < FIO_IO_U_PLAT_NR; j++)
- p.ts.io_u_plat[i][j] = cpu_to_le64(ts->io_u_plat[i][j]);
+ for (i = 0; i < FIO_LAT_CNT; i++)
+ for (j = 0; j < DDIR_RWDIR_CNT; j++)
+ for (k = 0; k < FIO_IO_U_PLAT_NR; k++)
+ p.ts.io_u_plat[i][j][k] = cpu_to_le64(ts->io_u_plat[i][j][k]);
for (j = 0; j < FIO_IO_U_PLAT_NR; j++)
p.ts.io_u_sync_plat[j] = cpu_to_le64(ts->io_u_sync_plat[j]);
@@ -1577,10 +1579,10 @@ void fio_server_send_ts(struct thread_stat *ts, struct group_run_stats *rs)
for (i = 0; i < DDIR_RWDIR_CNT; i++) {
for (j = 0; j < FIO_IO_U_PLAT_NR; j++) {
p.ts.io_u_plat_high_prio[i][j] = cpu_to_le64(ts->io_u_plat_high_prio[i][j]);
- p.ts.io_u_plat_prio[i][j] = cpu_to_le64(ts->io_u_plat_prio[i][j]);
+ p.ts.io_u_plat_low_prio[i][j] = cpu_to_le64(ts->io_u_plat_low_prio[i][j]);
}
convert_io_stat(&p.ts.clat_high_prio_stat[i], &ts->clat_high_prio_stat[i]);
- convert_io_stat(&p.ts.clat_prio_stat[i], &ts->clat_prio_stat[i]);
+ convert_io_stat(&p.ts.clat_low_prio_stat[i], &ts->clat_low_prio_stat[i]);
}
convert_gs(&p.rs, rs);
diff --git a/server.h b/server.h
index 6ac75366..279b6917 100644
--- a/server.h
+++ b/server.h
@@ -48,7 +48,7 @@ struct fio_net_cmd_reply {
};
enum {
- FIO_SERVER_VER = 81,
+ FIO_SERVER_VER = 82,
FIO_SERVER_MAX_FRAGMENT_PDU = 1024,
FIO_SERVER_MAX_CMD_MB = 2048,
diff --git a/stat.c b/stat.c
index cc1c360e..69d57b69 100644
--- a/stat.c
+++ b/stat.c
@@ -483,26 +483,38 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts,
if (calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev))
display_lat(" lat", min, max, mean, dev, out);
if (calc_lat(&ts->clat_high_prio_stat[ddir], &min, &max, &mean, &dev))
- display_lat("prio_clat", min, max, mean, dev, out);
+ display_lat(ts->lat_percentiles ? "prio_lat" : "prio_clat",
+ min, max, mean, dev, out);
+
+ if (ts->slat_percentiles && ts->slat_stat[ddir].samples > 0)
+ show_clat_percentiles(ts->io_u_plat[FIO_SLAT][ddir],
+ ts->slat_stat[ddir].samples,
+ ts->percentile_list,
+ ts->percentile_precision, "slat", out);
+ if (ts->clat_percentiles && ts->clat_stat[ddir].samples > 0)
+ show_clat_percentiles(ts->io_u_plat[FIO_CLAT][ddir],
+ ts->clat_stat[ddir].samples,
+ ts->percentile_list,
+ ts->percentile_precision, "clat", out);
+ if (ts->lat_percentiles && ts->lat_stat[ddir].samples > 0)
+ show_clat_percentiles(ts->io_u_plat[FIO_LAT][ddir],
+ ts->lat_stat[ddir].samples,
+ ts->percentile_list,
+ ts->percentile_precision, "lat", out);
if (ts->clat_percentiles || ts->lat_percentiles) {
- const char *name = ts->clat_percentiles ? "clat" : " lat";
+ const char *name = ts->lat_percentiles ? "lat" : "clat";
char prio_name[32];
uint64_t samples;
- if (ts->clat_percentiles)
- samples = ts->clat_stat[ddir].samples;
- else
+ if (ts->lat_percentiles)
samples = ts->lat_stat[ddir].samples;
-
- show_clat_percentiles(ts->io_u_plat[ddir],
- samples,
- ts->percentile_list,
- ts->percentile_precision, name, out);
+ else
+ samples = ts->clat_stat[ddir].samples;
/* Only print this if some high and low priority stats were collected */
if (ts->clat_high_prio_stat[ddir].samples > 0 &&
- ts->clat_prio_stat[ddir].samples > 0)
+ ts->clat_low_prio_stat[ddir].samples > 0)
{
sprintf(prio_name, "high prio (%.2f%%) %s",
100. * (double) ts->clat_high_prio_stat[ddir].samples / (double) samples,
@@ -513,14 +525,15 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts,
ts->percentile_precision, prio_name, out);
sprintf(prio_name, "low prio (%.2f%%) %s",
- 100. * (double) ts->clat_prio_stat[ddir].samples / (double) samples,
+ 100. * (double) ts->clat_low_prio_stat[ddir].samples / (double) samples,
name);
- show_clat_percentiles(ts->io_u_plat_prio[ddir],
- ts->clat_prio_stat[ddir].samples,
+ show_clat_percentiles(ts->io_u_plat_low_prio[ddir],
+ ts->clat_low_prio_stat[ddir].samples,
ts->percentile_list,
ts->percentile_precision, prio_name, out);
}
}
+
if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
double p_of_agg = 100.0, fkb_base = (double)rs->kb_base;
const char *bw_str;
@@ -1170,12 +1183,17 @@ static void show_ddir_status_terse(struct thread_stat *ts,
else
log_buf(out, ";%llu;%llu;%f;%f", 0ULL, 0ULL, 0.0, 0.0);
- if (ts->clat_percentiles || ts->lat_percentiles) {
- len = calc_clat_percentiles(ts->io_u_plat[ddir],
+ if (ts->lat_percentiles)
+ len = calc_clat_percentiles(ts->io_u_plat[FIO_LAT][ddir],
+ ts->lat_stat[ddir].samples,
+ ts->percentile_list, &ovals, &maxv,
+ &minv);
+ else if (ts->clat_percentiles)
+ len = calc_clat_percentiles(ts->io_u_plat[FIO_CLAT][ddir],
ts->clat_stat[ddir].samples,
ts->percentile_list, &ovals, &maxv,
&minv);
- } else
+ else
len = 0;
for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) {
@@ -1221,18 +1239,63 @@ static void show_ddir_status_terse(struct thread_stat *ts,
}
}
+static struct json_object *add_ddir_lat_json(struct thread_stat *ts, uint32_t percentiles,
+ struct io_stat *lat_stat, uint64_t *io_u_plat)
+{
+ char buf[120];
+ double mean, dev;
+ unsigned int i, len;
+ struct json_object *lat_object, *percentile_object, *clat_bins_object;
+ unsigned long long min, max, maxv, minv, *ovals = NULL;
+
+ if (!calc_lat(lat_stat, &min, &max, &mean, &dev)) {
+ min = max = 0;
+ mean = dev = 0.0;
+ }
+ lat_object = json_create_object();
+ json_object_add_value_int(lat_object, "min", min);
+ json_object_add_value_int(lat_object, "max", max);
+ json_object_add_value_float(lat_object, "mean", mean);
+ json_object_add_value_float(lat_object, "stddev", dev);
+ json_object_add_value_int(lat_object, "N", lat_stat->samples);
+
+ if (percentiles && lat_stat->samples) {
+ len = calc_clat_percentiles(io_u_plat, lat_stat->samples,
+ ts->percentile_list, &ovals, &maxv, &minv);
+
+ if (len > FIO_IO_U_LIST_MAX_LEN)
+ len = FIO_IO_U_LIST_MAX_LEN;
+
+ percentile_object = json_create_object();
+ json_object_add_value_object(lat_object, "percentile", percentile_object);
+ for (i = 0; i < len; i++) {
+ snprintf(buf, sizeof(buf), "%f", ts->percentile_list[i].u.f);
+ json_object_add_value_int(percentile_object, buf, ovals[i]);
+ }
+ free(ovals);
+
+ if (output_format & FIO_OUTPUT_JSON_PLUS) {
+ clat_bins_object = json_create_object();
+ json_object_add_value_object(lat_object, "bins", clat_bins_object);
+
+ for(i = 0; i < FIO_IO_U_PLAT_NR; i++)
+ if (io_u_plat[i]) {
+ snprintf(buf, sizeof(buf), "%llu", plat_idx_to_val(i));
+ json_object_add_value_int(clat_bins_object, buf, io_u_plat[i]);
+ }
+ }
+ }
+
+ return lat_object;
+}
+
static void add_ddir_status_json(struct thread_stat *ts,
struct group_run_stats *rs, int ddir, struct json_object *parent)
{
- unsigned long long min, max, minv, maxv;
+ unsigned long long min, max;
unsigned long long bw_bytes, bw;
- unsigned long long *ovals = NULL;
double mean, dev, iops;
- unsigned int len;
- int i;
- struct json_object *dir_object, *tmp_object, *percentile_object = NULL,
- *clat_bins_object = NULL;
- char buf[120];
+ struct json_object *dir_object, *tmp_object;
double p_of_agg = 100.0;
assert(ddir_rw(ddir) || ddir_sync(ddir));
@@ -1266,222 +1329,47 @@ static void add_ddir_status_json(struct thread_stat *ts,
json_object_add_value_int(dir_object, "short_ios", ts->short_io_u[ddir]);
json_object_add_value_int(dir_object, "drop_ios", ts->drop_io_u[ddir]);
- if (!calc_lat(&ts->slat_stat[ddir], &min, &max, &mean, &dev)) {
- min = max = 0;
- mean = dev = 0.0;
- }
- tmp_object = json_create_object();
+ tmp_object = add_ddir_lat_json(ts, ts->slat_percentiles,
+ &ts->slat_stat[ddir], ts->io_u_plat[FIO_SLAT][ddir]);
json_object_add_value_object(dir_object, "slat_ns", tmp_object);
- json_object_add_value_int(tmp_object, "min", min);
- json_object_add_value_int(tmp_object, "max", max);
- json_object_add_value_float(tmp_object, "mean", mean);
- json_object_add_value_float(tmp_object, "stddev", dev);
-
- if (!calc_lat(&ts->clat_stat[ddir], &min, &max, &mean, &dev)) {
- min = max = 0;
- mean = dev = 0.0;
- }
- tmp_object = json_create_object();
+
+ tmp_object = add_ddir_lat_json(ts, ts->clat_percentiles,
+ &ts->clat_stat[ddir], ts->io_u_plat[FIO_CLAT][ddir]);
json_object_add_value_object(dir_object, "clat_ns", tmp_object);
- json_object_add_value_int(tmp_object, "min", min);
- json_object_add_value_int(tmp_object, "max", max);
- json_object_add_value_float(tmp_object, "mean", mean);
- json_object_add_value_float(tmp_object, "stddev", dev);
- } else {
- if (!calc_lat(&ts->sync_stat, &min, &max, &mean, &dev)) {
- min = max = 0;
- mean = dev = 0.0;
- }
- tmp_object = json_create_object();
+ tmp_object = add_ddir_lat_json(ts, ts->lat_percentiles,
+ &ts->lat_stat[ddir], ts->io_u_plat[FIO_LAT][ddir]);
json_object_add_value_object(dir_object, "lat_ns", tmp_object);
+ } else {
json_object_add_value_int(dir_object, "total_ios", ts->total_io_u[DDIR_SYNC]);
- json_object_add_value_int(tmp_object, "min", min);
- json_object_add_value_int(tmp_object, "max", max);
- json_object_add_value_float(tmp_object, "mean", mean);
- json_object_add_value_float(tmp_object, "stddev", dev);
- }
-
- if (ts->clat_percentiles || ts->lat_percentiles) {
- if (ddir_rw(ddir)) {
- uint64_t samples;
-
- if (ts->clat_percentiles)
- samples = ts->clat_stat[ddir].samples;
- else
- samples = ts->lat_stat[ddir].samples;
-
- len = calc_clat_percentiles(ts->io_u_plat[ddir],
- samples, ts->percentile_list, &ovals,
- &maxv, &minv);
- } else {
- len = calc_clat_percentiles(ts->io_u_sync_plat,
- ts->sync_stat.samples,
- ts->percentile_list, &ovals, &maxv,
- &minv);
- }
-
- if (len > FIO_IO_U_LIST_MAX_LEN)
- len = FIO_IO_U_LIST_MAX_LEN;
- } else
- len = 0;
-
- if (ts->clat_percentiles) {
- percentile_object = json_create_object();
- json_object_add_value_object(tmp_object, "percentile", percentile_object);
- for (i = 0; i < len; i++) {
- snprintf(buf, sizeof(buf), "%f",
- ts->percentile_list[i].u.f);
- json_object_add_value_int(percentile_object, buf,
- ovals[i]);
- }
- }
-
- free(ovals);
-
- if (output_format & FIO_OUTPUT_JSON_PLUS && ts->clat_percentiles) {
- clat_bins_object = json_create_object();
- json_object_add_value_object(tmp_object, "bins",
- clat_bins_object);
-
- for(i = 0; i < FIO_IO_U_PLAT_NR; i++) {
- if (ddir_rw(ddir)) {
- if (ts->io_u_plat[ddir][i]) {
- snprintf(buf, sizeof(buf), "%llu", plat_idx_to_val(i));
- json_object_add_value_int(clat_bins_object, buf, ts->io_u_plat[ddir][i]);
- }
- } else {
- if (ts->io_u_sync_plat[i]) {
- snprintf(buf, sizeof(buf), "%llu", plat_idx_to_val(i));
- json_object_add_value_int(clat_bins_object, buf, ts->io_u_sync_plat[i]);
- }
- }
- }
+ tmp_object = add_ddir_lat_json(ts, ts->lat_percentiles | ts->clat_percentiles,
+ &ts->sync_stat, ts->io_u_sync_plat);
+ json_object_add_value_object(dir_object, "lat_ns", tmp_object);
}
+ if (!ddir_rw(ddir))
+ return;
/* Only print PRIO latencies if some high priority samples were gathered */
if (ts->clat_high_prio_stat[ddir].samples > 0) {
- /* START OF HIGH PRIO CLAT */
- if (!calc_lat(&ts->clat_high_prio_stat[ddir], &min, &max, &mean, &dev)) {
- min = max = 0;
- mean = dev = 0.0;
- }
- tmp_object = json_create_object();
- json_object_add_value_object(dir_object, "clat_prio",
- tmp_object);
- json_object_add_value_int(tmp_object, "samples",
- ts->clat_high_prio_stat[ddir].samples);
- json_object_add_value_int(tmp_object, "min", min);
- json_object_add_value_int(tmp_object, "max", max);
- json_object_add_value_float(tmp_object, "mean", mean);
- json_object_add_value_float(tmp_object, "stddev", dev);
-
- if (ts->clat_percentiles) {
- len = calc_clat_percentiles(ts->io_u_plat_high_prio[ddir],
- ts->clat_high_prio_stat[ddir].samples,
- ts->percentile_list, &ovals, &maxv,
- &minv);
- } else
- len = 0;
-
- percentile_object = json_create_object();
- json_object_add_value_object(tmp_object, "percentile", percentile_object);
- for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) {
- if (i >= len) {
- json_object_add_value_int(percentile_object, "0.00", 0);
- continue;
- }
- snprintf(buf, sizeof(buf), "%f", ts->percentile_list[i].u.f);
- json_object_add_value_int(percentile_object, (const char *)buf, ovals[i]);
- }
-
- if (output_format & FIO_OUTPUT_JSON_PLUS) {
- clat_bins_object = json_create_object();
- json_object_add_value_object(tmp_object, "bins", clat_bins_object);
- for(i = 0; i < FIO_IO_U_PLAT_NR; i++) {
- snprintf(buf, sizeof(buf), "%d", i);
- json_object_add_value_int(clat_bins_object, (const char *)buf,
- ts->io_u_plat_high_prio[ddir][i]);
- }
- json_object_add_value_int(clat_bins_object, "FIO_IO_U_PLAT_BITS",
- FIO_IO_U_PLAT_BITS);
- json_object_add_value_int(clat_bins_object, "FIO_IO_U_PLAT_VAL",
- FIO_IO_U_PLAT_VAL);
- json_object_add_value_int(clat_bins_object, "FIO_IO_U_PLAT_NR",
- FIO_IO_U_PLAT_NR);
- }
- /* END OF HIGH PRIO CLAT */
-
- /* START OF PRIO CLAT */
- if (!calc_lat(&ts->clat_prio_stat[ddir], &min, &max, &mean, &dev)) {
- min = max = 0;
- mean = dev = 0.0;
- }
- tmp_object = json_create_object();
- json_object_add_value_object(dir_object, "clat_low_prio",
- tmp_object);
- json_object_add_value_int(tmp_object, "samples",
- ts->clat_prio_stat[ddir].samples);
- json_object_add_value_int(tmp_object, "min", min);
- json_object_add_value_int(tmp_object, "max", max);
- json_object_add_value_float(tmp_object, "mean", mean);
- json_object_add_value_float(tmp_object, "stddev", dev);
-
- if (ts->clat_percentiles) {
- len = calc_clat_percentiles(ts->io_u_plat_prio[ddir],
- ts->clat_prio_stat[ddir].samples,
- ts->percentile_list, &ovals, &maxv,
- &minv);
- } else
- len = 0;
-
- percentile_object = json_create_object();
- json_object_add_value_object(tmp_object, "percentile", percentile_object);
- for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) {
- if (i >= len) {
- json_object_add_value_int(percentile_object, "0.00", 0);
- continue;
- }
- snprintf(buf, sizeof(buf), "%f", ts->percentile_list[i].u.f);
- json_object_add_value_int(percentile_object, (const char *)buf, ovals[i]);
- }
+ const char *high, *low;
- if (output_format & FIO_OUTPUT_JSON_PLUS) {
- clat_bins_object = json_create_object();
- json_object_add_value_object(tmp_object, "bins", clat_bins_object);
- for(i = 0; i < FIO_IO_U_PLAT_NR; i++) {
- snprintf(buf, sizeof(buf), "%d", i);
- json_object_add_value_int(clat_bins_object, (const char *)buf,
- ts->io_u_plat_prio[ddir][i]);
- }
- json_object_add_value_int(clat_bins_object, "FIO_IO_U_PLAT_BITS",
- FIO_IO_U_PLAT_BITS);
- json_object_add_value_int(clat_bins_object, "FIO_IO_U_PLAT_VAL",
- FIO_IO_U_PLAT_VAL);
- json_object_add_value_int(clat_bins_object, "FIO_IO_U_PLAT_NR",
- FIO_IO_U_PLAT_NR);
+ if (ts->lat_percentiles) {
+ high = "lat_high_prio";
+ low = "lat_low_prio";
+ } else {
+ high = "clat_high_prio";
+ low = "clat_low_prio";
}
- /* END OF PRIO CLAT */
- }
- if (!ddir_rw(ddir))
- return;
+ tmp_object = add_ddir_lat_json(ts, ts->clat_percentiles | ts->lat_percentiles,
+ &ts->clat_high_prio_stat[ddir], ts->io_u_plat_high_prio[ddir]);
+ json_object_add_value_object(dir_object, high, tmp_object);
- if (!calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev)) {
- min = max = 0;
- mean = dev = 0.0;
+ tmp_object = add_ddir_lat_json(ts, ts->clat_percentiles | ts->lat_percentiles,
+ &ts->clat_low_prio_stat[ddir], ts->io_u_plat_low_prio[ddir]);
+ json_object_add_value_object(dir_object, low, tmp_object);
}
- tmp_object = json_create_object();
- json_object_add_value_object(dir_object, "lat_ns", tmp_object);
- json_object_add_value_int(tmp_object, "min", min);
- json_object_add_value_int(tmp_object, "max", max);
- json_object_add_value_float(tmp_object, "mean", mean);
- json_object_add_value_float(tmp_object, "stddev", dev);
- if (ts->lat_percentiles)
- json_object_add_value_object(tmp_object, "percentile", percentile_object);
- if (output_format & FIO_OUTPUT_JSON_PLUS && ts->lat_percentiles)
- json_object_add_value_object(tmp_object, "bins", clat_bins_object);
if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
if (rs->agg[ddir]) {
@@ -1493,6 +1381,7 @@ static void add_ddir_status_json(struct thread_stat *ts,
min = max = 0;
p_of_agg = mean = dev = 0.0;
}
+
json_object_add_value_int(dir_object, "bw_min", min);
json_object_add_value_int(dir_object, "bw_max", max);
json_object_add_value_float(dir_object, "bw_agg", p_of_agg);
@@ -1981,13 +1870,13 @@ void sum_group_stats(struct group_run_stats *dst, struct group_run_stats *src)
void sum_thread_stats(struct thread_stat *dst, struct thread_stat *src,
bool first)
{
- int l, k;
+ int k, l, m;
for (l = 0; l < DDIR_RWDIR_CNT; l++) {
if (!dst->unified_rw_rep) {
sum_stat(&dst->clat_stat[l], &src->clat_stat[l], first, false);
sum_stat(&dst->clat_high_prio_stat[l], &src->clat_high_prio_stat[l], first, false);
- sum_stat(&dst->clat_prio_stat[l], &src->clat_prio_stat[l], first, false);
+ sum_stat(&dst->clat_low_prio_stat[l], &src->clat_low_prio_stat[l], first, false);
sum_stat(&dst->slat_stat[l], &src->slat_stat[l], first, false);
sum_stat(&dst->lat_stat[l], &src->lat_stat[l], first, false);
sum_stat(&dst->bw_stat[l], &src->bw_stat[l], first, true);
@@ -1999,8 +1888,8 @@ void sum_thread_stats(struct thread_stat *dst, struct thread_stat *src,
dst->runtime[l] = src->runtime[l];
} else {
sum_stat(&dst->clat_stat[0], &src->clat_stat[l], first, false);
- sum_stat(&dst->clat_high_prio_stat[l], &src->clat_high_prio_stat[l], first, false);
- sum_stat(&dst->clat_prio_stat[l], &src->clat_prio_stat[l], first, false);
+ sum_stat(&dst->clat_high_prio_stat[0], &src->clat_high_prio_stat[l], first, false);
+ sum_stat(&dst->clat_low_prio_stat[0], &src->clat_low_prio_stat[l], first, false);
sum_stat(&dst->slat_stat[0], &src->slat_stat[l], first, false);
sum_stat(&dst->lat_stat[0], &src->lat_stat[l], first, false);
sum_stat(&dst->bw_stat[0], &src->bw_stat[l], first, true);
@@ -2039,9 +1928,6 @@ void sum_thread_stats(struct thread_stat *dst, struct thread_stat *src,
for (k = 0; k < FIO_IO_U_LAT_M_NR; k++)
dst->io_u_lat_m[k] += src->io_u_lat_m[k];
- for (k = 0; k < FIO_IO_U_PLAT_NR; k++)
- dst->io_u_sync_plat[k] += src->io_u_sync_plat[k];
-
for (k = 0; k < DDIR_RWDIR_CNT; k++) {
if (!dst->unified_rw_rep) {
dst->total_io_u[k] += src->total_io_u[k];
@@ -2056,18 +1942,25 @@ void sum_thread_stats(struct thread_stat *dst, struct thread_stat *src,
dst->total_io_u[DDIR_SYNC] += src->total_io_u[DDIR_SYNC];
- for (k = 0; k < DDIR_RWDIR_CNT; k++) {
- int m;
+ for (k = 0; k < FIO_LAT_CNT; k++)
+ for (l = 0; l < DDIR_RWDIR_CNT; l++)
+ for (m = 0; m < FIO_IO_U_PLAT_NR; m++)
+ if (!dst->unified_rw_rep)
+ dst->io_u_plat[k][l][m] += src->io_u_plat[k][l][m];
+ else
+ dst->io_u_plat[k][0][m] += src->io_u_plat[k][l][m];
+ for (k = 0; k < FIO_IO_U_PLAT_NR; k++)
+ dst->io_u_sync_plat[k] += src->io_u_sync_plat[k];
+
+ for (k = 0; k < DDIR_RWDIR_CNT; k++) {
for (m = 0; m < FIO_IO_U_PLAT_NR; m++) {
if (!dst->unified_rw_rep) {
- dst->io_u_plat[k][m] += src->io_u_plat[k][m];
dst->io_u_plat_high_prio[k][m] += src->io_u_plat_high_prio[k][m];
- dst->io_u_plat_prio[k][m] += src->io_u_plat_prio[k][m];
+ dst->io_u_plat_low_prio[k][m] += src->io_u_plat_low_prio[k][m];
} else {
- dst->io_u_plat[0][m] += src->io_u_plat[k][m];
dst->io_u_plat_high_prio[0][m] += src->io_u_plat_high_prio[k][m];
- dst->io_u_plat_prio[0][m] += src->io_u_plat_prio[k][m];
+ dst->io_u_plat_low_prio[0][m] += src->io_u_plat_low_prio[k][m];
}
}
@@ -2103,7 +1996,7 @@ void init_thread_stat(struct thread_stat *ts)
ts->bw_stat[j].min_val = -1UL;
ts->iops_stat[j].min_val = -1UL;
ts->clat_high_prio_stat[j].min_val = -1UL;
- ts->clat_prio_stat[j].min_val = -1UL;
+ ts->clat_low_prio_stat[j].min_val = -1UL;
}
ts->sync_stat.min_val = -1UL;
ts->groupid = -1;
@@ -2173,6 +2066,7 @@ void __show_run_stats(void)
ts->clat_percentiles = td->o.clat_percentiles;
ts->lat_percentiles = td->o.lat_percentiles;
+ ts->slat_percentiles = td->o.slat_percentiles;
ts->percentile_precision = td->o.percentile_precision;
memcpy(ts->percentile_list, td->o.percentile_list, sizeof(td->o.percentile_list));
opt_lists[j] = &td->opt_list;
@@ -2728,11 +2622,11 @@ static inline void reset_io_stat(struct io_stat *ios)
void reset_io_stats(struct thread_data *td)
{
struct thread_stat *ts = &td->ts;
- int i, j;
+ int i, j, k;
for (i = 0; i < DDIR_RWDIR_CNT; i++) {
reset_io_stat(&ts->clat_high_prio_stat[i]);
- reset_io_stat(&ts->clat_prio_stat[i]);
+ reset_io_stat(&ts->clat_low_prio_stat[i]);
reset_io_stat(&ts->clat_stat[i]);
reset_io_stat(&ts->slat_stat[i]);
reset_io_stat(&ts->lat_stat[i]);
@@ -2746,14 +2640,18 @@ void reset_io_stats(struct thread_data *td)
ts->drop_io_u[i] = 0;
for (j = 0; j < FIO_IO_U_PLAT_NR; j++) {
- ts->io_u_plat[i][j] = 0;
ts->io_u_plat_high_prio[i][j] = 0;
- ts->io_u_plat_prio[i][j] = 0;
+ ts->io_u_plat_low_prio[i][j] = 0;
if (!i)
ts->io_u_sync_plat[j] = 0;
}
}
+ for (i = 0; i < FIO_LAT_CNT; i++)
+ for (j = 0; j < DDIR_RWDIR_CNT; j++)
+ for (k = 0; k < FIO_IO_U_PLAT_NR; k++)
+ ts->io_u_plat[i][j][k] = 0;
+
ts->total_io_u[DDIR_SYNC] = 0;
for (i = 0; i < FIO_IO_U_MAP_NR; i++) {
@@ -2892,19 +2790,27 @@ void add_sync_clat_sample(struct thread_stat *ts, unsigned long long nsec)
add_stat_sample(&ts->sync_stat, nsec);
}
-static void add_clat_percentile_sample(struct thread_stat *ts,
- unsigned long long nsec, enum fio_ddir ddir, uint8_t priority_bit)
+static void add_lat_percentile_sample_noprio(struct thread_stat *ts,
+ unsigned long long nsec, enum fio_ddir ddir, enum fio_lat lat)
{
unsigned int idx = plat_val_to_idx(nsec);
assert(idx < FIO_IO_U_PLAT_NR);
- ts->io_u_plat[ddir][idx]++;
+ ts->io_u_plat[lat][ddir][idx]++;
+}
- if (!priority_bit) {
- ts->io_u_plat_prio[ddir][idx]++;
- } else {
+static void add_lat_percentile_sample(struct thread_stat *ts,
+ unsigned long long nsec, enum fio_ddir ddir, uint8_t priority_bit,
+ enum fio_lat lat)
+{
+ unsigned int idx = plat_val_to_idx(nsec);
+
+ add_lat_percentile_sample_noprio(ts, nsec, ddir, lat);
+
+ if (!priority_bit)
+ ts->io_u_plat_low_prio[ddir][idx]++;
+ else
ts->io_u_plat_high_prio[ddir][idx]++;
- }
}
void add_clat_sample(struct thread_data *td, enum fio_ddir ddir,
@@ -2921,10 +2827,11 @@ void add_clat_sample(struct thread_data *td, enum fio_ddir ddir,
add_stat_sample(&ts->clat_stat[ddir], nsec);
- if (priority_bit) {
- add_stat_sample(&ts->clat_high_prio_stat[ddir], nsec);
- } else {
- add_stat_sample(&ts->clat_prio_stat[ddir], nsec);
+ if (!ts->lat_percentiles) {
+ if (priority_bit)
+ add_stat_sample(&ts->clat_high_prio_stat[ddir], nsec);
+ else
+ add_stat_sample(&ts->clat_low_prio_stat[ddir], nsec);
}
if (td->clat_log)
@@ -2932,7 +2839,10 @@ void add_clat_sample(struct thread_data *td, enum fio_ddir ddir,
offset, priority_bit);
if (ts->clat_percentiles) {
- add_clat_percentile_sample(ts, nsec, ddir, priority_bit);
+ if (ts->lat_percentiles)
+ add_lat_percentile_sample_noprio(ts, nsec, ddir, FIO_CLAT);
+ else
+ add_lat_percentile_sample(ts, nsec, ddir, priority_bit, FIO_CLAT);
}
if (iolog && iolog->hist_msec) {
@@ -2955,7 +2865,7 @@ void add_clat_sample(struct thread_data *td, enum fio_ddir ddir,
* located in iolog.c after printing this sample to the
* log file.
*/
- io_u_plat = (uint64_t *) td->ts.io_u_plat[ddir];
+ io_u_plat = (uint64_t *) td->ts.io_u_plat[FIO_CLAT][ddir];
dst = malloc(sizeof(struct io_u_plat_entry));
memcpy(&(dst->io_u_plat), io_u_plat,
FIO_IO_U_PLAT_NR * sizeof(uint64_t));
@@ -2978,7 +2888,7 @@ void add_clat_sample(struct thread_data *td, enum fio_ddir ddir,
}
void add_slat_sample(struct thread_data *td, enum fio_ddir ddir,
- unsigned long usec, unsigned long long bs, uint64_t offset,
+ unsigned long long nsec, unsigned long long bs, uint64_t offset,
uint8_t priority_bit)
{
const bool needs_lock = td_async_processing(td);
@@ -2990,12 +2900,15 @@ void add_slat_sample(struct thread_data *td, enum fio_ddir ddir,
if (needs_lock)
__td_io_u_lock(td);
- add_stat_sample(&ts->slat_stat[ddir], usec);
+ add_stat_sample(&ts->slat_stat[ddir], nsec);
if (td->slat_log)
- add_log_sample(td, td->slat_log, sample_val(usec), ddir, bs, offset,
+ add_log_sample(td, td->slat_log, sample_val(nsec), ddir, bs, offset,
priority_bit);
+ if (ts->slat_percentiles)
+ add_lat_percentile_sample_noprio(ts, nsec, ddir, FIO_SLAT);
+
if (needs_lock)
__td_io_u_unlock(td);
}
@@ -3019,9 +2932,14 @@ void add_lat_sample(struct thread_data *td, enum fio_ddir ddir,
add_log_sample(td, td->lat_log, sample_val(nsec), ddir, bs,
offset, priority_bit);
- if (ts->lat_percentiles)
- add_clat_percentile_sample(ts, nsec, ddir, priority_bit);
+ if (ts->lat_percentiles) {
+ add_lat_percentile_sample(ts, nsec, ddir, priority_bit, FIO_LAT);
+ if (priority_bit)
+ add_stat_sample(&ts->clat_high_prio_stat[ddir], nsec);
+ else
+ add_stat_sample(&ts->clat_low_prio_stat[ddir], nsec);
+ }
if (needs_lock)
__td_io_u_unlock(td);
}
diff --git a/stat.h b/stat.h
index 9320c6bd..0d141666 100644
--- a/stat.h
+++ b/stat.h
@@ -37,7 +37,7 @@ struct group_run_stats {
list of percentiles */
/*
- * Aggregate clat samples to report percentile(s) of them.
+ * Aggregate latency samples for reporting percentile(s).
*
* EXECUTIVE SUMMARY
*
@@ -58,7 +58,7 @@ struct group_run_stats {
*
* DETAILS
*
- * Suppose the clat varies from 0 to 999 (usec), the straightforward
+ * Suppose the lat varies from 0 to 999 (usec), the straightforward
* method is to keep an array of (999 + 1) buckets, in which a counter
* keeps the count of samples which fall in the bucket, e.g.,
* {[0],[1],...,[999]}. However this consumes a huge amount of space,
@@ -147,6 +147,14 @@ enum block_info_state {
#define FIO_JOBDESC_SIZE 256
#define FIO_VERROR_SIZE 128
+enum fio_lat {
+ FIO_SLAT = 0,
+ FIO_CLAT,
+ FIO_LAT,
+
+ FIO_LAT_CNT = 3,
+};
+
struct thread_stat {
char name[FIO_JOBNAME_SIZE];
char verror[FIO_VERROR_SIZE];
@@ -181,6 +189,8 @@ struct thread_stat {
*/
uint32_t clat_percentiles;
uint32_t lat_percentiles;
+ uint32_t slat_percentiles;
+ uint32_t pad;
uint64_t percentile_precision;
fio_fp64_t percentile_list[FIO_IO_U_LIST_MAX_LEN];
@@ -190,7 +200,7 @@ struct thread_stat {
uint64_t io_u_lat_n[FIO_IO_U_LAT_N_NR];
uint64_t io_u_lat_u[FIO_IO_U_LAT_U_NR];
uint64_t io_u_lat_m[FIO_IO_U_LAT_M_NR];
- uint64_t io_u_plat[DDIR_RWDIR_CNT][FIO_IO_U_PLAT_NR];
+ uint64_t io_u_plat[FIO_LAT_CNT][DDIR_RWDIR_CNT][FIO_IO_U_PLAT_NR];
uint64_t io_u_sync_plat[FIO_IO_U_PLAT_NR];
uint64_t total_io_u[DDIR_RWDIR_SYNC_CNT];
@@ -240,9 +250,9 @@ struct thread_stat {
fio_fp64_t ss_criterion;
uint64_t io_u_plat_high_prio[DDIR_RWDIR_CNT][FIO_IO_U_PLAT_NR] __attribute__((aligned(8)));;
- uint64_t io_u_plat_prio[DDIR_RWDIR_CNT][FIO_IO_U_PLAT_NR];
+ uint64_t io_u_plat_low_prio[DDIR_RWDIR_CNT][FIO_IO_U_PLAT_NR];
struct io_stat clat_high_prio_stat[DDIR_RWDIR_CNT] __attribute__((aligned(8)));
- struct io_stat clat_prio_stat[DDIR_RWDIR_CNT];
+ struct io_stat clat_low_prio_stat[DDIR_RWDIR_CNT];
union {
uint64_t *ss_iops_data;
@@ -331,7 +341,7 @@ extern void add_lat_sample(struct thread_data *, enum fio_ddir, unsigned long lo
unsigned long long, uint64_t, uint8_t);
extern void add_clat_sample(struct thread_data *, enum fio_ddir, unsigned long long,
unsigned long long, uint64_t, uint8_t);
-extern void add_slat_sample(struct thread_data *, enum fio_ddir, unsigned long,
+extern void add_slat_sample(struct thread_data *, enum fio_ddir, unsigned long long,
unsigned long long, uint64_t, uint8_t);
extern void add_agg_sample(union io_sample_data, enum fio_ddir, unsigned long long bs,
uint8_t priority_bit);
diff --git a/t/latency_percentiles.py b/t/latency_percentiles.py
new file mode 100755
index 00000000..0c8d0c19
--- /dev/null
+++ b/t/latency_percentiles.py
@@ -0,0 +1,1324 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (c) 2020 Western Digital Corporation or its affiliates.
+#
+"""
+# latency_percentiles.py
+#
+# Test the code that produces latency percentiles
+# This is mostly to test the code changes to allow reporting
+# of slat, clat, and lat percentiles
+#
+# USAGE
+# python3 latency-tests.py [-f fio-path] [-a artifact-root] [--debug]
+#
+#
+# Test scenarios:
+#
+# - DONE json
+# unified rw reporting
+# compare with latency log
+# try various combinations of the ?lat_percentile options
+# null, aio
+# r, w, t
+# - DONE json+
+# check presence of latency bins
+# if the json percentiles match those from the raw data
+# then the latency bin values and counts are probably ok
+# - DONE terse
+# produce both terse, JSON output and confirm that they match
+# lat only; both lat and clat
+# - DONE sync_lat
+# confirm that sync_lat data appears
+# - MANUAL TESTING normal output:
+# null ioengine
+# enable all, but only clat and lat appear
+# enable subset of latency types
+# read, write, trim, unified
+# libaio ioengine
+# enable all latency types
+# enable subset of latency types
+# read, write, trim, unified
+# ./fio/fio --name=test --randrepeat=0 --norandommap --time_based --runtime=2s --size=512M \
+# --ioengine=null --slat_percentiles=1 --clat_percentiles=1 --lat_percentiles=1
+# echo confirm that clat and lat percentiles appear
+# ./fio/fio --name=test --randrepeat=0 --norandommap --time_based --runtime=2s --size=512M \
+# --ioengine=null --slat_percentiles=0 --clat_percentiles=0 --lat_percentiles=1
+# echo confirm that only lat percentiles appear
+# ./fio/fio --name=test --randrepeat=0 --norandommap --time_based --runtime=2s --size=512M \
+# --ioengine=null --slat_percentiles=0 --clat_percentiles=1 --lat_percentiles=0
+# echo confirm that only clat percentiles appear
+# ./fio/fio --name=test --randrepeat=0 --norandommap --time_based --runtime=2s --size=512M \
+# --ioengine=libaio --slat_percentiles=1 --clat_percentiles=1 --lat_percentiles=1
+# echo confirm that slat, clat, lat percentiles appear
+# ./fio/fio --name=test --randrepeat=0 --norandommap --time_based --runtime=2s --size=512M \
+# --ioengine=libaio --slat_percentiles=0 --clat_percentiles=1 --lat_percentiles=1
+# echo confirm that clat and lat percentiles appear
+# ./fio/fio --name=test --randrepeat=0 --norandommap --time_based --runtime=2s --size=512M \
+# --ioengine=libaio -rw=randrw
+# echo confirm that clat percentiles appear for reads and writes
+# ./fio/fio --name=test --randrepeat=0 --norandommap --time_based --runtime=2s --size=512M \
+# --ioengine=libaio --slat_percentiles=1 --clat_percentiles=0 --lat_percentiles=0 --rw=randrw
+# echo confirm that slat percentiles appear for both reads and writes
+# ./fio/fio --name=test --randrepeat=0 --norandommap --time_based --runtime=2s --size=512M \
+# --ioengine=libaio --slat_percentiles=1 --clat_percentiles=1 --lat_percentiles=1 \
+# --rw=randrw --unified_rw_reporting=1
+# echo confirm that slat, clat, and lat percentiles appear for 'mixed' IOs
+#./fio/fio --name=test --randrepeat=0 --norandommap --time_based --runtime=2s --size=512M \
+# --ioengine=null --slat_percentiles=1 --clat_percentiles=1 --lat_percentiles=1 \
+# --rw=randrw --fsync=32
+# echo confirm that fsync latencies appear
+"""
+
+import os
+import csv
+import sys
+import json
+import math
+import time
+import argparse
+import platform
+import subprocess
+from pathlib import Path
+
+
+class FioLatTest():
+ """fio latency percentile test."""
+
+ def __init__(self, artifact_root, test_options, debug):
+ """
+ artifact_root root directory for artifacts (subdirectory will be created under here)
+ test test specification
+ """
+ self.artifact_root = artifact_root
+ self.test_options = test_options
+ self.debug = debug
+ self.filename = None
+ self.json_data = None
+ self.terse_data = None
+
+ self.test_dir = os.path.join(self.artifact_root,
+ "{:03d}".format(self.test_options['test_id']))
+ if not os.path.exists(self.test_dir):
+ os.mkdir(self.test_dir)
+
+ self.filename = "latency{:03d}".format(self.test_options['test_id'])
+
+ def run_fio(self, fio_path):
+ """Run a test."""
+
+ fio_args = [
+ "--name=latency",
+ "--randrepeat=0",
+ "--norandommap",
+ "--time_based",
+ "--size=16M",
+ "--rwmixread=50",
+ "--group_reporting=1",
+ "--write_lat_log={0}".format(self.filename),
+ "--output={0}.out".format(self.filename),
+ "--ioengine={ioengine}".format(**self.test_options),
+ "--rw={rw}".format(**self.test_options),
+ "--runtime={runtime}".format(**self.test_options),
+ "--output-format={output-format}".format(**self.test_options),
+ ]
+ for opt in ['slat_percentiles', 'clat_percentiles', 'lat_percentiles',
+ 'unified_rw_reporting', 'fsync', 'fdatasync', 'numjobs', 'cmdprio_percentage']:
+ if opt in self.test_options:
+ option = '--{0}={{{0}}}'.format(opt)
+ fio_args.append(option.format(**self.test_options))
+
+ command = [fio_path] + fio_args
+ with open(os.path.join(self.test_dir, "{0}.command".format(self.filename)), "w+") as \
+ command_file:
+ command_file.write("%s\n" % command)
+
+ passed = True
+ stdout_file = open(os.path.join(self.test_dir, "{0}.stdout".format(self.filename)), "w+")
+ stderr_file = open(os.path.join(self.test_dir, "{0}.stderr".format(self.filename)), "w+")
+ exitcode_file = open(os.path.join(self.test_dir,
+ "{0}.exitcode".format(self.filename)), "w+")
+ try:
+ proc = None
+ # Avoid using subprocess.run() here because when a timeout occurs,
+ # fio will be stopped with SIGKILL. This does not give fio a
+ # chance to clean up and means that child processes may continue
+ # running and submitting IO.
+ proc = subprocess.Popen(command,
+ stdout=stdout_file,
+ stderr=stderr_file,
+ cwd=self.test_dir,
+ universal_newlines=True)
+ proc.communicate(timeout=300)
+ exitcode_file.write('{0}\n'.format(proc.returncode))
+ passed &= (proc.returncode == 0)
+ except subprocess.TimeoutExpired:
+ proc.terminate()
+ proc.communicate()
+ assert proc.poll()
+ print("Timeout expired")
+ passed = False
+ except Exception:
+ if proc:
+ if not proc.poll():
+ proc.terminate()
+ proc.communicate()
+ print("Exception: %s" % sys.exc_info())
+ passed = False
+ finally:
+ stdout_file.close()
+ stderr_file.close()
+ exitcode_file.close()
+
+ if passed:
+ if 'json' in self.test_options['output-format']:
+ if not self.get_json():
+ print('Unable to decode JSON data')
+ passed = False
+ if 'terse' in self.test_options['output-format']:
+ if not self.get_terse():
+ print('Unable to decode terse data')
+ passed = False
+
+ return passed
+
+ def get_json(self):
+ """Convert fio JSON output into a python JSON object"""
+
+ filename = os.path.join(self.test_dir, "{0}.out".format(self.filename))
+ with open(filename, 'r') as file:
+ file_data = file.read()
+
+ #
+ # Sometimes fio informational messages are included at the top of the
+ # JSON output, especially under Windows. Try to decode output as JSON
+ # data, lopping off up to the first four lines
+ #
+ lines = file_data.splitlines()
+ for i in range(5):
+ file_data = '\n'.join(lines[i:])
+ try:
+ self.json_data = json.loads(file_data)
+ except json.JSONDecodeError:
+ continue
+ else:
+ return True
+
+ return False
+
+ def get_terse(self):
+ """Read fio output and return terse format data."""
+
+ filename = os.path.join(self.test_dir, "{0}.out".format(self.filename))
+ with open(filename, 'r') as file:
+ file_data = file.read()
+
+ #
+ # Read the first few lines and see if any of them begin with '3;fio-'
+ # If so, the line is probably terse output. Obviously, this only
+ # works for fio terse version 3 and it does not work for
+ # multi-line terse output
+ #
+ lines = file_data.splitlines()
+ for i in range(8):
+ file_data = lines[i]
+ if file_data.startswith('3;fio-'):
+ self.terse_data = file_data.split(';')
+ return True
+
+ return False
+
+ def check_latencies(self, jsondata, ddir, slat=True, clat=True, tlat=True, plus=False,
+ unified=False):
+ """Check fio latency data.
+
+ ddir data direction to check (0=read, 1=write, 2=trim)
+ slat True if submission latency data available to check
+ clat True if completion latency data available to check
+ tlat True of total latency data available to check
+ plus True if we actually have json+ format data where additional checks can
+ be carried out
+ unified True if fio is reporting unified r/w data
+ """
+
+ types = {
+ 'slat': slat,
+ 'clat': clat,
+ 'lat': tlat
+ }
+
+ retval = True
+
+ for lat in ['slat', 'clat', 'lat']:
+ this_iter = True
+ if not types[lat]:
+ if 'percentile' in jsondata[lat+'_ns']:
+ this_iter = False
+ print('unexpected %s percentiles found' % lat)
+ else:
+ print("%s percentiles skipped" % lat)
+ continue
+ else:
+ if 'percentile' not in jsondata[lat+'_ns']:
+ this_iter = False
+ print('%s percentiles not found in fio output' % lat)
+
+ #
+ # Check only for the presence/absence of json+
+ # latency bins. Future work can check the
+ # accurracy of the bin values and counts.
+ #
+ # Because the latency percentiles are based on
+ # the bins, we can be confident that the bin
+ # values and counts are correct if fio's
+ # latency percentiles match what we compute
+ # from the raw data.
+ #
+ if plus:
+ if 'bins' not in jsondata[lat+'_ns']:
+ print('bins not found with json+ output format')
+ this_iter = False
+ else:
+ if not self.check_jsonplus(jsondata[lat+'_ns']):
+ this_iter = False
+ else:
+ if 'bins' in jsondata[lat+'_ns']:
+ print('json+ bins found with json output format')
+ this_iter = False
+
+ latencies = []
+ for i in range(10):
+ lat_file = os.path.join(self.test_dir, "%s_%s.%s.log" % (self.filename, lat, i+1))
+ if not os.path.exists(lat_file):
+ break
+ with open(lat_file, 'r', newline='') as file:
+ reader = csv.reader(file)
+ for line in reader:
+ if unified or int(line[2]) == ddir:
+ latencies.append(int(line[1]))
+
+ if int(jsondata['total_ios']) != len(latencies):
+ this_iter = False
+ print('%s: total_ios = %s, latencies logged = %d' % \
+ (lat, jsondata['total_ios'], len(latencies)))
+ elif self.debug:
+ print("total_ios %s match latencies logged" % jsondata['total_ios'])
+
+ latencies.sort()
+ ptiles = jsondata[lat+'_ns']['percentile']
+
+ for percentile in ptiles.keys():
+ #
+ # numpy.percentile(latencies, float(percentile),
+ # interpolation='higher')
+ # produces values that mostly match what fio reports
+ # however, in the tails of the distribution, the values produced
+ # by fio's and numpy.percentile's algorithms are occasionally off
+ # by one latency measurement. So instead of relying on the canned
+ # numpy.percentile routine, implement here fio's algorithm
+ #
+ rank = math.ceil(float(percentile)/100 * len(latencies))
+ if rank > 0:
+ index = rank - 1
+ else:
+ index = 0
+ value = latencies[int(index)]
+ fio_val = int(ptiles[percentile])
+ # The theory in stat.h says that the proportional error will be
+ # less than 1/128
+ if not self.similar(fio_val, value):
+ delta = abs(fio_val - value) / value
+ print("Error with %s %sth percentile: "
+ "fio: %d, expected: %d, proportional delta: %f" %
+ (lat, percentile, fio_val, value, delta))
+ print("Rank: %d, index: %d" % (rank, index))
+ this_iter = False
+ elif self.debug:
+ print('%s %sth percentile values match: %d, %d' %
+ (lat, percentile, fio_val, value))
+
+ if this_iter:
+ print("%s percentiles match" % lat)
+ else:
+ retval = False
+
+ return retval
+
+ @staticmethod
+ def check_empty(job):
+ """
+ Make sure JSON data is empty.
+
+ Some data structures should be empty. This function makes sure that they are.
+
+ job JSON object that we need to check for emptiness
+ """
+
+ return job['total_ios'] == 0 and \
+ job['slat_ns']['N'] == 0 and \
+ job['clat_ns']['N'] == 0 and \
+ job['lat_ns']['N'] == 0
+
+ def check_nocmdprio_lat(self, job):
+ """
+ Make sure no high/low priority latencies appear.
+
+ job JSON object to check
+ """
+
+ for ddir in ['read', 'write', 'trim']:
+ if ddir in job:
+ if 'lat_high_prio' in job[ddir] or 'lat_low_prio' in job[ddir] or \
+ 'clat_high_prio' in job[ddir] or 'clat_low_prio' in job[ddir]:
+ print("Unexpected high/low priority latencies found in %s output" % ddir)
+ return False
+
+ if self.debug:
+ print("No high/low priority latencies found")
+
+ return True
+
+ @staticmethod
+ def similar(approximation, actual):
+ """
+ Check whether the approximate values recorded by fio are within the theoretical bound.
+
+ Since it is impractical to store exact latency measurements for each and every IO, fio
+ groups similar latency measurements into variable-sized bins. The theory in stat.h says
+ that the proportional error will be less than 1/128. This function checks whether this
+ is true.
+
+ TODO This test will fail when comparing a value from the largest latency bin against its
+ actual measurement. Find some way to detect this and avoid failing.
+
+ approximation value of the bin used by fio to store a given latency
+ actual actual latency value
+ """
+ delta = abs(approximation - actual) / actual
+ return delta <= 1/128
+
+ def check_jsonplus(self, jsondata):
+ """Check consistency of json+ data
+
+ When we have json+ data we can check the min value, max value, and
+ sample size reported by fio
+
+ jsondata json+ data that we need to check
+ """
+
+ retval = True
+
+ keys = [int(k) for k in jsondata['bins'].keys()]
+ values = [int(jsondata['bins'][k]) for k in jsondata['bins'].keys()]
+ smallest = min(keys)
+ biggest = max(keys)
+ sampsize = sum(values)
+
+ if not self.similar(jsondata['min'], smallest):
+ retval = False
+ print('reported min %d does not match json+ min %d' % (jsondata['min'], smallest))
+ elif self.debug:
+ print('json+ min values match: %d' % jsondata['min'])
+
+ if not self.similar(jsondata['max'], biggest):
+ retval = False
+ print('reported max %d does not match json+ max %d' % (jsondata['max'], biggest))
+ elif self.debug:
+ print('json+ max values match: %d' % jsondata['max'])
+
+ if sampsize != jsondata['N']:
+ retval = False
+ print('reported sample size %d does not match json+ total count %d' % \
+ (jsondata['N'], sampsize))
+ elif self.debug:
+ print('json+ sample sizes match: %d' % sampsize)
+
+ return retval
+
+ def check_sync_lat(self, jsondata, plus=False):
+ """Check fsync latency percentile data.
+
+ All we can check is that some percentiles are reported, unless we have json+ data.
+ If we actually have json+ data then we can do more checking.
+
+ jsondata JSON data for fsync operations
+ plus True if we actually have json+ data
+ """
+ retval = True
+
+ if 'percentile' not in jsondata['lat_ns']:
+ print("Sync percentile data not found")
+ return False
+
+ if int(jsondata['total_ios']) != int(jsondata['lat_ns']['N']):
+ retval = False
+ print('Mismatch between total_ios and lat_ns sample size')
+ elif self.debug:
+ print('sync sample sizes match: %d' % jsondata['total_ios'])
+
+ if not plus:
+ if 'bins' in jsondata['lat_ns']:
+ print('Unexpected json+ bin data found')
+ return False
+
+ if not self.check_jsonplus(jsondata['lat_ns']):
+ retval = False
+
+ return retval
+
+ def check_terse(self, terse, jsondata):
+ """Compare terse latencies with JSON latencies.
+
+ terse terse format data for checking
+ jsondata JSON format data for checking
+ """
+
+ retval = True
+
+ for lat in terse:
+ split = lat.split('%')
+ pct = split[0]
+ terse_val = int(split[1][1:])
+ json_val = math.floor(jsondata[pct]/1000)
+ if terse_val != json_val:
+ retval = False
+ print('Mismatch with %sth percentile: json value=%d,%d terse value=%d' % \
+ (pct, jsondata[pct], json_val, terse_val))
+ elif self.debug:
+ print('Terse %sth percentile matches JSON value: %d' % (pct, terse_val))
+
+ return retval
+
+ def check_prio_latencies(self, jsondata, clat=True, plus=False):
+ """Check consistency of high/low priority latencies.
+
+ clat True if we should check clat data; other check lat data
+ plus True if we have json+ format data where additional checks can
+ be carried out
+ unified True if fio is reporting unified r/w data
+ """
+
+ if clat:
+ high = 'clat_high_prio'
+ low = 'clat_low_prio'
+ combined = 'clat_ns'
+ else:
+ high = 'lat_high_prio'
+ low = 'lat_low_prio'
+ combined = 'lat_ns'
+
+ if not high in jsondata or not low in jsondata or not combined in jsondata:
+ print("Error identifying high/low priority latencies")
+ return False
+
+ if jsondata[high]['N'] + jsondata[low]['N'] != jsondata[combined]['N']:
+ print("High %d + low %d != combined sample size %d" % \
+ (jsondata[high]['N'], jsondata[low]['N'], jsondata[combined]['N']))
+ return False
+ elif self.debug:
+ print("High %d + low %d == combined sample size %d" % \
+ (jsondata[high]['N'], jsondata[low]['N'], jsondata[combined]['N']))
+
+ if min(jsondata[high]['min'], jsondata[low]['min']) != jsondata[combined]['min']:
+ print("Min of high %d, low %d min latencies does not match min %d from combined data" % \
+ (jsondata[high]['min'], jsondata[low]['min'], jsondata[combined]['min']))
+ return False
+ elif self.debug:
+ print("Min of high %d, low %d min latencies matches min %d from combined data" % \
+ (jsondata[high]['min'], jsondata[low]['min'], jsondata[combined]['min']))
+
+ if max(jsondata[high]['max'], jsondata[low]['max']) != jsondata[combined]['max']:
+ print("Max of high %d, low %d max latencies does not match max %d from combined data" % \
+ (jsondata[high]['max'], jsondata[low]['max'], jsondata[combined]['max']))
+ return False
+ elif self.debug:
+ print("Max of high %d, low %d max latencies matches max %d from combined data" % \
+ (jsondata[high]['max'], jsondata[low]['max'], jsondata[combined]['max']))
+
+ weighted_avg = (jsondata[high]['mean'] * jsondata[high]['N'] + \
+ jsondata[low]['mean'] * jsondata[low]['N']) / jsondata[combined]['N']
+ delta = abs(weighted_avg - jsondata[combined]['mean'])
+ if (delta / jsondata[combined]['mean']) > 0.0001:
+ print("Difference between weighted average %f of high, low means "
+ "and actual mean %f exceeds 0.01%%" % (weighted_avg, jsondata[combined]['mean']))
+ return False
+ elif self.debug:
+ print("Weighted average %f of high, low means matches actual mean %f" % \
+ (weighted_avg, jsondata[combined]['mean']))
+
+ if plus:
+ if not self.check_jsonplus(jsondata[high]):
+ return False
+ if not self.check_jsonplus(jsondata[low]):
+ return False
+
+ bins = {**jsondata[high]['bins'], **jsondata[low]['bins']}
+ for duration in bins.keys():
+ if duration in jsondata[high]['bins'] and duration in jsondata[low]['bins']:
+ bins[duration] = jsondata[high]['bins'][duration] + \
+ jsondata[low]['bins'][duration]
+
+ if len(bins) != len(jsondata[combined]['bins']):
+ print("Number of combined high/low bins does not match number of overall bins")
+ return False
+ elif self.debug:
+ print("Number of bins from merged high/low data matches number of overall bins")
+
+ for duration in bins.keys():
+ if bins[duration] != jsondata[combined]['bins'][duration]:
+ print("Merged high/low count does not match overall count for duration %d" \
+ % duration)
+ return False
+
+ print("Merged high/low priority latency data match combined latency data")
+ return True
+
+ def check(self):
+ """Check test output."""
+
+ raise NotImplementedError()
+
+
+class Test001(FioLatTest):
+ """Test object for Test 1."""
+
+ def check(self):
+ """Check Test 1 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if not self.check_empty(job['write']):
+ print("Unexpected write data found in output")
+ retval = False
+ if not self.check_empty(job['trim']):
+ print("Unexpected trim data found in output")
+ retval = False
+ if not self.check_nocmdprio_lat(job):
+ print("Unexpected high/low priority latencies found")
+ retval = False
+
+ retval &= self.check_latencies(job['read'], 0, slat=False)
+
+ return retval
+
+
+class Test002(FioLatTest):
+ """Test object for Test 2."""
+
+ def check(self):
+ """Check Test 2 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if not self.check_empty(job['read']):
+ print("Unexpected read data found in output")
+ retval = False
+ if not self.check_empty(job['trim']):
+ print("Unexpected trim data found in output")
+ retval = False
+ if not self.check_nocmdprio_lat(job):
+ print("Unexpected high/low priority latencies found")
+ retval = False
+
+ retval &= self.check_latencies(job['write'], 1, slat=False, clat=False)
+
+ return retval
+
+
+class Test003(FioLatTest):
+ """Test object for Test 3."""
+
+ def check(self):
+ """Check Test 3 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if not self.check_empty(job['read']):
+ print("Unexpected read data found in output")
+ retval = False
+ if not self.check_empty(job['write']):
+ print("Unexpected write data found in output")
+ retval = False
+ if not self.check_nocmdprio_lat(job):
+ print("Unexpected high/low priority latencies found")
+ retval = False
+
+ retval &= self.check_latencies(job['trim'], 2, slat=False, tlat=False)
+
+ return retval
+
+
+class Test004(FioLatTest):
+ """Test object for Tests 4, 13."""
+
+ def check(self):
+ """Check Test 4, 13 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if not self.check_empty(job['write']):
+ print("Unexpected write data found in output")
+ retval = False
+ if not self.check_empty(job['trim']):
+ print("Unexpected trim data found in output")
+ retval = False
+ if not self.check_nocmdprio_lat(job):
+ print("Unexpected high/low priority latencies found")
+ retval = False
+
+ retval &= self.check_latencies(job['read'], 0, plus=True)
+
+ return retval
+
+
+class Test005(FioLatTest):
+ """Test object for Test 5."""
+
+ def check(self):
+ """Check Test 5 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if not self.check_empty(job['read']):
+ print("Unexpected read data found in output")
+ retval = False
+ if not self.check_empty(job['trim']):
+ print("Unexpected trim data found in output")
+ retval = False
+ if not self.check_nocmdprio_lat(job):
+ print("Unexpected high/low priority latencies found")
+ retval = False
+
+ retval &= self.check_latencies(job['write'], 1, slat=False, plus=True)
+
+ return retval
+
+
+class Test006(FioLatTest):
+ """Test object for Test 6."""
+
+ def check(self):
+ """Check Test 6 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if not self.check_empty(job['write']):
+ print("Unexpected write data found in output")
+ retval = False
+ if not self.check_empty(job['trim']):
+ print("Unexpected trim data found in output")
+ retval = False
+ if not self.check_nocmdprio_lat(job):
+ print("Unexpected high/low priority latencies found")
+ retval = False
+
+ retval &= self.check_latencies(job['read'], 0, slat=False, tlat=False, plus=True)
+
+ return retval
+
+
+class Test007(FioLatTest):
+ """Test object for Test 7."""
+
+ def check(self):
+ """Check Test 7 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if not self.check_empty(job['trim']):
+ print("Unexpected trim data found in output")
+ retval = False
+ if not self.check_nocmdprio_lat(job):
+ print("Unexpected high/low priority latencies found")
+ retval = False
+
+ retval &= self.check_latencies(job['read'], 0, clat=False, tlat=False, plus=True)
+ retval &= self.check_latencies(job['write'], 1, clat=False, tlat=False, plus=True)
+
+ return retval
+
+
+class Test008(FioLatTest):
+ """Test object for Tests 8, 14."""
+
+ def check(self):
+ """Check Test 8, 14 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if 'read' in job or 'write'in job or 'trim' in job:
+ print("Unexpected data direction found in fio output")
+ retval = False
+ if not self.check_nocmdprio_lat(job):
+ print("Unexpected high/low priority latencies found")
+ retval = False
+
+ retval &= self.check_latencies(job['mixed'], 0, plus=True, unified=True)
+
+ return retval
+
+
+class Test009(FioLatTest):
+ """Test object for Test 9."""
+
+ def check(self):
+ """Check Test 9 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if not self.check_empty(job['read']):
+ print("Unexpected read data found in output")
+ retval = False
+ if not self.check_empty(job['trim']):
+ print("Unexpected trim data found in output")
+ retval = False
+ if not self.check_sync_lat(job['sync'], plus=True):
+ print("Error checking fsync latency data")
+ retval = False
+ if not self.check_nocmdprio_lat(job):
+ print("Unexpected high/low priority latencies found")
+ retval = False
+
+ retval &= self.check_latencies(job['write'], 1, slat=False, plus=True)
+
+ return retval
+
+
+class Test010(FioLatTest):
+ """Test object for Test 10."""
+
+ def check(self):
+ """Check Test 10 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if not self.check_empty(job['trim']):
+ print("Unexpected trim data found in output")
+ retval = False
+ if not self.check_nocmdprio_lat(job):
+ print("Unexpected high/low priority latencies found")
+ retval = False
+
+ retval &= self.check_latencies(job['read'], 0, plus=True)
+ retval &= self.check_latencies(job['write'], 1, plus=True)
+ retval &= self.check_terse(self.terse_data[17:34], job['read']['lat_ns']['percentile'])
+ retval &= self.check_terse(self.terse_data[58:75], job['write']['lat_ns']['percentile'])
+ # Terse data checking only works for default percentiles.
+ # This needs to be changed if something other than the default is ever used.
+
+ return retval
+
+
+class Test011(FioLatTest):
+ """Test object for Test 11."""
+
+ def check(self):
+ """Check Test 11 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if not self.check_empty(job['trim']):
+ print("Unexpected trim data found in output")
+ retval = False
+ if not self.check_nocmdprio_lat(job):
+ print("Unexpected high/low priority latencies found")
+ retval = False
+
+ retval &= self.check_latencies(job['read'], 0, slat=False, clat=False, plus=True)
+ retval &= self.check_latencies(job['write'], 1, slat=False, clat=False, plus=True)
+ retval &= self.check_terse(self.terse_data[17:34], job['read']['lat_ns']['percentile'])
+ retval &= self.check_terse(self.terse_data[58:75], job['write']['lat_ns']['percentile'])
+ # Terse data checking only works for default percentiles.
+ # This needs to be changed if something other than the default is ever used.
+
+ return retval
+
+
+class Test015(FioLatTest):
+ """Test object for Test 15."""
+
+ def check(self):
+ """Check Test 15 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if not self.check_empty(job['write']):
+ print("Unexpected write data found in output")
+ retval = False
+ if not self.check_empty(job['trim']):
+ print("Unexpected trim data found in output")
+ retval = False
+
+ retval &= self.check_latencies(job['read'], 0, plus=True)
+ retval &= self.check_prio_latencies(job['read'], clat=False, plus=True)
+
+ return retval
+
+
+class Test016(FioLatTest):
+ """Test object for Test 16."""
+
+ def check(self):
+ """Check Test 16 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if not self.check_empty(job['read']):
+ print("Unexpected read data found in output")
+ retval = False
+ if not self.check_empty(job['trim']):
+ print("Unexpected trim data found in output")
+ retval = False
+
+ retval &= self.check_latencies(job['write'], 1, slat=False, plus=True)
+ retval &= self.check_prio_latencies(job['write'], clat=False, plus=True)
+
+ return retval
+
+
+class Test017(FioLatTest):
+ """Test object for Test 17."""
+
+ def check(self):
+ """Check Test 17 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if not self.check_empty(job['write']):
+ print("Unexpected write data found in output")
+ retval = False
+ if not self.check_empty(job['trim']):
+ print("Unexpected trim data found in output")
+ retval = False
+
+ retval &= self.check_latencies(job['read'], 0, slat=False, tlat=False, plus=True)
+ retval &= self.check_prio_latencies(job['read'], plus=True)
+
+ return retval
+
+
+class Test018(FioLatTest):
+ """Test object for Test 18."""
+
+ def check(self):
+ """Check Test 18 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if not self.check_empty(job['trim']):
+ print("Unexpected trim data found in output")
+ retval = False
+
+ retval &= self.check_latencies(job['read'], 0, clat=False, tlat=False, plus=True)
+ retval &= self.check_latencies(job['write'], 1, clat=False, tlat=False, plus=True)
+
+ # We actually have json+ data but setting plus=False below avoids checking the
+ # json+ bins which did not exist for clat and lat because this job is run with
+ # clat_percentiles=0, lat_percentiles=0, However, we can still check the summary
+ # statistics
+ retval &= self.check_prio_latencies(job['write'], plus=False)
+ retval &= self.check_prio_latencies(job['read'], plus=False)
+
+ return retval
+
+
+class Test019(FioLatTest):
+ """Test object for Tests 19, 20."""
+
+ def check(self):
+ """Check Test 19, 20 output."""
+
+ job = self.json_data['jobs'][0]
+
+ retval = True
+ if 'read' in job or 'write'in job or 'trim' in job:
+ print("Unexpected data direction found in fio output")
+ retval = False
+
+ retval &= self.check_latencies(job['mixed'], 0, plus=True, unified=True)
+ retval &= self.check_prio_latencies(job['mixed'], clat=False, plus=True)
+
+ return retval
+
+
+def parse_args():
+ """Parse command-line arguments."""
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-f', '--fio', help='path to file executable (e.g., ./fio)')
+ parser.add_argument('-a', '--artifact-root', help='artifact root directory')
+ parser.add_argument('-d', '--debug', help='enable debug output', action='store_true')
+ parser.add_argument('-s', '--skip', nargs='+', type=int,
+ help='list of test(s) to skip')
+ parser.add_argument('-o', '--run-only', nargs='+', type=int,
+ help='list of test(s) to run, skipping all others')
+ args = parser.parse_args()
+
+ return args
+
+
+def main():
+ """Run tests of fio latency percentile reporting"""
+
+ args = parse_args()
+
+ artifact_root = args.artifact_root if args.artifact_root else \
+ "latency-test-{0}".format(time.strftime("%Y%m%d-%H%M%S"))
+ os.mkdir(artifact_root)
+ print("Artifact directory is %s" % artifact_root)
+
+ if args.fio:
+ fio = str(Path(args.fio).absolute())
+ else:
+ fio = 'fio'
+ print("fio path is %s" % fio)
+
+ if platform.system() == 'Linux':
+ aio = 'libaio'
+ elif platform.system() == 'Windows':
+ aio = 'windowsaio'
+ else:
+ aio = 'posixaio'
+
+ test_list = [
+ {
+ # randread, null
+ # enable slat, clat, lat
+ # only clat and lat will appear because
+ # because the null ioengine is syncrhonous
+ "test_id": 1,
+ "runtime": 2,
+ "output-format": "json",
+ "slat_percentiles": 1,
+ "clat_percentiles": 1,
+ "lat_percentiles": 1,
+ "ioengine": 'null',
+ 'rw': 'randread',
+ "test_obj": Test001,
+ },
+ {
+ # randwrite, null
+ # enable lat only
+ "test_id": 2,
+ "runtime": 2,
+ "output-format": "json",
+ "slat_percentiles": 0,
+ "clat_percentiles": 0,
+ "lat_percentiles": 1,
+ "ioengine": 'null',
+ 'rw': 'randwrite',
+ "test_obj": Test002,
+ },
+ {
+ # randtrim, null
+ # enable clat only
+ "test_id": 3,
+ "runtime": 2,
+ "output-format": "json",
+ "slat_percentiles": 0,
+ "clat_percentiles": 1,
+ "lat_percentiles": 0,
+ "ioengine": 'null',
+ 'rw': 'randtrim',
+ "test_obj": Test003,
+ },
+ {
+ # randread, aio
+ # enable slat, clat, lat
+ # all will appear because liaio is asynchronous
+ "test_id": 4,
+ "runtime": 5,
+ "output-format": "json+",
+ "slat_percentiles": 1,
+ "clat_percentiles": 1,
+ "lat_percentiles": 1,
+ "ioengine": aio,
+ 'rw': 'randread',
+ "test_obj": Test004,
+ },
+ {
+ # randwrite, aio
+ # enable only clat, lat
+ "test_id": 5,
+ "runtime": 5,
+ "output-format": "json+",
+ "slat_percentiles": 0,
+ "clat_percentiles": 1,
+ "lat_percentiles": 1,
+ "ioengine": aio,
+ 'rw': 'randwrite',
+ "test_obj": Test005,
+ },
+ {
+ # randread, aio
+ # by default only clat should appear
+ "test_id": 6,
+ "runtime": 5,
+ "output-format": "json+",
+ "ioengine": aio,
+ 'rw': 'randread',
+ "test_obj": Test006,
+ },
+ {
+ # 50/50 r/w, aio
+ # enable only slat
+ "test_id": 7,
+ "runtime": 5,
+ "output-format": "json+",
+ "slat_percentiles": 1,
+ "clat_percentiles": 0,
+ "lat_percentiles": 0,
+ "ioengine": aio,
+ 'rw': 'randrw',
+ "test_obj": Test007,
+ },
+ {
+ # 50/50 r/w, aio, unified_rw_reporting
+ # enable slat, clat, lat
+ "test_id": 8,
+ "runtime": 5,
+ "output-format": "json+",
+ "slat_percentiles": 1,
+ "clat_percentiles": 1,
+ "lat_percentiles": 1,
+ "ioengine": aio,
+ 'rw': 'randrw',
+ 'unified_rw_reporting': 1,
+ "test_obj": Test008,
+ },
+ {
+ # randwrite, null
+ # enable slat, clat, lat
+ # fsync
+ "test_id": 9,
+ "runtime": 2,
+ "output-format": "json+",
+ "slat_percentiles": 1,
+ "clat_percentiles": 1,
+ "lat_percentiles": 1,
+ "ioengine": 'null',
+ 'rw': 'randwrite',
+ 'fsync': 32,
+ "test_obj": Test009,
+ },
+ {
+ # 50/50 r/w, aio
+ # enable slat, clat, lat
+ "test_id": 10,
+ "runtime": 5,
+ "output-format": "terse,json+",
+ "slat_percentiles": 1,
+ "clat_percentiles": 1,
+ "lat_percentiles": 1,
+ "ioengine": aio,
+ 'rw': 'randrw',
+ "test_obj": Test010,
+ },
+ {
+ # 50/50 r/w, aio
+ # enable only lat
+ "test_id": 11,
+ "runtime": 5,
+ "output-format": "terse,json+",
+ "slat_percentiles": 0,
+ "clat_percentiles": 0,
+ "lat_percentiles": 1,
+ "ioengine": aio,
+ 'rw': 'randrw',
+ "test_obj": Test011,
+ },
+ {
+ # randread, null
+ # enable slat, clat, lat
+ # only clat and lat will appear because
+ # because the null ioengine is syncrhonous
+ # same as Test 1 except
+ # numjobs = 4 to test sum_thread_stats() changes
+ "test_id": 12,
+ "runtime": 2,
+ "output-format": "json",
+ "slat_percentiles": 1,
+ "clat_percentiles": 1,
+ "lat_percentiles": 1,
+ "ioengine": 'null',
+ 'rw': 'randread',
+ 'numjobs': 4,
+ "test_obj": Test001,
+ },
+ {
+ # randread, aio
+ # enable slat, clat, lat
+ # all will appear because liaio is asynchronous
+ # same as Test 4 except
+ # numjobs = 4 to test sum_thread_stats() changes
+ "test_id": 13,
+ "runtime": 5,
+ "output-format": "json+",
+ "slat_percentiles": 1,
+ "clat_percentiles": 1,
+ "lat_percentiles": 1,
+ "ioengine": aio,
+ 'rw': 'randread',
+ 'numjobs': 4,
+ "test_obj": Test004,
+ },
+ {
+ # 50/50 r/w, aio, unified_rw_reporting
+ # enable slat, clat, lata
+ # same as Test 8 except
+ # numjobs = 4 to test sum_thread_stats() changes
+ "test_id": 14,
+ "runtime": 5,
+ "output-format": "json+",
+ "slat_percentiles": 1,
+ "clat_percentiles": 1,
+ "lat_percentiles": 1,
+ "ioengine": aio,
+ 'rw': 'randrw',
+ 'unified_rw_reporting': 1,
+ 'numjobs': 4,
+ "test_obj": Test008,
+ },
+ {
+ # randread, aio
+ # enable slat, clat, lat
+ # all will appear because liaio is asynchronous
+ # same as Test 4 except add cmdprio_percentage
+ "test_id": 15,
+ "runtime": 5,
+ "output-format": "json+",
+ "slat_percentiles": 1,
+ "clat_percentiles": 1,
+ "lat_percentiles": 1,
+ "ioengine": aio,
+ 'rw': 'randread',
+ 'cmdprio_percentage': 50,
+ "test_obj": Test015,
+ },
+ {
+ # randwrite, aio
+ # enable only clat, lat
+ # same as Test 5 except add cmdprio_percentage
+ "test_id": 16,
+ "runtime": 5,
+ "output-format": "json+",
+ "slat_percentiles": 0,
+ "clat_percentiles": 1,
+ "lat_percentiles": 1,
+ "ioengine": aio,
+ 'rw': 'randwrite',
+ 'cmdprio_percentage': 50,
+ "test_obj": Test016,
+ },
+ {
+ # randread, aio
+ # by default only clat should appear
+ # same as Test 6 except add cmdprio_percentage
+ "test_id": 17,
+ "runtime": 5,
+ "output-format": "json+",
+ "ioengine": aio,
+ 'rw': 'randread',
+ 'cmdprio_percentage': 50,
+ "test_obj": Test017,
+ },
+ {
+ # 50/50 r/w, aio
+ # enable only slat
+ # same as Test 7 except add cmdprio_percentage
+ "test_id": 18,
+ "runtime": 5,
+ "output-format": "json+",
+ "slat_percentiles": 1,
+ "clat_percentiles": 0,
+ "lat_percentiles": 0,
+ "ioengine": aio,
+ 'rw': 'randrw',
+ 'cmdprio_percentage': 50,
+ "test_obj": Test018,
+ },
+ {
+ # 50/50 r/w, aio, unified_rw_reporting
+ # enable slat, clat, lat
+ # same as Test 8 except add cmdprio_percentage
+ "test_id": 19,
+ "runtime": 5,
+ "output-format": "json+",
+ "slat_percentiles": 1,
+ "clat_percentiles": 1,
+ "lat_percentiles": 1,
+ "ioengine": aio,
+ 'rw': 'randrw',
+ 'unified_rw_reporting': 1,
+ 'cmdprio_percentage': 50,
+ "test_obj": Test019,
+ },
+ {
+ # 50/50 r/w, aio, unified_rw_reporting
+ # enable slat, clat, lat
+ # same as Test 19 except
+ # add numjobs = 4 to test sum_thread_stats() changes
+ "test_id": 20,
+ "runtime": 5,
+ "output-format": "json+",
+ "slat_percentiles": 1,
+ "clat_percentiles": 1,
+ "lat_percentiles": 1,
+ "ioengine": aio,
+ 'rw': 'randrw',
+ 'unified_rw_reporting': 1,
+ 'cmdprio_percentage': 50,
+ 'numjobs': 4,
+ "test_obj": Test019,
+ },
+ ]
+
+ passed = 0
+ failed = 0
+ skipped = 0
+
+ for test in test_list:
+ if (args.skip and test['test_id'] in args.skip) or \
+ (args.run_only and test['test_id'] not in args.run_only):
+ skipped = skipped + 1
+ outcome = 'SKIPPED (User request)'
+ elif platform.system() != 'Linux' and 'cmdprio_percentage' in test:
+ skipped = skipped + 1
+ outcome = 'SKIPPED (Linux required for cmdprio_percentage tests)'
+ else:
+ test_obj = test['test_obj'](artifact_root, test, args.debug)
+ status = test_obj.run_fio(fio)
+ if status:
+ status = test_obj.check()
+ if status:
+ passed = passed + 1
+ outcome = 'PASSED'
+ else:
+ failed = failed + 1
+ outcome = 'FAILED'
+
+ print("**********Test {0} {1}**********".format(test['test_id'], outcome))
+
+ print("{0} tests passed, {1} failed, {2} skipped".format(passed, failed, skipped))
+
+ sys.exit(failed)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/t/run-fio-tests.py b/t/run-fio-tests.py
index 3d236e37..003ff664 100755
--- a/t/run-fio-tests.py
+++ b/t/run-fio-tests.py
@@ -510,17 +510,17 @@ class Requirements(object):
SUCCESS_DEFAULT = {
'zero_return': True,
'stderr_empty': True,
- 'timeout': 300,
+ 'timeout': 600,
}
SUCCESS_NONZERO = {
'zero_return': False,
'stderr_empty': False,
- 'timeout': 300,
+ 'timeout': 600,
}
SUCCESS_STDERR = {
'zero_return': True,
'stderr_empty': False,
- 'timeout': 300,
+ 'timeout': 600,
}
TEST_LIST = [
{
@@ -712,6 +712,14 @@ TEST_LIST = [
'success': SUCCESS_DEFAULT,
'requirements': [Requirements.unittests],
},
+ {
+ 'test_id': 1010,
+ 'test_class': FioExeTest,
+ 'exe': 't/latency_percentiles.py',
+ 'parameters': ['-f', '{fio_path}'],
+ 'success': SUCCESS_DEFAULT,
+ 'requirements': [],
+ },
]
diff --git a/thread_options.h b/thread_options.h
index 4b131bda..c78ed43d 100644
--- a/thread_options.h
+++ b/thread_options.h
@@ -250,6 +250,7 @@ struct thread_options {
unsigned int trim_zero;
unsigned long long trim_backlog;
unsigned int clat_percentiles;
+ unsigned int slat_percentiles;
unsigned int lat_percentiles;
unsigned int percentile_precision; /* digits after decimal for percentiles */
fio_fp64_t percentile_list[FIO_IO_U_LIST_MAX_LEN];
@@ -370,7 +371,7 @@ struct thread_options_pack {
uint32_t iodepth_batch_complete_min;
uint32_t iodepth_batch_complete_max;
uint32_t serialize_overlap;
- uint32_t lat_percentiles;
+ uint32_t pad;
uint64_t size;
uint64_t io_size;
@@ -430,7 +431,7 @@ struct thread_options_pack {
uint32_t override_sync;
uint32_t rand_repeatable;
uint32_t allrand_repeatable;
- uint32_t pad;
+ uint32_t pad2;
uint64_t rand_seed;
uint32_t log_avg_msec;
uint32_t log_hist_msec;
@@ -464,7 +465,6 @@ struct thread_options_pack {
uint32_t hugepage_size;
uint64_t rw_min_bs;
- uint32_t pad2;
uint32_t thinktime;
uint32_t thinktime_spin;
uint32_t thinktime_blocks;
@@ -539,7 +539,10 @@ struct thread_options_pack {
uint32_t trim_zero;
uint64_t trim_backlog;
uint32_t clat_percentiles;
+ uint32_t lat_percentiles;
+ uint32_t slat_percentiles;
uint32_t percentile_precision;
+ uint32_t pad3;
fio_fp64_t percentile_list[FIO_IO_U_LIST_MAX_LEN];
uint8_t read_iolog_file[FIO_TOP_STR_MAX];
@@ -573,7 +576,6 @@ struct thread_options_pack {
uint32_t rate_iops_min[DDIR_RWDIR_CNT];
uint32_t rate_process;
uint32_t rate_ign_think;
- uint32_t pad3;
uint8_t ioscheduler[FIO_TOP_STR_MAX];
@@ -603,7 +605,6 @@ struct thread_options_pack {
uint32_t flow_sleep;
uint32_t offset_increment_percent;
- uint32_t pad4;
uint64_t offset_increment;
uint64_t number_ios;
next reply other threads:[~2020-02-05 13:00 UTC|newest]
Thread overview: 1510+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-05 13:00 Jens Axboe [this message]
-- strict thread matches above, loose matches on Subject: below --
2026-05-13 12:00 Recent changes (master) Jens Axboe
2026-05-01 12:00 Jens Axboe
2026-04-29 12:00 Jens Axboe
2026-04-23 12:00 Jens Axboe
2026-04-18 12:00 Jens Axboe
2026-04-17 12:00 Jens Axboe
2026-04-08 12:00 Jens Axboe
2026-04-07 12:00 Jens Axboe
2026-04-02 12:00 Jens Axboe
2026-03-19 12:00 Jens Axboe
2026-03-17 12:00 Jens Axboe
2026-03-11 12:00 Jens Axboe
2026-03-10 12:00 Jens Axboe
2026-03-04 13:00 Jens Axboe
2026-03-03 13:00 Jens Axboe
2026-03-02 13:00 Jens Axboe
2026-02-25 13:00 Jens Axboe
2026-02-14 13:00 Jens Axboe
2026-02-10 13:00 Jens Axboe
2026-02-09 13:00 Jens Axboe
2026-02-06 13:00 Jens Axboe
2026-02-03 13:00 Jens Axboe
2026-01-31 13:00 Jens Axboe
2026-01-28 13:00 Jens Axboe
2026-01-24 13:00 Jens Axboe
2026-01-21 13:00 Jens Axboe
2026-01-17 13:00 Jens Axboe
2026-01-16 13:00 Jens Axboe
2026-01-12 13:00 Jens Axboe
2026-01-08 13:00 Jens Axboe
2025-12-30 13:00 Jens Axboe
2025-12-19 13:00 Jens Axboe
2025-12-17 13:00 Jens Axboe
2025-12-14 13:00 Jens Axboe
2025-12-11 13:00 Jens Axboe
2025-12-09 13:00 Jens Axboe
2025-11-25 13:00 Jens Axboe
2025-11-19 13:00 Jens Axboe
2025-11-18 13:00 Jens Axboe
2025-11-15 13:00 Jens Axboe
2025-11-06 13:00 Jens Axboe
2025-11-01 12:00 Jens Axboe
2025-10-31 12:00 Jens Axboe
2025-10-30 12:00 Jens Axboe
2025-10-29 12:00 Jens Axboe
2025-10-16 12:00 Jens Axboe
2025-10-11 12:00 Jens Axboe
2025-10-10 12:00 Jens Axboe
2025-10-09 12:00 Jens Axboe
2025-10-06 12:00 Jens Axboe
2025-10-05 12:00 Jens Axboe
2025-10-02 12:00 Jens Axboe
2025-09-26 12:00 Jens Axboe
2025-09-24 12:00 Jens Axboe
2025-09-19 12:00 Jens Axboe
2025-09-18 12:00 Jens Axboe
2025-09-17 12:00 Jens Axboe
2025-09-09 12:00 Jens Axboe
2025-09-06 12:00 Jens Axboe
2025-09-05 12:00 Jens Axboe
2025-09-04 12:00 Jens Axboe
2025-08-27 12:00 Jens Axboe
2025-08-26 12:00 Jens Axboe
2025-08-23 12:00 Jens Axboe
2025-08-22 12:00 Jens Axboe
2025-08-21 12:00 Jens Axboe
2025-08-20 12:00 Jens Axboe
2025-08-19 12:00 Jens Axboe
2025-08-12 12:00 Jens Axboe
2025-08-10 12:00 Jens Axboe
2025-08-08 12:00 Jens Axboe
2025-08-06 12:00 Jens Axboe
2025-08-03 12:00 Jens Axboe
2025-08-01 12:00 Jens Axboe
2025-07-24 12:00 Jens Axboe
2025-07-23 12:00 Jens Axboe
2025-07-19 12:00 Jens Axboe
2025-07-17 12:00 Jens Axboe
2025-07-10 12:00 Jens Axboe
2025-07-09 12:00 Jens Axboe
2025-07-01 12:00 Jens Axboe
2025-06-24 12:00 Jens Axboe
2025-06-05 12:00 Jens Axboe
2025-06-03 12:00 Jens Axboe
2025-06-01 12:00 Jens Axboe
2025-05-24 12:00 Jens Axboe
2025-05-21 12:00 Jens Axboe
2025-05-17 12:00 Jens Axboe
2025-05-14 12:00 Jens Axboe
2025-05-10 12:00 Jens Axboe
2025-05-09 12:00 Jens Axboe
2025-05-08 12:00 Jens Axboe
2025-05-07 12:00 Jens Axboe
2025-04-16 12:00 Jens Axboe
2025-04-15 12:00 Jens Axboe
2025-04-08 12:00 Jens Axboe
2025-04-05 12:00 Jens Axboe
2025-03-20 12:00 Jens Axboe
2025-03-19 12:00 Jens Axboe
2025-03-08 13:00 Jens Axboe
2025-03-07 13:00 Jens Axboe
2025-03-06 13:00 Jens Axboe
2025-02-21 13:00 Jens Axboe
2025-02-19 13:00 Jens Axboe
2025-02-18 13:00 Jens Axboe
2025-02-15 13:00 Jens Axboe
2025-02-14 13:00 Jens Axboe
2025-01-31 13:00 Jens Axboe
2025-01-24 13:00 Jens Axboe
2025-01-23 13:00 Jens Axboe
2025-01-22 13:00 Jens Axboe
2024-12-17 13:00 Jens Axboe
2024-12-10 13:00 Jens Axboe
2024-12-05 13:00 Jens Axboe
2024-11-23 13:00 Jens Axboe
2024-11-06 13:00 Jens Axboe
2024-11-05 13:00 Jens Axboe
2024-10-29 12:00 Jens Axboe
2024-10-17 12:00 Jens Axboe
2024-10-09 12:00 Jens Axboe
2024-10-04 12:00 Jens Axboe
2024-10-03 12:00 Jens Axboe
2024-10-01 12:00 Jens Axboe
2024-09-28 12:00 Jens Axboe
2024-09-27 12:00 Jens Axboe
2024-09-17 12:00 Jens Axboe
2024-09-07 12:00 Jens Axboe
2024-09-06 12:00 Jens Axboe
2024-09-05 12:00 Jens Axboe
2024-09-04 12:00 Jens Axboe
2024-08-30 12:00 Jens Axboe
2024-08-29 12:00 Jens Axboe
2024-08-22 12:00 Jens Axboe
2024-08-17 12:00 Jens Axboe
2024-08-07 12:00 Jens Axboe
2024-08-06 12:00 Jens Axboe
2024-07-27 12:00 Jens Axboe
2024-07-18 12:00 Jens Axboe
2024-07-16 12:00 Jens Axboe
2024-07-13 12:00 Jens Axboe
2024-07-12 12:00 Jens Axboe
2024-06-29 12:00 Jens Axboe
2024-06-15 12:00 Jens Axboe
2024-06-13 12:00 Jens Axboe
2024-06-13 12:00 Jens Axboe
2024-06-12 12:00 Jens Axboe
2024-06-08 12:00 Jens Axboe
2024-06-07 12:00 Jens Axboe
2024-06-05 12:00 Jens Axboe
2024-06-04 12:00 Jens Axboe
2024-06-04 12:11 ` Niklas Cassel
2024-06-04 12:53 ` Vincent Fu
2024-06-01 12:00 Jens Axboe
2024-05-29 12:00 Jens Axboe
2024-05-25 12:00 Jens Axboe
2024-05-22 12:00 Jens Axboe
2024-05-01 12:00 Jens Axboe
2024-04-26 12:00 Jens Axboe
2024-04-25 12:00 Jens Axboe
2024-04-20 12:00 Jens Axboe
2024-04-19 12:00 Jens Axboe
2024-04-18 12:00 Jens Axboe
2024-04-17 12:00 Jens Axboe
2024-04-16 12:00 Jens Axboe
2024-04-03 12:00 Jens Axboe
2024-03-27 12:00 Jens Axboe
2024-03-26 12:00 Jens Axboe
2024-03-23 12:00 Jens Axboe
2024-03-22 12:00 Jens Axboe
2024-03-21 12:00 Jens Axboe
2024-03-19 12:00 Jens Axboe
2024-03-08 13:00 Jens Axboe
2024-03-06 13:00 Jens Axboe
2024-03-05 13:00 Jens Axboe
2024-02-28 13:00 Jens Axboe
2024-02-23 13:00 Jens Axboe
2024-02-17 13:00 Jens Axboe
2024-02-16 13:00 Jens Axboe
2024-02-15 13:00 Jens Axboe
2024-02-14 13:00 Jens Axboe
2024-02-13 13:00 Jens Axboe
2024-02-09 13:00 Jens Axboe
2024-02-08 13:00 Jens Axboe
2024-01-28 13:00 Jens Axboe
2024-01-26 13:00 Jens Axboe
2024-01-25 13:00 Jens Axboe
2024-01-24 13:00 Jens Axboe
2024-01-23 13:00 Jens Axboe
2024-01-19 13:00 Jens Axboe
2024-01-18 13:00 Jens Axboe
2024-01-18 13:00 Jens Axboe
2024-01-17 13:00 Jens Axboe
2023-12-30 13:00 Jens Axboe
2023-12-20 13:00 Jens Axboe
2023-12-16 13:00 Jens Axboe
2023-12-15 13:00 Jens Axboe
2023-12-13 13:00 Jens Axboe
2023-12-12 13:00 Jens Axboe
2023-11-20 13:00 Jens Axboe
2023-11-08 13:00 Jens Axboe
2023-11-07 13:00 Jens Axboe
2023-11-04 12:00 Jens Axboe
2023-11-03 12:00 Jens Axboe
2023-11-01 12:00 Jens Axboe
2023-10-26 12:00 Jens Axboe
2023-10-24 12:00 Jens Axboe
2023-10-23 12:00 Jens Axboe
2023-10-20 12:00 Jens Axboe
2023-10-17 12:00 Jens Axboe
2023-10-14 12:00 Jens Axboe
2023-10-07 12:00 Jens Axboe
2023-10-03 12:00 Jens Axboe
2023-09-30 12:00 Jens Axboe
2023-09-29 12:00 Jens Axboe
2023-09-27 12:00 Jens Axboe
2023-09-20 12:00 Jens Axboe
2023-09-16 12:00 Jens Axboe
2023-09-12 12:00 Jens Axboe
2023-09-03 12:00 Jens Axboe
2023-08-24 12:00 Jens Axboe
2023-08-17 12:00 Jens Axboe
2023-08-15 12:00 Jens Axboe
2023-08-04 12:00 Jens Axboe
2023-08-03 12:00 Jens Axboe
2023-08-01 12:00 Jens Axboe
2023-07-29 12:00 Jens Axboe
2023-07-28 12:00 Jens Axboe
2023-07-22 12:00 Jens Axboe
2023-07-21 12:00 Jens Axboe
2023-07-16 12:00 Jens Axboe
2023-07-15 12:00 Jens Axboe
2023-07-14 12:00 Jens Axboe
2023-07-06 12:00 Jens Axboe
2023-07-04 12:00 Jens Axboe
2023-06-22 12:00 Jens Axboe
2023-06-17 12:00 Jens Axboe
2023-06-10 12:00 Jens Axboe
2023-06-09 12:00 Jens Axboe
2023-06-02 12:00 Jens Axboe
2023-05-31 12:00 Jens Axboe
2023-05-25 12:00 Jens Axboe
2023-05-24 12:00 Jens Axboe
2023-05-20 12:00 Jens Axboe
2023-05-19 12:00 Jens Axboe
2023-05-18 12:00 Jens Axboe
2023-05-17 12:00 Jens Axboe
2023-05-16 12:00 Jens Axboe
2023-05-12 12:00 Jens Axboe
2023-05-11 12:00 Jens Axboe
2023-04-28 12:00 Jens Axboe
2023-04-27 12:00 Jens Axboe
2023-04-21 12:00 Jens Axboe
2023-04-14 12:00 Jens Axboe
2023-04-11 12:00 Jens Axboe
2023-04-08 12:00 Jens Axboe
2023-04-05 12:00 Jens Axboe
2023-04-01 12:00 Jens Axboe
2023-03-28 12:00 Jens Axboe
2023-03-22 12:00 Jens Axboe
2023-03-21 12:00 Jens Axboe
2023-03-16 12:00 Jens Axboe
2023-03-15 12:00 Jens Axboe
2023-03-08 13:00 Jens Axboe
2023-03-04 13:00 Jens Axboe
2023-03-03 13:00 Jens Axboe
2023-03-01 13:00 Jens Axboe
2023-02-28 13:00 Jens Axboe
2023-02-24 13:00 Jens Axboe
2023-02-22 13:00 Jens Axboe
2023-02-21 13:00 Jens Axboe
2023-02-18 13:00 Jens Axboe
2023-02-16 13:00 Jens Axboe
2023-02-15 13:00 Jens Axboe
2023-02-11 13:00 Jens Axboe
2023-02-10 13:00 Jens Axboe
2023-02-08 13:00 Jens Axboe
2023-02-07 13:00 Jens Axboe
2023-02-04 13:00 Jens Axboe
2023-02-01 13:00 Jens Axboe
2023-01-31 13:00 Jens Axboe
2023-01-26 13:00 Jens Axboe
2023-01-25 13:00 Jens Axboe
2023-01-24 13:00 Jens Axboe
2023-01-21 13:00 Jens Axboe
2023-01-19 13:00 Jens Axboe
2023-01-12 13:00 Jens Axboe
2022-12-23 13:00 Jens Axboe
2022-12-17 13:00 Jens Axboe
2022-12-16 13:00 Jens Axboe
2022-12-13 13:00 Jens Axboe
2022-12-03 13:00 Jens Axboe
2022-12-02 13:00 Jens Axboe
2022-12-01 13:00 Jens Axboe
2022-11-30 13:00 Jens Axboe
2022-11-29 13:00 Jens Axboe
2022-11-24 13:00 Jens Axboe
2022-11-19 13:00 Jens Axboe
2022-11-15 13:00 Jens Axboe
2022-11-08 13:00 Jens Axboe
2022-11-07 13:00 Jens Axboe
2022-11-05 12:00 Jens Axboe
2022-11-03 12:00 Jens Axboe
2022-11-02 12:00 Jens Axboe
2022-10-25 12:00 Jens Axboe
2022-10-22 12:00 Jens Axboe
2022-10-20 12:00 Jens Axboe
2022-10-19 12:00 Jens Axboe
2022-10-17 12:00 Jens Axboe
2022-10-16 12:00 Jens Axboe
2022-10-15 12:00 Jens Axboe
2022-10-08 12:00 Jens Axboe
2022-10-06 12:00 Jens Axboe
2022-10-05 12:00 Jens Axboe
2022-10-04 12:00 Jens Axboe
2022-09-29 12:00 Jens Axboe
2022-09-23 12:00 Jens Axboe
2022-09-20 12:00 Jens Axboe
2022-09-16 12:00 Jens Axboe
2022-09-14 12:00 Jens Axboe
2022-09-13 12:00 Jens Axboe
2022-09-07 12:00 Jens Axboe
2022-09-04 12:00 Jens Axboe
2022-09-03 12:00 Jens Axboe
2022-09-02 12:00 Jens Axboe
2022-09-01 12:00 Jens Axboe
2022-08-31 12:00 Jens Axboe
2022-08-30 12:00 Jens Axboe
2022-08-27 12:00 Jens Axboe
2022-08-26 12:00 Jens Axboe
2022-08-25 12:00 Jens Axboe
2022-08-24 12:00 Jens Axboe
2022-08-17 12:00 Jens Axboe
2022-08-16 12:00 Jens Axboe
2022-08-12 12:00 Jens Axboe
2022-08-11 12:00 Jens Axboe
2022-08-10 12:00 Jens Axboe
2022-08-08 12:00 Jens Axboe
2022-08-04 12:00 Jens Axboe
2022-08-03 12:00 Jens Axboe
2022-08-01 12:00 Jens Axboe
2022-07-29 12:00 Jens Axboe
2022-07-28 12:00 Jens Axboe
2022-07-23 12:00 Jens Axboe
2022-07-22 12:00 Jens Axboe
2022-07-20 12:00 Jens Axboe
2022-07-12 12:00 Jens Axboe
2022-07-08 12:00 Jens Axboe
2022-07-07 12:00 Jens Axboe
2022-07-06 12:00 Jens Axboe
2022-07-02 12:00 Jens Axboe
2022-06-24 12:00 Jens Axboe
2022-06-23 12:00 Jens Axboe
2022-06-20 12:00 Jens Axboe
2022-06-16 12:00 Jens Axboe
2022-06-14 12:00 Jens Axboe
2022-06-02 12:00 Jens Axboe
2022-06-01 12:00 Jens Axboe
2022-05-30 12:00 Jens Axboe
2022-05-26 12:00 Jens Axboe
2022-05-13 12:00 Jens Axboe
2022-05-02 12:00 Jens Axboe
2022-04-30 12:00 Jens Axboe
2022-04-18 12:00 Jens Axboe
2022-04-11 12:00 Jens Axboe
2022-04-09 12:00 Jens Axboe
2022-04-07 12:00 Jens Axboe
2022-04-06 12:00 Jens Axboe
2022-03-31 12:00 Jens Axboe
2022-03-30 12:00 Jens Axboe
2022-03-29 12:00 Jens Axboe
2022-03-25 12:00 Jens Axboe
2022-03-21 12:00 Jens Axboe
2022-03-16 12:00 Jens Axboe
2022-03-12 13:00 Jens Axboe
2022-03-11 13:00 Jens Axboe
2022-03-10 13:00 Jens Axboe
2022-03-09 13:00 Jens Axboe
2022-03-08 13:00 Jens Axboe
2022-02-27 13:00 Jens Axboe
2022-02-25 13:00 Jens Axboe
2022-02-22 13:00 Jens Axboe
2022-02-21 13:00 Jens Axboe
2022-02-19 13:00 Jens Axboe
2022-02-18 13:00 Jens Axboe
2022-02-16 13:00 Jens Axboe
2022-02-12 13:00 Jens Axboe
2022-02-09 13:00 Jens Axboe
2022-02-05 13:00 Jens Axboe
2022-02-04 13:00 Jens Axboe
2022-01-29 13:00 Jens Axboe
2022-01-27 13:00 Jens Axboe
2022-01-22 13:00 Jens Axboe
2022-01-21 13:00 Jens Axboe
2022-01-19 13:00 Jens Axboe
2022-01-18 13:00 Jens Axboe
2022-01-11 13:00 Jens Axboe
2022-01-10 13:00 Jens Axboe
2021-12-24 13:00 Jens Axboe
2021-12-19 13:00 Jens Axboe
2021-12-16 13:00 Jens Axboe
2021-12-15 13:00 Jens Axboe
2021-12-11 13:00 Jens Axboe
2021-12-10 13:00 Jens Axboe
2021-12-07 13:00 Jens Axboe
2021-12-03 13:00 Jens Axboe
2021-11-26 13:00 Jens Axboe
2021-11-25 13:00 Jens Axboe
2021-11-22 13:00 Jens Axboe
2021-11-21 13:00 Jens Axboe
2021-11-20 13:00 Jens Axboe
2021-11-18 13:00 Jens Axboe
2021-11-13 13:00 Jens Axboe
2021-11-11 13:00 Jens Axboe
2021-10-26 12:00 Jens Axboe
2021-10-23 12:00 Jens Axboe
2021-10-25 15:37 ` Rebecca Cran
2021-10-25 15:41 ` Jens Axboe
2021-10-25 15:42 ` Rebecca Cran
2021-10-25 15:43 ` Jens Axboe
2021-10-20 12:00 Jens Axboe
2021-10-19 12:00 Jens Axboe
2021-10-18 12:00 Jens Axboe
2021-10-16 12:00 Jens Axboe
2021-10-15 12:00 Jens Axboe
2021-10-14 12:00 Jens Axboe
2021-10-13 12:00 Jens Axboe
2021-10-12 12:00 Jens Axboe
2021-10-10 12:00 Jens Axboe
2021-10-08 12:00 Jens Axboe
2021-10-06 12:00 Jens Axboe
2021-10-05 12:00 Jens Axboe
2021-10-02 12:00 Jens Axboe
2021-10-01 12:00 Jens Axboe
2021-09-30 12:00 Jens Axboe
2021-09-29 12:00 Jens Axboe
2021-09-27 12:00 Jens Axboe
2021-09-26 12:00 Jens Axboe
2021-09-25 12:00 Jens Axboe
2021-09-24 12:00 Jens Axboe
2021-09-21 12:00 Jens Axboe
2021-09-17 12:00 Jens Axboe
2021-09-16 12:00 Jens Axboe
2021-09-14 12:00 Jens Axboe
2021-09-09 12:00 Jens Axboe
2021-09-06 12:00 Jens Axboe
2021-09-04 12:00 Jens Axboe
2021-09-04 12:00 ` Jens Axboe
2021-09-03 12:00 Jens Axboe
2021-08-29 12:00 Jens Axboe
2021-08-28 12:00 Jens Axboe
2021-08-27 12:00 Jens Axboe
2021-08-21 12:00 Jens Axboe
2021-08-19 12:00 Jens Axboe
2021-08-14 12:00 Jens Axboe
2021-08-12 12:00 Jens Axboe
2021-08-07 12:00 Jens Axboe
2021-08-05 12:00 Jens Axboe
2021-08-04 12:00 Jens Axboe
2021-08-03 12:00 Jens Axboe
2021-08-02 12:00 Jens Axboe
2021-07-29 12:00 Jens Axboe
2021-07-26 12:00 Jens Axboe
2021-07-16 12:00 Jens Axboe
2021-07-08 12:00 Jens Axboe
2021-07-02 12:00 Jens Axboe
2021-06-30 12:00 Jens Axboe
2021-06-21 12:00 Jens Axboe
2021-06-18 12:00 Jens Axboe
2021-06-15 12:00 Jens Axboe
2021-06-11 12:00 Jens Axboe
2021-06-09 12:00 Jens Axboe
2021-06-04 12:00 Jens Axboe
2021-05-28 12:00 Jens Axboe
2021-05-27 12:00 Jens Axboe
2021-05-26 12:00 Jens Axboe
2021-05-19 12:00 Jens Axboe
2021-05-15 12:00 Jens Axboe
2021-05-12 12:00 Jens Axboe
2021-05-11 12:00 Jens Axboe
2021-05-09 12:00 Jens Axboe
2021-05-07 12:00 Jens Axboe
2021-04-28 12:00 Jens Axboe
2021-04-26 12:00 Jens Axboe
2021-04-24 12:00 Jens Axboe
2021-04-23 12:00 Jens Axboe
2021-04-17 12:00 Jens Axboe
2021-04-16 12:00 Jens Axboe
2021-04-14 12:00 Jens Axboe
2021-04-13 12:00 Jens Axboe
2021-04-11 12:00 Jens Axboe
2021-03-31 12:00 Jens Axboe
2021-03-19 12:00 Jens Axboe
2021-03-18 12:00 Jens Axboe
2021-03-12 13:00 Jens Axboe
2021-03-11 13:00 Jens Axboe
2021-03-10 13:00 Jens Axboe
2021-03-09 13:00 Jens Axboe
2021-03-07 13:00 Jens Axboe
2021-02-22 13:00 Jens Axboe
2021-02-17 13:00 Jens Axboe
2021-02-15 13:00 Jens Axboe
2021-02-11 13:00 Jens Axboe
2021-01-30 13:00 Jens Axboe
2021-01-28 13:00 Jens Axboe
2021-01-27 13:00 Jens Axboe
2021-01-26 13:00 Jens Axboe
2021-01-24 13:00 Jens Axboe
2021-01-17 13:00 Jens Axboe
2021-01-16 13:00 Jens Axboe
2021-01-13 13:00 Jens Axboe
2021-01-10 13:00 Jens Axboe
2021-01-08 13:00 Jens Axboe
2021-01-07 13:00 Jens Axboe
2021-01-06 13:00 Jens Axboe
2020-12-30 13:00 Jens Axboe
2020-12-25 13:00 Jens Axboe
2020-12-18 13:00 Jens Axboe
2020-12-16 13:00 Jens Axboe
2020-12-08 13:00 Jens Axboe
2020-12-06 13:00 Jens Axboe
2020-12-05 13:00 Jens Axboe
2020-12-04 13:00 Jens Axboe
2020-11-28 13:00 Jens Axboe
2020-11-26 13:00 Jens Axboe
2020-11-23 13:00 Jens Axboe
2020-11-14 13:00 Jens Axboe
2020-11-13 13:00 Jens Axboe
2020-11-10 13:00 Jens Axboe
2020-11-06 13:00 Jens Axboe
2020-11-12 20:51 ` Rebecca Cran
2020-11-05 13:00 Jens Axboe
2020-11-02 13:00 Jens Axboe
2020-10-31 12:00 Jens Axboe
2020-10-29 12:00 Jens Axboe
2020-10-15 12:00 Jens Axboe
2020-10-14 12:00 Jens Axboe
2020-10-11 12:00 Jens Axboe
2020-10-10 12:00 Jens Axboe
2020-09-15 12:00 Jens Axboe
2020-09-12 12:00 Jens Axboe
2020-09-10 12:00 Jens Axboe
2020-09-09 12:00 Jens Axboe
2020-09-08 12:00 Jens Axboe
2020-09-07 12:00 Jens Axboe
2020-09-06 12:00 Jens Axboe
2020-09-04 12:00 Jens Axboe
2020-09-02 12:00 Jens Axboe
2020-09-01 12:00 Jens Axboe
2020-08-30 12:00 Jens Axboe
2020-08-29 12:00 Jens Axboe
2020-08-28 12:00 Jens Axboe
2020-08-23 12:00 Jens Axboe
2020-08-22 12:00 Jens Axboe
2020-08-20 12:00 Jens Axboe
2020-08-19 12:00 Jens Axboe
2020-08-18 12:00 Jens Axboe
2020-08-17 12:00 Jens Axboe
2020-08-15 12:00 Jens Axboe
2020-08-14 12:00 Jens Axboe
2020-08-13 12:00 Jens Axboe
2020-08-12 12:00 Jens Axboe
2020-08-11 12:00 Jens Axboe
2020-08-08 12:00 Jens Axboe
2020-08-02 12:00 Jens Axboe
2020-07-28 12:00 Jens Axboe
2020-07-27 12:00 Jens Axboe
2020-07-26 12:00 Jens Axboe
2020-07-25 12:00 Jens Axboe
2020-07-22 12:00 Jens Axboe
2020-07-21 12:00 Jens Axboe
2020-07-19 12:00 Jens Axboe
2020-07-18 12:00 Jens Axboe
2020-07-15 12:00 Jens Axboe
2020-07-14 12:00 Jens Axboe
2020-07-09 12:00 Jens Axboe
2020-07-05 12:00 Jens Axboe
2020-07-04 12:00 Jens Axboe
2020-07-03 12:00 Jens Axboe
2020-06-29 12:00 Jens Axboe
2020-06-25 12:00 Jens Axboe
2020-06-24 12:00 Jens Axboe
2020-06-22 12:00 Jens Axboe
2020-06-13 12:00 Jens Axboe
2020-06-10 12:00 Jens Axboe
2020-06-08 12:00 Jens Axboe
2020-06-06 12:00 Jens Axboe
2020-06-04 12:00 Jens Axboe
2020-06-03 12:00 Jens Axboe
2020-05-30 12:00 Jens Axboe
2020-05-29 12:00 Jens Axboe
2020-05-26 12:00 Jens Axboe
2020-05-25 12:00 Jens Axboe
2020-05-24 12:00 Jens Axboe
2020-05-22 12:00 Jens Axboe
2020-05-21 12:00 Jens Axboe
2020-05-20 12:00 Jens Axboe
2020-05-19 12:00 Jens Axboe
2020-05-15 12:00 Jens Axboe
2020-05-14 12:00 Jens Axboe
2020-05-12 12:00 Jens Axboe
2020-04-30 12:00 Jens Axboe
2020-04-22 12:00 Jens Axboe
2020-04-21 12:00 Jens Axboe
2020-04-18 12:00 Jens Axboe
2020-04-17 12:00 Jens Axboe
2020-04-16 12:00 Jens Axboe
2020-04-14 12:00 Jens Axboe
2020-04-09 12:00 Jens Axboe
2020-04-08 12:00 Jens Axboe
2020-04-07 12:00 Jens Axboe
2020-04-03 12:00 Jens Axboe
2020-04-01 12:00 Jens Axboe
2020-03-27 12:00 Jens Axboe
2020-03-18 12:00 Jens Axboe
2020-03-17 12:00 Jens Axboe
2020-03-16 12:00 Jens Axboe
2020-03-13 12:00 Jens Axboe
2020-03-04 13:00 Jens Axboe
2020-03-03 13:00 Jens Axboe
2020-03-02 13:00 Jens Axboe
2020-02-27 13:00 Jens Axboe
2020-02-25 13:00 Jens Axboe
2020-02-07 13:00 Jens Axboe
2020-02-06 13:00 Jens Axboe
2020-01-29 13:00 Jens Axboe
2020-01-24 13:00 Jens Axboe
2020-01-23 13:00 Jens Axboe
2020-01-19 13:00 Jens Axboe
2020-01-17 13:00 Jens Axboe
2020-01-15 13:00 Jens Axboe
2020-01-14 13:00 Jens Axboe
2020-01-10 13:00 Jens Axboe
2020-01-07 13:00 Jens Axboe
2020-01-06 13:00 Jens Axboe
2020-01-05 13:00 Jens Axboe
2020-01-04 13:00 Jens Axboe
2019-12-26 13:00 Jens Axboe
2019-12-24 13:00 Jens Axboe
2019-12-22 13:00 Jens Axboe
2019-12-19 13:00 Jens Axboe
2019-12-17 13:00 Jens Axboe
2019-12-12 13:00 Jens Axboe
2019-12-07 13:00 Jens Axboe
2019-11-28 13:00 Jens Axboe
2019-11-27 13:00 Jens Axboe
2019-11-26 13:00 Jens Axboe
2019-11-15 13:00 Jens Axboe
2019-11-07 15:25 Jens Axboe
2019-11-07 13:00 Jens Axboe
2019-11-06 13:00 Jens Axboe
2019-11-04 13:00 Jens Axboe
2019-11-03 13:00 Jens Axboe
2019-10-30 12:00 Jens Axboe
2019-10-25 12:00 Jens Axboe
2019-10-22 12:00 Jens Axboe
2019-10-16 12:00 Jens Axboe
2019-10-15 12:00 Jens Axboe
2019-10-14 12:00 Jens Axboe
2019-10-09 12:00 Jens Axboe
2019-10-08 12:00 Jens Axboe
2019-10-07 12:00 Jens Axboe
2019-10-03 12:00 Jens Axboe
2019-10-02 12:00 Jens Axboe
2019-09-28 12:00 Jens Axboe
2019-09-26 12:00 Jens Axboe
2019-09-25 12:00 Jens Axboe
2019-09-24 12:00 Jens Axboe
2019-09-20 12:00 Jens Axboe
2019-09-14 12:00 Jens Axboe
2019-09-13 12:00 Jens Axboe
2019-09-06 12:00 Jens Axboe
2019-09-04 12:00 Jens Axboe
2019-08-30 12:00 Jens Axboe
2019-08-29 12:00 Jens Axboe
2019-08-16 12:00 Jens Axboe
2019-08-15 12:00 Jens Axboe
2019-08-15 14:27 ` Rebecca Cran
2019-08-15 14:28 ` Jens Axboe
2019-08-15 15:05 ` Rebecca Cran
2019-08-15 15:17 ` Jens Axboe
2019-08-15 15:35 ` Rebecca Cran
2019-08-09 12:00 Jens Axboe
2019-08-06 12:00 Jens Axboe
2019-08-04 12:00 Jens Axboe
2019-08-03 12:00 Jens Axboe
2019-08-01 12:00 Jens Axboe
2019-07-27 12:00 Jens Axboe
2019-07-13 12:00 Jens Axboe
2019-07-10 12:00 Jens Axboe
2019-07-02 12:00 Jens Axboe
2019-06-01 12:00 Jens Axboe
2019-05-24 12:00 Jens Axboe
2019-05-23 12:00 Jens Axboe
2019-05-21 12:00 Jens Axboe
2019-05-17 12:00 Jens Axboe
2019-05-10 12:00 Jens Axboe
2019-05-09 12:00 Jens Axboe
2019-05-09 12:47 ` Erwan Velu
2019-05-09 14:07 ` Jens Axboe
2019-05-09 15:47 ` Elliott, Robert (Servers)
2019-05-09 15:52 ` Sebastien Boisvert
2019-05-09 16:12 ` Elliott, Robert (Servers)
2019-05-09 15:57 ` Jens Axboe
2019-05-07 12:00 Jens Axboe
2019-04-26 12:00 Jens Axboe
2019-04-23 12:00 Jens Axboe
2019-04-20 12:00 Jens Axboe
2019-04-19 12:00 Jens Axboe
2019-04-18 12:00 Jens Axboe
2019-04-02 12:00 Jens Axboe
2019-03-26 12:00 Jens Axboe
2019-03-22 12:00 Jens Axboe
2019-03-12 12:00 Jens Axboe
2019-03-09 13:00 Jens Axboe
2019-03-08 13:00 Jens Axboe
2019-03-07 13:00 Jens Axboe
2019-03-01 13:00 Jens Axboe
2019-02-25 13:00 Jens Axboe
2019-02-24 13:00 Jens Axboe
2019-02-22 13:00 Jens Axboe
2019-02-12 13:00 Jens Axboe
2019-02-11 13:00 Jens Axboe
2019-02-09 13:00 Jens Axboe
2019-02-08 13:00 Jens Axboe
2019-02-05 13:00 Jens Axboe
2019-02-01 13:00 Jens Axboe
2019-01-30 13:00 Jens Axboe
2019-01-29 13:00 Jens Axboe
2019-01-25 13:00 Jens Axboe
2019-01-24 13:00 Jens Axboe
2019-01-17 13:00 Jens Axboe
2019-01-16 13:00 Jens Axboe
2019-01-15 13:00 Jens Axboe
2019-01-14 13:00 Jens Axboe
2019-01-13 13:00 Jens Axboe
2019-01-12 13:00 Jens Axboe
2019-01-11 13:00 Jens Axboe
2019-01-10 13:00 Jens Axboe
2019-01-09 13:00 Jens Axboe
2019-01-08 13:00 Jens Axboe
2019-01-06 13:00 Jens Axboe
2019-01-05 13:00 Jens Axboe
2018-12-31 13:00 Jens Axboe
2018-12-22 13:00 Jens Axboe
2018-12-20 13:00 Jens Axboe
2018-12-15 13:00 Jens Axboe
2018-12-14 13:00 Jens Axboe
2018-12-13 13:00 Jens Axboe
2018-12-11 13:00 Jens Axboe
2018-12-05 13:00 Jens Axboe
2018-12-02 13:00 Jens Axboe
2018-12-01 13:00 Jens Axboe
2018-11-30 13:00 Jens Axboe
2018-11-28 13:00 Jens Axboe
2018-11-27 13:00 Jens Axboe
2018-11-26 13:00 Jens Axboe
2018-11-25 13:00 Jens Axboe
2018-11-22 13:00 Jens Axboe
2018-11-21 13:00 Jens Axboe
2018-11-20 13:00 Jens Axboe
2018-11-16 13:00 Jens Axboe
2018-11-07 13:00 Jens Axboe
2018-11-03 12:00 Jens Axboe
2018-10-27 12:00 Jens Axboe
2018-10-24 12:00 Jens Axboe
2018-10-20 12:00 Jens Axboe
2018-10-19 12:00 Jens Axboe
2018-10-16 12:00 Jens Axboe
2018-10-09 12:00 Jens Axboe
2018-10-06 12:00 Jens Axboe
2018-10-05 12:00 Jens Axboe
2018-10-04 12:00 Jens Axboe
2018-10-02 12:00 Jens Axboe
2018-10-01 12:00 Jens Axboe
2018-09-30 12:00 Jens Axboe
2018-09-28 12:00 Jens Axboe
2018-09-27 12:00 Jens Axboe
2018-09-26 12:00 Jens Axboe
2018-09-23 12:00 Jens Axboe
2018-09-22 12:00 Jens Axboe
2018-09-21 12:00 Jens Axboe
2018-09-20 12:00 Jens Axboe
2018-09-18 12:00 Jens Axboe
2018-09-17 12:00 Jens Axboe
2018-09-13 12:00 Jens Axboe
2018-09-12 12:00 Jens Axboe
2018-09-11 12:00 Jens Axboe
2018-09-10 12:00 Jens Axboe
2018-09-09 12:00 Jens Axboe
2018-09-08 12:00 Jens Axboe
2018-09-07 12:00 Jens Axboe
2018-09-06 12:00 Jens Axboe
2018-09-04 12:00 Jens Axboe
2018-09-01 12:00 Jens Axboe
2018-08-31 12:00 Jens Axboe
2018-08-26 12:00 Jens Axboe
2018-08-25 12:00 Jens Axboe
2018-08-24 12:00 Jens Axboe
2018-08-23 12:00 Jens Axboe
2018-08-22 12:00 Jens Axboe
2018-08-21 12:00 Jens Axboe
2018-08-18 12:00 Jens Axboe
2018-08-17 12:00 Jens Axboe
2018-08-16 12:00 Jens Axboe
2018-08-15 12:00 Jens Axboe
2018-08-14 12:00 Jens Axboe
2018-08-13 12:00 Jens Axboe
2018-08-11 12:00 Jens Axboe
2018-08-10 12:00 Jens Axboe
2018-08-08 12:00 Jens Axboe
2018-08-06 12:00 Jens Axboe
2018-08-04 12:00 Jens Axboe
2018-08-03 12:00 Jens Axboe
2018-07-31 12:00 Jens Axboe
2018-07-27 12:00 Jens Axboe
2018-07-26 12:00 Jens Axboe
2018-07-25 12:00 Jens Axboe
2018-07-24 12:00 Jens Axboe
2018-07-13 12:00 Jens Axboe
2018-07-12 12:00 Jens Axboe
2018-07-11 12:00 Jens Axboe
2018-07-05 12:00 Jens Axboe
2018-06-30 12:00 Jens Axboe
2018-06-22 12:00 Jens Axboe
2018-06-19 12:00 Jens Axboe
2018-06-16 12:00 Jens Axboe
2018-06-13 12:00 Jens Axboe
2018-06-12 12:00 Jens Axboe
2018-06-09 12:00 Jens Axboe
2018-06-08 12:00 Jens Axboe
2018-06-06 12:00 Jens Axboe
2018-06-05 12:00 Jens Axboe
2018-06-02 12:00 Jens Axboe
2018-06-01 12:00 Jens Axboe
2018-05-26 12:00 Jens Axboe
2018-05-19 12:00 Jens Axboe
2018-05-17 12:00 Jens Axboe
2018-05-15 12:00 Jens Axboe
2018-04-27 12:00 Jens Axboe
2018-04-25 12:00 Jens Axboe
2018-04-21 12:00 Jens Axboe
2018-04-19 12:00 Jens Axboe
2018-04-18 12:00 Jens Axboe
2018-04-17 12:00 Jens Axboe
2018-04-15 12:00 Jens Axboe
2018-04-14 12:00 Jens Axboe
2018-04-11 12:00 Jens Axboe
2018-04-10 12:00 Jens Axboe
2018-04-09 12:00 Jens Axboe
2018-04-07 12:00 Jens Axboe
2018-04-05 12:00 Jens Axboe
2018-04-04 12:00 Jens Axboe
2018-03-31 12:00 Jens Axboe
2018-03-30 12:00 Jens Axboe
2018-03-24 12:00 Jens Axboe
2018-03-23 12:00 Jens Axboe
2018-03-22 12:00 Jens Axboe
2018-03-21 12:00 Jens Axboe
2018-03-20 12:00 Jens Axboe
2018-03-14 12:00 Jens Axboe
2018-03-13 12:00 Jens Axboe
2018-03-10 13:00 Jens Axboe
2018-03-08 13:00 Jens Axboe
2018-03-07 13:00 Jens Axboe
2018-03-06 13:00 Jens Axboe
2018-03-03 13:00 Jens Axboe
2018-03-02 13:00 Jens Axboe
2018-03-01 13:00 Jens Axboe
2018-02-28 13:00 Jens Axboe
2018-02-27 13:00 Jens Axboe
2018-02-21 13:00 Jens Axboe
2018-02-15 13:00 Jens Axboe
2018-02-13 13:00 Jens Axboe
2018-02-11 13:00 Jens Axboe
2018-02-09 13:00 Jens Axboe
2018-02-08 13:00 Jens Axboe
2018-01-26 13:00 Jens Axboe
2018-01-25 13:00 Jens Axboe
2018-01-17 13:00 Jens Axboe
2018-01-13 13:00 Jens Axboe
2018-01-11 13:00 Jens Axboe
2018-01-07 13:00 Jens Axboe
2018-01-06 13:00 Jens Axboe
2018-01-03 13:00 Jens Axboe
2017-12-30 13:00 Jens Axboe
2017-12-29 13:00 Jens Axboe
2017-12-28 13:00 Jens Axboe
2017-12-22 13:00 Jens Axboe
2017-12-20 13:00 Jens Axboe
2017-12-16 13:00 Jens Axboe
2017-12-15 13:00 Jens Axboe
2017-12-14 13:00 Jens Axboe
2017-12-09 13:00 Jens Axboe
2017-12-08 13:00 Jens Axboe
2017-12-07 13:00 Jens Axboe
2017-12-04 13:00 Jens Axboe
2017-12-03 13:00 Jens Axboe
2017-12-02 13:00 Jens Axboe
2017-12-01 13:00 Jens Axboe
2017-11-30 13:00 Jens Axboe
2017-11-29 13:00 Jens Axboe
2017-11-24 13:00 Jens Axboe
2017-11-23 13:00 Jens Axboe
2017-11-18 13:00 Jens Axboe
2017-11-20 15:00 ` Elliott, Robert (Persistent Memory)
2017-11-17 13:00 Jens Axboe
2017-11-16 13:00 Jens Axboe
2017-11-07 13:00 Jens Axboe
2017-11-04 12:00 Jens Axboe
2017-11-03 12:00 Jens Axboe
2017-11-02 12:00 Jens Axboe
2017-11-01 12:00 Jens Axboe
2017-10-31 12:00 Jens Axboe
2017-10-27 12:00 Jens Axboe
2017-10-26 12:00 Jens Axboe
2017-10-21 12:00 Jens Axboe
2017-10-18 12:00 Jens Axboe
2017-10-13 12:00 Jens Axboe
2017-10-12 12:00 Jens Axboe
2017-10-11 12:00 Jens Axboe
2017-10-10 12:00 Jens Axboe
2017-10-07 12:00 Jens Axboe
2017-10-04 12:00 Jens Axboe
2017-09-29 12:00 Jens Axboe
2017-09-28 12:00 Jens Axboe
2017-09-27 12:00 Jens Axboe
2017-09-21 12:00 Jens Axboe
2017-09-19 12:00 Jens Axboe
2017-09-15 12:00 Jens Axboe
2017-09-14 12:00 Jens Axboe
2017-09-13 12:00 Jens Axboe
2017-09-12 12:00 Jens Axboe
2017-09-06 12:00 Jens Axboe
2017-09-03 12:00 Jens Axboe
2017-09-02 12:00 Jens Axboe
2017-09-01 12:00 Jens Axboe
2017-08-31 12:00 Jens Axboe
2017-08-30 12:00 Jens Axboe
2017-08-29 12:00 Jens Axboe
2017-08-28 12:00 Jens Axboe
2017-08-24 12:00 Jens Axboe
2017-08-23 12:00 Jens Axboe
2017-08-18 12:00 Jens Axboe
2017-08-17 12:00 Jens Axboe
2017-08-15 12:00 Jens Axboe
2017-08-10 12:00 Jens Axboe
2017-08-09 12:00 Jens Axboe
2017-08-08 12:00 Jens Axboe
2017-08-02 12:00 Jens Axboe
2017-08-01 12:00 Jens Axboe
2017-07-28 12:00 Jens Axboe
2017-07-26 12:00 Jens Axboe
2017-07-21 12:00 Jens Axboe
2017-07-17 12:00 Jens Axboe
2017-07-15 12:00 Jens Axboe
2017-07-14 12:00 Jens Axboe
2017-07-13 12:00 Jens Axboe
2017-07-11 12:00 Jens Axboe
2017-07-08 12:00 Jens Axboe
2017-07-07 12:00 Jens Axboe
2017-07-05 12:00 Jens Axboe
2017-07-04 12:00 Jens Axboe
2017-07-03 12:00 Jens Axboe
2017-06-29 12:00 Jens Axboe
2017-06-28 12:00 Jens Axboe
2017-06-27 12:00 Jens Axboe
2017-06-26 12:00 Jens Axboe
2017-06-24 12:00 Jens Axboe
2017-06-23 12:00 Jens Axboe
2017-06-20 12:00 Jens Axboe
2017-06-19 12:00 Jens Axboe
2017-06-16 12:00 Jens Axboe
2017-06-15 12:00 Jens Axboe
2017-06-13 12:00 Jens Axboe
2017-06-09 12:00 Jens Axboe
2017-06-08 12:00 Jens Axboe
2017-06-06 12:00 Jens Axboe
2013-03-20 5:00 Jens Axboe
2017-11-05 13:00 ` Jens Axboe
2017-11-06 13:00 ` Jens Axboe
2017-11-08 13:00 ` Jens Axboe
2018-01-24 13:00 ` Jens Axboe
2018-01-25 13:00 ` Jens Axboe
2018-04-10 12:00 ` Jens Axboe
2018-05-03 12:00 ` Jens Axboe
2018-05-17 12:00 ` Jens Axboe
2018-08-31 12:00 ` Jens Axboe
2018-09-01 12:00 ` Jens Axboe
2019-05-22 12:00 ` Jens Axboe
2019-09-17 12:00 ` Jens Axboe
2019-09-25 12:00 ` Jens Axboe
2020-01-17 13:00 ` Jens Axboe
2020-03-21 12:00 ` Jens Axboe
2020-05-08 12:00 ` Jens Axboe
2020-05-21 12:00 ` Jens Axboe
2021-02-20 13:00 ` Jens Axboe
2021-04-20 12:00 ` Jens Axboe
2021-06-15 11:59 ` Jens Axboe
2021-06-29 12:00 ` Jens Axboe
2021-10-22 12:00 ` Jens Axboe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200205130002.3E8491BC017F@kernel.dk \
--to=axboe@kernel.dk \
--cc=fio@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.