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 <axboe@kernel.dk>
diff --git a/goptions.c b/goptions.c
index 6484197..547d9cf 100644
--- a/goptions.c
+++ b/goptions.c
@@ -24,6 +24,8 @@
struct gopt_int {
struct gopt gopt;
+ unsigned int lastval;
+ unsigned int in_change;
GtkWidget *spin;
};
@@ -160,6 +162,7 @@
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 @@
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 @@
{
struct gopt_int *i = (struct gopt_int *) data;
struct fio_option *o = &fio_options[i->gopt.opt_index];
+ GtkAdjustment *adj;
+ int value, delta;
- printf("int %s changed\n", o->name);
+ 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 @@
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 @@
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 @@
}
gtk_box_pack_start(GTK_BOX(r->gopt.box), label, FALSE, FALSE, 0);
+ o->gui_data = r;
return &r->gopt;
}
@@ -587,6 +619,9 @@
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 8681c21..635779d 100644
--- a/options.c
+++ b/options.c
@@ -2124,6 +2124,7 @@
.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 @@
.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 c1fed56..545c3de 100644
--- a/parse.c
+++ b/parse.c
@@ -833,9 +833,8 @@
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 @@
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 030a180..fe3b6bc 100644
--- a/parse.h
+++ b/parse.h
@@ -62,10 +62,13 @@
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 *);