X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=options.c;h=dcee7e55a90efe4fbe38dc250296d4849537def5;hp=519982394693cb0aa41fe612d08703640b843486;hb=89978a6b26f81bdbd63228e2e2a86f604ee46c56;hpb=54d0a3150d44adca3ee4047fabd85651c6ea2db1 diff --git a/options.c b/options.c index 51998239..dcee7e55 100644 --- a/options.c +++ b/options.c @@ -20,7 +20,9 @@ char client_sockaddr_str[INET6_ADDRSTRLEN] = { 0 }; -struct pattern_fmt_desc fmt_desc[] = { +#define cb_data_to_td(data) container_of(data, struct thread_data, o) + +static struct pattern_fmt_desc fmt_desc[] = { { .fmt = "%o", .len = FIELD_SIZE(struct io_u *, offset), @@ -223,7 +225,7 @@ static int str_split_parse(struct thread_data *td, char *str, split_parse_fn *fn static int str_bssplit_cb(void *data, const char *input) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); char *str, *p; int ret = 0; @@ -258,7 +260,7 @@ static int str2error(char *str) "EINVAL", "ENFILE", "EMFILE", "ENOTTY", "ETXTBSY","EFBIG", "ENOSPC", "ESPIPE", "EROFS","EMLINK", "EPIPE", "EDOM", "ERANGE" }; - int i = 0, num = sizeof(err) / sizeof(void *); + int i = 0, num = sizeof(err) / sizeof(char *); while (i < num) { if (!strcmp(err[i], str)) @@ -324,7 +326,7 @@ static int ignore_error_type(struct thread_data *td, int etype, char *str) static int str_ignore_error_cb(void *data, const char *input) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); char *str, *p, *n; int type = 0, ret = 1; @@ -352,7 +354,7 @@ static int str_ignore_error_cb(void *data, const char *input) static int str_rw_cb(void *data, const char *str) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); struct thread_options *o = &td->o; char *nr; @@ -386,7 +388,7 @@ static int str_rw_cb(void *data, const char *str) static int str_mem_cb(void *data, const char *mem) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); if (td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAP || td->o.mem_type == MEM_MMAPSHARED) @@ -397,7 +399,7 @@ static int str_mem_cb(void *data, const char *mem) static int fio_clock_source_cb(void *data, const char *str) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); fio_clock_source = td->o.clocksource; fio_clock_source_set = 1; @@ -407,7 +409,7 @@ static int fio_clock_source_cb(void *data, const char *str) static int str_rwmix_read_cb(void *data, unsigned long long *val) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); td->o.rwmix[DDIR_READ] = *val; td->o.rwmix[DDIR_WRITE] = 100 - *val; @@ -416,7 +418,7 @@ static int str_rwmix_read_cb(void *data, unsigned long long *val) static int str_rwmix_write_cb(void *data, unsigned long long *val) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); td->o.rwmix[DDIR_WRITE] = *val; td->o.rwmix[DDIR_READ] = 100 - *val; @@ -454,7 +456,7 @@ int fio_cpus_split(os_cpu_mask_t *mask, unsigned int cpu_index) static int str_cpumask_cb(void *data, unsigned long long *val) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); unsigned int i; long max_cpu; int ret; @@ -554,7 +556,7 @@ static int set_cpus_allowed(struct thread_data *td, os_cpu_mask_t *mask, static int str_cpus_allowed_cb(void *data, const char *input) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); if (parse_dryrun()) return 0; @@ -564,7 +566,7 @@ static int str_cpus_allowed_cb(void *data, const char *input) static int str_verify_cpus_allowed_cb(void *data, const char *input) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); if (parse_dryrun()) return 0; @@ -575,7 +577,7 @@ static int str_verify_cpus_allowed_cb(void *data, const char *input) #ifdef CONFIG_ZLIB static int str_log_cpus_allowed_cb(void *data, const char *input) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); if (parse_dryrun()) return 0; @@ -589,7 +591,7 @@ static int str_log_cpus_allowed_cb(void *data, const char *input) #ifdef CONFIG_LIBNUMA static int str_numa_cpunodes_cb(void *data, char *input) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); struct bitmask *verify_bitmask; if (parse_dryrun()) @@ -614,7 +616,7 @@ static int str_numa_cpunodes_cb(void *data, char *input) static int str_numa_mpol_cb(void *data, char *input) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); const char * const policy_types[] = { "default", "prefer", "bind", "interleave", "local", NULL }; int i; @@ -723,7 +725,7 @@ out: static int str_fst_cb(void *data, const char *str) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); double val; bool done = false; char *nr; @@ -803,7 +805,7 @@ static int str_fst_cb(void *data, const char *str) #ifdef CONFIG_SYNC_FILE_RANGE static int str_sfr_cb(void *data, const char *str) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); char *nr = get_opt_postfix(str); td->sync_file_range_nr = 1; @@ -1006,7 +1008,7 @@ static int parse_zoned_distribution(struct thread_data *td, const char *input) static int str_random_distribution_cb(void *data, const char *str) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); double val; char *nr; @@ -1059,6 +1061,78 @@ static int str_random_distribution_cb(void *data, const char *str) return 0; } +static int str_steadystate_cb(void *data, const char *str) +{ + struct thread_data *td = cb_data_to_td(data); + double val; + char *nr; + char *pct; + long long ll; + + if (td->o.ss_state != FIO_SS_IOPS && td->o.ss_state != FIO_SS_IOPS_SLOPE && + td->o.ss_state != FIO_SS_BW && td->o.ss_state != FIO_SS_BW_SLOPE) { + /* should be impossible to get here */ + log_err("fio: unknown steady state criterion\n"); + return 1; + } + + nr = get_opt_postfix(str); + if (!nr) { + log_err("fio: steadystate threshold must be specified in addition to criterion\n"); + free(nr); + return 1; + } + + /* ENHANCEMENT Allow fio to understand size=10.2% and use here */ + pct = strstr(nr, "%"); + if (pct) { + *pct = '\0'; + strip_blank_end(nr); + if (!str_to_float(nr, &val, 0)) { + log_err("fio: could not parse steadystate threshold percentage\n"); + free(nr); + return 1; + } + + dprint(FD_PARSE, "set steady state threshold to %f%%\n", val); + free(nr); + if (parse_dryrun()) + return 0; + + td->o.ss_state |= __FIO_SS_PCT; + td->o.ss_limit.u.f = val; + } else if (td->o.ss_state & __FIO_SS_IOPS) { + if (!str_to_float(nr, &val, 0)) { + log_err("fio: steadystate IOPS threshold postfix parsing failed\n"); + free(nr); + return 1; + } + + dprint(FD_PARSE, "set steady state IOPS threshold to %f\n", val); + free(nr); + if (parse_dryrun()) + return 0; + + td->o.ss_limit.u.f = val; + } else { /* bandwidth criterion */ + if (str_to_decimal(nr, &ll, 1, td, 0, 0)) { + log_err("fio: steadystate BW threshold postfix parsing failed\n"); + free(nr); + return 1; + } + + dprint(FD_PARSE, "set steady state BW threshold to %lld\n", ll); + free(nr); + if (parse_dryrun()) + return 0; + + td->o.ss_limit.u.f = (double) ll; + } + + td->ss.state = td->o.ss_state; + return 0; +} + /* * Return next name in the string. Files are separated with ':'. If the ':' * is escaped with a '\', then that ':' is part of the filename and does not @@ -1151,7 +1225,7 @@ int set_name_idx(char *target, size_t tlen, char *input, int index, static int str_filename_cb(void *data, const char *input) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); char *fname, *str, *p; p = str = strdup(input); @@ -1159,6 +1233,9 @@ static int str_filename_cb(void *data, const char *input) strip_blank_front(&str); strip_blank_end(str); + /* + * Ignore what we may already have from nrfiles option. + */ if (!td->files_index) td->o.nr_files = 0; @@ -1174,7 +1251,7 @@ static int str_filename_cb(void *data, const char *input) static int str_directory_cb(void *data, const char fio_unused *unused) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); struct stat sb; char *dirname, *str, *p; int ret = 0; @@ -1205,7 +1282,7 @@ out: static int str_opendir_cb(void *data, const char fio_unused *str) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); if (parse_dryrun()) return 0; @@ -1218,7 +1295,7 @@ static int str_opendir_cb(void *data, const char fio_unused *str) static int str_buffer_pattern_cb(void *data, const char *input) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); int ret; /* FIXME: for now buffer pattern does not support formats */ @@ -1229,8 +1306,17 @@ static int str_buffer_pattern_cb(void *data, const char *input) assert(ret != 0); td->o.buffer_pattern_bytes = ret; - if (!td->o.compress_percentage) + + /* + * If this job is doing any reading or has compression set, + * ensure that we refill buffers for writes or we could be + * invalidating the pattern through reads. + */ + if (!td->o.compress_percentage && !td_read(td)) td->o.refill_buffers = 0; + else + td->o.refill_buffers = 1; + td->o.scramble_buffers = 0; td->o.zero_buffers = 0; @@ -1239,7 +1325,7 @@ static int str_buffer_pattern_cb(void *data, const char *input) static int str_buffer_compress_cb(void *data, unsigned long long *il) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); td->flags |= TD_F_COMPRESS; td->o.compress_percentage = *il; @@ -1248,7 +1334,7 @@ static int str_buffer_compress_cb(void *data, unsigned long long *il) static int str_dedupe_cb(void *data, unsigned long long *il) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); td->flags |= TD_F_COMPRESS; td->o.dedupe_percentage = *il; @@ -1258,7 +1344,7 @@ static int str_dedupe_cb(void *data, unsigned long long *il) static int str_verify_pattern_cb(void *data, const char *input) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); int ret; td->o.verify_fmt_sz = ARRAY_SIZE(td->o.verify_fmt); @@ -1281,7 +1367,7 @@ static int str_verify_pattern_cb(void *data, const char *input) static int str_gtod_reduce_cb(void *data, int *il) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); int val = *il; td->o.disable_lat = !!val; @@ -1295,9 +1381,24 @@ static int str_gtod_reduce_cb(void *data, int *il) return 0; } +static int str_offset_cb(void *data, unsigned long long *__val) +{ + struct thread_data *td = cb_data_to_td(data); + unsigned long long v = *__val; + + if (parse_is_percent(v)) { + td->o.start_offset = 0; + td->o.start_offset_percent = -1ULL - v; + dprint(FD_PARSE, "SET start_offset_percent %d\n", td->o.start_offset_percent); + } else + td->o.start_offset = v; + + return 0; +} + static int str_size_cb(void *data, unsigned long long *__val) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); unsigned long long v = *__val; if (parse_is_percent(v)) { @@ -1309,9 +1410,53 @@ static int str_size_cb(void *data, unsigned long long *__val) return 0; } +static int str_write_bw_log_cb(void *data, const char *str) +{ + struct thread_data *td = cb_data_to_td(data); + + if (str) + td->o.bw_log_file = strdup(str); + + td->o.write_bw_log = 1; + return 0; +} + +static int str_write_lat_log_cb(void *data, const char *str) +{ + struct thread_data *td = cb_data_to_td(data); + + if (str) + td->o.lat_log_file = strdup(str); + + td->o.write_lat_log = 1; + return 0; +} + +static int str_write_iops_log_cb(void *data, const char *str) +{ + struct thread_data *td = cb_data_to_td(data); + + if (str) + td->o.iops_log_file = strdup(str); + + td->o.write_iops_log = 1; + return 0; +} + +static int str_write_hist_log_cb(void *data, const char *str) +{ + struct thread_data *td = cb_data_to_td(data); + + if (str) + td->o.hist_log_file = strdup(str); + + td->o.write_hist_log = 1; + return 0; +} + static int rw_verify(struct fio_option *o, void *data) { - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); if (read_only && td_write(td)) { log_err("fio: job <%s> has write bit set, but fio is in" @@ -1325,7 +1470,7 @@ static int rw_verify(struct fio_option *o, void *data) static int gtod_cpu_verify(struct fio_option *o, void *data) { #ifndef FIO_HAVE_CPU_AFFINITY - struct thread_data *td = data; + struct thread_data *td = cb_data_to_td(data); if (td->o.gtod_cpu) { log_err("fio: platform must support CPU affinity for" @@ -1345,7 +1490,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "description", .lname = "Description of job", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(description), + .off1 = offsetof(struct thread_options, description), .help = "Text job description", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_DESC, @@ -1354,7 +1499,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "name", .lname = "Job name", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(name), + .off1 = offsetof(struct thread_options, name), .help = "Name of this job", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_DESC, @@ -1363,7 +1508,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "wait_for", .lname = "Waitee name", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(wait_for), + .off1 = offsetof(struct thread_options, wait_for), .help = "Name of the job this one wants to wait for before starting", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_DESC, @@ -1372,7 +1517,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "filename", .lname = "Filename(s)", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(filename), + .off1 = offsetof(struct thread_options, filename), .cb = str_filename_cb, .prio = -1, /* must come after "directory" */ .help = "File(s) to use for the workload", @@ -1383,7 +1528,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "directory", .lname = "Directory", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(directory), + .off1 = offsetof(struct thread_options, directory), .cb = str_directory_cb, .help = "Directory to store files in", .category = FIO_OPT_C_FILE, @@ -1393,7 +1538,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "filename_format", .lname = "Filename Format", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(filename_format), + .off1 = offsetof(struct thread_options, filename_format), .prio = -1, /* must come after "directory" */ .help = "Override default $jobname.$jobnum.$filenum naming", .def = "$jobname.$jobnum.$filenum", @@ -1404,7 +1549,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "unique_filename", .lname = "Unique Filename", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(unique_filename), + .off1 = offsetof(struct thread_options, unique_filename), .help = "For network clients, prefix file with source IP", .def = "1", .category = FIO_OPT_C_FILE, @@ -1414,7 +1559,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "lockfile", .lname = "Lockfile", .type = FIO_OPT_STR, - .off1 = td_var_offset(file_lock_mode), + .off1 = offsetof(struct thread_options, file_lock_mode), .help = "Lock file when doing IO to it", .prio = 1, .parent = "filename", @@ -1442,7 +1587,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "opendir", .lname = "Open directory", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(opendir), + .off1 = offsetof(struct thread_options, opendir), .cb = str_opendir_cb, .help = "Recursively add files from this directory and down", .category = FIO_OPT_C_FILE, @@ -1454,7 +1599,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .alias = "readwrite", .type = FIO_OPT_STR, .cb = str_rw_cb, - .off1 = td_var_offset(td_ddir), + .off1 = offsetof(struct thread_options, td_ddir), .help = "IO direction", .def = "read", .verify = rw_verify, @@ -1507,7 +1652,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "rw_sequencer", .lname = "RW Sequencer", .type = FIO_OPT_STR, - .off1 = td_var_offset(rw_seq), + .off1 = offsetof(struct thread_options, rw_seq), .help = "IO offset generator modifier", .def = "sequential", .category = FIO_OPT_C_IO, @@ -1528,7 +1673,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "ioengine", .lname = "IO Engine", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(ioengine), + .off1 = offsetof(struct thread_options, ioengine), .help = "IO engine to use", .def = FIO_PREFERRED_ENGINE, .category = FIO_OPT_C_IO, @@ -1651,6 +1796,11 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "NVML libpmemblk based IO engine", }, +#endif +#ifdef CONFIG_LINUX_DEVDAX + { .ival = "dev-dax", + .help = "DAX Device based IO engine", + }, #endif { .ival = "external", .help = "Load external engine (append name)", @@ -1661,7 +1811,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "iodepth", .lname = "IO Depth", .type = FIO_OPT_INT, - .off1 = td_var_offset(iodepth), + .off1 = offsetof(struct thread_options, iodepth), .help = "Number of IO buffers to keep in flight", .minval = 1, .interval = 1, @@ -1674,7 +1824,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "IO Depth batch", .alias = "iodepth_batch_submit", .type = FIO_OPT_INT, - .off1 = td_var_offset(iodepth_batch), + .off1 = offsetof(struct thread_options, iodepth_batch), .help = "Number of IO buffers to submit in one go", .parent = "iodepth", .hide = 1, @@ -1688,7 +1838,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Min IO depth batch complete", .alias = "iodepth_batch_complete", .type = FIO_OPT_INT, - .off1 = td_var_offset(iodepth_batch_complete_min), + .off1 = offsetof(struct thread_options, iodepth_batch_complete_min), .help = "Min number of IO buffers to retrieve in one go", .parent = "iodepth", .hide = 1, @@ -1702,7 +1852,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "iodepth_batch_complete_max", .lname = "Max IO depth batch complete", .type = FIO_OPT_INT, - .off1 = td_var_offset(iodepth_batch_complete_max), + .off1 = offsetof(struct thread_options, iodepth_batch_complete_max), .help = "Max number of IO buffers to retrieve in one go", .parent = "iodepth", .hide = 1, @@ -1715,7 +1865,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "iodepth_low", .lname = "IO Depth batch low", .type = FIO_OPT_INT, - .off1 = td_var_offset(iodepth_low), + .off1 = offsetof(struct thread_options, iodepth_low), .help = "Low water mark for queuing depth", .parent = "iodepth", .hide = 1, @@ -1727,7 +1877,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "io_submit_mode", .lname = "IO submit mode", .type = FIO_OPT_STR, - .off1 = td_var_offset(io_submit_mode), + .off1 = offsetof(struct thread_options, io_submit_mode), .help = "How IO submissions and completions are done", .def = "inline", .category = FIO_OPT_C_IO, @@ -1748,7 +1898,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Size", .type = FIO_OPT_STR_VAL, .cb = str_size_cb, - .off1 = td_var_offset(size), + .off1 = offsetof(struct thread_options, size), .help = "Total size of device or files", .interval = 1024 * 1024, .category = FIO_OPT_C_IO, @@ -1759,7 +1909,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .alias = "io_limit", .lname = "IO Size", .type = FIO_OPT_STR_VAL, - .off1 = td_var_offset(io_limit), + .off1 = offsetof(struct thread_options, io_size), + .help = "Total size of I/O to be performed", .interval = 1024 * 1024, .category = FIO_OPT_C_IO, .group = FIO_OPT_G_INVALID, @@ -1769,7 +1920,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Fill device", .alias = "fill_fs", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(fill_device), + .off1 = offsetof(struct thread_options, fill_device), .help = "Write until an ENOSPC error occurs", .def = "0", .category = FIO_OPT_C_FILE, @@ -1779,8 +1930,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "filesize", .lname = "File size", .type = FIO_OPT_STR_VAL, - .off1 = td_var_offset(file_size_low), - .off2 = td_var_offset(file_size_high), + .off1 = offsetof(struct thread_options, file_size_low), + .off2 = offsetof(struct thread_options, file_size_high), .minval = 1, .help = "Size of individual files", .interval = 1024 * 1024, @@ -1791,7 +1942,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "file_append", .lname = "File append", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(file_append), + .off1 = offsetof(struct thread_options, file_append), .help = "IO will start at the end of the file(s)", .def = "0", .category = FIO_OPT_C_FILE, @@ -1802,7 +1953,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "IO offset", .alias = "fileoffset", .type = FIO_OPT_STR_VAL, - .off1 = td_var_offset(start_offset), + .cb = str_offset_cb, + .off1 = offsetof(struct thread_options, start_offset), .help = "Start IO from this offset", .def = "0", .interval = 1024 * 1024, @@ -1813,7 +1965,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "offset_increment", .lname = "IO offset increment", .type = FIO_OPT_STR_VAL, - .off1 = td_var_offset(offset_increment), + .off1 = offsetof(struct thread_options, offset_increment), .help = "What is the increment from one offset to the next", .parent = "offset", .hide = 1, @@ -1826,7 +1978,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "number_ios", .lname = "Number of IOs to perform", .type = FIO_OPT_STR_VAL, - .off1 = td_var_offset(number_ios), + .off1 = offsetof(struct thread_options, number_ios), .help = "Force job completion after this number of IOs", .def = "0", .category = FIO_OPT_C_IO, @@ -1837,12 +1989,12 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Block size", .alias = "blocksize", .type = FIO_OPT_INT, - .off1 = td_var_offset(bs[DDIR_READ]), - .off2 = td_var_offset(bs[DDIR_WRITE]), - .off3 = td_var_offset(bs[DDIR_TRIM]), + .off1 = offsetof(struct thread_options, bs[DDIR_READ]), + .off2 = offsetof(struct thread_options, bs[DDIR_WRITE]), + .off3 = offsetof(struct thread_options, bs[DDIR_TRIM]), .minval = 1, .help = "Block size unit", - .def = "4k", + .def = "4096", .parent = "rw", .hide = 1, .interval = 512, @@ -1854,9 +2006,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Block size align", .alias = "blockalign", .type = FIO_OPT_INT, - .off1 = td_var_offset(ba[DDIR_READ]), - .off2 = td_var_offset(ba[DDIR_WRITE]), - .off3 = td_var_offset(ba[DDIR_TRIM]), + .off1 = offsetof(struct thread_options, ba[DDIR_READ]), + .off2 = offsetof(struct thread_options, ba[DDIR_WRITE]), + .off3 = offsetof(struct thread_options, ba[DDIR_TRIM]), .minval = 1, .help = "IO block offset alignment", .parent = "rw", @@ -1870,12 +2022,12 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Block size range", .alias = "blocksize_range", .type = FIO_OPT_RANGE, - .off1 = td_var_offset(min_bs[DDIR_READ]), - .off2 = td_var_offset(max_bs[DDIR_READ]), - .off3 = td_var_offset(min_bs[DDIR_WRITE]), - .off4 = td_var_offset(max_bs[DDIR_WRITE]), - .off5 = td_var_offset(min_bs[DDIR_TRIM]), - .off6 = td_var_offset(max_bs[DDIR_TRIM]), + .off1 = offsetof(struct thread_options, min_bs[DDIR_READ]), + .off2 = offsetof(struct thread_options, max_bs[DDIR_READ]), + .off3 = offsetof(struct thread_options, min_bs[DDIR_WRITE]), + .off4 = offsetof(struct thread_options, max_bs[DDIR_WRITE]), + .off5 = offsetof(struct thread_options, min_bs[DDIR_TRIM]), + .off6 = offsetof(struct thread_options, max_bs[DDIR_TRIM]), .minval = 1, .help = "Set block size range (in more detail than bs)", .parent = "rw", @@ -1889,7 +2041,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Block size split", .type = FIO_OPT_STR, .cb = str_bssplit_cb, - .off1 = td_var_offset(bssplit), + .off1 = offsetof(struct thread_options, bssplit), .help = "Set a specific mix of block sizes", .parent = "rw", .hide = 1, @@ -1901,7 +2053,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Block size unaligned", .alias = "blocksize_unaligned", .type = FIO_OPT_STR_SET, - .off1 = td_var_offset(bs_unaligned), + .off1 = offsetof(struct thread_options, bs_unaligned), .help = "Don't sector align IO buffer sizes", .parent = "rw", .hide = 1, @@ -1912,7 +2064,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "bs_is_seq_rand", .lname = "Block size division is seq/random (not read/write)", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(bs_is_seq_rand), + .off1 = offsetof(struct thread_options, bs_is_seq_rand), .help = "Consider any blocksize setting to be sequential,random", .def = "0", .parent = "blocksize", @@ -1923,7 +2075,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "randrepeat", .lname = "Random repeatable", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(rand_repeatable), + .off1 = offsetof(struct thread_options, rand_repeatable), .help = "Use repeatable random IO pattern", .def = "1", .parent = "rw", @@ -1935,7 +2087,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "randseed", .lname = "The random generator seed", .type = FIO_OPT_STR_VAL, - .off1 = td_var_offset(rand_seed), + .off1 = offsetof(struct thread_options, rand_seed), .help = "Set the random generator seed value", .def = "0x89", .parent = "rw", @@ -1946,7 +2098,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "use_os_rand", .lname = "Use OS random", .type = FIO_OPT_DEPRECATED, - .off1 = td_var_offset(dep_use_os_rand), + .off1 = offsetof(struct thread_options, dep_use_os_rand), .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RANDOM, }, @@ -1954,7 +2106,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "norandommap", .lname = "No randommap", .type = FIO_OPT_STR_SET, - .off1 = td_var_offset(norandommap), + .off1 = offsetof(struct thread_options, norandommap), .help = "Accept potential duplicate random blocks", .parent = "rw", .hide = 1, @@ -1966,7 +2118,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "softrandommap", .lname = "Soft randommap", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(softrandommap), + .off1 = offsetof(struct thread_options, softrandommap), .help = "Set norandommap if randommap allocation fails", .parent = "norandommap", .hide = 1, @@ -1978,7 +2130,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "random_generator", .lname = "Random Generator", .type = FIO_OPT_STR, - .off1 = td_var_offset(random_generator), + .off1 = offsetof(struct thread_options, random_generator), .help = "Type of random number generator to use", .def = "tausworthe", .posval = { @@ -2003,7 +2155,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "random_distribution", .lname = "Random Distribution", .type = FIO_OPT_STR, - .off1 = td_var_offset(random_distribution), + .off1 = offsetof(struct thread_options, random_distribution), .cb = str_random_distribution_cb, .help = "Random offset distribution generator", .def = "random", @@ -2037,9 +2189,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "percentage_random", .lname = "Percentage Random", .type = FIO_OPT_INT, - .off1 = td_var_offset(perc_rand[DDIR_READ]), - .off2 = td_var_offset(perc_rand[DDIR_WRITE]), - .off3 = td_var_offset(perc_rand[DDIR_TRIM]), + .off1 = offsetof(struct thread_options, perc_rand[DDIR_READ]), + .off2 = offsetof(struct thread_options, perc_rand[DDIR_WRITE]), + .off3 = offsetof(struct thread_options, perc_rand[DDIR_TRIM]), .maxval = 100, .help = "Percentage of seq/random mix that should be random", .def = "100,100,100", @@ -2059,7 +2211,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "allrandrepeat", .lname = "All Random Repeat", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(allrand_repeatable), + .off1 = offsetof(struct thread_options, allrand_repeatable), .help = "Use repeatable random numbers for everything", .def = "0", .category = FIO_OPT_C_IO, @@ -2070,7 +2222,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Number of files", .alias = "nr_files", .type = FIO_OPT_INT, - .off1 = td_var_offset(nr_files), + .off1 = offsetof(struct thread_options, nr_files), .help = "Split job workload between this number of files", .def = "1", .interval = 1, @@ -2081,7 +2233,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "openfiles", .lname = "Number of open files", .type = FIO_OPT_INT, - .off1 = td_var_offset(open_files), + .off1 = offsetof(struct thread_options, open_files), .help = "Number of files to keep open at the same time", .category = FIO_OPT_C_FILE, .group = FIO_OPT_G_INVALID, @@ -2091,7 +2243,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "File service type", .type = FIO_OPT_STR, .cb = str_fst_cb, - .off1 = td_var_offset(file_service_type), + .off1 = offsetof(struct thread_options, file_service_type), .help = "How to select which file to service next", .def = "roundrobin", .category = FIO_OPT_C_FILE, @@ -2111,7 +2263,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { }, { .ival = "gauss", .oval = FIO_FSERVICE_GAUSS, - .help = "Normal (guassian) distribution", + .help = "Normal (Gaussian) distribution", }, { .ival = "roundrobin", .oval = FIO_FSERVICE_RR, @@ -2130,7 +2282,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "fallocate", .lname = "Fallocate", .type = FIO_OPT_STR, - .off1 = td_var_offset(fallocate_mode), + .off1 = offsetof(struct thread_options, fallocate_mode), .help = "Whether pre-allocation is performed when laying out files", .def = "posix", .category = FIO_OPT_C_FILE, @@ -2172,8 +2324,26 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "fadvise_hint", .lname = "Fadvise hint", - .type = FIO_OPT_BOOL, - .off1 = td_var_offset(fadvise_hint), + .type = FIO_OPT_STR, + .off1 = offsetof(struct thread_options, fadvise_hint), + .posval = { + { .ival = "0", + .oval = F_ADV_NONE, + .help = "Don't issue fadvise", + }, + { .ival = "1", + .oval = F_ADV_TYPE, + .help = "Advise using fio IO pattern", + }, + { .ival = "random", + .oval = F_ADV_RANDOM, + .help = "Advise using FADV_RANDOM", + }, + { .ival = "sequential", + .oval = F_ADV_SEQUENTIAL, + .help = "Advise using FADV_SEQUENTIAL", + }, + }, .help = "Use fadvise() to advise the kernel on IO pattern", .def = "1", .category = FIO_OPT_C_FILE, @@ -2184,7 +2354,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "fadvise_stream", .lname = "Fadvise stream", .type = FIO_OPT_INT, - .off1 = td_var_offset(fadvise_stream), + .off1 = offsetof(struct thread_options, fadvise_stream), .help = "Use fadvise() to set stream ID", .category = FIO_OPT_C_FILE, .group = FIO_OPT_G_INVALID, @@ -2201,7 +2371,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "fsync", .lname = "Fsync", .type = FIO_OPT_INT, - .off1 = td_var_offset(fsync_blocks), + .off1 = offsetof(struct thread_options, fsync_blocks), .help = "Issue fsync for writes every given number of blocks", .def = "0", .interval = 1, @@ -2212,7 +2382,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "fdatasync", .lname = "Fdatasync", .type = FIO_OPT_INT, - .off1 = td_var_offset(fdatasync_blocks), + .off1 = offsetof(struct thread_options, fdatasync_blocks), .help = "Issue fdatasync for writes every given number of blocks", .def = "0", .interval = 1, @@ -2223,7 +2393,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "write_barrier", .lname = "Write barrier", .type = FIO_OPT_INT, - .off1 = td_var_offset(barrier_blocks), + .off1 = offsetof(struct thread_options, barrier_blocks), .help = "Make every Nth write a barrier write", .def = "0", .interval = 1, @@ -2254,7 +2424,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { }, .type = FIO_OPT_STR_MULTI, .cb = str_sfr_cb, - .off1 = td_var_offset(sync_file_range), + .off1 = offsetof(struct thread_options, sync_file_range), .help = "Use sync_file_range()", .category = FIO_OPT_C_FILE, .group = FIO_OPT_G_INVALID, @@ -2271,7 +2441,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "direct", .lname = "Direct I/O", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(odirect), + .off1 = offsetof(struct thread_options, odirect), .help = "Use O_DIRECT IO (negates buffered)", .def = "0", .inverse = "buffered", @@ -2282,7 +2452,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "atomic", .lname = "Atomic I/O", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(oatomic), + .off1 = offsetof(struct thread_options, oatomic), .help = "Use Atomic IO with O_DIRECT (implies O_DIRECT)", .def = "0", .category = FIO_OPT_C_IO, @@ -2292,7 +2462,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "buffered", .lname = "Buffered I/O", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(odirect), + .off1 = offsetof(struct thread_options, odirect), .neg = 1, .help = "Use buffered IO (negates direct)", .def = "1", @@ -2304,7 +2474,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "overwrite", .lname = "Overwrite", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(overwrite), + .off1 = offsetof(struct thread_options, overwrite), .help = "When writing, set whether to overwrite current data", .def = "0", .category = FIO_OPT_C_FILE, @@ -2314,7 +2484,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "loops", .lname = "Loops", .type = FIO_OPT_INT, - .off1 = td_var_offset(loops), + .off1 = offsetof(struct thread_options, loops), .help = "Number of times to run the job", .def = "1", .interval = 1, @@ -2325,7 +2495,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "numjobs", .lname = "Number of jobs", .type = FIO_OPT_INT, - .off1 = td_var_offset(numjobs), + .off1 = offsetof(struct thread_options, numjobs), .help = "Duplicate this job this many times", .def = "1", .interval = 1, @@ -2336,8 +2506,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "startdelay", .lname = "Start delay", .type = FIO_OPT_STR_VAL_TIME, - .off1 = td_var_offset(start_delay), - .off2 = td_var_offset(start_delay_high), + .off1 = offsetof(struct thread_options, start_delay), + .off2 = offsetof(struct thread_options, start_delay_high), .help = "Only start job when this period has passed", .def = "0", .is_seconds = 1, @@ -2350,7 +2520,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Runtime", .alias = "timeout", .type = FIO_OPT_STR_VAL_TIME, - .off1 = td_var_offset(timeout), + .off1 = offsetof(struct thread_options, timeout), .help = "Stop workload when this amount of time has passed", .def = "0", .is_seconds = 1, @@ -2362,7 +2532,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "time_based", .lname = "Time based", .type = FIO_OPT_STR_SET, - .off1 = td_var_offset(time_based), + .off1 = offsetof(struct thread_options, time_based), .help = "Keep running until runtime/timeout is met", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_RUNTIME, @@ -2371,7 +2541,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "verify_only", .lname = "Verify only", .type = FIO_OPT_STR_SET, - .off1 = td_var_offset(verify_only), + .off1 = offsetof(struct thread_options, verify_only), .help = "Verifies previously written data is still valid", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_RUNTIME, @@ -2380,7 +2550,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "ramp_time", .lname = "Ramp time", .type = FIO_OPT_STR_VAL_TIME, - .off1 = td_var_offset(ramp_time), + .off1 = offsetof(struct thread_options, ramp_time), .help = "Ramp up time before measuring performance", .is_seconds = 1, .is_time = 1, @@ -2392,7 +2562,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Clock source", .type = FIO_OPT_STR, .cb = fio_clock_source_cb, - .off1 = td_var_offset(clocksource), + .off1 = offsetof(struct thread_options, clocksource), .help = "What type of timing source to use", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_CLOCK, @@ -2423,7 +2593,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "I/O Memory", .type = FIO_OPT_STR, .cb = str_mem_cb, - .off1 = td_var_offset(mem_type), + .off1 = offsetof(struct thread_options, mem_type), .help = "Backing type for IO buffers", .def = "malloc", .category = FIO_OPT_C_IO, @@ -2458,6 +2628,12 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .oval = MEM_MMAPHUGE, .help = "Like mmap, but use huge pages", }, +#endif +#ifdef CONFIG_CUDA + { .ival = "cudamalloc", + .oval = MEM_CUDA_MALLOC, + .help = "Allocate GPU device memory for GPUDirect RDMA", + }, #endif }, }, @@ -2466,7 +2642,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .alias = "mem_align", .lname = "I/O memory alignment", .type = FIO_OPT_INT, - .off1 = td_var_offset(mem_align), + .off1 = offsetof(struct thread_options, mem_align), .minval = 0, .help = "IO memory buffer offset alignment", .def = "0", @@ -2479,7 +2655,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "verify", .lname = "Verify", .type = FIO_OPT_STR, - .off1 = td_var_offset(verify), + .off1 = offsetof(struct thread_options, verify), .help = "Verify data written", .def = "0", .category = FIO_OPT_C_IO, @@ -2529,6 +2705,22 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .oval = VERIFY_SHA512, .help = "Use sha512 checksums for verification", }, + { .ival = "sha3-224", + .oval = VERIFY_SHA3_224, + .help = "Use sha3-224 checksums for verification", + }, + { .ival = "sha3-256", + .oval = VERIFY_SHA3_256, + .help = "Use sha3-256 checksums for verification", + }, + { .ival = "sha3-384", + .oval = VERIFY_SHA3_384, + .help = "Use sha3-384 checksums for verification", + }, + { .ival = "sha3-512", + .oval = VERIFY_SHA3_512, + .help = "Use sha3-512 checksums for verification", + }, { .ival = "xxhash", .oval = VERIFY_XXHASH, .help = "Use xxhash checksums for verification", @@ -2556,7 +2748,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "do_verify", .lname = "Perform verify step", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(do_verify), + .off1 = offsetof(struct thread_options, do_verify), .help = "Run verification stage after write", .def = "1", .parent = "verify", @@ -2568,7 +2760,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "verifysort", .lname = "Verify sort", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(verifysort), + .off1 = offsetof(struct thread_options, verifysort), .help = "Sort written verify blocks for read back", .def = "1", .parent = "verify", @@ -2580,7 +2772,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "verifysort_nr", .lname = "Verify Sort Nr", .type = FIO_OPT_INT, - .off1 = td_var_offset(verifysort_nr), + .off1 = offsetof(struct thread_options, verifysort_nr), .help = "Pre-load and sort verify blocks for a read workload", .minval = 0, .maxval = 131072, @@ -2593,7 +2785,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "verify_interval", .lname = "Verify interval", .type = FIO_OPT_INT, - .off1 = td_var_offset(verify_interval), + .off1 = offsetof(struct thread_options, verify_interval), .minval = 2 * sizeof(struct verify_header), .help = "Store verify buffer header every N bytes", .parent = "verify", @@ -2607,7 +2799,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Verify offset", .type = FIO_OPT_INT, .help = "Offset verify header location by N bytes", - .off1 = td_var_offset(verify_offset), + .off1 = offsetof(struct thread_options, verify_offset), .minval = sizeof(struct verify_header), .parent = "verify", .hide = 1, @@ -2619,7 +2811,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Verify pattern", .type = FIO_OPT_STR, .cb = str_verify_pattern_cb, - .off1 = td_var_offset(verify_pattern), + .off1 = offsetof(struct thread_options, verify_pattern), .help = "Fill pattern for IO buffers", .parent = "verify", .hide = 1, @@ -2630,7 +2822,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "verify_fatal", .lname = "Verify fatal", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(verify_fatal), + .off1 = offsetof(struct thread_options, verify_fatal), .def = "0", .help = "Exit on a single verify failure, don't continue", .parent = "verify", @@ -2642,7 +2834,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "verify_dump", .lname = "Verify dump", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(verify_dump), + .off1 = offsetof(struct thread_options, verify_dump), .def = "0", .help = "Dump contents of good and bad blocks on failure", .parent = "verify", @@ -2654,7 +2846,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "verify_async", .lname = "Verify asynchronously", .type = FIO_OPT_INT, - .off1 = td_var_offset(verify_async), + .off1 = offsetof(struct thread_options, verify_async), .def = "0", .help = "Number of async verifier threads to use", .parent = "verify", @@ -2666,7 +2858,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "verify_backlog", .lname = "Verify backlog", .type = FIO_OPT_STR_VAL, - .off1 = td_var_offset(verify_backlog), + .off1 = offsetof(struct thread_options, verify_backlog), .help = "Verify after this number of blocks are written", .parent = "verify", .hide = 1, @@ -2677,7 +2869,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "verify_backlog_batch", .lname = "Verify backlog batch", .type = FIO_OPT_INT, - .off1 = td_var_offset(verify_batch), + .off1 = offsetof(struct thread_options, verify_batch), .help = "Verify this number of IO blocks", .parent = "verify", .hide = 1, @@ -2690,7 +2882,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Async verify CPUs", .type = FIO_OPT_STR, .cb = str_verify_cpus_allowed_cb, - .off1 = td_var_offset(verify_cpumask), + .off1 = offsetof(struct thread_options, verify_cpumask), .help = "Set CPUs allowed for async verify threads", .parent = "verify_async", .hide = 1, @@ -2708,7 +2900,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "experimental_verify", .lname = "Experimental Verify", - .off1 = td_var_offset(experimental_verify), + .off1 = offsetof(struct thread_options, experimental_verify), .type = FIO_OPT_BOOL, .help = "Enable experimental verification", .parent = "verify", @@ -2718,7 +2910,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "verify_state_load", .lname = "Load verify state", - .off1 = td_var_offset(verify_state), + .off1 = offsetof(struct thread_options, verify_state), .type = FIO_OPT_BOOL, .help = "Load verify termination state", .parent = "verify", @@ -2728,7 +2920,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "verify_state_save", .lname = "Save verify state", - .off1 = td_var_offset(verify_state_save), + .off1 = offsetof(struct thread_options, verify_state_save), .type = FIO_OPT_BOOL, .def = "1", .help = "Save verify state on termination", @@ -2741,10 +2933,10 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "trim_percentage", .lname = "Trim percentage", .type = FIO_OPT_INT, - .off1 = td_var_offset(trim_percentage), + .off1 = offsetof(struct thread_options, trim_percentage), .minval = 0, .maxval = 100, - .help = "Number of verify blocks to discard/trim", + .help = "Number of verify blocks to trim (i.e., discard)", .parent = "verify", .def = "0", .interval = 1, @@ -2756,8 +2948,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "trim_verify_zero", .lname = "Verify trim zero", .type = FIO_OPT_BOOL, - .help = "Verify that trim/discarded blocks are returned as zeroes", - .off1 = td_var_offset(trim_zero), + .help = "Verify that trimmed (i.e., discarded) blocks are returned as zeroes", + .off1 = offsetof(struct thread_options, trim_zero), .parent = "trim_percentage", .hide = 1, .def = "1", @@ -2768,7 +2960,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "trim_backlog", .lname = "Trim backlog", .type = FIO_OPT_STR_VAL, - .off1 = td_var_offset(trim_backlog), + .off1 = offsetof(struct thread_options, trim_backlog), .help = "Trim after this number of blocks are written", .parent = "trim_percentage", .hide = 1, @@ -2780,7 +2972,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "trim_backlog_batch", .lname = "Trim backlog batch", .type = FIO_OPT_INT, - .off1 = td_var_offset(trim_batch), + .off1 = offsetof(struct thread_options, trim_batch), .help = "Trim this number of IO blocks", .parent = "trim_percentage", .hide = 1, @@ -2818,7 +3010,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "write_iolog", .lname = "Write I/O log", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(write_iolog_file), + .off1 = offsetof(struct thread_options, write_iolog_file), .help = "Store IO pattern to file", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_IOLOG, @@ -2827,7 +3019,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "read_iolog", .lname = "Read I/O log", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(read_iolog_file), + .off1 = offsetof(struct thread_options, read_iolog_file), .help = "Playback IO pattern from file", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_IOLOG, @@ -2836,7 +3028,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "replay_no_stall", .lname = "Don't stall on replay", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(no_stall), + .off1 = offsetof(struct thread_options, no_stall), .def = "0", .parent = "read_iolog", .hide = 1, @@ -2848,7 +3040,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "replay_redirect", .lname = "Redirect device for replay", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(replay_redirect), + .off1 = offsetof(struct thread_options, replay_redirect), .parent = "read_iolog", .hide = 1, .help = "Replay all I/O onto this device, regardless of trace device", @@ -2859,7 +3051,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "replay_scale", .lname = "Replace offset scale factor", .type = FIO_OPT_INT, - .off1 = td_var_offset(replay_scale), + .off1 = offsetof(struct thread_options, replay_scale), .parent = "read_iolog", .def = "1", .help = "Align offsets to this blocksize", @@ -2870,7 +3062,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "replay_align", .lname = "Replace alignment", .type = FIO_OPT_INT, - .off1 = td_var_offset(replay_align), + .off1 = offsetof(struct thread_options, replay_align), .parent = "read_iolog", .help = "Scale offset down by this factor", .category = FIO_OPT_C_IO, @@ -2881,7 +3073,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "exec_prerun", .lname = "Pre-execute runnable", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(exec_prerun), + .off1 = offsetof(struct thread_options, exec_prerun), .help = "Execute this file prior to running job", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_INVALID, @@ -2890,7 +3082,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "exec_postrun", .lname = "Post-execute runnable", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(exec_postrun), + .off1 = offsetof(struct thread_options, exec_postrun), .help = "Execute this file after running job", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_INVALID, @@ -2900,7 +3092,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "ioscheduler", .lname = "I/O scheduler", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(ioscheduler), + .off1 = offsetof(struct thread_options, ioscheduler), .help = "Use this IO scheduler on the backing device", .category = FIO_OPT_C_FILE, .group = FIO_OPT_G_INVALID, @@ -2917,7 +3109,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "zonesize", .lname = "Zone size", .type = FIO_OPT_STR_VAL, - .off1 = td_var_offset(zone_size), + .off1 = offsetof(struct thread_options, zone_size), .help = "Amount of data to read per zone", .def = "0", .interval = 1024 * 1024, @@ -2928,7 +3120,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "zonerange", .lname = "Zone range", .type = FIO_OPT_STR_VAL, - .off1 = td_var_offset(zone_range), + .off1 = offsetof(struct thread_options, zone_range), .help = "Give size of an IO zone", .def = "0", .interval = 1024 * 1024, @@ -2939,7 +3131,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "zoneskip", .lname = "Zone skip", .type = FIO_OPT_STR_VAL, - .off1 = td_var_offset(zone_skip), + .off1 = offsetof(struct thread_options, zone_skip), .help = "Space between IO zones", .def = "0", .interval = 1024 * 1024, @@ -2950,7 +3142,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "lockmem", .lname = "Lock memory", .type = FIO_OPT_STR_VAL, - .off1 = td_var_offset(lockmem), + .off1 = offsetof(struct thread_options, lockmem), .help = "Lock down this amount of memory (per worker)", .def = "0", .interval = 1024 * 1024, @@ -2962,7 +3154,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Read/write mix read", .type = FIO_OPT_INT, .cb = str_rwmix_read_cb, - .off1 = td_var_offset(rwmix[DDIR_READ]), + .off1 = offsetof(struct thread_options, rwmix[DDIR_READ]), .maxval = 100, .help = "Percentage of mixed workload that is reads", .def = "50", @@ -2976,7 +3168,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Read/write mix write", .type = FIO_OPT_INT, .cb = str_rwmix_write_cb, - .off1 = td_var_offset(rwmix[DDIR_WRITE]), + .off1 = offsetof(struct thread_options, rwmix[DDIR_WRITE]), .maxval = 100, .help = "Percentage of mixed workload that is writes", .def = "50", @@ -2996,7 +3188,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "nice", .lname = "Nice", .type = FIO_OPT_INT, - .off1 = td_var_offset(nice), + .off1 = offsetof(struct thread_options, nice), .help = "Set job CPU nice value", .minval = -19, .maxval = 20, @@ -3010,45 +3202,51 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "prio", .lname = "I/O nice priority", .type = FIO_OPT_INT, - .off1 = td_var_offset(ioprio), + .off1 = offsetof(struct thread_options, ioprio), .help = "Set job IO priority value", - .minval = 0, - .maxval = 7, + .minval = IOPRIO_MIN_PRIO, + .maxval = IOPRIO_MAX_PRIO, .interval = 1, .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_CRED, }, +#else + { + .name = "prio", + .lname = "I/O nice priority", + .type = FIO_OPT_UNSUPPORTED, + .help = "Your platform does not support IO priorities", + }, +#endif +#ifdef FIO_HAVE_IOPRIO_CLASS +#ifndef FIO_HAVE_IOPRIO +#error "FIO_HAVE_IOPRIO_CLASS requires FIO_HAVE_IOPRIO" +#endif { .name = "prioclass", .lname = "I/O nice priority class", .type = FIO_OPT_INT, - .off1 = td_var_offset(ioprio_class), + .off1 = offsetof(struct thread_options, ioprio_class), .help = "Set job IO priority class", - .minval = 0, - .maxval = 3, + .minval = IOPRIO_MIN_PRIO_CLASS, + .maxval = IOPRIO_MAX_PRIO_CLASS, .interval = 1, .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_CRED, }, #else - { - .name = "prio", - .lname = "I/O nice priority", - .type = FIO_OPT_UNSUPPORTED, - .help = "Your platform does not support IO priorities", - }, { .name = "prioclass", .lname = "I/O nice priority class", .type = FIO_OPT_UNSUPPORTED, - .help = "Your platform does not support IO priorities", + .help = "Your platform does not support IO priority classes", }, #endif { .name = "thinktime", .lname = "Thinktime", .type = FIO_OPT_INT, - .off1 = td_var_offset(thinktime), + .off1 = offsetof(struct thread_options, thinktime), .help = "Idle time between IO buffers (usec)", .def = "0", .is_time = 1, @@ -3059,7 +3257,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "thinktime_spin", .lname = "Thinktime spin", .type = FIO_OPT_INT, - .off1 = td_var_offset(thinktime_spin), + .off1 = offsetof(struct thread_options, thinktime_spin), .help = "Start think time by spinning this amount (usec)", .def = "0", .is_time = 1, @@ -3072,7 +3270,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "thinktime_blocks", .lname = "Thinktime blocks", .type = FIO_OPT_INT, - .off1 = td_var_offset(thinktime_blocks), + .off1 = offsetof(struct thread_options, thinktime_blocks), .help = "IO buffer period between 'thinktime'", .def = "1", .parent = "thinktime", @@ -3084,9 +3282,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "rate", .lname = "I/O rate", .type = FIO_OPT_INT, - .off1 = td_var_offset(rate[DDIR_READ]), - .off2 = td_var_offset(rate[DDIR_WRITE]), - .off3 = td_var_offset(rate[DDIR_TRIM]), + .off1 = offsetof(struct thread_options, rate[DDIR_READ]), + .off2 = offsetof(struct thread_options, rate[DDIR_WRITE]), + .off3 = offsetof(struct thread_options, rate[DDIR_TRIM]), .help = "Set bandwidth rate", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RATE, @@ -3096,9 +3294,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .alias = "ratemin", .lname = "I/O min rate", .type = FIO_OPT_INT, - .off1 = td_var_offset(ratemin[DDIR_READ]), - .off2 = td_var_offset(ratemin[DDIR_WRITE]), - .off3 = td_var_offset(ratemin[DDIR_TRIM]), + .off1 = offsetof(struct thread_options, ratemin[DDIR_READ]), + .off2 = offsetof(struct thread_options, ratemin[DDIR_WRITE]), + .off3 = offsetof(struct thread_options, ratemin[DDIR_TRIM]), .help = "Job must meet this rate or it will be shutdown", .parent = "rate", .hide = 1, @@ -3109,9 +3307,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "rate_iops", .lname = "I/O rate IOPS", .type = FIO_OPT_INT, - .off1 = td_var_offset(rate_iops[DDIR_READ]), - .off2 = td_var_offset(rate_iops[DDIR_WRITE]), - .off3 = td_var_offset(rate_iops[DDIR_TRIM]), + .off1 = offsetof(struct thread_options, rate_iops[DDIR_READ]), + .off2 = offsetof(struct thread_options, rate_iops[DDIR_WRITE]), + .off3 = offsetof(struct thread_options, rate_iops[DDIR_TRIM]), .help = "Limit IO used to this number of IO operations/sec", .hide = 1, .category = FIO_OPT_C_IO, @@ -3121,9 +3319,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "rate_iops_min", .lname = "I/O min rate IOPS", .type = FIO_OPT_INT, - .off1 = td_var_offset(rate_iops_min[DDIR_READ]), - .off2 = td_var_offset(rate_iops_min[DDIR_WRITE]), - .off3 = td_var_offset(rate_iops_min[DDIR_TRIM]), + .off1 = offsetof(struct thread_options, rate_iops_min[DDIR_READ]), + .off2 = offsetof(struct thread_options, rate_iops_min[DDIR_WRITE]), + .off3 = offsetof(struct thread_options, rate_iops_min[DDIR_TRIM]), .help = "Job must meet this rate or it will be shut down", .parent = "rate_iops", .hide = 1, @@ -3134,7 +3332,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "rate_process", .lname = "Rate Process", .type = FIO_OPT_STR, - .off1 = td_var_offset(rate_process), + .off1 = offsetof(struct thread_options, rate_process), .help = "What process controls how rated IO is managed", .def = "linear", .category = FIO_OPT_C_IO, @@ -3157,7 +3355,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .alias = "ratecycle", .lname = "I/O rate cycle", .type = FIO_OPT_INT, - .off1 = td_var_offset(ratecycle), + .off1 = offsetof(struct thread_options, ratecycle), .help = "Window average for rate limits (msec)", .def = "1000", .parent = "rate", @@ -3169,7 +3367,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "max_latency", .lname = "Max Latency", .type = FIO_OPT_INT, - .off1 = td_var_offset(max_latency), + .off1 = offsetof(struct thread_options, max_latency), .help = "Maximum tolerated IO latency (usec)", .is_time = 1, .category = FIO_OPT_C_IO, @@ -3179,7 +3377,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "latency_target", .lname = "Latency Target (usec)", .type = FIO_OPT_STR_VAL_TIME, - .off1 = td_var_offset(latency_target), + .off1 = offsetof(struct thread_options, latency_target), .help = "Ramp to max queue depth supporting this latency", .is_time = 1, .category = FIO_OPT_C_IO, @@ -3189,7 +3387,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "latency_window", .lname = "Latency Window (usec)", .type = FIO_OPT_STR_VAL_TIME, - .off1 = td_var_offset(latency_window), + .off1 = offsetof(struct thread_options, latency_window), .help = "Time to sustain latency_target", .is_time = 1, .category = FIO_OPT_C_IO, @@ -3199,7 +3397,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "latency_percentile", .lname = "Latency Percentile", .type = FIO_OPT_FLOAT_LIST, - .off1 = td_var_offset(latency_percentile), + .off1 = offsetof(struct thread_options, latency_percentile), .help = "Percentile of IOs must be below latency_target", .def = "100", .maxlen = 1, @@ -3212,7 +3410,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "invalidate", .lname = "Cache invalidate", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(invalidate_cache), + .off1 = offsetof(struct thread_options, invalidate_cache), .help = "Invalidate buffer/page cache prior to running job", .def = "1", .category = FIO_OPT_C_IO, @@ -3222,7 +3420,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "sync", .lname = "Synchronous I/O", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(sync_io), + .off1 = offsetof(struct thread_options, sync_io), .help = "Use O_SYNC for buffered writes", .def = "0", .parent = "buffered", @@ -3234,8 +3432,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "create_serialize", .lname = "Create serialize", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(create_serialize), - .help = "Serialize creating of job files", + .off1 = offsetof(struct thread_options, create_serialize), + .help = "Serialize creation of job files", .def = "1", .category = FIO_OPT_C_FILE, .group = FIO_OPT_G_INVALID, @@ -3244,7 +3442,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "create_fsync", .lname = "Create fsync", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(create_fsync), + .off1 = offsetof(struct thread_options, create_fsync), .help = "fsync file after creation", .def = "1", .category = FIO_OPT_C_FILE, @@ -3254,7 +3452,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "create_on_open", .lname = "Create on open", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(create_on_open), + .off1 = offsetof(struct thread_options, create_on_open), .help = "Create files when they are opened for IO", .def = "0", .category = FIO_OPT_C_FILE, @@ -3264,7 +3462,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "create_only", .lname = "Create Only", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(create_only), + .off1 = offsetof(struct thread_options, create_only), .help = "Only perform file creation phase", .category = FIO_OPT_C_FILE, .def = "0", @@ -3273,7 +3471,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "allow_file_create", .lname = "Allow file create", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(allow_create), + .off1 = offsetof(struct thread_options, allow_create), .help = "Permit fio to create files, if they don't exist", .def = "1", .category = FIO_OPT_C_FILE, @@ -3283,7 +3481,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "allow_mounted_write", .lname = "Allow mounted write", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(allow_mounted_write), + .off1 = offsetof(struct thread_options, allow_mounted_write), .help = "Allow writes to a mounted partition", .def = "0", .category = FIO_OPT_C_FILE, @@ -3293,7 +3491,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "pre_read", .lname = "Pre-read files", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(pre_read), + .off1 = offsetof(struct thread_options, pre_read), .help = "Pre-read files before starting official testing", .def = "0", .category = FIO_OPT_C_FILE, @@ -3305,7 +3503,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "CPU mask", .type = FIO_OPT_INT, .cb = str_cpumask_cb, - .off1 = td_var_offset(cpumask), + .off1 = offsetof(struct thread_options, cpumask), .help = "CPU affinity mask", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_CRED, @@ -3315,7 +3513,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "CPUs allowed", .type = FIO_OPT_STR, .cb = str_cpus_allowed_cb, - .off1 = td_var_offset(cpumask), + .off1 = offsetof(struct thread_options, cpumask), .help = "Set CPUs allowed", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_CRED, @@ -3324,7 +3522,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "cpus_allowed_policy", .lname = "CPUs allowed distribution policy", .type = FIO_OPT_STR, - .off1 = td_var_offset(cpus_allowed_policy), + .off1 = offsetof(struct thread_options, cpus_allowed_policy), .help = "Distribution policy for cpus_allowed", .parent = "cpus_allowed", .prio = 1, @@ -3367,7 +3565,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "NUMA CPU Nodes", .type = FIO_OPT_STR, .cb = str_numa_cpunodes_cb, - .off1 = td_var_offset(numa_cpunodes), + .off1 = offsetof(struct thread_options, numa_cpunodes), .help = "NUMA CPU nodes bind", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_INVALID, @@ -3377,7 +3575,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "NUMA Memory Policy", .type = FIO_OPT_STR, .cb = str_numa_mpol_cb, - .off1 = td_var_offset(numa_memnodes), + .off1 = offsetof(struct thread_options, numa_memnodes), .help = "NUMA memory policy setup", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_INVALID, @@ -3395,12 +3593,24 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .type = FIO_OPT_UNSUPPORTED, .help = "Build fio with libnuma-dev(el) to enable this option", }, +#endif +#ifdef CONFIG_CUDA + { + .name = "gpu_dev_id", + .lname = "GPU device ID", + .type = FIO_OPT_INT, + .off1 = offsetof(struct thread_options, gpu_dev_id), + .help = "Set GPU device ID for GPUDirect RDMA", + .def = "0", + .category = FIO_OPT_C_GENERAL, + .group = FIO_OPT_G_INVALID, + }, #endif { .name = "end_fsync", .lname = "End fsync", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(end_fsync), + .off1 = offsetof(struct thread_options, end_fsync), .help = "Include fsync at the end of job", .def = "0", .category = FIO_OPT_C_FILE, @@ -3410,7 +3620,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "fsync_on_close", .lname = "Fsync on close", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(fsync_on_close), + .off1 = offsetof(struct thread_options, fsync_on_close), .help = "fsync files on close", .def = "0", .category = FIO_OPT_C_FILE, @@ -3420,12 +3630,22 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "unlink", .lname = "Unlink file", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(unlink), + .off1 = offsetof(struct thread_options, unlink), .help = "Unlink created files after job has completed", .def = "0", .category = FIO_OPT_C_FILE, .group = FIO_OPT_G_INVALID, }, + { + .name = "unlink_each_loop", + .lname = "Unlink file after each loop of a job", + .type = FIO_OPT_BOOL, + .off1 = offsetof(struct thread_options, unlink_each_loop), + .help = "Unlink created files after each loop in a job has completed", + .def = "0", + .category = FIO_OPT_C_FILE, + .group = FIO_OPT_G_INVALID, + }, { .name = "exitall", .lname = "Exit-all on terminate", @@ -3438,8 +3658,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "exitall_on_error", .lname = "Exit-all on terminate in error", - .type = FIO_OPT_BOOL, - .off1 = td_var_offset(unlink), + .type = FIO_OPT_STR_SET, + .off1 = offsetof(struct thread_options, exitall_error), .help = "Terminate all jobs when one exits in error", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_PROCESS, @@ -3449,7 +3669,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Wait for previous", .alias = "wait_for_previous", .type = FIO_OPT_STR_SET, - .off1 = td_var_offset(stonewall), + .off1 = offsetof(struct thread_options, stonewall), .help = "Insert a hard barrier between this job and previous", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_PROCESS, @@ -3458,7 +3678,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "new_group", .lname = "New group", .type = FIO_OPT_STR_SET, - .off1 = td_var_offset(new_group), + .off1 = offsetof(struct thread_options, new_group), .help = "Mark the start of a new group (for reporting)", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_PROCESS, @@ -3467,7 +3687,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "thread", .lname = "Thread", .type = FIO_OPT_STR_SET, - .off1 = td_var_offset(use_thread), + .off1 = offsetof(struct thread_options, use_thread), .help = "Use threads instead of processes", #ifdef CONFIG_NO_SHM .def = "1", @@ -3480,7 +3700,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "per_job_logs", .lname = "Per Job Logs", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(per_job_logs), + .off1 = offsetof(struct thread_options, per_job_logs), .help = "Include job number in generated log files or not", .def = "1", .category = FIO_OPT_C_LOG, @@ -3489,8 +3709,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "write_bw_log", .lname = "Write bandwidth log", - .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(bw_log_file), + .type = FIO_OPT_STR, + .off1 = offsetof(struct thread_options, bw_log_file), + .cb = str_write_bw_log_cb, .help = "Write log of bandwidth during run", .category = FIO_OPT_C_LOG, .group = FIO_OPT_G_INVALID, @@ -3498,8 +3719,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "write_lat_log", .lname = "Write latency log", - .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(lat_log_file), + .type = FIO_OPT_STR, + .off1 = offsetof(struct thread_options, lat_log_file), + .cb = str_write_lat_log_cb, .help = "Write log of latency during run", .category = FIO_OPT_C_LOG, .group = FIO_OPT_G_INVALID, @@ -3507,8 +3729,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "write_iops_log", .lname = "Write IOPS log", - .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(iops_log_file), + .type = FIO_OPT_STR, + .off1 = offsetof(struct thread_options, iops_log_file), + .cb = str_write_iops_log_cb, .help = "Write log of IOPS during run", .category = FIO_OPT_C_LOG, .group = FIO_OPT_G_INVALID, @@ -3517,17 +3740,49 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "log_avg_msec", .lname = "Log averaging (msec)", .type = FIO_OPT_INT, - .off1 = td_var_offset(log_avg_msec), + .off1 = offsetof(struct thread_options, log_avg_msec), .help = "Average bw/iops/lat logs over this period of time", .def = "0", .category = FIO_OPT_C_LOG, .group = FIO_OPT_G_INVALID, }, + { + .name = "log_hist_msec", + .lname = "Log histograms (msec)", + .type = FIO_OPT_INT, + .off1 = offsetof(struct thread_options, log_hist_msec), + .help = "Dump completion latency histograms at frequency of this time value", + .def = "0", + .category = FIO_OPT_C_LOG, + .group = FIO_OPT_G_INVALID, + }, + { + .name = "log_hist_coarseness", + .lname = "Histogram logs coarseness", + .type = FIO_OPT_INT, + .off1 = offsetof(struct thread_options, log_hist_coarseness), + .help = "Integer in range [0,6]. Higher coarseness outputs" + " fewer histogram bins per sample. The number of bins for" + " these are [1216, 608, 304, 152, 76, 38, 19] respectively.", + .def = "0", + .category = FIO_OPT_C_LOG, + .group = FIO_OPT_G_INVALID, + }, + { + .name = "write_hist_log", + .lname = "Write latency histogram logs", + .type = FIO_OPT_STR, + .off1 = offsetof(struct thread_options, hist_log_file), + .cb = str_write_hist_log_cb, + .help = "Write log of latency histograms during run", + .category = FIO_OPT_C_LOG, + .group = FIO_OPT_G_INVALID, + }, { .name = "log_max_value", .lname = "Log maximum instead of average", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(log_max), + .off1 = offsetof(struct thread_options, log_max), .help = "Log max sample in a window instead of average", .def = "0", .category = FIO_OPT_C_LOG, @@ -3537,7 +3792,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "log_offset", .lname = "Log offset of IO", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(log_offset), + .off1 = offsetof(struct thread_options, log_offset), .help = "Include offset of IO for each log entry", .def = "0", .category = FIO_OPT_C_LOG, @@ -3548,7 +3803,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "log_compression", .lname = "Log compression", .type = FIO_OPT_INT, - .off1 = td_var_offset(log_gz), + .off1 = offsetof(struct thread_options, log_gz), .help = "Log in compressed chunks of this size", .minval = 1024ULL, .maxval = 512 * 1024 * 1024ULL, @@ -3561,7 +3816,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Log Compression CPUs", .type = FIO_OPT_STR, .cb = str_log_cpus_allowed_cb, - .off1 = td_var_offset(log_gz_cpumask), + .off1 = offsetof(struct thread_options, log_gz_cpumask), .parent = "log_compression", .help = "Limit log compression to these CPUs", .category = FIO_OPT_C_LOG, @@ -3579,7 +3834,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "log_store_compressed", .lname = "Log store compressed", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(log_gz_store), + .off1 = offsetof(struct thread_options, log_gz_store), .help = "Store logs in a compressed format", .category = FIO_OPT_C_LOG, .group = FIO_OPT_G_INVALID, @@ -3598,11 +3853,20 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Install libz-dev(el) to get compression support", }, #endif + { + .name = "log_unix_epoch", + .lname = "Log epoch unix", + .type = FIO_OPT_BOOL, + .off1 = offsetof(struct thread_options, log_unix_epoch), + .help = "Use Unix time in log files", + .category = FIO_OPT_C_LOG, + .group = FIO_OPT_G_INVALID, + }, { .name = "block_error_percentiles", .lname = "Block error percentiles", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(block_error_hist), + .off1 = offsetof(struct thread_options, block_error_hist), .help = "Record trim block errors and make a histogram", .def = "0", .category = FIO_OPT_C_LOG, @@ -3612,7 +3876,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "bwavgtime", .lname = "Bandwidth average time", .type = FIO_OPT_INT, - .off1 = td_var_offset(bw_avg_time), + .off1 = offsetof(struct thread_options, bw_avg_time), .help = "Time window over which to calculate bandwidth" " (msec)", .def = "500", @@ -3626,7 +3890,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "iopsavgtime", .lname = "IOPS average time", .type = FIO_OPT_INT, - .off1 = td_var_offset(iops_avg_time), + .off1 = offsetof(struct thread_options, iops_avg_time), .help = "Time window over which to calculate IOPS (msec)", .def = "500", .parent = "write_iops_log", @@ -3639,16 +3903,26 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "group_reporting", .lname = "Group reporting", .type = FIO_OPT_STR_SET, - .off1 = td_var_offset(group_reporting), + .off1 = offsetof(struct thread_options, group_reporting), .help = "Do reporting on a per-group basis", .category = FIO_OPT_C_STAT, .group = FIO_OPT_G_INVALID, }, + { + .name = "stats", + .lname = "Stats", + .type = FIO_OPT_BOOL, + .off1 = offsetof(struct thread_options, stats), + .help = "Enable collection of stats", + .def = "1", + .category = FIO_OPT_C_STAT, + .group = FIO_OPT_G_INVALID, + }, { .name = "zero_buffers", .lname = "Zero I/O buffers", .type = FIO_OPT_STR_SET, - .off1 = td_var_offset(zero_buffers), + .off1 = offsetof(struct thread_options, zero_buffers), .help = "Init IO buffers to all zeroes", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_IO_BUF, @@ -3657,7 +3931,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "refill_buffers", .lname = "Refill I/O buffers", .type = FIO_OPT_STR_SET, - .off1 = td_var_offset(refill_buffers), + .off1 = offsetof(struct thread_options, refill_buffers), .help = "Refill IO buffers on every IO submit", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_IO_BUF, @@ -3666,7 +3940,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "scramble_buffers", .lname = "Scramble I/O buffers", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(scramble_buffers), + .off1 = offsetof(struct thread_options, scramble_buffers), .help = "Slightly scramble buffers on every IO submit", .def = "1", .category = FIO_OPT_C_IO, @@ -3677,7 +3951,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Buffer pattern", .type = FIO_OPT_STR, .cb = str_buffer_pattern_cb, - .off1 = td_var_offset(buffer_pattern), + .off1 = offsetof(struct thread_options, buffer_pattern), .help = "Fill pattern for IO buffers", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_IO_BUF, @@ -3687,7 +3961,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Buffer compression percentage", .type = FIO_OPT_INT, .cb = str_buffer_compress_cb, - .off1 = td_var_offset(compress_percentage), + .off1 = offsetof(struct thread_options, compress_percentage), .maxval = 100, .minval = 0, .help = "How compressible the buffer is (approximately)", @@ -3699,7 +3973,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "buffer_compress_chunk", .lname = "Buffer compression chunk size", .type = FIO_OPT_INT, - .off1 = td_var_offset(compress_chunk), + .off1 = offsetof(struct thread_options, compress_chunk), .parent = "buffer_compress_percentage", .hide = 1, .help = "Size of compressible region in buffer", @@ -3712,7 +3986,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Dedupe percentage", .type = FIO_OPT_INT, .cb = str_dedupe_cb, - .off1 = td_var_offset(dedupe_percentage), + .off1 = offsetof(struct thread_options, dedupe_percentage), .maxval = 100, .minval = 0, .help = "Percentage of buffers that are dedupable", @@ -3724,7 +3998,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "clat_percentiles", .lname = "Completion latency percentiles", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(clat_percentiles), + .off1 = offsetof(struct thread_options, clat_percentiles), .help = "Enable the reporting of completion latency percentiles", .def = "1", .category = FIO_OPT_C_STAT, @@ -3734,8 +4008,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "percentile_list", .lname = "Percentile list", .type = FIO_OPT_FLOAT_LIST, - .off1 = td_var_offset(percentile_list), - .off2 = td_var_offset(percentile_precision), + .off1 = offsetof(struct thread_options, percentile_list), + .off2 = offsetof(struct thread_options, percentile_precision), .help = "Specify a custom list of percentiles to report for " "completion latency and block errors", .def = "1:5:10:20:30:40:50:60:70:80:90:95:99:99.5:99.9:99.95:99.99", @@ -3751,7 +4025,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "disk_util", .lname = "Disk utilization", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(do_disk_util), + .off1 = offsetof(struct thread_options, do_disk_util), .help = "Log disk utilization statistics", .def = "1", .category = FIO_OPT_C_STAT, @@ -3780,7 +4054,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "disable_lat", .lname = "Disable all latency stats", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(disable_lat), + .off1 = offsetof(struct thread_options, disable_lat), .help = "Disable latency numbers", .parent = "gtod_reduce", .hide = 1, @@ -3792,7 +4066,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "disable_clat", .lname = "Disable completion latency stats", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(disable_clat), + .off1 = offsetof(struct thread_options, disable_clat), .help = "Disable completion latency numbers", .parent = "gtod_reduce", .hide = 1, @@ -3804,7 +4078,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "disable_slat", .lname = "Disable submission latency stats", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(disable_slat), + .off1 = offsetof(struct thread_options, disable_slat), .help = "Disable submission latency numbers", .parent = "gtod_reduce", .hide = 1, @@ -3814,9 +4088,10 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { }, { .name = "disable_bw_measurement", + .alias = "disable_bw", .lname = "Disable bandwidth stats", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(disable_bw), + .off1 = offsetof(struct thread_options, disable_bw), .help = "Disable bandwidth logging", .parent = "gtod_reduce", .hide = 1, @@ -3828,7 +4103,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "gtod_cpu", .lname = "Dedicated gettimeofday() CPU", .type = FIO_OPT_INT, - .off1 = td_var_offset(gtod_cpu), + .off1 = offsetof(struct thread_options, gtod_cpu), .help = "Set up dedicated gettimeofday() thread on this CPU", .verify = gtod_cpu_verify, .category = FIO_OPT_C_GENERAL, @@ -3838,7 +4113,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "unified_rw_reporting", .lname = "Unified RW Reporting", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(unified_rw_rep), + .off1 = offsetof(struct thread_options, unified_rw_rep), .help = "Unify reporting across data direction", .def = "0", .category = FIO_OPT_C_GENERAL, @@ -3848,7 +4123,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "continue_on_error", .lname = "Continue on error", .type = FIO_OPT_STR, - .off1 = td_var_offset(continue_on_error), + .off1 = offsetof(struct thread_options, continue_on_error), .help = "Continue on non-fatal errors during IO", .def = "none", .category = FIO_OPT_C_GENERAL, @@ -3893,7 +4168,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Ignore Error", .type = FIO_OPT_STR, .cb = str_ignore_error_cb, - .off1 = td_var_offset(ignore_error_nr), + .off1 = offsetof(struct thread_options, ignore_error_nr), .help = "Set a specific list of errors to ignore", .parent = "rw", .category = FIO_OPT_C_GENERAL, @@ -3903,7 +4178,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "error_dump", .lname = "Error Dump", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(error_dump), + .off1 = offsetof(struct thread_options, error_dump), .def = "0", .help = "Dump info on each error", .category = FIO_OPT_C_GENERAL, @@ -3913,7 +4188,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "profile", .lname = "Profile", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(profile), + .off1 = offsetof(struct thread_options, profile), .help = "Select a specific builtin performance test", .category = FIO_OPT_C_PROFILE, .group = FIO_OPT_G_INVALID, @@ -3922,7 +4197,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "cgroup", .lname = "Cgroup", .type = FIO_OPT_STR_STORE, - .off1 = td_var_offset(cgroup), + .off1 = offsetof(struct thread_options, cgroup), .help = "Add job to cgroup of this name", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_CGROUP, @@ -3931,7 +4206,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "cgroup_nodelete", .lname = "Cgroup no-delete", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(cgroup_nodelete), + .off1 = offsetof(struct thread_options, cgroup_nodelete), .help = "Do not delete cgroups after job completion", .def = "0", .parent = "cgroup", @@ -3942,7 +4217,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "cgroup_weight", .lname = "Cgroup weight", .type = FIO_OPT_INT, - .off1 = td_var_offset(cgroup_weight), + .off1 = offsetof(struct thread_options, cgroup_weight), .help = "Use given weight for cgroup", .minval = 100, .maxval = 1000, @@ -3954,7 +4229,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "uid", .lname = "User ID", .type = FIO_OPT_INT, - .off1 = td_var_offset(uid), + .off1 = offsetof(struct thread_options, uid), .help = "Run job with this user ID", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_CRED, @@ -3963,7 +4238,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "gid", .lname = "Group ID", .type = FIO_OPT_INT, - .off1 = td_var_offset(gid), + .off1 = offsetof(struct thread_options, gid), .help = "Run job with this group ID", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_CRED, @@ -3972,28 +4247,28 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "kb_base", .lname = "KB Base", .type = FIO_OPT_INT, - .off1 = td_var_offset(kb_base), + .off1 = offsetof(struct thread_options, kb_base), .prio = 1, .def = "1024", .posval = { { .ival = "1024", .oval = 1024, - .help = "Use 1024 as the K base", + .help = "Inputs invert IEC and SI prefixes (for compatibility); outputs prefer binary", }, { .ival = "1000", .oval = 1000, - .help = "Use 1000 as the K base", + .help = "Inputs use IEC and SI prefixes; outputs prefer SI", }, }, - .help = "How many bytes per KB for reporting (1000 or 1024)", + .help = "Unit prefix interpretation for quantities of data (IEC and SI)", .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_INVALID, }, { .name = "unit_base", - .lname = "Base unit for reporting (Bits or Bytes)", + .lname = "Unit for quantities of data (Bits or Bytes)", .type = FIO_OPT_INT, - .off1 = td_var_offset(unit_base), + .off1 = offsetof(struct thread_options, unit_base), .prio = 1, .posval = { { .ival = "0", @@ -4017,7 +4292,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "hugepage-size", .lname = "Hugepage size", .type = FIO_OPT_INT, - .off1 = td_var_offset(hugepage_size), + .off1 = offsetof(struct thread_options, hugepage_size), .help = "When using hugepages, specify size of each page", .def = __fio_stringify(FIO_HUGE_PAGE), .interval = 1024 * 1024, @@ -4028,7 +4303,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "flow_id", .lname = "I/O flow ID", .type = FIO_OPT_INT, - .off1 = td_var_offset(flow_id), + .off1 = offsetof(struct thread_options, flow_id), .help = "The flow index ID to use", .def = "0", .category = FIO_OPT_C_IO, @@ -4038,7 +4313,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "flow", .lname = "I/O flow weight", .type = FIO_OPT_INT, - .off1 = td_var_offset(flow), + .off1 = offsetof(struct thread_options, flow), .help = "Weight for flow control of this job", .parent = "flow_id", .hide = 1, @@ -4050,7 +4325,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "flow_watermark", .lname = "I/O flow watermark", .type = FIO_OPT_INT, - .off1 = td_var_offset(flow_watermark), + .off1 = offsetof(struct thread_options, flow_watermark), .help = "High watermark for flow control. This option" " should be set to the same value for all threads" " with non-zero flow.", @@ -4064,7 +4339,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "flow_sleep", .lname = "I/O flow sleep", .type = FIO_OPT_INT, - .off1 = td_var_offset(flow_sleep), + .off1 = offsetof(struct thread_options, flow_sleep), .help = "How many microseconds to sleep after being held" " back by the flow control mechanism", .parent = "flow_id", @@ -4077,13 +4352,72 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "skip_bad", .lname = "Skip operations against bad blocks", .type = FIO_OPT_BOOL, - .off1 = td_var_offset(skip_bad), + .off1 = offsetof(struct thread_options, skip_bad), .help = "Skip operations against known bad blocks.", .hide = 1, .def = "0", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_MTD, }, + { + .name = "steadystate", + .lname = "Steady state threshold", + .alias = "ss", + .type = FIO_OPT_STR, + .off1 = offsetof(struct thread_options, ss_state), + .cb = str_steadystate_cb, + .help = "Define the criterion and limit to judge when a job has reached steady state", + .def = "iops_slope:0.01%", + .posval = { + { .ival = "iops", + .oval = FIO_SS_IOPS, + .help = "maximum mean deviation of IOPS measurements", + }, + { .ival = "iops_slope", + .oval = FIO_SS_IOPS_SLOPE, + .help = "slope calculated from IOPS measurements", + }, + { .ival = "bw", + .oval = FIO_SS_BW, + .help = "maximum mean deviation of bandwidth measurements", + }, + { + .ival = "bw_slope", + .oval = FIO_SS_BW_SLOPE, + .help = "slope calculated from bandwidth measurements", + }, + }, + .category = FIO_OPT_C_GENERAL, + .group = FIO_OPT_G_RUNTIME, + }, + { + .name = "steadystate_duration", + .lname = "Steady state duration", + .alias = "ss_dur", + .parent = "steadystate", + .type = FIO_OPT_STR_VAL_TIME, + .off1 = offsetof(struct thread_options, ss_dur), + .help = "Stop workload upon attaining steady state for specified duration", + .def = "0", + .is_seconds = 1, + .is_time = 1, + .category = FIO_OPT_C_GENERAL, + .group = FIO_OPT_G_RUNTIME, + }, + { + .name = "steadystate_ramp_time", + .lname = "Steady state ramp time", + .alias = "ss_ramp", + .parent = "steadystate", + .type = FIO_OPT_STR_VAL_TIME, + .off1 = offsetof(struct thread_options, ss_ramp_time), + .help = "Delay before initiation of data collection for steady state job termination testing", + .def = "0", + .is_seconds = 1, + .is_time = 1, + .category = FIO_OPT_C_GENERAL, + .group = FIO_OPT_G_RUNTIME, + }, { .name = NULL, }, @@ -4427,7 +4761,7 @@ int fio_options_parse(struct thread_data *td, char **opts, int num_opts) for (ret = 0, i = 0, unknown = 0; i < num_opts; i++) { struct fio_option *o; int newret = parse_option(opts_copy[i], opts[i], fio_options, - &o, td, &td->opt_list); + &o, &td->o, &td->opt_list); if (!newret && o) fio_option_mark_set(&td->o, o); @@ -4480,7 +4814,7 @@ int fio_cmd_option_parse(struct thread_data *td, const char *opt, char *val) { int ret; - ret = parse_cmd_option(opt, val, fio_options, td, &td->opt_list); + ret = parse_cmd_option(opt, val, fio_options, &td->o, &td->opt_list); if (!ret) { struct fio_option *o; @@ -4502,7 +4836,7 @@ int fio_cmd_ioengine_option_parse(struct thread_data *td, const char *opt, void fio_fill_default_options(struct thread_data *td) { td->o.magic = OPT_MAGIC; - fill_default_options(td, fio_options); + fill_default_options(&td->o, fio_options); } int fio_show_option_help(const char *opt) @@ -4510,40 +4844,26 @@ int fio_show_option_help(const char *opt) return show_cmd_help(fio_options, opt); } -void options_mem_dupe(void *data, struct fio_option *options) -{ - struct fio_option *o; - char **ptr; - - for (o = &options[0]; o->name; o++) { - if (o->type != FIO_OPT_STR_STORE) - continue; - - ptr = td_var(data, o, o->off1); - if (*ptr) - *ptr = strdup(*ptr); - } -} - /* * dupe FIO_OPT_STR_STORE options */ void fio_options_mem_dupe(struct thread_data *td) { - options_mem_dupe(&td->o, fio_options); + options_mem_dupe(fio_options, &td->o); if (td->eo && td->io_ops) { void *oldeo = td->eo; td->eo = malloc(td->io_ops->option_struct_size); memcpy(td->eo, oldeo, td->io_ops->option_struct_size); - options_mem_dupe(td->eo, td->io_ops->options); + options_mem_dupe(td->io_ops->options, td->eo); } } unsigned int fio_get_kb_base(void *data) { - struct thread_options *o = data; + struct thread_data *td = cb_data_to_td(data); + struct thread_options *o = &td->o; unsigned int kb_base = 0; /* @@ -4639,7 +4959,7 @@ void del_opt_posval(const char *optname, const char *ival) void fio_options_free(struct thread_data *td) { - options_free(fio_options, td); + options_free(fio_options, &td->o); if (td->eo && td->io_ops && td->io_ops->options) { options_free(td->io_ops->options, td->eo); free(td->eo);