{
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;
}
struct thread_data *td = data;
fio_clock_source = td->o.clocksource;
- fio_time_init();
+ fio_clock_source_set = 1;
+ fio_clock_init();
return 0;
}
}
#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)
{
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;
}
#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
{ .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",
},
{ .ival = "mmap",
.help = "Memory mapped IO"
},
-#ifdef FIO_HAVE_SPLICE
+#ifdef CONFIG_LINUX_SPLICE
{ .ival = "splice",
.help = "splice/vmsplice based IO",
},
{ .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",
},
.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",
},
.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",
.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 = {
.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,
.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,
.parent = "verify_async",
},
#endif
+ {
+ .name = "experimental_verify",
+ .off1 = td_var_offset(experimental_verify),
+ .type = FIO_OPT_BOOL,
+ },
#ifdef FIO_HAVE_TRIM
{
.name = "trim_percentage",
.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,
.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",