The following changes since commit 9f81736c7531e002038621577d5ffea571649bd7: Make sure profile options get added to long_options[] (2010-03-04 14:38:10 +0100) are available in the git repository at: git://git.kernel.dk/fio.git master Jens Axboe (6): Cleanup profile support Add profile description Allow holes in the option posval (possible values) Allow the adding of 'posval' for dynamic options like 'profile' Allow profiles to override internal io_u functions Fix parse strlen() bug fio.c | 4 ++ fio.h | 9 ++++- init.c | 8 +++- io_u.c | 20 ++++++++++- options.c | 90 ++++++++++++++++++++++++++++++++++--------------- options.h | 37 ++++++++++++++++---- parse.c | 93 ++++++++++++-------------------------------------- parse.h | 12 ++++--- profile.c | 72 +++++++++++++++++++++++++++++---------- profile.h | 11 +++++- profiles/tiobench.c | 4 ++- 11 files changed, 225 insertions(+), 135 deletions(-) --- Diff of recent changes: diff --git a/fio.c b/fio.c index 778749d..c33f786 100644 --- a/fio.c +++ b/fio.c @@ -40,6 +40,7 @@ #include "verify.h" #include "diskutil.h" #include "cgroup.h" +#include "profile.h" unsigned long page_mask; unsigned long page_size; @@ -1653,6 +1654,9 @@ int main(int argc, char *argv[]) if (parse_options(argc, argv)) return 1; + if (exec_profile && load_profile(exec_profile)) + return 1; + if (!thread_number) return 0; diff --git a/fio.h b/fio.h index 91a28b4..751fc3d 100644 --- a/fio.h +++ b/fio.h @@ -29,6 +29,7 @@ #include "ioengine.h" #include "iolog.h" #include "helpers.h" +#include "options.h" #ifdef FIO_HAVE_GUASI #include <guasi.h> @@ -425,6 +426,12 @@ struct thread_data { */ unsigned int total_err_count; int first_error; + + /* + * Can be overloaded by profiles + */ + int (*fill_io_u_off)(struct thread_data *, struct io_u *); + int (*fill_io_u_size)(struct thread_data *, struct io_u *); }; /* @@ -539,7 +546,7 @@ extern void options_mem_free(struct thread_data *); extern void td_fill_rand_seeds(struct thread_data *); extern void add_job_opts(const char **); #define FIO_GETOPT_JOB 0x89988998 -#define FIO_NR_OPTIONS 512 +#define FIO_NR_OPTIONS (FIO_MAX_OPTS + 128) /* * ETA/status stuff diff --git a/init.c b/init.c index c0ce431..a79bd1a 100644 --- a/init.c +++ b/init.c @@ -39,6 +39,7 @@ unsigned long long mlock_size = 0; FILE *f_out = NULL; FILE *f_err = NULL; char *job_section = NULL; +char *exec_profile = NULL; int write_bw_log = 0; int read_only = 0; @@ -167,6 +168,8 @@ static struct thread_data *get_new_job(int global, struct thread_data *parent) dup_files(td, parent); options_mem_dupe(td); + profile_add_hooks(td); + td->thread_number = thread_number; return td; } @@ -1114,8 +1117,7 @@ static int parse_cmd_line(int argc, char *argv[]) job_section = strdup(optarg); break; case 'p': - if (load_profile(optarg)) - do_exit++; + exec_profile = strdup(optarg); break; case FIO_GETOPT_JOB: { const char *opt = l_opts[lidx].name; @@ -1204,6 +1206,8 @@ int parse_options(int argc, char *argv[]) if (!thread_number) { if (dump_cmdline) return 0; + if (exec_profile) + return 0; log_err("No jobs defined(s)\n\n"); usage(argv[0]); diff --git a/io_u.c b/io_u.c index 1845d3b..278d47a 100644 --- a/io_u.c +++ b/io_u.c @@ -187,7 +187,7 @@ static int get_next_rand_offset(struct thread_data *td, struct fio_file *f, * until we find a free one. For sequential io, just return the end of * the last io issued. */ -static int get_next_offset(struct thread_data *td, struct io_u *io_u) +static int __get_next_offset(struct thread_data *td, struct io_u *io_u) { struct fio_file *f = io_u->file; unsigned long long b; @@ -231,7 +231,15 @@ static int get_next_offset(struct thread_data *td, struct io_u *io_u) return 0; } -static unsigned int get_next_buflen(struct thread_data *td, struct io_u *io_u) +static int get_next_offset(struct thread_data *td, struct io_u *io_u) +{ + if (td->fill_io_u_off) + return td->fill_io_u_off(td, io_u); + + return __get_next_offset(td, io_u); +} + +static unsigned int __get_next_buflen(struct thread_data *td, struct io_u *io_u) { const int ddir = io_u->ddir; unsigned int uninitialized_var(buflen); @@ -276,6 +284,14 @@ static unsigned int get_next_buflen(struct thread_data *td, struct io_u *io_u) return buflen; } +static unsigned int get_next_buflen(struct thread_data *td, struct io_u *io_u) +{ + if (td->fill_io_u_size) + return td->fill_io_u_size(td, io_u); + + return __get_next_buflen(td, io_u); +} + static void set_rwmix_bytes(struct thread_data *td) { unsigned int diff; diff --git a/options.c b/options.c index 6cfd80d..e2daf37 100644 --- a/options.c +++ b/options.c @@ -16,8 +16,6 @@ #include "lib/fls.h" #include "options.h" -static FLIST_HEAD(ext_opt_list); - /* * Check if mmap/mmaphuge has a :/foo/bar/file at the end. If so, return that. */ @@ -736,7 +734,7 @@ static int kb_base_verify(struct fio_option *o, void *data) /* * Map of job/command line options */ -static struct fio_option options[] = { +static struct fio_option options[FIO_MAX_OPTS] = { { .name = "description", .type = FIO_OPT_STR_STORE, @@ -1774,8 +1772,6 @@ static void add_to_lopt(struct option *lopt, struct fio_option *o) void fio_options_dup_and_init(struct option *long_options) { struct fio_option *o; - struct ext_option *eo; - struct flist_head *n; unsigned int i; options_init(options); @@ -1792,13 +1788,6 @@ void fio_options_dup_and_init(struct option *long_options) o++; assert(i < FIO_NR_OPTIONS); } - - flist_for_each(n, &ext_opt_list) { - eo = flist_entry(n, struct ext_option, list); - add_to_lopt(&long_options[i], &eo->o); - i++; - assert(i < FIO_NR_OPTIONS); - } } struct fio_keyword { @@ -1955,7 +1944,7 @@ int fio_options_parse(struct thread_data *td, char **opts, int num_opts) for (ret = 0, i = 0; i < num_opts; i++) { opts[i] = fio_keyword_replace(opts[i]); - ret |= parse_option(opts[i], options, &ext_opt_list, td); + ret |= parse_option(opts[i], options, td); } return ret; @@ -1963,7 +1952,7 @@ 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, options, &ext_opt_list, td); + return parse_cmd_option(opt, val, options, td); } void fio_fill_default_options(struct thread_data *td) @@ -1973,7 +1962,7 @@ void fio_fill_default_options(struct thread_data *td) int fio_show_option_help(const char *opt) { - return show_cmd_help(options, &ext_opt_list, opt); + return show_cmd_help(options, opt); } static void __options_mem(struct thread_data *td, int alloc) @@ -2027,23 +2016,70 @@ unsigned int fio_get_kb_base(void *data) return kb_base; } -void register_ext_option(struct ext_option *eopt) +int add_option(struct fio_option *o) +{ + struct fio_option *__o; + int opt_index = 0; + + __o = options; + while (__o->name) { + opt_index++; + __o++; + } + + memcpy(&options[opt_index], o, sizeof(*o)); + return 0; +} + +void invalidate_profile_options(const char *prof_name) +{ + struct fio_option *o; + + o = options; + while (o->name) { + if (o->prof_name && !strcmp(o->prof_name, prof_name)) { + o->type = FIO_OPT_INVALID; + o->prof_name = NULL; + } + o++; + } +} + +void add_opt_posval(const char *optname, const char *ival, const char *help) { - dprint(FD_PARSE, "register option '%s'\n", eopt->o.name); - option_init(&eopt->o); - flist_add_tail(&eopt->list, &ext_opt_list); + struct fio_option *o; + unsigned int i; + + o = find_option(options, optname); + if (!o) + return; + + for (i = 0; i < PARSE_MAX_VP; i++) { + if (o->posval[i].ival) + continue; + + o->posval[i].ival = ival; + o->posval[i].help = help; + break; + } } -void prune_profile_options(const char *prof_name) +void del_opt_posval(const char *optname, const char *ival) { - struct ext_option *eo; - struct flist_head *n, *tmp; + struct fio_option *o; + unsigned int i; + + o = find_option(options, optname); + if (!o) + return; - flist_for_each_safe(n, tmp, &ext_opt_list) { - eo = flist_entry(n, struct ext_option, list); - if (strcmp(eo->prof_name, prof_name)) + for (i = 0; i < PARSE_MAX_VP; i++) { + if (!o->posval[i].ival) continue; - flist_del(&eo->list); - free(eo); + if (strcmp(o->posval[i].ival, ival)) + continue; + + o->posval[i].ival = NULL; + o->posval[i].help = NULL; } } diff --git a/options.h b/options.h index 96c81a1..c6c2086 100644 --- a/options.h +++ b/options.h @@ -1,18 +1,41 @@ #ifndef FIO_OPTION_H #define FIO_OPTION_H +#define FIO_MAX_OPTS 512 + +#include <string.h> #include "parse.h" #include "flist.h" #define td_var_offset(var) ((size_t) &((struct thread_options *)0)->var) -struct ext_option { - struct flist_head list; - const char *prof_name; - struct fio_option o; -}; +int add_option(struct fio_option *); +void invalidate_profile_options(const char *); +extern char *exec_profile; + +void add_opt_posval(const char *, const char *, const char *); +void del_opt_posval(const char *, const char *); + +static inline int o_match(struct fio_option *o, const char *opt) +{ + if (!strcmp(o->name, opt)) + return 1; + else if (o->alias && !strcmp(o->alias, opt)) + return 1; + + return 0; +} + +static inline struct fio_option *find_option(struct fio_option *options, + const char *opt) +{ + struct fio_option *o; + + for (o = &options[0]; o->name; o++) + if (o_match(o, opt)) + return o; -void register_ext_option(struct ext_option *); -void prune_profile_options(const char *); + return NULL; +} #endif diff --git a/parse.c b/parse.c index 9c0965f..9e3c5b1 100644 --- a/parse.c +++ b/parse.c @@ -56,20 +56,19 @@ static void show_option_range(struct fio_option *o, FILE *out) static void show_option_values(struct fio_option *o) { - int i = 0; + int i; - do { + for (i = 0; i < PARSE_MAX_VP; i++) { const struct value_pair *vp = &o->posval[i]; if (!vp->ival) - break; + continue; printf("%20s: %-10s", i == 0 ? "valid values" : "", vp->ival); if (vp->help) printf(" %s", vp->help); printf("\n"); - i++; - } while (i < PARSE_MAX_VP); + } if (i) printf("\n"); @@ -78,6 +77,7 @@ static void show_option_values(struct fio_option *o) static void show_option_help(struct fio_option *o, FILE *out) { const char *typehelp[] = { + "invalid", "string (opt=bla)", "string with possible k/m/g postfix (opt=4k)", "string with time postfix (opt=10s)", @@ -86,6 +86,7 @@ static void show_option_help(struct fio_option *o, FILE *out) "integer value (opt=100)", "boolean value (opt=1)", "no argument (opt)", + "deprecated", }; if (o->alias) @@ -93,6 +94,8 @@ static void show_option_help(struct fio_option *o, FILE *out) fprintf(out, "%20s: %s\n", "type", typehelp[o->type]); fprintf(out, "%20s: %s\n", "default", o->def ? o->def : "no default"); + if (o->prof_name) + fprintf(out, "%20s: only for profile '%s'\n", "valid", o->prof_name); show_option_range(o, stdout); show_option_values(o); } @@ -254,40 +257,6 @@ static int check_int(const char *p, int *val) return 1; } -static inline int o_match(struct fio_option *o, const char *opt) -{ - if (!strcmp(o->name, opt)) - return 1; - else if (o->alias && !strcmp(o->alias, opt)) - return 1; - - return 0; -} - -static struct fio_option *find_option(struct fio_option *options, - struct flist_head *eops, const char *opt) -{ - struct flist_head *n; - struct fio_option *o; - - for (o = &options[0]; o->name; o++) - if (o_match(o, opt)) - return o; - - if (!eops) - return NULL; - - flist_for_each(n, eops) { - struct ext_option *eopt; - - eopt = flist_entry(n, struct ext_option, list); - if (o_match(&eopt->o, opt)) - return &eopt->o; - } - - return NULL; -} - #define val_store(ptr, val, off, data) \ do { \ ptr = td_var((data), (off)); \ @@ -323,7 +292,7 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, for (i = 0; i < PARSE_MAX_VP; i++) { vp = &posval[i]; if (!vp->ival || vp->ival[0] == '\0') - break; + continue; ret = 1; if (!strncmp(vp->ival, ptr, strlen(vp->ival))) { ret = 0; @@ -604,8 +573,7 @@ static int handle_option(struct fio_option *o, const char *__ptr, void *data) } static struct fio_option *get_option(const char *opt, - struct fio_option *options, - struct flist_head *eops, char **post) + struct fio_option *options, char **post) { struct fio_option *o; char *ret; @@ -617,9 +585,9 @@ static struct fio_option *get_option(const char *opt, ret = (char *) opt; (*post)++; strip_blank_end(ret); - o = find_option(options, eops, ret); + o = find_option(options, ret); } else { - o = find_option(options, eops, opt); + o = find_option(options, opt); *post = NULL; } @@ -635,8 +603,8 @@ static int opt_cmp(const void *p1, const void *p2) s1 = strdup(*((char **) p1)); s2 = strdup(*((char **) p2)); - o1 = get_option(s1, fio_options, NULL, &foo); - o2 = get_option(s2, fio_options, NULL, &foo); + o1 = get_option(s1, fio_options, &foo); + o2 = get_option(s2, fio_options, &foo); prio1 = prio2 = 0; if (o1) @@ -657,12 +625,11 @@ void sort_options(char **opts, struct fio_option *options, int num_opts) } int parse_cmd_option(const char *opt, const char *val, - struct fio_option *options, struct flist_head *eops, - void *data) + struct fio_option *options, void *data) { struct fio_option *o; - o = find_option(options, eops, opt); + o = find_option(options, opt); if (!o) { fprintf(stderr, "Bad option <%s>\n", opt); return 1; @@ -691,7 +658,7 @@ static char *option_dup_subs(const char *opt) ssize_t nchr = OPT_LEN_MAX; size_t envlen; - if (strlen(in) + 1 > OPT_LEN_MAX) { + if (strlen(opt) + 1 > OPT_LEN_MAX) { fprintf(stderr, "OPT_LEN_MAX (%d) is too small\n", OPT_LEN_MAX); return NULL; } @@ -729,8 +696,7 @@ static char *option_dup_subs(const char *opt) return strdup(out); } -int parse_option(const char *opt, struct fio_option *options, - struct flist_head *ext_opt_list, void *data) +int parse_option(const char *opt, struct fio_option *options, void *data) { struct fio_option *o; char *post, *tmp; @@ -739,7 +705,7 @@ int parse_option(const char *opt, struct fio_option *options, if (!tmp) return 1; - o = get_option(tmp, options, ext_opt_list, &post); + o = get_option(tmp, options, &post); if (!o) { fprintf(stderr, "Bad option <%s>\n", tmp); free(tmp); @@ -852,11 +818,8 @@ static void print_option(struct fio_option *o) } while (printed); } -int show_cmd_help(struct fio_option *options, struct flist_head *ext_opts, - const char *name) +int show_cmd_help(struct fio_option *options, const char *name) { - struct flist_head *n; - struct ext_option *eo; struct fio_option *o, *closest; unsigned int best_dist; int found = 0; @@ -872,6 +835,8 @@ int show_cmd_help(struct fio_option *options, struct flist_head *ext_opts, if (o->type == FIO_OPT_DEPRECATED) continue; + if (!exec_profile && o->prof_name) + continue; if (name) { if (!strcmp(name, o->name) || @@ -891,7 +856,7 @@ int show_cmd_help(struct fio_option *options, struct flist_head *ext_opts, if (show_all || match) { found = 1; if (match) - printf("%24s: %s\n", o->name, o->help); + printf("%20s: %s\n", o->name, o->help); if (show_all) { if (!o->parent) print_option(o); @@ -908,18 +873,6 @@ int show_cmd_help(struct fio_option *options, struct flist_head *ext_opts, if (found) return 0; - flist_for_each(n, ext_opts) { - eo = flist_entry(n, struct ext_option, list); - o = &eo->o; - if (!strcmp(name, o->name) || - (o->alias && !strcmp(name, o->alias))) { - printf("%20s: %s\n", o->name, o->help); - show_option_help(o, stdout); - printf("%20s: External, valid for '%s'\n", "Restriction", eo->prof_name); - return 0; - } - } - printf("No such command: %s", name); if (closest) { printf(" - showing closest match\n"); diff --git a/parse.h b/parse.h index 5f602a3..9cda559 100644 --- a/parse.h +++ b/parse.h @@ -7,7 +7,8 @@ * Option types */ enum fio_opt_type { - FIO_OPT_STR = 0, + FIO_OPT_INVALID = 0, + FIO_OPT_STR, FIO_OPT_STR_VAL, FIO_OPT_STR_VAL_TIME, FIO_OPT_STR_STORE, @@ -49,17 +50,18 @@ struct fio_option { void *cb; /* callback */ const char *help; /* help text for option */ const char *def; /* default setting */ - const struct value_pair posval[PARSE_MAX_VP];/* possible values */ + struct value_pair posval[PARSE_MAX_VP];/* possible values */ const char *parent; /* parent option */ int (*verify)(struct fio_option *, void *); + const char *prof_name; /* only valid for specific profile */ }; typedef int (str_cb_fn)(void *, char *); -extern int parse_option(const char *, struct fio_option *, struct flist_head *, void *); +extern int parse_option(const char *, struct fio_option *, void *); extern void sort_options(char **, struct fio_option *, int); -extern int parse_cmd_option(const char *t, const char *l, struct fio_option *, struct flist_head *, void *); -extern int show_cmd_help(struct fio_option *, struct flist_head *, const char *); +extern int parse_cmd_option(const char *t, const char *l, struct fio_option *, void *); +extern int show_cmd_help(struct fio_option *, const char *); extern void fill_default_options(void *, struct fio_option *); extern void option_init(struct fio_option *); extern void options_init(struct fio_option *); diff --git a/profile.c b/profile.c index 44e6269..0e2b97d 100644 --- a/profile.c +++ b/profile.c @@ -6,13 +6,11 @@ static FLIST_HEAD(profile_list); -int load_profile(const char *profile) +struct profile_ops *find_profile(const char *profile) { - struct profile_ops *ops; + struct profile_ops *ops = NULL; struct flist_head *n; - dprint(FD_PROFILE, "loading profile '%s'\n", profile); - flist_for_each(n, &profile_list) { ops = flist_entry(n, struct profile_ops, list); if (!strcmp(profile, ops->name)) @@ -21,6 +19,16 @@ int load_profile(const char *profile) ops = NULL; } + return ops; +} + +int load_profile(const char *profile) +{ + struct profile_ops *ops; + + dprint(FD_PROFILE, "loading profile '%s'\n", profile); + + ops = find_profile(profile); if (ops) { ops->prep_cmd(); add_job_opts(ops->cmdline); @@ -31,34 +39,60 @@ int load_profile(const char *profile) return 1; } -static void add_profile_options(struct profile_ops *ops) +static int add_profile_options(struct profile_ops *ops) { - struct fio_option *fo; - struct ext_option *eo; + struct fio_option *o; if (!ops->options) - return; + return 0; - fo = ops->options; - while (fo->name) { - eo = malloc(sizeof(*eo)); - eo->prof_name = ops->name; - memcpy(&eo->o, fo, sizeof(*fo)); - register_ext_option(eo); - fo++; + o = ops->options; + while (o->name) { + o->prof_name = ops->name; + if (add_option(o)) + return 1; + o++; } + + return 0; } -void register_profile(struct profile_ops *ops) +int register_profile(struct profile_ops *ops) { + int ret; + dprint(FD_PROFILE, "register profile '%s'\n", ops->name); - flist_add_tail(&ops->list, &profile_list); - add_profile_options(ops); + + ret = add_profile_options(ops); + if (!ret) { + flist_add_tail(&ops->list, &profile_list); + add_opt_posval("profile", ops->name, ops->desc); + return 0; + } + + invalidate_profile_options(ops->name); + return ret; } void unregister_profile(struct profile_ops *ops) { dprint(FD_PROFILE, "unregister profile '%s'\n", ops->name); flist_del(&ops->list); - prune_profile_options(ops->name); + invalidate_profile_options(ops->name); + del_opt_posval("profile", ops->name); +} + +void profile_add_hooks(struct thread_data *td) +{ + struct profile_ops *ops; + + if (!exec_profile) + return; + + ops = find_profile(exec_profile); + if (!ops) + return; + + td->fill_io_u_off = ops->fill_io_u_off; + td->fill_io_u_size = ops->fill_io_u_size; } diff --git a/profile.h b/profile.h index 8ea77d9..3bae500 100644 --- a/profile.h +++ b/profile.h @@ -6,6 +6,7 @@ struct profile_ops { struct flist_head list; char name[32]; + char desc[64]; int flags; /* @@ -22,10 +23,18 @@ struct profile_ops { * The complete command line */ const char **cmdline; + + /* + * Functions for overriding internal fio io_u functions + */ + int (*fill_io_u_off)(struct thread_data *, struct io_u *); + int (*fill_io_u_size)(struct thread_data *, struct io_u *); }; -void register_profile(struct profile_ops *); +int register_profile(struct profile_ops *); void unregister_profile(struct profile_ops *); int load_profile(const char *); +struct profile_ops *find_profile(const char *); +void profile_add_hooks(struct thread_data *); #endif diff --git a/profiles/tiobench.c b/profiles/tiobench.c index 4bdcfa2..f86a337 100644 --- a/profiles/tiobench.c +++ b/profiles/tiobench.c @@ -85,6 +85,7 @@ static void tb_prep_cmdline(void) static struct profile_ops tiobench_profile = { .name = "tiobench", + .desc = "tiotest/tiobench benchmark", .options = options, .prep_cmd = tb_prep_cmdline, .cmdline = tb_opts, @@ -92,7 +93,8 @@ static struct profile_ops tiobench_profile = { static void fio_init tiobench_register(void) { - register_profile(&tiobench_profile); + if (register_profile(&tiobench_profile)) + log_err("fio: failed to register profile 'tiobench'\n"); } static void fio_exit tiobench_unregister(void) -- To unsubscribe from this list: send the line "unsubscribe fio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html