Merge branch 'master' into gfio
authorJens Axboe <axboe@kernel.dk>
Mon, 7 May 2012 07:54:41 +0000 (09:54 +0200)
committerJens Axboe <axboe@kernel.dk>
Mon, 7 May 2012 07:54:41 +0000 (09:54 +0200)
Conflicts:
Makefile
backend.c
client.c
fio.h
os/windows/install.wxs
server.c
server.h

Signed-off-by: Jens Axboe <axboe@kernel.dk>
1  2 
HOWTO
Makefile
backend.c
cconv.c
eta.c
filesetup.c
fio.1
options.c
stat.c
thread_options.h

diff --combined HOWTO
index eeaddbac69520f3997bebd5cc8c8f79149e23626,025443be406669ece150b28858c67ed9cb2f56d9..8a4e2bde1b7b8a1bd85d1a56dba41eb7d23e1d26
--- 1/HOWTO
--- 2/HOWTO
+++ b/HOWTO
@@@ -320,7 -320,7 +320,7 @@@ rw=str             Type of io pattern. Accepted va
                one by appending a ':<nr>' to the end of the string given.
                For a random read, it would look like 'rw=randread:8' for
                passing in an offset modifier with a value of 8. If the
-               postfix is used with a sequential IO pattern, then the value
+               suffix is used with a sequential IO pattern, then the value
                specified will be added to the generated offset for each IO.
                For instance, using rw=write:4k will skip 4k for every
                write. It turns sequential IO into sequential IO with holes.
@@@ -893,6 -893,11 +893,11 @@@ create_fsync=bool        fsync the data file a
  create_on_open=bool   Don't pre-setup the files for IO, just create open()
                        when it's time to do IO to that file.
  
+ create_only=bool      If true, fio will only run the setup phase of the job.
+                       If files need to be laid out or updated on disk, only
+                       that will be done. The actual job contents are not
+                       executed.
  pre_read=bool If this is given, files will be pre-read into memory before
                starting the given IO operation. This will also clear
                the 'invalidate' flag, since it is pointless to pre-read
@@@ -1107,8 -1112,8 +1112,8 @@@ write_bw_log=str If given, write a band
                file. Can be used to store data of the bandwidth of the
                jobs in their lifetime. The included fio_generate_plots
                script uses gnuplot to turn these text files into nice
-               graphs. See write_log_log for behaviour of given
-               filename. For this option, the postfix is _bw.log.
+               graphs. See write_lat_log for behaviour of given
+               filename. For this option, the suffix is _bw.log.
  
  write_lat_log=str Same as write_bw_log, except that this option stores io
                submission, completion, and total latencies instead. If no
@@@ -1150,6 -1155,12 +1155,6 @@@ exec_postrun=str After the job complete
  ioscheduler=str       Attempt to switch the device hosting the file to the specified
                io scheduler before running.
  
 -cpuload=int   If the job is a CPU cycle eater, attempt to use the specified
 -              percentage of CPU cycles.
 -
 -cpuchunks=int If the job is a CPU cycle eater, split the load into
 -              cycles of the given time. In microseconds.
 -
  disk_util=bool        Generate disk utilization statistics, if the platform
                supports it. Defaults to on.
  
@@@ -1280,11 -1291,6 +1285,11 @@@ that defines them is selected
                enabled when polling for a minimum of 0 events (eg when
                iodepth_batch_complete=0).
  
 +[cpu] cpuload=int Attempt to use the specified percentage of CPU cycles.
 +
 +[cpu] cpuchunks=int Split the load into cycles of the given time. In
 +              microseconds.
 +
  [netsplice] hostname=str
  [net] hostname=str The host name or IP address to use for TCP or UDP based IO.
                If the job is a TCP listener or UDP reader, the hostname is not
@@@ -1447,6 -1453,9 +1452,9 @@@ io_queue=       Total time spent in the disk 
  util=         The disk utilization. A value of 100% means we kept the disk
                busy constantly, 50% would be a disk idling half of the time.
  
+ It is also possible to get fio to dump the current output while it is
+ running, without terminating the job. To do that, send fio the USR1 signal.
  
  7.0 Terse output
  ----------------
diff --combined Makefile
index fe22741e940e51628934e2f3900e66dd9356fbda,f72bf8e2562f6d941bc18a5984c0bab21a2c6f6e..5165cd9ff38dd1cbb0e59b933c1dfafc124fd0b8
+++ b/Makefile
@@@ -4,21 -4,17 +4,21 @@@ CPPFLAGS= -D_GNU_SOURCE -D_LARGEFILE_SO
        $(DEBUGFLAGS)
  OPTFLAGS= -O3 -fno-omit-frame-pointer -g $(EXTFLAGS)
  CFLAGS        = -std=gnu99 -Wwrite-strings -Wall $(OPTFLAGS)
 -LIBS  = -lm $(EXTLIBS)
 +LIBS  = -lm -lz $(EXTLIBS)
  PROGS = fio
  SCRIPTS = fio_generate_plots
  UNAME  := $(shell uname)
  
 -SOURCE := gettime.c fio.c ioengines.c init.c stat.c log.c time.c filesetup.c \
 +GTK_CFLAGS = `pkg-config --cflags gtk+-2.0 gthread-2.0`
 +GTK_LDFLAGS = `pkg-config --libs gtk+-2.0 gthread-2.0`
 +
 +SOURCE := gettime.c ioengines.c init.c stat.c log.c time.c filesetup.c \
                eta.c verify.c memory.c io_u.c parse.c mutex.c options.c \
 -              rbtree.c smalloc.c filehash.c profile.c debug.c lib/rand.c \
 +              lib/rbtree.c smalloc.c filehash.c profile.c debug.c lib/rand.c \
                lib/num2str.c lib/ieee754.c $(wildcard crc/*.c) engines/cpu.c \
                engines/mmap.c engines/sync.c engines/null.c engines/net.c \
 -              memalign.c server.c client.c iolog.c backend.c libfio.c flow.c
 +              memalign.c server.c client.c iolog.c backend.c libfio.c flow.c \
 +              cconv.c lib/prio_tree.c
  
  ifeq ($(UNAME), Linux)
    SOURCE += diskutil.c fifo.c blktrace.c helpers.c cgroup.c trim.c \
@@@ -68,16 -64,13 +68,16 @@@ ifneq (,$(findstring CYGWIN,$(UNAME))
  endif
  
  OBJS = $(SOURCE:.c=.o)
 +FIO_OBJS = $(OBJS) fio.o
 +GFIO_OBJS = $(OBJS) gfio.o graph.o tickmarks.o ghelpers.o goptions.o gerror.o \
 +                      gclient.o gcompat.o cairo_text_helpers.o printing.o
  
  T_SMALLOC_OBJS = t/stest.o
 -T_SMALLOC_OBJS += mutex.o smalloc.o t/log.o
 +T_SMALLOC_OBJS += mutex.o smalloc.o t/log.o gettime.o time.o
  T_SMALLOC_PROGS = t/stest
  
  T_IEEE_OBJS = t/ieee754.o
 -T_IEEE_OBJS += ieee754.o
 +T_IEEE_OBJS += lib/ieee754.o
  T_IEEE_PROGS = t/ieee754
  
  T_OBJS = $(T_SMALLOC_OBJS)
@@@ -106,7 -99,7 +106,7 @@@ all: .depend $(PROGS) $(SCRIPTS) FORC
  .PHONY: FORCE cscope
  
  FIO-VERSION-FILE: FORCE
-       @$(SHELL_PATH) ./FIO-VERSION-GEN
+       @$(SHELL) ./FIO-VERSION-GEN
  -include FIO-VERSION-FILE
  
  CFLAGS += -DFIO_VERSION='"$(FIO_VERSION)"'
  init.o: FIO-VERSION-FILE
        $(QUIET_CC)$(CC) -o init.o -c $(CFLAGS) $(CPPFLAGS) -c init.c
  
 +gcompat.o: gcompat.c gcompat.h
 +      $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c gcompat.c
 +
 +goptions.o: goptions.c goptions.h
 +      $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c goptions.c
 +
 +ghelpers.o: ghelpers.c ghelpers.h
 +      $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c ghelpers.c
 +
 +gerror.o: gerror.c gerror.h
 +      $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c gerror.c
 +
 +gclient.o: gclient.c gclient.h
 +      $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c gclient.c
 +
 +gfio.o: gfio.c ghelpers.c
 +      $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c gfio.c
 +
 +graph.o: graph.c graph.h
 +      $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c graph.c
 +
 +cairo_text_helpers.o: cairo_text_helpers.c cairo_text_helpers.h
 +      $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c cairo_text_helpers.c
 +
 +printing.o: printing.c printing.h
 +      $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c printing.c
 +
  t/stest: $(T_SMALLOC_OBJS)
        $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_SMALLOC_OBJS) $(LIBS) $(LDFLAGS)
  
  t/ieee754: $(T_IEEE_OBJS)
        $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_IEEE_OBJS) $(LIBS) $(LDFLAGS)
  
 -fio: $(OBJS)
 -      $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(LDFLAGS)
 +fio: $(FIO_OBJS)
 +      $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(FIO_OBJS) $(LIBS) $(LDFLAGS)
 +
 +gfio: $(GFIO_OBJS)
 +      $(QUIET_CC)$(CC) $(LIBS) -o gfio $(GFIO_OBJS) $(LIBS) $(GTK_LDFLAGS)
  
  .depend: $(SOURCE)
        $(QUIET_DEP)$(CC) -MM $(CFLAGS) $(CPPFLAGS) $(SOURCE) 1> .depend
  $(PROGS): .depend
  
  clean: FORCE
-       -rm -f .depend $(GFIO_OBJS) $(FIO_OBJS) $(T_OBJS) $(PROGS) $(T_PROGS) core.* core gfio FIO-VERSION-FILE
 -      -rm -f .depend $(OBJS) $(T_OBJS) $(PROGS) $(T_PROGS) core.* core FIO-VERSION-FILE
++      -rm -f .depend $(GFIO_OBJS )$(OBJS) $(T_OBJS) $(PROGS) $(T_PROGS) core.* core gfio FIO-VERSION-FILE
  
  cscope:
        @cscope -b -R
@@@ -177,5 -140,3 +177,5 @@@ install: $(PROGS) $(SCRIPTS) FORC
  ifneq ($(wildcard .depend),)
  include .depend
  endif
 +
 +
diff --combined backend.c
index 3a471521d6931508335f9ede44b3ab5aae1598f1,e1dc0ac8b154a662866eea6ecc381921f5000cf0..38efc2307809266d234cfeb183e33bda94b5ea68
+++ b/backend.c
@@@ -56,13 -56,13 +56,13 @@@ static struct flist_head *cgroup_list
  static char *cgroup_mnt;
  static int exit_value;
  static volatile int fio_abort;
 +static unsigned int nr_process = 0;
 +static unsigned int nr_thread = 0;
  
  struct io_log *agg_io_log[2];
  
  int groupid = 0;
  unsigned int thread_number = 0;
 -unsigned int nr_process = 0;
 -unsigned int nr_thread = 0;
  int shm_id = 0;
  int temp_stall_ts;
  unsigned long done_secs = 0;
@@@ -345,8 -345,8 +345,8 @@@ static int break_on_this_error(struct t
                        return 1;
  
                if (td_non_fatal_error(err)) {
 -                      /*
 -                       * Continue with the I/Os in case of
 +                      /*
 +                       * Continue with the I/Os in case of
                         * a non fatal error.
                         */
                        update_error_count(td, err);
@@@ -968,12 -968,10 +968,12 @@@ static void *thread_main(void *data
  {
        unsigned long long elapsed;
        struct thread_data *td = data;
 +      struct thread_options *o = &td->o;
        pthread_condattr_t attr;
        int clear_state;
 +      int ret;
  
 -      if (!td->o.use_thread) {
 +      if (!o->use_thread) {
                setsid();
                td->pid = getpid();
        } else
  
        dprint(FD_PROCESS, "jobs pid=%d started\n", (int) td->pid);
  
 +      if (is_backend)
 +              fio_server_send_start(td);
 +
        INIT_FLIST_HEAD(&td->io_u_freelist);
        INIT_FLIST_HEAD(&td->io_u_busylist);
        INIT_FLIST_HEAD(&td->io_u_requeues);
         * eating a file descriptor
         */
        fio_mutex_remove(td->mutex);
 +      td->mutex = NULL;
  
        /*
         * A new gid requires privilege, so we need to do this before setting
         * the uid.
         */
 -      if (td->o.gid != -1U && setgid(td->o.gid)) {
 +      if (o->gid != -1U && setgid(o->gid)) {
                td_verror(td, errno, "setgid");
                goto err;
        }
 -      if (td->o.uid != -1U && setuid(td->o.uid)) {
 +      if (o->uid != -1U && setuid(o->uid)) {
                td_verror(td, errno, "setuid");
                goto err;
        }
         * If we have a gettimeofday() thread, make sure we exclude that
         * thread from this job
         */
 -      if (td->o.gtod_cpu)
 -              fio_cpu_clear(&td->o.cpumask, td->o.gtod_cpu);
 +      if (o->gtod_cpu)
 +              fio_cpu_clear(&o->cpumask, o->gtod_cpu);
  
        /*
         * Set affinity first, in case it has an impact on the memory
         * allocations.
         */
 -      if (td->o.cpumask_set && fio_setaffinity(td->pid, td->o.cpumask) == -1) {
 -              td_verror(td, errno, "cpu_set_affinity");
 -              goto err;
 +      if (o->cpumask_set) {
 +              ret = fio_setaffinity(td->pid, o->cpumask);
 +              if (ret == -1) {
 +                      td_verror(td, errno, "cpu_set_affinity");
 +                      goto err;
 +              }
        }
  
 +      if (fio_pin_memory(td))
 +              goto err;
 +
        /*
         * May alter parameters that init_io_u() will use, so we need to
         * do this first.
        if (init_io_u(td))
                goto err;
  
 -      if (td->o.verify_async && verify_async_init(td))
 +      if (o->verify_async && verify_async_init(td))
                goto err;
  
 -      if (td->ioprio_set) {
 -              if (ioprio_set(IOPRIO_WHO_PROCESS, 0, td->ioprio) == -1) {
 +      if (o->ioprio) {
 +              ret = ioprio_set(IOPRIO_WHO_PROCESS, 0, o->ioprio_class, o->ioprio);
 +              if (ret == -1) {
                        td_verror(td, errno, "ioprio_set");
                        goto err;
                }
        }
  
-       if (o->cgroup_weight && cgroup_setup(td, cgroup_list, &cgroup_mnt))
+       if (td->o.cgroup && cgroup_setup(td, cgroup_list, &cgroup_mnt))
                goto err;
  
        errno = 0;
 -      if (nice(td->o.nice) == -1 && errno != 0) {
 +      if (nice(o->nice) == -1 && errno != 0) {
                td_verror(td, errno, "nice");
                goto err;
        }
  
 -      if (td->o.ioscheduler && switch_ioscheduler(td))
 +      if (o->ioscheduler && switch_ioscheduler(td))
                goto err;
  
 -      if (!td->o.create_serialize && setup_files(td))
 +      if (!o->create_serialize && setup_files(td))
                goto err;
  
        if (td_io_init(td))
        if (init_random_map(td))
                goto err;
  
 -      if (td->o.exec_prerun) {
 -              if (exec_string(td->o.exec_prerun))
 -                      goto err;
 -      }
 +      if (o->exec_prerun && exec_string(o->exec_prerun))
 +              goto err;
  
 -      if (td->o.pre_read) {
 +      if (o->pre_read) {
                if (pre_read_files(td) < 0)
                        goto err;
        }
  
 +      fio_verify_init(td);
 +
        fio_gettime(&td->epoch, NULL);
        getrusage(RUSAGE_SELF, &td->ru_start);
  
                memcpy(&td->tv_cache, &td->start, sizeof(td->start));
  
                if (td->o.ratemin[0] || td->o.ratemin[1]) {
 -                      memcpy(&td->lastrate[0], &td->bw_sample_time,
 +                      memcpy(&td->lastrate[0], &td->bw_sample_time,
                                                sizeof(td->bw_sample_time));
 -                      memcpy(&td->lastrate[1], &td->bw_sample_time,
 +                      memcpy(&td->lastrate[1], &td->bw_sample_time,
                                                sizeof(td->bw_sample_time));
                }
  
        td->ts.io_bytes[0] = td->io_bytes[0];
        td->ts.io_bytes[1] = td->io_bytes[1];
  
 +      fio_unpin_memory(td);
 +
        fio_mutex_down(writeout_mutex);
        if (td->bw_log) {
                if (td->o.bw_log_file) {
@@@ -1220,8 -1205,8 +1220,8 @@@ err
        cleanup_io_u(td);
        cgroup_shutdown(td, &cgroup_mnt);
  
 -      if (td->o.cpumask_set) {
 -              int ret = fio_cpuset_exit(&td->o.cpumask);
 +      if (o->cpumask_set) {
 +              int ret = fio_cpuset_exit(&o->cpumask);
  
                td_verror(td, ret, "fio_cpuset_exit");
        }
@@@ -1375,19 -1360,14 +1375,19 @@@ static void run_threads(void
        unsigned long spent;
        unsigned int i, todo, nr_running, m_rate, t_rate, nr_started;
  
 -      if (fio_pin_memory())
 -              return;
 -
        if (fio_gtod_offload && fio_start_gtod_thread())
                return;
  
        set_sig_handlers();
  
 +      nr_thread = nr_process = 0;
 +      for_each_td(td, i) {
 +              if (td->o.use_thread)
 +                      nr_thread++;
 +              else
 +                      nr_process++;
 +      }
 +
        if (!terse_output) {
                log_info("Starting ");
                if (nr_thread)
  
                reap_threads(&nr_running, &t_rate, &m_rate);
  
 -              if (todo) {
 -                      if (is_backend)
 -                              fio_server_idle_loop();
 -                      else
 -                              usleep(100000);
 -              }
 +              if (todo)
 +                      usleep(100000);
        }
  
        while (nr_running) {
                reap_threads(&nr_running, &t_rate, &m_rate);
 -
 -              if (is_backend)
 -                      fio_server_idle_loop();
 -              else
 -                      usleep(10000);
 +              usleep(10000);
        }
  
        update_io_ticks();
 -      fio_unpin_memory();
  }
  
  static void *disk_thread_main(void *data)
@@@ -1653,8 -1642,8 +1653,8 @@@ int fio_backend(void
                return 0;
  
        if (write_bw_log) {
 -              setup_log(&agg_io_log[DDIR_READ], 0);
 -              setup_log(&agg_io_log[DDIR_WRITE], 0);
 +              setup_log(&agg_io_log[DDIR_READ], 0, IO_LOG_TYPE_BW);
 +              setup_log(&agg_io_log[DDIR_WRITE], 0, IO_LOG_TYPE_BW);
        }
  
        startup_mutex = fio_mutex_init(0);
diff --combined cconv.c
index ae34e5490672925bae4bfbdd07a13da9db4ecbd3,0000000000000000000000000000000000000000..2bfe6aa09d9585884f0766a6d4ff504580c24aac
mode 100644,000000..100644
--- /dev/null
+++ b/cconv.c
@@@ -1,400 -1,0 +1,402 @@@
 +#include <string.h>
 +
 +#include "thread_options.h"
 +
 +static void string_to_cpu(char **dst, const uint8_t *src)
 +{
 +      const char *__src = (const char *) src;
 +
 +      if (strlen(__src))
 +              *dst = strdup(__src);
 +}
 +
 +static void string_to_net(uint8_t *dst, const char *src)
 +{
 +      if (src)
 +              strcpy((char *) dst, src);
 +      else
 +              dst[0] = '\0';
 +}
 +
 +void convert_thread_options_to_cpu(struct thread_options *o,
 +                                 struct thread_options_pack *top)
 +{
 +      int i, j;
 +
 +      string_to_cpu(&o->description, top->description);
 +      string_to_cpu(&o->name, top->name);
 +      string_to_cpu(&o->directory, top->directory);
 +      string_to_cpu(&o->filename, top->filename);
 +      string_to_cpu(&o->opendir, top->opendir);
 +      string_to_cpu(&o->ioengine, top->ioengine);
 +      string_to_cpu(&o->mmapfile, top->mmapfile);
 +      string_to_cpu(&o->read_iolog_file, top->read_iolog_file);
 +      string_to_cpu(&o->write_iolog_file, top->write_iolog_file);
 +      string_to_cpu(&o->bw_log_file, top->bw_log_file);
 +      string_to_cpu(&o->lat_log_file, top->lat_log_file);
 +      string_to_cpu(&o->iops_log_file, top->iops_log_file);
 +      string_to_cpu(&o->replay_redirect, top->replay_redirect);
 +      string_to_cpu(&o->exec_prerun, top->exec_prerun);
 +      string_to_cpu(&o->exec_postrun, top->exec_postrun);
 +      string_to_cpu(&o->ioscheduler, top->ioscheduler);
 +      string_to_cpu(&o->profile, top->profile);
 +      string_to_cpu(&o->cgroup, top->cgroup);
 +
 +      o->td_ddir = le32_to_cpu(top->td_ddir);
 +      o->rw_seq = le32_to_cpu(top->rw_seq);
 +      o->kb_base = le32_to_cpu(top->kb_base);
 +      o->ddir_seq_nr = le32_to_cpu(top->ddir_seq_nr);
 +      o->ddir_seq_add = le64_to_cpu(top->ddir_seq_add);
 +      o->iodepth = le32_to_cpu(top->iodepth);
 +      o->iodepth_low = le32_to_cpu(top->iodepth_low);
 +      o->iodepth_batch = le32_to_cpu(top->iodepth_batch);
 +      o->iodepth_batch_complete = le32_to_cpu(top->iodepth_batch_complete);
 +      o->size = le64_to_cpu(top->size);
 +      o->size_percent = le32_to_cpu(top->size_percent);
 +      o->fill_device = le32_to_cpu(top->fill_device);
 +      o->file_size_low = le64_to_cpu(top->file_size_low);
 +      o->file_size_high = le64_to_cpu(top->file_size_high);
 +      o->start_offset = le64_to_cpu(top->start_offset);
 +
 +      for (i = 0; i < 2; i++) {
 +              o->bs[i] = le32_to_cpu(top->bs[i]);
 +              o->ba[i] = le32_to_cpu(top->ba[i]);
 +              o->min_bs[i] = le32_to_cpu(top->min_bs[i]);
 +              o->max_bs[i] = le32_to_cpu(top->max_bs[i]);
 +              o->bssplit_nr[i] = le32_to_cpu(top->bssplit_nr[i]);
 +
 +              if (o->bssplit_nr[i]) {
 +                      o->bssplit[i] = malloc(o->bssplit_nr[i] * sizeof(struct bssplit));
 +                      for (j = 0; j < o->bssplit_nr[i]; j++) {
 +                              o->bssplit[i][j].bs = le32_to_cpu(top->bssplit[i][j].bs);
 +                              o->bssplit[i][j].perc = le32_to_cpu(top->bssplit[i][j].perc);
 +                      }
 +              }
 +
 +              o->rwmix[i] = le32_to_cpu(top->rwmix[i]);
 +              o->rate[i] = le32_to_cpu(top->rate[i]);
 +              o->ratemin[i] = le32_to_cpu(top->ratemin[i]);
 +              o->rate_iops[i] = le32_to_cpu(top->rate_iops[i]);
 +              o->rate_iops_min[i] = le32_to_cpu(top->rate_iops_min[i]);
 +      }
 +
 +      o->ratecycle = le32_to_cpu(top->ratecycle);
 +      o->nr_files = le32_to_cpu(top->nr_files);
 +      o->open_files = le32_to_cpu(top->open_files);
 +      o->file_lock_mode = le32_to_cpu(top->file_lock_mode);
 +      o->lockfile_batch = le32_to_cpu(top->lockfile_batch);
 +      o->odirect = le32_to_cpu(top->odirect);
 +      o->invalidate_cache = le32_to_cpu(top->invalidate_cache);
 +      o->create_serialize = le32_to_cpu(top->create_serialize);
 +      o->create_fsync = le32_to_cpu(top->create_fsync);
 +      o->create_on_open = le32_to_cpu(top->create_on_open);
++      o->create_only = le32_to_cpu(top->create_only);
 +      o->end_fsync = le32_to_cpu(top->end_fsync);
 +      o->pre_read = le32_to_cpu(top->pre_read);
 +      o->sync_io = le32_to_cpu(top->sync_io);
 +      o->verify = le32_to_cpu(top->verify);
 +      o->do_verify = le32_to_cpu(top->do_verify);
 +      o->verifysort = le32_to_cpu(top->verifysort);
 +      o->verify_interval = le32_to_cpu(top->verify_interval);
 +      o->verify_offset = le32_to_cpu(top->verify_offset);
 +
 +      memcpy(o->verify_pattern, top->verify_pattern, MAX_PATTERN_SIZE);
 +
 +      o->verify_pattern_bytes = le32_to_cpu(top->verify_pattern_bytes);
 +      o->verify_fatal = le32_to_cpu(top->verify_fatal);
 +      o->verify_dump = le32_to_cpu(top->verify_dump);
 +      o->verify_async = le32_to_cpu(top->verify_async);
 +      o->verify_batch = le32_to_cpu(top->verify_batch);
 +      o->use_thread = le32_to_cpu(top->use_thread);
 +      o->unlink = le32_to_cpu(top->unlink);
 +      o->do_disk_util = le32_to_cpu(top->do_disk_util);
 +      o->override_sync = le32_to_cpu(top->override_sync);
 +      o->rand_repeatable = le32_to_cpu(top->rand_repeatable);
 +      o->use_os_rand = le32_to_cpu(top->use_os_rand);
 +      o->log_avg_msec = le32_to_cpu(top->log_avg_msec);
 +      o->norandommap = le32_to_cpu(top->norandommap);
 +      o->softrandommap = le32_to_cpu(top->softrandommap);
 +      o->bs_unaligned = le32_to_cpu(top->bs_unaligned);
 +      o->fsync_on_close = le32_to_cpu(top->fsync_on_close);
 +      o->hugepage_size = le32_to_cpu(top->hugepage_size);
 +      o->rw_min_bs = le32_to_cpu(top->rw_min_bs);
 +      o->thinktime = le32_to_cpu(top->thinktime);
 +      o->thinktime_spin = le32_to_cpu(top->thinktime_spin);
 +      o->thinktime_blocks = le32_to_cpu(top->thinktime_blocks);
 +      o->fsync_blocks = le32_to_cpu(top->fsync_blocks);
 +      o->fdatasync_blocks = le32_to_cpu(top->fdatasync_blocks);
 +      o->barrier_blocks = le32_to_cpu(top->barrier_blocks);
 +
 +      o->verify_backlog = le64_to_cpu(top->verify_backlog);
 +      o->start_delay = le64_to_cpu(top->start_delay);
 +      o->timeout = le64_to_cpu(top->timeout);
 +      o->ramp_time = le64_to_cpu(top->ramp_time);
 +      o->zone_range = le64_to_cpu(top->zone_range);
 +      o->zone_size = le64_to_cpu(top->zone_size);
 +      o->zone_skip = le64_to_cpu(top->zone_skip);
 +      o->lockmem = le64_to_cpu(top->lockmem);
 +      o->offset_increment = le64_to_cpu(top->offset_increment);
 +
 +      o->overwrite = le32_to_cpu(top->overwrite);
 +      o->bw_avg_time = le32_to_cpu(top->bw_avg_time);
 +      o->iops_avg_time = le32_to_cpu(top->iops_avg_time);
 +      o->loops = le32_to_cpu(top->loops);
 +      o->mem_type = le32_to_cpu(top->mem_type);
 +      o->mem_align = le32_to_cpu(top->mem_align);
 +      o->stonewall = le32_to_cpu(top->stonewall);
 +      o->new_group = le32_to_cpu(top->new_group);
 +      o->numjobs = le32_to_cpu(top->numjobs);
 +      o->cpumask_set = le32_to_cpu(top->cpumask_set);
 +      o->verify_cpumask_set = le32_to_cpu(top->verify_cpumask_set);
 +      o->iolog = le32_to_cpu(top->iolog);
 +      o->rwmixcycle = le32_to_cpu(top->rwmixcycle);
 +      o->nice = le32_to_cpu(top->nice);
 +      o->ioprio = le32_to_cpu(top->ioprio);
 +      o->ioprio_class = le32_to_cpu(top->ioprio_class);
 +      o->file_service_type = le32_to_cpu(top->file_service_type);
 +      o->group_reporting = le32_to_cpu(top->group_reporting);
 +      o->fadvise_hint = le32_to_cpu(top->fadvise_hint);
 +      o->fallocate_mode = le32_to_cpu(top->fallocate_mode);
 +      o->zero_buffers = le32_to_cpu(top->zero_buffers);
 +      o->refill_buffers = le32_to_cpu(top->refill_buffers);
 +      o->scramble_buffers = le32_to_cpu(top->scramble_buffers);
 +      o->time_based = le32_to_cpu(top->time_based);
 +      o->disable_lat = le32_to_cpu(top->disable_lat);
 +      o->disable_clat = le32_to_cpu(top->disable_clat);
 +      o->disable_slat = le32_to_cpu(top->disable_slat);
 +      o->disable_bw = le32_to_cpu(top->disable_bw);
 +      o->gtod_reduce = le32_to_cpu(top->gtod_reduce);
 +      o->gtod_cpu = le32_to_cpu(top->gtod_cpu);
 +      o->gtod_offload = le32_to_cpu(top->gtod_offload);
 +      o->clocksource = le32_to_cpu(top->clocksource);
 +      o->no_stall = le32_to_cpu(top->no_stall);
 +      o->trim_percentage = le32_to_cpu(top->trim_percentage);
 +      o->trim_batch = le32_to_cpu(top->trim_batch);
 +      o->trim_zero = le32_to_cpu(top->trim_zero);
 +      o->clat_percentiles = le32_to_cpu(top->clat_percentiles);
 +      o->overwrite_plist = le32_to_cpu(top->overwrite_plist);
 +      o->continue_on_error = le32_to_cpu(top->continue_on_error);
 +      o->cgroup_weight = le32_to_cpu(top->cgroup_weight);
 +      o->cgroup_nodelete = le32_to_cpu(top->cgroup_nodelete);
 +      o->uid = le32_to_cpu(top->uid);
 +      o->gid = le32_to_cpu(top->gid);
 +      o->flow_id = __le32_to_cpu(top->flow_id);
 +      o->flow = __le32_to_cpu(top->flow);
 +      o->flow_watermark = __le32_to_cpu(top->flow_watermark);
 +      o->flow_sleep = le32_to_cpu(top->flow_sleep);
 +      o->sync_file_range = le32_to_cpu(top->sync_file_range);
 +      o->compress_percentage = le32_to_cpu(top->compress_percentage);
 +      o->compress_chunk = le32_to_cpu(top->compress_chunk);
 +
 +      o->trim_backlog = le64_to_cpu(top->trim_backlog);
 +
 +      for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++)
 +              o->percentile_list[i].u.f = fio_uint64_to_double(le64_to_cpu(top->percentile_list[i].u.i));
 +#if 0
 +      uint8_t cpumask[FIO_TOP_STR_MAX];
 +      uint8_t verify_cpumask[FIO_TOP_STR_MAX];
 +#endif
 +}
 +
 +void convert_thread_options_to_net(struct thread_options_pack *top,
 +                                 struct thread_options *o)
 +{
 +      int i, j;
 +
 +      string_to_net(top->description, o->description);
 +      string_to_net(top->name, o->name);
 +      string_to_net(top->directory, o->directory);
 +      string_to_net(top->filename, o->filename);
 +      string_to_net(top->opendir, o->opendir);
 +      string_to_net(top->ioengine, o->ioengine);
 +      string_to_net(top->mmapfile, o->mmapfile);
 +      string_to_net(top->read_iolog_file, o->read_iolog_file);
 +      string_to_net(top->write_iolog_file, o->write_iolog_file);
 +      string_to_net(top->bw_log_file, o->bw_log_file);
 +      string_to_net(top->lat_log_file, o->lat_log_file);
 +      string_to_net(top->iops_log_file, o->iops_log_file);
 +      string_to_net(top->replay_redirect, o->replay_redirect);
 +      string_to_net(top->exec_prerun, o->exec_prerun);
 +      string_to_net(top->exec_postrun, o->exec_postrun);
 +      string_to_net(top->ioscheduler, o->ioscheduler);
 +      string_to_net(top->profile, o->profile);
 +      string_to_net(top->cgroup, o->cgroup);
 +
 +      top->td_ddir = cpu_to_le32(o->td_ddir);
 +      top->rw_seq = cpu_to_le32(o->rw_seq);
 +      top->kb_base = cpu_to_le32(o->kb_base);
 +      top->ddir_seq_nr = cpu_to_le32(o->ddir_seq_nr);
 +      top->iodepth = cpu_to_le32(o->iodepth);
 +      top->iodepth_low = cpu_to_le32(o->iodepth_low);
 +      top->iodepth_batch = cpu_to_le32(o->iodepth_batch);
 +      top->iodepth_batch_complete = cpu_to_le32(o->iodepth_batch_complete);
 +      top->size_percent = cpu_to_le32(o->size_percent);
 +      top->fill_device = cpu_to_le32(o->fill_device);
 +      top->ratecycle = cpu_to_le32(o->ratecycle);
 +      top->nr_files = cpu_to_le32(o->nr_files);
 +      top->open_files = cpu_to_le32(o->open_files);
 +      top->file_lock_mode = cpu_to_le32(o->file_lock_mode);
 +      top->lockfile_batch = cpu_to_le32(o->lockfile_batch);
 +      top->odirect = cpu_to_le32(o->odirect);
 +      top->invalidate_cache = cpu_to_le32(o->invalidate_cache);
 +      top->create_serialize = cpu_to_le32(o->create_serialize);
 +      top->create_fsync = cpu_to_le32(o->create_fsync);
 +      top->create_on_open = cpu_to_le32(o->create_on_open);
++      top->create_only = cpu_to_le32(o->create_only);
 +      top->end_fsync = cpu_to_le32(o->end_fsync);
 +      top->pre_read = cpu_to_le32(o->pre_read);
 +      top->sync_io = cpu_to_le32(o->sync_io);
 +      top->verify = cpu_to_le32(o->verify);
 +      top->do_verify = cpu_to_le32(o->do_verify);
 +      top->verifysort = cpu_to_le32(o->verifysort);
 +      top->verify_interval = cpu_to_le32(o->verify_interval);
 +      top->verify_offset = cpu_to_le32(o->verify_offset);
 +      top->verify_pattern_bytes = cpu_to_le32(o->verify_pattern_bytes);
 +      top->verify_fatal = cpu_to_le32(o->verify_fatal);
 +      top->verify_dump = cpu_to_le32(o->verify_dump);
 +      top->verify_async = cpu_to_le32(o->verify_async);
 +      top->verify_batch = cpu_to_le32(o->verify_batch);
 +      top->use_thread = cpu_to_le32(o->use_thread);
 +      top->unlink = cpu_to_le32(o->unlink);
 +      top->do_disk_util = cpu_to_le32(o->do_disk_util);
 +      top->override_sync = cpu_to_le32(o->override_sync);
 +      top->rand_repeatable = cpu_to_le32(o->rand_repeatable);
 +      top->use_os_rand = cpu_to_le32(o->use_os_rand);
 +      top->log_avg_msec = cpu_to_le32(o->log_avg_msec);
 +      top->norandommap = cpu_to_le32(o->norandommap);
 +      top->softrandommap = cpu_to_le32(o->softrandommap);
 +      top->bs_unaligned = cpu_to_le32(o->bs_unaligned);
 +      top->fsync_on_close = cpu_to_le32(o->fsync_on_close);
 +      top->hugepage_size = cpu_to_le32(o->hugepage_size);
 +      top->rw_min_bs = cpu_to_le32(o->rw_min_bs);
 +      top->thinktime = cpu_to_le32(o->thinktime);
 +      top->thinktime_spin = cpu_to_le32(o->thinktime_spin);
 +      top->thinktime_blocks = cpu_to_le32(o->thinktime_blocks);
 +      top->fsync_blocks = cpu_to_le32(o->fsync_blocks);
 +      top->fdatasync_blocks = cpu_to_le32(o->fdatasync_blocks);
 +      top->barrier_blocks = cpu_to_le32(o->barrier_blocks);
 +      top->overwrite = cpu_to_le32(o->overwrite);
 +      top->bw_avg_time = cpu_to_le32(o->bw_avg_time);
 +      top->iops_avg_time = cpu_to_le32(o->iops_avg_time);
 +      top->loops = cpu_to_le32(o->loops);
 +      top->mem_type = cpu_to_le32(o->mem_type);
 +      top->mem_align = cpu_to_le32(o->mem_align);
 +      top->stonewall = cpu_to_le32(o->stonewall);
 +      top->new_group = cpu_to_le32(o->new_group);
 +      top->numjobs = cpu_to_le32(o->numjobs);
 +      top->cpumask_set = cpu_to_le32(o->cpumask_set);
 +      top->verify_cpumask_set = cpu_to_le32(o->verify_cpumask_set);
 +      top->iolog = cpu_to_le32(o->iolog);
 +      top->rwmixcycle = cpu_to_le32(o->rwmixcycle);
 +      top->nice = cpu_to_le32(o->nice);
 +      top->ioprio = cpu_to_le32(o->ioprio);
 +      top->ioprio_class = cpu_to_le32(o->ioprio_class);
 +      top->file_service_type = cpu_to_le32(o->file_service_type);
 +      top->group_reporting = cpu_to_le32(o->group_reporting);
 +      top->fadvise_hint = cpu_to_le32(o->fadvise_hint);
 +      top->fallocate_mode = cpu_to_le32(o->fallocate_mode);
 +      top->zero_buffers = cpu_to_le32(o->zero_buffers);
 +      top->refill_buffers = cpu_to_le32(o->refill_buffers);
 +      top->scramble_buffers = cpu_to_le32(o->scramble_buffers);
 +      top->time_based = cpu_to_le32(o->time_based);
 +      top->disable_lat = cpu_to_le32(o->disable_lat);
 +      top->disable_clat = cpu_to_le32(o->disable_clat);
 +      top->disable_slat = cpu_to_le32(o->disable_slat);
 +      top->disable_bw = cpu_to_le32(o->disable_bw);
 +      top->gtod_reduce = cpu_to_le32(o->gtod_reduce);
 +      top->gtod_cpu = cpu_to_le32(o->gtod_cpu);
 +      top->gtod_offload = cpu_to_le32(o->gtod_offload);
 +      top->clocksource = cpu_to_le32(o->clocksource);
 +      top->no_stall = cpu_to_le32(o->no_stall);
 +      top->trim_percentage = cpu_to_le32(o->trim_percentage);
 +      top->trim_batch = cpu_to_le32(o->trim_batch);
 +      top->trim_zero = cpu_to_le32(o->trim_zero);
 +      top->clat_percentiles = cpu_to_le32(o->clat_percentiles);
 +      top->overwrite_plist = cpu_to_le32(o->overwrite_plist);
 +      top->continue_on_error = cpu_to_le32(o->continue_on_error);
 +      top->cgroup_weight = cpu_to_le32(o->cgroup_weight);
 +      top->cgroup_nodelete = cpu_to_le32(o->cgroup_nodelete);
 +      top->uid = cpu_to_le32(o->uid);
 +      top->gid = cpu_to_le32(o->gid);
 +      top->flow_id = __cpu_to_le32(o->flow_id);
 +      top->flow = __cpu_to_le32(o->flow);
 +      top->flow_watermark = __cpu_to_le32(o->flow_watermark);
 +      top->flow_sleep = cpu_to_le32(o->flow_sleep);
 +      top->sync_file_range = cpu_to_le32(o->sync_file_range);
 +      top->compress_percentage = cpu_to_le32(o->compress_percentage);
 +      top->compress_chunk = cpu_to_le32(o->compress_chunk);
 +
 +      for (i = 0; i < 2; i++) {
 +              top->bs[i] = cpu_to_le32(o->bs[i]);
 +              top->ba[i] = cpu_to_le32(o->ba[i]);
 +              top->min_bs[i] = cpu_to_le32(o->min_bs[i]);
 +              top->max_bs[i] = cpu_to_le32(o->max_bs[i]);
 +              top->bssplit_nr[i] = cpu_to_le32(o->bssplit_nr[i]);
 +
 +              if (o->bssplit_nr[i]) {
 +                      unsigned int bssplit_nr = o->bssplit_nr[i];
 +
 +                      if (bssplit_nr > BSSPLIT_MAX) {
 +                              log_err("fio: BSSPLIT_MAX is too small\n");
 +                              bssplit_nr = BSSPLIT_MAX;
 +                      }
 +                      for (j = 0; j < bssplit_nr; j++) {
 +                              top->bssplit[i][j].bs = cpu_to_le32(o->bssplit[i][j].bs);
 +                              top->bssplit[i][j].perc = cpu_to_le32(o->bssplit[i][j].perc);
 +                      }
 +              }
 +
 +              top->rwmix[i] = cpu_to_le32(o->rwmix[i]);
 +              top->rate[i] = cpu_to_le32(o->rate[i]);
 +              top->ratemin[i] = cpu_to_le32(o->ratemin[i]);
 +              top->rate_iops[i] = cpu_to_le32(o->rate_iops[i]);
 +              top->rate_iops_min[i] = cpu_to_le32(o->rate_iops_min[i]);
 +      }
 +
 +      memcpy(top->verify_pattern, o->verify_pattern, MAX_PATTERN_SIZE);
 +
 +      top->size = __cpu_to_le64(o->size);
 +      top->verify_backlog = __cpu_to_le64(o->verify_backlog);
 +      top->start_delay = __cpu_to_le64(o->start_delay);
 +      top->timeout = __cpu_to_le64(o->timeout);
 +      top->ramp_time = __cpu_to_le64(o->ramp_time);
 +      top->zone_range = __cpu_to_le64(o->zone_range);
 +      top->zone_size = __cpu_to_le64(o->zone_size);
 +      top->zone_skip = __cpu_to_le64(o->zone_skip);
 +      top->lockmem = __cpu_to_le64(o->lockmem);
 +      top->ddir_seq_add = __cpu_to_le64(o->ddir_seq_add);
 +      top->file_size_low = __cpu_to_le64(o->file_size_low);
 +      top->file_size_high = __cpu_to_le64(o->file_size_high);
 +      top->start_offset = __cpu_to_le64(o->start_offset);
 +      top->trim_backlog = __cpu_to_le64(o->trim_backlog);
 +      top->offset_increment = __cpu_to_le64(o->offset_increment);
 +
 +      for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++)
 +              top->percentile_list[i].u.i = __cpu_to_le64(fio_double_to_uint64(o->percentile_list[i].u.f));
 +#if 0
 +      uint8_t cpumask[FIO_TOP_STR_MAX];
 +      uint8_t verify_cpumask[FIO_TOP_STR_MAX];
 +#endif
 +
 +}
 +
 +/*
 + * Basic conversion test. We'd really need to fill in more of the options
 + * to have a thorough test. Even better, we should auto-generate the
 + * converter functions...
 + */
 +int fio_test_cconv(struct thread_options *__o)
 +{
 +      struct thread_options o;
 +      struct thread_options_pack top1, top2;
 +
 +      memset(&top1, 0, sizeof(top1));
 +      memset(&top2, 0, sizeof(top2));
 +
 +      convert_thread_options_to_net(&top1, __o);
 +      memset(&o, 0, sizeof(o));
 +      convert_thread_options_to_cpu(&o, &top1);
 +      convert_thread_options_to_net(&top2, &o);
 +
 +      return memcmp(&top1, &top2, sizeof(top1));
 +}
diff --combined eta.c
index e80fa4845e8583d8e9e74e5ce74039320ef4de81,4679a21a1192b0c36f2df0b5016580537cb1f0b8..a068e1e9cf770cc4fc4b8754fc1f52c9759878b5
--- 1/eta.c
--- 2/eta.c
+++ b/eta.c
@@@ -88,7 -88,7 +88,7 @@@ static void check_str_update(struct thr
  /*
   * Convert seconds to a printable string.
   */
 -static void eta_to_str(char *str, unsigned long eta_sec)
 +void eta_to_str(char *str, unsigned long eta_sec)
  {
        unsigned int d, h, m, s;
        int disp_hour = 0;
@@@ -278,14 -278,11 +278,14 @@@ int calc_thread_status(struct jobs_eta 
                    || td->runstate == TD_FSYNCING
                    || td->runstate == TD_PRE_READING) {
                        je->nr_running++;
 -                      je->t_rate += td->o.rate[0] + td->o.rate[1];
 -                      je->m_rate += td->o.ratemin[0] + td->o.ratemin[1];
 -                      je->t_iops += td->o.rate_iops[0] + td->o.rate_iops[1];
 -                      je->m_iops += td->o.rate_iops_min[0] +
 -                                      td->o.rate_iops_min[1];
 +                      je->t_rate[0] += td->o.rate[0];
 +                      je->t_rate[1] += td->o.rate[1];
 +                      je->m_rate[0] += td->o.ratemin[0];
 +                      je->m_rate[1] += td->o.ratemin[1];
 +                      je->t_iops[0] += td->o.rate_iops[0];
 +                      je->t_iops[1] += td->o.rate_iops[1];
 +                      je->m_iops[0] += td->o.rate_iops_min[0];
 +                      je->m_iops[1] += td->o.rate_iops_min[1];
                        je->files_open += td->nr_open_files;
                } else if (td->runstate == TD_RAMP) {
                        je->nr_running++;
@@@ -363,7 -360,7 +363,7 @@@ void display_thread_status(struct jobs_
  {
        static int linelen_last;
        static int eta_good;
-       char output[512], *p = output;
+       char output[REAL_MAX_JOBS + 512], *p = output;
        char eta_str[128];
        double perc = 0.0;
        int i2p = 0;
        }
  
        p += sprintf(p, "Jobs: %d (f=%d)", je->nr_running, je->files_open);
 -      if (je->m_rate || je->t_rate) {
 +      if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
                char *tr, *mr;
  
 -              mr = num2str(je->m_rate, 4, 0, i2p);
 -              tr = num2str(je->t_rate, 4, 0, i2p);
 +              mr = num2str(je->m_rate[0] + je->m_rate[1], 4, 0, i2p);
 +              tr = num2str(je->t_rate[0] + je->t_rate[1], 4, 0, i2p);
                p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
                free(tr);
                free(mr);
 -      } else if (je->m_iops || je->t_iops)
 -              p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
 +      } else if (je->m_iops[0] || je->m_iops[1] || je->t_iops[0] || je->t_iops[1]) {
 +              p += sprintf(p, ", CR=%d/%d IOPS",
 +                                      je->t_iops[0] + je->t_iops[1],
 +                                      je->m_iops[0] + je->t_iops[1]);
 +      }
        if (je->eta_sec != INT_MAX && je->nr_running) {
                char perc_str[32];
                char *iops_str[2];
                char *rate_str[2];
+               size_t left;
                int l;
  
                if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
                iops_str[0] = num2str(je->iops[0], 4, 1, 0);
                iops_str[1] = num2str(je->iops[1], 4, 1, 0);
  
-               l = sprintf(p, ": [%s] [%s] [%s/%s /s] [%s/%s iops] [eta %s]",
+               left = sizeof(output) - (p - output) - 1;
+               l = snprintf(p, left, ": [%s] [%s] [%s/%s /s] [%s/%s iops] [eta %s]",
                                je->run_str, perc_str, rate_str[0],
                                rate_str[1], iops_str[0], iops_str[1], eta_str);
                p += l;
diff --combined filesetup.c
index 166ace8c529e02d0afa5cc91fb4ca66d6626cd21,a1ad02633f10d2871adc8d93dc83e833f3afa340..d30b61639afa62548c0147613facbeff3854c724
@@@ -94,9 -94,9 +94,9 @@@ static int extend_file(struct thread_da
  
                        r = fallocate(f->fd, FALLOC_FL_KEEP_SIZE, 0,
                                        f->real_file_size);
 -                      if (r != 0) {
 +                      if (r != 0)
                                td_verror(td, errno, "fallocate");
 -                      }
 +
                        break;
  #endif /* FIO_HAVE_LINUX_FALLOCATE */
                default:
@@@ -665,7 -665,7 +665,7 @@@ int setup_files(struct thread_data *td
        dprint(FD_FILE, "setup files\n");
  
        if (td->o.read_iolog_file)
-               return 0;
+               goto done;
  
        /*
         * if ioengine defines a setup() method, it's responsible for
         */
        if (!td->o.read_iolog_file)
                td->total_io_size = td->o.size * td->o.loops;
+ done:
+       if (td->o.create_only)
+               td->done = 1;
        return 0;
  err_offset:
        log_err("%s: you need to specify valid offset=\n", td->o.name);
diff --combined fio.1
index cc6fd35b32d72e0efd9294b34e3e01a8871405b1,7997526a343120e3d24eb64fc51784498cae7749..10cb51d5ced620e523a60aff4600c17566e054a6
--- 1/fio.1
--- 2/fio.1
+++ b/fio.1
@@@ -204,7 -204,7 +204,7 @@@ Mixed random reads and writes
  .P
  For mixed I/O, the default split is 50/50. For certain types of io the result
  may still be skewed a bit, since the speed may be different. It is possible to
- specify a number of IO's to do before getting a new offset, this is one by
+ specify a number of IO's to do before getting a new offset, this is done by
  appending a `:\fI<nr>\fR to the end of the string given. For a random read, it
  would look like \fBrw=randread:8\fR for passing in an offset modifier with a
  value of 8. If the postfix is used with a sequential IO pattern, then the value
@@@ -555,10 -555,6 +555,6 @@@ Sync file contents when job exits.  Def
  If true, sync file contents on close.  This differs from \fBend_fsync\fR in that
  it will happen on every close, not just at the end of the job.  Default: false.
  .TP
- .BI rwmixcycle \fR=\fPint
- How many milliseconds before switching between reads and writes for a mixed
- workload. Default: 500ms.
- .TP
  .BI rwmixread \fR=\fPint
  Percentage of a mixed workload that should be reads. Default: 50.
  .TP
@@@ -725,6 -721,11 +721,11 @@@ If true, serialize file creation for th
  .BI create_on_open \fR=\fPbool
  If true, the files are not created until they are opened for IO by the job.
  .TP
+ .BI create_only \fR=\fPbool
+ If true, fio will only run the setup phase of the job. If files need to be
+ laid out or updated on disk, only that will be done. The actual job contents
+ are not executed.
+ .TP
  .BI pre_read \fR=\fPbool
  If this is given, files will be pre-read into memory before starting the given
  IO operation. This will also clear the \fR \fBinvalidate\fR flag, since it is
@@@ -1015,12 -1016,6 +1016,12 @@@ Some parameters are only valid when a s
  used identically to normal parameters, with the caveat that when used on the
  command line, the must come after the ioengine that defines them is selected.
  .TP
 +.BI (cpu)cpuload \fR=\fPint
 +Attempt to use the specified percentage of CPU cycles.
 +.TP
 +.BI (cpu)cpuchunks \fR=\fPint
 +Split the load into cycles of the given time. In microseconds.
 +.TP
  .BI (libaio)userspace_reap
  Normally, with the libaio engine in use, fio will use
  the io_getevents system call to reap newly returned events.
@@@ -1209,6 -1204,10 +1210,10 @@@ Total time spent in the disk queue
  Disk utilization.
  .RE
  .PD
+ .P
+ It is also possible to get fio to dump the current output while it is
+ running, without terminating the job. To do that, send fio the \fBUSR1\fR
+ signal.
  .SH TERSE OUTPUT
  If the \fB\-\-minimal\fR option is given, the results will be printed in a
  semicolon-delimited format suitable for scripted use - a job description
diff --combined options.c
index ae9fdac8f169d2985e77f7e5ac376c521677a353,28a228c6fefbb5ec7bab60ef8afc225685f70609..0074e5fbc98e5d7cf9356e7967dd14de834da3d7
+++ b/options.c
@@@ -37,7 -37,7 +37,7 @@@ static int converthexchartoint(char a
  {
        int base;
  
 -      switch(a) {
 +      switch (a) {
        case '0'...'9':
                base = '0';
                break;
@@@ -50,7 -50,7 +50,7 @@@
        default:
                base = 0;
        }
 -      return (a - base);
 +      return a - base;
  }
  
  static int bs_cmp(const void *p1, const void *p2)
@@@ -61,7 -61,7 +61,7 @@@
        return bsp1->perc < bsp2->perc;
  }
  
 -static int bssplit_ddir(struct thread_data *td, int ddir, char *str)
 +static int bssplit_ddir(struct thread_options *o, int ddir, char *str)
  {
        struct bssplit *bssplit;
        unsigned int i, perc, perc_missing;
@@@ -69,7 -69,7 +69,7 @@@
        long long val;
        char *fname;
  
 -      td->o.bssplit_nr[ddir] = 4;
 +      o->bssplit_nr[ddir] = 4;
        bssplit = malloc(4 * sizeof(struct bssplit));
  
        i = 0;
@@@ -84,9 -84,9 +84,9 @@@
                /*
                 * grow struct buffer, if needed
                 */
 -              if (i == td->o.bssplit_nr[ddir]) {
 -                      td->o.bssplit_nr[ddir] <<= 1;
 -                      bssplit = realloc(bssplit, td->o.bssplit_nr[ddir]
 +              if (i == o->bssplit_nr[ddir]) {
 +                      o->bssplit_nr[ddir] <<= 1;
 +                      bssplit = realloc(bssplit, o->bssplit_nr[ddir]
                                                  * sizeof(struct bssplit));
                }
  
                } else
                        perc = -1;
  
 -              if (str_to_decimal(fname, &val, 1, td)) {
 +              if (str_to_decimal(fname, &val, 1, o)) {
                        log_err("fio: bssplit conversion failed\n");
 -                      free(td->o.bssplit);
 +                      free(o->bssplit);
                        return 1;
                }
  
                i++;
        }
  
 -      td->o.bssplit_nr[ddir] = i;
 +      o->bssplit_nr[ddir] = i;
  
        /*
         * Now check if the percentages add up, and how much is missing
         */
        perc = perc_missing = 0;
 -      for (i = 0; i < td->o.bssplit_nr[ddir]; i++) {
 +      for (i = 0; i < o->bssplit_nr[ddir]; i++) {
                struct bssplit *bsp = &bssplit[i];
  
                if (bsp->perc == (unsigned char) -1)
         * them.
         */
        if (perc_missing) {
 -              for (i = 0; i < td->o.bssplit_nr[ddir]; i++) {
 +              for (i = 0; i < o->bssplit_nr[ddir]; i++) {
                        struct bssplit *bsp = &bssplit[i];
  
                        if (bsp->perc == (unsigned char) -1)
                }
        }
  
 -      td->o.min_bs[ddir] = min_bs;
 -      td->o.max_bs[ddir] = max_bs;
 +      o->min_bs[ddir] = min_bs;
 +      o->max_bs[ddir] = max_bs;
  
        /*
         * now sort based on percentages, for ease of lookup
         */
 -      qsort(bssplit, td->o.bssplit_nr[ddir], sizeof(struct bssplit), bs_cmp);
 -      td->o.bssplit[ddir] = bssplit;
 +      qsort(bssplit, o->bssplit_nr[ddir], sizeof(struct bssplit), bs_cmp);
 +      o->bssplit[ddir] = bssplit;
        return 0;
 -
  }
  
  static int str_bssplit_cb(void *data, const char *input)
  
        odir = strchr(str, ',');
        if (odir) {
 -              ret = bssplit_ddir(td, DDIR_WRITE, odir + 1);
 +              ret = bssplit_ddir(&td->o, DDIR_WRITE, odir + 1);
                if (!ret) {
                        *odir = '\0';
 -                      ret = bssplit_ddir(td, DDIR_READ, str);
 +                      ret = bssplit_ddir(&td->o, DDIR_READ, str);
                }
        } else {
                char *op;
  
                op = strdup(str);
  
 -              ret = bssplit_ddir(td, DDIR_READ, str);
 +              ret = bssplit_ddir(&td->o, DDIR_READ, str);
                if (!ret)
 -                      ret = bssplit_ddir(td, DDIR_WRITE, op);
 +                      ret = bssplit_ddir(&td->o, DDIR_WRITE, op);
  
                free(op);
        }
  static int str_rw_cb(void *data, const char *str)
  {
        struct thread_data *td = data;
 +      struct thread_options *o = &td->o;
        char *nr = get_opt_postfix(str);
  
 -      td->o.ddir_seq_nr = 1;
 -      td->o.ddir_seq_add = 0;
 +      o->ddir_seq_nr = 1;
 +      o->ddir_seq_add = 0;
  
        if (!nr)
                return 0;
  
        if (td_random(td))
 -              td->o.ddir_seq_nr = atoi(nr);
 +              o->ddir_seq_nr = atoi(nr);
        else {
                long long val;
  
 -              if (str_to_decimal(nr, &val, 1, td)) {
 +              if (str_to_decimal(nr, &val, 1, o)) {
                        log_err("fio: rw postfix parsing failed\n");
                        free(nr);
                        return 1;
                }
  
 -              td->o.ddir_seq_add = val;
 +              o->ddir_seq_add = val;
        }
  
        free(nr);
  static int str_mem_cb(void *data, const char *mem)
  {
        struct thread_data *td = data;
 +      struct thread_options *o = &td->o;
  
 -      if (td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAP) {
 -              td->mmapfile = get_opt_postfix(mem);
 -              if (td->o.mem_type == MEM_MMAPHUGE && !td->mmapfile) {
 +      if (o->mem_type == MEM_MMAPHUGE || o->mem_type == MEM_MMAP) {
 +              o->mmapfile = get_opt_postfix(mem);
 +              if (o->mem_type == MEM_MMAPHUGE && !o->mmapfile) {
                        log_err("fio: mmaphuge:/path/to/file\n");
                        return 1;
                }
        return 0;
  }
  
 -static int str_verify_cb(void *data, const char *mem)
 -{
 -      struct thread_data *td = data;
 -
 -      if (td->o.verify == VERIFY_CRC32C_INTEL ||
 -          td->o.verify == VERIFY_CRC32C) {
 -              crc32c_intel_probe();
 -      }
 -
 -      return 0;
 -}
 -
  static int fio_clock_source_cb(void *data, const char *str)
  {
        struct thread_data *td = data;
        return 0;
  }
  
 -static int str_lockmem_cb(void fio_unused *data, unsigned long long *val)
 -{
 -      mlock_size = *val;
 -      return 0;
 -}
 -
  static int str_rwmix_read_cb(void *data, unsigned long long *val)
  {
        struct thread_data *td = data;
@@@ -269,6 -286,40 +269,6 @@@ static int str_rwmix_write_cb(void *dat
        return 0;
  }
  
 -#ifdef FIO_HAVE_IOPRIO
 -static int str_prioclass_cb(void *data, unsigned long long *val)
 -{
 -      struct thread_data *td = data;
 -      unsigned short mask;
 -
 -      /*
 -       * mask off old class bits, str_prio_cb() may have set a default class
 -       */
 -      mask = (1 << IOPRIO_CLASS_SHIFT) - 1;
 -      td->ioprio &= mask;
 -
 -      td->ioprio |= *val << IOPRIO_CLASS_SHIFT;
 -      td->ioprio_set = 1;
 -      return 0;
 -}
 -
 -static int str_prio_cb(void *data, unsigned long long *val)
 -{
 -      struct thread_data *td = data;
 -
 -      td->ioprio |= *val;
 -
 -      /*
 -       * If no class is set, assume BE
 -       */
 -      if ((td->ioprio >> IOPRIO_CLASS_SHIFT) == 0)
 -              td->ioprio |= IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT;
 -
 -      td->ioprio_set = 1;
 -      return 0;
 -}
 -#endif
 -
  static int str_exitall_cb(void)
  {
        exitall_on_terminate = 1;
@@@ -401,6 -452,16 +401,6 @@@ static int str_verify_cpus_allowed_cb(v
  }
  #endif
  
 -#ifdef FIO_HAVE_TRIM
 -static int str_verify_trim_cb(void *data, unsigned long long *val)
 -{
 -      struct thread_data *td = data;
 -
 -      td->o.trim_percentage = *val;
 -      return 0;
 -}
 -#endif
 -
  static int str_fst_cb(void *data, const char *str)
  {
        struct thread_data *td = data;
@@@ -431,6 -492,45 +431,6 @@@ static int str_sfr_cb(void *data, cons
  }
  #endif
  
 -static int check_dir(struct thread_data *td, char *fname)
 -{
 -#if 0
 -      char file[PATH_MAX], *dir;
 -      int elen = 0;
 -
 -      if (td->o.directory) {
 -              strcpy(file, td->o.directory);
 -              strcat(file, "/");
 -              elen = strlen(file);
 -      }
 -
 -      sprintf(file + elen, "%s", fname);
 -      dir = dirname(file);
 -
 -      {
 -      struct stat sb;
 -      /*
 -       * We can't do this on FIO_DISKLESSIO engines. The engine isn't loaded
 -       * yet, so we can't do this check right here...
 -       */
 -      if (lstat(dir, &sb) < 0) {
 -              int ret = errno;
 -
 -              log_err("fio: %s is not a directory\n", dir);
 -              td_verror(td, ret, "lstat");
 -              return 1;
 -      }
 -
 -      if (!S_ISDIR(sb.st_mode)) {
 -              log_err("fio: %s is not a directory\n", dir);
 -              return 1;
 -      }
 -      }
 -#endif
 -
 -      return 0;
 -}
 -
  /*
   * Return next file in the string. Files are separated with ':'. If the ':'
   * is escaped with a '\', then that ':' is part of the filename and does not
@@@ -493,6 -593,10 +493,6 @@@ static int str_filename_cb(void *data, 
        while ((fname = get_next_file_name(&str)) != NULL) {
                if (!strlen(fname))
                        break;
 -              if (check_dir(td, fname)) {
 -                      free(p);
 -                      return 1;
 -              }
                add_file(td, fname);
                td->o.nr_files++;
        }
@@@ -531,12 -635,25 +531,12 @@@ static int str_opendir_cb(void *data, c
        return add_dir_files(td, td->o.opendir);
  }
  
 -static int str_verify_offset_cb(void *data, unsigned long long *off)
 -{
 -      struct thread_data *td = data;
 -
 -      if (*off && *off < sizeof(struct verify_header)) {
 -              log_err("fio: verify_offset too small\n");
 -              return 1;
 -      }
 -
 -      td->o.verify_offset = *off;
 -      return 0;
 -}
 -
  static int str_verify_pattern_cb(void *data, const char *input)
  {
        struct thread_data *td = data;
        long off;
        int i = 0, j = 0, len, k, base = 10;
 -      char* loc1, * loc2;
 +      char *loc1, *loc2;
  
        loc1 = strstr(input, "0x");
        loc2 = strstr(input, "0X");
@@@ -612,6 -729,39 +612,6 @@@ static int str_lockfile_cb(void *data, 
        return 0;
  }
  
 -static int str_write_bw_log_cb(void *data, const char *str)
 -{
 -      struct thread_data *td = data;
 -
 -      if (str)
 -              td->o.bw_log_file = strdup(str);
 -
 -      td->o.write_bw_log = 1;
 -      return 0;
 -}
 -
 -static int str_write_lat_log_cb(void *data, const char *str)
 -{
 -      struct thread_data *td = data;
 -
 -      if (str)
 -              td->o.lat_log_file = strdup(str);
 -
 -      td->o.write_lat_log = 1;
 -      return 0;
 -}
 -
 -static int str_write_iops_log_cb(void *data, const char *str)
 -{
 -      struct thread_data *td = data;
 -
 -      if (str)
 -              td->o.iops_log_file = strdup(str);
 -
 -      td->o.write_iops_log = 1;
 -      return 0;
 -}
 -
  static int str_gtod_reduce_cb(void *data, int *il)
  {
        struct thread_data *td = data;
@@@ -693,216 -843,54 +693,216 @@@ static int kb_base_verify(struct fio_op
        return 0;
  }
  
 +/*
 + * Option grouping
 + */
 +static struct opt_group fio_opt_groups[] = {
 +      {
 +              .name   = "General",
 +              .mask   = FIO_OPT_C_GENERAL,
 +      },
 +      {
 +              .name   = "I/O",
 +              .mask   = FIO_OPT_C_IO,
 +      },
 +      {
 +              .name   = "File",
 +              .mask   = FIO_OPT_C_FILE,
 +      },
 +      {
 +              .name   = "Statistics",
 +              .mask   = FIO_OPT_C_STAT,
 +      },
 +      {
 +              .name   = "Logging",
 +              .mask   = FIO_OPT_C_LOG,
 +      },
 +      {
 +              .name   = "Profiles",
 +              .mask   = FIO_OPT_C_PROFILE,
 +      },
 +      {
 +              .name   = NULL,
 +      },
 +};
 +
 +static struct opt_group *__opt_group_from_mask(struct opt_group *ogs, unsigned int *mask,
 +                                             unsigned int inv_mask)
 +{
 +      struct opt_group *og;
 +      int i;
 +
 +      if (*mask == inv_mask || !*mask)
 +              return NULL;
 +
 +      for (i = 0; ogs[i].name; i++) {
 +              og = &ogs[i];
 +
 +              if (*mask & og->mask) {
 +                      *mask &= ~(og->mask);
 +                      return og;
 +              }
 +      }
 +
 +      return NULL;
 +}
 +
 +struct opt_group *opt_group_from_mask(unsigned int *mask)
 +{
 +      return __opt_group_from_mask(fio_opt_groups, mask, FIO_OPT_C_INVALID);
 +}
 +
 +static struct opt_group fio_opt_cat_groups[] = {
 +      {
 +              .name   = "Rate",
 +              .mask   = FIO_OPT_G_RATE,
 +      },
 +      {
 +              .name   = "Zone",
 +              .mask   = FIO_OPT_G_ZONE,
 +      },
 +      {
 +              .name   = "Read/write mix",
 +              .mask   = FIO_OPT_G_RWMIX,
 +      },
 +      {
 +              .name   = "Verify",
 +              .mask   = FIO_OPT_G_VERIFY,
 +      },
 +      {
 +              .name   = "Trim",
 +              .mask   = FIO_OPT_G_TRIM,
 +      },
 +      {
 +              .name   = "I/O Logging",
 +              .mask   = FIO_OPT_G_IOLOG,
 +      },
 +      {
 +              .name   = "I/O Depth",
 +              .mask   = FIO_OPT_G_IO_DEPTH,
 +      },
 +      {
 +              .name   = "I/O Flow",
 +              .mask   = FIO_OPT_G_IO_FLOW,
 +      },
 +      {
 +              .name   = "Description",
 +              .mask   = FIO_OPT_G_DESC,
 +      },
 +      {
 +              .name   = "Filename",
 +              .mask   = FIO_OPT_G_FILENAME,
 +      },
 +      {
 +              .name   = "General I/O",
 +              .mask   = FIO_OPT_G_IO_BASIC,
 +      },
 +      {
 +              .name   = "Cgroups",
 +              .mask   = FIO_OPT_G_CGROUP,
 +      },
 +      {
 +              .name   = "Runtime",
 +              .mask   = FIO_OPT_G_RUNTIME,
 +      },
 +      {
 +              .name   = "Process",
 +              .mask   = FIO_OPT_G_PROCESS,
 +      },
 +      {
 +              .name   = "Job credentials / priority",
 +              .mask   = FIO_OPT_G_CRED,
 +      },
 +      {
 +              .name   = "Clock settings",
 +              .mask   = FIO_OPT_G_CLOCK,
 +      },
 +      {
 +              .name   = "I/O Type",
 +              .mask   = FIO_OPT_G_IO_TYPE,
 +      },
 +      {
 +              .name   = "I/O Thinktime",
 +              .mask   = FIO_OPT_G_THINKTIME,
 +      },
 +      {
 +              .name   = "Randomizations",
 +              .mask   = FIO_OPT_G_RANDOM,
 +      },
 +      {
 +              .name   = "I/O buffers",
 +              .mask   = FIO_OPT_G_IO_BUF,
 +      },
 +      {
 +              .name   = "Tiobench profile",
 +              .mask   = FIO_OPT_G_TIOBENCH,
 +      },
 +
 +      {
 +              .name   = NULL,
 +      }
 +};
 +
 +struct opt_group *opt_group_cat_from_mask(unsigned int *mask)
 +{
 +      return __opt_group_from_mask(fio_opt_cat_groups, mask, FIO_OPT_G_INVALID);
 +}
 +
  /*
   * Map of job/command line options
   */
 -static struct fio_option options[FIO_MAX_OPTS] = {
 +struct fio_option fio_options[FIO_MAX_OPTS] = {
        {
                .name   = "description",
 +              .lname  = "Description of job",
                .type   = FIO_OPT_STR_STORE,
                .off1   = td_var_offset(description),
                .help   = "Text job description",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_DESC,
        },
        {
                .name   = "name",
 +              .lname  = "Job name",
                .type   = FIO_OPT_STR_STORE,
                .off1   = td_var_offset(name),
                .help   = "Name of this job",
 -      },
 -      {
 -              .name   = "directory",
 -              .type   = FIO_OPT_STR_STORE,
 -              .off1   = td_var_offset(directory),
 -              .cb     = str_directory_cb,
 -              .help   = "Directory to store files in",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_DESC,
        },
        {
                .name   = "filename",
 +              .lname  = "Filename(s)",
                .type   = FIO_OPT_STR_STORE,
                .off1   = td_var_offset(filename),
                .cb     = str_filename_cb,
                .prio   = -1, /* must come after "directory" */
                .help   = "File(s) to use for the workload",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_FILENAME,
        },
        {
 -              .name   = "kb_base",
 -              .type   = FIO_OPT_INT,
 -              .off1   = td_var_offset(kb_base),
 -              .verify = kb_base_verify,
 -              .prio   = 1,
 -              .def    = "1024",
 -              .help   = "How many bytes per KB for reporting (1000 or 1024)",
 +              .name   = "directory",
 +              .lname  = "Directory",
 +              .type   = FIO_OPT_STR_STORE,
 +              .off1   = td_var_offset(directory),
 +              .cb     = str_directory_cb,
 +              .help   = "Directory to store files in",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_FILENAME,
        },
        {
                .name   = "lockfile",
 +              .lname  = "Lockfile",
                .type   = FIO_OPT_STR,
                .cb     = str_lockfile_cb,
                .off1   = td_var_offset(file_lock_mode),
                .help   = "Lock file when doing IO to it",
                .parent = "filename",
 +              .hide   = 0,
                .def    = "none",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_FILENAME,
                .posval = {
                          { .ival = "none",
                            .oval = FILE_LOCK_NONE,
        },
        {
                .name   = "opendir",
 +              .lname  = "Open directory",
                .type   = FIO_OPT_STR_STORE,
                .off1   = td_var_offset(opendir),
                .cb     = str_opendir_cb,
                .help   = "Recursively add files from this directory and down",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_FILENAME,
        },
        {
                .name   = "rw",
 +              .lname  = "Read/write",
                .alias  = "readwrite",
                .type   = FIO_OPT_STR,
                .cb     = str_rw_cb,
                .help   = "IO direction",
                .def    = "read",
                .verify = rw_verify,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_BASIC,
                .posval = {
                          { .ival = "read",
                            .oval = TD_DDIR_READ,
        },
        {
                .name   = "rw_sequencer",
 +              .lname  = "RW Sequencer",
                .type   = FIO_OPT_STR,
                .off1   = td_var_offset(rw_seq),
                .help   = "IO offset generator modifier",
                .def    = "sequential",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_BASIC,
                .posval = {
                          { .ival = "sequential",
                            .oval = RW_SEQ_SEQ,
  
        {
                .name   = "ioengine",
 +              .lname  = "IO Engine",
                .type   = FIO_OPT_STR_STORE,
                .off1   = td_var_offset(ioengine),
                .help   = "IO engine to use",
                .def    = FIO_PREFERRED_ENGINE,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_BASIC,
                .posval = {
                          { .ival = "sync",
                            .help = "Use read/write",
        },
        {
                .name   = "iodepth",
 +              .lname  = "IO Depth",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(iodepth),
                .help   = "Number of IO buffers to keep in flight",
                .minval = 1,
 +              .interval = 1,
                .def    = "1",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_BASIC,
        },
        {
                .name   = "iodepth_batch",
 +              .lname  = "IO Depth batch",
                .alias  = "iodepth_batch_submit",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(iodepth_batch),
                .help   = "Number of IO buffers to submit in one go",
                .parent = "iodepth",
 +              .hide   = 1,
                .minval = 1,
 +              .interval = 1,
                .def    = "1",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_BASIC,
        },
        {
                .name   = "iodepth_batch_complete",
 +              .lname  = "IO Depth batch complete",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(iodepth_batch_complete),
                .help   = "Number of IO buffers to retrieve in one go",
                .parent = "iodepth",
 +              .hide   = 1,
                .minval = 0,
 +              .interval = 1,
                .def    = "1",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_BASIC,
        },
        {
                .name   = "iodepth_low",
 +              .lname  = "IO Depth batch low",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(iodepth_low),
                .help   = "Low water mark for queuing depth",
                .parent = "iodepth",
 +              .hide   = 1,
 +              .interval = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_BASIC,
        },
        {
                .name   = "size",
 +              .lname  = "Size",
                .type   = FIO_OPT_STR_VAL,
                .cb     = str_size_cb,
                .help   = "Total size of device or files",
 +              .interval = 1024 * 1024,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "fill_device",
 +              .lname  = "Fill device",
                .alias  = "fill_fs",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(fill_device),
                .help   = "Write until an ENOSPC error occurs",
                .def    = "0",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "filesize",
 +              .lname  = "File size",
                .type   = FIO_OPT_STR_VAL,
                .off1   = td_var_offset(file_size_low),
                .off2   = td_var_offset(file_size_high),
                .minval = 1,
                .help   = "Size of individual files",
 +              .interval = 1024 * 1024,
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "offset",
 +              .lname  = "IO offset",
                .alias  = "fileoffset",
                .type   = FIO_OPT_STR_VAL,
                .off1   = td_var_offset(start_offset),
                .help   = "Start IO from this offset",
                .def    = "0",
 +              .interval = 1024 * 1024,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "offset_increment",
 +              .lname  = "IO offset increment",
                .type   = FIO_OPT_STR_VAL,
                .off1   = td_var_offset(offset_increment),
                .help   = "What is the increment from one offset to the next",
                .parent = "offset",
 +              .hide   = 1,
                .def    = "0",
 +              .interval = 1024 * 1024,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "bs",
 +              .lname  = "Block size",
                .alias  = "blocksize",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(bs[DDIR_READ]),
                .help   = "Block size unit",
                .def    = "4k",
                .parent = "rw",
 +              .hide   = 1,
 +              .interval = 512,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "ba",
 +              .lname  = "Block size align",
                .alias  = "blockalign",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(ba[DDIR_READ]),
                .minval = 1,
                .help   = "IO block offset alignment",
                .parent = "rw",
 +              .hide   = 1,
 +              .interval = 512,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "bsrange",
 +              .lname  = "Block size range",
                .alias  = "blocksize_range",
                .type   = FIO_OPT_RANGE,
                .off1   = td_var_offset(min_bs[DDIR_READ]),
                .minval = 1,
                .help   = "Set block size range (in more detail than bs)",
                .parent = "rw",
 +              .hide   = 1,
 +              .interval = 4096,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "bssplit",
 +              .lname  = "Block size split",
                .type   = FIO_OPT_STR,
                .cb     = str_bssplit_cb,
                .help   = "Set a specific mix of block sizes",
                .parent = "rw",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "bs_unaligned",
 +              .lname  = "Block size unaligned",
                .alias  = "blocksize_unaligned",
                .type   = FIO_OPT_STR_SET,
                .off1   = td_var_offset(bs_unaligned),
                .help   = "Don't sector align IO buffer sizes",
                .parent = "rw",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "randrepeat",
 +              .lname  = "Random repeatable",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(rand_repeatable),
                .help   = "Use repeatable random IO pattern",
                .def    = "1",
                .parent = "rw",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_RANDOM,
        },
        {
                .name   = "use_os_rand",
 +              .lname  = "Use OS random",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(use_os_rand),
                .help   = "Set to use OS random generator",
                .def    = "0",
                .parent = "rw",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_RANDOM,
        },
        {
                .name   = "norandommap",
 +              .lname  = "No randommap",
                .type   = FIO_OPT_STR_SET,
                .off1   = td_var_offset(norandommap),
                .help   = "Accept potential duplicate random blocks",
                .parent = "rw",
 +              .hide   = 1,
 +              .hide_on_set = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_RANDOM,
        },
        {
                .name   = "softrandommap",
 +              .lname  = "Soft randommap",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(softrandommap),
                .help   = "Set norandommap if randommap allocation fails",
                .parent = "norandommap",
 +              .hide   = 1,
                .def    = "0",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_RANDOM,
        },
        {
                .name   = "nrfiles",
 +              .lname  = "Number of files",
                .alias  = "nr_files",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(nr_files),
                .help   = "Split job workload between this number of files",
                .def    = "1",
 +              .interval = 1,
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "openfiles",
 +              .lname  = "Number of open files",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(open_files),
                .help   = "Number of files to keep open at the same time",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "file_service_type",
 +              .lname  = "File service type",
                .type   = FIO_OPT_STR,
                .cb     = str_fst_cb,
                .off1   = td_var_offset(file_service_type),
                .help   = "How to select which file to service next",
                .def    = "roundrobin",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
                .posval = {
                          { .ival = "random",
                            .oval = FIO_FSERVICE_RANDOM,
                          },
                },
                .parent = "nrfiles",
 +              .hide   = 1,
        },
  #ifdef FIO_HAVE_FALLOCATE
        {
                .name   = "fallocate",
 +              .lname  = "Fallocate",
                .type   = FIO_OPT_STR,
                .off1   = td_var_offset(fallocate_mode),
                .help   = "Whether pre-allocation is performed when laying out files",
                .def    = "posix",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
                .posval = {
                          { .ival = "none",
                            .oval = FIO_FALLOCATE_NONE,
  #endif        /* FIO_HAVE_FALLOCATE */
        {
                .name   = "fadvise_hint",
 +              .lname  = "Fadvise hint",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(fadvise_hint),
                .help   = "Use fadvise() to advise the kernel on IO pattern",
                .def    = "1",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "fsync",
 +              .lname  = "Fsync",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(fsync_blocks),
                .help   = "Issue fsync for writes every given number of blocks",
                .def    = "0",
 +              .interval = 1,
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "fdatasync",
 +              .lname  = "Fdatasync",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(fdatasync_blocks),
                .help   = "Issue fdatasync for writes every given number of blocks",
                .def    = "0",
 +              .interval = 1,
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "write_barrier",
 +              .lname  = "Write barrier",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(barrier_blocks),
                .help   = "Make every Nth write a barrier write",
                .def    = "0",
 +              .interval = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_INVALID,
        },
  #ifdef FIO_HAVE_SYNC_FILE_RANGE
        {
                .name   = "sync_file_range",
 +              .lname  = "Sync file range",
                .posval = {
                          { .ival = "wait_before",
                            .oval = SYNC_FILE_RANGE_WAIT_BEFORE,
                .cb     = str_sfr_cb,
                .off1   = td_var_offset(sync_file_range),
                .help   = "Use sync_file_range()",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
  #endif
        {
                .name   = "direct",
 +              .lname  = "Direct I/O",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(odirect),
                .help   = "Use O_DIRECT IO (negates buffered)",
                .def    = "0",
 +              .inverse = "buffered",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_TYPE,
        },
        {
                .name   = "buffered",
 +              .lname  = "Buffered I/O",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(odirect),
                .neg    = 1,
                .help   = "Use buffered IO (negates direct)",
                .def    = "1",
 +              .inverse = "direct",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_TYPE,
        },
        {
                .name   = "overwrite",
 +              .lname  = "Overwrite",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(overwrite),
                .help   = "When writing, set whether to overwrite current data",
                .def    = "0",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "loops",
 +              .lname  = "Loops",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(loops),
                .help   = "Number of times to run the job",
                .def    = "1",
 +              .interval = 1,
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_RUNTIME,
        },
        {
                .name   = "numjobs",
 +              .lname  = "Number of jobs",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(numjobs),
                .help   = "Duplicate this job this many times",
                .def    = "1",
 +              .interval = 1,
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_RUNTIME,
        },
        {
                .name   = "startdelay",
 +              .lname  = "Start delay",
                .type   = FIO_OPT_STR_VAL_TIME,
                .off1   = td_var_offset(start_delay),
                .help   = "Only start job when this period has passed",
                .def    = "0",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_RUNTIME,
        },
        {
                .name   = "runtime",
 +              .lname  = "Runtime",
                .alias  = "timeout",
                .type   = FIO_OPT_STR_VAL_TIME,
                .off1   = td_var_offset(timeout),
                .help   = "Stop workload when this amount of time has passed",
                .def    = "0",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_RUNTIME,
        },
        {
                .name   = "time_based",
 +              .lname  = "Time based",
                .type   = FIO_OPT_STR_SET,
                .off1   = td_var_offset(time_based),
                .help   = "Keep running until runtime/timeout is met",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_RUNTIME,
        },
        {
                .name   = "ramp_time",
 +              .lname  = "Ramp time",
                .type   = FIO_OPT_STR_VAL_TIME,
                .off1   = td_var_offset(ramp_time),
                .help   = "Ramp up time before measuring performance",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_RUNTIME,
        },
        {
                .name   = "clocksource",
 +              .lname  = "Clock source",
                .type   = FIO_OPT_STR,
                .cb     = fio_clock_source_cb,
                .off1   = td_var_offset(clocksource),
                .help   = "What type of timing source to use",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_CLOCK,
                .posval = {
                          { .ival = "gettimeofday",
                            .oval = CS_GTOD,
        {
                .name   = "mem",
                .alias  = "iomem",
 +              .lname  = "I/O Memory",
                .type   = FIO_OPT_STR,
                .cb     = str_mem_cb,
                .off1   = td_var_offset(mem_type),
                .help   = "Backing type for IO buffers",
                .def    = "malloc",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_INVALID,
                .posval = {
                          { .ival = "malloc",
                            .oval = MEM_MALLOC,
        {
                .name   = "iomem_align",
                .alias  = "mem_align",
 +              .lname  = "I/O memory alignment",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(mem_align),
                .minval = 0,
                .help   = "IO memory buffer offset alignment",
                .def    = "0",
                .parent = "iomem",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "verify",
 +              .lname  = "Verify",
                .type   = FIO_OPT_STR,
                .off1   = td_var_offset(verify),
                .help   = "Verify data written",
 -              .cb     = str_verify_cb,
                .def    = "0",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_VERIFY,
                .posval = {
                          { .ival = "0",
                            .oval = VERIFY_NONE,
        },
        {
                .name   = "do_verify",
 +              .lname  = "Perform verify step",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(do_verify),
                .help   = "Run verification stage after write",
                .def    = "1",
                .parent = "verify",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_VERIFY,
        },
        {
                .name   = "verifysort",
 +              .lname  = "Verify sort",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(verifysort),
                .help   = "Sort written verify blocks for read back",
                .def    = "1",
                .parent = "verify",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_VERIFY,
        },
        {
                .name   = "verify_interval",
 +              .lname  = "Verify interval",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(verify_interval),
                .minval = 2 * sizeof(struct verify_header),
                .help   = "Store verify buffer header every N bytes",
                .parent = "verify",
 +              .hide   = 1,
 +              .interval = 2 * sizeof(struct verify_header),
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_VERIFY,
        },
        {
                .name   = "verify_offset",
 +              .lname  = "Verify offset",
                .type   = FIO_OPT_INT,
                .help   = "Offset verify header location by N bytes",
 -              .def    = "0",
 -              .cb     = str_verify_offset_cb,
 +              .off1   = td_var_offset(verify_offset),
 +              .minval = sizeof(struct verify_header),
                .parent = "verify",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_VERIFY,
        },
        {
                .name   = "verify_pattern",
 +              .lname  = "Verify pattern",
                .type   = FIO_OPT_STR,
                .cb     = str_verify_pattern_cb,
                .help   = "Fill pattern for IO buffers",
                .parent = "verify",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_VERIFY,
        },
        {
                .name   = "verify_fatal",
 +              .lname  = "Verify fatal",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(verify_fatal),
                .def    = "0",
                .help   = "Exit on a single verify failure, don't continue",
                .parent = "verify",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_VERIFY,
        },
        {
                .name   = "verify_dump",
 +              .lname  = "Verify dump",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(verify_dump),
                .def    = "0",
                .help   = "Dump contents of good and bad blocks on failure",
                .parent = "verify",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_VERIFY,
        },
        {
                .name   = "verify_async",
 +              .lname  = "Verify asynchronously",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(verify_async),
                .def    = "0",
                .help   = "Number of async verifier threads to use",
                .parent = "verify",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_VERIFY,
        },
        {
                .name   = "verify_backlog",
 +              .lname  = "Verify backlog",
                .type   = FIO_OPT_STR_VAL,
                .off1   = td_var_offset(verify_backlog),
                .help   = "Verify after this number of blocks are written",
                .parent = "verify",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_VERIFY,
        },
        {
                .name   = "verify_backlog_batch",
 +              .lname  = "Verify backlog batch",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(verify_batch),
                .help   = "Verify this number of IO blocks",
                .parent = "verify",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_VERIFY,
        },
  #ifdef FIO_HAVE_CPU_AFFINITY
        {
                .name   = "verify_async_cpus",
 +              .lname  = "Async verify CPUs",
                .type   = FIO_OPT_STR,
                .cb     = str_verify_cpus_allowed_cb,
                .help   = "Set CPUs allowed for async verify threads",
                .parent = "verify_async",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_VERIFY,
        },
  #endif
  #ifdef FIO_HAVE_TRIM
        {
                .name   = "trim_percentage",
 +              .lname  = "Trim percentage",
                .type   = FIO_OPT_INT,
 -              .cb     = str_verify_trim_cb,
 +              .off1   = td_var_offset(trim_percentage),
 +              .minval = 0,
                .maxval = 100,
                .help   = "Number of verify blocks to discard/trim",
                .parent = "verify",
                .def    = "0",
 +              .interval = 1,
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_TRIM,
        },
        {
                .name   = "trim_verify_zero",
 -              .type   = FIO_OPT_INT,
 +              .lname  = "Verify trim zero",
 +              .type   = FIO_OPT_BOOL,
                .help   = "Verify that trim/discarded blocks are returned as zeroes",
                .off1   = td_var_offset(trim_zero),
                .parent = "trim_percentage",
 +              .hide   = 1,
                .def    = "1",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_TRIM,
        },
        {
                .name   = "trim_backlog",
 +              .lname  = "Trim backlog",
                .type   = FIO_OPT_STR_VAL,
                .off1   = td_var_offset(trim_backlog),
                .help   = "Trim after this number of blocks are written",
                .parent = "trim_percentage",
 +              .hide   = 1,
 +              .interval = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_TRIM,
        },
        {
                .name   = "trim_backlog_batch",
 +              .lname  = "Trim backlog batch",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(trim_batch),
                .help   = "Trim this number of IO blocks",
                .parent = "trim_percentage",
 +              .hide   = 1,
 +              .interval = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_TRIM,
        },
  #endif
        {
                .name   = "write_iolog",
 +              .lname  = "Write I/O log",
                .type   = FIO_OPT_STR_STORE,
                .off1   = td_var_offset(write_iolog_file),
                .help   = "Store IO pattern to file",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IOLOG,
        },
        {
                .name   = "read_iolog",
 +              .lname  = "Read I/O log",
                .type   = FIO_OPT_STR_STORE,
                .off1   = td_var_offset(read_iolog_file),
                .help   = "Playback IO pattern from file",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IOLOG,
        },
        {
                .name   = "replay_no_stall",
 -              .type   = FIO_OPT_INT,
 +              .lname  = "Don't stall on replay",
 +              .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(no_stall),
                .def    = "0",
                .parent = "read_iolog",
 +              .hide   = 1,
                .help   = "Playback IO pattern file as fast as possible without stalls",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IOLOG,
        },
        {
                .name   = "replay_redirect",
 +              .lname  = "Redirect device for replay",
                .type   = FIO_OPT_STR_STORE,
                .off1   = td_var_offset(replay_redirect),
                .parent = "read_iolog",
 +              .hide   = 1,
                .help   = "Replay all I/O onto this device, regardless of trace device",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IOLOG,
        },
        {
                .name   = "exec_prerun",
 +              .lname  = "Pre-execute runnable",
                .type   = FIO_OPT_STR_STORE,
                .off1   = td_var_offset(exec_prerun),
                .help   = "Execute this file prior to running job",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "exec_postrun",
 +              .lname  = "Post-execute runnable",
                .type   = FIO_OPT_STR_STORE,
                .off1   = td_var_offset(exec_postrun),
                .help   = "Execute this file after running job",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_INVALID,
        },
  #ifdef FIO_HAVE_IOSCHED_SWITCH
        {
                .name   = "ioscheduler",
 +              .lname  = "I/O scheduler",
                .type   = FIO_OPT_STR_STORE,
                .off1   = td_var_offset(ioscheduler),
                .help   = "Use this IO scheduler on the backing device",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
  #endif
        {
                .name   = "zonesize",
 +              .lname  = "Zone size",
                .type   = FIO_OPT_STR_VAL,
                .off1   = td_var_offset(zone_size),
                .help   = "Amount of data to read per zone",
                .def    = "0",
 +              .interval = 1024 * 1024,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_ZONE,
        },
        {
                .name   = "zonerange",
 +              .lname  = "Zone range",
                .type   = FIO_OPT_STR_VAL,
                .off1   = td_var_offset(zone_range),
                .help   = "Give size of an IO zone",
                .def    = "0",
 +              .interval = 1024 * 1024,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_ZONE,
        },
        {
                .name   = "zoneskip",
 +              .lname  = "Zone skip",
                .type   = FIO_OPT_STR_VAL,
                .off1   = td_var_offset(zone_skip),
                .help   = "Space between IO zones",
                .def    = "0",
 +              .interval = 1024 * 1024,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_ZONE,
        },
        {
                .name   = "lockmem",
 +              .lname  = "Lock memory",
                .type   = FIO_OPT_STR_VAL,
 -              .cb     = str_lockmem_cb,
 +              .off1   = td_var_offset(lockmem),
                .help   = "Lock down this amount of memory",
                .def    = "0",
 +              .interval = 1024 * 1024,
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "rwmixread",
 +              .lname  = "Read/write mix read",
                .type   = FIO_OPT_INT,
                .cb     = str_rwmix_read_cb,
                .maxval = 100,
                .help   = "Percentage of mixed workload that is reads",
                .def    = "50",
 +              .interval = 5,
 +              .inverse = "rwmixwrite",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_RWMIX,
        },
        {
                .name   = "rwmixwrite",
 +              .lname  = "Read/write mix write",
                .type   = FIO_OPT_INT,
                .cb     = str_rwmix_write_cb,
                .maxval = 100,
                .help   = "Percentage of mixed workload that is writes",
                .def    = "50",
 +              .interval = 5,
 +              .inverse = "rwmixread",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_RWMIX,
        },
        {
                .name   = "rwmixcycle",
 +              .lname  = "Read/write mix cycle",
                .type   = FIO_OPT_DEPRECATED,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_RWMIX,
        },
        {
                .name   = "nice",
 +              .lname  = "Nice",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(nice),
                .help   = "Set job CPU nice value",
                .minval = -19,
                .maxval = 20,
                .def    = "0",
 +              .interval = 1,
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_CRED,
        },
  #ifdef FIO_HAVE_IOPRIO
        {
                .name   = "prio",
 +              .lname  = "I/O nice priority",
                .type   = FIO_OPT_INT,
 -              .cb     = str_prio_cb,
 +              .off1   = td_var_offset(ioprio),
                .help   = "Set job IO priority value",
                .minval = 0,
                .maxval = 7,
 +              .interval = 1,
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_CRED,
        },
        {
                .name   = "prioclass",
 +              .lname  = "I/O nice priority class",
                .type   = FIO_OPT_INT,
 -              .cb     = str_prioclass_cb,
 +              .off1   = td_var_offset(ioprio_class),
                .help   = "Set job IO priority class",
                .minval = 0,
                .maxval = 3,
 +              .interval = 1,
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_CRED,
        },
  #endif
        {
                .name   = "thinktime",
 +              .lname  = "Thinktime",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(thinktime),
                .help   = "Idle time between IO buffers (usec)",
                .def    = "0",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_THINKTIME,
        },
        {
                .name   = "thinktime_spin",
 +              .lname  = "Thinktime spin",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(thinktime_spin),
                .help   = "Start think time by spinning this amount (usec)",
                .def    = "0",
                .parent = "thinktime",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_THINKTIME,
        },
        {
                .name   = "thinktime_blocks",
 +              .lname  = "Thinktime blocks",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(thinktime_blocks),
                .help   = "IO buffer period between 'thinktime'",
                .def    = "1",
                .parent = "thinktime",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_THINKTIME,
        },
        {
                .name   = "rate",
 +              .lname  = "I/O rate",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(rate[0]),
                .off2   = td_var_offset(rate[1]),
                .help   = "Set bandwidth rate",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_RATE,
        },
        {
                .name   = "ratemin",
 +              .lname  = "I/O min rate",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(ratemin[0]),
                .off2   = td_var_offset(ratemin[1]),
                .help   = "Job must meet this rate or it will be shutdown",
                .parent = "rate",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_RATE,
        },
        {
                .name   = "rate_iops",
 +              .lname  = "I/O rate IOPS",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(rate_iops[0]),
                .off2   = td_var_offset(rate_iops[1]),
                .help   = "Limit IO used to this number of IO operations/sec",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_RATE,
        },
        {
                .name   = "rate_iops_min",
 +              .lname  = "I/O min rate IOPS",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(rate_iops_min[0]),
                .off2   = td_var_offset(rate_iops_min[1]),
                .help   = "Job must meet this rate or it will be shut down",
                .parent = "rate_iops",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_RATE,
        },
        {
                .name   = "ratecycle",
 +              .lname  = "I/O rate cycle",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(ratecycle),
                .help   = "Window average for rate limits (msec)",
                .def    = "1000",
                .parent = "rate",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_RATE,
        },
        {
                .name   = "invalidate",
 +              .lname  = "Cache invalidate",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(invalidate_cache),
                .help   = "Invalidate buffer/page cache prior to running job",
                .def    = "1",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_TYPE,
        },
        {
                .name   = "sync",
 +              .lname  = "Synchronous I/O",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(sync_io),
                .help   = "Use O_SYNC for buffered writes",
                .def    = "0",
                .parent = "buffered",
 -      },
 -      {
 -              .name   = "bwavgtime",
 -              .type   = FIO_OPT_INT,
 -              .off1   = td_var_offset(bw_avg_time),
 -              .help   = "Time window over which to calculate bandwidth"
 -                        " (msec)",
 -              .def    = "500",
 -              .parent = "write_bw_log",
 -      },
 -      {
 -              .name   = "iopsavgtime",
 -              .type   = FIO_OPT_INT,
 -              .off1   = td_var_offset(iops_avg_time),
 -              .help   = "Time window over which to calculate IOPS (msec)",
 -              .def    = "500",
 -              .parent = "write_iops_log",
 +              .hide   = 1,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_TYPE,
        },
        {
                .name   = "create_serialize",
 +              .lname  = "Create serialize",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(create_serialize),
                .help   = "Serialize creating of job files",
                .def    = "1",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "create_fsync",
 +              .lname  = "Create fsync",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(create_fsync),
                .help   = "fsync file after creation",
                .def    = "1",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "create_on_open",
 +              .lname  = "Create on open",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(create_on_open),
                .help   = "Create files when they are opened for IO",
                .def    = "0",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
+       {
+               .name   = "create_only",
+               .type   = FIO_OPT_BOOL,
+               .off1   = td_var_offset(create_only),
+               .help   = "Only perform file creation phase",
+               .def    = "0",
+       },
        {
                .name   = "pre_read",
 +              .lname  = "Pre-read files",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(pre_read),
                .help   = "Pre-read files before starting official testing",
                .def    = "0",
 -      },
 -      {
 -              .name   = "cpuload",
 -              .type   = FIO_OPT_INT,
 -              .off1   = td_var_offset(cpuload),
 -              .help   = "Use this percentage of CPU",
 -      },
 -      {
 -              .name   = "cpuchunks",
 -              .type   = FIO_OPT_INT,
 -              .off1   = td_var_offset(cpucycle),
 -              .help   = "Length of the CPU burn cycles (usecs)",
 -              .def    = "50000",
 -              .parent = "cpuload",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
  #ifdef FIO_HAVE_CPU_AFFINITY
        {
                .name   = "cpumask",
 +              .lname  = "CPU mask",
                .type   = FIO_OPT_INT,
                .cb     = str_cpumask_cb,
                .help   = "CPU affinity mask",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_CRED,
        },
        {
                .name   = "cpus_allowed",
 +              .lname  = "CPUs allowed",
                .type   = FIO_OPT_STR,
                .cb     = str_cpus_allowed_cb,
                .help   = "Set CPUs allowed",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_CRED,
        },
  #endif
        {
                .name   = "end_fsync",
 +              .lname  = "End fsync",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(end_fsync),
                .help   = "Include fsync at the end of job",
                .def    = "0",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "fsync_on_close",
 +              .lname  = "Fsync on close",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(fsync_on_close),
                .help   = "fsync files on close",
                .def    = "0",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "unlink",
 +              .lname  = "Unlink file",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(unlink),
                .help   = "Unlink created files after job has completed",
                .def    = "0",
 +              .category = FIO_OPT_C_FILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "exitall",
 +              .lname  = "Exit-all on terminate",
                .type   = FIO_OPT_STR_SET,
                .cb     = str_exitall_cb,
                .help   = "Terminate all jobs when one exits",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_PROCESS,
        },
        {
                .name   = "stonewall",
 +              .lname  = "Wait for previous",
                .alias  = "wait_for_previous",
                .type   = FIO_OPT_STR_SET,
                .off1   = td_var_offset(stonewall),
                .help   = "Insert a hard barrier between this job and previous",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_PROCESS,
        },
        {
                .name   = "new_group",
 +              .lname  = "New group",
                .type   = FIO_OPT_STR_SET,
                .off1   = td_var_offset(new_group),
                .help   = "Mark the start of a new group (for reporting)",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_PROCESS,
        },
        {
                .name   = "thread",
 +              .lname  = "Thread",
                .type   = FIO_OPT_STR_SET,
                .off1   = td_var_offset(use_thread),
 -              .help   = "Use threads instead of forks",
 +              .help   = "Use threads instead of processes",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_PROCESS,
        },
        {
                .name   = "write_bw_log",
 -              .type   = FIO_OPT_STR,
 -              .off1   = td_var_offset(write_bw_log),
 -              .cb     = str_write_bw_log_cb,
 +              .lname  = "Write bandwidth log",
 +              .type   = FIO_OPT_STR_STORE,
 +              .off1   = td_var_offset(bw_log_file),
                .help   = "Write log of bandwidth during run",
 +              .category = FIO_OPT_C_LOG,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "write_lat_log",
 -              .type   = FIO_OPT_STR,
 -              .off1   = td_var_offset(write_lat_log),
 -              .cb     = str_write_lat_log_cb,
 +              .lname  = "Write latency log",
 +              .type   = FIO_OPT_STR_STORE,
 +              .off1   = td_var_offset(lat_log_file),
                .help   = "Write log of latency during run",
 +              .category = FIO_OPT_C_LOG,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "write_iops_log",
 +              .lname  = "Write IOPS log",
                .type   = FIO_OPT_STR,
 -              .off1   = td_var_offset(write_iops_log),
 -              .cb     = str_write_iops_log_cb,
 +              .off1   = td_var_offset(iops_log_file),
                .help   = "Write log of IOPS during run",
 +              .category = FIO_OPT_C_LOG,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "log_avg_msec",
 +              .lname  = "Log averaging (msec)",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(log_avg_msec),
                .help   = "Average bw/iops/lat logs over this period of time",
                .def    = "0",
 +              .category = FIO_OPT_C_LOG,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
 -              .name   = "hugepage-size",
 +              .name   = "bwavgtime",
 +              .lname  = "Bandwidth average time",
                .type   = FIO_OPT_INT,
 -              .off1   = td_var_offset(hugepage_size),
 -              .help   = "When using hugepages, specify size of each page",
 -              .def    = __fio_stringify(FIO_HUGE_PAGE),
 +              .off1   = td_var_offset(bw_avg_time),
 +              .help   = "Time window over which to calculate bandwidth"
 +                        " (msec)",
 +              .def    = "500",
 +              .parent = "write_bw_log",
 +              .hide   = 1,
 +              .interval = 100,
 +              .category = FIO_OPT_C_LOG,
 +              .group  = FIO_OPT_G_INVALID,
 +      },
 +      {
 +              .name   = "iopsavgtime",
 +              .lname  = "IOPS average time",
 +              .type   = FIO_OPT_INT,
 +              .off1   = td_var_offset(iops_avg_time),
 +              .help   = "Time window over which to calculate IOPS (msec)",
 +              .def    = "500",
 +              .parent = "write_iops_log",
 +              .hide   = 1,
 +              .interval = 100,
 +              .category = FIO_OPT_C_LOG,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "group_reporting",
 -              .type   = FIO_OPT_STR_SET,
 +              .lname  = "Group reporting",
 +              .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(group_reporting),
                .help   = "Do reporting on a per-group basis",
 +              .def    = "1",
 +              .category = FIO_OPT_C_STAT,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "zero_buffers",
 +              .lname  = "Zero I/O buffers",
                .type   = FIO_OPT_STR_SET,
                .off1   = td_var_offset(zero_buffers),
                .help   = "Init IO buffers to all zeroes",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_BUF,
        },
        {
                .name   = "refill_buffers",
 +              .lname  = "Refill I/O buffers",
                .type   = FIO_OPT_STR_SET,
                .off1   = td_var_offset(refill_buffers),
                .help   = "Refill IO buffers on every IO submit",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_BUF,
        },
        {
                .name   = "scramble_buffers",
 +              .lname  = "Scramble I/O buffers",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(scramble_buffers),
                .help   = "Slightly scramble buffers on every IO submit",
                .def    = "1",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_BUF,
        },
        {
                .name   = "buffer_compress_percentage",
 +              .lname  = "Buffer compression percentage",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(compress_percentage),
                .maxval = 100,
                .minval = 1,
                .help   = "How compressible the buffer is (approximately)",
 +              .interval = 5,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_BUF,
        },
        {
                .name   = "buffer_compress_chunk",
 +              .lname  = "Buffer compression chunk size",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(compress_chunk),
                .parent = "buffer_compress_percentage",
 +              .hide   = 1,
                .help   = "Size of compressible region in buffer",
 +              .interval = 256,
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_BUF,
        },
        {
                .name   = "clat_percentiles",
 +              .lname  = "Completion latency percentiles",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(clat_percentiles),
                .help   = "Enable the reporting of completion latency percentiles",
                .def    = "1",
 +              .category = FIO_OPT_C_STAT,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "percentile_list",
 +              .lname  = "Completion latency percentile list",
                .type   = FIO_OPT_FLOAT_LIST,
                .off1   = td_var_offset(percentile_list),
                .off2   = td_var_offset(overwrite_plist),
                .maxlen = FIO_IO_U_LIST_MAX_LEN,
                .minfp  = 0.0,
                .maxfp  = 100.0,
 +              .category = FIO_OPT_C_STAT,
 +              .group  = FIO_OPT_G_INVALID,
        },
  
  #ifdef FIO_HAVE_DISK_UTIL
        {
                .name   = "disk_util",
 +              .lname  = "Disk utilization",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(do_disk_util),
                .help   = "Log disk utilization statistics",
                .def    = "1",
 +              .category = FIO_OPT_C_STAT,
 +              .group  = FIO_OPT_G_INVALID,
        },
  #endif
        {
                .name   = "gtod_reduce",
 +              .lname  = "Reduce gettimeofday() calls",
                .type   = FIO_OPT_BOOL,
                .help   = "Greatly reduce number of gettimeofday() calls",
                .cb     = str_gtod_reduce_cb,
                .def    = "0",
 +              .hide_on_set = 1,
 +              .category = FIO_OPT_C_STAT,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "disable_lat",
 +              .lname  = "Disable all latency stats",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(disable_lat),
                .help   = "Disable latency numbers",
                .parent = "gtod_reduce",
 +              .hide   = 1,
                .def    = "0",
 +              .category = FIO_OPT_C_STAT,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "disable_clat",
 +              .lname  = "Disable completion latency stats",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(disable_clat),
                .help   = "Disable completion latency numbers",
                .parent = "gtod_reduce",
 +              .hide   = 1,
                .def    = "0",
 +              .category = FIO_OPT_C_STAT,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "disable_slat",
 +              .lname  = "Disable submission latency stats",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(disable_slat),
                .help   = "Disable submission latency numbers",
                .parent = "gtod_reduce",
 +              .hide   = 1,
                .def    = "0",
 +              .category = FIO_OPT_C_STAT,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "disable_bw_measurement",
 +              .lname  = "Disable bandwidth stats",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(disable_bw),
                .help   = "Disable bandwidth logging",
                .parent = "gtod_reduce",
 +              .hide   = 1,
                .def    = "0",
 +              .category = FIO_OPT_C_STAT,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "gtod_cpu",
 +              .lname  = "Dedicated gettimeofday() CPU",
                .type   = FIO_OPT_INT,
                .cb     = str_gtod_cpu_cb,
                .help   = "Set up dedicated gettimeofday() thread on this CPU",
                .verify = gtod_cpu_verify,
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_CLOCK,
        },
        {
                .name   = "continue_on_error",
 +              .lname  = "Continue on error",
                .type   = FIO_OPT_STR,
                .off1   = td_var_offset(continue_on_error),
                .help   = "Continue on non-fatal errors during IO",
                .def    = "none",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_INVALID,
                .posval = {
                          { .ival = "none",
                            .oval = ERROR_TYPE_NONE,
        },
        {
                .name   = "profile",
 +              .lname  = "Profile",
                .type   = FIO_OPT_STR_STORE,
                .off1   = td_var_offset(profile),
                .help   = "Select a specific builtin performance test",
 +              .category = FIO_OPT_C_PROFILE,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "cgroup",
 +              .lname  = "Cgroup",
                .type   = FIO_OPT_STR_STORE,
                .off1   = td_var_offset(cgroup),
                .help   = "Add job to cgroup of this name",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_CGROUP,
 +      },
 +      {
 +              .name   = "cgroup_nodelete",
 +              .lname  = "Cgroup no-delete",
 +              .type   = FIO_OPT_BOOL,
 +              .off1   = td_var_offset(cgroup_nodelete),
 +              .help   = "Do not delete cgroups after job completion",
 +              .def    = "0",
 +              .parent = "cgroup",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_CGROUP,
        },
        {
                .name   = "cgroup_weight",
 +              .lname  = "Cgroup weight",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(cgroup_weight),
                .help   = "Use given weight for cgroup",
                .minval = 100,
                .maxval = 1000,
 -      },
 -      {
 -              .name   = "cgroup_nodelete",
 -              .type   = FIO_OPT_BOOL,
 -              .off1   = td_var_offset(cgroup_nodelete),
 -              .help   = "Do not delete cgroups after job completion",
 -              .def    = "0",
 +              .parent = "cgroup",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_CGROUP,
        },
        {
                .name   = "uid",
 +              .lname  = "User ID",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(uid),
                .help   = "Run job with this user ID",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_CRED,
        },
        {
                .name   = "gid",
 +              .lname  = "Group ID",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(gid),
                .help   = "Run job with this group ID",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_CRED,
 +      },
 +      {
 +              .name   = "kb_base",
 +              .lname  = "KB Base",
 +              .type   = FIO_OPT_INT,
 +              .off1   = td_var_offset(kb_base),
 +              .verify = kb_base_verify,
 +              .prio   = 1,
 +              .def    = "1024",
 +              .help   = "How many bytes per KB for reporting (1000 or 1024)",
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_INVALID,
 +      },
 +      {
 +              .name   = "hugepage-size",
 +              .lname  = "Hugepage size",
 +              .type   = FIO_OPT_INT,
 +              .off1   = td_var_offset(hugepage_size),
 +              .help   = "When using hugepages, specify size of each page",
 +              .def    = __fio_stringify(FIO_HUGE_PAGE),
 +              .interval = 1024 * 1024,
 +              .category = FIO_OPT_C_GENERAL,
 +              .group  = FIO_OPT_G_INVALID,
        },
        {
                .name   = "flow_id",
 +              .lname  = "I/O flow ID",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(flow_id),
                .help   = "The flow index ID to use",
                .def    = "0",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_FLOW,
        },
        {
                .name   = "flow",
 +              .lname  = "I/O flow weight",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(flow),
                .help   = "Weight for flow control of this job",
                .parent = "flow_id",
 +              .hide   = 1,
                .def    = "0",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_FLOW,
        },
        {
                .name   = "flow_watermark",
 +              .lname  = "I/O flow watermark",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(flow_watermark),
                .help   = "High watermark for flow control. This option"
                        " should be set to the same value for all threads"
                        " with non-zero flow.",
                .parent = "flow_id",
 +              .hide   = 1,
                .def    = "1024",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_FLOW,
        },
        {
                .name   = "flow_sleep",
 +              .lname  = "I/O flow sleep",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(flow_sleep),
                .help   = "How many microseconds to sleep after being held"
                        " back by the flow control mechanism",
                .parent = "flow_id",
 +              .hide   = 1,
                .def    = "0",
 +              .category = FIO_OPT_C_IO,
 +              .group  = FIO_OPT_G_IO_FLOW,
        },
        {
                .name = NULL,
@@@ -2785,13 -2296,13 +2792,13 @@@ void fio_options_dup_and_init(struct op
  {
        unsigned int i;
  
 -      options_init(options);
 +      options_init(fio_options);
  
        i = 0;
        while (long_options[i].name)
                i++;
  
 -      options_to_lopts(options, long_options, i, FIO_GETOPT_JOB);
 +      options_to_lopts(fio_options, long_options, i, FIO_GETOPT_JOB);
  }
  
  struct fio_keyword {
@@@ -2874,12 -2385,14 +2881,12 @@@ static char *bc_calc(char *str
  
        sprintf(buf, "echo '%s' | %s", tmp, BC_APP);
        f = popen(buf, "r");
 -      if (!f) {
 +      if (!f)
                return NULL;
 -      }
  
        ret = fread(&buf[tmp - str], 1, 128 - (tmp - str), f);
 -      if (ret <= 0) {
 +      if (ret <= 0)
                return NULL;
 -      }
  
        pclose(f);
        buf[(tmp - str) + ret - 1] = '\0';
@@@ -3012,13 -2525,13 +3019,13 @@@ int fio_options_parse(struct thread_dat
        int i, ret, unknown;
        char **opts_copy;
  
 -      sort_options(opts, options, num_opts);
 +      sort_options(opts, fio_options, num_opts);
        opts_copy = dup_and_sub_options(opts, num_opts);
  
        for (ret = 0, i = 0, unknown = 0; i < num_opts; i++) {
                struct fio_option *o;
 -              int newret = parse_option(opts_copy[i], opts[i], options, &o,
 -                                        td);
 +              int newret = parse_option(opts_copy[i], opts[i], fio_options,
 +                                              &o, td);
  
                if (opts_copy[i]) {
                        if (newret && !o) {
  
  int fio_cmd_option_parse(struct thread_data *td, const char *opt, char *val)
  {
 -      return parse_cmd_option(opt, val, options, td);
 +      return parse_cmd_option(opt, val, fio_options, td);
  }
  
  int fio_cmd_ioengine_option_parse(struct thread_data *td, const char *opt,
  
  void fio_fill_default_options(struct thread_data *td)
  {
 -      fill_default_options(td, options);
 +      fill_default_options(td, fio_options);
  }
  
  int fio_show_option_help(const char *opt)
  {
 -      return show_cmd_help(options, opt);
 +      return show_cmd_help(fio_options, opt);
  }
  
  void options_mem_dupe(void *data, struct fio_option *options)
   */
  void fio_options_mem_dupe(struct thread_data *td)
  {
 -      options_mem_dupe(&td->o, options);
 +      options_mem_dupe(&td->o, fio_options);
  
        if (td->eo && td->io_ops) {
                void *oldeo = td->eo;
  
  unsigned int fio_get_kb_base(void *data)
  {
 -      struct thread_data *td = data;
 +      struct thread_options *o = data;
        unsigned int kb_base = 0;
  
 -      if (td)
 -              kb_base = td->o.kb_base;
 +      if (o)
 +              kb_base = o->kb_base;
        if (!kb_base)
                kb_base = 1024;
  
@@@ -3132,13 -2645,13 +3139,13 @@@ int add_option(struct fio_option *o
        struct fio_option *__o;
        int opt_index = 0;
  
 -      __o = options;
 +      __o = fio_options;
        while (__o->name) {
                opt_index++;
                __o++;
        }
  
 -      memcpy(&options[opt_index], o, sizeof(*o));
 +      memcpy(&fio_options[opt_index], o, sizeof(*o));
        return 0;
  }
  
@@@ -3146,7 -2659,7 +3153,7 @@@ void invalidate_profile_options(const c
  {
        struct fio_option *o;
  
 -      o = options;
 +      o = fio_options;
        while (o->name) {
                if (o->prof_name && !strcmp(o->prof_name, prof_name)) {
                        o->type = FIO_OPT_INVALID;
@@@ -3161,7 -2674,7 +3168,7 @@@ void add_opt_posval(const char *optname
        struct fio_option *o;
        unsigned int i;
  
 -      o = find_option(options, optname);
 +      o = find_option(fio_options, optname);
        if (!o)
                return;
  
@@@ -3180,7 -2693,7 +3187,7 @@@ void del_opt_posval(const char *optname
        struct fio_option *o;
        unsigned int i;
  
 -      o = find_option(options, optname);
 +      o = find_option(fio_options, optname);
        if (!o)
                return;
  
  
  void fio_options_free(struct thread_data *td)
  {
 -      options_free(options, td);
 +      options_free(fio_options, td);
        if (td->eo && td->io_ops && td->io_ops->options) {
                options_free(td->io_ops->options, td->eo);
                free(td->eo);
                td->eo = NULL;
        }
  }
 +
 +struct fio_option *fio_option_find(const char *name)
 +{
 +      return find_option(fio_options, name);
 +}
 +
diff --combined stat.c
index eff1a27e4d135acae099bca57513a980f935b44b,8c846f666f431e9a80d5930f1939df42f32020c4..ee495ffd88dc5dae82f92717deda18e59ef8bd57
--- 1/stat.c
--- 2/stat.c
+++ b/stat.c
@@@ -63,12 -63,12 +63,12 @@@ static unsigned int plat_val_to_idx(uns
  
        /*
         * Discard the error bits and apply the mask to find the
 -         * index for the buckets in the group
 +       * index for the buckets in the group
         */
        offset = (FIO_IO_U_PLAT_VAL - 1) & (val >> error_bits);
  
        /* Make sure the index does not exceed (array size - 1) */
 -      idx = (base + offset) < (FIO_IO_U_PLAT_NR - 1)?
 +      idx = (base + offset) < (FIO_IO_U_PLAT_NR - 1) ?
                (base + offset) : (FIO_IO_U_PLAT_NR - 1);
  
        return idx;
@@@ -86,11 -86,11 +86,11 @@@ static unsigned int plat_idx_to_val(uns
  
        /* MSB <= (FIO_IO_U_PLAT_BITS-1), cannot be rounded off. Use
         * all bits of the sample as index */
 -      if (idx < (FIO_IO_U_PLAT_VAL << 1) )
 +      if (idx < (FIO_IO_U_PLAT_VAL << 1))
                return idx;
  
        /* Find the group and compute the minimum value of that group */
 -      error_bits = (idx >> FIO_IO_U_PLAT_BITS) -1;
 +      error_bits = (idx >> FIO_IO_U_PLAT_BITS) - 1;
        base = 1 << (error_bits + FIO_IO_U_PLAT_BITS);
  
        /* Find its bucket number of the group */
@@@ -114,9 -114,11 +114,9 @@@ static int double_cmp(const void *a, co
        return cmp;
  }
  
 -static unsigned int calc_clat_percentiles(unsigned int *io_u_plat,
 -                                        unsigned long nr, fio_fp64_t *plist,
 -                                        unsigned int **output,
 -                                        unsigned int *maxv,
 -                                        unsigned int *minv)
 +unsigned int calc_clat_percentiles(unsigned int *io_u_plat, unsigned long nr,
 +                                 fio_fp64_t *plist, unsigned int **output,
 +                                 unsigned int *maxv, unsigned int *minv)
  {
        unsigned long sum = 0;
        unsigned int len, i, j = 0;
         * isn't a worry. Also note that this does not work for NaN values.
         */
        if (len > 1)
 -              qsort((void*)plist, len, sizeof(plist[0]), double_cmp);
 +              qsort((void *)plist, len, sizeof(plist[0]), double_cmp);
  
        /*
         * Calculate bucket values, note down max and min values
@@@ -232,8 -234,8 +232,8 @@@ out
                free(ovals);
  }
  
 -static int calc_lat(struct io_stat *is, unsigned long *min, unsigned long *max,
 -                  double *mean, double *dev)
 +int calc_lat(struct io_stat *is, unsigned long *min, unsigned long *max,
 +           double *mean, double *dev)
  {
        double n = is->samples;
  
@@@ -285,7 -287,11 +285,7 @@@ void show_group_stats(struct group_run_
        }
  }
  
 -#define ts_total_io_u(ts)     \
 -      ((ts)->total_io_u[0] + (ts)->total_io_u[1])
 -
 -static void stat_calc_dist(unsigned int *map, unsigned long total,
 -                         double *io_u_dist)
 +void stat_calc_dist(unsigned int *map, unsigned long total, double *io_u_dist)
  {
        int i;
  
@@@ -323,33 -329,28 +323,33 @@@ static void stat_calc_lat(struct thread
        }
  }
  
 -static void stat_calc_lat_u(struct thread_stat *ts, double *io_u_lat)
 +void stat_calc_lat_u(struct thread_stat *ts, double *io_u_lat)
  {
        stat_calc_lat(ts, io_u_lat, ts->io_u_lat_u, FIO_IO_U_LAT_U_NR);
  }
  
 -static void stat_calc_lat_m(struct thread_stat *ts, double *io_u_lat)
 +void stat_calc_lat_m(struct thread_stat *ts, double *io_u_lat)
  {
        stat_calc_lat(ts, io_u_lat, ts->io_u_lat_m, FIO_IO_U_LAT_M_NR);
  }
  
 -static int usec_to_msec(unsigned long *min, unsigned long *max, double *mean,
 -                      double *dev)
 +static void display_lat(const char *name, unsigned long min, unsigned long max,
 +                      double mean, double dev)
  {
 -      if (*min > 1000 && *max > 1000 && *mean > 1000.0 && *dev > 1000.0) {
 -              *min /= 1000;
 -              *max /= 1000;
 -              *mean /= 1000.0;
 -              *dev /= 1000.0;
 -              return 0;
 -      }
 +      const char *base = "(usec)";
 +      char *minp, *maxp;
  
 -      return 1;
 +      if (!usec_to_msec(&min, &max, &mean, &dev))
 +              base = "(msec)";
 +
 +      minp = num2str(min, 6, 1, 0);
 +      maxp = num2str(max, 6, 1, 0);
 +
 +      log_info("    %s %s: min=%s, max=%s, avg=%5.02f,"
 +               " stdev=%5.02f\n", name, base, minp, maxp, mean, dev);
 +
 +      free(minp);
 +      free(maxp);
  }
  
  static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts,
        free(bw_p);
        free(iops_p);
  
 -      if (calc_lat(&ts->slat_stat[ddir], &min, &max, &mean, &dev)) {
 -              const char *base = "(usec)";
 -              char *minp, *maxp;
 -
 -              if (!usec_to_msec(&min, &max, &mean, &dev))
 -                      base = "(msec)";
 -
 -              minp = num2str(min, 6, 1, 0);
 -              maxp = num2str(max, 6, 1, 0);
 -
 -              log_info("    slat %s: min=%s, max=%s, avg=%5.02f,"
 -                       " stdev=%5.02f\n", base, minp, maxp, mean, dev);
 -
 -              free(minp);
 -              free(maxp);
 -      }
 -      if (calc_lat(&ts->clat_stat[ddir], &min, &max, &mean, &dev)) {
 -              const char *base = "(usec)";
 -              char *minp, *maxp;
 -
 -              if (!usec_to_msec(&min, &max, &mean, &dev))
 -                      base = "(msec)";
 -
 -              minp = num2str(min, 6, 1, 0);
 -              maxp = num2str(max, 6, 1, 0);
 -
 -              log_info("    clat %s: min=%s, max=%s, avg=%5.02f,"
 -                       " stdev=%5.02f\n", base, minp, maxp, mean, dev);
 -
 -              free(minp);
 -              free(maxp);
 -      }
 -      if (calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev)) {
 -              const char *base = "(usec)";
 -              char *minp, *maxp;
 -
 -              if (!usec_to_msec(&min, &max, &mean, &dev))
 -                      base = "(msec)";
 -
 -              minp = num2str(min, 6, 1, 0);
 -              maxp = num2str(max, 6, 1, 0);
 -
 -              log_info("     lat %s: min=%s, max=%s, avg=%5.02f,"
 -                       " stdev=%5.02f\n", base, minp, maxp, mean, dev);
 +      if (calc_lat(&ts->slat_stat[ddir], &min, &max, &mean, &dev))
 +              display_lat("slat", min, max, mean, dev);
 +      if (calc_lat(&ts->clat_stat[ddir], &min, &max, &mean, &dev))
 +              display_lat("clat", min, max, mean, dev);
 +      if (calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev))
 +              display_lat(" lat", min, max, mean, dev);
  
 -              free(minp);
 -              free(maxp);
 -      }
        if (ts->clat_percentiles) {
                show_clat_percentiles(ts->io_u_plat[ddir],
                                        ts->clat_stat[ddir].samples,
@@@ -468,14 -510,8 +468,14 @@@ static void show_lat_m(double *io_u_lat
        show_lat(io_u_lat_m, FIO_IO_U_LAT_M_NR, ranges, "msec");
  }
  
 -static void show_latencies(double *io_u_lat_u, double *io_u_lat_m)
 +static void show_latencies(struct thread_stat *ts)
  {
 +      double io_u_lat_u[FIO_IO_U_LAT_U_NR];
 +      double io_u_lat_m[FIO_IO_U_LAT_M_NR];
 +
 +      stat_calc_lat_u(ts, io_u_lat_u);
 +      stat_calc_lat_m(ts, io_u_lat_m);
 +
        show_lat_u(io_u_lat_u);
        show_lat_m(io_u_lat_m);
  }
@@@ -485,6 -521,8 +485,6 @@@ void show_thread_status(struct thread_s
        double usr_cpu, sys_cpu;
        unsigned long runtime;
        double io_u_dist[FIO_IO_U_MAP_NR];
 -      double io_u_lat_u[FIO_IO_U_LAT_U_NR];
 -      double io_u_lat_m[FIO_IO_U_LAT_M_NR];
  
        if (!(ts->io_bytes[0] + ts->io_bytes[1]) &&
            !(ts->total_io_u[0] + ts->total_io_u[1]))
        if (ts->io_bytes[DDIR_WRITE])
                show_ddir_status(rs, ts, DDIR_WRITE);
  
 -      stat_calc_lat_u(ts, io_u_lat_u);
 -      stat_calc_lat_m(ts, io_u_lat_m);
 -      show_latencies(io_u_lat_u, io_u_lat_m);
 +      show_latencies(ts);
  
        runtime = ts->total_run_time;
        if (runtime) {
@@@ -573,7 -613,7 +573,7 @@@ static void show_ddir_status_terse(stru
        if (ts->runtime[ddir]) {
                uint64_t runt = ts->runtime[ddir];
  
-               bw = ts->io_bytes[ddir] / runt;
+               bw = ((1000 * ts->io_bytes[ddir]) / runt) / 1024;
                iops = (1000 * (uint64_t) ts->total_io_u[ddir]) / runt;
        }
  
  }
  
  static void show_thread_status_terse_v2(struct thread_stat *ts,
 -                                      struct group_run_stats *rs)
 +                                      struct group_run_stats *rs)
  {
        double io_u_dist[FIO_IO_U_MAP_NR];
        double io_u_lat_u[FIO_IO_U_LAT_U_NR];
@@@ -957,11 -997,6 +957,11 @@@ void show_run_stats(void
                        else
                                memset(ts->description, 0, FIO_JOBNAME_SIZE);
  
 +                      /*
 +                       * If multiple entries in this group, this is
 +                       * the first member.
 +                       */
 +                      ts->thread_number = td->thread_number;
                        ts->groupid = td->groupid;
  
                        /*
diff --combined thread_options.h
index a5d06aad5a80aaceb848fa2b46eaf3013ec15712,0000000000000000000000000000000000000000..a78684cf985030f861da02a68f77de30d3f114fe
mode 100644,000000..100644
--- /dev/null
@@@ -1,410 -1,0 +1,412 @@@
 +#ifndef FIO_THREAD_OPTIONS_H
 +#define FIO_THREAD_OPTIONS_H
 +
 +#include "arch/arch.h"
 +#include "os/os.h"
 +#include "stat.h"
 +#include "gettime.h"
 +
 +/*
 + * What type of allocation to use for io buffers
 + */
 +enum fio_memtype {
 +      MEM_MALLOC = 0, /* ordinary malloc */
 +      MEM_SHM,        /* use shared memory segments */
 +      MEM_SHMHUGE,    /* use shared memory segments with huge pages */
 +      MEM_MMAP,       /* use anonynomous mmap */
 +      MEM_MMAPHUGE,   /* memory mapped huge file */
 +};
 +
 +/*
 + * What type of errors to continue on when continue_on_error is used
 + */
 +enum error_type {
 +        ERROR_TYPE_NONE = 0,
 +        ERROR_TYPE_READ = 1 << 0,
 +        ERROR_TYPE_WRITE = 1 << 1,
 +        ERROR_TYPE_VERIFY = 1 << 2,
 +        ERROR_TYPE_ANY = 0xffff,
 +};
 +
 +#define BSSPLIT_MAX   64
 +
 +struct bssplit {
 +      uint32_t bs;
 +      uint32_t perc;
 +};
 +
 +struct thread_options {
 +      int pad;
 +      char *description;
 +      char *name;
 +      char *directory;
 +      char *filename;
 +      char *opendir;
 +      char *ioengine;
 +      char *mmapfile;
 +      enum td_ddir td_ddir;
 +      unsigned int rw_seq;
 +      unsigned int kb_base;
 +      unsigned int ddir_seq_nr;
 +      long ddir_seq_add;
 +      unsigned int iodepth;
 +      unsigned int iodepth_low;
 +      unsigned int iodepth_batch;
 +      unsigned int iodepth_batch_complete;
 +
 +      unsigned long long size;
 +      unsigned int size_percent;
 +      unsigned int fill_device;
 +      unsigned long long file_size_low;
 +      unsigned long long file_size_high;
 +      unsigned long long start_offset;
 +
 +      unsigned int bs[2];
 +      unsigned int ba[2];
 +      unsigned int min_bs[2];
 +      unsigned int max_bs[2];
 +      struct bssplit *bssplit[2];
 +      unsigned int bssplit_nr[2];
 +
 +      unsigned int nr_files;
 +      unsigned int open_files;
 +      enum file_lock_mode file_lock_mode;
 +      unsigned int lockfile_batch;
 +
 +      unsigned int odirect;
 +      unsigned int invalidate_cache;
 +      unsigned int create_serialize;
 +      unsigned int create_fsync;
 +      unsigned int create_on_open;
++      unsigned int create_only;
 +      unsigned int end_fsync;
 +      unsigned int pre_read;
 +      unsigned int sync_io;
 +      unsigned int verify;
 +      unsigned int do_verify;
 +      unsigned int verifysort;
 +      unsigned int verify_interval;
 +      unsigned int verify_offset;
 +      char verify_pattern[MAX_PATTERN_SIZE];
 +      unsigned int verify_pattern_bytes;
 +      unsigned int verify_fatal;
 +      unsigned int verify_dump;
 +      unsigned int verify_async;
 +      unsigned long long verify_backlog;
 +      unsigned int verify_batch;
 +      unsigned int use_thread;
 +      unsigned int unlink;
 +      unsigned int do_disk_util;
 +      unsigned int override_sync;
 +      unsigned int rand_repeatable;
 +      unsigned int use_os_rand;
 +      unsigned int log_avg_msec;
 +      unsigned int norandommap;
 +      unsigned int softrandommap;
 +      unsigned int bs_unaligned;
 +      unsigned int fsync_on_close;
 +
 +      unsigned int hugepage_size;
 +      unsigned int rw_min_bs;
 +      unsigned int thinktime;
 +      unsigned int thinktime_spin;
 +      unsigned int thinktime_blocks;
 +      unsigned int fsync_blocks;
 +      unsigned int fdatasync_blocks;
 +      unsigned int barrier_blocks;
 +      unsigned long long start_delay;
 +      unsigned long long timeout;
 +      unsigned long long ramp_time;
 +      unsigned int overwrite;
 +      unsigned int bw_avg_time;
 +      unsigned int iops_avg_time;
 +      unsigned int loops;
 +      unsigned long long zone_range;
 +      unsigned long long zone_size;
 +      unsigned long long zone_skip;
 +      unsigned long long lockmem;
 +      enum fio_memtype mem_type;
 +      unsigned int mem_align;
 +
 +      unsigned int stonewall;
 +      unsigned int new_group;
 +      unsigned int numjobs;
 +      os_cpu_mask_t cpumask;
 +      unsigned int cpumask_set;
 +      os_cpu_mask_t verify_cpumask;
 +      unsigned int verify_cpumask_set;
 +      unsigned int iolog;
 +      unsigned int rwmixcycle;
 +      unsigned int rwmix[2];
 +      unsigned int nice;
 +      unsigned int ioprio;
 +      unsigned int ioprio_class;
 +      unsigned int file_service_type;
 +      unsigned int group_reporting;
 +      unsigned int fadvise_hint;
 +      enum fio_fallocate_mode fallocate_mode;
 +      unsigned int zero_buffers;
 +      unsigned int refill_buffers;
 +      unsigned int scramble_buffers;
 +      unsigned int compress_percentage;
 +      unsigned int compress_chunk;
 +      unsigned int time_based;
 +      unsigned int disable_lat;
 +      unsigned int disable_clat;
 +      unsigned int disable_slat;
 +      unsigned int disable_bw;
 +      unsigned int gtod_reduce;
 +      unsigned int gtod_cpu;
 +      unsigned int gtod_offload;
 +      enum fio_cs clocksource;
 +      unsigned int no_stall;
 +      unsigned int trim_percentage;
 +      unsigned int trim_batch;
 +      unsigned int trim_zero;
 +      unsigned long long trim_backlog;
 +      unsigned int clat_percentiles;
 +      unsigned int overwrite_plist;
 +      fio_fp64_t percentile_list[FIO_IO_U_LIST_MAX_LEN];
 +
 +      char *read_iolog_file;
 +      char *write_iolog_file;
 +      char *bw_log_file;
 +      char *lat_log_file;
 +      char *iops_log_file;
 +      char *replay_redirect;
 +
 +      /*
 +       * Pre-run and post-run shell
 +       */
 +      char *exec_prerun;
 +      char *exec_postrun;
 +
 +      unsigned int rate[2];
 +      unsigned int ratemin[2];
 +      unsigned int ratecycle;
 +      unsigned int rate_iops[2];
 +      unsigned int rate_iops_min[2];
 +
 +      char *ioscheduler;
 +
 +      /*
 +       * I/O Error handling
 +       */
 +      enum error_type continue_on_error;
 +
 +      /*
 +       * Benchmark profile type
 +       */
 +      char *profile;
 +
 +      /*
 +       * blkio cgroup support
 +       */
 +      char *cgroup;
 +      unsigned int cgroup_weight;
 +      unsigned int cgroup_nodelete;
 +
 +      unsigned int uid;
 +      unsigned int gid;
 +
 +      int flow_id;
 +      int flow;
 +      int flow_watermark;
 +      unsigned int flow_sleep;
 +
 +      unsigned long long offset_increment;
 +
 +      unsigned int sync_file_range;
 +};
 +
 +#define FIO_TOP_STR_MAX               256
 +
 +struct thread_options_pack {
 +      uint8_t description[FIO_TOP_STR_MAX];
 +      uint8_t name[FIO_TOP_STR_MAX];
 +      uint8_t directory[FIO_TOP_STR_MAX];
 +      uint8_t filename[FIO_TOP_STR_MAX];
 +      uint8_t opendir[FIO_TOP_STR_MAX];
 +      uint8_t ioengine[FIO_TOP_STR_MAX];
 +      uint8_t mmapfile[FIO_TOP_STR_MAX];
 +      uint32_t td_ddir;
 +      uint32_t rw_seq;
 +      uint32_t kb_base;
 +      uint32_t ddir_seq_nr;
 +      uint64_t ddir_seq_add;
 +      uint32_t iodepth;
 +      uint32_t iodepth_low;
 +      uint32_t iodepth_batch;
 +      uint32_t iodepth_batch_complete;
 +
 +      uint64_t size;
 +      uint32_t size_percent;
 +      uint32_t fill_device;
 +      uint64_t file_size_low;
 +      uint64_t file_size_high;
 +      uint64_t start_offset;
 +
 +      uint32_t bs[2];
 +      uint32_t ba[2];
 +      uint32_t min_bs[2];
 +      uint32_t max_bs[2];
 +      struct bssplit bssplit[2][BSSPLIT_MAX];
 +      uint32_t bssplit_nr[2];
 +
 +      uint32_t nr_files;
 +      uint32_t open_files;
 +      uint32_t file_lock_mode;
 +      uint32_t lockfile_batch;
 +
 +      uint32_t odirect;
 +      uint32_t invalidate_cache;
 +      uint32_t create_serialize;
 +      uint32_t create_fsync;
 +      uint32_t create_on_open;
++      uint32_t create_only;
 +      uint32_t end_fsync;
 +      uint32_t pre_read;
 +      uint32_t sync_io;
 +      uint32_t verify;
 +      uint32_t do_verify;
 +      uint32_t verifysort;
 +      uint32_t verify_interval;
 +      uint32_t verify_offset;
 +      uint8_t verify_pattern[MAX_PATTERN_SIZE];
 +      uint32_t verify_pattern_bytes;
 +      uint32_t verify_fatal;
 +      uint32_t verify_dump;
 +      uint32_t verify_async;
 +      uint64_t verify_backlog;
 +      uint32_t verify_batch;
 +      uint32_t use_thread;
 +      uint32_t unlink;
 +      uint32_t do_disk_util;
 +      uint32_t override_sync;
 +      uint32_t rand_repeatable;
 +      uint32_t use_os_rand;
 +      uint32_t log_avg_msec;
 +      uint32_t norandommap;
 +      uint32_t softrandommap;
 +      uint32_t bs_unaligned;
 +      uint32_t fsync_on_close;
 +
 +      uint32_t hugepage_size;
 +      uint32_t rw_min_bs;
 +      uint32_t thinktime;
 +      uint32_t thinktime_spin;
 +      uint32_t thinktime_blocks;
 +      uint32_t fsync_blocks;
 +      uint32_t fdatasync_blocks;
 +      uint32_t barrier_blocks;
 +      uint64_t start_delay;
 +      uint64_t timeout;
 +      uint64_t ramp_time;
 +      uint32_t overwrite;
 +      uint32_t bw_avg_time;
 +      uint32_t iops_avg_time;
 +      uint32_t loops;
 +      uint64_t zone_range;
 +      uint64_t zone_size;
 +      uint64_t zone_skip;
 +      uint64_t lockmem;
 +      uint32_t mem_type;
 +      uint32_t mem_align;
 +
 +      uint32_t stonewall;
 +      uint32_t new_group;
 +      uint32_t numjobs;
 +      uint8_t cpumask[FIO_TOP_STR_MAX];
 +      uint32_t cpumask_set;
 +      uint8_t verify_cpumask[FIO_TOP_STR_MAX];
 +      uint32_t verify_cpumask_set;
 +      uint32_t iolog;
 +      uint32_t rwmixcycle;
 +      uint32_t rwmix[2];
 +      uint32_t nice;
 +      uint32_t ioprio;
 +      uint32_t ioprio_class;
 +      uint32_t file_service_type;
 +      uint32_t group_reporting;
 +      uint32_t fadvise_hint;
 +      uint32_t fallocate_mode;
 +      uint32_t zero_buffers;
 +      uint32_t refill_buffers;
 +      uint32_t scramble_buffers;
 +      unsigned int compress_percentage;
 +      unsigned int compress_chunk;
 +      uint32_t time_based;
 +      uint32_t disable_lat;
 +      uint32_t disable_clat;
 +      uint32_t disable_slat;
 +      uint32_t disable_bw;
 +      uint32_t gtod_reduce;
 +      uint32_t gtod_cpu;
 +      uint32_t gtod_offload;
 +      uint32_t clocksource;
 +      uint32_t no_stall;
 +      uint32_t trim_percentage;
 +      uint32_t trim_batch;
 +      uint32_t trim_zero;
 +      uint64_t trim_backlog;
 +      uint32_t clat_percentiles;
 +      uint32_t overwrite_plist;
 +      fio_fp64_t percentile_list[FIO_IO_U_LIST_MAX_LEN];
 +
 +      uint8_t read_iolog_file[FIO_TOP_STR_MAX];
 +      uint8_t write_iolog_file[FIO_TOP_STR_MAX];
 +      uint8_t bw_log_file[FIO_TOP_STR_MAX];
 +      uint8_t lat_log_file[FIO_TOP_STR_MAX];
 +      uint8_t iops_log_file[FIO_TOP_STR_MAX];
 +      uint8_t replay_redirect[FIO_TOP_STR_MAX];
 +
 +      /*
 +       * Pre-run and post-run shell
 +       */
 +      uint8_t exec_prerun[FIO_TOP_STR_MAX];
 +      uint8_t exec_postrun[FIO_TOP_STR_MAX];
 +
 +      uint32_t rate[2];
 +      uint32_t ratemin[2];
 +      uint32_t ratecycle;
 +      uint32_t rate_iops[2];
 +      uint32_t rate_iops_min[2];
 +
 +      uint8_t ioscheduler[FIO_TOP_STR_MAX];
 +
 +      /*
 +       * I/O Error handling
 +       */
 +      uint32_t continue_on_error;
 +
 +      /*
 +       * Benchmark profile type
 +       */
 +      uint8_t profile[FIO_TOP_STR_MAX];
 +
 +      /*
 +       * blkio cgroup support
 +       */
 +      uint8_t cgroup[FIO_TOP_STR_MAX];
 +      uint32_t cgroup_weight;
 +      uint32_t cgroup_nodelete;
 +
 +      uint32_t uid;
 +      uint32_t gid;
 +
 +      int32_t flow_id;
 +      int32_t flow;
 +      int32_t flow_watermark;
 +      uint32_t flow_sleep;
 +
 +      uint64_t offset_increment;
 +
 +      uint32_t sync_file_range;
 +} __attribute__((packed));
 +
 +extern void convert_thread_options_to_cpu(struct thread_options *o, struct thread_options_pack *top);
 +extern void convert_thread_options_to_net(struct thread_options_pack *top, struct thread_options *);
 +extern int fio_test_cconv(struct thread_options *);
 +extern void options_default_fill(struct thread_options *o);
 +
 +#endif