This is pretty crap right now, but it's exposing all the options.
Now we just need them to reflect the current job, and be able to
update a remote job with a new set of options.
Signed-off-by: Jens Axboe <axboe@kernel.dk>
OBJS = $(SOURCE:.c=.o)
FIO_OBJS = $(OBJS) fio.o
-GFIO_OBJS = $(OBJS) gfio.o graph.o tickmarks.o ghelpers.o
+GFIO_OBJS = $(OBJS) gfio.o graph.o tickmarks.o ghelpers.o goptions.o
T_SMALLOC_OBJS = t/stest.o
T_SMALLOC_OBJS += mutex.o smalloc.o t/log.o
.c.o: .depend
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(CPPFLAGS) $<
+goptions.o: goptions.c goptions.h
+ $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c goptions.c
+
ghelpers.o: ghelpers.c ghelpers.h
$(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c ghelpers.c
#include "fio.h"
#include "gfio.h"
#include "ghelpers.h"
+#include "goptions.h"
#include "graph.h"
static int gfio_server_running;
case GE_STATE_NEW:
connect_state = 1;
- edit_state = 0;
+ edit_state = 1;
connect_str = "Connect";
send_state = 0;
start_state = 0;
break;
case GE_STATE_CONNECTED:
connect_state = 1;
- edit_state = 0;
+ edit_state = 1;
connect_str = "Disconnect";
send_state = 1;
start_state = 0;
break;
case GE_STATE_JOB_SENT:
connect_state = 1;
- edit_state = 0;
+ edit_state = 1;
connect_str = "Disconnect";
send_state = 0;
start_state = 1;
static void edit_job_entry(GtkWidget *w, gpointer data)
{
+ struct gui *ui = (struct gui *) data;
+
+ gopt_get_options_window(ui->window);
}
static void start_job_entry(GtkWidget *w, gpointer data)
--- /dev/null
+#include <locale.h>
+#include <malloc.h>
+#include <string.h>
+
+#include <glib.h>
+#include <cairo.h>
+#include <gtk/gtk.h>
+
+#include "fio.h"
+#include "gfio.h"
+#include "ghelpers.h"
+#include "parse.h"
+
+struct gopt {
+ GtkWidget *box;
+ unsigned int opt_index;
+ unsigned int opt_type;
+};
+
+struct gopt_combo {
+ struct gopt gopt;
+ GtkWidget *combo;
+};
+
+struct gopt_int {
+ struct gopt gopt;
+ GtkWidget *spin;
+};
+
+struct gopt_bool {
+ struct gopt gopt;
+ GtkWidget *check;
+};
+
+struct gopt_str {
+ struct gopt gopt;
+ GtkWidget *entry;
+};
+
+struct gopt_range {
+ struct gopt gopt;
+ GtkWidget *spins[4];
+};
+
+static struct gopt *gopt_new_str_store(struct fio_option *o)
+{
+ struct gopt_str *s;
+ GtkWidget *label;
+
+ s = malloc(sizeof(*s));
+
+ s->gopt.box = gtk_hbox_new(FALSE, 3);
+ label = gtk_label_new(o->name);
+ gtk_box_pack_start(GTK_BOX(s->gopt.box), label, FALSE, FALSE, 0);
+
+ s->entry = gtk_entry_new();
+ gtk_entry_set_editable(GTK_ENTRY(s->entry), 1);
+
+ if (o->def)
+ gtk_entry_set_text(GTK_ENTRY(s->entry), o->def);
+
+ gtk_box_pack_start(GTK_BOX(s->gopt.box), s->entry, FALSE, FALSE, 0);
+ return &s->gopt;
+}
+
+static struct gopt *gopt_new_combo(struct fio_option *o)
+{
+ struct gopt_combo *combo;
+ struct value_pair *vp;
+ GtkWidget *label;
+ int i, active = 0;
+
+ combo = malloc(sizeof(*combo));
+
+ combo->gopt.box = gtk_hbox_new(FALSE, 3);
+ label = gtk_label_new(o->name);
+ gtk_box_pack_start(GTK_BOX(combo->gopt.box), label, FALSE, FALSE, 0);
+
+ combo->combo = gtk_combo_box_new_text();
+ gtk_box_pack_start(GTK_BOX(combo->gopt.box), combo->combo, FALSE, FALSE, 0);
+
+ i = 0;
+ vp = &o->posval[0];
+ while (vp->ival) {
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combo->combo), vp->ival);
+ if (o->def && !strcmp(vp->ival, o->def))
+ active = i;
+ vp++;
+ i++;
+ }
+
+ gtk_combo_box_set_active(GTK_COMBO_BOX(combo->combo), active);
+ return &combo->gopt;
+}
+
+static struct gopt *gopt_new_int(struct fio_option *o)
+{
+ struct gopt_int *i;
+ gint maxval, defval;
+ GtkWidget *label;
+
+ i = malloc(sizeof(*i));
+ i->gopt.box = gtk_hbox_new(FALSE, 3);
+ label = gtk_label_new(o->name);
+ gtk_box_pack_start(GTK_BOX(i->gopt.box), label, FALSE, FALSE, 0);
+
+ maxval = o->maxval;
+ if (!maxval)
+ maxval = INT_MAX;
+
+ defval = 0;
+ if (o->def) {
+ long long val;
+
+ check_str_bytes(o->def, &val, NULL);
+ defval = val;
+ }
+
+ i->spin = gtk_spin_button_new_with_range(o->minval, maxval, 1.0);
+ 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);
+
+ gtk_box_pack_start(GTK_BOX(i->gopt.box), i->spin, FALSE, FALSE, 0);
+ return &i->gopt;
+}
+
+static struct gopt *gopt_new_bool(struct fio_option *o)
+{
+ struct gopt_bool *b;
+ GtkWidget *label;
+ int defstate = 0;
+
+ b = malloc(sizeof(*b));
+ b->gopt.box = gtk_hbox_new(FALSE, 3);
+ label = gtk_label_new(o->name);
+ gtk_box_pack_start(GTK_BOX(b->gopt.box), label, FALSE, FALSE, 0);
+
+ b->check = gtk_check_button_new();
+ if (o->def && !strcmp(o->def, "1"))
+ defstate = 1;
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->check), defstate);
+
+ gtk_box_pack_start(GTK_BOX(b->gopt.box), b->check, FALSE, FALSE, 0);
+ return &b->gopt;
+}
+
+static struct gopt *gopt_new_int_range(struct fio_option *o)
+{
+ struct gopt_range *r;
+ gint maxval, defval;
+ GtkWidget *label;
+ int i;
+
+ r = malloc(sizeof(*r));
+ r->gopt.box = gtk_hbox_new(FALSE, 3);
+ label = gtk_label_new(o->name);
+ gtk_box_pack_start(GTK_BOX(r->gopt.box), label, FALSE, FALSE, 0);
+
+ maxval = o->maxval;
+ if (!maxval)
+ maxval = INT_MAX;
+
+ defval = 0;
+ if (o->def) {
+ long long val;
+
+ check_str_bytes(o->def, &val, NULL);
+ defval = val;
+ }
+
+ for (i = 0; i < 4; i++) {
+ r->spins[i] = gtk_spin_button_new_with_range(o->minval, maxval, 1.0);
+ gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(r->spins[i]), GTK_UPDATE_IF_VALID);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(r->spins[i]), defval);
+
+ gtk_box_pack_start(GTK_BOX(r->gopt.box), r->spins[i], FALSE, FALSE, 0);
+ }
+
+ return &r->gopt;
+}
+
+static void gopt_add_option(GtkWidget *hbox, struct fio_option *o,
+ unsigned int opt_index)
+{
+ struct gopt *go = NULL;
+
+ switch (o->type) {
+ case FIO_OPT_STR_STORE:
+ go = gopt_new_str_store(o);
+ break;
+ case FIO_OPT_STR_VAL:
+ case FIO_OPT_STR_VAL_TIME:
+ case FIO_OPT_INT:
+ go = gopt_new_int(o);
+ break;
+ case FIO_OPT_STR_SET:
+ case FIO_OPT_BOOL:
+ go = gopt_new_bool(o);
+ break;
+ case FIO_OPT_STR:
+ if (!o->posval[0].ival) {
+ go = gopt_new_str_store(o);
+ break;
+ }
+ case FIO_OPT_STR_MULTI:
+ go = gopt_new_combo(o);
+ break;
+ case FIO_OPT_RANGE:
+ go = gopt_new_int_range(o);
+ break;
+ /* still need to handle this one */
+ case FIO_OPT_FLOAT_LIST:
+ break;
+ case FIO_OPT_DEPRECATED:
+ break;
+ default:
+ printf("ignore type %u\n", o->type);
+ break;
+ }
+
+ if (go) {
+ if (o->help)
+ gtk_widget_set_tooltip_text(go->box, o->help);
+
+ gtk_box_pack_start(GTK_BOX(hbox), go->box, FALSE, FALSE, 5);
+ go->opt_index = opt_index;
+ go->opt_type = o->type;
+ }
+}
+
+static void gopt_add_options(GtkWidget **vboxes)
+{
+ GtkWidget *hbox = NULL;
+ int i;
+
+ for (i = 0; fio_options[i].name; i++) {
+ struct fio_option *o = &fio_options[i];
+ unsigned int mask = o->category;
+ struct opt_group *og;
+
+ while ((og = opt_group_from_mask(&mask)) != NULL) {
+ GtkWidget *vbox = vboxes[ffz(~og->mask)];
+
+ hbox = gtk_hbox_new(FALSE, 3);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
+ gopt_add_option(hbox, &fio_options[i], i);
+ }
+ }
+}
+
+static GtkWidget *gopt_add_group_tab(GtkWidget *notebook, struct opt_group *og)
+{
+ GtkWidget *box, *vbox, *scroll;
+
+ scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+ vbox = gtk_vbox_new(FALSE, 3);
+ box = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
+ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scroll, gtk_label_new(og->name));
+
+ return vbox;
+}
+
+static void gopt_add_group_tabs(GtkWidget *notebook, GtkWidget **vbox)
+{
+ struct opt_group *og;
+ unsigned int i = 0;
+
+ do {
+ unsigned int mask = (1U << i);
+
+ og = opt_group_from_mask(&mask);
+ if (!og)
+ break;
+ vbox[i] = gopt_add_group_tab(notebook, og);
+ i++;
+ } while (1);
+}
+
+void gopt_get_options_window(GtkWidget *window)
+{
+ GtkWidget *dialog, *notebook;
+ GtkWidget *vboxes[__FIO_OPT_G_NR];
+
+ dialog = gtk_dialog_new_with_buttons("Fio options",
+ GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
+
+ gtk_widget_set_size_request(GTK_WIDGET(dialog), 1024, 768);
+
+ notebook = gtk_notebook_new();
+ gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), 1);
+ gtk_notebook_popup_enable(GTK_NOTEBOOK(notebook));
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), notebook, TRUE, TRUE, 5);
+
+ gopt_add_group_tabs(notebook, vboxes);
+
+ gopt_add_options(vboxes);
+
+ gtk_widget_show_all(dialog);
+
+ gtk_dialog_run(GTK_DIALOG(dialog));
+
+ gtk_widget_destroy(dialog);
+}
--- /dev/null
+#ifndef GFIO_OPTIONS_H
+#define GFIO_OPTIONS_H
+
+void gopt_get_options_window(GtkWidget *window);
+
+#endif
return 0;
}
+/*
+ * Option grouping
+ */
+static struct opt_group fio_opt_groups[] = {
+ {
+ .name = "Description",
+ .mask = FIO_OPT_G_DESC,
+ },
+ {
+ .name = "File",
+ .mask = FIO_OPT_G_FILE,
+ },
+ {
+ .name = "Misc",
+ .mask = FIO_OPT_G_MISC,
+ },
+ {
+ .name = "IO (main)",
+ .mask = FIO_OPT_G_IO,
+ },
+ {
+ .name = "IO direction",
+ .mask = FIO_OPT_G_IO_DDIR,
+ },
+ {
+ .name = "IO buffer",
+ .mask = FIO_OPT_G_IO_BUF,
+ },
+ {
+ .name = "Random",
+ .mask = FIO_OPT_G_RAND,
+ },
+ {
+ .name = "OS",
+ .mask = FIO_OPT_G_OS,
+ },
+ {
+ .name = "Memory",
+ .mask = FIO_OPT_G_MEM,
+ },
+ {
+ .name = "Verify",
+ .mask = FIO_OPT_G_VERIFY,
+ },
+ {
+ .name = "CPU",
+ .mask = FIO_OPT_G_CPU,
+ },
+ {
+ .name = "Log",
+ .mask = FIO_OPT_G_LOG,
+ },
+ {
+ .name = "Zone",
+ .mask = FIO_OPT_G_ZONE,
+ },
+ {
+ .name = "Cache",
+ .mask = FIO_OPT_G_CACHE,
+ },
+ {
+ .name = "Stat",
+ .mask = FIO_OPT_G_STAT,
+ },
+ {
+ .name = "Error",
+ .mask = FIO_OPT_G_ERR,
+ },
+ {
+ .name = "Job",
+ .mask = FIO_OPT_G_JOB,
+ },
+ {
+ .name = NULL,
+ },
+};
+
+struct opt_group *opt_group_from_mask(unsigned int *mask)
+{
+ struct opt_group *og;
+ int i;
+
+ if (*mask == FIO_OPT_G_INVALID)
+ return NULL;
+
+ for (i = 0; fio_opt_groups[i].name; i++) {
+ og = &fio_opt_groups[i];
+
+ if (*mask & og->mask) {
+ *mask &= ~(og->mask);
+ return og;
+ }
+ }
+
+ return NULL;
+}
+
/*
* Map of job/command line options
*/
-static struct fio_option options[FIO_MAX_OPTS] = {
+struct fio_option fio_options[FIO_MAX_OPTS] = {
{
.name = "description",
.type = FIO_OPT_STR_STORE,
{
unsigned int i;
- options_init(options);
+ options_init(fio_options);
i = 0;
while (long_options[i].name)
i++;
- options_to_lopts(options, long_options, i, FIO_GETOPT_JOB);
+ options_to_lopts(fio_options, long_options, i, FIO_GETOPT_JOB);
}
struct fio_keyword {
int i, ret, unknown;
char **opts_copy;
- sort_options(opts, options, num_opts);
+ sort_options(opts, fio_options, num_opts);
opts_copy = dup_and_sub_options(opts, num_opts);
for (ret = 0, i = 0, unknown = 0; i < num_opts; i++) {
struct fio_option *o;
- int newret = parse_option(opts_copy[i], opts[i], options, &o,
- td);
+ int newret = parse_option(opts_copy[i], opts[i], fio_options,
+ &o, td);
if (opts_copy[i]) {
if (newret && !o) {
int fio_cmd_option_parse(struct thread_data *td, const char *opt, char *val)
{
- return parse_cmd_option(opt, val, options, td);
+ return parse_cmd_option(opt, val, fio_options, td);
}
int fio_cmd_ioengine_option_parse(struct thread_data *td, const char *opt,
void fio_fill_default_options(struct thread_data *td)
{
- fill_default_options(td, options);
+ fill_default_options(td, fio_options);
}
int fio_show_option_help(const char *opt)
{
- return show_cmd_help(options, opt);
+ return show_cmd_help(fio_options, opt);
}
void options_mem_dupe(void *data, struct fio_option *options)
*/
void fio_options_mem_dupe(struct thread_data *td)
{
- options_mem_dupe(&td->o, options);
+ options_mem_dupe(&td->o, fio_options);
if (td->eo && td->io_ops) {
void *oldeo = td->eo;
struct fio_option *__o;
int opt_index = 0;
- __o = options;
+ __o = fio_options;
while (__o->name) {
opt_index++;
__o++;
}
- memcpy(&options[opt_index], o, sizeof(*o));
+ memcpy(&fio_options[opt_index], o, sizeof(*o));
return 0;
}
{
struct fio_option *o;
- o = options;
+ o = fio_options;
while (o->name) {
if (o->prof_name && !strcmp(o->prof_name, prof_name)) {
o->type = FIO_OPT_INVALID;
struct fio_option *o;
unsigned int i;
- o = find_option(options, optname);
+ o = find_option(fio_options, optname);
if (!o)
return;
struct fio_option *o;
unsigned int i;
- o = find_option(options, optname);
+ o = find_option(fio_options, optname);
if (!o)
return;
void fio_options_free(struct thread_data *td)
{
- options_free(options, td);
+ options_free(fio_options, td);
if (td->eo && td->io_ops && td->io_ops->options) {
options_free(td->io_ops->options, td->eo);
free(td->eo);
struct thread_data;
void fio_options_free(struct thread_data *);
+extern struct fio_option fio_options[FIO_MAX_OPTS];
+
static inline int o_match(struct fio_option *o, const char *opt)
{
if (!strcmp(o->name, opt))
return NULL;
}
+struct opt_group {
+ const char *name;
+ unsigned int mask;
+};
+
+enum opt_category {
+ __FIO_OPT_G_DESC = 0,
+ __FIO_OPT_G_FILE = 1,
+ __FIO_OPT_G_MISC = 2,
+ __FIO_OPT_G_IO = 3,
+ __FIO_OPT_G_IO_DDIR = 4,
+ __FIO_OPT_G_IO_BUF = 5,
+ __FIO_OPT_G_RAND = 6,
+ __FIO_OPT_G_OS = 7,
+ __FIO_OPT_G_MEM = 8,
+ __FIO_OPT_G_VERIFY = 9,
+ __FIO_OPT_G_CPU = 10,
+ __FIO_OPT_G_LOG = 11,
+ __FIO_OPT_G_ZONE = 12,
+ __FIO_OPT_G_CACHE = 13,
+ __FIO_OPT_G_STAT = 14,
+ __FIO_OPT_G_ERR = 15,
+ __FIO_OPT_G_JOB = 16,
+ __FIO_OPT_G_NR = 17,
+
+ FIO_OPT_G_DESC = (1U << __FIO_OPT_G_DESC),
+ FIO_OPT_G_FILE = (1U << __FIO_OPT_G_FILE),
+ FIO_OPT_G_MISC = (1U << __FIO_OPT_G_MISC),
+ FIO_OPT_G_IO = (1U << __FIO_OPT_G_IO),
+ FIO_OPT_G_IO_DDIR = (1U << __FIO_OPT_G_IO_DDIR),
+ FIO_OPT_G_IO_BUF = (1U << __FIO_OPT_G_IO_BUF),
+ FIO_OPT_G_RAND = (1U << __FIO_OPT_G_RAND),
+ FIO_OPT_G_OS = (1U << __FIO_OPT_G_OS),
+ FIO_OPT_G_MEM = (1U << __FIO_OPT_G_MEM),
+ FIO_OPT_G_VERIFY = (1U << __FIO_OPT_G_VERIFY),
+ FIO_OPT_G_CPU = (1U << __FIO_OPT_G_CPU),
+ FIO_OPT_G_LOG = (1U << __FIO_OPT_G_LOG),
+ FIO_OPT_G_ZONE = (1U << __FIO_OPT_G_ZONE),
+ FIO_OPT_G_CACHE = (1U << __FIO_OPT_G_CACHE),
+ FIO_OPT_G_STAT = (1U << __FIO_OPT_G_STAT),
+ FIO_OPT_G_ERR = (1U << __FIO_OPT_G_ERR),
+ FIO_OPT_G_JOB = (1U << __FIO_OPT_G_JOB),
+ FIO_OPT_G_INVALID = (1U << __FIO_OPT_G_NR),
+};
+
+extern struct opt_group *opt_group_from_mask(unsigned int *mask);
+
#endif
#include "debug.h"
#include "options.h"
-static struct fio_option *fio_options;
+static struct fio_option *__fio_options;
extern unsigned int fio_get_kb_base(void *);
static int vp_cmp(const void *p1, const void *p2)
return 0;
}
-static int check_str_bytes(const char *p, long long *val, void *data)
+int check_str_bytes(const char *p, long long *val, void *data)
{
return str_to_decimal(p, val, 1, data);
}
if (*(char **)p1) {
s = strdup(*((char **) p1));
- o = get_option(s, fio_options, &foo);
+ o = get_option(s, __fio_options, &foo);
if (o)
prio1 = o->prio;
free(s);
}
if (*(char **)p2) {
s = strdup(*((char **) p2));
- o = get_option(s, fio_options, &foo);
+ o = get_option(s, __fio_options, &foo);
if (o)
prio2 = o->prio;
free(s);
void sort_options(char **opts, struct fio_option *options, int num_opts)
{
- fio_options = options;
+ __fio_options = options;
qsort(opts, num_opts, sizeof(char *), opt_cmp);
- fio_options = NULL;
+ __fio_options = NULL;
}
int parse_cmd_option(const char *opt, const char *val,
#define OPT_LEN_MAX 4096
#define PARSE_MAX_VP 16
-enum opt_category {
- FIO_OPT_G_DESC = 1UL << 0,
- FIO_OPT_G_FILE = 1UL << 1,
- FIO_OPT_G_MISC = 1UL << 2,
- FIO_OPT_G_IO = 1UL << 3,
- FIO_OPT_G_IO_DDIR = 1UL << 4,
- FIO_OPT_G_IO_BUF = 1UL << 5,
- FIO_OPT_G_RAND = 1UL << 6,
- FIO_OPT_G_OS = 1UL << 7,
- FIO_OPT_G_MEM = 1UL << 8,
- FIO_OPT_G_VERIFY = 1UL << 9,
- FIO_OPT_G_CPU = 1UL << 10,
- FIO_OPT_G_LOG = 1UL << 11,
- FIO_OPT_G_ZONE = 1UL << 12,
- FIO_OPT_G_CACHE = 1UL << 13,
- FIO_OPT_G_STAT = 1UL << 14,
- FIO_OPT_G_ERR = 1UL << 15,
- FIO_OPT_G_JOB = 1UL << 16,
-};
-
/*
* Option define
*/
extern void strip_blank_front(char **);
extern void strip_blank_end(char *);
extern int str_to_decimal(const char *, long long *, int, void *);
+extern int check_str_bytes(const char *p, long long *val, void *data);
/*
* Handlers for the options