Split helper thread debug logging away from steadystate debug logging
[fio.git] / init.c
diff --git a/init.c b/init.c
index 065a71a58e1611d8388b2fc674d03ea966c139a3..7be31a14fa2ca910aa02a29b8560439c69edab1d 100644 (file)
--- a/init.c
+++ b/init.c
@@ -25,6 +25,7 @@
 #include "server.h"
 #include "idletime.h"
 #include "filelock.h"
+#include "steadystate.h"
 
 #include "oslib/getopt.h"
 #include "oslib/strcasestr.h"
@@ -80,6 +81,8 @@ unsigned int *fio_debug_jobp = NULL;
 static char cmd_optstr[256];
 static int did_arg;
 
+bool steadystate = false;
+
 #define FIO_CLIENT_FLAG                (1 << 16)
 
 /*
@@ -114,7 +117,7 @@ static struct option l_opts[FIO_NR_OPTIONS] = {
        },
        {
                .name           = (char *) "output-format",
-               .has_arg        = optional_argument,
+               .has_arg        = required_argument,
                .val            = 'F' | FIO_CLIENT_FLAG,
        },
        {
@@ -677,7 +680,7 @@ static int fixup_options(struct thread_data *td)
                        "verify limited\n");
                ret = warnings_fatal;
        }
-       if (o->bs_unaligned && (o->odirect || td->io_ops->flags & FIO_RAWIO))
+       if (o->bs_unaligned && (o->odirect || td_ioengine_flagged(td, FIO_RAWIO)))
                log_err("fio: bs_unaligned may not work with raw io\n");
 
        /*
@@ -764,7 +767,7 @@ static int fixup_options(struct thread_data *td)
 
        if (o->pre_read) {
                o->invalidate_cache = 0;
-               if (td->io_ops->flags & FIO_PIPEIO) {
+               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");
                        ret = warnings_fatal;
@@ -772,7 +775,7 @@ static int fixup_options(struct thread_data *td)
        }
 
        if (!o->unit_base) {
-               if (td->io_ops->flags & FIO_BIT_BASED)
+               if (td_ioengine_flagged(td, FIO_BIT_BASED))
                        o->unit_base = 1;
                else
                        o->unit_base = 8;
@@ -795,7 +798,7 @@ static int fixup_options(struct thread_data *td)
         * Windows doesn't support O_DIRECT or O_SYNC with the _open interface,
         * so fail if we're passed those flags
         */
-       if ((td->io_ops->flags & FIO_SYNCIO) && (td->o.odirect || td->o.sync_io)) {
+       if (td_ioengine_flagged(td, FIO_SYNCIO) && (td->o.odirect || td->o.sync_io)) {
                log_err("fio: Windows does not support direct or non-buffered io with"
                                " the synchronous ioengines. Use the 'windowsaio' ioengine"
                                " with 'direct=1' and 'iodepth=1' instead.\n");
@@ -844,7 +847,7 @@ static int fixup_options(struct thread_data *td)
        if (fio_option_is_set(&td->o, rand_seed))
                td->o.rand_repeatable = 0;
 
-       if ((td->io_ops->flags & FIO_NOEXTEND) && td->o.file_append) {
+       if (td_ioengine_flagged(td, FIO_NOEXTEND) && td->o.file_append) {
                log_err("fio: can't append/extent with IO engine %s\n", td->io_ops->name);
                ret = 1;
        }
@@ -860,7 +863,7 @@ static int fixup_options(struct thread_data *td)
                td->loops = 1;
 
        if (td->o.block_error_hist && td->o.nr_files != 1) {
-               log_err("fio: block error histogram only available with "
+               log_err("fio: block error histogram only available "
                        "with a single file per job, but %d files "
                        "provided\n", td->o.nr_files);
                ret = 1;
@@ -904,17 +907,22 @@ static const char *get_engine_name(const char *str)
        return p;
 }
 
-static int exists_and_not_file(const char *filename)
+static int exists_and_not_regfile(const char *filename)
 {
        struct stat sb;
 
        if (lstat(filename, &sb) == -1)
                return 0;
 
+#ifndef WIN32 /* NOT Windows */
+       if (S_ISREG(sb.st_mode))
+               return 0;
+#else
        /* \\.\ is the device namespace in Windows, where every file
         * is a device node */
        if (S_ISREG(sb.st_mode) && strncmp(filename, "\\\\.\\", 4) != 0)
                return 0;
+#endif
 
        return 1;
 }
@@ -1064,6 +1072,10 @@ int ioengine_load(struct thread_data *td)
                *(struct thread_data **)td->eo = td;
        }
 
+       if (td->o.odirect)
+               td->io_ops->flags |= FIO_RAWIO;
+
+       td_set_ioengine_flags(td);
        return 0;
 }
 
@@ -1335,14 +1347,11 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
        if (ioengine_load(td))
                goto err;
 
-       if (o->odirect)
-               td->io_ops->flags |= FIO_RAWIO;
-
        file_alloced = 0;
        if (!o->filename && !td->files_index && !o->read_iolog_file) {
                file_alloced = 1;
 
-               if (o->nr_files == 1 && exists_and_not_file(jobname))
+               if (o->nr_files == 1 && exists_and_not_regfile(jobname))
                        add_file(td, jobname, job_add_num, 0);
                else {
                        for (i = 0; i < o->nr_files; i++)
@@ -1368,7 +1377,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
        if (td->eo)
                *(struct thread_data **)td->eo = NULL;
 
-       if (td->io_ops->flags & FIO_DISKLESSIO) {
+       if (td_ioengine_flagged(td, FIO_DISKLESSIO)) {
                struct fio_file *f;
 
                for_each_file(td, f, i)
@@ -1413,6 +1422,8 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                struct log_params p = {
                        .td = td,
                        .avg_msec = o->log_avg_msec,
+                       .hist_msec = o->log_hist_msec,
+                       .hist_coarseness = o->log_hist_coarseness,
                        .log_type = IO_LOG_TYPE_LAT,
                        .log_offset = o->log_offset,
                        .log_gz = o->log_gz,
@@ -1437,10 +1448,36 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                                td->thread_number, suf, o->per_job_logs);
                setup_log(&td->clat_log, &p, logname);
        }
+
+       if (o->hist_log_file) {
+               struct log_params p = {
+                       .td = td,
+                       .avg_msec = o->log_avg_msec,
+                       .hist_msec = o->log_hist_msec,
+                       .hist_coarseness = o->log_hist_coarseness,
+                       .log_type = IO_LOG_TYPE_HIST,
+                       .log_offset = o->log_offset,
+                       .log_gz = o->log_gz,
+                       .log_gz_store = o->log_gz_store,
+               };
+               const char *suf;
+
+               if (p.log_gz_store)
+                       suf = "log.fz";
+               else
+                       suf = "log";
+
+               gen_log_name(logname, sizeof(logname), "clat_hist", o->hist_log_file,
+                               td->thread_number, suf, o->per_job_logs);
+               setup_log(&td->clat_hist_log, &p, logname);
+       }
+
        if (o->bw_log_file) {
                struct log_params p = {
                        .td = td,
                        .avg_msec = o->log_avg_msec,
+                       .hist_msec = o->log_hist_msec,
+                       .hist_coarseness = o->log_hist_coarseness,
                        .log_type = IO_LOG_TYPE_BW,
                        .log_offset = o->log_offset,
                        .log_gz = o->log_gz,
@@ -1452,6 +1489,9 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                        p.avg_msec = min(o->log_avg_msec, o->bw_avg_time);
                else
                        o->bw_avg_time = p.avg_msec;
+       
+               p.hist_msec = o->log_hist_msec;
+               p.hist_coarseness = o->log_hist_coarseness;
 
                if (p.log_gz_store)
                        suf = "log.fz";
@@ -1466,6 +1506,8 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                struct log_params p = {
                        .td = td,
                        .avg_msec = o->log_avg_msec,
+                       .hist_msec = o->log_hist_msec,
+                       .hist_coarseness = o->log_hist_coarseness,
                        .log_type = IO_LOG_TYPE_IOPS,
                        .log_offset = o->log_offset,
                        .log_gz = o->log_gz,
@@ -1477,6 +1519,9 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                        p.avg_msec = min(o->log_avg_msec, o->iops_avg_time);
                else
                        o->iops_avg_time = p.avg_msec;
+       
+               p.hist_msec = o->log_hist_msec;
+               p.hist_coarseness = o->log_hist_coarseness;
 
                if (p.log_gz_store)
                        suf = "log.fz";
@@ -1496,7 +1541,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                        if (is_backend && !recursed)
                                fio_server_send_add_job(td);
 
-                       if (!(td->io_ops->flags & FIO_NOIO)) {
+                       if (!td_ioengine_flagged(td, FIO_NOIO)) {
                                char *c1, *c2, *c3, *c4;
                                char *c5 = NULL, *c6 = NULL;
 
@@ -1535,6 +1580,50 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                        log_info("...\n");
        }
 
+       if (o->ss_dur) {
+               steadystate = true;
+               o->ss_dur /= 1000000L;
+
+               /* put all steady state info in one place */
+               td->ss.dur = o->ss_dur;
+               td->ss.limit = o->ss_limit.u.f; 
+               td->ss.ramp_time = o->ss_ramp_time;
+               td->ss.pct = o->ss_pct;
+
+               if (o->ss == FIO_STEADYSTATE_IOPS_SLOPE || o->ss == FIO_STEADYSTATE_BW_SLOPE) {
+                       td->ss.check_slope = true;
+                       td->ss.evaluate = &steadystate_slope;
+               } else {
+                       td->ss.check_slope = false;
+                       td->ss.evaluate = &steadystate_deviation;
+               }
+
+               if (o->ss == FIO_STEADYSTATE_IOPS || o->ss == FIO_STEADYSTATE_IOPS_SLOPE)
+                       td->ss.check_iops = true;
+               else
+                       td->ss.check_iops = false;
+
+               td->ss.bw_data = NULL;
+               td->ss.iops_data = NULL;
+               td->ss.ramp_time_over = (td->ss.ramp_time == 0);
+               td->ss.attained = 0;
+               td->ss.last_in_group = 0;
+               td->ss.head = 0;
+               td->ss.tail = 0;
+               td->ss.sum_x = o->ss_dur * (o->ss_dur - 1) / 2;
+               td->ss.sum_x_sq = (o->ss_dur - 1) * (o->ss_dur) * (2*o->ss_dur - 1) / 6;
+               td->ss.prev_bytes = 0;
+               td->ss.prev_iops = 0;
+               td->ss.sum_y = 0;
+               td->ss.oldest_y = 0;
+               td->ss.criterion = 0.0;
+               td->ss.slope = 0.0;
+               td->ss.deviation = 0.0;
+               td->ts.ss = &td->ss;
+       }
+       else
+               td->ts.ss = NULL;
+
        /*
         * recurse add identical jobs, clear numjobs and stonewall options
         * as they don't apply to sub-jobs
@@ -1550,6 +1639,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) {
@@ -2092,6 +2183,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, },
 };
 
@@ -2261,7 +2360,7 @@ 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 *ostr = cmd_optstr;
-       void *pid_file = NULL;
+       char *pid_file = NULL;
        void *cur_client = NULL;
        int backend = 0;
 
@@ -2311,12 +2410,6 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        output_format = FIO_OUTPUT_TERSE;
                        break;
                case 'F':
-                       if (!optarg) {
-                               log_err("fio: missing --output-format argument\n");
-                               exit_val = 1;
-                               do_exit++;
-                               break;
-                       }
                        if (parse_output_format(optarg)) {
                                log_err("fio: failed parsing output-format\n");
                                exit_val = 1;