#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/types.h>
-#include <sys/stat.h>
#include <dlfcn.h>
#ifdef CONFIG_VALGRIND_DEV
#include <valgrind/drd.h>
int warnings_fatal = 0;
int terse_version = 3;
int is_backend = 0;
+int is_local_backend = 0;
int nr_clients = 0;
int log_syslog = 0;
{
.name = (char *) "status-interval",
.has_arg = required_argument,
- .val = 'L',
+ .val = 'L' | FIO_CLIENT_FLAG,
},
{
.name = (char *) "trigger-file",
static int __setup_rate(struct thread_data *td, enum fio_ddir ddir)
{
- unsigned int bs = td->o.min_bs[ddir];
+ unsigned long long bs = td->o.min_bs[ddir];
assert(ddir_rw(ddir));
o->min_bs[DDIR_READ] == o->min_bs[DDIR_TRIM];
}
-
-static unsigned long long get_rand_start_delay(struct thread_data *td)
-{
- unsigned long long delayrange;
- uint64_t frand_max;
- unsigned long r;
-
- delayrange = td->o.start_delay_high - td->o.start_delay;
-
- frand_max = rand_max(&td->delay_state);
- r = __rand(&td->delay_state);
- delayrange = (unsigned long long) ((double) delayrange * (r / (frand_max + 1.0)));
-
- delayrange += td->o.start_delay;
- return delayrange;
-}
-
/*
* <3 Johannes
*/
struct thread_options *o = &td->o;
int ret = 0;
+ if (read_only && (td_write(td) || td_trim(td))) {
+ log_err("fio: trim and write operations are not allowed"
+ " with the --readonly parameter.\n");
+ ret |= 1;
+ }
+
#ifndef CONFIG_PSHARED
if (!o->use_thread) {
log_info("fio: this platform does not support process shared"
" mutexes, forcing use of threads. Use the 'thread'"
" option to get rid of this warning.\n");
o->use_thread = 1;
- ret = warnings_fatal;
+ ret |= warnings_fatal;
}
#endif
log_err("fio: read iolog overrides write_iolog\n");
free(o->write_iolog_file);
o->write_iolog_file = NULL;
- ret = warnings_fatal;
+ ret |= warnings_fatal;
+ }
+
+ if (o->zone_mode == ZONE_MODE_NONE && o->zone_size) {
+ log_err("fio: --zonemode=none and --zonesize 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;
+ }
+
+ if (o->zone_mode == ZONE_MODE_NOT_SPECIFIED) {
+ if (o->zone_size)
+ o->zone_mode = ZONE_MODE_STRIDED;
+ else
+ o->zone_mode = ZONE_MODE_NONE;
}
/*
- * only really works with 1 file
+ * Strided zone mode only really works with 1 file.
*/
- if (o->zone_size && o->open_files > 1)
- o->zone_size = 0;
+ if (o->zone_mode == ZONE_MODE_STRIDED && o->open_files > 1)
+ o->zone_mode = ZONE_MODE_NONE;
/*
* If zone_range isn't specified, backward compatibility dictates it
* should be made equal to zone_size.
*/
- if (o->zone_size && !o->zone_range)
+ if (o->zone_mode == ZONE_MODE_STRIDED && !o->zone_range)
o->zone_range = o->zone_size;
/*
!o->norandommap) {
log_err("fio: Any use of blockalign= turns off randommap\n");
o->norandommap = 1;
- ret = warnings_fatal;
+ ret |= warnings_fatal;
}
if (!o->file_size_high)
o->file_size_high = o->file_size_low;
- if (o->start_delay_high)
- o->start_delay = get_rand_start_delay(td);
+ if (o->start_delay_high) {
+ if (!o->start_delay_orig)
+ o->start_delay_orig = o->start_delay;
+ o->start_delay = rand_between(&td->delay_state,
+ o->start_delay_orig,
+ o->start_delay_high);
+ }
if (o->norandommap && o->verify != VERIFY_NONE
&& !fixed_block_size(o)) {
log_err("fio: norandommap given for variable block sizes, "
"verify limited\n");
- ret = warnings_fatal;
+ ret |= warnings_fatal;
}
if (o->bs_unaligned && (o->odirect || td_ioengine_flagged(td, FIO_RAWIO)))
log_err("fio: bs_unaligned may not work with raw io\n");
log_err("fio: checking for in-flight overlaps when the "
"io_submit_mode is offload is not supported\n");
o->serialize_overlap = 0;
- ret = warnings_fatal;
+ ret |= warnings_fatal;
}
if (o->nr_files > td->files_index)
((o->ratemin[DDIR_READ] + o->ratemin[DDIR_WRITE] + o->ratemin[DDIR_TRIM]) &&
(o->rate_iops_min[DDIR_READ] + o->rate_iops_min[DDIR_WRITE] + o->rate_iops_min[DDIR_TRIM]))) {
log_err("fio: rate and rate_iops are mutually exclusive\n");
- ret = 1;
+ ret |= 1;
}
if ((o->rate[DDIR_READ] && (o->rate[DDIR_READ] < o->ratemin[DDIR_READ])) ||
(o->rate[DDIR_WRITE] && (o->rate[DDIR_WRITE] < o->ratemin[DDIR_WRITE])) ||
(o->rate_iops[DDIR_WRITE] && (o->rate_iops[DDIR_WRITE] < o->rate_iops_min[DDIR_WRITE])) ||
(o->rate_iops[DDIR_TRIM] && (o->rate_iops[DDIR_TRIM] < o->rate_iops_min[DDIR_TRIM]))) {
log_err("fio: minimum rate exceeds rate\n");
- ret = 1;
+ ret |= 1;
}
if (!o->timeout && o->time_based) {
log_err("fio: time_based requires a runtime/timeout setting\n");
o->time_based = 0;
- ret = warnings_fatal;
+ ret |= warnings_fatal;
}
if (o->fill_device && !o->size)
log_info("fio: multiple writers may overwrite blocks "
"that belong to other jobs. This can cause "
"verification failures.\n");
- ret = warnings_fatal;
+ ret |= warnings_fatal;
}
/*
log_info("fio: verification read phase will never "
"start because write phase uses all of "
"runtime\n");
- ret = warnings_fatal;
+ ret |= warnings_fatal;
}
if (!fio_option_is_set(o, refill_buffers))
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;
+ ret |= warnings_fatal;
}
}
- if (!o->unit_base) {
+ if (o->unit_base == N2S_NONE) {
if (td_ioengine_flagged(td, FIO_BIT_BASED))
- o->unit_base = 1;
+ o->unit_base = N2S_BITPERSEC;
else
- o->unit_base = 8;
+ o->unit_base = N2S_BYTEPERSEC;
}
#ifndef FIO_HAVE_ANY_FALLOCATE
" this warning\n");
o->fsync_blocks = o->fdatasync_blocks;
o->fdatasync_blocks = 0;
- ret = warnings_fatal;
+ ret |= warnings_fatal;
}
#endif
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");
- ret = 1;
+ ret |= 1;
}
#endif
* 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 not be less than minimum block size: %llu < %u\n",
+ log_err("fio: size too small, must not be less than minimum block size: %llu < %llu\n",
(unsigned long long) o->size, td_min_bs(td));
- ret = 1;
+ ret |= 1;
}
/*
if (td_ioengine_flagged(td, FIO_NOEXTEND) && o->file_append) {
log_err("fio: can't append/extent with IO engine %s\n", td->io_ops->name);
- ret = 1;
+ ret |= 1;
}
if (fio_option_is_set(o, gtod_cpu)) {
log_err("fio: block error histogram only available "
"with a single file per job, but %d files "
"provided\n", o->nr_files);
- ret = 1;
+ ret |= 1;
}
if (fio_option_is_set(o, clat_percentiles) &&
o->lat_percentiles && o->clat_percentiles) {
log_err("fio: lat_percentiles and clat_percentiles are "
"mutually exclusive\n");
- ret = 1;
+ ret |= 1;
}
if (o->disable_lat)
static void td_fill_rand_seeds_internal(struct thread_data *td, bool use64)
{
+ unsigned int read_seed = td->rand_seeds[FIO_RAND_BS_OFF];
+ unsigned int write_seed = td->rand_seeds[FIO_RAND_BS1_OFF];
+ unsigned int 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
* using bssplit to set buffer length distributions, ensure that
- * we seed the trim and write generators identically.
+ * we seed the trim and write generators identically. Ditto for
+ * verify, read and writes must have the same seed, if we are doing
+ * read verify.
*/
- if (td_trimwrite(td)) {
- init_rand_seed(&td->bsrange_state[DDIR_READ], td->rand_seeds[FIO_RAND_BS_OFF], use64);
- init_rand_seed(&td->bsrange_state[DDIR_WRITE], td->rand_seeds[FIO_RAND_BS1_OFF], use64);
- init_rand_seed(&td->bsrange_state[DDIR_TRIM], td->rand_seeds[FIO_RAND_BS1_OFF], use64);
- } else {
- init_rand_seed(&td->bsrange_state[DDIR_READ], td->rand_seeds[FIO_RAND_BS_OFF], use64);
- init_rand_seed(&td->bsrange_state[DDIR_WRITE], td->rand_seeds[FIO_RAND_BS1_OFF], use64);
- init_rand_seed(&td->bsrange_state[DDIR_TRIM], td->rand_seeds[FIO_RAND_BS2_OFF], use64);
- }
+ if (td->o.verify != VERIFY_NONE)
+ write_seed = read_seed;
+ if (td_trimwrite(td))
+ trim_seed = write_seed;
+ init_rand_seed(&td->bsrange_state[DDIR_READ], read_seed, use64);
+ 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->rwmix_state, td->rand_seeds[FIO_RAND_MIX_OFF], false);
fio_option_is_set(o, zero_buffers)))
td->flags |= TD_F_SCRAMBLE_BUFFERS;
if (o->verify != VERIFY_NONE)
- td->flags |= TD_F_VER_NONE;
+ td->flags |= TD_F_DO_VERIFY;
if (o->verify_async || o->io_submit_mode == IO_MODE_OFFLOAD)
td->flags |= TD_F_NEED_LOCK;
return true;
}
+/*
+ * Treat an empty log file name the same as a one not given
+ */
+static const char *make_log_name(const char *logname, const char *jobname)
+{
+ if (logname && strcmp(logname, ""))
+ return logname;
+
+ return jobname;
+}
+
/*
* Adds a job to the list of things todo. Sanitizes the various options
* to make sure we don't have conflicts, and initializes various
}
}
+ if (setup_random_seeds(td)) {
+ td_verror(td, errno, "setup_random_seeds");
+ goto err;
+ }
+
if (fixup_options(td))
goto err;
td->groupid = groupid;
prev_group_jobs++;
- if (setup_random_seeds(td)) {
- td_verror(td, errno, "setup_random_seeds");
- goto err;
- }
-
if (setup_rate(td))
goto err;
.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 *pre = make_log_name(o->lat_log_file, o->name);
const char *suf;
if (p.log_gz_store)
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->write_hist_log) {
.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 *pre = make_log_name(o->hist_log_file, o->name);
const char *suf;
#ifndef CONFIG_ZLIB
.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 *pre = make_log_name(o->bw_log_file, o->name);
const char *suf;
if (fio_option_is_set(o, bw_avg_time))
.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 *pre = make_log_name(o->iops_log_file, o->name);
const char *suf;
if (fio_option_is_set(o, iops_avg_time))
char *c1, *c2, *c3, *c4;
char *c5 = NULL, *c6 = NULL;
int i2p = is_power_of_2(o->kb_base);
+ struct buf_output out;
c1 = num2str(o->min_bs[DDIR_READ], o->sig_figs, 1, i2p, N2S_BYTE);
c2 = num2str(o->max_bs[DDIR_READ], o->sig_figs, 1, i2p, N2S_BYTE);
c6 = num2str(o->max_bs[DDIR_TRIM], o->sig_figs, 1, i2p, N2S_BYTE);
}
- log_info("%s: (g=%d): rw=%s, ", td->o.name,
+ buf_output_init(&out);
+ __log_buf(&out, "%s: (g=%d): rw=%s, ", td->o.name,
td->groupid,
ddir_str(o->td_ddir));
if (o->bs_is_seq_rand)
- log_info("bs=(R) %s-%s, (W) %s-%s, bs_is_seq_rand, ",
+ __log_buf(&out, "bs=(R) %s-%s, (W) %s-%s, bs_is_seq_rand, ",
c1, c2, c3, c4);
else
- log_info("bs=(R) %s-%s, (W) %s-%s, (T) %s-%s, ",
+ __log_buf(&out, "bs=(R) %s-%s, (W) %s-%s, (T) %s-%s, ",
c1, c2, c3, c4, c5, c6);
- log_info("ioengine=%s, iodepth=%u\n",
+ __log_buf(&out, "ioengine=%s, iodepth=%u\n",
td->io_ops->name, o->iodepth);
+ log_info_buf(out.buf, out.buflen);
+ buf_output_free(&out);
free(c1);
free(c2);
if (p[0] == '[') {
if (nested) {
log_err("No new sections in included files\n");
- return 1;
+ ret = 1;
+ goto out;
}
skip_fgets = 1;
printf(" --showcmd\t\tTurn a job file into command line options\n");
printf(" --eta=when\t\tWhen ETA estimate should be printed\n");
printf(" \t\tMay be \"always\", \"never\" or \"auto\"\n");
- printf(" --eta-newline=time\tForce a new line for every 'time'");
+ printf(" --eta-newline=t\tForce a new line for every 't'");
printf(" period passed\n");
printf(" --status-interval=t\tForce full status dump every");
printf(" 't' period passed\n");
.help = "Helper thread logging",
.shift = FD_HELPERTHREAD,
},
+ { .name = "zbd",
+ .help = "Zoned Block Device logging",
+ .shift = FD_ZBD,
+ },
{ .name = NULL, },
};