X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=init.c;h=7be31a14fa2ca910aa02a29b8560439c69edab1d;hp=065a71a58e1611d8388b2fc674d03ea966c139a3;hb=e569ca6bfecb44f42f8e52cf2c294728c4bf3a1b;hpb=883e4841d5466955ad464ee3a6b37e009cfa80ef diff --git a/init.c b/init.c index 065a71a5..7be31a14 100644 --- 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;