Convert unit_base to posval[]
[fio.git] / options.c
index 84101d1a3752ce3e3c0f60b9587962edab4562a1..193bdbc12af01c770f559ba08f9089e632c3465e 100644 (file)
--- a/options.c
+++ b/options.c
@@ -342,13 +342,8 @@ static int str_mem_cb(void *data, const char *mem)
 {
        struct thread_data *td = data;
 
-       if (td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAP) {
+       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) {
-                       log_err("fio: mmaphuge:/path/to/file\n");
-                       return 1;
-               }
-       }
 
        return 0;
 }
@@ -370,7 +365,8 @@ static int fio_clock_source_cb(void *data, const char *str)
        struct thread_data *td = data;
 
        fio_clock_source = td->o.clocksource;
-       fio_time_init();
+       fio_clock_source_set = 1;
+       fio_clock_init();
        return 0;
 }
 
@@ -564,6 +560,130 @@ static int str_verify_cpus_allowed_cb(void *data, const char *input)
 }
 #endif
 
+#ifdef CONFIG_LIBNUMA
+static int str_numa_cpunodes_cb(void *data, char *input)
+{
+       struct thread_data *td = data;
+
+       /* numa_parse_nodestring() parses a character string list
+        * of nodes into a bit mask. The bit mask is allocated by
+        * numa_allocate_nodemask(), so it should be freed by
+        * numa_free_nodemask().
+        */
+       td->o.numa_cpunodesmask = numa_parse_nodestring(input);
+       if (td->o.numa_cpunodesmask == NULL) {
+               log_err("fio: numa_parse_nodestring failed\n");
+               td_verror(td, 1, "str_numa_cpunodes_cb");
+               return 1;
+       }
+
+       td->o.numa_cpumask_set = 1;
+       return 0;
+}
+
+static int str_numa_mpol_cb(void *data, char *input)
+{
+       struct thread_data *td = data;
+       const char * const policy_types[] =
+               { "default", "prefer", "bind", "interleave", "local" };
+       int i;
+
+       char *nodelist = strchr(input, ':');
+       if (nodelist) {
+               /* NUL-terminate mode */
+               *nodelist++ = '\0';
+       }
+
+       for (i = 0; i <= MPOL_LOCAL; i++) {
+               if (!strcmp(input, policy_types[i])) {
+                       td->o.numa_mem_mode = i;
+                       break;
+               }
+       }
+       if (i > MPOL_LOCAL) {
+               log_err("fio: memory policy should be: default, prefer, bind, interleave, local\n");
+               goto out;
+       }
+
+       switch (td->o.numa_mem_mode) {
+       case MPOL_PREFERRED:
+               /*
+                * Insist on a nodelist of one node only
+                */
+               if (nodelist) {
+                       char *rest = nodelist;
+                       while (isdigit(*rest))
+                               rest++;
+                       if (*rest) {
+                               log_err("fio: one node only for \'prefer\'\n");
+                               goto out;
+                       }
+               } else {
+                       log_err("fio: one node is needed for \'prefer\'\n");
+                       goto out;
+               }
+               break;
+       case MPOL_INTERLEAVE:
+               /*
+                * Default to online nodes with memory if no nodelist
+                */
+               if (!nodelist)
+                       nodelist = strdup("all");
+               break;
+       case MPOL_LOCAL:
+       case MPOL_DEFAULT:
+               /*
+                * Don't allow a nodelist
+                */
+               if (nodelist) {
+                       log_err("fio: NO nodelist for \'local\'\n");
+                       goto out;
+               }
+               break;
+       case MPOL_BIND:
+               /*
+                * Insist on a nodelist
+                */
+               if (!nodelist) {
+                       log_err("fio: a nodelist is needed for \'bind\'\n");
+                       goto out;
+               }
+               break;
+       }
+
+
+       /* numa_parse_nodestring() parses a character string list
+        * of nodes into a bit mask. The bit mask is allocated by
+        * numa_allocate_nodemask(), so it should be freed by
+        * numa_free_nodemask().
+        */
+       switch (td->o.numa_mem_mode) {
+       case MPOL_PREFERRED:
+               td->o.numa_mem_prefer_node = atoi(nodelist);
+               break;
+       case MPOL_INTERLEAVE:
+       case MPOL_BIND:
+               td->o.numa_memnodesmask = numa_parse_nodestring(nodelist);
+               if (td->o.numa_memnodesmask == NULL) {
+                       log_err("fio: numa_parse_nodestring failed\n");
+                       td_verror(td, 1, "str_numa_memnodes_cb");
+                       return 1;
+               }
+               break;
+       case MPOL_LOCAL:
+       case MPOL_DEFAULT:
+       default:
+               break;
+       }
+
+       td->o.numa_memmask_set = 1;
+       return 0;
+
+out:
+       return 1;
+}
+#endif
+
 #ifdef FIO_HAVE_TRIM
 static int str_verify_trim_cb(void *data, unsigned long long *val)
 {
@@ -588,7 +708,7 @@ static int str_fst_cb(void *data, const char *str)
        return 0;
 }
 
-#ifdef FIO_HAVE_SYNC_FILE_RANGE
+#ifdef CONFIG_SYNC_FILE_RANGE
 static int str_sfr_cb(void *data, const char *str)
 {
        struct thread_data *td = data;
@@ -604,6 +724,45 @@ static int str_sfr_cb(void *data, const char *str)
 }
 #endif
 
+static int str_random_distribution_cb(void *data, const char *str)
+{
+       struct thread_data *td = data;
+       double val;
+       char *nr;
+
+       if (td->o.random_distribution == FIO_RAND_DIST_ZIPF)
+               val = 1.1;
+       else if (td->o.random_distribution == FIO_RAND_DIST_PARETO)
+               val = 0.2;
+       else
+               return 0;
+
+       nr = get_opt_postfix(str);
+       if (nr && !str_to_float(nr, &val)) {
+               log_err("fio: random postfix parsing failed\n");
+               free(nr);
+               return 1;
+       }
+
+       free(nr);
+
+       if (td->o.random_distribution == FIO_RAND_DIST_ZIPF) {
+               if (val == 1.00) {
+                       log_err("fio: zipf theta must different than 1.0\n");
+                       return 1;
+               }
+               td->o.zipf_theta = val;
+       } else {
+               if (val <= 0.00 || val >= 1.00) {
+                       log_err("fio: pareto input out of range (0 < input < 1.0)\n");
+                       return 1;
+               }
+               td->o.pareto_h = val;
+       }
+
+       return 0;
+}
+
 static int check_dir(struct thread_data *td, char *fname)
 {
 #if 0
@@ -827,20 +986,6 @@ static int str_verify_pattern_cb(void *data, const char *input)
        return 0;
 }
 
-static int str_lockfile_cb(void *data, const char *str)
-{
-       struct thread_data *td = data;
-       char *nr = get_opt_postfix(str);
-
-       td->o.lockfile_batch = 1;
-       if (nr) {
-               td->o.lockfile_batch = atoi(nr);
-               free(nr);
-       }
-
-       return 0;
-}
-
 static int str_write_bw_log_cb(void *data, const char *str)
 {
        struct thread_data *td = data;
@@ -942,19 +1087,6 @@ static int gtod_cpu_verify(struct fio_option *o, void *data)
        return 0;
 }
 
-static int kb_base_verify(struct fio_option *o, void *data)
-{
-       struct thread_data *td = data;
-
-       if (td->o.kb_base != 1024 && td->o.kb_base != 1000) {
-               log_err("fio: kb_base set to nonsensical value: %u\n",
-                               td->o.kb_base);
-               return 1;
-       }
-
-       return 0;
-}
-
 /*
  * Map of job/command line options
  */
@@ -986,19 +1118,56 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                .prio   = -1, /* must come after "directory" */
                .help   = "File(s) to use for the workload",
        },
+       {
+               .name   = "filename_format",
+               .type   = FIO_OPT_STR_STORE,
+               .off1   = td_var_offset(filename_format),
+               .prio   = -1, /* must come after "directory" */
+               .help   = "Override default $jobname.$jobnum.$filenum naming",
+               .def    = "$jobname.$jobnum.$filenum",
+       },
        {
                .name   = "kb_base",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(kb_base),
-               .verify = kb_base_verify,
                .prio   = 1,
                .def    = "1024",
+               .posval = {
+                         { .ival = "1024",
+                           .oval = 1024,
+                           .help = "Use 1024 as the K base",
+                         },
+                         { .ival = "1000",
+                           .oval = 1000,
+                           .help = "Use 1000 as the K base",
+                         },
+               },
                .help   = "How many bytes per KB for reporting (1000 or 1024)",
        },
+       {
+               .name   = "unit_base",
+               .type   = FIO_OPT_INT,
+               .off1   = td_var_offset(unit_base),
+               .prio   = 1,
+               .posval = {
+                         { .ival = "0",
+                           .oval = 0,
+                           .help = "Auto-detect",
+                         },
+                         { .ival = "8",
+                           .oval = 8,
+                           .help = "Normal (byte based)",
+                         },
+                         { .ival = "1",
+                           .oval = 1,
+                           .help = "Bit based",
+                         },
+               },
+               .help   = "Bit multiple of result summary data (8 for byte, 1 for bit)",
+       },
        {
                .name   = "lockfile",
                .type   = FIO_OPT_STR,
-               .cb     = str_lockfile_cb,
                .off1   = td_var_offset(file_lock_mode),
                .help   = "Lock file when doing IO to it",
                .parent = "filename",
@@ -1108,22 +1277,22 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                          { .ival = "vsync",
                            .help = "Use readv/writev",
                          },
-#ifdef FIO_HAVE_LIBAIO
+#ifdef CONFIG_LIBAIO
                          { .ival = "libaio",
                            .help = "Linux native asynchronous IO",
                          },
 #endif
-#ifdef FIO_HAVE_POSIXAIO
+#ifdef CONFIG_POSIXAIO
                          { .ival = "posixaio",
                            .help = "POSIX asynchronous IO",
                          },
 #endif
-#ifdef FIO_HAVE_SOLARISAIO
+#ifdef CONFIG_SOLARISAIO
                          { .ival = "solarisaio",
                            .help = "Solaris native asynchronous IO",
                          },
 #endif
-#ifdef FIO_HAVE_WINDOWSAIO
+#ifdef CONFIG_WINDOWSAIO
                          { .ival = "windowsaio",
                            .help = "Windows native asynchronous IO"
                          },
@@ -1131,7 +1300,7 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                          { .ival = "mmap",
                            .help = "Memory mapped IO"
                          },
-#ifdef FIO_HAVE_SPLICE
+#ifdef CONFIG_LINUX_SPLICE
                          { .ival = "splice",
                            .help = "splice/vmsplice based IO",
                          },
@@ -1150,15 +1319,10 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                          { .ival = "net",
                            .help = "Network IO",
                          },
-#ifdef FIO_HAVE_SYSLET
-                         { .ival = "syslet-rw",
-                           .help = "syslet enabled async pread/pwrite IO",
-                         },
-#endif
                          { .ival = "cpuio",
                            .help = "CPU cycle burner engine",
                          },
-#ifdef FIO_HAVE_GUASI
+#ifdef CONFIG_GUASI
                          { .ival = "guasi",
                            .help = "GUASI IO engine",
                          },
@@ -1168,22 +1332,22 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                            .help = "binject direct inject block engine",
                          },
 #endif
-#ifdef FIO_HAVE_RDMA
+#ifdef CONFIG_RDMA
                          { .ival = "rdma",
                            .help = "RDMA IO engine",
                          },
 #endif
-#ifdef FIO_HAVE_FUSION_AW
+#ifdef CONFIG_FUSION_AW
                          { .ival = "fusion-aw-sync",
                            .help = "Fusion-io atomic write engine",
                          },
 #endif
-#ifdef FIO_HAVE_E4_ENG
+#ifdef CONFIG_LINUX_EXT4_MOVE_EXTENT
                          { .ival = "e4defrag",
                            .help = "ext4 defrag engine",
                          },
 #endif
-#ifdef FIO_HAVE_FALLOC_ENG
+#ifdef CONFIG_LINUX_FALLOCATE
                          { .ival = "falloc",
                            .help = "fallocate() file based engine",
                          },
@@ -1348,6 +1512,45 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                .parent = "norandommap",
                .def    = "0",
        },
+       {
+               .name   = "random_generator",
+               .type   = FIO_OPT_STR,
+               .off1   = td_var_offset(random_generator),
+               .help   = "Type of random number generator to use",
+               .def    = "tausworthe",
+               .posval = {
+                         { .ival = "tausworthe",
+                           .oval = FIO_RAND_GEN_TAUSWORTHE,
+                           .help = "Strong Tausworthe generator",
+                         },
+                         { .ival = "lfsr",
+                           .oval = FIO_RAND_GEN_LFSR,
+                           .help = "Variable length LFSR",
+                         },
+               },
+       },
+       {
+               .name   = "random_distribution",
+               .type   = FIO_OPT_STR,
+               .off1   = td_var_offset(random_distribution),
+               .cb     = str_random_distribution_cb,
+               .help   = "Random offset distribution generator",
+               .def    = "random",
+               .posval = {
+                         { .ival = "random",
+                           .oval = FIO_RAND_DIST_RANDOM,
+                           .help = "Completely random",
+                         },
+                         { .ival = "zipf",
+                           .oval = FIO_RAND_DIST_ZIPF,
+                           .help = "Zipf distribution",
+                         },
+                         { .ival = "pareto",
+                           .oval = FIO_RAND_DIST_PARETO,
+                           .help = "Pareto distribution",
+                         },
+               },
+       },
        {
                .name   = "nrfiles",
                .alias  = "nr_files",
@@ -1385,7 +1588,7 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                },
                .parent = "nrfiles",
        },
-#ifdef FIO_HAVE_FALLOCATE
+#ifdef CONFIG_POSIX_FALLOCATE
        {
                .name   = "fallocate",
                .type   = FIO_OPT_STR,
@@ -1401,7 +1604,7 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                            .oval = FIO_FALLOCATE_POSIX,
                            .help = "Use posix_fallocate()",
                          },
-#ifdef FIO_HAVE_LINUX_FALLOCATE
+#ifdef CONFIG_LINUX_FALLOCATE
                          { .ival = "keep",
                            .oval = FIO_FALLOCATE_KEEP_SIZE,
                            .help = "Use fallocate(..., FALLOC_FL_KEEP_SIZE, ...)",
@@ -1418,7 +1621,7 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                          },
                },
        },
-#endif /* FIO_HAVE_FALLOCATE */
+#endif /* CONFIG_POSIX_FALLOCATE */
        {
                .name   = "fadvise_hint",
                .type   = FIO_OPT_BOOL,
@@ -1447,7 +1650,7 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                .help   = "Make every Nth write a barrier write",
                .def    = "0",
        },
-#ifdef FIO_HAVE_SYNC_FILE_RANGE
+#ifdef CONFIG_SYNC_FILE_RANGE
        {
                .name   = "sync_file_range",
                .posval = {
@@ -1544,14 +1747,18 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                .off1   = td_var_offset(clocksource),
                .help   = "What type of timing source to use",
                .posval = {
+#ifdef CONFIG_GETTIMEOFDAY
                          { .ival = "gettimeofday",
                            .oval = CS_GTOD,
                            .help = "Use gettimeofday(2) for timing",
                          },
+#endif
+#ifdef CONFIG_CLOCK_GETTIME
                          { .ival = "clock_gettime",
                            .oval = CS_CGETTIME,
                            .help = "Use clock_gettime(2) for timing",
                          },
+#endif
 #ifdef ARCH_HAVE_CPU_CLOCK
                          { .ival = "cpu",
                            .oval = CS_CPUCLOCK,
@@ -1684,6 +1891,16 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                .def    = "1",
                .parent = "verify",
        },
+       {
+               .name   = "verifysort_nr",
+               .type   = FIO_OPT_INT,
+               .off1   = td_var_offset(verifysort_nr),
+               .help   = "Pre-load and sort verify blocks for a read workload",
+               .minval = 0,
+               .maxval = 131072,
+               .def    = "1024",
+               .parent = "verify",
+       },
        {
                .name   = "verify_interval",
                .type   = FIO_OPT_INT,
@@ -1754,6 +1971,12 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                .parent = "verify_async",
        },
 #endif
+       {
+               .name   = "experimental_verify",
+               .off1   = td_var_offset(experimental_verify),
+               .type   = FIO_OPT_BOOL,
+               .help   = "Enable experimental verification",
+       },
 #ifdef FIO_HAVE_TRIM
        {
                .name   = "trim_percentage",
@@ -1974,6 +2197,12 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                .def    = "1000",
                .parent = "rate",
        },
+       {
+               .name   = "max_latency",
+               .type   = FIO_OPT_INT,
+               .off1   = td_var_offset(max_latency),
+               .help   = "Maximum tolerated IO latency (usec)",
+       },
        {
                .name   = "invalidate",
                .type   = FIO_OPT_BOOL,
@@ -2068,6 +2297,20 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                .cb     = str_cpus_allowed_cb,
                .help   = "Set CPUs allowed",
        },
+#endif
+#ifdef CONFIG_LIBNUMA
+       {
+               .name   = "numa_cpu_nodes",
+               .type   = FIO_OPT_STR,
+               .cb     = str_numa_cpunodes_cb,
+               .help   = "NUMA CPU nodes bind",
+       },
+       {
+               .name   = "numa_mem_policy",
+               .type   = FIO_OPT_STR,
+               .cb     = str_numa_mpol_cb,
+               .help   = "NUMA memory policy setup",
+       },
 #endif
        {
                .name   = "end_fsync",
@@ -2201,8 +2444,9 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                .name   = "percentile_list",
                .type   = FIO_OPT_FLOAT_LIST,
                .off1   = td_var_offset(percentile_list),
-               .off2   = td_var_offset(overwrite_plist),
+               .off2   = td_var_offset(percentile_precision),
                .help   = "Specify a custom list of percentiles to report",
+               .def    = "1:5:10:20:30:40:50:60:70:80:90:95:99:99.5:99.9:99.95:99.99",
                .maxlen = FIO_IO_U_LIST_MAX_LEN,
                .minfp  = 0.0,
                .maxfp  = 100.0,
@@ -2263,6 +2507,13 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                .help   = "Set up dedicated gettimeofday() thread on this CPU",
                .verify = gtod_cpu_verify,
        },
+       {
+               .name   = "unified_rw_reporting",
+               .type   = FIO_OPT_BOOL,
+               .off1   = td_var_offset(unified_rw_rep),
+               .help   = "Unify reporting across data direction",
+               .def    = "0",
+       },
        {
                .name   = "continue_on_error",
                .type   = FIO_OPT_STR,