Merge branch 'master' into gfio
authorJens Axboe <axboe@kernel.dk>
Tue, 21 Aug 2012 13:34:13 +0000 (15:34 +0200)
committerJens Axboe <axboe@kernel.dk>
Tue, 21 Aug 2012 13:34:13 +0000 (15:34 +0200)
Conflicts:
eta.c

Signed-off-by: Jens Axboe <axboe@kernel.dk>
1  2 
Makefile
backend.c
eta.c
filesetup.c
init.c
io_u.c

diff --combined Makefile
index 5d4e3e7ab2ea709302115f19cde76e5bbe53eeb3,9d3945b39564de873d65f0939c79faaf1d5fbe2b..ea8c851e81b24f9d50e02876feca3bcaffe16441
+++ b/Makefile
@@@ -1,24 -1,20 +1,24 @@@
- CC    = gcc
+ CC    ?= gcc
  DEBUGFLAGS = -D_FORTIFY_SOURCE=2 -DFIO_INC_DEBUG
  CPPFLAGS= -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 \
        $(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 \
@@@ -69,16 -65,13 +69,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)
@@@ -118,44 -111,14 +118,44 @@@ 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 $(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
@@@ -178,5 -141,3 +178,5 @@@ install: $(PROGS) $(SCRIPTS) FORC
  ifneq ($(wildcard .depend),)
  include .depend
  endif
 +
 +
diff --combined backend.c
index dcc6fba06fdb58636555cdd1db13d5113cab9b21,e41e8f1b41fffe64a8dc023523b48e482dd662d0..f20857a0c965058968166cfecda644196be26a1a
+++ b/backend.c
@@@ -57,13 -57,13 +57,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;
@@@ -346,8 -346,8 +346,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);
@@@ -969,12 -969,10 +969,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;
                }
                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) {
@@@ -1221,8 -1206,8 +1221,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");
        }
@@@ -1376,19 -1361,14 +1376,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();
  }
  
  void wait_for_disk_thread_exit(void)
@@@ -1631,7 -1620,7 +1631,7 @@@ static int create_disk_util_thread(void
  
        setup_disk_util();
  
-       disk_thread_mutex = fio_mutex_init(0);
+       disk_thread_mutex = fio_mutex_init(FIO_MUTEX_LOCKED);
  
        ret = pthread_create(&disk_util_thread, NULL, disk_thread_main, NULL);
        if (ret) {
@@@ -1668,14 -1657,14 +1668,14 @@@ 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);
+       startup_mutex = fio_mutex_init(FIO_MUTEX_LOCKED);
        if (startup_mutex == NULL)
                return 1;
-       writeout_mutex = fio_mutex_init(1);
+       writeout_mutex = fio_mutex_init(FIO_MUTEX_UNLOCKED);
        if (writeout_mutex == NULL)
                return 1;
  
diff --combined eta.c
index 34afe0ca4cb89c35c0e895c487bf9228bba60b56,552845d85d9379cbd67bc35fe2594801f173d441..e1050b52b5a8801c9eb2fef0077353eb17bb656c
--- 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;
@@@ -285,14 -285,18 +285,18 @@@ int calc_thread_status(struct jobs_eta 
                    || td->runstate == TD_FSYNCING
                    || td->runstate == TD_PRE_READING) {
                        je->nr_running++;
-                       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];
+                       if (td_read(td)) {
 -                              je->t_rate += td->o.rate[DDIR_READ];
 -                              je->t_iops += td->o.rate_iops[DDIR_READ];
 -                              je->m_rate += td->o.ratemin[DDIR_READ];
 -                              je->m_iops += td->o.rate_iops_min[DDIR_READ];
++                              je->t_rate[0] += td->o.rate[DDIR_READ];
++                              je->t_iops[0] += td->o.rate_iops[DDIR_READ];
++                              je->m_rate[0] += td->o.ratemin[DDIR_READ];
++                              je->m_iops[0] += td->o.rate_iops_min[DDIR_READ];
+                       }
+                       if (td_write(td)) {
 -                              je->t_rate += td->o.rate[DDIR_WRITE];
 -                              je->t_iops += td->o.rate_iops[DDIR_WRITE];
 -                              je->m_rate += td->o.ratemin[DDIR_WRITE];
 -                              je->m_iops += td->o.rate_iops_min[DDIR_WRITE];
++                              je->t_rate[1] += td->o.rate[DDIR_WRITE];
++                              je->t_iops[1] += td->o.rate_iops[DDIR_WRITE];
++                              je->m_rate[1] += td->o.ratemin[DDIR_WRITE];
++                              je->m_iops[1] += td->o.rate_iops_min[DDIR_WRITE];
+                       }
                        je->files_open += td->nr_open_files;
                } else if (td->runstate == TD_RAMP) {
                        je->nr_running++;
@@@ -378,19 -382,16 +382,19 @@@ void display_thread_status(struct jobs_
        }
  
        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, je->is_pow2);
 -              tr = num2str(je->t_rate, 4, 0, je->is_pow2);
 +              mr = num2str(je->m_rate[0] + je->m_rate[1], 4, 0, je->is_pow2);
 +              tr = num2str(je->t_rate[0] + je->t_rate[1], 4, 0, je->is_pow2);
                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];
diff --combined filesetup.c
index 76e142af88972748f8ac96df047d7fd68ffd4cee,3594a80faf3bfe8300e29fc7cc04f7c892e826f8..9c486bec3122355b5e439151ea9860ec636bec25
@@@ -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:
@@@ -657,6 -657,12 +657,12 @@@ static unsigned long long get_fs_free_c
        return ret;
  }
  
+ unsigned long long get_start_offset(struct thread_data *td)
+ {
+       return td->o.start_offset +
+               (td->thread_number - 1) * td->o.offset_increment;
+ }
  /*
   * Open the files and setup files sizes, creating files if necessary.
   */
@@@ -718,8 -724,7 +724,7 @@@ int setup_files(struct thread_data *td
        extend_size = total_size = 0;
        need_extend = 0;
        for_each_file(td, f, i) {
-               f->file_offset = td->o.start_offset +
-                       (td->thread_number - 1) * td->o.offset_increment;
+               f->file_offset = get_start_offset(td);
  
                if (!td->o.file_size_low) {
                        /*
@@@ -1006,7 -1011,7 +1011,7 @@@ int add_file(struct thread_data *td, co
                f->lock = fio_mutex_rw_init();
                break;
        case FILE_LOCK_EXCLUSIVE:
-               f->lock = fio_mutex_init(1);
+               f->lock = fio_mutex_init(FIO_MUTEX_UNLOCKED);
                break;
        default:
                log_err("fio: unknown lock mode: %d\n", td->o.file_lock_mode);
diff --combined init.c
index 4f42a5cccf066eb441e6ca830d4400169fc3ad8a,475a6ad29f69a87da2463f4e020609c5e99861b5..2b581fbc519668a4057d541493481f2d979e4724
--- 1/init.c
--- 2/init.c
+++ b/init.c
@@@ -38,6 -38,7 +38,6 @@@ struct thread_data *threads = NULL
  int exitall_on_terminate = 0;
  int terse_output = 0;
  int eta_print;
 -unsigned long long mlock_size = 0;
  FILE *f_out = NULL;
  FILE *f_err = NULL;
  char **job_sections = NULL;
@@@ -204,7 -205,7 +204,7 @@@ static struct option l_opts[FIO_NR_OPTI
        },
  };
  
 -static void free_shm(void)
 +void free_threads_shm(void)
  {
        struct shmid_ds sbuf;
  
                void *tp = threads;
  
                threads = NULL;
 +              shmdt(tp);
 +              shmctl(shm_id, IPC_RMID, &sbuf);
 +              shm_id = -1;
 +      }
 +}
 +
 +void free_shm(void)
 +{
 +      if (threads) {
                file_hash_exit();
                flow_exit();
                fio_debug_jobp = NULL;
 -              shmdt(tp);
 -              shmctl(shm_id, IPC_RMID, &sbuf);
 +              free_threads_shm();
        }
  
        scleanup();
@@@ -583,7 -576,7 +583,7 @@@ static int fixup_options(struct thread_
  /*
   * This function leaks the buffer
   */
 -static char *to_kmg(unsigned int val)
 +char *fio_uint_to_kmg(unsigned int val)
  {
        char *buf = malloc(32);
        char post[] = { 0, 'K', 'M', 'G', 'P', 'E', 0 };
@@@ -744,9 -737,10 +744,9 @@@ int ioengine_load(struct thread_data *t
   * to make sure we don't have conflicts, and initializes various
   * members of td.
   */
 -static int add_job(struct thread_data *td, const char *jobname, int job_add_num)
 +static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
 +                 int recursed, int client_type)
  {
 -      const char *ddir_str[] = { NULL, "read", "write", "rw", NULL,
 -                                 "randread", "randwrite", "randrw" };
        unsigned int i;
        char fname[PATH_MAX];
        int numjobs, file_alloced;
                return 0;
        }
  
 +      td->client_type = client_type;
 +
        if (profile_td_init(td))
                goto err;
  
        if (ioengine_load(td))
                goto err;
  
 -      if (td->o.use_thread)
 -              nr_thread++;
 -      else
 -              nr_process++;
 -
        if (td->o.odirect)
                td->io_ops->flags |= FIO_RAWIO;
  
                        f->real_file_size = -1ULL;
        }
  
-       td->mutex = fio_mutex_init(0);
+       td->mutex = fio_mutex_init(FIO_MUTEX_LOCKED);
  
        td->ts.clat_percentiles = td->o.clat_percentiles;
        if (td->o.overwrite_plist)
        if (setup_rate(td))
                goto err;
  
 -      if (td->o.write_lat_log) {
 -              setup_log(&td->lat_log, td->o.log_avg_msec);
 -              setup_log(&td->slat_log, td->o.log_avg_msec);
 -              setup_log(&td->clat_log, td->o.log_avg_msec);
 +      if (td->o.lat_log_file) {
 +              setup_log(&td->lat_log, td->o.log_avg_msec, IO_LOG_TYPE_LAT);
 +              setup_log(&td->slat_log, td->o.log_avg_msec, IO_LOG_TYPE_SLAT);
 +              setup_log(&td->clat_log, td->o.log_avg_msec, IO_LOG_TYPE_CLAT);
        }
 -      if (td->o.write_bw_log)
 -              setup_log(&td->bw_log, td->o.log_avg_msec);
 -      if (td->o.write_iops_log)
 -              setup_log(&td->iops_log, td->o.log_avg_msec);
 +      if (td->o.bw_log_file)
 +              setup_log(&td->bw_log, td->o.log_avg_msec, IO_LOG_TYPE_BW);
 +      if (td->o.iops_log_file)
 +              setup_log(&td->iops_log, td->o.log_avg_msec, IO_LOG_TYPE_IOPS);
  
        if (!td->o.name)
                td->o.name = strdup(jobname);
  
        if (!terse_output) {
                if (!job_add_num) {
 -                      if (!strcmp(td->io_ops->name, "cpuio")) {
 -                              log_info("%s: ioengine=cpu, cpuload=%u,"
 -                                       " cpucycle=%u\n", td->o.name,
 -                                                      td->o.cpuload,
 -                                                      td->o.cpucycle);
 -                      } else {
 +                      if (is_backend && !recursed)
 +                              fio_server_send_add_job(td);
 +
 +                      if (!(td->io_ops->flags & FIO_NOIO)) {
                                char *c1, *c2, *c3, *c4;
  
 -                              c1 = to_kmg(td->o.min_bs[DDIR_READ]);
 -                              c2 = to_kmg(td->o.max_bs[DDIR_READ]);
 -                              c3 = to_kmg(td->o.min_bs[DDIR_WRITE]);
 -                              c4 = to_kmg(td->o.max_bs[DDIR_WRITE]);
 +                              c1 = fio_uint_to_kmg(td->o.min_bs[DDIR_READ]);
 +                              c2 = fio_uint_to_kmg(td->o.max_bs[DDIR_READ]);
 +                              c3 = fio_uint_to_kmg(td->o.min_bs[DDIR_WRITE]);
 +                              c4 = fio_uint_to_kmg(td->o.max_bs[DDIR_WRITE]);
  
                                log_info("%s: (g=%d): rw=%s, bs=%s-%s/%s-%s,"
                                         " ioengine=%s, iodepth=%u\n",
                                                td->o.name, td->groupid,
 -                                              ddir_str[td->o.td_ddir],
 +                                              ddir_str(td->o.td_ddir),
                                                c1, c2, c3, c4,
                                                td->io_ops->name,
                                                td->o.iodepth);
  
                job_add_num = numjobs - 1;
  
 -              if (add_job(td_new, jobname, job_add_num))
 +              if (add_job(td_new, jobname, job_add_num, 1, client_type))
                        goto err;
        }
  
@@@ -920,7 -919,7 +920,7 @@@ err
  /*
   * Parse as if 'o' was a command line
   */
 -void add_job_opts(const char **o)
 +void add_job_opts(const char **o, int client_type)
  {
        struct thread_data *td, *td_parent;
        int i, in_global = 1;
                if (!strncmp(o[i], "name", 4)) {
                        in_global = 0;
                        if (td)
 -                              add_job(td, jobname, 0);
 +                              add_job(td, jobname, 0, 0, client_type);
                        td = NULL;
                        sprintf(jobname, "%s", o[i] + 5);
                }
        }
  
        if (td)
 -              add_job(td, jobname, 0);
 +              add_job(td, jobname, 0, 0, client_type);
  }
  
  static int skip_this_section(const char *name)
@@@ -989,7 -988,7 +989,7 @@@ static int is_empty_or_comment(char *li
  /*
   * This is our [ini] type file parser.
   */
 -int parse_jobs_ini(char *file, int is_buf, int stonewall_flag)
 +int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type)
  {
        unsigned int global;
        struct thread_data *td;
                                for (i = 0; i < num_opts; i++)
                                        log_info("--%s ", opts[i]);
  
 -                      ret = add_job(td, name, 0);
 +                      ret = add_job(td, name, 0, 0, type);
                } else {
                        log_err("fio: job %s dropped\n", name);
                        put_job(td);
@@@ -1218,62 -1217,20 +1218,62 @@@ static void usage(const char *name
  
  #ifdef FIO_INC_DEBUG
  struct debug_level debug_levels[] = {
 -      { .name = "process",    .shift = FD_PROCESS, },
 -      { .name = "file",       .shift = FD_FILE, },
 -      { .name = "io",         .shift = FD_IO, },
 -      { .name = "mem",        .shift = FD_MEM, },
 -      { .name = "blktrace",   .shift = FD_BLKTRACE },
 -      { .name = "verify",     .shift = FD_VERIFY },
 -      { .name = "random",     .shift = FD_RANDOM },
 -      { .name = "parse",      .shift = FD_PARSE },
 -      { .name = "diskutil",   .shift = FD_DISKUTIL },
 -      { .name = "job",        .shift = FD_JOB },
 -      { .name = "mutex",      .shift = FD_MUTEX },
 -      { .name = "profile",    .shift = FD_PROFILE },
 -      { .name = "time",       .shift = FD_TIME },
 -      { .name = "net",        .shift = FD_NET },
 +      { .name = "process",
 +        .help = "Process creation/exit logging",
 +        .shift = FD_PROCESS,
 +      },
 +      { .name = "file",
 +        .help = "File related action logging",
 +        .shift = FD_FILE,
 +      },
 +      { .name = "io",
 +        .help = "IO and IO engine action logging (offsets, queue, completions, etc)",
 +        .shift = FD_IO,
 +      },
 +      { .name = "mem",
 +        .help = "Memory allocation/freeing logging",
 +        .shift = FD_MEM,
 +      },
 +      { .name = "blktrace",
 +        .help = "blktrace action logging",
 +        .shift = FD_BLKTRACE,
 +      },
 +      { .name = "verify",
 +        .help = "IO verification action logging",
 +        .shift = FD_VERIFY,
 +      },
 +      { .name = "random",
 +        .help = "Random generation logging",
 +        .shift = FD_RANDOM,
 +      },
 +      { .name = "parse",
 +        .help = "Parser logging",
 +        .shift = FD_PARSE,
 +      },
 +      { .name = "diskutil",
 +        .help = "Disk utility logging actions",
 +        .shift = FD_DISKUTIL,
 +      },
 +      { .name = "job",
 +        .help = "Logging related to creating/destroying jobs",
 +        .shift = FD_JOB,
 +      },
 +      { .name = "mutex",
 +        .help = "Mutex logging",
 +        .shift = FD_MUTEX
 +      },
 +      { .name = "profile",
 +        .help = "Logging related to profiles",
 +        .shift = FD_PROFILE,
 +      },
 +      { .name = "time",
 +        .help = "Logging related to time keeping functions",
 +        .shift = FD_TIME,
 +      },
 +      { .name = "net",
 +        .help = "Network logging",
 +        .shift = FD_NET,
 +      },
        { .name = NULL, },
  };
  
@@@ -1380,7 -1337,7 +1380,7 @@@ void parse_cmd_client(void *client, cha
        fio_client_add_cmd_option(client, opt);
  }
  
 -int parse_cmd_line(int argc, char *argv[])
 +int parse_cmd_line(int argc, char *argv[], int client_type)
  {
        struct thread_data *td = NULL;
        int c, ini_idx = 0, lidx, ret = 0, do_exit = 0, exit_val = 0;
                        char *val = optarg;
  
                        if (!strncmp(opt, "name", 4) && td) {
 -                              ret = add_job(td, td->o.name ?: "fio", 0);
 +                              ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type);
                                if (ret)
                                        return 0;
                                td = NULL;
                                exit_val = 1;
                                break;
                        }
 -                      if (fio_client_add(optarg, &cur_client)) {
 +                      if (fio_client_add(&fio_client_ops, optarg, &cur_client)) {
                                log_err("fio: failed adding client %s\n", optarg);
                                do_exit++;
                                exit_val = 1;
  
        if (td) {
                if (!ret)
 -                      ret = add_job(td, td->o.name ?: "fio", 0);
 +                      ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type);
        }
  
        while (!ret && optind < argc) {
        return ini_idx;
  }
  
 -int parse_options(int argc, char *argv[])
 +int fio_init_options(void)
  {
 -      int job_files, i;
 -
        f_out = stdout;
        f_err = stderr;
  
        if (fill_def_thread())
                return 1;
  
 -      job_files = parse_cmd_line(argc, argv);
 +      return 0;
 +}
 +
 +extern int fio_check_options(struct thread_options *);
 +
 +int parse_options(int argc, char *argv[])
 +{
 +      const int type = FIO_CLIENT_TYPE_CLI;
 +      int job_files, i;
 +
 +      if (fio_init_options())
 +              return 1;
 +      if (fio_test_cconv(&def_thread.o))
 +              log_err("fio: failed internal cconv test\n");
 +
 +      job_files = parse_cmd_line(argc, argv, type);
  
        if (job_files > 0) {
                for (i = 0; i < job_files; i++) {
                                        return 1;
                                free(ini_file[i]);
                        } else if (!is_backend) {
 -                              if (parse_jobs_ini(ini_file[i], 0, i))
 +                              if (parse_jobs_ini(ini_file[i], 0, i, type))
                                        return 1;
                                free(ini_file[i]);
                        }
  
        return 0;
  }
 +
 +void options_default_fill(struct thread_options *o)
 +{
 +      memcpy(o, &def_thread.o, sizeof(*o));
 +}
diff --combined io_u.c
index 7e05ff972c379b660316545f285a8bd5d024655f,2f5456294cea559bd97504f7c534626eb0933344..28a86f7e8c4c07c9b046a8b7110a935ca4a567e1
--- 1/io_u.c
--- 2/io_u.c
+++ b/io_u.c
@@@ -78,7 -78,7 +78,7 @@@ static void mark_random_map(struct thre
                                mask = -1UL;
                        else
                                mask = ((1UL << this_blocks) - 1) << bit;
 -      
 +
                        if (!(f->file_map[idx] & mask))
                                break;
  
@@@ -256,7 -256,7 +256,7 @@@ static int get_next_seq_offset(struct t
  {
        assert(ddir_rw(ddir));
  
-       if (f->last_pos >= f->io_size && td->o.time_based)
+       if (f->last_pos >= f->io_size + get_start_offset(td) && td->o.time_based)
                f->last_pos = f->last_pos - f->io_size;
  
        if (f->last_pos < f->real_file_size) {
@@@ -310,7 -310,7 +310,7 @@@ static int get_next_block(struct thread
                        ret = 1;
                }
        }
 -      
 +
        if (!ret) {
                if (offset != -1ULL)
                        io_u->offset = offset;
@@@ -377,7 -377,7 +377,7 @@@ static inline int io_u_fits(struct thre
  {
        struct fio_file *f = io_u->file;
  
-       return io_u->offset + buflen <= f->io_size + td->o.start_offset;
+       return io_u->offset + buflen <= f->io_size + get_start_offset(td);
  }
  
  static unsigned int __get_next_buflen(struct thread_data *td, struct io_u *io_u)
@@@ -1429,7 -1429,7 +1429,7 @@@ static void io_completed(struct thread_
                io_u_log_error(td, io_u);
        }
        if (icd->error && td_non_fatal_error(icd->error) &&
 -           (td->o.continue_on_error & td_error_type(io_u->ddir, icd->error))) {
 +          (td->o.continue_on_error & td_error_type(io_u->ddir, icd->error))) {
                /*
                 * If there is a non_fatal error, then add to the error count
                 * and clear all the errors.