gfio: add bs display
[fio.git] / gfio.c
diff --git a/gfio.c b/gfio.c
index 7dcb18822db81516830fd2def5c0865be5190fb1..c67e49242e0493e0e88f569a6c6ff80545c5a953 100644 (file)
--- a/gfio.c
+++ b/gfio.c
@@ -52,16 +52,16 @@ static void send_clicked(GtkWidget *widget, gpointer data);
 static struct button_spec {
        const char *buttontext;
        clickfunction f;
-       const char *tooltiptext;
-       const int start_insensitive;
+       const char *tooltiptext[2];
+       const int start_sensitive;
 } buttonspeclist[] = {
 #define CONNECT_BUTTON 0
 #define SEND_BUTTON 1
 #define START_JOB_BUTTON 2
-       { "Connect", connect_clicked, "Connect to host", 0 },
-       { "Send", send_clicked, "Send job description to host", 1 },
+       { "Connect", connect_clicked, { "Disconnect from host", "Connect to host" }, 1 },
+       { "Send", send_clicked, { "Send job description to host", NULL }, 0 },
        { "Start Job", start_job_clicked,
-               "Start the current job on the server", 1 },
+               { "Start the current job on the server", NULL }, 0 },
 };
 
 struct probe_widget {
@@ -81,6 +81,7 @@ struct multitext_widget {
 struct eta_widget {
        GtkWidget *names;
        struct multitext_widget iotype;
+       struct multitext_widget bs;
        struct multitext_widget ioengine;
        struct multitext_widget iodepth;
        GtkWidget *jobs;
@@ -157,11 +158,11 @@ struct gui_entry {
        GtkWidget *notebook;
        GtkWidget *error_info_bar;
        GtkWidget *error_label;
-       GtkWidget *results_notebook;
        GtkWidget *results_window;
+       GtkWidget *results_notebook;
        GtkUIManager *results_uimanager;
-       GtkWidget *results_vbox;
        GtkWidget *results_menu;
+       GtkWidget *disk_util_vbox;
        GtkListStore *log_model;
        GtkWidget *log_tree;
        GtkWidget *log_view;
@@ -188,14 +189,14 @@ struct end_results {
 struct gfio_client {
        struct gui_entry *ge;
        struct fio_client *client;
-       GtkWidget *results_widget;
-       GtkWidget *disk_util_vbox;
        GtkWidget *err_entry;
-       unsigned int job_added;
        struct thread_options o;
 
        struct end_results *results;
        unsigned int nr_results;
+
+       struct cmd_du_pdu *du;
+       unsigned int nr_du;
 };
 
 static void gfio_update_thread_status(struct gui_entry *ge, char *status_message, double perc);
@@ -300,6 +301,7 @@ static void clear_ge_ui_info(struct gui_entry *ge)
        gtk_entry_set_text(GTK_ENTRY(ge->eta.name), "");
 #endif
        multitext_update_entry(&ge->eta.iotype, 0, "");
+       multitext_update_entry(&ge->eta.bs, 0, "");
        multitext_update_entry(&ge->eta.ioengine, 0, "");
        multitext_update_entry(&ge->eta.iodepth, 0, "");
        gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), "");
@@ -432,6 +434,39 @@ static void set_view_results_visible(struct gui *ui, int visible)
        set_menu_entry_visible(ui, "/MainMenu/ViewMenu/Results", visible);
 }
 
+static const char *get_button_tooltip(struct button_spec *s, int sensitive)
+{
+       if (s->tooltiptext[sensitive])
+               return s->tooltiptext[sensitive];
+
+       return s->tooltiptext[0];
+}
+
+static GtkWidget *add_button(GtkWidget *buttonbox,
+                            struct button_spec *buttonspec, gpointer data)
+{
+       GtkWidget *button = gtk_button_new_with_label(buttonspec->buttontext);
+       gboolean sens = buttonspec->start_sensitive;
+
+       g_signal_connect(button, "clicked", G_CALLBACK(buttonspec->f), data);
+       gtk_box_pack_start(GTK_BOX(buttonbox), button, FALSE, FALSE, 3);
+
+       sens = buttonspec->start_sensitive;
+       gtk_widget_set_tooltip_text(button, get_button_tooltip(buttonspec, sens));
+       gtk_widget_set_sensitive(button, sens);
+
+       return button;
+}
+
+static void add_buttons(struct gui_entry *ge, struct button_spec *buttonlist,
+                       int nbuttons)
+{
+       int i;
+
+       for (i = 0; i < nbuttons; i++)
+               ge->button[i] = add_button(ge->buttonbox, &buttonlist[i], ge);
+}
+
 /*
  * Update sensitivity of job buttons and job menu items, based on the
  * state of the client.
@@ -498,6 +533,7 @@ static void update_button_states(struct gui *ui, struct gui_entry *ge)
        gtk_widget_set_sensitive(ge->button[SEND_BUTTON], send_state);
        gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], start_state);
        gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), connect_str);
+       gtk_widget_set_tooltip_text(ge->button[CONNECT_BUTTON], get_button_tooltip(&buttonspeclist[CONNECT_BUTTON], connect_state));
 
        set_menu_entry_visible(ui, "/MainMenu/JobMenu/Connect", connect_state);
        set_menu_entry_text(ui, "/MainMenu/JobMenu/Connect", connect_str);
@@ -1247,6 +1283,136 @@ static GtkWidget *get_results_window(struct gui_entry *ge)
        return ge->results_notebook;
 }
 
+static void disk_util_destroy(GtkWidget *w, gpointer data)
+{
+       struct gui_entry *ge = (struct gui_entry *) data;
+
+       ge->disk_util_vbox = NULL;
+       gtk_widget_destroy(w);
+}
+
+static GtkWidget *get_scrolled_window(gint border_width)
+{
+       GtkWidget *scroll;
+
+       scroll = gtk_scrolled_window_new(NULL, NULL);
+       gtk_container_set_border_width(GTK_CONTAINER(scroll), border_width);
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+       return scroll;
+}
+
+static GtkWidget *gfio_disk_util_get_vbox(struct gui_entry *ge)
+{
+       GtkWidget *vbox, *box, *scroll, *res_notebook;
+
+       if (ge->disk_util_vbox)
+               return ge->disk_util_vbox;
+
+       scroll = get_scrolled_window(5);
+       vbox = gtk_vbox_new(FALSE, 3);
+       box = gtk_hbox_new(FALSE, 0);
+       gtk_box_pack_start(GTK_BOX(vbox), box, TRUE, FALSE, 5);
+
+       gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
+       res_notebook = get_results_window(ge);
+
+       gtk_notebook_append_page(GTK_NOTEBOOK(res_notebook), scroll, gtk_label_new("Disk utilization"));
+       ge->disk_util_vbox = box;
+       g_signal_connect(vbox, "destroy", G_CALLBACK(disk_util_destroy), ge);
+
+       return ge->disk_util_vbox;
+}
+
+static int __gfio_disk_util_show(GtkWidget *res_notebook,
+                                struct gfio_client *gc, struct cmd_du_pdu *p)
+{
+       GtkWidget *box, *frame, *entry, *vbox, *util_vbox;
+       struct gui_entry *ge = gc->ge;
+       double util;
+       char tmp[16];
+
+       util_vbox = gfio_disk_util_get_vbox(ge);
+
+       vbox = gtk_vbox_new(FALSE, 3);
+       gtk_container_add(GTK_CONTAINER(util_vbox), vbox);
+
+       frame = gtk_frame_new((char *) p->dus.name);
+       gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
+
+       box = gtk_vbox_new(FALSE, 3);
+       gtk_container_add(GTK_CONTAINER(frame), box);
+
+       frame = gtk_frame_new("Read");
+       gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
+       vbox = gtk_hbox_new(TRUE, 3);
+       gtk_container_add(GTK_CONTAINER(frame), vbox);
+       entry = new_info_entry_in_frame(vbox, "IOs");
+       entry_set_int_value(entry, p->dus.ios[0]);
+       entry = new_info_entry_in_frame(vbox, "Merges");
+       entry_set_int_value(entry, p->dus.merges[0]);
+       entry = new_info_entry_in_frame(vbox, "Sectors");
+       entry_set_int_value(entry, p->dus.sectors[0]);
+       entry = new_info_entry_in_frame(vbox, "Ticks");
+       entry_set_int_value(entry, p->dus.ticks[0]);
+
+       frame = gtk_frame_new("Write");
+       gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
+       vbox = gtk_hbox_new(TRUE, 3);
+       gtk_container_add(GTK_CONTAINER(frame), vbox);
+       entry = new_info_entry_in_frame(vbox, "IOs");
+       entry_set_int_value(entry, p->dus.ios[1]);
+       entry = new_info_entry_in_frame(vbox, "Merges");
+       entry_set_int_value(entry, p->dus.merges[1]);
+       entry = new_info_entry_in_frame(vbox, "Sectors");
+       entry_set_int_value(entry, p->dus.sectors[1]);
+       entry = new_info_entry_in_frame(vbox, "Ticks");
+       entry_set_int_value(entry, p->dus.ticks[1]);
+
+       frame = gtk_frame_new("Shared");
+       gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
+       vbox = gtk_hbox_new(TRUE, 3);
+       gtk_container_add(GTK_CONTAINER(frame), vbox);
+       entry = new_info_entry_in_frame(vbox, "IO ticks");
+       entry_set_int_value(entry, p->dus.io_ticks);
+       entry = new_info_entry_in_frame(vbox, "Time in queue");
+       entry_set_int_value(entry, p->dus.time_in_queue);
+
+       util = 0.0;
+       if (p->dus.msec)
+               util = (double) 100 * p->dus.io_ticks / (double) p->dus.msec;
+       if (util > 100.0)
+               util = 100.0;
+
+       sprintf(tmp, "%3.2f%%", util);
+       entry = new_info_entry_in_frame(vbox, "Disk utilization");
+       gtk_entry_set_text(GTK_ENTRY(entry), tmp);
+
+       gtk_widget_show_all(ge->results_window);
+       return 0;
+}
+
+static int gfio_disk_util_show(struct gfio_client *gc)
+{
+       struct gui_entry *ge = gc->ge;
+       GtkWidget *res_notebook;
+       int i;
+
+       if (!gc->nr_du)
+               return 1;
+
+       res_notebook = get_results_window(ge);
+
+       for (i = 0; i < gc->nr_du; i++) {
+               struct cmd_du_pdu *p = &gc->du[i];
+
+               __gfio_disk_util_show(res_notebook, gc, p);
+       }
+
+       gtk_widget_show_all(ge->results_window);
+       return 0;
+}
+
 static void gfio_add_end_results(struct gfio_client *gc, struct thread_stat *ts,
                                 struct group_run_stats *rs)
 {
@@ -1277,8 +1443,6 @@ static void __gfio_display_end_results(GtkWidget *win, struct gfio_client *gc,
 
        gtk_notebook_append_page(GTK_NOTEBOOK(win), scroll, gtk_label_new(ts->name));
 
-       gc->results_widget = vbox;
-
        entry = new_info_entry_in_frame(box, "Name");
        gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
        if (strlen(ts->description)) {
@@ -1318,18 +1482,23 @@ static void gfio_display_end_results(struct gfio_client *gc)
                __gfio_display_end_results(res_notebook, gc, &e->ts, &e->gs);
        }
 
-       gtk_widget_show_all(ge->results_window);
+       if (gfio_disk_util_show(gc))
+               gtk_widget_show_all(ge->results_window);
 }
 
 static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
                            struct group_run_stats *rs)
 {
        struct gfio_client *gc = client->client_data;
+       struct gui_entry *ge = gc->ge;
 
        gfio_add_end_results(gc, ts, rs);
 
        gdk_threads_enter();
-       gfio_display_end_results(gc);
+       if (ge->results_window)
+               __gfio_display_end_results(ge->results_notebook, gc, ts, rs);
+       else
+               gfio_display_end_results(gc);
        gdk_threads_leave();
 }
 
@@ -1365,79 +1534,18 @@ static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd
 {
        struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
        struct gfio_client *gc = client->client_data;
-       GtkWidget *box, *frame, *entry, *vbox;
-       double util;
-       char tmp[16];
-
-       gdk_threads_enter();
-
-       if (!gc->results_widget)
-               goto out;
-
-       if (!gc->disk_util_vbox) {
-               frame = gtk_frame_new("Disk utilization");
-               gtk_box_pack_start(GTK_BOX(gc->results_widget), frame, FALSE, FALSE, 5);
-               vbox = gtk_vbox_new(FALSE, 3);
-               gtk_container_add(GTK_CONTAINER(frame), vbox);
-               gc->disk_util_vbox = vbox;
-       }
-
-       vbox = gtk_vbox_new(FALSE, 3);
-       gtk_container_add(GTK_CONTAINER(gc->disk_util_vbox), vbox);
-
-       frame = gtk_frame_new((char *) p->dus.name);
-       gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
-
-       box = gtk_vbox_new(FALSE, 3);
-       gtk_container_add(GTK_CONTAINER(frame), box);
-
-       frame = gtk_frame_new("Read");
-       gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
-       vbox = gtk_hbox_new(TRUE, 3);
-       gtk_container_add(GTK_CONTAINER(frame), vbox);
-       entry = new_info_entry_in_frame(vbox, "IOs");
-       entry_set_int_value(entry, p->dus.ios[0]);
-       entry = new_info_entry_in_frame(vbox, "Merges");
-       entry_set_int_value(entry, p->dus.merges[0]);
-       entry = new_info_entry_in_frame(vbox, "Sectors");
-       entry_set_int_value(entry, p->dus.sectors[0]);
-       entry = new_info_entry_in_frame(vbox, "Ticks");
-       entry_set_int_value(entry, p->dus.ticks[0]);
-
-       frame = gtk_frame_new("Write");
-       gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
-       vbox = gtk_hbox_new(TRUE, 3);
-       gtk_container_add(GTK_CONTAINER(frame), vbox);
-       entry = new_info_entry_in_frame(vbox, "IOs");
-       entry_set_int_value(entry, p->dus.ios[1]);
-       entry = new_info_entry_in_frame(vbox, "Merges");
-       entry_set_int_value(entry, p->dus.merges[1]);
-       entry = new_info_entry_in_frame(vbox, "Sectors");
-       entry_set_int_value(entry, p->dus.sectors[1]);
-       entry = new_info_entry_in_frame(vbox, "Ticks");
-       entry_set_int_value(entry, p->dus.ticks[1]);
-
-       frame = gtk_frame_new("Shared");
-       gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
-       vbox = gtk_hbox_new(TRUE, 3);
-       gtk_container_add(GTK_CONTAINER(frame), vbox);
-       entry = new_info_entry_in_frame(vbox, "IO ticks");
-       entry_set_int_value(entry, p->dus.io_ticks);
-       entry = new_info_entry_in_frame(vbox, "Time in queue");
-       entry_set_int_value(entry, p->dus.time_in_queue);
-
-       util = 0.0;
-       if (p->dus.msec)
-               util = (double) 100 * p->dus.io_ticks / (double) p->dus.msec;
-       if (util > 100.0)
-               util = 100.0;
+       struct gui_entry *ge = gc->ge;
+       unsigned int nr = gc->nr_du;
 
-       sprintf(tmp, "%3.2f%%", util);
-       entry = new_info_entry_in_frame(vbox, "Disk utilization");
-       gtk_entry_set_text(GTK_ENTRY(entry), tmp);
+       gc->du = realloc(gc->du, (nr + 1) * sizeof(struct cmd_du_pdu));
+       memcpy(&gc->du[nr], p, sizeof(*p));
+       gc->nr_du++;
 
-       gtk_widget_show_all(gc->results_widget);
-out:
+       gdk_threads_enter();
+       if (ge->results_window)
+               __gfio_disk_util_show(ge->results_notebook, gc, p);
+       else
+               gfio_disk_util_show(gc);
        gdk_threads_leave();
 }
 
@@ -1787,7 +1895,8 @@ static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
        struct gfio_client *gc = client->client_data;
        struct thread_options *o = &gc->o;
        struct gui_entry *ge = gc->ge;
-       char tmp[8];
+       char *c1, *c2, *c3, *c4;
+       char tmp[80];
 
        p->thread_number = le32_to_cpu(p->thread_number);
        p->groupid = le32_to_cpu(p->groupid);
@@ -1801,17 +1910,28 @@ static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
        gtk_combo_box_set_active(GTK_COMBO_BOX(ge->eta.names), 0);
 
        multitext_add_entry(&ge->eta.iotype, ddir_str(o->td_ddir));
+
+       c1 = fio_uint_to_kmg(o->min_bs[DDIR_READ]);
+       c2 = fio_uint_to_kmg(o->max_bs[DDIR_WRITE]);
+       c3 = fio_uint_to_kmg(o->min_bs[DDIR_READ]);
+       c4 = fio_uint_to_kmg(o->max_bs[DDIR_WRITE]);
+       sprintf(tmp, "%s-%s/%s-%s", c1, c2, c3, c4);
+       free(c1);
+       free(c2);
+       free(c3);
+       free(c4);
+       multitext_add_entry(&ge->eta.bs, tmp);
+
        multitext_add_entry(&ge->eta.ioengine, (const char *) o->ioengine);
 
        sprintf(tmp, "%u", o->iodepth);
        multitext_add_entry(&ge->eta.iodepth, tmp);
 
        multitext_set_entry(&ge->eta.iotype, 0);
+       multitext_set_entry(&ge->eta.bs, 0);
        multitext_set_entry(&ge->eta.ioengine, 0);
        multitext_set_entry(&ge->eta.iodepth, 0);
 
-       gc->job_added++;
-
        gfio_set_state(ge, GE_STATE_JOB_SENT);
 
        gdk_threads_leave();
@@ -2018,6 +2138,8 @@ static void connect_clicked(GtkWidget *widget, gpointer data)
                if (!ge->nr_job_files)
                        return;
 
+               gc = ge->client;
+
                gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No jobs running");
                gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
                ret = fio_client_connect(gc->client);
@@ -2054,28 +2176,6 @@ static void send_clicked(GtkWidget *widget, gpointer data)
        }
 }
 
-static GtkWidget *add_button(GtkWidget *buttonbox,
-                            struct button_spec *buttonspec, gpointer data)
-{
-       GtkWidget *button = gtk_button_new_with_label(buttonspec->buttontext);
-
-       g_signal_connect(button, "clicked", G_CALLBACK(buttonspec->f), data);
-       gtk_box_pack_start(GTK_BOX(buttonbox), button, FALSE, FALSE, 3);
-       gtk_widget_set_tooltip_text(button, buttonspec->tooltiptext);
-       gtk_widget_set_sensitive(button, !buttonspec->start_insensitive);
-
-       return button;
-}
-
-static void add_buttons(struct gui_entry *ge, struct button_spec *buttonlist,
-                       int nbuttons)
-{
-       int i;
-
-       for (i = 0; i < nbuttons; i++)
-               ge->button[i] = add_button(ge->buttonbox, &buttonlist[i], ge);
-}
-
 static void on_info_bar_response(GtkWidget *widget, gint response,
                                  gpointer data)
 {
@@ -2632,7 +2732,6 @@ static void view_results(GtkWidget *w, gpointer data)
                gfio_display_end_results(gc);
 }
 
-
 static void __update_graph_limits(struct gfio_graphs *g)
 {
        line_graph_set_data_count_limit(g->iops_graph, gfio_graph_limit);
@@ -2809,9 +2908,9 @@ static const gchar *ui_string = " \
                <menubar name=\"MainMenu\"> \
                        <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
                                <menuitem name=\"New\" action=\"NewFile\" /> \
+                               <menuitem name=\"Open\" action=\"OpenFile\" /> \
                                <menuitem name=\"Close\" action=\"CloseFile\" /> \
                                <separator name=\"Separator1\"/> \
-                               <menuitem name=\"Open\" action=\"OpenFile\" /> \
                                <menuitem name=\"Save\" action=\"SaveFile\" /> \
                                <separator name=\"Separator2\"/> \
                                <menuitem name=\"Preferences\" action=\"Preferences\" /> \
@@ -2871,6 +2970,7 @@ static void combo_entry_changed(GtkComboBox *box, gpointer data)
        index = gtk_combo_box_get_active(box);
 
        multitext_set_entry(&ge->eta.iotype, index);
+       multitext_set_entry(&ge->eta.bs, index);
        multitext_set_entry(&ge->eta.ioengine, index);
        multitext_set_entry(&ge->eta.iodepth, index);
 }
@@ -2880,6 +2980,7 @@ static void combo_entry_destroy(GtkWidget *widget, gpointer data)
        struct gui_entry *ge = (struct gui_entry *) data;
 
        multitext_free(&ge->eta.iotype);
+       multitext_free(&ge->eta.bs);
        multitext_free(&ge->eta.ioengine);
        multitext_free(&ge->eta.iodepth);
 }
@@ -2915,6 +3016,7 @@ static GtkWidget *new_client_page(struct gui_entry *ge)
        g_signal_connect(ge->eta.names, "changed", G_CALLBACK(combo_entry_changed), ge);
        g_signal_connect(ge->eta.names, "destroy", G_CALLBACK(combo_entry_destroy), ge);
        ge->eta.iotype.entry = new_info_entry_in_frame(probe_box, "IO");
+       ge->eta.bs.entry = new_info_entry_in_frame(probe_box, "Blocksize (Read/Write)");
        ge->eta.ioengine.entry = new_info_entry_in_frame(probe_box, "IO Engine");
        ge->eta.iodepth.entry = new_info_entry_in_frame(probe_box, "IO Depth");
        ge->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");