use true/false for bool type
[fio.git] / init.c
diff --git a/init.c b/init.c
index 5482c665c277e5050b89a5759fa9bcd49895fd26..2b7768ab8ce1f6d57e0e82eaf46854b993abbda5 100644 (file)
--- a/init.c
+++ b/init.c
 #include "server.h"
 #include "idletime.h"
 #include "filelock.h"
+#include "steadystate.h"
 
 #include "oslib/getopt.h"
 #include "oslib/strcasestr.h"
 
 #include "crc/test.h"
+#include "lib/pow2.h"
 
 const char fio_version_string[] = FIO_VERSION;
 
@@ -38,7 +40,6 @@ const char fio_version_string[] = FIO_VERSION;
 static char **ini_file;
 static int max_jobs = FIO_MAX_JOBS;
 static int dump_cmdline;
-static long long def_timeout;
 static int parse_only;
 
 static struct thread_data def_thread;
@@ -91,11 +92,6 @@ static struct option l_opts[FIO_NR_OPTIONS] = {
                .has_arg        = required_argument,
                .val            = 'o' | FIO_CLIENT_FLAG,
        },
-       {
-               .name           = (char *) "timeout",
-               .has_arg        = required_argument,
-               .val            = 't' | FIO_CLIENT_FLAG,
-       },
        {
                .name           = (char *) "latency-log",
                .has_arg        = required_argument,
@@ -103,7 +99,7 @@ static struct option l_opts[FIO_NR_OPTIONS] = {
        },
        {
                .name           = (char *) "bandwidth-log",
-               .has_arg        = required_argument,
+               .has_arg        = no_argument,
                .val            = 'b' | FIO_CLIENT_FLAG,
        },
        {
@@ -298,7 +294,6 @@ void free_threads_shm(void)
 static void free_shm(void)
 {
        if (threads) {
-               file_hash_exit();
                flow_exit();
                fio_debug_jobp = NULL;
                free_threads_shm();
@@ -311,6 +306,7 @@ static void free_shm(void)
 
        options_free(fio_options, &def_thread.o);
        fio_filelock_exit();
+       file_hash_exit();
        scleanup();
 }
 
@@ -322,8 +318,6 @@ static void free_shm(void)
  */
 static int setup_thread_area(void)
 {
-       void *hash;
-
        if (threads)
                return 0;
 
@@ -334,7 +328,6 @@ static int setup_thread_area(void)
        do {
                size_t size = max_jobs * sizeof(struct thread_data);
 
-               size += file_hash_size;
                size += sizeof(unsigned int);
 
 #ifndef CONFIG_NO_SHM
@@ -363,27 +356,19 @@ static int setup_thread_area(void)
                perror("shmat");
                return 1;
        }
+       if (shm_attach_to_open_removed())
+               shmctl(shm_id, IPC_RMID, NULL);
 #endif
 
        memset(threads, 0, max_jobs * sizeof(struct thread_data));
-       hash = (void *) threads + max_jobs * sizeof(struct thread_data);
-       fio_debug_jobp = (void *) hash + file_hash_size;
+       fio_debug_jobp = (void *) threads + max_jobs * sizeof(struct thread_data);
        *fio_debug_jobp = -1;
-       file_hash_init(hash);
 
        flow_init();
 
        return 0;
 }
 
-static void set_cmd_options(struct thread_data *td)
-{
-       struct thread_options *o = &td->o;
-
-       if (!o->timeout)
-               o->timeout = def_timeout;
-}
-
 static void dump_print_option(struct print_option *p)
 {
        const char *delim;
@@ -449,15 +434,13 @@ static void copy_opt_list(struct thread_data *dst, struct thread_data *src)
 /*
  * Return a free job structure.
  */
-static struct thread_data *get_new_job(int global, struct thread_data *parent,
-                                      int preserve_eo, const char *jobname)
+static struct thread_data *get_new_job(bool global, struct thread_data *parent,
+                                      bool preserve_eo, const char *jobname)
 {
        struct thread_data *td;
 
-       if (global) {
-               set_cmd_options(&def_thread);
+       if (global)
                return &def_thread;
-       }
        if (setup_thread_area()) {
                log_err("error: failed to setup shm segment\n");
                return NULL;
@@ -476,6 +459,7 @@ static struct thread_data *get_new_job(int global, struct thread_data *parent,
                copy_opt_list(td, parent);
 
        td->io_ops = NULL;
+       td->io_ops_init = 0;
        if (!preserve_eo)
                td->eo = NULL;
 
@@ -495,7 +479,6 @@ static struct thread_data *get_new_job(int global, struct thread_data *parent,
        if (!parent->o.group_reporting || parent == &def_thread)
                stat_number++;
 
-       set_cmd_options(td);
        return td;
 }
 
@@ -540,7 +523,7 @@ static int __setup_rate(struct thread_data *td, enum fio_ddir ddir)
 
        td->rate_next_io_time[ddir] = 0;
        td->rate_io_issue_bytes[ddir] = 0;
-       td->last_usec = 0;
+       td->last_usec[ddir] = 0;
        return 0;
 }
 
@@ -584,6 +567,17 @@ static unsigned long long get_rand_start_delay(struct thread_data *td)
        return delayrange;
 }
 
+/*
+ * <3 Johannes
+ */
+static unsigned int gcd(unsigned int m, unsigned int n)
+{
+       if (!n)
+               return m;
+
+       return gcd(n, m % n);
+}
+
 /*
  * Lazy way of fixing up options that depend on each other. We could also
  * define option callback handlers, but this is easier.
@@ -593,7 +587,7 @@ static int fixup_options(struct thread_data *td)
        struct thread_options *o = &td->o;
        int ret = 0;
 
-#ifndef FIO_HAVE_PSHARED_MUTEX
+#ifndef CONFIG_PSHARED
        if (!o->use_thread) {
                log_info("fio: this platform does not support process shared"
                         " mutexes, forcing use of threads. Use the 'thread'"
@@ -626,7 +620,7 @@ static int fixup_options(struct thread_data *td)
        /*
         * Reads can do overwrites, we always need to pre-create the file
         */
-       if (td_read(td) || td_rw(td))
+       if (td_read(td))
                o->overwrite = 1;
 
        if (!o->min_bs[DDIR_READ])
@@ -759,10 +753,20 @@ static int fixup_options(struct thread_data *td)
                        o->verify_interval = o->min_bs[DDIR_WRITE];
                else if (td_read(td) && o->verify_interval > o->min_bs[DDIR_READ])
                        o->verify_interval = o->min_bs[DDIR_READ];
+
+               /*
+                * Verify interval must be a factor or both min and max
+                * write size
+                */
+               if (o->verify_interval % o->min_bs[DDIR_WRITE] ||
+                   o->verify_interval % o->max_bs[DDIR_WRITE])
+                       o->verify_interval = gcd(o->min_bs[DDIR_WRITE],
+                                                       o->max_bs[DDIR_WRITE]);
        }
 
        if (o->pre_read) {
-               o->invalidate_cache = 0;
+               if (o->invalidate_cache)
+                       o->invalidate_cache = 0;
                if (td_ioengine_flagged(td, FIO_PIPEIO)) {
                        log_info("fio: cannot pre-read files with an IO engine"
                                 " that isn't seekable. Pre-read disabled.\n");
@@ -827,7 +831,8 @@ static int fixup_options(struct thread_data *td)
         * If size is set but less than the min block size, complain
         */
        if (o->size && o->size < td_min_bs(td)) {
-               log_err("fio: size too small, must be larger than the IO size: %llu\n", (unsigned long long) o->size);
+               log_err("fio: size too small, must not be less than minimum block size: %llu < %u\n",
+                       (unsigned long long) o->size, td_min_bs(td));
                ret = 1;
        }
 
@@ -868,27 +873,6 @@ static int fixup_options(struct thread_data *td)
        return ret;
 }
 
-/*
- * This function leaks the buffer
- */
-char *fio_uint_to_kmg(unsigned int val)
-{
-       char *buf = malloc(32);
-       char post[] = { 0, 'K', 'M', 'G', 'P', 'E', 0 };
-       char *p = post;
-
-       do {
-               if (val & 1023)
-                       break;
-
-               val >>= 10;
-               p++;
-       } while (*p);
-
-       snprintf(buf, 32, "%u%c", val, *p);
-       return buf;
-}
-
 /* External engines are specified by "external:name.o") */
 static const char *get_engine_name(const char *str)
 {
@@ -925,9 +909,9 @@ void td_fill_verify_state_seed(struct thread_data *td)
        bool use64;
 
        if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE64)
-               use64 = 1;
+               use64 = true;
        else
-               use64 = 0;
+               use64 = false;
 
        init_rand_seed(&td->verify_state, td->rand_seeds[FIO_RAND_VER_OFF],
                use64);
@@ -949,7 +933,9 @@ static void td_fill_rand_seeds_internal(struct thread_data *td, bool use64)
        init_rand_seed(&td->file_size_state, td->rand_seeds[FIO_RAND_FILE_SIZE_OFF], use64);
        init_rand_seed(&td->trim_state, td->rand_seeds[FIO_RAND_TRIM_OFF], use64);
        init_rand_seed(&td->delay_state, td->rand_seeds[FIO_RAND_START_DELAY], use64);
-       init_rand_seed(&td->poisson_state, td->rand_seeds[FIO_RAND_POISSON_OFF], 0);
+       init_rand_seed(&td->poisson_state[0], td->rand_seeds[FIO_RAND_POISSON_OFF], 0);
+       init_rand_seed(&td->poisson_state[1], td->rand_seeds[FIO_RAND_POISSON2_OFF], 0);
+       init_rand_seed(&td->poisson_state[2], td->rand_seeds[FIO_RAND_POISSON3_OFF], 0);
        init_rand_seed(&td->dedupe_state, td->rand_seeds[FIO_DEDUPE_OFF], false);
        init_rand_seed(&td->zone_state, td->rand_seeds[FIO_RAND_ZONE_OFF], false);
 
@@ -981,9 +967,9 @@ void td_fill_rand_seeds(struct thread_data *td)
        }
 
        if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE64)
-               use64 = 1;
+               use64 = true;
        else
-               use64 = 0;
+               use64 = false;
 
        td_fill_rand_seeds_internal(td, use64);
 
@@ -1040,7 +1026,7 @@ int ioengine_load(struct thread_data *td)
                 */
                if (origeo) {
                        memcpy(td->eo, origeo, td->io_ops->option_struct_size);
-                       options_mem_dupe(td->eo, td->io_ops->options);
+                       options_mem_dupe(td->io_ops->options, td->eo);
                } else {
                        memset(td->eo, 0, td->io_ops->option_struct_size);
                        fill_default_options(td->eo, td->io_ops->options);
@@ -1084,6 +1070,9 @@ static void init_flags(struct thread_data *td)
 
        if (o->verify_async || o->io_submit_mode == IO_MODE_OFFLOAD)
                td->flags |= TD_F_NEED_LOCK;
+
+       if (o->mem_type == MEM_CUDA_MALLOC)
+               td->flags &= ~TD_F_SCRAMBLE_BUFFERS;
 }
 
 static int setup_random_seeds(struct thread_data *td)
@@ -1091,8 +1080,12 @@ static int setup_random_seeds(struct thread_data *td)
        unsigned long seed;
        unsigned int i;
 
-       if (!td->o.rand_repeatable && !fio_option_is_set(&td->o, rand_seed))
-               return init_random_state(td, td->rand_seeds, sizeof(td->rand_seeds));
+       if (!td->o.rand_repeatable && !fio_option_is_set(&td->o, rand_seed)) {
+               int ret = init_random_seeds(td->rand_seeds, sizeof(td->rand_seeds));
+               if (!ret)
+                       td_fill_rand_seeds(td);
+               return ret;
+       }
 
        seed = td->o.rand_seed;
        for (i = 0; i < 4; i++)
@@ -1134,7 +1127,7 @@ static char *make_filename(char *buf, size_t buf_size,struct thread_options *o,
 
        if (!o->filename_format || !strlen(o->filename_format)) {
                sprintf(buf, "%s.%d.%d", jobname, jobnum, filenum);
-               return NULL;
+               return buf;
        }
 
        for (f = &fpre_keywords[0]; f->keyword; f++)
@@ -1387,14 +1380,14 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
        prev_group_jobs++;
 
        if (setup_random_seeds(td)) {
-               td_verror(td, errno, "init_random_state");
+               td_verror(td, errno, "setup_random_seeds");
                goto err;
        }
 
        if (setup_rate(td))
                goto err;
 
-       if (o->lat_log_file) {
+       if (o->write_lat_log) {
                struct log_params p = {
                        .td = td,
                        .avg_msec = o->log_avg_msec,
@@ -1405,6 +1398,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                        .log_gz = o->log_gz,
                        .log_gz_store = o->log_gz_store,
                };
+               const char *pre = o->lat_log_file ? o->lat_log_file : o->name;
                const char *suf;
 
                if (p.log_gz_store)
@@ -1412,20 +1406,20 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                else
                        suf = "log";
 
-               gen_log_name(logname, sizeof(logname), "lat", o->lat_log_file,
+               gen_log_name(logname, sizeof(logname), "lat", pre,
                                td->thread_number, suf, o->per_job_logs);
                setup_log(&td->lat_log, &p, logname);
 
-               gen_log_name(logname, sizeof(logname), "slat", o->lat_log_file,
+               gen_log_name(logname, sizeof(logname), "slat", pre,
                                td->thread_number, suf, o->per_job_logs);
                setup_log(&td->slat_log, &p, logname);
 
-               gen_log_name(logname, sizeof(logname), "clat", o->lat_log_file,
+               gen_log_name(logname, sizeof(logname), "clat", pre,
                                td->thread_number, suf, o->per_job_logs);
                setup_log(&td->clat_log, &p, logname);
        }
 
-       if (o->hist_log_file) {
+       if (o->write_hist_log) {
                struct log_params p = {
                        .td = td,
                        .avg_msec = o->log_avg_msec,
@@ -1436,6 +1430,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                        .log_gz = o->log_gz,
                        .log_gz_store = o->log_gz_store,
                };
+               const char *pre = o->hist_log_file ? o->hist_log_file : o->name;
                const char *suf;
 
 #ifndef CONFIG_ZLIB
@@ -1450,12 +1445,12 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                else
                        suf = "log";
 
-               gen_log_name(logname, sizeof(logname), "clat_hist", o->hist_log_file,
+               gen_log_name(logname, sizeof(logname), "clat_hist", pre,
                                td->thread_number, suf, o->per_job_logs);
                setup_log(&td->clat_hist_log, &p, logname);
        }
 
-       if (o->bw_log_file) {
+       if (o->write_bw_log) {
                struct log_params p = {
                        .td = td,
                        .avg_msec = o->log_avg_msec,
@@ -1466,6 +1461,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                        .log_gz = o->log_gz,
                        .log_gz_store = o->log_gz_store,
                };
+               const char *pre = o->bw_log_file ? o->bw_log_file : o->name;
                const char *suf;
 
                if (fio_option_is_set(o, bw_avg_time))
@@ -1481,11 +1477,11 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                else
                        suf = "log";
 
-               gen_log_name(logname, sizeof(logname), "bw", o->bw_log_file,
+               gen_log_name(logname, sizeof(logname), "bw", pre,
                                td->thread_number, suf, o->per_job_logs);
                setup_log(&td->bw_log, &p, logname);
        }
-       if (o->iops_log_file) {
+       if (o->write_iops_log) {
                struct log_params p = {
                        .td = td,
                        .avg_msec = o->log_avg_msec,
@@ -1496,6 +1492,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                        .log_gz = o->log_gz,
                        .log_gz_store = o->log_gz_store,
                };
+               const char *pre = o->iops_log_file ? o->iops_log_file : o->name;
                const char *suf;
 
                if (fio_option_is_set(o, iops_avg_time))
@@ -1511,7 +1508,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                else
                        suf = "log";
 
-               gen_log_name(logname, sizeof(logname), "iops", o->iops_log_file,
+               gen_log_name(logname, sizeof(logname), "iops", pre,
                                td->thread_number, suf, o->per_job_logs);
                setup_log(&td->iops_log, &p, logname);
        }
@@ -1527,15 +1524,16 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                        if (!td_ioengine_flagged(td, FIO_NOIO)) {
                                char *c1, *c2, *c3, *c4;
                                char *c5 = NULL, *c6 = NULL;
+                               int i2p = is_power_of_2(o->kb_base);
 
-                               c1 = fio_uint_to_kmg(o->min_bs[DDIR_READ]);
-                               c2 = fio_uint_to_kmg(o->max_bs[DDIR_READ]);
-                               c3 = fio_uint_to_kmg(o->min_bs[DDIR_WRITE]);
-                               c4 = fio_uint_to_kmg(o->max_bs[DDIR_WRITE]);
+                               c1 = num2str(o->min_bs[DDIR_READ], 4, 1, i2p, N2S_BYTE);
+                               c2 = num2str(o->max_bs[DDIR_READ], 4, 1, i2p, N2S_BYTE);
+                               c3 = num2str(o->min_bs[DDIR_WRITE], 4, 1, i2p, N2S_BYTE);
+                               c4 = num2str(o->max_bs[DDIR_WRITE], 4, 1, i2p, N2S_BYTE);
 
                                if (!o->bs_is_seq_rand) {
-                                       c5 = fio_uint_to_kmg(o->min_bs[DDIR_TRIM]);
-                                       c6 = fio_uint_to_kmg(o->max_bs[DDIR_TRIM]);
+                                       c5 = num2str(o->min_bs[DDIR_TRIM], 4, 1, i2p, N2S_BYTE);
+                                       c6 = num2str(o->max_bs[DDIR_TRIM], 4, 1, i2p, N2S_BYTE);
                                }
 
                                log_info("%s: (g=%d): rw=%s, ", td->o.name,
@@ -1543,10 +1541,10 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                                                        ddir_str(o->td_ddir));
 
                                if (o->bs_is_seq_rand)
-                                       log_info("bs(seq/rand)=%s-%s/%s-%s, ",
+                                       log_info("bs=(R) %s-%s, (W) %s-%s, bs_is_seq_rand, ",
                                                        c1, c2, c3, c4);
                                else
-                                       log_info("bs=%s-%s/%s-%s/%s-%s, ",
+                                       log_info("bs=(R) %s-%s, (W) %s-%s, (T) %s-%s, ",
                                                        c1, c2, c3, c4, c5, c6);
 
                                log_info("ioengine=%s, iodepth=%u\n",
@@ -1563,13 +1561,16 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                        log_info("...\n");
        }
 
+       if (td_steadystate_init(td))
+               goto err;
+
        /*
         * recurse add identical jobs, clear numjobs and stonewall options
         * as they don't apply to sub-jobs
         */
        numjobs = o->numjobs;
        while (--numjobs) {
-               struct thread_data *td_new = get_new_job(0, td, 1, jobname);
+               struct thread_data *td_new = get_new_job(false, td, true, jobname);
 
                if (!td_new)
                        goto err;
@@ -1578,6 +1579,8 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                td_new->o.stonewall = 0;
                td_new->o.new_group = 0;
                td_new->subjob_number = numjobs;
+               td_new->o.ss_dur = o->ss_dur * 1000000l;
+               td_new->o.ss_limit = o->ss_limit;
 
                if (file_alloced) {
                        if (td_new->files) {
@@ -1628,11 +1631,11 @@ void add_job_opts(const char **o, int client_type)
                        sprintf(jobname, "%s", o[i] + 5);
                }
                if (in_global && !td_parent)
-                       td_parent = get_new_job(1, &def_thread, 0, jobname);
+                       td_parent = get_new_job(true, &def_thread, false, jobname);
                else if (!in_global && !td) {
                        if (!td_parent)
                                td_parent = &def_thread;
-                       td = get_new_job(0, td_parent, 0, jobname);
+                       td = get_new_job(false, td_parent, false, jobname);
                }
                if (in_global)
                        fio_options_parse(td_parent, (char **) &o[i], 1);
@@ -1680,11 +1683,11 @@ static int is_empty_or_comment(char *line)
 /*
  * This is our [ini] type file parser.
  */
-int __parse_jobs_ini(struct thread_data *td,
+static int __parse_jobs_ini(struct thread_data *td,
                char *file, int is_buf, int stonewall_flag, int type,
                int nested, char *name, char ***popts, int *aopts, int *nopts)
 {
-       unsigned int global = 0;
+       bool global = false;
        char *string;
        FILE *f;
        char *p;
@@ -1793,7 +1796,7 @@ int __parse_jobs_ini(struct thread_data *td,
                                first_sect = 0;
                        }
 
-                       td = get_new_job(global, &def_thread, 0, name);
+                       td = get_new_job(global, &def_thread, false, name);
                        if (!td) {
                                ret = 1;
                                break;
@@ -1997,6 +2000,11 @@ static void show_debug_categories(void)
 #endif
 }
 
+/*
+ * Following options aren't printed by usage().
+ * --append-terse - Equivalent to --output-format=terse, see f6a7df53.
+ * --latency-log - Deprecated option.
+ */
 static void usage(const char *name)
 {
        printf("%s\n", fio_version_string);
@@ -2005,15 +2013,15 @@ static void usage(const char *name)
        show_debug_categories();
        printf("  --parse-only\t\tParse options only, don't start any IO\n");
        printf("  --output\t\tWrite output to file\n");
-       printf("  --runtime\t\tRuntime in seconds\n");
-       printf("  --bandwidth-log\tGenerate per-job bandwidth logs\n");
+       printf("  --bandwidth-log\tGenerate aggregate bandwidth logs\n");
        printf("  --minimal\t\tMinimal (terse) output\n");
-       printf("  --output-format=x\tOutput format (terse,json,json+,normal)\n");
-       printf("  --terse-version=x\tSet terse version output format to 'x'\n");
+       printf("  --output-format=type\tOutput format (terse,json,json+,normal)\n");
+       printf("  --terse-version=type\tSet terse version output format"
+               " (default 3, or 2 or 4)\n");
        printf("  --version\t\tPrint version info and exit\n");
        printf("  --help\t\tPrint this page\n");
        printf("  --cpuclock-test\tPerform test/validation of CPU clock\n");
-       printf("  --crctest\t\tTest speed of checksum functions\n");
+       printf("  --crctest=type\tTest speed of checksum functions\n");
        printf("  --cmdhelp=cmd\t\tPrint command help, \"all\" for all of"
                " them\n");
        printf("  --enghelp=engine\tPrint ioengine help, or list"
@@ -2029,14 +2037,15 @@ static void usage(const char *name)
        printf(" 't' period passed\n");
        printf("  --readonly\t\tTurn on safety read-only checks, preventing"
                " writes\n");
-       printf("  --section=name\tOnly run specified section in job file\n");
+       printf("  --section=name\tOnly run specified section in job file,"
+               " multiple sections can be specified\n");
        printf("  --alloc-size=kb\tSet smalloc pool to this size in kb"
-               " (def 1024)\n");
+               " (def 16384)\n");
        printf("  --warnings-fatal\tFio parser warnings are fatal\n");
        printf("  --max-jobs=nr\t\tMaximum number of threads/processes to support\n");
        printf("  --server=args\t\tStart a backend fio server\n");
        printf("  --daemonize=pidfile\tBackground fio server, write pid to file\n");
-       printf("  --client=hostname\tTalk to remote backend fio server at hostname\n");
+       printf("  --client=hostname\tTalk to remote backend(s) fio server at hostname\n");
        printf("  --remote-config=file\tTell fio server to load this local job file\n");
        printf("  --idle-prof=option\tReport cpu idleness on a system or percpu basis\n"
                "\t\t\t(option=system,percpu) or run unit work\n"
@@ -2120,6 +2129,14 @@ struct debug_level debug_levels[] = {
          .help = "Log compression logging",
          .shift = FD_COMPRESS,
        },
+       { .name = "steadystate",
+         .help = "Steady state detection logging",
+         .shift = FD_STEADYSTATE,
+       },
+       { .name = "helperthread",
+         .help = "Helper thread logging",
+         .shift = FD_HELPERTHREAD,
+       },
        { .name = NULL, },
 };
 
@@ -2309,13 +2326,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                case 'a':
                        smalloc_pool_size = atoi(optarg);
                        smalloc_pool_size <<= 10;
-                       break;
-               case 't':
-                       if (check_str_time(optarg, &def_timeout, 1)) {
-                               log_err("fio: failed parsing time %s\n", optarg);
-                               do_exit++;
-                               exit_val = 1;
-                       }
+                       sinit();
                        break;
                case 'l':
                        log_err("fio: --latency-log is deprecated. Use per-job latency log options.\n");
@@ -2325,17 +2336,22 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                case 'b':
                        write_bw_log = 1;
                        break;
-               case 'o':
+               case 'o': {
+                       FILE *tmp;
+
                        if (f_out && f_out != stdout)
                                fclose(f_out);
 
-                       f_out = fopen(optarg, "w+");
-                       if (!f_out) {
-                               perror("fopen output");
-                               exit(1);
+                       tmp = fopen(optarg, "w+");
+                       if (!tmp) {
+                               log_err("fio: output file open error: %s\n", strerror(errno));
+                               exit_val = 1;
+                               do_exit++;
+                               break;
                        }
-                       f_err = f_out;
+                       f_err = f_out = tmp;
                        break;
+                       }
                case 'm':
                        output_format = FIO_OUTPUT_TERSE;
                        break;
@@ -2469,7 +2485,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                                if (is_section && skip_this_section(val))
                                        continue;
 
-                               td = get_new_job(global, &def_thread, 1, NULL);
+                               td = get_new_job(global, &def_thread, true, NULL);
                                if (!td || ioengine_load(td)) {
                                        if (td) {
                                                put_job(td);
@@ -2707,7 +2723,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                if (!ret) {
                        ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type);
                        if (ret)
-                               did_arg = 1;
+                               exit(1);
                }
        }
 
@@ -2719,9 +2735,6 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
        }
 
 out_free:
-       if (pid_file)
-               free(pid_file);
-
        return ini_idx;
 }
 
@@ -2790,7 +2803,7 @@ int parse_options(int argc, char *argv[])
                if (did_arg)
                        return 0;
 
-               log_err("No jobs(s) defined\n\n");
+               log_err("No job(s) defined\n\n");
 
                if (!did_arg) {
                        usage(argv[0]);