X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=options.c;h=46d5fb92ea982e64aca4671105ed2128a5042278;hp=b5195c35c7e4bae7991d66b8c83b89c1f644bf58;hb=a64c13a449ddd63bf7b501d85571360f3afd8980;hpb=b84113993b3aa40dc33ba101cd39a95d88732811 diff --git a/options.c b/options.c index b5195c35..46d5fb92 100644 --- a/options.c +++ b/options.c @@ -8,15 +8,27 @@ #include #include #include +#include #include "fio.h" #include "verify.h" #include "parse.h" #include "lib/fls.h" +#include "lib/pattern.h" #include "options.h" #include "crc/crc32c.h" +char client_sockaddr_str[INET6_ADDRSTRLEN] = { 0 }; + +struct pattern_fmt_desc fmt_desc[] = { + { + .fmt = "%o", + .len = FIELD_SIZE(struct io_u *, offset), + .paste = paste_blockoff + } +}; + /* * Check if mmap/mmaphuge has a :/foo/bar/file at the end. If so, return that. */ @@ -33,26 +45,6 @@ static char *get_opt_postfix(const char *str) return strdup(p); } -static int converthexchartoint(char a) -{ - int base; - - switch (a) { - case '0'...'9': - base = '0'; - break; - case 'A'...'F': - base = 'A' - 10; - break; - case 'a'...'f': - base = 'a' - 10; - break; - default: - base = 0; - } - return a - base; -} - static int bs_cmp(const void *p1, const void *p2) { const struct bssplit *bsp1 = p1; @@ -212,7 +204,8 @@ static int str_bssplit_cb(void *data, const char *input) ret = bssplit_ddir(&td->o, DDIR_TRIM, op); free(op); } - ret = bssplit_ddir(&td->o, DDIR_READ, str); + if (!ret) + ret = bssplit_ddir(&td->o, DDIR_READ, str); } free(p); @@ -359,7 +352,8 @@ static int str_mem_cb(void *data, const char *mem) { struct thread_data *td = data; - if (td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAP) + if (td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAP || + td->o.mem_type == MEM_MMAPSHARED) td->o.mmapfile = get_opt_postfix(mem); return 0; @@ -503,9 +497,9 @@ static int set_cpus_allowed(struct thread_data *td, os_cpu_mask_t *mask, ret = 1; break; } - if (icpu > max_cpu) { + if (icpu >= max_cpu) { log_err("fio: CPU %d too large (max=%ld)\n", - icpu, max_cpu); + icpu, max_cpu - 1); ret = 1; break; } @@ -536,8 +530,22 @@ static int str_verify_cpus_allowed_cb(void *data, const char *input) { struct thread_data *td = data; + if (parse_dryrun()) + return 0; + return set_cpus_allowed(td, &td->o.verify_cpumask, input); } + +static int str_log_cpus_allowed_cb(void *data, const char *input) +{ + struct thread_data *td = data; + + if (parse_dryrun()) + return 0; + + return set_cpus_allowed(td, &td->o.log_gz_cpumask, input); +} + #endif #ifdef CONFIG_LIBNUMA @@ -820,7 +828,7 @@ static int get_max_name_idx(char *input) * Returns the directory at the index, indexes > entires will be * assigned via modulo division of the index */ -int set_name_idx(char *target, char *input, int index) +int set_name_idx(char *target, size_t tlen, char *input, int index) { unsigned int cur_idx; int len; @@ -832,7 +840,13 @@ int set_name_idx(char *target, char *input, int index) for (cur_idx = 0; cur_idx <= index; cur_idx++) fname = get_next_name(&str); - len = sprintf(target, "%s/", fname); + if (client_sockaddr_str[0]) { + len = snprintf(target, tlen, "%s/%s.", fname, + client_sockaddr_str); + } else + len = snprintf(target, tlen, "%s/", fname); + + target[tlen - 1] = '\0'; free(p); return len; @@ -905,122 +919,25 @@ static int str_opendir_cb(void *data, const char fio_unused *str) return add_dir_files(td, td->o.opendir); } -static int pattern_cb(char *pattern, unsigned int max_size, - const char *input, unsigned int *pattern_bytes) -{ - long off; - int i = 0, j = 0, len, k, base = 10; - uint32_t pattern_length; - char *loc1, *loc2; - - /* - * Check if it's a string input - */ - loc1 = strchr(input, '\"'); - if (loc1) { - do { - loc1++; - if (*loc1 == '\0' || *loc1 == '\"') - break; - - pattern[i] = *loc1; - i++; - } while (i < max_size); - - if (!i) - return 1; - - goto fill; - } - - /* - * No string, find out if it's decimal or hexidecimal - */ - loc1 = strstr(input, "0x"); - loc2 = strstr(input, "0X"); - if (loc1 || loc2) - base = 16; - off = strtol(input, NULL, base); - if (off != LONG_MAX || errno != ERANGE) { - while (off) { - pattern[i] = off & 0xff; - off >>= 8; - i++; - } - } else { - len = strlen(input); - k = len - 1; - if (base == 16) { - if (loc1) - j = loc1 - input + 2; - else - j = loc2 - input + 2; - } else - return 1; - if (len - j < max_size * 2) { - while (k >= j) { - off = converthexchartoint(input[k--]); - if (k >= j) - off += (converthexchartoint(input[k--]) - * 16); - pattern[i++] = (char) off; - } - } - } - - /* - * Fill the pattern all the way to the end. This greatly reduces - * the number of memcpy's we have to do when verifying the IO. - */ -fill: - pattern_length = i; - while (i > 1 && i * 2 <= max_size) { - memcpy(&pattern[i], &pattern[0], i); - i *= 2; - } - - /* - * Fill remainder, if the pattern multiple ends up not being - * max_size. - */ - while (i > 1 && i < max_size) { - unsigned int b = min(pattern_length, max_size - i); - - memcpy(&pattern[i], &pattern[0], b); - i += b; - } - - if (i == 1) { - /* - * The code in verify_io_u_pattern assumes a single byte - * pattern fills the whole verify pattern buffer. - */ - memset(pattern, pattern[0], max_size); - } - - *pattern_bytes = i; - return 0; -} - static int str_buffer_pattern_cb(void *data, const char *input) { struct thread_data *td = data; int ret; - ret = pattern_cb(td->o.buffer_pattern, MAX_PATTERN_SIZE, input, - &td->o.buffer_pattern_bytes); + /* FIXME: for now buffer pattern does not support formats */ + ret = parse_and_fill_pattern(input, strlen(input), td->o.buffer_pattern, + MAX_PATTERN_SIZE, NULL, 0, NULL, NULL); + if (ret < 0) + return 1; - if (!ret && td->o.buffer_pattern_bytes) { - if (!td->o.compress_percentage) - td->o.refill_buffers = 0; - td->o.scramble_buffers = 0; - td->o.zero_buffers = 0; - } else { - log_err("fio: failed parsing pattern `%s`\n", input); - ret = 1; - } + assert(ret != 0); + td->o.buffer_pattern_bytes = ret; + if (!td->o.compress_percentage) + td->o.refill_buffers = 0; + td->o.scramble_buffers = 0; + td->o.zero_buffers = 0; - return ret; + return 0; } static int str_buffer_compress_cb(void *data, unsigned long long *il) @@ -1047,16 +964,22 @@ static int str_verify_pattern_cb(void *data, const char *input) struct thread_data *td = data; int ret; - ret = pattern_cb(td->o.verify_pattern, MAX_PATTERN_SIZE, input, - &td->o.verify_pattern_bytes); + td->o.verify_fmt_sz = ARRAY_SIZE(td->o.verify_fmt); + ret = parse_and_fill_pattern(input, strlen(input), td->o.verify_pattern, + MAX_PATTERN_SIZE, fmt_desc, sizeof(fmt_desc), + td->o.verify_fmt, &td->o.verify_fmt_sz); + if (ret < 0) + return 1; + assert(ret != 0); + td->o.verify_pattern_bytes = ret; /* - * VERIFY_META could already be set + * VERIFY_* could already be set */ - if (!ret && td->o.verify == VERIFY_NONE) + if (!fio_option_is_set(&td->o, verify)) td->o.verify = VERIFY_PATTERN; - return ret; + return 0; } static int str_gtod_reduce_cb(void *data, int *il) @@ -1597,11 +1520,12 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .group = FIO_OPT_G_IO_BASIC, }, { - .name = "iodepth_batch_complete", - .lname = "IO Depth batch complete", + .name = "iodepth_batch_complete_min", + .lname = "Min IO depth batch complete", + .alias = "iodepth_batch_complete", .type = FIO_OPT_INT, - .off1 = td_var_offset(iodepth_batch_complete), - .help = "Number of IO buffers to retrieve in one go", + .off1 = td_var_offset(iodepth_batch_complete_min), + .help = "Min number of IO buffers to retrieve in one go", .parent = "iodepth", .hide = 1, .minval = 0, @@ -1610,6 +1534,19 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_IO, .group = FIO_OPT_G_IO_BASIC, }, + { + .name = "iodepth_batch_complete_max", + .lname = "Max IO depth batch complete", + .type = FIO_OPT_INT, + .off1 = td_var_offset(iodepth_batch_complete_max), + .help = "Max number of IO buffers to retrieve in one go", + .parent = "iodepth", + .hide = 1, + .minval = 0, + .interval = 1, + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_IO_BASIC, + }, { .name = "iodepth_low", .lname = "IO Depth batch low", @@ -1622,6 +1559,26 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_IO, .group = FIO_OPT_G_IO_BASIC, }, + { + .name = "io_submit_mode", + .lname = "IO submit mode", + .type = FIO_OPT_STR, + .off1 = td_var_offset(io_submit_mode), + .help = "How IO submissions and completions are done", + .def = "inline", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_IO_BASIC, + .posval = { + { .ival = "inline", + .oval = IO_MODE_INLINE, + .help = "Submit and complete IO inline", + }, + { .ival = "offload", + .oval = IO_MODE_OFFLOAD, + .help = "Offload submit and complete to threads", + }, + }, + }, { .name = "size", .lname = "Size", @@ -1816,6 +1773,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .type = FIO_OPT_STR_VAL, .off1 = td_var_offset(rand_seed), .help = "Set the random generator seed value", + .def = "0x89", .parent = "rw", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RANDOM, @@ -1867,6 +1825,11 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .oval = FIO_RAND_GEN_LFSR, .help = "Variable length LFSR", }, + { + .ival = "tausworthe64", + .oval = FIO_RAND_GEN_TAUSWORTHE64, + .help = "64-bit Tausworthe variant", + }, }, .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RANDOM, @@ -2281,6 +2244,10 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .oval = MEM_MMAP, .help = "Use mmap(2) (file or anon) for IO buffers", }, + { .ival = "mmapshared", + .oval = MEM_MMAPSHARED, + .help = "Like mmap, but use the shared flag", + }, #ifdef FIO_HAVE_HUGETLB { .ival = "mmaphuge", .oval = MEM_MMAPHUGE, @@ -2361,9 +2328,17 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .oval = VERIFY_XXHASH, .help = "Use xxhash checksums for verification", }, + /* Meta information was included into verify_header, + * 'meta' verification is implied by default. */ { .ival = "meta", - .oval = VERIFY_META, - .help = "Use io information", + .oval = VERIFY_HDR_ONLY, + .help = "Use io information for verification. " + "Now is implied by default, thus option is obsolete, " + "don't use it", + }, + { .ival = "pattern", + .oval = VERIFY_PATTERN_NO_HDR, + .help = "Verify strict pattern", }, { .ival = "null", @@ -2641,6 +2616,28 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_IO, .group = FIO_OPT_G_IOLOG, }, + { + .name = "replay_scale", + .lname = "Replace offset scale factor", + .type = FIO_OPT_INT, + .off1 = td_var_offset(replay_scale), + .parent = "read_iolog", + .def = "1", + .help = "Align offsets to this blocksize", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_IOLOG, + }, + { + .name = "replay_align", + .lname = "Replace alignment", + .type = FIO_OPT_INT, + .off1 = td_var_offset(replay_align), + .parent = "read_iolog", + .help = "Scale offset down by this factor", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_IOLOG, + .pow2 = 1, + }, { .name = "exec_prerun", .lname = "Pre-execute runnable", @@ -2836,7 +2833,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .group = FIO_OPT_G_RATE, }, { - .name = "ratemin", + .name = "rate_min", + .alias = "ratemin", .lname = "I/O min rate", .type = FIO_OPT_INT, .off1 = td_var_offset(ratemin[DDIR_READ]), @@ -2874,7 +2872,30 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .group = FIO_OPT_G_RATE, }, { - .name = "ratecycle", + .name = "rate_process", + .lname = "Rate Process", + .type = FIO_OPT_STR, + .off1 = td_var_offset(rate_process), + .help = "What process controls how rated IO is managed", + .def = "linear", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_RATE, + .posval = { + { .ival = "linear", + .oval = RATE_PROCESS_LINEAR, + .help = "Linear rate of IO", + }, + { + .ival = "poisson", + .oval = RATE_PROCESS_POISSON, + .help = "Rate follows Poisson process", + }, + }, + .parent = "rate", + }, + { + .name = "rate_cycle", + .alias = "ratecycle", .lname = "I/O rate cycle", .type = FIO_OPT_INT, .off1 = td_var_offset(ratecycle), @@ -2987,6 +3008,26 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_FILE, .def = "0", }, + { + .name = "allow_file_create", + .lname = "Allow file create", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(allow_create), + .help = "Permit fio to create files, if they don't exist", + .def = "1", + .category = FIO_OPT_C_FILE, + .group = FIO_OPT_G_FILENAME, + }, + { + .name = "allow_mounted_write", + .lname = "Allow mounted write", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(allow_mounted_write), + .help = "Allow writes to a mounted partition", + .def = "0", + .category = FIO_OPT_C_FILE, + .group = FIO_OPT_G_FILENAME, + }, { .name = "pre_read", .lname = "Pre-read files", @@ -3099,6 +3140,15 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_PROCESS, }, + { + .name = "exitall_on_error", + .lname = "Exit-all on terminate in error", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(unlink), + .help = "Terminate all jobs when one exits in error", + .category = FIO_OPT_C_GENERAL, + .group = FIO_OPT_G_PROCESS, + }, { .name = "stonewall", .lname = "Wait for previous", @@ -3131,6 +3181,15 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_PROCESS, }, + { + .name = "per_job_logs", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(per_job_logs), + .help = "Include job number in generated log files or not", + .def = "1", + .category = FIO_OPT_C_LOG, + .group = FIO_OPT_G_INVALID, + }, { .name = "write_bw_log", .lname = "Write bandwidth log", @@ -3185,11 +3244,24 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .type = FIO_OPT_INT, .off1 = td_var_offset(log_gz), .help = "Log in compressed chunks of this size", - .minval = 32 * 1024 * 1024ULL, + .minval = 1024ULL, .maxval = 512 * 1024 * 1024ULL, .category = FIO_OPT_C_LOG, .group = FIO_OPT_G_INVALID, }, +#ifdef FIO_HAVE_CPU_AFFINITY + { + .name = "log_compression_cpus", + .lname = "Log Compression CPUs", + .type = FIO_OPT_STR, + .cb = str_log_cpus_allowed_cb, + .off1 = td_var_offset(log_gz_cpumask), + .parent = "log_compression", + .help = "Limit log compression to these CPUs", + .category = FIO_OPT_C_LOG, + .group = FIO_OPT_G_INVALID, + }, +#endif { .name = "log_store_compressed", .lname = "Log store compressed", @@ -3771,6 +3843,18 @@ static struct fio_keyword fio_keywords[] = { }, }; +void fio_keywords_exit(void) +{ + struct fio_keyword *kw; + + kw = &fio_keywords[0]; + while (kw->word) { + free(kw->replace); + kw->replace = NULL; + kw++; + } +} + void fio_keywords_init(void) { unsigned long long mb_memory; @@ -3989,7 +4073,7 @@ static void show_closest_option(const char *opt) i++; } - if (best_option != -1) + if (best_option != -1 && string_distance_ok(name, best_distance)) log_err("Did you mean %s?\n", fio_options[best_option].name); free(name); @@ -4261,7 +4345,7 @@ static int opt_is_set(struct thread_options *o, struct fio_option *opt) opt_off = opt - &fio_options[0]; index = opt_off / (8 * sizeof(uint64_t)); offset = opt_off & ((8 * sizeof(uint64_t)) - 1); - return (o->set_options[index] & (1UL << offset)) != 0; + return (o->set_options[index] & ((uint64_t)1 << offset)) != 0; } int __fio_option_is_set(struct thread_options *o, unsigned int off1) @@ -4286,5 +4370,5 @@ void fio_option_mark_set(struct thread_options *o, struct fio_option *opt) opt_off = opt - &fio_options[0]; index = opt_off / (8 * sizeof(uint64_t)); offset = opt_off & ((8 * sizeof(uint64_t)) - 1); - o->set_options[index] |= 1UL << offset; + o->set_options[index] |= (uint64_t)1 << offset; }