X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;f=options.c;h=1c44f426dcbde350f6bff5479e31aeee37b7702f;hb=0fddbf7a07fa4d6501e7a2fcf2b058325affba57;hp=fd91eede7a2ae8a90fe78d59284627235fbecb7e;hpb=e90a0adf85f75a65c02b22ba3766dff0d9d82ae6;p=fio.git diff --git a/options.c b/options.c index fd91eede..1c44f426 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(o->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) @@ -178,36 +177,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 +215,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 +271,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++; @@ -312,26 +312,27 @@ 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; + 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 +344,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,39 +377,22 @@ 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) +static int str_perc_rand_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; + td->o.perc_rand = *val; return 0; } -static int str_prio_cb(void *data, unsigned long long *val) +static int str_perc_seq_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; + td->o.perc_rand = 100 - *val; return 0; } -#endif + static int str_exitall_cb(void) { @@ -579,7 +551,7 @@ 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 = strchr(input, ':'); @@ -735,53 +707,14 @@ 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; - } - - if (!S_ISDIR(sb.st_mode)) { - log_err("fio: %s is not a directory\n", dir); - return 1; - } + td->o.pareto_h.u.f = val; } -#endif return 0; } @@ -848,10 +781,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++; } @@ -894,8 +823,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 +862,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 +899,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 +1125,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 +1303,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", @@ -1751,6 +1665,32 @@ 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, + .cb = str_perc_rand_cb, + .maxval = 100, + .help = "Percentage of seq/random mix that should be random", + .def = "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_INT, + .cb = str_perc_seq_cb, + .maxval = 100, + .help = "Percentage of seq/random mix that should be sequential", + .def = "0", + .interval = 5, + .inverse = "percentage_random", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_RANDOM, + }, { .name = "nrfiles", .lname = "Number of files", @@ -2091,7 +2031,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 +2459,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 +2471,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 +2761,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 +2770,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 +2779,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 +2825,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 +3375,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'; @@ -3684,11 +3617,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 +3705,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); +} +