X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=options.c;h=5f4a8ec2923040ed35c89aaecacb906867cda47d;hp=87a443247a7f9e9d9005482670bc51be4b1441b2;hb=d2ba0d7c5b9b3ddd78e917a2c9e2ca98608f9480;hpb=a869d9c6496c63def848b798e41d2ba48dca0ba5 diff --git a/options.c b/options.c index 87a44324..5f4a8ec2 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; @@ -269,7 +269,7 @@ static int ignore_error_type(struct thread_data *td, int etype, char *str) } else { error[i] = atoi(fname); if (error[i] < 0) - error[i] = error[i]; + error[i] = -error[i]; } if (!error[i]) { log_err("Unknown error %s, please use number value \n", @@ -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; @@ -529,6 +554,7 @@ static int str_verify_cpus_allowed_cb(void *data, const char *input) static int str_numa_cpunodes_cb(void *data, char *input) { struct thread_data *td = data; + struct bitmask *verify_bitmask; if (parse_dryrun()) return 0; @@ -538,13 +564,15 @@ static int str_numa_cpunodes_cb(void *data, char *input) * numa_allocate_nodemask(), so it should be freed by * numa_free_nodemask(). */ - td->o.numa_cpunodesmask = numa_parse_nodestring(input); - if (td->o.numa_cpunodesmask == NULL) { + verify_bitmask = numa_parse_nodestring(input); + if (verify_bitmask == NULL) { log_err("fio: numa_parse_nodestring failed\n"); td_verror(td, 1, "str_numa_cpunodes_cb"); return 1; } + numa_free_nodemask(verify_bitmask); + td->o.numa_cpunodes = strdup(input); td->o.numa_cpumask_set = 1; return 0; } @@ -556,6 +584,7 @@ static int str_numa_mpol_cb(void *data, char *input) { "default", "prefer", "bind", "interleave", "local", NULL }; int i; char *nodelist; + struct bitmask *verify_bitmask; if (parse_dryrun()) return 0; @@ -635,12 +664,15 @@ static int str_numa_mpol_cb(void *data, char *input) break; case MPOL_INTERLEAVE: case MPOL_BIND: - td->o.numa_memnodesmask = numa_parse_nodestring(nodelist); - if (td->o.numa_memnodesmask == NULL) { + verify_bitmask = numa_parse_nodestring(nodelist); + if (verify_bitmask == NULL) { log_err("fio: numa_parse_nodestring failed\n"); td_verror(td, 1, "str_numa_memnodes_cb"); return 1; } + td->o.numa_memnodes = strdup(nodelist); + numa_free_nodemask(verify_bitmask); + break; case MPOL_LOCAL: case MPOL_DEFAULT: @@ -827,8 +859,7 @@ static int str_filename_cb(void *data, const char *input) while ((fname = get_next_name(&str)) != NULL) { if (!strlen(fname)) break; - add_file(td, fname, 0); - td->o.nr_files++; + add_file(td, fname, 0, 1); } free(p); @@ -954,8 +985,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); } @@ -972,15 +1003,27 @@ 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) { + if (!ret && td->o.buffer_pattern_bytes) { 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; } +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; @@ -1492,6 +1535,19 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .ival = "falloc", .help = "fallocate() file based engine", }, +#endif +#ifdef CONFIG_GFAPI + { .ival = "gfapi", + .help = "Glusterfs libgfapi(sync) based engine" + }, + { .ival = "gfapi_async", + .help = "Glusterfs libgfapi(async) based engine" + }, +#endif +#ifdef CONFIG_LIBHDFS + { .ival = "libhdfs", + .help = "Hadoop Distributed Filesystem (HDFS) engine" + }, #endif { .ival = "external", .help = "Load external engine (append name)", @@ -1561,6 +1617,15 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_IO, .group = FIO_OPT_G_INVALID, }, + { + .name = "io_limit", + .lname = "IO Limit", + .type = FIO_OPT_STR_VAL, + .off1 = td_var_offset(io_limit), + .interval = 1024 * 1024, + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_INVALID, + }, { .name = "fill_device", .lname = "Fill device", @@ -1584,6 +1649,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", @@ -2068,6 +2143,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .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, }, @@ -2079,6 +2155,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, }, @@ -2106,6 +2183,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, }, @@ -2155,6 +2233,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .oval = MEM_MALLOC, .help = "Use malloc(3) for IO buffers", }, +#ifndef CONFIG_NO_SHM { .ival = "shm", .oval = MEM_SHM, .help = "Use shared memory segments for IO buffers", @@ -2164,6 +2243,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .oval = MEM_SHMHUGE, .help = "Like shm, but use huge pages", }, +#endif #endif { .ival = "mmap", .oval = MEM_MMAP, @@ -2873,6 +2953,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 { @@ -2956,6 +3057,10 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .type = FIO_OPT_STR_SET, .off1 = td_var_offset(use_thread), .help = "Use threads instead of processes", +#ifdef CONFIG_NO_SHM + .def = "1", + .no_warn_def = 1, +#endif .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_PROCESS, }, @@ -2996,6 +3101,38 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_LOG, .group = FIO_OPT_G_INVALID, }, + { + .name = "log_offset", + .lname = "Log offset of IO", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(log_offset), + .help = "Include offset of IO for each log entry", + .def = "0", + .category = FIO_OPT_C_LOG, + .group = FIO_OPT_G_INVALID, + }, +#ifdef CONFIG_ZLIB + { + .name = "log_compression", + .lname = "Log compression", + .type = FIO_OPT_INT, + .off1 = td_var_offset(log_gz), + .help = "Log in compressed chunks of this size", + .minval = 32 * 1024 * 1024ULL, + .maxval = 512 * 1024 * 1024ULL, + .category = FIO_OPT_C_LOG, + .group = FIO_OPT_G_INVALID, + }, + { + .name = "log_store_compressed", + .lname = "Log store compressed", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(log_gz_store), + .help = "Store logs in a compressed format", + .category = FIO_OPT_C_LOG, + .group = FIO_OPT_G_INVALID, + }, +#endif { .name = "bwavgtime", .lname = "Bandwidth average time", @@ -3073,7 +3210,7 @@ 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 = 0, .help = "How compressible the buffer is (approximately)", @@ -3589,8 +3726,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'; @@ -3787,6 +3926,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); } @@ -3831,7 +3971,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;