.has_arg = optional_argument,
.val = 'S',
},
+#ifdef WIN32
+ {
+ .name = (char *) "server-internal",
+ .has_arg = required_argument,
+ .val = 'N',
+ },
+#endif
{ .name = (char *) "daemonize",
.has_arg = required_argument,
.val = 'D',
}
}
-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;
ret |= 1;
}
+ if (o->zone_mode == ZONE_MODE_ZBD && !o->create_serialize) {
+ log_err("fio: --zonemode=zbd and --create_serialize=0 are not compatible.\n");
+ ret |= 1;
+ }
+
if (o->zone_mode == ZONE_MODE_STRIDED && !o->zone_size) {
log_err("fio: --zonesize must be specified when using --zonemode=strided.\n");
ret |= 1;
ret |= 1;
}
- /*
- * O_ATOMIC implies O_DIRECT
- */
- if (o->oatomic)
- o->odirect = 1;
-
/*
* If randseed is set, that overrides randrepeat
*/
/*
* Fix these up to be nsec internally
*/
- o->max_latency *= 1000ULL;
+ for_each_rw_ddir(ddir)
+ o->max_latency[ddir] *= 1000ULL;
+
o->latency_target *= 1000ULL;
+ /*
+ * Dedupe working set verifications
+ */
+ if (o->dedupe_percentage && o->dedupe_mode == DEDUPE_MODE_WORKING_SET) {
+ if (!fio_option_is_set(o, size)) {
+ log_err("fio: pregenerated dedupe working set "
+ "requires size to be set\n");
+ ret |= 1;
+ } else if (o->nr_files != 1) {
+ log_err("fio: dedupe working set mode supported with "
+ "single file per job, but %d files "
+ "provided\n", o->nr_files);
+ ret |= 1;
+ } else if (o->dedupe_working_set_percentage + o->dedupe_percentage > 100) {
+ log_err("fio: impossible to reach expected dedupe percentage %u "
+ "since %u percentage of size is reserved to dedupe working set "
+ "(those are unique pages)\n",
+ o->dedupe_percentage, o->dedupe_working_set_percentage);
+ ret |= 1;
+ }
+ }
+
+ for_each_td(td2) {
+ if (td->o.ss_check_interval != td2->o.ss_check_interval) {
+ log_err("fio: conflicting ss_check_interval: %llu and %llu, must be globally equal\n",
+ td->o.ss_check_interval, td2->o.ss_check_interval);
+ ret |= 1;
+ }
+ } end_for_each();
+ if (td->o.ss_dur && td->o.ss_check_interval / 1000L < 1000) {
+ log_err("fio: ss_check_interval must be at least 1s\n");
+ ret |= 1;
+
+ }
+ if (td->o.ss_dur && (td->o.ss_dur % td->o.ss_check_interval != 0 || td->o.ss_dur <= td->o.ss_check_interval)) {
+ log_err("fio: ss_duration %lluus must be multiple of ss_check_interval %lluus\n",
+ td->o.ss_dur, td->o.ss_check_interval);
+ ret |= 1;
+ }
+
+
return ret;
}
}
}
-void td_fill_verify_state_seed(struct thread_data *td)
+void td_fill_rand_seeds(struct thread_data *td)
{
+ uint64_t read_seed = td->rand_seeds[FIO_RAND_BS_OFF];
+ uint64_t write_seed = td->rand_seeds[FIO_RAND_BS1_OFF];
+ uint64_t trim_seed = td->rand_seeds[FIO_RAND_BS2_OFF];
+ int i;
bool use64;
if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE64)
else
use64 = false;
- init_rand_seed(&td->verify_state, td->rand_seeds[FIO_RAND_VER_OFF],
- use64);
-}
-
-static void td_fill_rand_seeds_internal(struct thread_data *td, bool use64)
-{
- uint64_t read_seed = td->rand_seeds[FIO_RAND_BS_OFF];
- uint64_t write_seed = td->rand_seeds[FIO_RAND_BS1_OFF];
- uint64_t trim_seed = td->rand_seeds[FIO_RAND_BS2_OFF];
- int i;
-
/*
* trimwrite is special in that we need to generate the same
* offsets to get the "write after trim" effect. If we are
init_rand_seed(&td->bsrange_state[DDIR_WRITE], write_seed, use64);
init_rand_seed(&td->bsrange_state[DDIR_TRIM], trim_seed, use64);
- td_fill_verify_state_seed(td);
+ init_rand_seed(&td->verify_state, td->rand_seeds[FIO_RAND_VER_OFF],
+ use64);
init_rand_seed(&td->rwmix_state, td->rand_seeds[FIO_RAND_MIX_OFF], false);
if (td->o.file_service_type == FIO_FSERVICE_RANDOM)
init_rand_seed(&td->dedupe_state, td->rand_seeds[FIO_DEDUPE_OFF], false);
init_rand_seed(&td->zone_state, td->rand_seeds[FIO_RAND_ZONE_OFF], false);
init_rand_seed(&td->prio_state, td->rand_seeds[FIO_RAND_PRIO_CMDS], false);
-
- if (!td_random(td))
- return;
-
- if (td->o.rand_repeatable)
- td->rand_seeds[FIO_RAND_BLOCK_OFF] = FIO_RANDSEED * td->thread_number;
+ init_rand_seed(&td->dedupe_working_set_index_state, td->rand_seeds[FIO_RAND_DEDUPE_WORKING_SET_IX], use64);
init_rand_seed(&td->random_state, td->rand_seeds[FIO_RAND_BLOCK_OFF], use64);
init_rand_seed(s, td->rand_seeds[FIO_RAND_SEQ_RAND_READ_OFF], false);
}
+
+ init_rand_seed(&td->buf_state, td->rand_seeds[FIO_RAND_BUF_OFF], use64);
+ frand_copy(&td->buf_state_prev, &td->buf_state);
}
-void td_fill_rand_seeds(struct thread_data *td)
+static int setup_random_seeds(struct thread_data *td)
{
- bool use64;
-
- if (td->o.allrand_repeatable) {
- unsigned int i;
+ uint64_t seed;
+ unsigned int i;
- for (i = 0; i < FIO_RAND_NR_OFFS; i++)
- td->rand_seeds[i] = FIO_RANDSEED * td->thread_number
- + i;
+ if (!td->o.rand_repeatable && !fio_option_is_set(&td->o, rand_seed)) {
+ int ret = init_random_seeds(td->rand_seeds, sizeof(td->rand_seeds));
+ dprint(FD_RANDOM, "using system RNG for random seeds\n");
+ if (ret)
+ return ret;
+ } else {
+ seed = td->o.rand_seed;
+ for (i = 0; i < 4; i++)
+ seed *= 0x9e370001UL;
+
+ for (i = 0; i < FIO_RAND_NR_OFFS; i++) {
+ td->rand_seeds[i] = seed * td->thread_number + i;
+ seed *= 0x9e370001UL;
+ }
}
- if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE64)
- use64 = true;
- else
- use64 = false;
+ td_fill_rand_seeds(td);
- td_fill_rand_seeds_internal(td, use64);
+ dprint(FD_RANDOM, "FIO_RAND_NR_OFFS=%d\n", FIO_RAND_NR_OFFS);
+ for (int i = 0; i < FIO_RAND_NR_OFFS; i++)
+ dprint(FD_RANDOM, "rand_seeds[%d]=%" PRIu64 "\n", i, td->rand_seeds[i]);
- init_rand_seed(&td->buf_state, td->rand_seeds[FIO_RAND_BUF_OFF], use64);
- frand_copy(&td->buf_state_prev, &td->buf_state);
+ return 0;
}
/*
}
}
-static int setup_random_seeds(struct thread_data *td)
-{
- uint64_t seed;
- unsigned int i;
-
- if (!td->o.rand_repeatable && !fio_option_is_set(&td->o, rand_seed)) {
- int ret = init_random_seeds(td->rand_seeds, sizeof(td->rand_seeds));
- if (!ret)
- td_fill_rand_seeds(td);
- return ret;
- }
-
- seed = td->o.rand_seed;
- for (i = 0; i < 4; i++)
- seed *= 0x9e370001UL;
-
- for (i = 0; i < FIO_RAND_NR_OFFS; i++) {
- td->rand_seeds[i] = seed * td->thread_number + i;
- seed *= 0x9e370001UL;
- }
-
- td_fill_rand_seeds(td);
- return 0;
-}
-
enum {
FPRE_NONE = 0,
FPRE_JOBNAME,
FPRE_JOBNUM,
- FPRE_FILENUM
+ FPRE_FILENUM,
+ FPRE_CLIENTUID
};
static struct fpre_keyword {
{ .keyword = "$jobname", .key = FPRE_JOBNAME, },
{ .keyword = "$jobnum", .key = FPRE_JOBNUM, },
{ .keyword = "$filenum", .key = FPRE_FILENUM, },
+ { .keyword = "$clientuid", .key = FPRE_CLIENTUID, },
{ .keyword = NULL, },
};
}
break;
}
+ case FPRE_CLIENTUID: {
+ int ret;
+ ret = snprintf(dst, dst_left, "%s", client_sockaddr_str);
+ if (ret < 0)
+ break;
+ else if (ret > dst_left) {
+ log_err("fio: truncated filename\n");
+ dst += dst_left;
+ dst_left = 0;
+ } else {
+ dst += ret;
+ dst_left -= ret;
+ }
+ break;
+ }
default:
assert(0);
break;
static int check_waitees(char *waitee)
{
- struct thread_data *td;
- int i, ret = 0;
+ int ret = 0;
- for_each_td(td, i) {
+ for_each_td(td) {
if (td->subjob_number)
continue;
ret += !strcmp(td->o.name, waitee);
- }
+ } end_for_each();
return ret;
}
return true;
}
+static int verify_per_group_options(struct thread_data *td, const char *jobname)
+{
+ for_each_td(td2) {
+ if (td->groupid != td2->groupid)
+ continue;
+
+ if (td->o.stats &&
+ td->o.lat_percentiles != td2->o.lat_percentiles) {
+ log_err("fio: lat_percentiles in job: %s differs from group\n",
+ jobname);
+ return 1;
+ }
+ } end_for_each();
+
+ return 0;
+}
+
/*
* Treat an empty log file name the same as a one not given
*/
if (fixup_options(td))
goto err;
+ if (!td->o.dedupe_global && init_dedupe_working_set_seeds(td, 0))
+ goto err;
+
/*
* Belongs to fixup_options, but o->name is not necessarily set as yet
*/
memcpy(td->ts.percentile_list, o->percentile_list, sizeof(o->percentile_list));
td->ts.sig_figs = o->sig_figs;
- for (i = 0; i < DDIR_RWDIR_CNT; i++) {
- td->ts.clat_stat[i].min_val = ULONG_MAX;
- td->ts.slat_stat[i].min_val = ULONG_MAX;
- td->ts.lat_stat[i].min_val = ULONG_MAX;
- td->ts.bw_stat[i].min_val = ULONG_MAX;
- td->ts.iops_stat[i].min_val = ULONG_MAX;
- td->ts.clat_high_prio_stat[i].min_val = ULONG_MAX;
- td->ts.clat_low_prio_stat[i].min_val = ULONG_MAX;
- }
- td->ts.sync_stat.min_val = ULONG_MAX;
- td->ddir_seq_nr = o->ddir_seq_nr;
+ init_thread_stat_min_vals(&td->ts);
+
+ /*
+ * td->>ddir_seq_nr needs to be initialized to 1, NOT o->ddir_seq_nr,
+ * so that get_next_offset gets a new random offset the first time it
+ * is called, instead of keeping an initial offset of 0 for the first
+ * nr-1 calls
+ */
+ td->ddir_seq_nr = 1;
if ((o->stonewall || o->new_group) && prev_group_jobs) {
prev_group_jobs = 0;
td->groupid = groupid;
prev_group_jobs++;
+ if (td->o.group_reporting && prev_group_jobs > 1 &&
+ verify_per_group_options(td, jobname))
+ goto err;
+
if (setup_rate(td))
goto err;
.hist_coarseness = o->log_hist_coarseness,
.log_type = IO_LOG_TYPE_LAT,
.log_offset = o->log_offset,
+ .log_prio = o->log_prio,
.log_gz = o->log_gz,
.log_gz_store = o->log_gz_store,
};
else
suf = "log";
- gen_log_name(logname, sizeof(logname), "lat", pre,
- td->thread_number, suf, o->per_job_logs);
- setup_log(&td->lat_log, &p, logname);
+ if (!o->disable_lat) {
+ 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", pre,
- td->thread_number, suf, o->per_job_logs);
- setup_log(&td->slat_log, &p, logname);
+ if (!o->disable_slat) {
+ 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", pre,
- td->thread_number, suf, o->per_job_logs);
- setup_log(&td->clat_log, &p, logname);
+ if (!o->disable_clat) {
+ gen_log_name(logname, sizeof(logname), "clat", pre,
+ td->thread_number, suf, o->per_job_logs);
+ setup_log(&td->clat_log, &p, logname);
+ }
}
.hist_coarseness = o->log_hist_coarseness,
.log_type = IO_LOG_TYPE_HIST,
.log_offset = o->log_offset,
+ .log_prio = o->log_prio,
.log_gz = o->log_gz,
.log_gz_store = o->log_gz_store,
};
.hist_coarseness = o->log_hist_coarseness,
.log_type = IO_LOG_TYPE_BW,
.log_offset = o->log_offset,
+ .log_prio = o->log_prio,
.log_gz = o->log_gz,
.log_gz_store = o->log_gz_store,
};
.hist_coarseness = o->log_hist_coarseness,
.log_type = IO_LOG_TYPE_IOPS,
.log_offset = o->log_offset,
+ .log_prio = o->log_prio,
.log_gz = o->log_gz,
.log_gz_store = o->log_gz_store,
};
i++;
}
+ free(job_sections);
+ job_sections = NULL;
+ nr_job_sections = 0;
+
free(opts);
out:
free(string);
printf(" --minimal\t\tMinimal (terse) output\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");
+ " (default 3, or 2 or 4 or 5)\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");
break;
ret = fio_cmd_ioengine_option_parse(td, opt, val);
+
+ if (ret) {
+ if (td) {
+ put_job(td);
+ td = NULL;
+ }
+ do_exit++;
+ exit_val = 1;
+ }
break;
}
case 'w':
exit_val = 1;
#endif
break;
+#ifdef WIN32
+ case 'N':
+ did_arg = true;
+ fio_server_internal_set(optarg);
+ break;
+#endif
case 'D':
if (pid_file)
free(pid_file);
log_err("%s: unrecognized option '%s'\n", argv[0],
argv[optind - 1]);
show_closest_option(argv[optind - 1]);
- fallthrough;
+ fio_fallthrough;
default:
do_exit++;
exit_val = 1;