#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;
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;
.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,
},
{
.name = (char *) "bandwidth-log",
- .has_arg = required_argument,
+ .has_arg = no_argument,
.val = 'b' | FIO_CLIENT_FLAG,
},
{
static void free_shm(void)
{
if (threads) {
- file_hash_exit();
flow_exit();
fio_debug_jobp = NULL;
free_threads_shm();
options_free(fio_options, &def_thread.o);
fio_filelock_exit();
+ file_hash_exit();
scleanup();
}
*/
static int setup_thread_area(void)
{
- void *hash;
-
if (threads)
return 0;
do {
size_t size = max_jobs * sizeof(struct thread_data);
- size += file_hash_size;
size += sizeof(unsigned int);
#ifndef CONFIG_NO_SHM
#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;
{
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;
if (!parent->o.group_reporting || parent == &def_thread)
stat_number++;
- set_cmd_options(td);
return td;
}
return delayrange;
}
+static unsigned int gcd(unsigned int m, unsigned int n)
+{
+ unsigned int r;
+
+ if (!m || !n)
+ return 0;
+
+ do {
+ r = m % n;
+ if (!r)
+ break;
+ m = n;
+ n = r;
+ } while (1);
+
+ return n;
+}
+
/*
* Lazy way of fixing up options that depend on each other. We could also
* define option callback handlers, but this is easier.
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) {
* 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;
}
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)
{
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,
.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)
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) {
-#ifndef CONFIG_ZLIB
- if (td->client_type) {
- log_err("fio: --write_hist_log requires zlib in client/server mode\n");
- goto err;
- }
-#endif
+ if (o->write_hist_log) {
struct log_params p = {
.td = td,
.avg_msec = o->log_avg_msec,
.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
+ if (td->client_type) {
+ log_err("fio: --write_hist_log requires zlib in client/server mode\n");
+ goto err;
+ }
+#endif
+
if (p.log_gz_store)
suf = "log.fz";
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,
.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))
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,
.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))
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);
}
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,
ddir_str(o->td_ddir));
if (o->bs_is_seq_rand)
- log_info("bs(seq/rand)=%s-%s/%s-%s, ",
+ log_info("bs=%s-%s,%s-%s, bs_is_seq_rand, ",
c1, c2, c3, c4);
else
- log_info("bs=%s-%s/%s-%s/%s-%s, ",
+ log_info("bs=%s-%s,%s-%s,%s-%s, ",
c1, c2, c3, c4, c5, c6);
log_info("ioengine=%s, iodepth=%u\n",
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
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) {
/*
* 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)
{
#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);
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"
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"
.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, },
};
switch (c) {
case 'a':
smalloc_pool_size = atoi(optarg);
- 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;
- }
+ smalloc_pool_size <<= 10;
+ sinit();
break;
case 'l':
log_err("fio: --latency-log is deprecated. Use per-job latency log options.\n");