options: add support for checking if an option has been set
authorJens Axboe <axboe@fb.com>
Tue, 9 Dec 2014 19:58:15 +0000 (12:58 -0700)
committerJens Axboe <axboe@fb.com>
Tue, 9 Dec 2014 19:58:15 +0000 (12:58 -0700)
We often just do a non-zero check, but an option can be set
and be set to zero, so we can't currently detect that. For
complicated options, we add a second variable to mark if it
has been set or not. This allows us to directly check if a
given option was set by the user or not.

Signed-off-by: Jens Axboe <axboe@fb.com>
cconv.c
options.c
options.h
parse.c
thread_options.h

diff --git a/cconv.c b/cconv.c
index d0a124e..a4d5003 100644 (file)
--- a/cconv.c
+++ b/cconv.c
@@ -49,6 +49,7 @@ void convert_thread_options_to_cpu(struct thread_options *o,
 {
        int i, j;
 
+       memcpy(o->set_options, top->set_options, NR_OPTS_SZ * sizeof(uint64_t));
        string_to_cpu(&o->description, top->description);
        string_to_cpu(&o->name, top->name);
        string_to_cpu(&o->directory, top->directory);
@@ -258,6 +259,7 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
 {
        int i, j;
 
+       memcpy(top->set_options, o->set_options, NR_OPTS_SZ * sizeof(uint64_t));
        string_to_net(top->description, o->description);
        string_to_net(top->name, o->name);
        string_to_net(top->directory, o->directory);
index 2c703fd..ac561bc 100644 (file)
--- a/options.c
+++ b/options.c
@@ -1650,6 +1650,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "Size",
                .type   = FIO_OPT_STR_VAL,
                .cb     = str_size_cb,
+               .off1   = td_var_offset(size),
                .help   = "Total size of device or files",
                .interval = 1024 * 1024,
                .category = FIO_OPT_C_IO,
@@ -1789,6 +1790,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "Block size split",
                .type   = FIO_OPT_STR,
                .cb     = str_bssplit_cb,
+               .off1   = td_var_offset(bssplit),
                .help   = "Set a specific mix of block sizes",
                .parent = "rw",
                .hide   = 1,
@@ -2443,6 +2445,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "Verify pattern",
                .type   = FIO_OPT_STR,
                .cb     = str_verify_pattern_cb,
+               .off1   = td_var_offset(verify_pattern),
                .help   = "Fill pattern for IO buffers",
                .parent = "verify",
                .hide   = 1,
@@ -2513,6 +2516,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "Async verify CPUs",
                .type   = FIO_OPT_STR,
                .cb     = str_verify_cpus_allowed_cb,
+               .off1   = td_var_offset(verify_cpumask),
                .help   = "Set CPUs allowed for async verify threads",
                .parent = "verify_async",
                .hide   = 1,
@@ -2722,6 +2726,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "Read/write mix read",
                .type   = FIO_OPT_INT,
                .cb     = str_rwmix_read_cb,
+               .off1   = td_var_offset(rwmix[DDIR_READ]),
                .maxval = 100,
                .help   = "Percentage of mixed workload that is reads",
                .def    = "50",
@@ -2735,6 +2740,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "Read/write mix write",
                .type   = FIO_OPT_INT,
                .cb     = str_rwmix_write_cb,
+               .off1   = td_var_offset(rwmix[DDIR_WRITE]),
                .maxval = 100,
                .help   = "Percentage of mixed workload that is writes",
                .def    = "50",
@@ -3004,6 +3010,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "CPU mask",
                .type   = FIO_OPT_INT,
                .cb     = str_cpumask_cb,
+               .off1   = td_var_offset(cpumask),
                .help   = "CPU affinity mask",
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_CRED,
@@ -3013,6 +3020,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "CPUs allowed",
                .type   = FIO_OPT_STR,
                .cb     = str_cpus_allowed_cb,
+               .off1   = td_var_offset(cpumask),
                .help   = "Set CPUs allowed",
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_CRED,
@@ -3266,6 +3274,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "Buffer pattern",
                .type   = FIO_OPT_STR,
                .cb     = str_buffer_pattern_cb,
+               .off1   = td_var_offset(buffer_pattern),
                .help   = "Fill pattern for IO buffers",
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_IO_BUF,
@@ -3275,6 +3284,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "Buffer compression percentage",
                .type   = FIO_OPT_INT,
                .cb     = str_buffer_compress_cb,
+               .off1   = td_var_offset(compress_percentage),
                .maxval = 100,
                .minval = 0,
                .help   = "How compressible the buffer is (approximately)",
@@ -3299,6 +3309,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "Dedupe percentage",
                .type   = FIO_OPT_INT,
                .cb     = str_dedupe_cb,
+               .off1   = td_var_offset(dedupe_percentage),
                .maxval = 100,
                .minval = 0,
                .help   = "Percentage of buffers that are dedupable",
@@ -3469,6 +3480,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .name   = "ignore_error",
                .type   = FIO_OPT_STR,
                .cb     = str_ignore_error_cb,
+               .off1   = td_var_offset(ignore_error_nr),
                .help   = "Set a specific list of errors to ignore",
                .parent = "rw",
                .category = FIO_OPT_C_GENERAL,
@@ -3980,6 +3992,9 @@ int fio_options_parse(struct thread_data *td, char **opts, int num_opts,
                int newret = parse_option(opts_copy[i], opts[i], fio_options,
                                                &o, td, dump_cmdline);
 
+               if (!newret && o)
+                       fio_option_mark_set(&td->o, o);
+
                if (opts_copy[i]) {
                        if (newret && !o) {
                                unknown++;
@@ -4026,7 +4041,18 @@ int fio_options_parse(struct thread_data *td, char **opts, int num_opts,
 
 int fio_cmd_option_parse(struct thread_data *td, const char *opt, char *val)
 {
-       return parse_cmd_option(opt, val, fio_options, td);
+       int ret;
+
+       ret = parse_cmd_option(opt, val, fio_options, td);
+       if (!ret) {
+               struct fio_option *o;
+
+               o = find_option(fio_options, opt);
+               if (o)
+                       fio_option_mark_set(&td->o, o);
+       }
+
+       return ret;
 }
 
 int fio_cmd_ioengine_option_parse(struct thread_data *td, const char *opt,
@@ -4188,3 +4214,36 @@ struct fio_option *fio_option_find(const char *name)
        return find_option(fio_options, name);
 }
 
+int __fio_option_is_set(struct thread_options *o, unsigned int off1)
+{
+       unsigned int opt_off, index, offset;
+       struct fio_option *opt = NULL;
+       int i;
+
+       for (i = 0; fio_options[i].name; i++) {
+               if (off1 == fio_options[i].off1) {
+                       opt = &fio_options[i];
+                       break;
+               }
+       }
+
+       if (!opt) {
+               log_err("fio: no option found at offset %u\n", off1);
+               return 0;
+       }
+
+       opt_off = opt - &fio_options[0];
+       index = opt_off / (8 * sizeof(uint64_t));
+       offset = opt_off & ((8 * sizeof(uint64_t)) - 1);
+       return (o->set_options[index] & (1UL << offset)) != 0;
+}
+
+void fio_option_mark_set(struct thread_options *o, struct fio_option *opt)
+{
+       unsigned int opt_off, index, offset;
+
+       opt_off = opt - &fio_options[0];
+       index = opt_off / (8 * sizeof(uint64_t));
+       offset = opt_off & ((8 * sizeof(uint64_t)) - 1);
+       o->set_options[index] |= 1UL << offset;
+}
index b2e2c0c..fa015c3 100644 (file)
--- a/options.h
+++ b/options.h
@@ -22,6 +22,13 @@ int set_name_idx(char *, char *, int);
 
 extern struct fio_option fio_options[FIO_MAX_OPTS];
 
+extern int __fio_option_is_set(struct thread_options *, unsigned int off);
+
+#define fio_option_is_set(__td, name)  \
+       __fio_option_is_set((__td), td_var_offset(name))
+
+extern void fio_option_mark_set(struct thread_options *, struct fio_option *);
+
 static inline int o_match(struct fio_option *o, const char *opt)
 {
        if (!strcmp(o->name, opt))
diff --git a/parse.c b/parse.c
index 141f4b2..ae87b1e 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -1279,8 +1279,6 @@ void option_init(struct fio_option *o)
        if (o->type == FIO_OPT_STR || o->type == FIO_OPT_STR_STORE ||
            o->type == FIO_OPT_STR_MULTI)
                return;
-       if (o->cb && (o->off1 || o->off2 || o->off3 || o->off4))
-               log_err("Option %s: both cb and offset given\n", o->name);
 }
 
 /*
index f311e2c..f0c6325 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "arch/arch.h"
 #include "os/os.h"
+#include "options.h"
 #include "stat.h"
 #include "gettime.h"
 #include "lib/ieee754.h"
@@ -28,10 +29,13 @@ struct bssplit {
        uint32_t perc;
 };
 
+#define NR_OPTS_SZ     (FIO_MAX_OPTS / (8 * sizeof(uint64_t)))
+
 #define OPT_MAGIC      0x4f50544e
 
 struct thread_options {
        int magic;
+       uint64_t set_options[NR_OPTS_SZ];
        char *description;
        char *name;
        char *directory;
@@ -265,6 +269,7 @@ struct thread_options {
 #define FIO_TOP_STR_MAX                256
 
 struct thread_options_pack {
+       uint64_t set_options[NR_OPTS_SZ];
        uint8_t description[FIO_TOP_STR_MAX];
        uint8_t name[FIO_TOP_STR_MAX];
        uint8_t directory[FIO_TOP_STR_MAX];