#define td_var_offset(var) ((size_t) &((struct thread_data *)0)->var)
-static int str_rw_cb(void *, const char *);
static int str_ioengine_cb(void *, const char *);
static int str_mem_cb(void *, const char *);
-static int str_verify_cb(void *, const char *);
static int str_lockmem_cb(void *, unsigned long *);
#ifdef FIO_HAVE_IOPRIO
static int str_prio_cb(void *, unsigned int *);
#endif
static int str_exitall_cb(void);
static int str_cpumask_cb(void *, unsigned int *);
-static int str_file_service_cb(void *, const char *);
#define __stringify_1(x) #x
#define __stringify(x) __stringify_1(x)
{
.name = "rw",
.type = FIO_OPT_STR,
- .cb = str_rw_cb,
+ .off1 = td_var_offset(td_ddir),
.help = "IO direction",
.def = "read",
- .posval = { "read", "write", "randwrite", "randread", "rw",
- "randrw", },
+ .posval = {
+ { .ival = "read", .oval = TD_DDIR_READ },
+ { .ival = "write", .oval = TD_DDIR_WRITE },
+ { .ival = "randread", .oval = TD_DDIR_RANDREAD },
+ { .ival = "randwrite", .oval = TD_DDIR_RANDWRITE },
+ { .ival = "rw", .oval = TD_DDIR_RW },
+ { .ival = "randrw", .oval = TD_DDIR_RANDRW },
+ },
},
{
.name = "ioengine",
.cb = str_ioengine_cb,
.help = "IO engine to use",
.def = "sync",
- .posval = { "sync", "libaio", "posixaio", "mmap", "splice",
- "sg", "null", "net", "syslet-rw" },
+ .posval = {
+ { .ival = "sync", },
+#ifdef FIO_HAVE_LIBAIO
+ { .ival = "libaio", },
+#endif
+#ifdef FIO_HAVE_POSIXAIO
+ { .ival = "posixaio", },
+#endif
+ { .ival = "mmap", },
+#ifdef FIO_HAVE_SPLICE
+ { .ival = "splice", },
+#endif
+#ifdef FIO_HAVE_SGIO
+ { .ival = "sg", },
+#endif
+ { .ival = "null", }, { .ival = "net", },
+#ifdef FIO_HAVE_SYSLET
+ { .ival = "syslet-rw", },
+#endif
+ { .ival = "external", },
+ },
},
{
.name = "iodepth",
.help = "Amount of IO buffers to keep in flight",
.def = "1",
},
+ {
+ .name = "iodepth_batch",
+ .type = FIO_OPT_INT,
+ .off1 = td_var_offset(iodepth_batch),
+ .help = "Number of IO to submit in one go",
+ },
{
.name = "iodepth_low",
.type = FIO_OPT_INT,
{
.name = "file_service_type",
.type = FIO_OPT_STR,
- .cb = str_file_service_cb,
+ .off1 = td_var_offset(file_service_type),
.help = "How to select which file to service next",
.def = "roundrobin",
- .posval = { "random", "roundrobin" },
+ .posval = {
+ { .ival = "random", .oval = FIO_FSERVICE_RANDOM },
+ { .ival = "roundrobin", .oval = FIO_FSERVICE_RR },
+ },
},
{
.name = "fsync",
.name = "mem",
.type = FIO_OPT_STR,
.cb = str_mem_cb,
+ .off1 = td_var_offset(mem_type),
.help = "Backing type for IO buffers",
.def = "malloc",
- .posval = { "malloc", "shm", "shmhuge", "mmap", "mmaphuge", },
+ .posval = {
+ { .ival = "malloc", .oval = MEM_MALLOC },
+ { .ival = "shm", .oval = MEM_SHM },
+#ifdef FIO_HAVE_HUGETLB
+ { .ival = "shmhuge", .oval = MEM_SHMHUGE },
+#endif
+ { .ival = "mmap", .oval = MEM_MMAP },
+#ifdef FIO_HAVE_HUGETLB
+ { .ival = "mmaphuge", .oval = MEM_MMAPHUGE },
+#endif
+ },
},
{
.name = "verify",
.type = FIO_OPT_STR,
- .cb = str_verify_cb,
+ .off1 = td_var_offset(verify),
.help = "Verify sum function",
.def = "0",
- .posval = { "crc32", "md5", },
+ .posval = {
+ { .ival = "0", .oval = VERIFY_NONE },
+ { .ival = "crc32", .oval = VERIFY_CRC32 },
+ { .ival = "md5", .oval = VERIFY_MD5 },
+ },
},
{
.name = "write_iolog",
},
{
.name = "cmdhelp",
- .has_arg = required_argument,
+ .has_arg = optional_argument,
.val = 'c',
},
{
static int def_timeout = 0;
-static char fio_version_string[] = "fio 1.11";
+static char fio_version_string[] = "fio 1.12";
static char **ini_file;
static int max_jobs = MAX_JOBS;
static int write_lat_log = 0;
int write_bw_log = 0;
+FILE *get_f_out()
+{
+ return f_out;
+}
+
+FILE *get_f_err()
+{
+ return f_err;
+}
+
/*
* Return a free job structure.
*/
/*
* The low water mark cannot be bigger than the iodepth
*/
- if (td->iodepth_low > td->iodepth || !td->iodepth_low)
- td->iodepth_low = td->iodepth;
+ if (td->iodepth_low > td->iodepth || !td->iodepth_low) {
+ /*
+ * syslet work around - if the workload is sequential,
+ * we want to let the queue drain all the way down to
+ * avoid seeking between async threads
+ */
+ if (!strcmp(td->io_ops->name, "syslet-rw") && !td_random(td))
+ td->iodepth_low = 1;
+ else
+ td->iodepth_low = td->iodepth;
+ }
+
+ /*
+ * If batch number isn't set, default to the same as iodepth
+ */
+ if (td->iodepth_batch > td->iodepth || !td->iodepth_batch)
+ td->iodepth_batch = td->iodepth;
}
/*
return 1;
}
-static int str_rw_cb(void *data, const char *mem)
-{
- struct thread_data *td = data;
-
- if (!strncmp(mem, "read", 4) || !strncmp(mem, "0", 1)) {
- td->td_ddir = TD_DDIR_READ;
- return 0;
- } else if (!strncmp(mem, "randread", 8)) {
- td->td_ddir = TD_DDIR_READ | TD_DDIR_RAND;
- return 0;
- } else if (!strncmp(mem, "write", 5) || !strncmp(mem, "1", 1)) {
- td->td_ddir = TD_DDIR_WRITE;
- return 0;
- } else if (!strncmp(mem, "randwrite", 9)) {
- td->td_ddir = TD_DDIR_WRITE | TD_DDIR_RAND;
- return 0;
- } else if (!strncmp(mem, "rw", 2)) {
- td->td_ddir = TD_DDIR_RW;
- return 0;
- } else if (!strncmp(mem, "randrw", 6)) {
- td->td_ddir = TD_DDIR_RW | TD_DDIR_RAND;
- return 0;
- }
-
- log_err("fio: data direction: read, write, randread, randwrite, rw, randrw\n");
- return 1;
-}
-
-static int str_verify_cb(void *data, const char *mem)
-{
- struct thread_data *td = data;
-
- if (!strncmp(mem, "0", 1)) {
- td->verify = VERIFY_NONE;
- return 0;
- } else if (!strncmp(mem, "md5", 3) || !strncmp(mem, "1", 1)) {
- td->verify = VERIFY_MD5;
- return 0;
- } else if (!strncmp(mem, "crc32", 5)) {
- td->verify = VERIFY_CRC32;
- return 0;
- }
-
- log_err("fio: verify types: md5, crc32\n");
- return 1;
-}
-
/*
* Check if mmap/mmaphuge has a :/foo/bar/file at the end. If so, return that.
*/
{
struct thread_data *td = data;
- if (!strncmp(mem, "malloc", 6)) {
- td->mem_type = MEM_MALLOC;
- return 0;
- } else if (!strncmp(mem, "mmaphuge", 8)) {
-#ifdef FIO_HAVE_HUGETLB
- /*
- * mmaphuge must be appended with the actual file
- */
+ if (td->mem_type == MEM_MMAPHUGE || td->mem_type == MEM_MMAP) {
td->mmapfile = get_mmap_file(mem);
- if (!td->mmapfile) {
+ if (td->mem_type == MEM_MMAPHUGE && !td->mmapfile) {
log_err("fio: mmaphuge:/path/to/file\n");
return 1;
}
-
- td->mem_type = MEM_MMAPHUGE;
- return 0;
-#else
- log_err("fio: mmaphuge not available\n");
- return 1;
-#endif
- } else if (!strncmp(mem, "mmap", 4)) {
- /*
- * Check if the user wants file backed memory. It's ok
- * if there's no file given, we'll just use anon mamp then.
- */
- td->mmapfile = get_mmap_file(mem);
- td->mem_type = MEM_MMAP;
- return 0;
- } else if (!strncmp(mem, "shmhuge", 7)) {
-#ifdef FIO_HAVE_HUGETLB
- td->mem_type = MEM_SHMHUGE;
- return 0;
-#else
- log_err("fio: shmhuge not available\n");
- return 1;
-#endif
- } else if (!strncmp(mem, "shm", 3)) {
- td->mem_type = MEM_SHM;
- return 0;
}
- log_err("fio: mem type: malloc, shm, shmhuge, mmap, mmaphuge\n");
- return 1;
+ return 0;
+}
+
+/* External engines are specified by "external:name.o") */
+static const char *get_engine_name(const char *str)
+{
+ char *p = strstr(str, ":");
+
+ if (!p)
+ return str;
+
+ p++;
+ strip_blank_front(&p);
+ strip_blank_end(p);
+ return p;
}
static int str_ioengine_cb(void *data, const char *str)
{
struct thread_data *td = data;
+ const char *name = get_engine_name(str);
- td->io_ops = load_ioengine(td, str);
+ td->io_ops = load_ioengine(td, name);
if (td->io_ops)
return 0;
- log_err("fio: ioengine= libaio, posixaio, sync, syslet-rw, mmap, sgio, splice, cpu, null\n");
- log_err("fio: or specify path to dynamic ioengine module\n");
return 1;
}
return 0;
}
-static int str_file_service_cb(void *data, const char *str)
-{
- struct thread_data *td = data;
-
- if (!strncmp(str, "random", 6)) {
- td->file_service_type = FIO_FSERVICE_RANDOM;
- return 0;
- } else if (!strncmp(str, "roundrobin", 10)) {
- td->file_service_type = FIO_FSERVICE_RR;
- return 0;
- }
-
- log_err("fio: file_service= random, roundrobin\n");
- return 1;
-}
-
/*
* This is our [ini] type file parser.
*/
static int parse_cmd_line(int argc, char *argv[])
{
struct thread_data *td = NULL;
- int c, ini_idx = 0, lidx, ret;
+ int c, ini_idx = 0, lidx, ret, dont_add_job = 0;
while ((c = getopt_long(argc, argv, "", long_options, &lidx)) != -1) {
switch (c) {
}
ret = parse_cmd_option(opt, val, options, td);
- if (ret) {
- log_err("fio: job dropped\n");
- put_job(td);
- td = NULL;
- }
+ if (ret)
+ dont_add_job = 1;
break;
}
default:
}
if (td) {
- ret = add_job(td, td->name ?: "fio", 0);
- if (ret)
+ if (dont_add_job)
put_job(td);
+ else {
+ ret = add_job(td, td->name ?: "fio", 0);
+ if (ret)
+ put_job(td);
+ }
}
while (optind < argc) {