X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=options.c;h=2c703fdb85e622c79f8537d80bd2681d87f85d05;hp=484efc1a2ebe8dd438dceff5a2a1307c8eaf7c0b;hb=e15b023bed77c710652eda2e5c39267fb9975c05;hpb=1b10477b21157800f030c3ec91511a810e75e4c7 diff --git a/options.c b/options.c index 484efc1a..2c703fdb 100644 --- a/options.c +++ b/options.c @@ -98,11 +98,11 @@ static int bssplit_ddir(struct thread_options *o, int ddir, char *str) if (perc > 100) perc = 100; else if (!perc) - perc = -1; + perc = -1U; } else - perc = -1; + perc = -1U; - if (str_to_decimal(fname, &val, 1, o, 0)) { + if (str_to_decimal(fname, &val, 1, o, 0, 0)) { log_err("fio: bssplit conversion failed\n"); free(bssplit); return 1; @@ -127,26 +127,29 @@ static int bssplit_ddir(struct thread_options *o, int ddir, char *str) for (i = 0; i < o->bssplit_nr[ddir]; i++) { struct bssplit *bsp = &bssplit[i]; - if (bsp->perc == (unsigned char) -1) + if (bsp->perc == -1U) perc_missing++; else perc += bsp->perc; } - if (perc > 100) { + if (perc > 100 && perc_missing > 1) { log_err("fio: bssplit percentages add to more than 100%%\n"); free(bssplit); return 1; } + /* * If values didn't have a percentage set, divide the remains between * them. */ if (perc_missing) { + if (perc_missing == 1 && o->bssplit_nr[ddir] == 1) + perc = 100; for (i = 0; i < o->bssplit_nr[ddir]; i++) { struct bssplit *bsp = &bssplit[i]; - if (bsp->perc == (unsigned char) -1) + if (bsp->perc == -1U) bsp->perc = (100 - perc) / perc_missing; } } @@ -339,7 +342,7 @@ static int str_rw_cb(void *data, const char *str) else { long long val; - if (str_to_decimal(nr, &val, 1, o, 0)) { + if (str_to_decimal(nr, &val, 1, o, 0, 0)) { log_err("fio: rw postfix parsing failed\n"); free(nr); return 1; @@ -672,7 +675,7 @@ static int str_numa_mpol_cb(void *data, char *input) } td->o.numa_memnodes = strdup(nodelist); numa_free_nodemask(verify_bitmask); - + break; case MPOL_LOCAL: case MPOL_DEFAULT: @@ -735,7 +738,7 @@ static int str_random_distribution_cb(void *data, const char *str) return 0; nr = get_opt_postfix(str); - if (nr && !str_to_float(nr, &val)) { + if (nr && !str_to_float(nr, &val, 0)) { log_err("fio: random postfix parsing failed\n"); free(nr); return 1; @@ -930,6 +933,29 @@ static int pattern_cb(char *pattern, unsigned int max_size, 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) @@ -966,6 +992,7 @@ static int pattern_cb(char *pattern, unsigned int max_size, * 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); @@ -985,8 +1012,8 @@ static int pattern_cb(char *pattern, unsigned int max_size, if (i == 1) { /* - * The code in verify_io_u_pattern assumes a single byte pattern - * fills the whole verify pattern buffer. + * The code in verify_io_u_pattern assumes a single byte + * pattern fills the whole verify pattern buffer. */ memset(pattern, pattern[0], max_size); } @@ -1003,10 +1030,14 @@ static int str_buffer_pattern_cb(void *data, const char *input) ret = pattern_cb(td->o.buffer_pattern, MAX_PATTERN_SIZE, input, &td->o.buffer_pattern_bytes); - if (!ret) { - td->o.refill_buffers = 0; + 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; } return ret; @@ -1021,6 +1052,16 @@ static int str_buffer_compress_cb(void *data, unsigned long long *il) return 0; } +static int str_dedupe_cb(void *data, unsigned long long *il) +{ + struct thread_data *td = data; + + td->flags |= TD_F_COMPRESS; + td->o.dedupe_percentage = *il; + td->o.refill_buffers = 1; + return 0; +} + static int str_verify_pattern_cb(void *data, const char *input) { struct thread_data *td = data; @@ -1542,7 +1583,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { }, #endif #ifdef CONFIG_LIBHDFS - { .ival = "hdfs", + { .ival = "libhdfs", .help = "Hadoop Distributed Filesystem (HDFS) engine" }, #endif @@ -1686,7 +1727,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Number of IOs to perform", .type = FIO_OPT_STR_VAL, .off1 = td_var_offset(number_ios), - .help = "Force job completion of this number of IOs", + .help = "Force job completion after this number of IOs", .def = "0", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_INVALID, @@ -1771,7 +1812,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Block size division is seq/random (not read/write)", .type = FIO_OPT_BOOL, .off1 = td_var_offset(bs_is_seq_rand), - .help = "Consider any blocksize setting to be sequential,ramdom", + .help = "Consider any blocksize setting to be sequential,random", .def = "0", .parent = "blocksize", .category = FIO_OPT_C_IO, @@ -1802,12 +1843,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "use_os_rand", .lname = "Use OS random", - .type = FIO_OPT_BOOL, - .off1 = td_var_offset(use_os_rand), - .help = "Set to use OS random generator", - .def = "0", - .parent = "rw", - .hide = 1, + .type = FIO_OPT_DEPRECATED, + .off1 = td_var_offset(dep_use_os_rand), .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RANDOM, }, @@ -2141,6 +2178,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Only start job when this period has passed", .def = "0", .is_seconds = 1, + .is_time = 1, .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_RUNTIME, }, @@ -2153,6 +2191,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Stop workload when this amount of time has passed", .def = "0", .is_seconds = 1, + .is_time = 1, .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_RUNTIME, }, @@ -2181,6 +2220,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(ramp_time), .help = "Ramp up time before measuring performance", .is_seconds = 1, + .is_time = 1, .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_RUNTIME, }, @@ -2485,6 +2525,28 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(experimental_verify), .type = FIO_OPT_BOOL, .help = "Enable experimental verification", + .parent = "verify", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_VERIFY, + }, + { + .name = "verify_state_load", + .lname = "Load verify state", + .off1 = td_var_offset(verify_state), + .type = FIO_OPT_BOOL, + .help = "Load verify termination state", + .parent = "verify", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_VERIFY, + }, + { + .name = "verify_state_save", + .lname = "Save verify state", + .off1 = td_var_offset(verify_state_save), + .type = FIO_OPT_BOOL, + .def = "1", + .help = "Save verify state on termination", + .parent = "verify", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_VERIFY, }, @@ -2734,6 +2796,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(thinktime), .help = "Idle time between IO buffers (usec)", .def = "0", + .is_time = 1, .category = FIO_OPT_C_IO, .group = FIO_OPT_G_THINKTIME, }, @@ -2744,6 +2807,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(thinktime_spin), .help = "Start think time by spinning this amount (usec)", .def = "0", + .is_time = 1, .parent = "thinktime", .hide = 1, .category = FIO_OPT_C_IO, @@ -2827,6 +2891,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .type = FIO_OPT_INT, .off1 = td_var_offset(max_latency), .help = "Maximum tolerated IO latency (usec)", + .is_time = 1, .category = FIO_OPT_C_IO, .group = FIO_OPT_G_LATPROF, }, @@ -2836,6 +2901,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .type = FIO_OPT_STR_VAL_TIME, .off1 = td_var_offset(latency_target), .help = "Ramp to max queue depth supporting this latency", + .is_time = 1, .category = FIO_OPT_C_IO, .group = FIO_OPT_G_LATPROF, }, @@ -2845,6 +2911,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .type = FIO_OPT_STR_VAL_TIME, .off1 = td_var_offset(latency_window), .help = "Time to sustain latency_target", + .is_time = 1, .category = FIO_OPT_C_IO, .group = FIO_OPT_G_LATPROF, }, @@ -3227,6 +3294,18 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_IO, .group = FIO_OPT_G_IO_BUF, }, + { + .name = "dedupe_percentage", + .lname = "Dedupe percentage", + .type = FIO_OPT_INT, + .cb = str_dedupe_cb, + .maxval = 100, + .minval = 0, + .help = "Percentage of buffers that are dedupable", + .interval = 1, + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_IO_BUF, + }, { .name = "clat_percentiles", .lname = "Completion latency percentiles", @@ -3854,6 +3933,39 @@ static char **dup_and_sub_options(char **opts, int num_opts) return opts_copy; } +static void show_closest_option(const char *opt) +{ + int best_option, best_distance; + int i, distance; + char *name; + + if (!strlen(opt)) + return; + + name = strdup(opt); + i = 0; + while (name[i] != '\0' && name[i] != '=') + i++; + name[i] = '\0'; + + best_option = -1; + best_distance = INT_MAX; + i = 0; + while (fio_options[i].name) { + distance = string_distance(name, fio_options[i].name); + if (distance < best_distance) { + best_distance = distance; + best_option = i; + } + i++; + } + + if (best_option != -1) + log_err("Did you mean %s?\n", fio_options[best_option].name); + + free(name); +} + int fio_options_parse(struct thread_data *td, char **opts, int num_opts, int dump_cmdline) { @@ -3889,6 +4001,7 @@ int fio_options_parse(struct thread_data *td, char **opts, int num_opts, for (i = 0; i < num_opts; i++) { struct fio_option *o = NULL; int newret = 1; + if (!opts_copy[i]) continue; @@ -3898,9 +4011,10 @@ int fio_options_parse(struct thread_data *td, char **opts, int num_opts, td->eo, dump_cmdline); ret |= newret; - if (!o) + if (!o) { log_err("Bad option <%s>\n", opts[i]); - + show_closest_option(opts[i]); + } free(opts_copy[i]); opts_copy[i] = NULL; }