X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=options.c;h=71c77b9205a9ade59502c73454e5ce310c018b3d;hp=8322dda34e76691ee4c4bfdff9795a30a5ddd0e9;hb=8c07860de982fabaaf41d44c22aa86aba2539b58;hpb=764593c0244bb47d67aa8279903cf946ade9eaf9 diff --git a/options.c b/options.c index 8322dda3..71c77b92 100644 --- a/options.c +++ b/options.c @@ -20,6 +20,14 @@ char client_sockaddr_str[INET6_ADDRSTRLEN] = { 0 }; +struct pattern_fmt_desc fmt_desc[] = { + { + .fmt = "%o", + .len = FIELD_SIZE(struct io_u *, offset), + .paste = paste_blockoff + } +}; + /* * Check if mmap/mmaphuge has a :/foo/bar/file at the end. If so, return that. */ @@ -44,35 +52,28 @@ static int bs_cmp(const void *p1, const void *p2) return (int) bsp1->perc - (int) bsp2->perc; } -static int bssplit_ddir(struct thread_options *o, enum fio_ddir ddir, char *str) +struct split { + unsigned int nr; + unsigned int val1[100]; + unsigned int val2[100]; +}; + +static int split_parse_ddir(struct thread_options *o, struct split *split, + enum fio_ddir ddir, char *str) { - struct bssplit *bssplit; - unsigned int i, perc, perc_missing; - unsigned int max_bs, min_bs; + unsigned int i, perc; long long val; char *fname; - o->bssplit_nr[ddir] = 4; - bssplit = malloc(4 * sizeof(struct bssplit)); + split->nr = 0; i = 0; - max_bs = 0; - min_bs = -1; while ((fname = strsep(&str, ":")) != NULL) { char *perc_str; if (!strlen(fname)) break; - /* - * grow struct buffer, if needed - */ - if (i == o->bssplit_nr[ddir]) { - o->bssplit_nr[ddir] <<= 1; - bssplit = realloc(bssplit, o->bssplit_nr[ddir] - * sizeof(struct bssplit)); - } - perc_str = strstr(fname, "/"); if (perc_str) { *perc_str = '\0'; @@ -87,28 +88,53 @@ static int bssplit_ddir(struct thread_options *o, enum fio_ddir ddir, char *str) if (str_to_decimal(fname, &val, 1, o, 0, 0)) { log_err("fio: bssplit conversion failed\n"); - free(bssplit); return 1; } - if (val > max_bs) - max_bs = val; - if (val < min_bs) - min_bs = val; - - bssplit[i].bs = val; - bssplit[i].perc = perc; + split->val1[i] = val; + split->val2[i] = perc; i++; + if (i == 100) + break; } - o->bssplit_nr[ddir] = i; + split->nr = i; + return 0; +} + +static int bssplit_ddir(struct thread_options *o, enum fio_ddir ddir, char *str) +{ + unsigned int i, perc, perc_missing; + unsigned int max_bs, min_bs; + struct split split; + + memset(&split, 0, sizeof(split)); + + if (split_parse_ddir(o, &split, ddir, str)) + return 1; + if (!split.nr) + return 0; + + max_bs = 0; + min_bs = -1; + o->bssplit[ddir] = malloc(split.nr * sizeof(struct bssplit)); + o->bssplit_nr[ddir] = split.nr; + for (i = 0; i < split.nr; i++) { + if (split.val1[i] > max_bs) + max_bs = split.val1[i]; + if (split.val1[i] < min_bs) + min_bs = split.val1[i]; + + o->bssplit[ddir][i].bs = split.val1[i]; + o->bssplit[ddir][i].perc =split.val2[i]; + } /* * Now check if the percentages add up, and how much is missing */ perc = perc_missing = 0; for (i = 0; i < o->bssplit_nr[ddir]; i++) { - struct bssplit *bsp = &bssplit[i]; + struct bssplit *bsp = &o->bssplit[ddir][i]; if (bsp->perc == -1U) perc_missing++; @@ -118,7 +144,8 @@ static int bssplit_ddir(struct thread_options *o, enum fio_ddir ddir, char *str) if (perc > 100 && perc_missing > 1) { log_err("fio: bssplit percentages add to more than 100%%\n"); - free(bssplit); + free(o->bssplit[ddir]); + o->bssplit[ddir] = NULL; return 1; } @@ -130,7 +157,7 @@ static int bssplit_ddir(struct thread_options *o, enum fio_ddir ddir, char *str) if (perc_missing == 1 && o->bssplit_nr[ddir] == 1) perc = 100; for (i = 0; i < o->bssplit_nr[ddir]; i++) { - struct bssplit *bsp = &bssplit[i]; + struct bssplit *bsp = &o->bssplit[ddir][i]; if (bsp->perc == -1U) bsp->perc = (100 - perc) / perc_missing; @@ -143,8 +170,7 @@ static int bssplit_ddir(struct thread_options *o, enum fio_ddir ddir, char *str) /* * now sort based on percentages, for ease of lookup */ - qsort(bssplit, o->bssplit_nr[ddir], sizeof(struct bssplit), bs_cmp); - o->bssplit[ddir] = bssplit; + qsort(o->bssplit[ddir], o->bssplit_nr[ddir], sizeof(struct bssplit), bs_cmp); return 0; } @@ -201,9 +227,6 @@ static int str_bssplit_cb(void *data, const char *input) char *str, *p; int ret = 0; - if (parse_dryrun()) - return 0; - p = str = strdup(input); strip_blank_front(&str); @@ -211,6 +234,16 @@ static int str_bssplit_cb(void *data, const char *input) ret = str_split_parse(td, str, bssplit_ddir); + if (parse_dryrun()) { + int i; + + for (i = 0; i < DDIR_RWDIR_CNT; i++) { + free(td->o.bssplit[i]); + td->o.bssplit[i] = NULL; + td->o.bssplit_nr[i] = 0; + } + } + free(p); return ret; } @@ -691,12 +724,77 @@ out: static int str_fst_cb(void *data, const char *str) { struct thread_data *td = data; - char *nr = get_opt_postfix(str); + double val; + bool done = false; + char *nr; td->file_service_nr = 1; - if (nr) { - td->file_service_nr = atoi(nr); + + switch (td->o.file_service_type) { + case FIO_FSERVICE_RANDOM: + case FIO_FSERVICE_RR: + case FIO_FSERVICE_SEQ: + nr = get_opt_postfix(str); + if (nr) { + td->file_service_nr = atoi(nr); + free(nr); + } + done = true; + break; + case FIO_FSERVICE_ZIPF: + val = FIO_DEF_ZIPF; + break; + case FIO_FSERVICE_PARETO: + val = FIO_DEF_PARETO; + break; + case FIO_FSERVICE_GAUSS: + val = 0.0; + break; + default: + log_err("fio: bad file service type: %d\n", td->o.file_service_type); + return 1; + } + + if (done) + return 0; + + nr = get_opt_postfix(str); + if (nr && !str_to_float(nr, &val, 0)) { + log_err("fio: file service type random postfix parsing failed\n"); free(nr); + return 1; + } + + free(nr); + + switch (td->o.file_service_type) { + case FIO_FSERVICE_ZIPF: + if (val == 1.00) { + log_err("fio: zipf theta must be different than 1.0\n"); + return 1; + } + if (parse_dryrun()) + return 0; + td->zipf_theta = val; + break; + case FIO_FSERVICE_PARETO: + if (val <= 0.00 || val >= 1.00) { + log_err("fio: pareto input out of range (0 < input < 1.0)\n"); + return 1; + } + if (parse_dryrun()) + return 0; + td->pareto_h = val; + break; + case FIO_FSERVICE_GAUSS: + if (val < 0.00 || val >= 100.00) { + log_err("fio: normal deviation out of range (0 < input < 100.0 )\n"); + return 1; + } + if (parse_dryrun()) + return 0; + td->gauss_dev = val; + break; } return 0; @@ -729,62 +827,30 @@ static int zone_cmp(const void *p1, const void *p2) static int zone_split_ddir(struct thread_options *o, enum fio_ddir ddir, char *str) { - struct zone_split *zsplit; unsigned int i, perc, perc_missing, sperc, sperc_missing; - long long val; - char *fname; - - o->zone_split_nr[ddir] = 4; - zsplit = malloc(4 * sizeof(struct zone_split)); - - i = 0; - while ((fname = strsep(&str, ":")) != NULL) { - char *perc_str; - - if (!strlen(fname)) - break; - - /* - * grow struct buffer, if needed - */ - if (i == o->zone_split_nr[ddir]) { - o->zone_split_nr[ddir] <<= 1; - zsplit = realloc(zsplit, o->zone_split_nr[ddir] - * sizeof(struct zone_split)); - } + struct split split; - perc_str = strstr(fname, "/"); - if (perc_str) { - *perc_str = '\0'; - perc_str++; - perc = atoi(perc_str); - if (perc > 100) - perc = 100; - else if (!perc) - perc = -1U; - } else - perc = -1U; + memset(&split, 0, sizeof(split)); - if (str_to_decimal(fname, &val, 1, o, 0, 0)) { - log_err("fio: zone_split conversion failed\n"); - free(zsplit); - return 1; - } + if (split_parse_ddir(o, &split, ddir, str)) + return 1; + if (!split.nr) + return 0; - zsplit[i].access_perc = val; - zsplit[i].size_perc = perc; - i++; + o->zone_split[ddir] = malloc(split.nr * sizeof(struct zone_split)); + o->zone_split_nr[ddir] = split.nr; + for (i = 0; i < split.nr; i++) { + o->zone_split[ddir][i].access_perc = split.val1[i]; + o->zone_split[ddir][i].size_perc = split.val2[i]; } - o->zone_split_nr[ddir] = i; - /* * Now check if the percentages add up, and how much is missing */ perc = perc_missing = 0; sperc = sperc_missing = 0; for (i = 0; i < o->zone_split_nr[ddir]; i++) { - struct zone_split *zsp = &zsplit[i]; + struct zone_split *zsp = &o->zone_split[ddir][i]; if (zsp->access_perc == (uint8_t) -1U) perc_missing++; @@ -800,13 +866,15 @@ static int zone_split_ddir(struct thread_options *o, enum fio_ddir ddir, if (perc > 100 || sperc > 100) { log_err("fio: zone_split percentages add to more than 100%%\n"); - free(zsplit); + free(o->zone_split[ddir]); + o->zone_split[ddir] = NULL; return 1; } if (perc < 100) { log_err("fio: access percentage don't add up to 100 for zoned " "random distribution (got=%u)\n", perc); - free(zsplit); + free(o->zone_split[ddir]); + o->zone_split[ddir] = NULL; return 1; } @@ -818,7 +886,7 @@ static int zone_split_ddir(struct thread_options *o, enum fio_ddir ddir, if (perc_missing == 1 && o->zone_split_nr[ddir] == 1) perc = 100; for (i = 0; i < o->zone_split_nr[ddir]; i++) { - struct zone_split *zsp = &zsplit[i]; + struct zone_split *zsp = &o->zone_split[ddir][i]; if (zsp->access_perc == (uint8_t) -1U) zsp->access_perc = (100 - perc) / perc_missing; @@ -828,7 +896,7 @@ static int zone_split_ddir(struct thread_options *o, enum fio_ddir ddir, if (sperc_missing == 1 && o->zone_split_nr[ddir] == 1) sperc = 100; for (i = 0; i < o->zone_split_nr[ddir]; i++) { - struct zone_split *zsp = &zsplit[i]; + struct zone_split *zsp = &o->zone_split[ddir][i]; if (zsp->size_perc == (uint8_t) -1U) zsp->size_perc = (100 - sperc) / sperc_missing; @@ -838,8 +906,7 @@ static int zone_split_ddir(struct thread_options *o, enum fio_ddir ddir, /* * now sort based on percentages, for ease of lookup */ - qsort(zsplit, o->zone_split_nr[ddir], sizeof(struct zone_split), zone_cmp); - o->zone_split[ddir] = zsplit; + qsort(o->zone_split[ddir], o->zone_split_nr[ddir], sizeof(struct zone_split), zone_cmp); return 0; } @@ -915,6 +982,18 @@ static int parse_zoned_distribution(struct thread_data *td, const char *input) } } + if (parse_dryrun()) { + int i; + + for (i = 0; i < DDIR_RWDIR_CNT; i++) { + free(td->o.zone_split[i]); + td->o.zone_split[i] = NULL; + td->o.zone_split_nr[i] = 0; + } + + return ret; + } + if (!ret) td_zone_gen_index(td); else { @@ -931,9 +1010,6 @@ 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 = FIO_DEF_ZIPF; else if (td->o.random_distribution == FIO_RAND_DIST_PARETO) @@ -959,18 +1035,24 @@ static int str_random_distribution_cb(void *data, const char *str) log_err("fio: zipf theta must different than 1.0\n"); return 1; } + if (parse_dryrun()) + return 0; td->o.zipf_theta.u.f = val; } else if (td->o.random_distribution == FIO_RAND_DIST_PARETO) { if (val <= 0.00 || val >= 1.00) { log_err("fio: pareto input out of range (0 < input < 1.0)\n"); return 1; } + if (parse_dryrun()) + return 0; td->o.pareto_h.u.f = val; } else { if (val <= 0.00 || val >= 100.0) { log_err("fio: normal deviation out of range (0 < input < 100.0)\n"); return 1; } + if (parse_dryrun()) + return 0; td->o.gauss_dev.u.f = val; } @@ -1175,20 +1257,13 @@ static int str_dedupe_cb(void *data, unsigned long long *il) static int str_verify_pattern_cb(void *data, const char *input) { - struct pattern_fmt_desc fmt_desc[] = { - { - .fmt = "%o", - .len = FIELD_SIZE(struct io_u *, offset), - .paste = paste_blockoff - } - }; struct thread_data *td = data; int ret; td->o.verify_fmt_sz = ARRAY_SIZE(td->o.verify_fmt); ret = parse_and_fill_pattern(input, strlen(input), td->o.verify_pattern, - MAX_PATTERN_SIZE, fmt_desc, sizeof(fmt_desc), - td->o.verify_fmt, &td->o.verify_fmt_sz); + MAX_PATTERN_SIZE, fmt_desc, sizeof(fmt_desc), + td->o.verify_fmt, &td->o.verify_fmt_sz); if (ret < 0) return 1; @@ -1461,7 +1536,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Use preadv/pwritev", }, #endif -#ifdef CONFIG_PWRITEV +#ifdef CONFIG_PWRITEV2 { .ival = "pvsync2", .help = "Use preadv2/pwritev2", }, @@ -1558,6 +1633,12 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .ival = "libhdfs", .help = "Hadoop Distributed Filesystem (HDFS) engine" }, +#endif +#ifdef CONFIG_PMEMBLK + { .ival = "pmemblk", + .help = "NVML libpmemblk based IO engine", + }, + #endif { .ival = "external", .help = "Load external engine (append name)", @@ -2004,7 +2085,19 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .posval = { { .ival = "random", .oval = FIO_FSERVICE_RANDOM, - .help = "Choose a file at random", + .help = "Choose a file at random (uniform)", + }, + { .ival = "zipf", + .oval = FIO_FSERVICE_ZIPF, + .help = "Zipf randomized", + }, + { .ival = "pareto", + .oval = FIO_FSERVICE_PARETO, + .help = "Pareto randomized", + }, + { .ival = "gauss", + .oval = FIO_FSERVICE_GAUSS, + .help = "Normal (guassian) distribution", }, { .ival = "roundrobin", .oval = FIO_FSERVICE_RR,