#include "filelock.h"
#include "lib/getopt.h"
-#include "lib/strcasestr.h"
+#include "oslib/strcasestr.h"
#include "crc/test.h"
static int nr_job_sections;
int exitall_on_terminate = 0;
+int exitall_on_terminate_error = 0;
int output_format = FIO_OUTPUT_NORMAL;
-int append_terse_output = 0;
int eta_print = FIO_ETA_AUTO;
int eta_new_line = 0;
FILE *f_out = NULL;
char *trigger_cmd = NULL;
char *trigger_remote_cmd = NULL;
+char *aux_path = NULL;
+
static int prev_group_jobs;
unsigned long fio_debug = 0;
.has_arg = required_argument,
.val = 'J',
},
+ {
+ .name = (char *) "aux-path",
+ .has_arg = required_argument,
+ .val = 'K',
+ },
{
.name = NULL,
},
o->timeout = def_timeout;
}
+static void dump_print_option(struct print_option *p)
+{
+ const char *delim;
+
+ if (!strcmp("description", p->name))
+ delim = "\"";
+ else
+ delim = "";
+
+ log_info("--%s%s", p->name, p->value ? "" : " ");
+ if (p->value)
+ log_info("=%s%s%s ", delim, p->value, delim);
+}
+
+static void dump_opt_list(struct thread_data *td)
+{
+ struct flist_head *entry;
+ struct print_option *p;
+
+ if (flist_empty(&td->opt_list))
+ return;
+
+ flist_for_each(entry, &td->opt_list) {
+ p = flist_entry(entry, struct print_option, list);
+ dump_print_option(p);
+ }
+}
+
+static void fio_dump_options_free(struct thread_data *td)
+{
+ while (!flist_empty(&td->opt_list)) {
+ struct print_option *p;
+
+ p = flist_first_entry(&td->opt_list, struct print_option, list);
+ flist_del_init(&p->list);
+ free(p->name);
+ free(p->value);
+ free(p);
+ }
+}
+
+static void copy_opt_list(struct thread_data *dst, struct thread_data *src)
+{
+ struct flist_head *entry;
+
+ if (flist_empty(&src->opt_list))
+ return;
+
+ flist_for_each(entry, &src->opt_list) {
+ struct print_option *srcp, *dstp;
+
+ srcp = flist_entry(entry, struct print_option, list);
+ dstp = malloc(sizeof(*dstp));
+ dstp->name = strdup(srcp->name);
+ if (srcp->value)
+ dstp->value = strdup(srcp->value);
+ else
+ dstp->value = NULL;
+ flist_add_tail(&dstp->list, &dst->opt_list);
+ }
+}
+
/*
* Return a free job structure.
*/
td = &threads[thread_number++];
*td = *parent;
+ INIT_FLIST_HEAD(&td->opt_list);
+ if (parent != &def_thread)
+ copy_opt_list(td, parent);
+
td->io_ops = NULL;
if (!preserve_eo)
td->eo = NULL;
log_info("fio: %s\n", td->verror);
fio_options_free(td);
+ fio_dump_options_free(td);
if (td->io_ops)
free_ioengine(td);
if (td->o.rate[ddir])
td->rate_bps[ddir] = td->o.rate[ddir];
else
- td->rate_bps[ddir] = td->o.rate_iops[ddir] * bs;
+ td->rate_bps[ddir] = (uint64_t) td->o.rate_iops[ddir] * bs;
if (!td->rate_bps[ddir]) {
log_err("rate lower than supported\n");
td->rate_next_io_time[ddir] = 0;
td->rate_io_issue_bytes[ddir] = 0;
+ td->last_usec = 0;
return 0;
}
if (o->iodepth_batch > o->iodepth || !o->iodepth_batch)
o->iodepth_batch = o->iodepth;
+ /*
+ * If max batch complete number isn't set or set incorrectly,
+ * default to the same as iodepth_batch_complete_min
+ */
+ if (o->iodepth_batch_complete_min > o->iodepth_batch_complete_max)
+ o->iodepth_batch_complete_max = o->iodepth_batch_complete_min;
+
if (o->nr_files > td->files_index)
o->nr_files = td->files_index;
/*
* For fully compressible data, just zero them at init time.
- * It's faster than repeatedly filling it.
+ * It's faster than repeatedly filling it. For non-zero
+ * compression, we should have refill_buffers set. Set it, unless
+ * the job file already changed it.
*/
- if (td->o.compress_percentage == 100) {
- td->o.zero_buffers = 1;
- td->o.compress_percentage = 0;
+ if (o->compress_percentage) {
+ if (o->compress_percentage == 100) {
+ o->zero_buffers = 1;
+ o->compress_percentage = 0;
+ } else if (!fio_option_is_set(o, refill_buffers))
+ o->refill_buffers = 1;
}
/*
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);
if (!td_random(td))
return;
if ((o->stonewall || o->new_group) && prev_group_jobs) {
prev_group_jobs = 0;
groupid++;
+ if (groupid == INT_MAX) {
+ log_err("fio: too many groups defined\n");
+ goto err;
+ }
}
td->groupid = groupid;
if (!o->name)
o->name = strdup(jobname);
- if (output_format == FIO_OUTPUT_NORMAL) {
+ if (output_format & FIO_OUTPUT_NORMAL) {
if (!job_add_num) {
if (is_backend && !recursed)
fio_server_send_add_job(td);
td = get_new_job(0, td_parent, 0, jobname);
}
if (in_global)
- fio_options_parse(td_parent, (char **) &o[i], 1, 0);
+ fio_options_parse(td_parent, (char **) &o[i], 1);
else
- fio_options_parse(td, (char **) &o[i], 1, 0);
+ fio_options_parse(td, (char **) &o[i], 1);
i++;
}
goto out;
}
- ret = fio_options_parse(td, opts, num_opts, dump_cmdline);
- if (!ret)
+ ret = fio_options_parse(td, opts, num_opts);
+ if (!ret) {
+ if (dump_cmdline)
+ dump_opt_list(td);
+
ret = add_job(td, name, 0, 0, type);
- else {
+ } else {
log_err("fio: job %s dropped\n", name);
put_job(td);
}
static int fill_def_thread(void)
{
memset(&def_thread, 0, sizeof(def_thread));
+ INIT_FLIST_HEAD(&def_thread.opt_list);
fio_getaffinity(getpid(), &def_thread.o.cpumask);
def_thread.o.error_dump = 1;
printf(" --runtime\t\tRuntime in seconds\n");
printf(" --bandwidth-log\tGenerate per-job bandwidth logs\n");
printf(" --minimal\t\tMinimal (terse) output\n");
- printf(" --output-format=x\tOutput format (terse,json,normal)\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(" --version\t\tPrint version info and exit\n");
printf(" --help\t\tPrint this page\n");
printf(" --trigger-timeout=t\tExecute trigger af this time\n");
printf(" --trigger=cmd\t\tSet this command as local trigger\n");
printf(" --trigger-remote=cmd\tSet this command as remote trigger\n");
+ printf(" --aux-path=path\tUse this path for fio state generated files\n");
printf("\nFio was written by Jens Axboe <jens.axboe@oracle.com>");
printf("\n Jens Axboe <jaxboe@fusionio.com>");
printf("\n Jens Axboe <axboe@fb.com>\n");
char *opt;
int i;
+ if (!string)
+ return 0;
+
if (!strcmp(string, "?") || !strcmp(string, "help")) {
log_info("fio: dumping debug options:");
for (i = 0; debug_levels[i].name; i++) {
i++;
}
- if (best_option != -1)
+ if (best_option != -1 && string_distance_ok(name, best_distance))
log_err("Did you mean %s?\n", l_opts[best_option].name);
}
+static int parse_output_format(const char *optarg)
+{
+ char *p, *orig, *opt;
+ int ret = 0;
+
+ p = orig = strdup(optarg);
+
+ output_format = 0;
+
+ while ((opt = strsep(&p, ",")) != NULL) {
+ if (!strcmp(opt, "minimal") ||
+ !strcmp(opt, "terse") ||
+ !strcmp(opt, "csv"))
+ output_format |= FIO_OUTPUT_TERSE;
+ else if (!strcmp(opt, "json"))
+ output_format |= FIO_OUTPUT_JSON;
+ else if (!strcmp(opt, "json+"))
+ output_format |= (FIO_OUTPUT_JSON | FIO_OUTPUT_JSON_PLUS);
+ else if (!strcmp(opt, "normal"))
+ output_format |= FIO_OUTPUT_NORMAL;
+ else {
+ log_err("fio: invalid output format %s\n", opt);
+ ret = 1;
+ break;
+ }
+ }
+
+ free(orig);
+ return ret;
+}
+
int parse_cmd_line(int argc, char *argv[], int client_type)
{
struct thread_data *td = NULL;
do_exit++;
break;
}
- if (!strcmp(optarg, "minimal") ||
- !strcmp(optarg, "terse") ||
- !strcmp(optarg, "csv"))
- output_format = FIO_OUTPUT_TERSE;
- else if (!strcmp(optarg, "json"))
- output_format = FIO_OUTPUT_JSON;
- else
- output_format = FIO_OUTPUT_NORMAL;
+ if (parse_output_format(optarg)) {
+ log_err("fio: failed parsing output-format\n");
+ exit_val = 1;
+ do_exit++;
+ break;
+ }
break;
case 'f':
- append_terse_output = 1;
+ output_format |= FIO_OUTPUT_TERSE;
break;
case 'h':
did_arg = 1;
free(trigger_remote_cmd);
trigger_remote_cmd = strdup(optarg);
break;
+ case 'K':
+ if (aux_path)
+ free(aux_path);
+ aux_path = strdup(optarg);
+ break;
case 'B':
if (check_str_time(optarg, &trigger_timeout, 1)) {
log_err("fio: failed parsing time %s\n", optarg);
return 0;
}
- if (output_format == FIO_OUTPUT_NORMAL)
+ if (output_format & FIO_OUTPUT_NORMAL)
log_info("%s\n", fio_version_string);
return 0;
{
memcpy(o, &def_thread.o, sizeof(*o));
}
+
+struct thread_data *get_global_options(void)
+{
+ return &def_thread;
+}