options: add missing long option names
[fio.git] / options.c
index 0bf1390a0d9f19c4f99d9f3e44582aca446e1c67..7f0f2c08ea7deed5db6b16dcfc2c705fda6d2dc0 100644 (file)
--- a/options.c
+++ b/options.c
 
 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, int 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, int 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, int 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, int 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,60 +170,78 @@ static int bssplit_ddir(struct thread_options *o, int 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;
 }
 
-static int str_bssplit_cb(void *data, const char *input)
+typedef int (split_parse_fn)(struct thread_options *, enum fio_ddir, char *);
+
+static int str_split_parse(struct thread_data *td, char *str, split_parse_fn *fn)
 {
-       struct thread_data *td = data;
-       char *str, *p, *odir, *ddir;
+       char *odir, *ddir;
        int ret = 0;
 
-       if (parse_dryrun())
-               return 0;
-
-       p = str = strdup(input);
-
-       strip_blank_front(&str);
-       strip_blank_end(str);
-
        odir = strchr(str, ',');
        if (odir) {
                ddir = strchr(odir + 1, ',');
                if (ddir) {
-                       ret = bssplit_ddir(&td->o, DDIR_TRIM, ddir + 1);
+                       ret = fn(&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);
+                       ret = fn(&td->o, DDIR_TRIM, op);
 
                        free(op);
                }
                if (!ret)
-                       ret = bssplit_ddir(&td->o, DDIR_WRITE, odir + 1);
+                       ret = fn(&td->o, DDIR_WRITE, odir + 1);
                if (!ret) {
                        *odir = '\0';
-                       ret = bssplit_ddir(&td->o, DDIR_READ, str);
+                       ret = fn(&td->o, DDIR_READ, str);
                }
        } else {
                char *op;
 
                op = strdup(str);
-               ret = bssplit_ddir(&td->o, DDIR_WRITE, op);
+               ret = fn(&td->o, DDIR_WRITE, op);
                free(op);
 
                if (!ret) {
                        op = strdup(str);
-                       ret = bssplit_ddir(&td->o, DDIR_TRIM, op);
+                       ret = fn(&td->o, DDIR_TRIM, op);
                        free(op);
                }
                if (!ret)
-                       ret = bssplit_ddir(&td->o, DDIR_READ, str);
+                       ret = fn(&td->o, DDIR_READ, str);
+       }
+
+       return ret;
+}
+
+static int str_bssplit_cb(void *data, const char *input)
+{
+       struct thread_data *td = data;
+       char *str, *p;
+       int ret = 0;
+
+       p = str = strdup(input);
+
+       strip_blank_front(&str);
+       strip_blank_end(str);
+
+       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);
@@ -679,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;
@@ -706,21 +816,208 @@ static int str_sfr_cb(void *data, const char *str)
 }
 #endif
 
+static int zone_cmp(const void *p1, const void *p2)
+{
+       const struct zone_split *zsp1 = p1;
+       const struct zone_split *zsp2 = p2;
+
+       return (int) zsp2->access_perc - (int) zsp1->access_perc;
+}
+
+static int zone_split_ddir(struct thread_options *o, enum fio_ddir ddir,
+                          char *str)
+{
+       unsigned int i, perc, perc_missing, sperc, sperc_missing;
+       struct split split;
+
+       memset(&split, 0, sizeof(split));
+
+       if (split_parse_ddir(o, &split, ddir, str))
+               return 1;
+       if (!split.nr)
+               return 0;
+
+       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];
+       }
+
+       /*
+        * 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 = &o->zone_split[ddir][i];
+
+               if (zsp->access_perc == (uint8_t) -1U)
+                       perc_missing++;
+               else
+                       perc += zsp->access_perc;
+
+               if (zsp->size_perc == (uint8_t) -1U)
+                       sperc_missing++;
+               else
+                       sperc += zsp->size_perc;
+
+       }
+
+       if (perc > 100 || sperc > 100) {
+               log_err("fio: zone_split percentages add to more than 100%%\n");
+               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(o->zone_split[ddir]);
+               o->zone_split[ddir] = NULL;
+               return 1;
+       }
+
+       /*
+        * If values didn't have a percentage set, divide the remains between
+        * them.
+        */
+       if (perc_missing) {
+               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 = &o->zone_split[ddir][i];
+
+                       if (zsp->access_perc == (uint8_t) -1U)
+                               zsp->access_perc = (100 - perc) / perc_missing;
+               }
+       }
+       if (sperc_missing) {
+               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 = &o->zone_split[ddir][i];
+
+                       if (zsp->size_perc == (uint8_t) -1U)
+                               zsp->size_perc = (100 - sperc) / sperc_missing;
+               }
+       }
+
+       /*
+        * now sort based on percentages, for ease of lookup
+        */
+       qsort(o->zone_split[ddir], o->zone_split_nr[ddir], sizeof(struct zone_split), zone_cmp);
+       return 0;
+}
+
+static void __td_zone_gen_index(struct thread_data *td, enum fio_ddir ddir)
+{
+       unsigned int i, j, sprev, aprev;
+
+       td->zone_state_index[ddir] = malloc(sizeof(struct zone_split_index) * 100);
+
+       sprev = aprev = 0;
+       for (i = 0; i < td->o.zone_split_nr[ddir]; i++) {
+               struct zone_split *zsp = &td->o.zone_split[ddir][i];
+
+               for (j = aprev; j < aprev + zsp->access_perc; j++) {
+                       struct zone_split_index *zsi = &td->zone_state_index[ddir][j];
+
+                       zsi->size_perc = sprev + zsp->size_perc;
+                       zsi->size_perc_prev = sprev;
+               }
+
+               aprev += zsp->access_perc;
+               sprev += zsp->size_perc;
+       }
+}
+
+/*
+ * Generate state table for indexes, so we don't have to do it inline from
+ * the hot IO path
+ */
+static void td_zone_gen_index(struct thread_data *td)
+{
+       int i;
+
+       td->zone_state_index = malloc(DDIR_RWDIR_CNT *
+                                       sizeof(struct zone_split_index *));
+
+       for (i = 0; i < DDIR_RWDIR_CNT; i++)
+               __td_zone_gen_index(td, i);
+}
+
+static int parse_zoned_distribution(struct thread_data *td, const char *input)
+{
+       char *str, *p;
+       int i, ret = 0;
+
+       p = str = strdup(input);
+
+       strip_blank_front(&str);
+       strip_blank_end(str);
+
+       /* We expect it to start like that, bail if not */
+       if (strncmp(str, "zoned:", 6)) {
+               log_err("fio: mismatch in zoned input <%s>\n", str);
+               free(p);
+               return 1;
+       }
+       str += strlen("zoned:");
+
+       ret = str_split_parse(td, str, zone_split_ddir);
+
+       free(p);
+
+       for (i = 0; i < DDIR_RWDIR_CNT; i++) {
+               int j;
+
+               dprint(FD_PARSE, "zone ddir %d (nr=%u): \n", i, td->o.zone_split_nr[i]);
+
+               for (j = 0; j < td->o.zone_split_nr[i]; j++) {
+                       struct zone_split *zsp = &td->o.zone_split[i][j];
+
+                       dprint(FD_PARSE, "\t%d: %u/%u\n", j, zsp->access_perc,
+                                                               zsp->size_perc);
+               }
+       }
+
+       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 {
+               for (i = 0; i < DDIR_RWDIR_CNT; i++)
+                       td->o.zone_split_nr[i] = 0;
+       }
+
+       return ret;
+}
+
 static int str_random_distribution_cb(void *data, const char *str)
 {
        struct thread_data *td = data;
        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)
                val = FIO_DEF_PARETO;
        else if (td->o.random_distribution == FIO_RAND_DIST_GAUSS)
                val = 0.0;
+       else if (td->o.random_distribution == FIO_RAND_DIST_ZONED)
+               return parse_zoned_distribution(td, str);
        else
                return 0;
 
@@ -738,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");
+               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;
        }
 
@@ -821,7 +1124,8 @@ static int get_max_name_idx(char *input)
  * Returns the directory at the index, indexes > entires will be
  * assigned via modulo division of the index
  */
-int set_name_idx(char *target, size_t tlen, char *input, int index)
+int set_name_idx(char *target, size_t tlen, char *input, int index,
+                bool unique_filename)
 {
        unsigned int cur_idx;
        int len;
@@ -833,7 +1137,7 @@ int set_name_idx(char *target, size_t tlen, char *input, int index)
        for (cur_idx = 0; cur_idx <= index; cur_idx++)
                fname = get_next_name(&str);
 
-       if (client_sockaddr_str[0]) {
+       if (client_sockaddr_str[0] && unique_filename) {
                len = snprintf(target, tlen, "%s/%s.", fname,
                                client_sockaddr_str);
        } else
@@ -954,20 +1258,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;
 
@@ -1094,6 +1391,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
        },
        {
                .name   = "filename_format",
+               .lname  = "Filename Format",
                .type   = FIO_OPT_STR_STORE,
                .off1   = td_var_offset(filename_format),
                .prio   = -1, /* must come after "directory" */
@@ -1102,6 +1400,16 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_FILE,
                .group  = FIO_OPT_G_FILENAME,
        },
+       {
+               .name   = "unique_filename",
+               .lname  = "Unique Filename",
+               .type   = FIO_OPT_BOOL,
+               .off1   = td_var_offset(unique_filename),
+               .help   = "For network clients, prefix file with source IP",
+               .def    = "1",
+               .category = FIO_OPT_C_FILE,
+               .group  = FIO_OPT_G_FILENAME,
+       },
        {
                .name   = "lockfile",
                .lname  = "Lockfile",
@@ -1240,6 +1548,11 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                            .help = "Use preadv/pwritev",
                          },
 #endif
+#ifdef CONFIG_PWRITEV2
+                         { .ival = "pvsync2",
+                           .help = "Use preadv2/pwritev2",
+                         },
+#endif
 #ifdef CONFIG_LIBAIO
                          { .ival = "libaio",
                            .help = "Linux native asynchronous IO",
@@ -1332,6 +1645,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)",
@@ -1658,6 +1977,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
        },
        {
                .name   = "random_generator",
+               .lname  = "Random Generator",
                .type   = FIO_OPT_STR,
                .off1   = td_var_offset(random_generator),
                .help   = "Type of random number generator to use",
@@ -1682,6 +2002,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
        },
        {
                .name   = "random_distribution",
+               .lname  = "Random Distribution",
                .type   = FIO_OPT_STR,
                .off1   = td_var_offset(random_distribution),
                .cb     = str_random_distribution_cb,
@@ -1704,6 +2025,11 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                            .oval = FIO_RAND_DIST_GAUSS,
                            .help = "Normal (gaussian) distribution",
                          },
+                         { .ival = "zoned",
+                           .oval = FIO_RAND_DIST_ZONED,
+                           .help = "Zoned random distribution",
+                         },
+
                },
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_RANDOM,
@@ -1732,6 +2058,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
        },
        {
                .name   = "allrandrepeat",
+               .lname  = "All Random Repeat",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(allrand_repeatable),
                .help   = "Use repeatable random numbers for everything",
@@ -1773,7 +2100,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,
@@ -2219,6 +2558,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
        },
        {
                .name   = "verifysort_nr",
+               .lname  = "Verify Sort Nr",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(verifysort_nr),
                .help   = "Pre-load and sort verify blocks for a read workload",
@@ -2340,6 +2680,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
 #endif
        {
                .name   = "experimental_verify",
+               .lname  = "Experimental Verify",
                .off1   = td_var_offset(experimental_verify),
                .type   = FIO_OPT_BOOL,
                .help   = "Enable experimental verification",
@@ -2754,6 +3095,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
        },
        {
                .name   = "max_latency",
+               .lname  = "Max Latency",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(max_latency),
                .help   = "Maximum tolerated IO latency (usec)",
@@ -2848,6 +3190,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
        },
        {
                .name   = "create_only",
+               .lname  = "Create Only",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(create_only),
                .help   = "Only perform file creation phase",
@@ -2930,6 +3273,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
 #ifdef CONFIG_LIBNUMA
        {
                .name   = "numa_cpu_nodes",
+               .lname  = "NUMA CPU Nodes",
                .type   = FIO_OPT_STR,
                .cb     = str_numa_cpunodes_cb,
                .off1   = td_var_offset(numa_cpunodes),
@@ -2939,6 +3283,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
        },
        {
                .name   = "numa_mem_policy",
+               .lname  = "NUMA Memory Policy",
                .type   = FIO_OPT_STR,
                .cb     = str_numa_mpol_cb,
                .off1   = td_var_offset(numa_memnodes),
@@ -3029,6 +3374,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
        },
        {
                .name   = "per_job_logs",
+               .lname  = "Per Job Logs",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(per_job_logs),
                .help   = "Include job number in generated log files or not",
@@ -3073,6 +3419,16 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_LOG,
                .group  = FIO_OPT_G_INVALID,
        },
+       {
+               .name   = "log_max_value",
+               .lname  = "Log maximum instead of average",
+               .type   = FIO_OPT_BOOL,
+               .off1   = td_var_offset(log_max),
+               .help   = "Log max sample in a window instead of average",
+               .def    = "0",
+               .category = FIO_OPT_C_LOG,
+               .group  = FIO_OPT_G_INVALID,
+       },
        {
                .name   = "log_offset",
                .lname  = "Log offset of IO",
@@ -3349,6 +3705,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
        },
        {
                .name   = "unified_rw_reporting",
+               .lname  = "Unified RW Reporting",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(unified_rw_rep),
                .help   = "Unify reporting across data direction",
@@ -3402,6 +3759,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
        },
        {
                .name   = "ignore_error",
+               .lname  = "Ignore Error",
                .type   = FIO_OPT_STR,
                .cb     = str_ignore_error_cb,
                .off1   = td_var_offset(ignore_error_nr),
@@ -3412,6 +3770,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
        },
        {
                .name   = "error_dump",
+               .lname  = "Error Dump",
                .type   = FIO_OPT_BOOL,
                .off1   = td_var_offset(error_dump),
                .def    = "0",