#include "server.h"
#include "idletime.h"
#include "filelock.h"
+#include "steadystate.h"
#include "oslib/getopt.h"
#include "oslib/strcasestr.h"
static char cmd_optstr[256];
static int did_arg;
+bool steadystate = false;
+
#define FIO_CLIENT_FLAG (1 << 16)
/*
},
{
.name = (char *) "output-format",
- .has_arg = optional_argument,
+ .has_arg = required_argument,
.val = 'F' | FIO_CLIENT_FLAG,
},
{
"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");
/*
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;
}
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;
* 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");
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;
}
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;
}
*(struct thread_data **)td->eo = td;
}
+ if (td->o.odirect)
+ td->io_ops->flags |= FIO_RAWIO;
+
+ td_set_ioengine_flags(td);
return 0;
}
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++)
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)
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,
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,
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";
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,
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";
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;
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
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) {
.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, },
};
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;
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;