Merge branch 'enable-dataplacement-scheme' of https://github.com/parkvibes/fio
[fio.git] / options.c
index 536ba91c3429d3e4df4e614afeb40bcb0e9e3045..f5d221c776317fe50e2e0229a8e9564d244b8db4 100644 (file)
--- a/options.c
+++ b/options.c
@@ -4,6 +4,7 @@
 #include <ctype.h>
 #include <string.h>
 #include <assert.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <netinet/in.h>
 
@@ -251,6 +252,78 @@ int str_split_parse(struct thread_data *td, char *str,
        return ret;
 }
 
+static int fio_fdp_cmp(const void *p1, const void *p2)
+{
+       const uint16_t *t1 = p1;
+       const uint16_t *t2 = p2;
+
+       return *t1 - *t2;
+}
+
+static int str_fdp_pli_cb(void *data, const char *input)
+{
+       struct thread_data *td = cb_data_to_td(data);
+       char *str, *p, *v;
+       int i = 0;
+
+       p = str = strdup(input);
+       strip_blank_front(&str);
+       strip_blank_end(str);
+
+       while ((v = strsep(&str, ",")) != NULL && i < FIO_MAX_DP_IDS) {
+               unsigned long long id = strtoull(v, NULL, 0);
+               if (id > 0xFFFF) {
+                       log_err("Placement IDs cannot exceed 0xFFFF\n");
+                       free(p);
+                       return 1;
+               }
+               td->o.dp_ids[i++] = id;
+       }
+       free(p);
+
+       qsort(td->o.dp_ids, i, sizeof(*td->o.dp_ids), fio_fdp_cmp);
+       td->o.dp_nr_ids = i;
+
+       return 0;
+}
+
+/* str_dp_scheme_cb() is a callback function for parsing the fdp_scheme option
+       This function validates the fdp_scheme filename. */
+static int str_dp_scheme_cb(void *data, const char *input)
+{
+       struct thread_data *td = cb_data_to_td(data);
+       struct stat sb;
+       char *filename;
+       int ret = 0;
+
+       if (parse_dryrun())
+               return 0;
+
+       filename = strdup(td->o.dp_scheme_file);
+       strip_blank_front(&filename);
+       strip_blank_end(filename);
+
+       strcpy(td->o.dp_scheme_file, filename);
+
+       if (lstat(filename, &sb) < 0){
+               ret = errno;
+               log_err("fio: lstat() error related to %s\n", filename);
+               td_verror(td, ret, "lstat");
+               goto out;
+       }
+
+       if (!S_ISREG(sb.st_mode)) {
+               ret = errno;
+               log_err("fio: %s is not a file\n", filename);
+               td_verror(td, ret, "S_ISREG");
+               goto out;
+       }
+
+out:
+       free(filename);
+       return ret;
+}
+
 static int str_bssplit_cb(void *data, const char *input)
 {
        struct thread_data *td = cb_data_to_td(data);
@@ -284,15 +357,17 @@ static int parse_cmdprio_bssplit_entry(struct thread_options *o,
        int matches = 0;
        char *bs_str = NULL;
        long long bs_val;
-       unsigned int perc = 0, class, level;
+       unsigned int perc = 0, class, level, hint;
 
        /*
         * valid entry formats:
         * bs/ - %s/ - set perc to 0, prio to -1.
         * bs/perc - %s/%u - set prio to -1.
         * bs/perc/class/level - %s/%u/%u/%u
+        * bs/perc/class/level/hint - %s/%u/%u/%u/%u
         */
-       matches = sscanf(str, "%m[^/]/%u/%u/%u", &bs_str, &perc, &class, &level);
+       matches = sscanf(str, "%m[^/]/%u/%u/%u/%u",
+                        &bs_str, &perc, &class, &level, &hint);
        if (matches < 1) {
                log_err("fio: invalid cmdprio_bssplit format\n");
                return 1;
@@ -313,9 +388,14 @@ static int parse_cmdprio_bssplit_entry(struct thread_options *o,
        case 2: /* bs/perc case */
                break;
        case 4: /* bs/perc/class/level case */
+       case 5: /* bs/perc/class/level/hint case */
                class = min(class, (unsigned int) IOPRIO_MAX_PRIO_CLASS);
                level = min(level, (unsigned int) IOPRIO_MAX_PRIO);
-               entry->prio = ioprio_value(class, level);
+               if (matches == 5)
+                       hint = min(hint, (unsigned int) IOPRIO_MAX_PRIO_HINT);
+               else
+                       hint = 0;
+               entry->prio = ioprio_value(class, level, hint);
                break;
        default:
                log_err("fio: invalid cmdprio_bssplit format\n");
@@ -560,9 +640,21 @@ static int str_rw_cb(void *data, const char *str)
        if (!nr)
                return 0;
 
-       if (td_random(td))
-               o->ddir_seq_nr = atoi(nr);
-       else {
+       if (td_random(td)) {
+               long long val;
+
+               if (str_to_decimal(nr, &val, 1, o, 0, 0)) {
+                       log_err("fio: randrw postfix parsing failed\n");
+                       free(nr);
+                       return 1;
+               }
+               if ((val <= 0) || (val > UINT_MAX)) {
+                       log_err("fio: randrw postfix parsing out of range\n");
+                       free(nr);
+                       return 1;
+               }
+               o->ddir_seq_nr = (unsigned int) val;
+       } else {
                long long val;
 
                if (str_to_decimal(nr, &val, 1, o, 0, 0)) {
@@ -599,7 +691,7 @@ static int fio_clock_source_cb(void *data, const char *str)
        return 0;
 }
 
-static int str_rwmix_read_cb(void *data, unsigned long long *val)
+static int str_rwmix_read_cb(void *data, long long *val)
 {
        struct thread_data *td = cb_data_to_td(data);
 
@@ -608,7 +700,7 @@ static int str_rwmix_read_cb(void *data, unsigned long long *val)
        return 0;
 }
 
-static int str_rwmix_write_cb(void *data, unsigned long long *val)
+static int str_rwmix_write_cb(void *data, long long *val)
 {
        struct thread_data *td = cb_data_to_td(data);
 
@@ -1577,7 +1669,7 @@ static int str_gtod_reduce_cb(void *data, int *il)
        return 0;
 }
 
-static int str_offset_cb(void *data, unsigned long long *__val)
+static int str_offset_cb(void *data, long long *__val)
 {
        struct thread_data *td = cb_data_to_td(data);
        unsigned long long v = *__val;
@@ -1598,7 +1690,7 @@ static int str_offset_cb(void *data, unsigned long long *__val)
        return 0;
 }
 
-static int str_offset_increment_cb(void *data, unsigned long long *__val)
+static int str_offset_increment_cb(void *data, long long *__val)
 {
        struct thread_data *td = cb_data_to_td(data);
        unsigned long long v = *__val;
@@ -1619,7 +1711,7 @@ static int str_offset_increment_cb(void *data, unsigned long long *__val)
        return 0;
 }
 
-static int str_size_cb(void *data, unsigned long long *__val)
+static int str_size_cb(void *data, long long *__val)
 {
        struct thread_data *td = cb_data_to_td(data);
        unsigned long long v = *__val;
@@ -1663,7 +1755,7 @@ static int str_io_size_cb(void *data, unsigned long long *__val)
        return 0;
 }
 
-static int str_zoneskip_cb(void *data, unsigned long long *__val)
+static int str_zoneskip_cb(void *data, long long *__val)
 {
        struct thread_data *td = cb_data_to_td(data);
        unsigned long long v = *__val;
@@ -2347,6 +2439,17 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_INVALID,
        },
+       {
+               .name   = "num_range",
+               .lname  = "Number of ranges",
+               .type   = FIO_OPT_INT,
+               .off1   = offsetof(struct thread_options, num_range),
+               .maxval = MAX_TRIM_RANGE,
+               .help   = "Number of ranges for trim command",
+               .def    = "1",
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_INVALID,
+       },
        {
                .name   = "bs",
                .lname  = "Block size",
@@ -2436,6 +2539,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
        },
        {
                .name   = "randrepeat",
+               .alias  = "allrandrepeat",
                .lname  = "Random repeatable",
                .type   = FIO_OPT_BOOL,
                .off1   = offsetof(struct thread_options, rand_repeatable),
@@ -2565,16 +2669,6 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_RANDOM,
        },
-       {
-               .name   = "allrandrepeat",
-               .lname  = "All Random Repeat",
-               .type   = FIO_OPT_BOOL,
-               .off1   = offsetof(struct thread_options, allrand_repeatable),
-               .help   = "Use repeatable random numbers for everything",
-               .def    = "0",
-               .category = FIO_OPT_C_IO,
-               .group  = FIO_OPT_G_RANDOM,
-       },
        {
                .name   = "nrfiles",
                .lname  = "Number of files",
@@ -2712,6 +2806,12 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                            .oval = F_ADV_SEQUENTIAL,
                            .help = "Advise using FADV_SEQUENTIAL",
                          },
+#ifdef POSIX_FADV_NOREUSE
+                         { .ival = "noreuse",
+                           .oval = F_ADV_NOREUSE,
+                           .help = "Advise using FADV_NOREUSE",
+                         },
+#endif
                },
                .help   = "Use fadvise() to advise the kernel on IO pattern",
                .def    = "1",
@@ -3592,7 +3692,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "Per device/file maximum number of open zones",
                .type   = FIO_OPT_INT,
                .off1   = offsetof(struct thread_options, max_open_zones),
-               .maxval = ZBD_MAX_OPEN_ZONES,
+               .maxval = ZBD_MAX_WRITE_ZONES,
                .help   = "Limit on the number of simultaneously opened sequential write zones with zonemode=zbd",
                .def    = "0",
                .category = FIO_OPT_C_IO,
@@ -3603,7 +3703,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "Job maximum number of open zones",
                .type   = FIO_OPT_INT,
                .off1   = offsetof(struct thread_options, job_max_open_zones),
-               .maxval = ZBD_MAX_OPEN_ZONES,
+               .maxval = ZBD_MAX_WRITE_ZONES,
                .help   = "Limit on the number of simultaneously opened sequential write zones with zonemode=zbd by one thread/process",
                .def    = "0",
                .category = FIO_OPT_C_IO,
@@ -3643,6 +3743,89 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_ZONE,
        },
+       {
+               .name   = "fdp",
+               .lname  = "Flexible data placement",
+               .type   = FIO_OPT_BOOL,
+               .off1   = offsetof(struct thread_options, fdp),
+               .help   = "Use Data placement directive (FDP)",
+               .def    = "0",
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_INVALID,
+       },
+       {
+               .name   = "dataplacement",
+               .alias  = "data_placement",
+               .lname  = "Data Placement interface",
+               .type   = FIO_OPT_STR,
+               .off1   = offsetof(struct thread_options, dp_type),
+               .help   = "Data Placement interface to use",
+               .def    = "none",
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_INVALID,
+               .posval = {
+                         { .ival = "none",
+                           .oval = FIO_DP_NONE,
+                           .help = "Do not specify a data placement interface",
+                         },
+                         { .ival = "fdp",
+                           .oval = FIO_DP_FDP,
+                           .help = "Use Flexible Data Placement interface",
+                         },
+                         { .ival = "streams",
+                           .oval = FIO_DP_STREAMS,
+                           .help = "Use Streams interface",
+                         },
+               },
+       },
+       {
+               .name   = "plid_select",
+               .alias  = "fdp_pli_select",
+               .lname  = "Data Placement ID selection strategy",
+               .type   = FIO_OPT_STR,
+               .off1   = offsetof(struct thread_options, dp_id_select),
+               .help   = "Strategy for selecting next Data Placement ID",
+               .def    = "roundrobin",
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_INVALID,
+               .posval = {
+                         { .ival = "random",
+                           .oval = FIO_DP_RANDOM,
+                           .help = "Choose a Placement ID at random (uniform)",
+                         },
+                         { .ival = "roundrobin",
+                           .oval = FIO_DP_RR,
+                           .help = "Round robin select Placement IDs",
+                         },
+                         { .ival = "scheme",
+                           .oval = FIO_DP_SCHEME,
+                           .help = "Use a scheme(based on LBA) to select Placement IDs",
+                         },
+               },
+       },
+       {
+               .name   = "plids",
+               .alias  = "fdp_pli",
+               .lname  = "Stream IDs/Data Placement ID indices",
+               .type   = FIO_OPT_STR,
+               .cb     = str_fdp_pli_cb,
+               .off1   = offsetof(struct thread_options, dp_ids),
+               .help   = "Sets which Data Placement ids to use (defaults to all for FDP)",
+               .hide   = 1,
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_INVALID,
+       },
+       {
+               .name   = "dp_scheme",
+               .lname  = "Data Placement Scheme",
+               .type   = FIO_OPT_STR_STORE,
+               .cb     = str_dp_scheme_cb,
+               .off1   = offsetof(struct thread_options, dp_scheme_file),
+               .maxlen = PATH_MAX,
+               .help   = "scheme file that specifies offset-RUH mapping",
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_INVALID,
+       },
        {
                .name   = "lockmem",
                .lname  = "Lock memory",
@@ -3739,6 +3922,18 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_CRED,
        },
+       {
+               .name   = "priohint",
+               .lname  = "I/O nice priority hint",
+               .type   = FIO_OPT_INT,
+               .off1   = offsetof(struct thread_options, ioprio_hint),
+               .help   = "Set job IO priority hint",
+               .minval = IOPRIO_MIN_PRIO_HINT,
+               .maxval = IOPRIO_MAX_PRIO_HINT,
+               .interval = 1,
+               .category = FIO_OPT_C_GENERAL,
+               .group  = FIO_OPT_G_CRED,
+       },
 #else
        {
                .name   = "prioclass",
@@ -3746,6 +3941,12 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .type   = FIO_OPT_UNSUPPORTED,
                .help   = "Your platform does not support IO priority classes",
        },
+       {
+               .name   = "priohint",
+               .lname  = "I/O nice priority hint",
+               .type   = FIO_OPT_UNSUPPORTED,
+               .help   = "Your platform does not support IO priority hints",
+       },
 #endif
        {
                .name   = "thinktime",
@@ -3771,6 +3972,18 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_THINKTIME,
        },
+       {
+               .name   = "thinkcycles",
+               .lname  = "Think cycles",
+               .type   = FIO_OPT_INT,
+               .off1   = offsetof(struct thread_options, thinkcycles),
+               .help   = "Spin for a constant amount of cycles between requests",
+               .def    = "0",
+               .parent = "thinktime",
+               .hide   = 1,
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_THINKTIME,
+       },
        {
                .name   = "thinktime_blocks",
                .lname  = "Thinktime blocks",
@@ -4424,14 +4637,38 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .group  = FIO_OPT_G_INVALID,
        },
        {
-               .name   = "log_max_value",
-               .lname  = "Log maximum instead of average",
-               .type   = FIO_OPT_BOOL,
+               .name   = "log_window_value",
+               .alias  = "log_max_value",
+               .lname  = "Log maximum, average or both values",
+               .type   = FIO_OPT_STR,
                .off1   = offsetof(struct thread_options, log_max),
-               .help   = "Log max sample in a window instead of average",
-               .def    = "0",
+               .help   = "Log max, average or both sample in a window",
+               .def    = "avg",
                .category = FIO_OPT_C_LOG,
                .group  = FIO_OPT_G_INVALID,
+               .posval = {
+                         { .ival = "avg",
+                           .oval = IO_LOG_SAMPLE_AVG,
+                           .help = "Log average value over the window",
+                         },
+                         { .ival = "max",
+                           .oval = IO_LOG_SAMPLE_MAX,
+                           .help = "Log maximum value in the window",
+                         },
+                         { .ival = "both",
+                           .oval = IO_LOG_SAMPLE_BOTH,
+                           .help = "Log both average and maximum values over the window"
+                         },
+                         /* Compatibility with former boolean values */
+                         { .ival = "0",
+                           .oval = IO_LOG_SAMPLE_AVG,
+                           .help = "Alias for 'avg'",
+                         },
+                         { .ival = "1",
+                           .oval = IO_LOG_SAMPLE_MAX,
+                           .help = "Alias for 'max'",
+                         },
+               },
        },
        {
                .name   = "log_offset",
@@ -4508,17 +4745,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .help   = "Install libz-dev(el) to get compression support",
        },
 #endif
-       {
-               .name = "log_unix_epoch",
-               .lname = "Log epoch unix",
-               .type = FIO_OPT_BOOL,
-               .off1 = offsetof(struct thread_options, log_unix_epoch),
-               .help = "Use Unix time in log files",
-               .category = FIO_OPT_C_LOG,
-               .group = FIO_OPT_G_INVALID,
-       },
        {
                .name = "log_alternate_epoch",
+               .alias = "log_unix_epoch",
                .lname = "Log epoch alternate",
                .type = FIO_OPT_BOOL,
                .off1 = offsetof(struct thread_options, log_alternate_epoch),
@@ -4531,7 +4760,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname = "Log alternate epoch clock_id",
                .type = FIO_OPT_INT,
                .off1 = offsetof(struct thread_options, log_alternate_epoch_clock_id),
-               .help = "If log_alternate_epoch or log_unix_epoch is true, this option specifies the clock_id from clock_gettime whose epoch should be used. If neither of those is true, this option has no effect. Default value is 0, or CLOCK_REALTIME",
+               .help = "If log_alternate_epoch is true, this option specifies the clock_id from clock_gettime whose epoch should be used. If log_alternate_epoch is false, this option has no effect. Default value is 0, or CLOCK_REALTIME",
                .category = FIO_OPT_C_LOG,
                .group = FIO_OPT_G_INVALID,
        },
@@ -4860,6 +5089,16 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_CLOCK,
        },
+       {
+               .name   = "job_start_clock_id",
+               .lname  = "Job start clock_id",
+               .type   = FIO_OPT_INT,
+               .off1   = offsetof(struct thread_options, job_start_clock_id),
+               .help   = "The clock_id passed to the call to clock_gettime used to record job_start in the json output format. Default is 0, or CLOCK_REALTIME",
+               .verify = gtod_cpu_verify,
+               .category = FIO_OPT_C_GENERAL,
+               .group  = FIO_OPT_G_CLOCK,
+       },
        {
                .name   = "unified_rw_reporting",
                .lname  = "Unified RW Reporting",
@@ -5179,6 +5418,20 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_RUNTIME,
        },
+        {
+               .name   = "steadystate_check_interval",
+               .lname  = "Steady state check interval",
+               .alias  = "ss_interval",
+               .parent = "steadystate",
+               .type   = FIO_OPT_STR_VAL_TIME,
+               .off1   = offsetof(struct thread_options, ss_check_interval),
+               .help   = "Polling interval for the steady state check (too low means steadystate will not converge)",
+               .def    = "1",
+               .is_seconds = 1,
+               .is_time = 1,
+               .category = FIO_OPT_C_GENERAL,
+               .group  = FIO_OPT_G_RUNTIME,
+       },
        {
                .name = NULL,
        },