X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=options.c;h=9096a322bbc089db652662f8a1b04defd3f228b3;hp=4dcefba05511879ad658efce073f699591351e3d;hb=5e1d8745471d1f315113c5c3fd8b93809d9ddff9;hpb=ebadc0ce34c11b3e0130d5602b18f4ed0e638386 diff --git a/options.c b/options.c index 4dcefba0..9096a322 100644 --- a/options.c +++ b/options.c @@ -102,7 +102,7 @@ static int bssplit_ddir(struct thread_options *o, int ddir, char *str) } else perc = -1; - if (str_to_decimal(fname, &val, 1, o)) { + if (str_to_decimal(fname, &val, 1, o, 0)) { log_err("fio: bssplit conversion failed\n"); free(bssplit); return 1; @@ -283,7 +283,9 @@ static int ignore_error_type(struct thread_data *td, int etype, char *str) td->o.continue_on_error |= 1 << etype; td->o.ignore_error_nr[etype] = i; td->o.ignore_error[etype] = error; - } + } else + free(error); + return 0; } @@ -320,7 +322,7 @@ static int str_rw_cb(void *data, const char *str) { struct thread_data *td = data; struct thread_options *o = &td->o; - char *nr = get_opt_postfix(str); + char *nr; if (parse_dryrun()) return 0; @@ -328,6 +330,7 @@ static int str_rw_cb(void *data, const char *str) o->ddir_seq_nr = 1; o->ddir_seq_add = 0; + nr = get_opt_postfix(str); if (!nr) return 0; @@ -336,7 +339,7 @@ static int str_rw_cb(void *data, const char *str) else { long long val; - if (str_to_decimal(nr, &val, 1, o)) { + if (str_to_decimal(nr, &val, 1, o, 0)) { log_err("fio: rw postfix parsing failed\n"); free(nr); return 1; @@ -394,6 +397,28 @@ static int str_exitall_cb(void) } #ifdef FIO_HAVE_CPU_AFFINITY +int fio_cpus_split(os_cpu_mask_t *mask, unsigned int cpu_index) +{ + unsigned int i, index, cpus_in_mask; + const long max_cpu = cpus_online(); + + cpus_in_mask = fio_cpu_count(mask); + cpu_index = cpu_index % cpus_in_mask; + + index = 0; + for (i = 0; i < max_cpu; i++) { + if (!fio_cpu_isset(mask, i)) + continue; + + if (cpu_index != index) + fio_cpu_clear(mask, i); + + index++; + } + + return fio_cpu_count(mask); +} + static int str_cpumask_cb(void *data, unsigned long long *val) { struct thread_data *td = data; @@ -729,11 +754,11 @@ static int str_random_distribution_cb(void *data, const char *str) } /* - * Return next file in the string. Files are separated with ':'. If the ':' + * 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 * indicate a new file. */ -static char *get_next_file_name(char **ptr) +static char *get_next_name(char **ptr) { char *str = *ptr; char *p, *start; @@ -774,6 +799,43 @@ static char *get_next_file_name(char **ptr) return start; } + +static int get_max_name_idx(char *input) +{ + unsigned int cur_idx; + char *str, *p; + + p = str = strdup(input); + for (cur_idx = 0; ; cur_idx++) + if (get_next_name(&str) == NULL) + break; + + free(p); + return cur_idx; +} + +/* + * 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) +{ + unsigned int cur_idx; + int len; + char *fname, *str, *p; + + p = str = strdup(input); + + index %= get_max_name_idx(input); + for (cur_idx = 0; cur_idx <= index; cur_idx++) + fname = get_next_name(&str); + + len = sprintf(target, "%s/", fname); + free(p); + + return len; +} + static int str_filename_cb(void *data, const char *input) { struct thread_data *td = data; @@ -787,38 +849,45 @@ static int str_filename_cb(void *data, const char *input) if (!td->files_index) td->o.nr_files = 0; - while ((fname = get_next_file_name(&str)) != NULL) { + while ((fname = get_next_name(&str)) != NULL) { if (!strlen(fname)) break; - add_file(td, fname); - td->o.nr_files++; + add_file(td, fname, 0, 1); } free(p); return 0; } -static int str_directory_cb(void *data, const char fio_unused *str) +static int str_directory_cb(void *data, const char fio_unused *unused) { struct thread_data *td = data; struct stat sb; + char *dirname, *str, *p; + int ret = 0; if (parse_dryrun()) return 0; - if (lstat(td->o.directory, &sb) < 0) { - int ret = errno; + p = str = strdup(td->o.directory); + while ((dirname = get_next_name(&str)) != NULL) { + if (lstat(dirname, &sb) < 0) { + ret = errno; - log_err("fio: %s is not a directory\n", td->o.directory); - td_verror(td, ret, "lstat"); - return 1; - } - if (!S_ISDIR(sb.st_mode)) { - log_err("fio: %s is not a directory\n", td->o.directory); - return 1; + log_err("fio: %s is not a directory\n", dirname); + td_verror(td, ret, "lstat"); + goto out; + } + if (!S_ISDIR(sb.st_mode)) { + log_err("fio: %s is not a directory\n", dirname); + ret = 1; + goto out; + } } - return 0; +out: + free(p); + return ret; } static int str_lockfile_cb(void *data, const char fio_unused *str) @@ -936,6 +1005,15 @@ static int str_buffer_pattern_cb(void *data, const char *input) return ret; } +static int str_buffer_compress_cb(void *data, unsigned long long *il) +{ + struct thread_data *td = data; + + td->flags |= TD_F_COMPRESS; + td->o.compress_percentage = *il; + return 0; +} + static int str_verify_pattern_cb(void *data, const char *input) { struct thread_data *td = data; @@ -1387,6 +1465,11 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .ival = "windowsaio", .help = "Windows native asynchronous IO" }, +#endif +#ifdef CONFIG_RBD + { .ival = "rbd", + .help = "Rados Block Device asynchronous IO" + }, #endif { .ival = "mmap", .help = "Memory mapped IO" @@ -1534,6 +1617,16 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_FILE, .group = FIO_OPT_G_INVALID, }, + { + .name = "file_append", + .lname = "File append", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(file_append), + .help = "IO will start at the end of the file(s)", + .def = "0", + .category = FIO_OPT_C_FILE, + .group = FIO_OPT_G_INVALID, + }, { .name = "offset", .lname = "IO offset", @@ -1778,6 +1871,15 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RANDOM, }, + { + .name = "allrandrepeat", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(allrand_repeatable), + .help = "Use repeatable random numbers for everything", + .def = "0", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_RANDOM, + }, { .name = "nrfiles", .lname = "Number of files", @@ -2006,8 +2108,10 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Start delay", .type = FIO_OPT_STR_VAL_TIME, .off1 = td_var_offset(start_delay), + .off2 = td_var_offset(start_delay_high), .help = "Only start job when this period has passed", .def = "0", + .is_seconds = 1, .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_RUNTIME, }, @@ -2019,6 +2123,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(timeout), .help = "Stop workload when this amount of time has passed", .def = "0", + .is_seconds = 1, .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_RUNTIME, }, @@ -2046,6 +2151,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .type = FIO_OPT_STR_VAL_TIME, .off1 = td_var_offset(ramp_time), .help = "Ramp up time before measuring performance", + .is_seconds = 1, .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_RUNTIME, }, @@ -2185,6 +2291,10 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .oval = VERIFY_SHA512, .help = "Use sha512 checksums for verification", }, + { .ival = "xxhash", + .oval = VERIFY_XXHASH, + .help = "Use xxhash checksums for verification", + }, { .ival = "meta", .oval = VERIFY_META, .help = "Use io information", @@ -2809,6 +2919,27 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_CRED, }, + { + .name = "cpus_allowed_policy", + .lname = "CPUs allowed distribution policy", + .type = FIO_OPT_STR, + .off1 = td_var_offset(cpus_allowed_policy), + .help = "Distribution policy for cpus_allowed", + .parent = "cpus_allowed", + .prio = 1, + .posval = { + { .ival = "shared", + .oval = FIO_CPUS_SHARED, + .help = "Mask shared between threads", + }, + { .ival = "split", + .oval = FIO_CPUS_SPLIT, + .help = "Mask split between threads", + }, + }, + .category = FIO_OPT_C_GENERAL, + .group = FIO_OPT_G_CRED, + }, #endif #ifdef CONFIG_LIBNUMA { @@ -3009,9 +3140,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "buffer_compress_percentage", .lname = "Buffer compression percentage", .type = FIO_OPT_INT, - .off1 = td_var_offset(compress_percentage), + .cb = str_buffer_compress_cb, .maxval = 100, - .minval = 1, + .minval = 0, .help = "How compressible the buffer is (approximately)", .interval = 5, .category = FIO_OPT_C_IO, @@ -3525,8 +3656,10 @@ static char *bc_calc(char *str) return NULL; ret = fread(&buf[tmp - str], 1, 128 - (tmp - str), f); - if (ret <= 0) + if (ret <= 0) { + pclose(f); return NULL; + } pclose(f); buf[(tmp - str) + ret - 1] = '\0'; @@ -3723,6 +3856,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); } @@ -3767,7 +3901,16 @@ unsigned int fio_get_kb_base(void *data) struct thread_options *o = data; unsigned int kb_base = 0; - if (o) + /* + * This is a hack... For private options, *data is not holding + * a pointer to the thread_options, but to private data. This means + * we can't safely dereference it, but magic is first so mem wise + * it is valid. But this also means that if the job first sets + * kb_base and expects that to be honored by private options, + * it will be disappointed. We will return the global default + * for this. + */ + if (o && o->magic == OPT_MAGIC) kb_base = o->kb_base; if (!kb_base) kb_base = 1024;