X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;f=options.c;h=4b4c251b92c3e6895d9dafe99c54dc1c9c388147;hb=7d6be13abb5155045cd8b6bcd8a50fea5391a741;hp=fd91eede7a2ae8a90fe78d59284627235fbecb7e;hpb=e90a0adf85f75a65c02b22ba3766dff0d9d82ae6;p=fio.git diff --git a/options.c b/options.c index fd91eede..4b4c251b 100644 --- a/options.c +++ b/options.c @@ -37,7 +37,7 @@ static int converthexchartoint(char a) { int base; - switch(a) { + switch (a) { case '0'...'9': base = '0'; break; @@ -50,7 +50,7 @@ static int converthexchartoint(char a) default: base = 0; } - return (a - base); + return a - base; } static int bs_cmp(const void *p1, const void *p2) @@ -61,7 +61,7 @@ static int bs_cmp(const void *p1, const void *p2) return bsp1->perc < bsp2->perc; } -static int bssplit_ddir(struct thread_data *td, int ddir, char *str) +static int bssplit_ddir(struct thread_options *o, int ddir, char *str) { struct bssplit *bssplit; unsigned int i, perc, perc_missing; @@ -69,7 +69,7 @@ static int bssplit_ddir(struct thread_data *td, int ddir, char *str) long long val; char *fname; - td->o.bssplit_nr[ddir] = 4; + o->bssplit_nr[ddir] = 4; bssplit = malloc(4 * sizeof(struct bssplit)); i = 0; @@ -84,9 +84,9 @@ static int bssplit_ddir(struct thread_data *td, int ddir, char *str) /* * grow struct buffer, if needed */ - if (i == td->o.bssplit_nr[ddir]) { - td->o.bssplit_nr[ddir] <<= 1; - bssplit = realloc(bssplit, td->o.bssplit_nr[ddir] + if (i == o->bssplit_nr[ddir]) { + o->bssplit_nr[ddir] <<= 1; + bssplit = realloc(bssplit, o->bssplit_nr[ddir] * sizeof(struct bssplit)); } @@ -102,9 +102,9 @@ static int bssplit_ddir(struct thread_data *td, int ddir, char *str) } else perc = -1; - if (str_to_decimal(fname, &val, 1, td)) { + if (str_to_decimal(fname, &val, 1, o)) { log_err("fio: bssplit conversion failed\n"); - free(td->o.bssplit); + free(bssplit); return 1; } @@ -118,13 +118,13 @@ static int bssplit_ddir(struct thread_data *td, int ddir, char *str) i++; } - td->o.bssplit_nr[ddir] = i; + o->bssplit_nr[ddir] = i; /* * Now check if the percentages add up, and how much is missing */ perc = perc_missing = 0; - for (i = 0; i < td->o.bssplit_nr[ddir]; i++) { + for (i = 0; i < o->bssplit_nr[ddir]; i++) { struct bssplit *bsp = &bssplit[i]; if (bsp->perc == (unsigned char) -1) @@ -143,7 +143,7 @@ static int bssplit_ddir(struct thread_data *td, int ddir, char *str) * them. */ if (perc_missing) { - for (i = 0; i < td->o.bssplit_nr[ddir]; i++) { + for (i = 0; i < o->bssplit_nr[ddir]; i++) { struct bssplit *bsp = &bssplit[i]; if (bsp->perc == (unsigned char) -1) @@ -151,16 +151,15 @@ static int bssplit_ddir(struct thread_data *td, int ddir, char *str) } } - td->o.min_bs[ddir] = min_bs; - td->o.max_bs[ddir] = max_bs; + o->min_bs[ddir] = min_bs; + o->max_bs[ddir] = max_bs; /* * now sort based on percentages, for ease of lookup */ - qsort(bssplit, td->o.bssplit_nr[ddir], sizeof(struct bssplit), bs_cmp); - td->o.bssplit[ddir] = bssplit; + qsort(bssplit, o->bssplit_nr[ddir], sizeof(struct bssplit), bs_cmp); + o->bssplit[ddir] = bssplit; return 0; - } static int str_bssplit_cb(void *data, const char *input) @@ -169,6 +168,9 @@ static int str_bssplit_cb(void *data, const char *input) char *str, *p, *odir, *ddir; int ret = 0; + if (parse_dryrun()) + return 0; + p = str = strdup(input); strip_blank_front(&str); @@ -178,36 +180,36 @@ static int str_bssplit_cb(void *data, const char *input) if (odir) { ddir = strchr(odir + 1, ','); if (ddir) { - ret = bssplit_ddir(td, DDIR_TRIM, ddir + 1); + ret = bssplit_ddir(&td->o, DDIR_TRIM, ddir + 1); if (!ret) *ddir = '\0'; } else { char *op; op = strdup(odir + 1); - ret = bssplit_ddir(td, DDIR_TRIM, op); + ret = bssplit_ddir(&td->o, DDIR_TRIM, op); free(op); } - if (!ret) - ret = bssplit_ddir(td, DDIR_WRITE, odir + 1); + if (!ret) + ret = bssplit_ddir(&td->o, DDIR_WRITE, odir + 1); if (!ret) { *odir = '\0'; - ret = bssplit_ddir(td, DDIR_READ, str); + ret = bssplit_ddir(&td->o, DDIR_READ, str); } } else { char *op; op = strdup(str); - ret = bssplit_ddir(td, DDIR_WRITE, op); + ret = bssplit_ddir(&td->o, DDIR_WRITE, op); free(op); if (!ret) { op = strdup(str); - ret = bssplit_ddir(td, DDIR_TRIM, op); + ret = bssplit_ddir(&td->o, DDIR_TRIM, op); free(op); } - ret = bssplit_ddir(td, DDIR_READ, str); + ret = bssplit_ddir(&td->o, DDIR_READ, str); } free(p); @@ -216,17 +218,17 @@ static int str_bssplit_cb(void *data, const char *input) static int str2error(char *str) { - const char * err[] = {"EPERM", "ENOENT", "ESRCH", "EINTR", "EIO", + const char *err[] = { "EPERM", "ENOENT", "ESRCH", "EINTR", "EIO", "ENXIO", "E2BIG", "ENOEXEC", "EBADF", "ECHILD", "EAGAIN", "ENOMEM", "EACCES", "EFAULT", "ENOTBLK", "EBUSY", "EEXIST", "EXDEV", "ENODEV", "ENOTDIR", "EISDIR", "EINVAL", "ENFILE", "EMFILE", "ENOTTY", "ETXTBSY","EFBIG", "ENOSPC", "ESPIPE", - "EROFS","EMLINK", "EPIPE", "EDOM", "ERANGE"}; + "EROFS","EMLINK", "EPIPE", "EDOM", "ERANGE" }; int i = 0, num = sizeof(err) / sizeof(void *); - while( i < num) { + while (i < num) { if (!strcmp(err[i], str)) return i + 1; i++; @@ -272,6 +274,7 @@ static int ignore_error_type(struct thread_data *td, int etype, char *str) if (!error[i]) { log_err("Unknown error %s, please use number value \n", fname); + free(error); return 1; } i++; @@ -290,6 +293,10 @@ static int str_ignore_error_cb(void *data, const char *input) struct thread_data *td = data; char *str, *p, *n; int type = 0, ret = 1; + + if (parse_dryrun()) + return 0; + p = str = strdup(input); strip_blank_front(&str); @@ -312,26 +319,30 @@ 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_options *o = &td->o; char *nr = get_opt_postfix(str); - td->o.ddir_seq_nr = 1; - td->o.ddir_seq_add = 0; + if (parse_dryrun()) + return 0; + + o->ddir_seq_nr = 1; + o->ddir_seq_add = 0; if (!nr) return 0; if (td_random(td)) - td->o.ddir_seq_nr = atoi(nr); + o->ddir_seq_nr = atoi(nr); else { long long val; - if (str_to_decimal(nr, &val, 1, td)) { + if (str_to_decimal(nr, &val, 1, o)) { log_err("fio: rw postfix parsing failed\n"); free(nr); return 1; } - td->o.ddir_seq_add = val; + o->ddir_seq_add = val; } free(nr); @@ -343,19 +354,7 @@ 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) - td->mmapfile = get_opt_postfix(mem); - - return 0; -} - -static int str_verify_cb(void *data, const char *mem) -{ - struct thread_data *td = data; - - if (td->o.verify == VERIFY_CRC32C_INTEL || - td->o.verify == VERIFY_CRC32C) { - crc32c_intel_probe(); - } + td->o.mmapfile = get_opt_postfix(mem); return 0; } @@ -388,40 +387,6 @@ static int str_rwmix_write_cb(void *data, unsigned long long *val) return 0; } -#ifdef FIO_HAVE_IOPRIO -static int str_prioclass_cb(void *data, unsigned long long *val) -{ - struct thread_data *td = data; - unsigned short mask; - - /* - * mask off old class bits, str_prio_cb() may have set a default class - */ - mask = (1 << IOPRIO_CLASS_SHIFT) - 1; - td->ioprio &= mask; - - td->ioprio |= *val << IOPRIO_CLASS_SHIFT; - td->ioprio_set = 1; - return 0; -} - -static int str_prio_cb(void *data, unsigned long long *val) -{ - struct thread_data *td = data; - - td->ioprio |= *val; - - /* - * If no class is set, assume BE - */ - if ((td->ioprio >> IOPRIO_CLASS_SHIFT) == 0) - td->ioprio |= IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT; - - td->ioprio_set = 1; - return 0; -} -#endif - static int str_exitall_cb(void) { exitall_on_terminate = 1; @@ -436,6 +401,9 @@ static int str_cpumask_cb(void *data, unsigned long long *val) long max_cpu; int ret; + if (parse_dryrun()) + return 0; + ret = fio_cpuset_init(&td->o.cpumask); if (ret < 0) { log_err("fio: cpuset_init failed\n"); @@ -534,6 +502,9 @@ static int str_cpus_allowed_cb(void *data, const char *input) struct thread_data *td = data; int ret; + if (parse_dryrun()) + return 0; + ret = set_cpus_allowed(td, &td->o.cpumask, input); if (!ret) td->o.cpumask_set = 1; @@ -559,6 +530,9 @@ static int str_numa_cpunodes_cb(void *data, char *input) { struct thread_data *td = data; + if (parse_dryrun()) + return 0; + /* numa_parse_nodestring() parses a character string list * of nodes into a bit mask. The bit mask is allocated by * numa_allocate_nodemask(), so it should be freed by @@ -579,10 +553,14 @@ static int str_numa_mpol_cb(void *data, char *input) { struct thread_data *td = data; const char * const policy_types[] = - { "default", "prefer", "bind", "interleave", "local" }; + { "default", "prefer", "bind", "interleave", "local", NULL }; int i; + char *nodelist; - char *nodelist = strchr(input, ':'); + if (parse_dryrun()) + return 0; + + nodelist = strchr(input, ':'); if (nodelist) { /* NUL-terminate mode */ *nodelist++ = '\0'; @@ -714,6 +692,9 @@ static int str_random_distribution_cb(void *data, const char *str) double val; char *nr; + if (parse_dryrun()) + return 0; + if (td->o.random_distribution == FIO_RAND_DIST_ZIPF) val = 1.1; else if (td->o.random_distribution == FIO_RAND_DIST_PARETO) @@ -735,54 +716,15 @@ static int str_random_distribution_cb(void *data, const char *str) log_err("fio: zipf theta must different than 1.0\n"); return 1; } - td->o.zipf_theta = val; + td->o.zipf_theta.u.f = val; } else { if (val <= 0.00 || val >= 1.00) { log_err("fio: pareto input out of range (0 < input < 1.0)\n"); return 1; } - td->o.pareto_h = val; - } - - return 0; -} - -static int check_dir(struct thread_data *td, char *fname) -{ -#if 0 - char file[PATH_MAX], *dir; - int elen = 0; - - if (td->o.directory) { - strcpy(file, td->o.directory); - strcat(file, "/"); - elen = strlen(file); - } - - sprintf(file + elen, "%s", fname); - dir = dirname(file); - - { - struct stat sb; - /* - * We can't do this on FIO_DISKLESSIO engines. The engine isn't loaded - * yet, so we can't do this check right here... - */ - if (lstat(dir, &sb) < 0) { - int ret = errno; - - log_err("fio: %s is not a directory\n", dir); - td_verror(td, ret, "lstat"); - return 1; + td->o.pareto_h.u.f = val; } - if (!S_ISDIR(sb.st_mode)) { - log_err("fio: %s is not a directory\n", dir); - return 1; - } - } -#endif - return 0; } @@ -848,10 +790,6 @@ static int str_filename_cb(void *data, const char *input) while ((fname = get_next_file_name(&str)) != NULL) { if (!strlen(fname)) break; - if (check_dir(td, fname)) { - free(p); - return 1; - } add_file(td, fname); td->o.nr_files++; } @@ -865,6 +803,9 @@ static int str_directory_cb(void *data, const char fio_unused *str) struct thread_data *td = data; struct stat sb; + if (parse_dryrun()) + return 0; + if (lstat(td->o.directory, &sb) < 0) { int ret = errno; @@ -884,6 +825,9 @@ static int str_opendir_cb(void *data, const char fio_unused *str) { struct thread_data *td = data; + if (parse_dryrun()) + return 0; + if (!td->files_index) td->o.nr_files = 0; @@ -894,8 +838,8 @@ static int str_verify_pattern_cb(void *data, const char *input) { struct thread_data *td = data; long off; - int i = 0, j = 0, len, k, base = 10; - char* loc1, * loc2; + int i = 0, j = 0, len, k, base = 10, pattern_length; + char *loc1, *loc2; loc1 = strstr(input, "0x"); loc2 = strstr(input, "0X"); @@ -933,10 +877,23 @@ static int str_verify_pattern_cb(void *data, const char *input) * 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. */ + pattern_length = i; while (i > 1 && i * 2 <= MAX_PATTERN_SIZE) { memcpy(&td->o.verify_pattern[i], &td->o.verify_pattern[0], i); i *= 2; } + + /* + * Fill remainder, if the pattern multiple ends up not being + * MAX_PATTERN_SIZE. + */ + while (i > 1 && i < MAX_PATTERN_SIZE) { + unsigned int b = min(pattern_length, MAX_PATTERN_SIZE - i); + + memcpy(&td->o.verify_pattern[i], &td->o.verify_pattern[0], b); + i += b; + } + if (i == 1) { /* * The code in verify_io_u_pattern assumes a single byte pattern @@ -957,39 +914,6 @@ static int str_verify_pattern_cb(void *data, const char *input) return 0; } -static int str_write_bw_log_cb(void *data, const char *str) -{ - struct thread_data *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 = 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 = data; - - if (str) - td->o.iops_log_file = strdup(str); - - td->o.write_iops_log = 1; - return 0; -} - static int str_gtod_reduce_cb(void *data, int *il) { struct thread_data *td = data; @@ -1216,7 +1140,7 @@ struct opt_group *opt_group_cat_from_mask(unsigned int *mask) /* * Map of job/command line options */ -static struct fio_option fio_options[FIO_MAX_OPTS] = { +struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "description", .lname = "Description of job", @@ -1394,6 +1318,11 @@ static struct fio_option fio_options[FIO_MAX_OPTS] = { { .ival = "vsync", .help = "Use readv/writev", }, +#ifdef CONFIG_PWRITEV + { .ival = "pvsync", + .help = "Use preadv/pwritev", + }, +#endif #ifdef CONFIG_LIBAIO { .ival = "libaio", .help = "Linux native asynchronous IO", @@ -1585,6 +1514,16 @@ static struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_IO, .group = FIO_OPT_G_INVALID, }, + { + .name = "number_ios", + .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", + .def = "0", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_INVALID, + }, { .name = "bs", .lname = "Block size", @@ -1660,6 +1599,17 @@ static struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_IO, .group = FIO_OPT_G_INVALID, }, + { + .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), + .help = "Consider any blocksize setting to be sequential,ramdom", + .def = "0", + .parent = "blocksize", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_INVALID, + }, { .name = "randrepeat", .lname = "Random repeatable", @@ -1751,6 +1701,28 @@ static struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RANDOM, }, + { + .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]), + .maxval = 100, + .help = "Percentage of seq/random mix that should be random", + .def = "100,100,100", + .interval = 5, + .inverse = "percentage_sequential", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_RANDOM, + }, + { + .name = "percentage_sequential", + .lname = "Percentage Sequential", + .type = FIO_OPT_DEPRECATED, + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_RANDOM, + }, { .name = "nrfiles", .lname = "Number of files", @@ -1920,6 +1892,16 @@ static struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_IO, .group = FIO_OPT_G_IO_TYPE, }, + { + .name = "atomic", + .lname = "Atomic I/O", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(oatomic), + .help = "Use Atomic IO with O_DIRECT (implies O_DIRECT)", + .def = "0", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_IO_TYPE, + }, { .name = "buffered", .lname = "Buffered I/O", @@ -2091,7 +2073,6 @@ static struct fio_option fio_options[FIO_MAX_OPTS] = { .type = FIO_OPT_STR, .off1 = td_var_offset(verify), .help = "Verify data written", - .cb = str_verify_cb, .def = "0", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_VERIFY, @@ -2520,7 +2501,7 @@ static struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "prio", .lname = "I/O nice priority", .type = FIO_OPT_INT, - .cb = str_prio_cb, + .off1 = td_var_offset(ioprio), .help = "Set job IO priority value", .minval = 0, .maxval = 7, @@ -2532,7 +2513,7 @@ static struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "prioclass", .lname = "I/O nice priority class", .type = FIO_OPT_INT, - .cb = str_prioclass_cb, + .off1 = td_var_offset(ioprio_class), .help = "Set job IO priority class", .minval = 0, .maxval = 3, @@ -2822,9 +2803,8 @@ static struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "write_bw_log", .lname = "Write bandwidth log", - .type = FIO_OPT_STR, + .type = FIO_OPT_STR_STORE, .off1 = td_var_offset(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, @@ -2832,9 +2812,8 @@ static struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "write_lat_log", .lname = "Write latency log", - .type = FIO_OPT_STR, + .type = FIO_OPT_STR_STORE, .off1 = td_var_offset(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, @@ -2842,9 +2821,8 @@ static struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "write_iops_log", .lname = "Write IOPS log", - .type = FIO_OPT_STR, + .type = FIO_OPT_STR_STORE, .off1 = td_var_offset(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, @@ -2889,10 +2867,9 @@ static struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "group_reporting", .lname = "Group reporting", - .type = FIO_OPT_BOOL, + .type = FIO_OPT_STR_SET, .off1 = td_var_offset(group_reporting), .help = "Do reporting on a per-group basis", - .def = "1", .category = FIO_OPT_C_STAT, .group = FIO_OPT_G_INVALID, }, @@ -3440,14 +3417,12 @@ static char *bc_calc(char *str) sprintf(buf, "echo '%s' | %s", tmp, BC_APP); f = popen(buf, "r"); - if (!f) { + if (!f) return NULL; - } ret = fread(&buf[tmp - str], 1, 128 - (tmp - str), f); - if (ret <= 0) { + if (ret <= 0) return NULL; - } pclose(f); buf[(tmp - str) + ret - 1] = '\0'; @@ -3638,7 +3613,7 @@ int fio_cmd_option_parse(struct thread_data *td, const char *opt, char *val) int fio_cmd_ioengine_option_parse(struct thread_data *td, const char *opt, char *val) { - return parse_cmd_option(opt, val, td->io_ops->options, td); + return parse_cmd_option(opt, val, td->io_ops->options, td->eo); } void fio_fill_default_options(struct thread_data *td) @@ -3684,11 +3659,11 @@ void fio_options_mem_dupe(struct thread_data *td) unsigned int fio_get_kb_base(void *data) { - struct thread_data *td = data; + struct thread_options *o = data; unsigned int kb_base = 0; - if (td) - kb_base = td->o.kb_base; + if (o) + kb_base = o->kb_base; if (!kb_base) kb_base = 1024; @@ -3772,3 +3747,9 @@ void fio_options_free(struct thread_data *td) td->eo = NULL; } } + +struct fio_option *fio_option_find(const char *name) +{ + return find_option(fio_options, name); +} +