#!/bin/sh
GVF=FIO-VERSION-FILE
-DEF_VER=fio-3.0
+DEF_VER=fio-3.1
LF='
'
.. option:: --max-jobs=nr
Set the maximum number of threads/processes to support to `nr`.
+ NOTE: On Linux, it may be necessary to increase the shared-memory
+ limit ('/proc/sys/kernel/shmmax') if fio runs into errors while
+ creating jobs.
.. option:: --server=args
absolute or relative. See :file:`engines/skeleton_external.c` for
details of writing an external I/O engine.
+ **filecreate**
+ Simply create the files and do no IO to them. You still need to
+ set `filesize` so that all the accounting still occurs, but no
+ actual IO will be done other than creating the file.
I/O engine specific parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eta.c verify.c memory.c io_u.c parse.c mutex.c options.c \
smalloc.c filehash.c profile.c debug.c engines/cpu.c \
engines/mmap.c engines/sync.c engines/null.c engines/net.c \
- engines/ftruncate.c \
+ engines/ftruncate.c engines/filecreate.c \
server.c client.c iolog.c backend.c libfio.c flow.c cconv.c \
gettime-thread.c helpers.c json.c idletime.c td_error.c \
profiles/tiobench.c profiles/act.c io_u_queue.c filelock.c \
if (ddir_rw(io_u->ddir))
td->ts.short_io_u[io_u->ddir]++;
- f = io_u->file;
if (io_u->offset == f->real_file_size)
goto sync_done;
struct sk_out *sk_out = fd->sk_out;
uint64_t bytes_done[DDIR_RWDIR_CNT];
int deadlock_loop_cnt;
- int clear_state;
+ bool clear_state, did_some_io;
int ret;
sk_out_assign(sk_out);
}
memset(bytes_done, 0, sizeof(bytes_done));
- clear_state = 0;
+ clear_state = false;
+ did_some_io = false;
while (keep_running(td)) {
uint64_t verify_bytes;
if (td->runstate >= TD_EXITED)
break;
- clear_state = 1;
+ clear_state = true;
/*
* Make sure we've successfully updated the rusage stats
td_ioengine_flagged(td, FIO_UNIDIR))
continue;
+ if (ddir_rw_sum(bytes_done))
+ did_some_io = true;
+
clear_io_state(td, 0);
fio_gettime(&td->start, NULL);
* (Are we not missing other flags that can be ignored ?)
*/
if ((td->o.size || td->o.io_size) && !ddir_rw_sum(bytes_done) &&
+ !did_some_io && !td->o.create_only &&
!(td_ioengine_flagged(td, FIO_NOIO) ||
td_ioengine_flagged(td, FIO_DISKLESSIO)))
log_err("%s: No I/O performed by %s, "
for_each_td(td, i) {
int flags = 0;
- /*
- * ->io_ops is NULL for a thread that has closed its
- * io engine
- */
- if (td->io_ops && !strcmp(td->io_ops->name, "cpuio"))
+ if (!strcmp(td->o.ioengine, "cpuio"))
cputhreads++;
else
realthreads++;
fio_terminate_threads(TERMINATE_ALL);
fio_abort = 1;
nr_started--;
+ free(fd);
break;
}
dprint(FD_MUTEX, "done waiting on startup_mutex\n");
handle_trace(td, &t, ios, rw_bs);
} while (1);
- for (i = 0; i < td->files_index; i++) {
- f = td->files[i];
+ for_each_file(td, f, i)
trace_add_open_close_event(td, f->fileno, FIO_LOG_CLOSE_FILE);
- }
fifo_free(fifo);
close(fd);
static int fio_client_handle_iolog(struct fio_client *client,
struct fio_net_cmd *cmd)
{
- struct cmd_iolog_pdu *pdu;
+ struct cmd_iolog_pdu *pdu = NULL;
bool store_direct;
- char *log_pathname;
+ char *log_pathname = NULL;
+ int ret = 0;
pdu = convert_iolog(cmd, &store_direct);
if (!pdu) {
log_err("fio: failed converting IO log\n");
- return 1;
+ ret = 1;
+ goto out;
}
/* allocate buffer big enough for next sprintf() call */
strlen(client->hostname));
if (!log_pathname) {
log_err("fio: memory allocation of unique pathname failed\n");
- return -1;
+ ret = -1;
+ goto out;
}
/* generate a unique pathname for the log file using hostname */
sprintf(log_pathname, "%s.%s", pdu->name, client->hostname);
if (fd < 0) {
log_err("fio: open log %s: %s\n",
log_pathname, strerror(errno));
- return 1;
+ ret = 1;
+ goto out;
}
sz = cmd->pdu_len - sizeof(*pdu);
if (ret != sz) {
log_err("fio: short write on compressed log\n");
- return 1;
+ ret = 1;
+ goto out;
}
- return 0;
+ ret = 0;
} else {
FILE *f;
f = fopen((const char *) log_pathname, "w");
if (!f) {
log_err("fio: fopen log %s : %s\n",
log_pathname, strerror(errno));
- return 1;
+ ret = 1;
+ goto out;
}
if (pdu->log_type == IO_LOG_TYPE_HIST) {
pdu->nr_samples * sizeof(struct io_sample));
}
fclose(f);
- return 0;
+ ret = 0;
}
+
+out:
+ if (pdu && pdu != (void *) cmd->payload)
+ free(pdu);
+
+ if (log_pathname)
+ free(log_pathname);
+
+ return ret;
}
static void handle_probe(struct fio_client *client, struct fio_net_cmd *cmd)
static int handle_cmd_timeout(struct fio_client *client,
struct fio_net_cmd_reply *reply)
{
+ uint16_t reply_opcode = reply->opcode;
+
flist_del(&reply->list);
free(reply);
- if (reply->opcode != FIO_NET_CMD_SEND_ETA)
+ if (reply_opcode != FIO_NET_CMD_SEND_ETA)
return 1;
log_info("client <%s>: timeout on SEND_ETA\n", client->hostname);
--- /dev/null
+/*
+ * filecreate engine
+ *
+ * IO engine that doesn't do any IO, just creates files and tracks the latency
+ * of the file creation.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "../fio.h"
+#include "../filehash.h"
+
+struct fc_data {
+ enum fio_ddir stat_ddir;
+};
+
+static int open_file(struct thread_data *td, struct fio_file *f)
+{
+ struct timespec start;
+ int do_lat = !td->o.disable_lat;
+
+ dprint(FD_FILE, "fd open %s\n", f->file_name);
+
+ if (f->filetype != FIO_TYPE_FILE) {
+ log_err("fio: only files are supported fallocate \n");
+ return 1;
+ }
+ if (!strcmp(f->file_name, "-")) {
+ log_err("fio: can't read/write to stdin/out\n");
+ return 1;
+ }
+
+ if (do_lat)
+ fio_gettime(&start, NULL);
+
+ f->fd = open(f->file_name, O_CREAT|O_RDWR, 0600);
+
+ if (f->fd == -1) {
+ char buf[FIO_VERROR_SIZE];
+ int e = errno;
+
+ snprintf(buf, sizeof(buf), "open(%s)", f->file_name);
+ td_verror(td, e, buf);
+ return 1;
+ }
+
+ if (do_lat) {
+ struct fc_data *data = td->io_ops_data;
+ uint64_t nsec;
+
+ nsec = ntime_since_now(&start);
+ add_clat_sample(td, data->stat_ddir, nsec, 0, 0);
+ }
+
+ return 0;
+}
+
+static int queue_io(struct thread_data *td, struct io_u fio_unused *io_u)
+{
+ return FIO_Q_COMPLETED;
+}
+
+/*
+ * Ensure that we at least have a block size worth of IO to do for each
+ * file. If the job file has td->o.size < nr_files * block_size, then
+ * fio won't do anything.
+ */
+static int get_file_size(struct thread_data *td, struct fio_file *f)
+{
+ f->real_file_size = td_min_bs(td);
+ return 0;
+}
+
+static int init(struct thread_data *td)
+{
+ struct fc_data *data;
+
+ data = calloc(1, sizeof(*data));
+
+ if (td_read(td))
+ data->stat_ddir = DDIR_READ;
+ else if (td_write(td))
+ data->stat_ddir = DDIR_WRITE;
+
+ td->io_ops_data = data;
+ return 0;
+}
+
+static void cleanup(struct thread_data *td)
+{
+ struct fc_data *data = td->io_ops_data;
+
+ free(data);
+}
+
+static struct ioengine_ops ioengine = {
+ .name = "filecreate",
+ .version = FIO_IOOPS_VERSION,
+ .init = init,
+ .cleanup = cleanup,
+ .queue = queue_io,
+ .get_file_size = get_file_size,
+ .open_file = open_file,
+ .close_file = generic_close_file,
+ .flags = FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
+ FIO_NOSTATS | FIO_NOFILEHASH,
+};
+
+static void fio_init fio_filecreate_register(void)
+{
+ register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_filecreate_unregister(void)
+{
+ unregister_ioengine(&ioengine);
+}
*
* It also can act as external C++ engine - compiled with:
*
- * g++ -O2 -g -shared -rdynamic -fPIC -o null.so null.c -DFIO_EXTERNAL_ENGINE
+ * g++ -O2 -g -shared -rdynamic -fPIC -o cpp_null null.c -DFIO_EXTERNAL_ENGINE
+ *
+ * to test it execute:
+ *
+ * LD_LIBRARY_PATH=./engines ./fio examples/cpp_null.fio
*
*/
#include <stdio.h>
int events;
};
-static struct io_u *fio_null_event(struct thread_data *td, int event)
+static struct io_u *null_event(struct null_data *nd, int event)
{
- struct null_data *nd = (struct null_data *) td->io_ops_data;
-
return nd->io_us[event];
}
-static int fio_null_getevents(struct thread_data *td, unsigned int min_events,
- unsigned int fio_unused max,
- const struct timespec fio_unused *t)
+static int null_getevents(struct null_data *nd, unsigned int min_events,
+ unsigned int fio_unused max,
+ const struct timespec fio_unused *t)
{
- struct null_data *nd = (struct null_data *) td->io_ops_data;
int ret = 0;
-
+
if (min_events) {
ret = nd->events;
nd->events = 0;
return ret;
}
-static int fio_null_commit(struct thread_data *td)
+static int null_commit(struct thread_data *td, struct null_data *nd)
{
- struct null_data *nd = (struct null_data *) td->io_ops_data;
-
if (!nd->events) {
#ifndef FIO_EXTERNAL_ENGINE
io_u_mark_submit(td, nd->queued);
return 0;
}
-static int fio_null_queue(struct thread_data *td, struct io_u *io_u)
+static int null_queue(struct thread_data *td, struct null_data *nd,
+ struct io_u *io_u)
{
- struct null_data *nd = (struct null_data *) td->io_ops_data;
-
fio_ro_check(td, io_u);
if (td->io_ops->flags & FIO_SYNCIO)
return FIO_Q_QUEUED;
}
-static int fio_null_open(struct thread_data fio_unused *td,
- struct fio_file fio_unused *f)
+static int null_open(struct null_data fio_unused *nd,
+ struct fio_file fio_unused *f)
{
return 0;
}
-static void fio_null_cleanup(struct thread_data *td)
+static void null_cleanup(struct null_data *nd)
{
- struct null_data *nd = (struct null_data *) td->io_ops_data;
-
if (nd) {
free(nd->io_us);
free(nd);
}
}
-static int fio_null_init(struct thread_data *td)
+static int null_init(struct thread_data *td, struct null_data **nd_ptr)
{
- struct null_data *nd = (struct null_data *) malloc(sizeof(*nd));
+ struct null_data *nd = (struct null_data *) malloc(sizeof(**nd_ptr));
memset(nd, 0, sizeof(*nd));
} else
td->io_ops->flags |= FIO_SYNCIO;
- td->io_ops_data = nd;
+ *nd_ptr = nd;
return 0;
}
#ifndef __cplusplus
+
+static struct io_u *fio_null_event(struct thread_data *td, int event)
+{
+ return null_event((struct null_data *)td->io_ops_data, event);
+}
+
+static int fio_null_getevents(struct thread_data *td, unsigned int min_events,
+ unsigned int max, const struct timespec *t)
+{
+ struct null_data *nd = (struct null_data *)td->io_ops_data;
+ return null_getevents(nd, min_events, max, t);
+}
+
+static int fio_null_commit(struct thread_data *td)
+{
+ return null_commit(td, (struct null_data *)td->io_ops_data);
+}
+
+static int fio_null_queue(struct thread_data *td, struct io_u *io_u)
+{
+ return null_queue(td, (struct null_data *)td->io_ops_data, io_u);
+}
+
+static int fio_null_open(struct thread_data *td, struct fio_file *f)
+{
+ return null_open((struct null_data *)td->io_ops_data, f);
+}
+
+static void fio_null_cleanup(struct thread_data *td)
+{
+ null_cleanup((struct null_data *)td->io_ops_data);
+}
+
+static int fio_null_init(struct thread_data *td)
+{
+ return null_init(td, (struct null_data **)&td->io_ops_data);
+}
+
static struct ioengine_ops ioengine = {
.name = "null",
.version = FIO_IOOPS_VERSION,
#else
#ifdef FIO_EXTERNAL_ENGINE
+
+struct NullData {
+ NullData(struct thread_data *td)
+ {
+ null_init(td, &impl_);
+ }
+
+ ~NullData()
+ {
+ null_cleanup(impl_);
+ }
+
+ static NullData *get(struct thread_data *td)
+ {
+ return reinterpret_cast<NullData *>(td->io_ops_data);
+ }
+
+ io_u *fio_null_event(struct thread_data *, int event)
+ {
+ return null_event(impl_, event);
+ }
+
+ int fio_null_getevents(struct thread_data *, unsigned int min_events,
+ unsigned int max, const struct timespec *t)
+ {
+ return null_getevents(impl_, min_events, max, t);
+ }
+
+ int fio_null_commit(struct thread_data *td)
+ {
+ return null_commit(td, impl_);
+ }
+
+ int fio_null_queue(struct thread_data *td, struct io_u *io_u)
+ {
+ return null_queue(td, impl_, io_u);
+ }
+
+ int fio_null_open(struct thread_data *, struct fio_file *f)
+ {
+ return null_open(impl_, f);
+ }
+
+ struct null_data *impl_;
+};
+
extern "C" {
+
+static struct io_u *fio_null_event(struct thread_data *td, int event)
+{
+ return NullData::get(td)->fio_null_event(td, event);
+}
+
+static int fio_null_getevents(struct thread_data *td, unsigned int min_events,
+ unsigned int max, const struct timespec *t)
+{
+ return NullData::get(td)->fio_null_getevents(td, min_events, max, t);
+}
+
+static int fio_null_commit(struct thread_data *td)
+{
+ return NullData::get(td)->fio_null_commit(td);
+}
+
+static int fio_null_queue(struct thread_data *td, struct io_u *io_u)
+{
+ return NullData::get(td)->fio_null_queue(td, io_u);
+}
+
+static int fio_null_open(struct thread_data *td, struct fio_file *f)
+{
+ return NullData::get(td)->fio_null_open(td, f);
+}
+
+static int fio_null_init(struct thread_data *td)
+{
+ td->io_ops_data = new NullData(td);
+ return 0;
+}
+
+static void fio_null_cleanup(struct thread_data *td)
+{
+ delete NullData::get(td);
+}
+
static struct ioengine_ops ioengine;
void get_ioengine(struct ioengine_ops **ioengine_ptr)
{
--- /dev/null
+[global]
+bs=4k
+gtod_reduce=1
+
+[null]
+ioengine=cpp_null
+size=100g
+rw=randread
+norandommap
+time_based=0
--- /dev/null
+# Example filecreate job
+#
+# create_on_open is needed so that the open happens during the run and not the
+# setup.
+#
+# openfiles needs to be set so that you do not exceed the maximum allowed open
+# files.
+#
+# filesize needs to be set to a non zero value so fio will actually run, but the
+# IO will not really be done and the write latency numbers will only reflect the
+# open times.
+[global]
+create_on_open=1
+nrfiles=31250
+ioengine=filecreate
+fallocate=none
+filesize=4k
+openfiles=1
+
+[t0]
+[t1]
+[t2]
+[t3]
+[t4]
+[t5]
+[t6]
+[t7]
+[t8]
+[t9]
+[t10]
+[t11]
+[t12]
+[t13]
+[t14]
+[t15]
+++ /dev/null
-simple-expression-parser
-========================
-
-A simple expression parser for arithmetic expressions made with bison + flex
-
-To use, see the example test-expression-parser.c
-
extern uint64_t get_start_offset(struct thread_data *, struct fio_file *);
extern int __must_check setup_files(struct thread_data *);
extern int __must_check file_invalidate_cache(struct thread_data *, struct fio_file *);
+#ifdef __cplusplus
+extern "C" {
+#endif
extern int __must_check generic_open_file(struct thread_data *, struct fio_file *);
extern int __must_check generic_close_file(struct thread_data *, struct fio_file *);
extern int __must_check generic_get_file_size(struct thread_data *, struct fio_file *);
+#ifdef __cplusplus
+}
+#endif
extern int __must_check file_lookup_open(struct fio_file *f, int flags);
extern int __must_check pre_read_files(struct thread_data *);
extern unsigned long long get_rand_file_size(struct thread_data *td);
{
struct fio_file *f;
unsigned int i;
+ bool use_free = td_ioengine_flagged(td, FIO_NOFILEHASH);
dprint(FD_FILE, "close files\n");
td_io_unlink_file(td, f);
}
- sfree(f->file_name);
+ if (use_free)
+ free(f->file_name);
+ else
+ sfree(f->file_name);
f->file_name = NULL;
if (fio_file_axmap(f)) {
axmap_free(f->io_axmap);
f->io_axmap = NULL;
}
- sfree(f);
+ if (use_free)
+ free(f);
+ else
+ sfree(f);
}
td->o.filename = NULL;
{
struct fio_file *f;
- f = smalloc(sizeof(*f));
+ if (td_ioengine_flagged(td, FIO_NOFILEHASH))
+ f = calloc(1, sizeof(*f));
+ else
+ f = smalloc(sizeof(*f));
if (!f) {
assert(0);
return NULL;
if (td->io_ops && td_ioengine_flagged(td, FIO_DISKLESSIO))
f->real_file_size = -1ULL;
- f->file_name = smalloc_strdup(file_name);
+ if (td_ioengine_flagged(td, FIO_NOFILEHASH))
+ f->file_name = strdup(file_name);
+ else
+ f->file_name = smalloc_strdup(file_name);
if (!f->file_name)
assert(0);
if (f->filetype == FIO_TYPE_FILE)
td->nr_normal_files++;
- set_already_allocated(file_name);
+ if (td->o.numjobs > 1)
+ set_already_allocated(file_name);
if (inc)
td->o.nr_files++;
__f = alloc_new_file(td);
if (f->file_name) {
- __f->file_name = smalloc_strdup(f->file_name);
+ if (td_ioengine_flagged(td, FIO_NOFILEHASH))
+ __f->file_name = strdup(f->file_name);
+ else
+ __f->file_name = smalloc_strdup(f->file_name);
if (!__f->file_name)
assert(0);
.TP
.BI \-\-max\-jobs \fR=\fPnr
Set the maximum number of threads/processes to support to \fInr\fR.
+NOTE: On Linux, it may be necessary to increase the shared-memory limit
+(`/proc/sys/kernel/shmmax') if fio runs into errors while creating jobs.
.TP
.BI \-\-server \fR=\fPargs
Start a backend server, with \fIargs\fR specifying what to listen to.
ioengine `foo.o' in `/tmp'. The path can be either
absolute or relative. See `engines/skeleton_external.c' in the fio source for
details of writing an external I/O engine.
+.TP
+.B filecreate
+Create empty files only. \fBfilesize\fR still needs to be specified so that fio
+will run and grab latency results, but no IO will actually be done on the files.
.SS "I/O engine specific parameters"
In addition, there are some parameters which are only valid when a specific
\fBioengine\fR is in use. These are used identically to normal parameters,
struct thread_data;
extern uint64_t ntime_since(const struct timespec *, const struct timespec *);
+extern uint64_t ntime_since_now(const struct timespec *);
extern uint64_t utime_since(const struct timespec *, const struct timespec *);
extern uint64_t utime_since_now(const struct timespec *);
extern uint64_t mtime_since(const struct timespec *, const struct timespec *);
return nsec + (sec * 1000000000LL);
}
+uint64_t ntime_since_now(const struct timespec *s)
+{
+ struct timespec now;
+
+ fio_gettime(&now, NULL);
+ return ntime_since(s, &now);
+}
+
uint64_t utime_since(const struct timespec *s, const struct timespec *e)
{
int64_t sec, usec;
static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir)
{
enum fio_ddir odir = ddir ^ 1;
- long usec;
+ uint64_t usec;
uint64_t now;
assert(ddir_rw(ddir));
if (td->parent)
td = td->parent;
- if (!td->o.stats)
+ if (!td->o.stats || td_ioengine_flagged(td, FIO_NOSTATS))
return;
if (no_reduce)
/*
* linux libaio has alias names, so convert to what we want
*/
- if (!strncmp(engine, "linuxaio", 8) || !strncmp(engine, "aio", 3))
+ if (!strncmp(engine, "linuxaio", 8) || !strncmp(engine, "aio", 3)) {
+ dprint(FD_IO, "converting ioengine name: %s -> libaio\n", name);
strcpy(engine, "libaio");
+ }
dprint(FD_IO, "load ioengine %s\n", engine);
return find_ioengine(engine);
{
assert(!fio_file_open(f));
assert(f->fd == -1);
+ assert(td->io_ops->open_file);
if (td->io_ops->open_file(td, f)) {
if (td->error == EINVAL && td->o.odirect)
FIO_MEMALIGN = 1 << 9, /* engine wants aligned memory */
FIO_BIT_BASED = 1 << 10, /* engine uses a bit base (e.g. uses Kbit as opposed to KB) */
FIO_FAKEIO = 1 << 11, /* engine pretends to do IO */
+ FIO_NOSTATS = 1 << 12, /* don't do IO stats */
+ FIO_NOFILEHASH = 1 << 13, /* doesn't hash the files for lookup later. */
};
/*
#ifndef FIO_TYPES_H
#define FIO_TYPES_H
-#ifndef CONFIG_HAVE_BOOL
+#if !defined(CONFIG_HAVE_BOOL) && !defined(__cplusplus)
typedef int bool;
#ifndef false
#define false 0
.help = "DAX Device based IO engine",
},
#endif
+ {
+ .ival = "filecreate",
+ .help = "File creation engine",
+ },
{ .ival = "external",
.help = "Load external engine (append name)",
.cb = str_ioengine_external_cb,
<Product Id="*"
Codepage="1252" Language="1033"
Manufacturer="fio" Name="fio"
- UpgradeCode="2338A332-5511-43CF-B9BD-5C60496CCFCC" Version="3.0">
+ UpgradeCode="2338A332-5511-43CF-B9BD-5C60496CCFCC" Version="3.1">
<Package
Description="Flexible IO Tester"
InstallerVersion="301" Keywords="Installer,MSI,Database"
}
}
- err = 0;
normsg("PEB %d passed torture test, do not mark it a bad", eb);
out:
unsigned int len;
int i;
const char *ddirname[] = {"read", "write", "trim"};
- struct json_object *dir_object, *tmp_object, *percentile_object, *clat_bins_object;
+ struct json_object *dir_object, *tmp_object, *percentile_object, *clat_bins_object = NULL;
char buf[120];
double p_of_agg = 100.0;
if (output_format & FIO_OUTPUT_JSON_PLUS) {
clat_bins_object = json_create_object();
- json_object_add_value_object(tmp_object, "bins", clat_bins_object);
+ if (ts->clat_percentiles)
+ json_object_add_value_object(tmp_object, "bins", clat_bins_object);
+
for(i = 0; i < FIO_IO_U_PLAT_NR; i++) {
if (ts->io_u_plat[ddir][i]) {
snprintf(buf, sizeof(buf), "%llu", plat_idx_to_val(i));
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 (output_format & FIO_OUTPUT_JSON_PLUS && ts->lat_percentiles)
+ json_object_add_value_object(tmp_object, "bins", clat_bins_object);
+
if (ovals)
free(ovals);
#define FIO_IO_U_LAT_U_NR 10
#define FIO_IO_U_LAT_M_NR 12
+/*
+ * Constants for clat percentiles
+ */
+#define FIO_IO_U_PLAT_BITS 6
+#define FIO_IO_U_PLAT_VAL (1 << FIO_IO_U_PLAT_BITS)
+#define FIO_IO_U_PLAT_GROUP_NR 29
+#define FIO_IO_U_PLAT_NR (FIO_IO_U_PLAT_GROUP_NR * FIO_IO_U_PLAT_VAL)
+#define FIO_IO_U_LIST_MAX_LEN 20 /* The size of the default and user-specified
+ list of percentiles */
+
/*
* Aggregate clat samples to report percentile(s) of them.
*
*
* FIO_IO_U_PLAT_GROUP_NR and FIO_IO_U_PLAT_BITS determine the maximum
* range being tracked for latency samples. The maximum value tracked
- * accurately will be 2^(GROUP_NR + PLAT_BITS -1) microseconds.
+ * accurately will be 2^(GROUP_NR + PLAT_BITS - 1) nanoseconds.
*
* FIO_IO_U_PLAT_GROUP_NR and FIO_IO_U_PLAT_BITS determine the memory
* requirement of storing those aggregate counts. The memory used will
* 3 8 2 [256,511] 64
* 4 9 3 [512,1023] 64
* ... ... ... [...,...] ...
- * 18 23 17 [8838608,+inf]** 64
+ * 28 33 27 [8589934592,+inf]** 64
*
* * Special cases: when n < (M-1) or when n == (M-1), in both cases,
* the value cannot be rounded off. Use all bits of the sample as
* index.
*
- * ** If a sample's MSB is greater than 23, it will be counted as 23.
+ * ** If a sample's MSB is greater than 33, it will be counted as 33.
*/
-#define FIO_IO_U_PLAT_BITS 6
-#define FIO_IO_U_PLAT_VAL (1 << FIO_IO_U_PLAT_BITS)
-#define FIO_IO_U_PLAT_GROUP_NR 29
-#define FIO_IO_U_PLAT_NR (FIO_IO_U_PLAT_GROUP_NR * FIO_IO_U_PLAT_VAL)
-#define FIO_IO_U_LIST_MAX_LEN 20 /* The size of the default and user-specified
- list of percentiles */
-
/*
* Trim cycle count measurements
*/
}
printf("Passes=%lu, Fail=%lu\n", pass, fail);
-
+ free(buckets);
return 0;
}
prev_ddir = None
for ddir in ddir_set:
+ if 'bins' in jsondata['jobs'][jobnum][ddir]['clat_ns']:
+ bins_loc = 'clat_ns'
+ elif 'bins' in jsondata['jobs'][jobnum][ddir]['lat_ns']:
+ bins_loc = 'lat_ns'
+ else:
+ raise RuntimeError("Latency bins not found. "
+ "Are you sure you are using json+ output?")
+
bins[ddir] = [[int(key), value] for key, value in
- jsondata['jobs'][jobnum][ddir]['clat_ns']
+ jsondata['jobs'][jobnum][ddir][bins_loc]
['bins'].iteritems()]
bins[ddir] = sorted(bins[ddir], key=lambda bin: bin[0])
outfile = stub + '_job' + str(jobnum) + ext
with open(outfile, 'w') as output:
- output.write("clat_nsec, ")
+ output.write("{0}ec, ".format(bins_loc))
ddir_list = list(ddir_set)
for ddir in ddir_list:
output.write("{0}_count, {0}_cumulative, {0}_percentile, ".