From 90265353af8dbf1c43804996909777d4c1a5998e Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 19 Mar 2012 20:29:44 +0100 Subject: [PATCH] Add support for inverse options Options that are tied to each other, meaning that if one is incremented by X, the other is decremented by X automatically. Signed-off-by: Jens Axboe --- goptions.c | 39 +++++++++++++++++++++++++++++++++++++-- options.c | 2 ++ parse.c | 8 +++++--- parse.h | 3 +++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/goptions.c b/goptions.c index 6484197f..547d9cf9 100644 --- a/goptions.c +++ b/goptions.c @@ -24,6 +24,8 @@ struct gopt_combo { struct gopt_int { struct gopt gopt; + unsigned int lastval; + unsigned int in_change; GtkWidget *spin; }; @@ -160,6 +162,7 @@ static struct gopt *gopt_new_str_store(struct fio_option *o, const char *text, u gtk_box_pack_start(GTK_BOX(s->gopt.box), s->entry, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(s->gopt.box), label, FALSE, FALSE, 0); + o->gui_data = s; return &s->gopt; } @@ -191,6 +194,7 @@ static struct gopt_combo *__gopt_new_combo(struct fio_option *o, unsigned int id gtk_box_pack_start(GTK_BOX(c->gopt.box), c->combo, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(c->gopt.box), label, FALSE, FALSE, 0); + o->gui_data = c; return c; } @@ -276,8 +280,32 @@ static void gopt_int_changed(GtkSpinButton *spin, gpointer data) { struct gopt_int *i = (struct gopt_int *) data; struct fio_option *o = &fio_options[i->gopt.opt_index]; - - printf("int %s changed\n", o->name); + GtkAdjustment *adj; + int value, delta; + + adj = gtk_spin_button_get_adjustment(spin); + value = gtk_adjustment_get_value(adj); + delta = value - i->lastval; + i->lastval = value; + + if (o->inv_opt) { + struct gopt_int *i_inv = o->inv_opt->gui_data; + int cur_val; + + /* + * Don't recourse into notify changes. Is there a better + * way than this? We essentially want to block the update + * signal while we perform the below set_value(). + */ + if (i_inv->in_change) + return; + + i->in_change = 1; + cur_val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(i_inv->spin)); + cur_val -= delta; + gtk_spin_button_set_value(GTK_SPIN_BUTTON(i_inv->spin), cur_val); + i->in_change = 0; + } } static struct gopt_int *__gopt_new_int(struct fio_option *o, unsigned long long *p, @@ -317,11 +345,13 @@ static struct gopt_int *__gopt_new_int(struct fio_option *o, unsigned long long gopt_mark_index(&i->gopt, idx); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(i->spin), GTK_UPDATE_IF_VALID); gtk_spin_button_set_value(GTK_SPIN_BUTTON(i->spin), defval); + i->lastval = defval; g_signal_connect(G_OBJECT(i->spin), "value-changed", G_CALLBACK(gopt_int_changed), i); gtk_box_pack_start(GTK_BOX(i->gopt.box), i->spin, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(i->gopt.box), label, FALSE, FALSE, 0); + o->gui_data = i; return i; } @@ -386,6 +416,7 @@ static struct gopt *gopt_new_bool(struct fio_option *o, unsigned int *val, unsig gtk_box_pack_start(GTK_BOX(b->gopt.box), b->check, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(b->gopt.box), label, FALSE, FALSE, 0); + o->gui_data = b; return &b->gopt; } @@ -475,6 +506,7 @@ static struct gopt *gopt_new_int_range(struct fio_option *o, unsigned int **ip, } gtk_box_pack_start(GTK_BOX(r->gopt.box), label, FALSE, FALSE, 0); + o->gui_data = r; return &r->gopt; } @@ -587,6 +619,9 @@ static void gopt_add_options(GtkWidget **vboxes, struct thread_options *to) GtkWidget *hbox = NULL; int i; + /* + * First add all options + */ for (i = 0; fio_options[i].name; i++) { struct fio_option *o = &fio_options[i]; unsigned int mask = o->category; diff --git a/options.c b/options.c index 8681c218..635779db 100644 --- a/options.c +++ b/options.c @@ -2124,6 +2124,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Percentage of mixed workload that is reads", .def = "50", .interval = 5, + .inverse = "rwmixwrite", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RWMIX, }, @@ -2136,6 +2137,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Percentage of mixed workload that is writes", .def = "50", .interval = 5, + .inverse = "rwmixread", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RWMIX, }, diff --git a/parse.c b/parse.c index c1fed56a..545c3de5 100644 --- a/parse.c +++ b/parse.c @@ -833,9 +833,8 @@ int parse_option(char *opt, const char *input, return 1; } - if (!handle_option(*o, post, data)) { + if (!handle_option(*o, post, data)) return 0; - } log_err("fio: failed parsing %s\n", input); return 1; @@ -1063,8 +1062,11 @@ void options_init(struct fio_option *options) dprint(FD_PARSE, "init options\n"); - for (o = &options[0]; o->name; o++) + for (o = &options[0]; o->name; o++) { option_init(o); + if (o->inverse) + o->inv_opt = find_option(options, o->inverse); + } } void options_free(struct fio_option *options, void *data) diff --git a/parse.h b/parse.h index 030a1806..fe3b6bc5 100644 --- a/parse.h +++ b/parse.h @@ -62,10 +62,13 @@ struct fio_option { struct value_pair posval[PARSE_MAX_VP];/* possible values */ const char *parent; /* parent option */ int hide; /* hide if parent isn't set */ + const char *inverse; /* if set, apply opposite action to this option */ + struct fio_option *inv_opt; /* cached lookup */ int (*verify)(struct fio_option *, void *); const char *prof_name; /* only valid for specific profile */ unsigned int category; /* what type of option */ unsigned int group; /* who to group with */ + void *gui_data; }; typedef int (str_cb_fn)(void *, char *); -- 2.25.1