X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;f=options.c;h=c4ecf02b6a868c4240a4cdc52d424884826bddf5;hb=5442cfb01f805ba26d3b8917b85c8e5f7bc50456;hp=635779db0a6d31f3e7e9eb8cc26bfd88521fb9bd;hpb=90265353af8dbf1c43804996909777d4c1a5998e;p=fio.git diff --git a/options.c b/options.c index 635779db..c4ecf02b 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,21 +151,21 @@ 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) { struct thread_data *td = data; - char *str, *p, *odir; + char *str, *p, *odir, *ddir; int ret = 0; p = str = strdup(input); @@ -175,50 +175,163 @@ static int str_bssplit_cb(void *data, const char *input) odir = strchr(str, ','); if (odir) { - ret = bssplit_ddir(td, DDIR_WRITE, odir + 1); + ddir = strchr(odir + 1, ','); + if (ddir) { + ret = bssplit_ddir(&td->o, DDIR_TRIM, ddir + 1); + if (!ret) + *ddir = '\0'; + } else { + char *op; + + op = strdup(odir + 1); + ret = bssplit_ddir(&td->o, DDIR_TRIM, op); + + free(op); + } + 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_READ, str); - if (!ret) - 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->o, DDIR_TRIM, op); + free(op); + } + ret = bssplit_ddir(&td->o, DDIR_READ, str); } free(p); return ret; } +static int str2error(char *str) +{ + 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" }; + int i = 0, num = sizeof(err) / sizeof(void *); + + while (i < num) { + if (!strcmp(err[i], str)) + return i + 1; + i++; + } + return 0; +} + +static int ignore_error_type(struct thread_data *td, int etype, char *str) +{ + unsigned int i; + int *error; + char *fname; + + if (etype >= ERROR_TYPE_CNT) { + log_err("Illegal error type\n"); + return 1; + } + + td->o.ignore_error_nr[etype] = 4; + error = malloc(4 * sizeof(struct bssplit)); + + i = 0; + while ((fname = strsep(&str, ":")) != NULL) { + + if (!strlen(fname)) + break; + + /* + * grow struct buffer, if needed + */ + if (i == td->o.ignore_error_nr[etype]) { + td->o.ignore_error_nr[etype] <<= 1; + error = realloc(error, td->o.ignore_error_nr[etype] + * sizeof(int)); + } + if (fname[0] == 'E') { + error[i] = str2error(fname); + } else { + error[i] = atoi(fname); + if (error[i] < 0) + error[i] = error[i]; + } + if (!error[i]) { + log_err("Unknown error %s, please use number value \n", + fname); + return 1; + } + i++; + } + if (i) { + td->o.continue_on_error |= 1 << etype; + td->o.ignore_error_nr[etype] = i; + td->o.ignore_error[etype] = error; + } + return 0; + +} + +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; + p = str = strdup(input); + + strip_blank_front(&str); + strip_blank_end(str); + + while (p) { + n = strchr(p, ','); + if (n) + *n++ = '\0'; + ret = ignore_error_type(td, type, p); + if (ret) + break; + p = n; + type++; + } + free(str); + return ret; +} + 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); @@ -228,10 +341,11 @@ static int str_rw_cb(void *data, const char *str) static int str_mem_cb(void *data, const char *mem) { struct thread_data *td = data; + struct thread_options *o = &td->o; - if (td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAP) { - td->mmapfile = get_opt_postfix(mem); - if (td->o.mem_type == MEM_MMAPHUGE && !td->mmapfile) { + if (o->mem_type == MEM_MMAPHUGE || o->mem_type == MEM_MMAP) { + o->mmapfile = get_opt_postfix(mem); + if (o->mem_type == MEM_MMAPHUGE && !o->mmapfile) { log_err("fio: mmaphuge:/path/to/file\n"); return 1; } @@ -240,18 +354,6 @@ static int str_mem_cb(void *data, const char *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(); - } - - return 0; -} - static int fio_clock_source_cb(void *data, const char *str) { struct thread_data *td = data; @@ -261,12 +363,6 @@ static int fio_clock_source_cb(void *data, const char *str) return 0; } -static int str_lockmem_cb(void fio_unused *data, unsigned long long *val) -{ - mlock_size = *val; - return 0; -} - static int str_rwmix_read_cb(void *data, unsigned long long *val) { struct thread_data *td = data; @@ -285,40 +381,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; @@ -451,16 +513,6 @@ static int str_verify_cpus_allowed_cb(void *data, const char *input) } #endif -#ifdef FIO_HAVE_TRIM -static int str_verify_trim_cb(void *data, unsigned long long *val) -{ - struct thread_data *td = data; - - td->o.trim_percentage = *val; - return 0; -} -#endif - static int str_fst_cb(void *data, const char *str) { struct thread_data *td = data; @@ -491,45 +543,6 @@ static int str_sfr_cb(void *data, const char *str) } #endif -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; - } - } -#endif - - return 0; -} - /* * Return next file in the string. Files are separated with ':'. If the ':' * is escaped with a '\', then that ':' is part of the filename and does not @@ -592,10 +605,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++; } @@ -634,25 +643,12 @@ static int str_opendir_cb(void *data, const char fio_unused *str) return add_dir_files(td, td->o.opendir); } -static int str_verify_offset_cb(void *data, unsigned long long *off) -{ - struct thread_data *td = data; - - if (*off && *off < sizeof(struct verify_header)) { - log_err("fio: verify_offset too small\n"); - return 1; - } - - td->o.verify_offset = *off; - return 0; -} - 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; + char *loc1, *loc2; loc1 = strstr(input, "0x"); loc2 = strstr(input, "0X"); @@ -728,39 +724,6 @@ static int str_lockfile_cb(void *data, const char *str) 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; @@ -866,6 +829,10 @@ static struct opt_group fio_opt_groups[] = { .name = "Logging", .mask = FIO_OPT_C_LOG, }, + { + .name = "Profiles", + .mask = FIO_OPT_C_PROFILE, + }, { .name = NULL, }, @@ -942,6 +909,47 @@ static struct opt_group fio_opt_cat_groups[] = { .name = "General I/O", .mask = FIO_OPT_G_IO_BASIC, }, + { + .name = "Cgroups", + .mask = FIO_OPT_G_CGROUP, + }, + { + .name = "Runtime", + .mask = FIO_OPT_G_RUNTIME, + }, + { + .name = "Process", + .mask = FIO_OPT_G_PROCESS, + }, + { + .name = "Job credentials / priority", + .mask = FIO_OPT_G_CRED, + }, + { + .name = "Clock settings", + .mask = FIO_OPT_G_CLOCK, + }, + { + .name = "I/O Type", + .mask = FIO_OPT_G_IO_TYPE, + }, + { + .name = "I/O Thinktime", + .mask = FIO_OPT_G_THINKTIME, + }, + { + .name = "Randomizations", + .mask = FIO_OPT_G_RANDOM, + }, + { + .name = "I/O buffers", + .mask = FIO_OPT_G_IO_BUF, + }, + { + .name = "Tiobench profile", + .mask = FIO_OPT_G_TIOBENCH, + }, + { .name = NULL, } @@ -974,18 +982,6 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_DESC, }, - { - .name = "kb_base", - .lname = "KB Base", - .type = FIO_OPT_INT, - .off1 = td_var_offset(kb_base), - .verify = kb_base_verify, - .prio = 1, - .def = "1024", - .help = "How many bytes per KB for reporting (1000 or 1024)", - .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, - }, { .name = "filename", .lname = "Filename(s)", @@ -1066,6 +1062,10 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .oval = TD_DDIR_WRITE, .help = "Sequential write", }, + { .ival = "trim", + .oval = TD_DDIR_TRIM, + .help = "Sequential trim", + }, { .ival = "randread", .oval = TD_DDIR_RANDREAD, .help = "Random read", @@ -1074,10 +1074,18 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .oval = TD_DDIR_RANDWRITE, .help = "Random write", }, + { .ival = "randtrim", + .oval = TD_DDIR_RANDTRIM, + .help = "Random trim", + }, { .ival = "rw", .oval = TD_DDIR_RW, .help = "Sequential read and write mix", }, + { .ival = "readwrite", + .oval = TD_DDIR_RW, + .help = "Sequential read and write mix", + }, { .ival = "randrw", .oval = TD_DDIR_RANDRW, .help = "Random read and write mix" @@ -1188,6 +1196,21 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .ival = "rdma", .help = "RDMA IO engine", }, +#endif +#ifdef FIO_HAVE_FUSION_AW + { .ival = "fusion-aw-sync", + .help = "Fusion-io atomic write engine", + }, +#endif +#ifdef FIO_HAVE_E4_ENG + { .ival = "e4defrag", + .help = "ext4 defrag engine", + }, +#endif +#ifdef FIO_HAVE_FALLOC_ENG + { .ival = "falloc", + .help = "fallocate() file based engine", + }, #endif { .ival = "external", .help = "Load external engine (append name)", @@ -1312,6 +1335,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .type = FIO_OPT_INT, .off1 = td_var_offset(bs[DDIR_READ]), .off2 = td_var_offset(bs[DDIR_WRITE]), + .off3 = td_var_offset(bs[DDIR_TRIM]), .minval = 1, .help = "Block size unit", .def = "4k", @@ -1328,6 +1352,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .type = FIO_OPT_INT, .off1 = td_var_offset(ba[DDIR_READ]), .off2 = td_var_offset(ba[DDIR_WRITE]), + .off3 = td_var_offset(ba[DDIR_TRIM]), .minval = 1, .help = "IO block offset alignment", .parent = "rw", @@ -1345,6 +1370,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off2 = td_var_offset(max_bs[DDIR_READ]), .off3 = td_var_offset(min_bs[DDIR_WRITE]), .off4 = td_var_offset(max_bs[DDIR_WRITE]), + .off5 = td_var_offset(min_bs[DDIR_TRIM]), + .off6 = td_var_offset(max_bs[DDIR_TRIM]), .minval = 1, .help = "Set block size range (in more detail than bs)", .parent = "rw", @@ -1386,7 +1413,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .parent = "rw", .hide = 1, .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_RANDOM, }, { .name = "use_os_rand", @@ -1398,7 +1425,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .parent = "rw", .hide = 1, .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_RANDOM, }, { .name = "norandommap", @@ -1408,8 +1435,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Accept potential duplicate random blocks", .parent = "rw", .hide = 1, + .hide_on_set = 1, .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_RANDOM, }, { .name = "softrandommap", @@ -1421,7 +1449,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .hide = 1, .def = "0", .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_RANDOM, }, { .name = "nrfiles", @@ -1588,8 +1616,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(odirect), .help = "Use O_DIRECT IO (negates buffered)", .def = "0", + .inverse = "buffered", .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_IO_TYPE, }, { .name = "buffered", @@ -1599,8 +1628,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .neg = 1, .help = "Use buffered IO (negates direct)", .def = "1", + .inverse = "direct", .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_IO_TYPE, }, { .name = "overwrite", @@ -1621,7 +1651,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .def = "1", .interval = 1, .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_RUNTIME, }, { .name = "numjobs", @@ -1632,7 +1662,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .def = "1", .interval = 1, .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_RUNTIME, }, { .name = "startdelay", @@ -1642,7 +1672,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Only start job when this period has passed", .def = "0", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_RUNTIME, }, { .name = "runtime", @@ -1653,7 +1683,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Stop workload when this amount of time has passed", .def = "0", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_RUNTIME, }, { .name = "time_based", @@ -1662,7 +1692,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(time_based), .help = "Keep running until runtime/timeout is met", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_RUNTIME, }, { .name = "ramp_time", @@ -1671,7 +1701,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(ramp_time), .help = "Ramp up time before measuring performance", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_RUNTIME, }, { .name = "clocksource", @@ -1681,7 +1711,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(clocksource), .help = "What type of timing source to use", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_CLOCK, .posval = { { .ival = "gettimeofday", .oval = CS_GTOD, @@ -1757,10 +1787,9 @@ 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_INVALID, + .group = FIO_OPT_G_VERIFY, .posval = { { .ival = "0", .oval = VERIFY_NONE, @@ -1859,8 +1888,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Verify offset", .type = FIO_OPT_INT, .help = "Offset verify header location by N bytes", - .def = "0", - .cb = str_verify_offset_cb, + .off1 = td_var_offset(verify_offset), + .minval = sizeof(struct verify_header), .parent = "verify", .hide = 1, .category = FIO_OPT_C_IO, @@ -1953,7 +1982,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "trim_percentage", .lname = "Trim percentage", .type = FIO_OPT_INT, - .cb = str_verify_trim_cb, + .off1 = td_var_offset(trim_percentage), .minval = 0, .maxval = 100, .help = "Number of verify blocks to discard/trim", @@ -2108,7 +2137,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "lockmem", .lname = "Lock memory", .type = FIO_OPT_STR_VAL, - .cb = str_lockmem_cb, + .off1 = td_var_offset(lockmem), .help = "Lock down this amount of memory", .def = "0", .interval = 1024 * 1024, @@ -2159,32 +2188,32 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .def = "0", .interval = 1, .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_CRED, }, #ifdef FIO_HAVE_IOPRIO { .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, .interval = 1, .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_CRED, }, { .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, .interval = 1, .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_CRED, }, #endif { @@ -2195,7 +2224,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Idle time between IO buffers (usec)", .def = "0", .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_THINKTIME, }, { .name = "thinktime_spin", @@ -2207,7 +2236,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .parent = "thinktime", .hide = 1, .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_THINKTIME, }, { .name = "thinktime_blocks", @@ -2219,14 +2248,15 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .parent = "thinktime", .hide = 1, .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_THINKTIME, }, { .name = "rate", .lname = "I/O rate", .type = FIO_OPT_INT, - .off1 = td_var_offset(rate[0]), - .off2 = td_var_offset(rate[1]), + .off1 = td_var_offset(rate[DDIR_READ]), + .off2 = td_var_offset(rate[DDIR_WRITE]), + .off3 = td_var_offset(rate[DDIR_TRIM]), .help = "Set bandwidth rate", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RATE, @@ -2235,8 +2265,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "ratemin", .lname = "I/O min rate", .type = FIO_OPT_INT, - .off1 = td_var_offset(ratemin[0]), - .off2 = td_var_offset(ratemin[1]), + .off1 = td_var_offset(ratemin[DDIR_READ]), + .off2 = td_var_offset(ratemin[DDIR_WRITE]), + .off3 = td_var_offset(ratemin[DDIR_TRIM]), .help = "Job must meet this rate or it will be shutdown", .parent = "rate", .hide = 1, @@ -2247,8 +2278,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "rate_iops", .lname = "I/O rate IOPS", .type = FIO_OPT_INT, - .off1 = td_var_offset(rate_iops[0]), - .off2 = td_var_offset(rate_iops[1]), + .off1 = td_var_offset(rate_iops[DDIR_READ]), + .off2 = td_var_offset(rate_iops[DDIR_WRITE]), + .off3 = td_var_offset(rate_iops[DDIR_TRIM]), .help = "Limit IO used to this number of IO operations/sec", .hide = 1, .category = FIO_OPT_C_IO, @@ -2258,8 +2290,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "rate_iops_min", .lname = "I/O min rate IOPS", .type = FIO_OPT_INT, - .off1 = td_var_offset(rate_iops_min[0]), - .off2 = td_var_offset(rate_iops_min[1]), + .off1 = td_var_offset(rate_iops_min[DDIR_READ]), + .off2 = td_var_offset(rate_iops_min[DDIR_WRITE]), + .off3 = td_var_offset(rate_iops_min[DDIR_TRIM]), .help = "Job must meet this rate or it will be shut down", .parent = "rate_iops", .hide = 1, @@ -2286,7 +2319,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Invalidate buffer/page cache prior to running job", .def = "1", .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_IO_TYPE, }, { .name = "sync", @@ -2298,34 +2331,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .parent = "buffered", .hide = 1, .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, - }, - { - .name = "bwavgtime", - .lname = "Bandwidth average time", - .type = FIO_OPT_INT, - .off1 = td_var_offset(bw_avg_time), - .help = "Time window over which to calculate bandwidth" - " (msec)", - .def = "500", - .parent = "write_bw_log", - .hide = 1, - .interval = 100, - .category = FIO_OPT_C_LOG, - .group = FIO_OPT_G_INVALID, - }, - { - .name = "iopsavgtime", - .lname = "IOPS average time", - .type = FIO_OPT_INT, - .off1 = td_var_offset(iops_avg_time), - .help = "Time window over which to calculate IOPS (msec)", - .def = "500", - .parent = "write_iops_log", - .hide = 1, - .interval = 100, - .category = FIO_OPT_C_LOG, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_IO_TYPE, }, { .name = "create_serialize", @@ -2357,6 +2363,14 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_FILE, .group = FIO_OPT_G_INVALID, }, + { + .name = "create_only", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(create_only), + .help = "Only perform file creation phase", + .category = FIO_OPT_C_FILE, + .def = "0", + }, { .name = "pre_read", .lname = "Pre-read files", @@ -2367,27 +2381,6 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_FILE, .group = FIO_OPT_G_INVALID, }, - { - .name = "cpuload", - .lname = "CPU load", - .type = FIO_OPT_INT, - .off1 = td_var_offset(cpuload), - .help = "Use this percentage of CPU", - .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, - }, - { - .name = "cpuchunks", - .lname = "CPU chunk", - .type = FIO_OPT_INT, - .off1 = td_var_offset(cpucycle), - .help = "Length of the CPU burn cycles (usecs)", - .def = "50000", - .parent = "cpuload", - .hide = 1, - .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, - }, #ifdef FIO_HAVE_CPU_AFFINITY { .name = "cpumask", @@ -2396,7 +2389,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .cb = str_cpumask_cb, .help = "CPU affinity mask", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_CRED, }, { .name = "cpus_allowed", @@ -2405,7 +2398,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .cb = str_cpus_allowed_cb, .help = "Set CPUs allowed", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_CRED, }, #endif { @@ -2445,7 +2438,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .cb = str_exitall_cb, .help = "Terminate all jobs when one exits", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_PROCESS, }, { .name = "stonewall", @@ -2455,7 +2448,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(stonewall), .help = "Insert a hard barrier between this job and previous", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_PROCESS, }, { .name = "new_group", @@ -2464,7 +2457,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(new_group), .help = "Mark the start of a new group (for reporting)", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_PROCESS, }, { .name = "thread", @@ -2473,14 +2466,13 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(use_thread), .help = "Use threads instead of processes", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_PROCESS, }, { .name = "write_bw_log", .lname = "Write bandwidth log", - .type = FIO_OPT_STR, - .off1 = td_var_offset(write_bw_log), - .cb = str_write_bw_log_cb, + .type = FIO_OPT_STR_STORE, + .off1 = td_var_offset(bw_log_file), .help = "Write log of bandwidth during run", .category = FIO_OPT_C_LOG, .group = FIO_OPT_G_INVALID, @@ -2488,9 +2480,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "write_lat_log", .lname = "Write latency log", - .type = FIO_OPT_STR, - .off1 = td_var_offset(write_lat_log), - .cb = str_write_lat_log_cb, + .type = FIO_OPT_STR_STORE, + .off1 = td_var_offset(lat_log_file), .help = "Write log of latency during run", .category = FIO_OPT_C_LOG, .group = FIO_OPT_G_INVALID, @@ -2499,8 +2490,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "write_iops_log", .lname = "Write IOPS log", .type = FIO_OPT_STR, - .off1 = td_var_offset(write_iops_log), - .cb = str_write_iops_log_cb, + .off1 = td_var_offset(iops_log_file), .help = "Write log of IOPS during run", .category = FIO_OPT_C_LOG, .group = FIO_OPT_G_INVALID, @@ -2516,14 +2506,30 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .group = FIO_OPT_G_INVALID, }, { - .name = "hugepage-size", - .lname = "Hugepage size", + .name = "bwavgtime", + .lname = "Bandwidth average time", .type = FIO_OPT_INT, - .off1 = td_var_offset(hugepage_size), - .help = "When using hugepages, specify size of each page", - .def = __fio_stringify(FIO_HUGE_PAGE), - .interval = 1024 * 1024, - .category = FIO_OPT_C_GENERAL, + .off1 = td_var_offset(bw_avg_time), + .help = "Time window over which to calculate bandwidth" + " (msec)", + .def = "500", + .parent = "write_bw_log", + .hide = 1, + .interval = 100, + .category = FIO_OPT_C_LOG, + .group = FIO_OPT_G_INVALID, + }, + { + .name = "iopsavgtime", + .lname = "IOPS average time", + .type = FIO_OPT_INT, + .off1 = td_var_offset(iops_avg_time), + .help = "Time window over which to calculate IOPS (msec)", + .def = "500", + .parent = "write_iops_log", + .hide = 1, + .interval = 100, + .category = FIO_OPT_C_LOG, .group = FIO_OPT_G_INVALID, }, { @@ -2533,7 +2539,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(group_reporting), .help = "Do reporting on a per-group basis", .def = "1", - .category = FIO_OPT_C_GENERAL, + .category = FIO_OPT_C_STAT, .group = FIO_OPT_G_INVALID, }, { @@ -2543,7 +2549,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(zero_buffers), .help = "Init IO buffers to all zeroes", .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_IO_BUF, }, { .name = "refill_buffers", @@ -2552,7 +2558,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(refill_buffers), .help = "Refill IO buffers on every IO submit", .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_IO_BUF, }, { .name = "scramble_buffers", @@ -2562,7 +2568,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Slightly scramble buffers on every IO submit", .def = "1", .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_IO_BUF, }, { .name = "buffer_compress_percentage", @@ -2574,7 +2580,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "How compressible the buffer is (approximately)", .interval = 5, .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_IO_BUF, }, { .name = "buffer_compress_chunk", @@ -2586,7 +2592,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Size of compressible region in buffer", .interval = 256, .category = FIO_OPT_C_IO, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_IO_BUF, }, { .name = "clat_percentiles", @@ -2631,6 +2637,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Greatly reduce number of gettimeofday() calls", .cb = str_gtod_reduce_cb, .def = "0", + .hide_on_set = 1, .category = FIO_OPT_C_STAT, .group = FIO_OPT_G_INVALID, }, @@ -2690,7 +2697,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Set up dedicated gettimeofday() thread on this CPU", .verify = gtod_cpu_verify, .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_CLOCK, }, { .name = "continue_on_error", @@ -2736,13 +2743,31 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { }, }, }, + { + .name = "ignore_error", + .type = FIO_OPT_STR, + .cb = str_ignore_error_cb, + .help = "Set a specific list of errors to ignore", + .parent = "rw", + .category = FIO_OPT_C_GENERAL, + .group = FIO_OPT_G_INVALID, + }, + { + .name = "error_dump", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(error_dump), + .def = "0", + .help = "Dump info on each error", + .category = FIO_OPT_C_GENERAL, + .group = FIO_OPT_G_INVALID, + }, { .name = "profile", .lname = "Profile", .type = FIO_OPT_STR_STORE, .off1 = td_var_offset(profile), .help = "Select a specific builtin performance test", - .category = FIO_OPT_C_GENERAL, + .category = FIO_OPT_C_PROFILE, .group = FIO_OPT_G_INVALID, }, { @@ -2752,7 +2777,18 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(cgroup), .help = "Add job to cgroup of this name", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_CGROUP, + }, + { + .name = "cgroup_nodelete", + .lname = "Cgroup no-delete", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(cgroup_nodelete), + .help = "Do not delete cgroups after job completion", + .def = "0", + .parent = "cgroup", + .category = FIO_OPT_C_GENERAL, + .group = FIO_OPT_G_CGROUP, }, { .name = "cgroup_weight", @@ -2762,18 +2798,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Use given weight for cgroup", .minval = 100, .maxval = 1000, + .parent = "cgroup", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, - }, - { - .name = "cgroup_nodelete", - .lname = "Cgroup no-delete", - .type = FIO_OPT_BOOL, - .off1 = td_var_offset(cgroup_nodelete), - .help = "Do not delete cgroups after job completion", - .def = "0", - .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_CGROUP, }, { .name = "uid", @@ -2782,7 +2809,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(uid), .help = "Run job with this user ID", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_CRED, }, { .name = "gid", @@ -2791,6 +2818,29 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off1 = td_var_offset(gid), .help = "Run job with this group ID", .category = FIO_OPT_C_GENERAL, + .group = FIO_OPT_G_CRED, + }, + { + .name = "kb_base", + .lname = "KB Base", + .type = FIO_OPT_INT, + .off1 = td_var_offset(kb_base), + .verify = kb_base_verify, + .prio = 1, + .def = "1024", + .help = "How many bytes per KB for reporting (1000 or 1024)", + .category = FIO_OPT_C_GENERAL, + .group = FIO_OPT_G_INVALID, + }, + { + .name = "hugepage-size", + .lname = "Hugepage size", + .type = FIO_OPT_INT, + .off1 = td_var_offset(hugepage_size), + .help = "When using hugepages, specify size of each page", + .def = __fio_stringify(FIO_HUGE_PAGE), + .interval = 1024 * 1024, + .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_INVALID, }, { @@ -2993,14 +3043,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'; @@ -3237,11 +3285,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; @@ -3325,3 +3373,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); +} +