parser: relax restriction on postfix ranges
[fio.git] / gfio.c
diff --git a/gfio.c b/gfio.c
index 09a2484224f090d4a39ab3083a32b5a076e7b32f..a52d84d33e3a8221bec40767760f3cab73a667b3 100644 (file)
--- a/gfio.c
+++ b/gfio.c
@@ -2,6 +2,7 @@
  * gfio - gui front end for fio - the flexible io tester
  *
  * Copyright (C) 2012 Stephen M. Cameron <stephenmcameron@gmail.com> 
+ * Copyright (C) 2012 Jens Axboe <axboe@kernel.dk>
  *
  * The license below covers all files distributed with fio unless otherwise
  * noted in the file itself.
 #include <malloc.h>
 
 #include <glib.h>
+#include <cairo.h>
 #include <gtk/gtk.h>
 
 #include "fio.h"
+#include "graph.h"
+
+static int gfio_server_running;
 
 static void gfio_update_thread_status(char *status_message, double perc);
 
@@ -85,7 +90,9 @@ struct gui {
        GtkWidget *buttonbox;
        GtkWidget *button[ARRAYSIZE(buttonspeclist)];
        GtkWidget *scrolled_window;
-       GtkWidget *textview;
+#define DRAWING_AREA_XDIM 1000
+#define DRAWING_AREA_YDIM 400
+       GtkWidget *drawing_area;
        GtkWidget *error_info_bar;
        GtkWidget *error_label;
        GtkWidget *results_notebook;
@@ -98,7 +105,10 @@ struct gui {
        struct eta_widget eta;
        int connected;
        pthread_t t;
+       pthread_t server_t;
 
+       struct graph *iops_graph;
+       struct graph *bandwidth_graph;
        struct fio_client *client;
        int nr_job_files;
        char **job_files;
@@ -110,6 +120,36 @@ struct gfio_client {
        GtkWidget *disk_util_frame;
 };
 
+static void setup_iops_graph(struct gui *ui)
+{
+       if (ui->iops_graph)
+               graph_free(ui->iops_graph);
+       ui->iops_graph = graph_new((int) DRAWING_AREA_XDIM / 2.0,
+                                       (int) DRAWING_AREA_YDIM);
+       graph_title(ui->iops_graph, "IOPS");
+       graph_x_title(ui->iops_graph, "Time");
+       graph_y_title(ui->iops_graph, "IOPS");
+       graph_add_label(ui->iops_graph, "Read IOPS");
+       graph_add_label(ui->iops_graph, "Write IOPS");
+       graph_set_color(ui->iops_graph, "Read IOPS", 0.7, 0.0, 0.0);
+       graph_set_color(ui->iops_graph, "Write IOPS", 0.0, 0.0, 0.7);
+}
+
+static void setup_bandwidth_graph(struct gui *ui)
+{
+       if (ui->bandwidth_graph)
+               graph_free(ui->bandwidth_graph);
+       ui->bandwidth_graph = graph_new((int) DRAWING_AREA_XDIM / 2.0,
+                                       (int) DRAWING_AREA_YDIM);
+       graph_title(ui->bandwidth_graph, "Bandwidth");
+       graph_x_title(ui->bandwidth_graph, "Time");
+       graph_y_title(ui->bandwidth_graph, "Bandwidth");
+       graph_add_label(ui->bandwidth_graph, "Read Bandwidth");
+       graph_add_label(ui->bandwidth_graph, "Write Bandwidth");
+       graph_set_color(ui->bandwidth_graph, "Read Bandwidth", 0.7, 0.0, 0.0);
+       graph_set_color(ui->bandwidth_graph, "Write Bandwidth", 0.0, 0.0, 0.7);
+}
+
 static void clear_ui_info(struct gui *ui)
 {
        gtk_label_set_text(GTK_LABEL(ui->probe.hostname), "");
@@ -181,6 +221,7 @@ static void gfio_set_connected(struct gui *ui, int connected)
                ui->connected = 0;
                gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Connect");
                gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
+               gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
        }
 }
 
@@ -258,11 +299,13 @@ static void gfio_ui_setup_log(struct gui *ui)
 
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
        gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
+       g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
+               "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
 
        tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
        tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
        tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
-       tree_view_column(tree_view, 3, "Text", ALIGN_RIGHT | UNSORTABLE);
+       tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
 
        ui->log_model = model;
        ui->log_tree = tree_view;
@@ -289,6 +332,9 @@ static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
        tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
        gtk_widget_set_can_focus(tree_view, FALSE);
 
+       g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
+               "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
+
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
        gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
 
@@ -543,6 +589,9 @@ static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
        tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
        gtk_widget_set_can_focus(tree_view, FALSE);
 
+       g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
+               "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
+
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
        gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
 
@@ -725,6 +774,9 @@ static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
        tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
        gtk_widget_set_can_focus(tree_view, FALSE);
 
+       g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
+               "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
+
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
        gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
 
@@ -944,6 +996,32 @@ static void gfio_group_stats_op(struct fio_client *client,
        gdk_threads_leave();
 }
 
+static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
+{
+       struct gui *ui = (struct gui *) p;
+       cairo_t *cr;
+
+       cr = gdk_cairo_create(w->window);
+
+       cairo_set_source_rgb(cr, 0, 0, 0);
+
+       cairo_save(cr);
+       cairo_translate(cr, 0, 0);
+       line_graph_draw(ui->bandwidth_graph, cr);
+       cairo_stroke(cr);
+       cairo_restore(cr);
+
+       cairo_save(cr);
+       cairo_translate(cr, DRAWING_AREA_XDIM / 2.0, 0);
+                               // DRAWING_AREA_YDIM * 0.05);
+       line_graph_draw(ui->iops_graph, cr);
+       cairo_stroke(cr);
+       cairo_restore(cr);
+       cairo_destroy(cr);
+
+       return FALSE;
+}
+
 static void gfio_update_eta(struct jobs_eta *je)
 {
        static int eta_good;
@@ -1011,6 +1089,11 @@ static void gfio_update_eta(struct jobs_eta *je)
                gtk_entry_set_text(GTK_ENTRY(ui.eta.write_bw), rate_str[1]);
                gtk_entry_set_text(GTK_ENTRY(ui.eta.write_iops), iops_str[1]);
 
+               graph_add_xy_data(ui.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
+               graph_add_xy_data(ui.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
+               graph_add_xy_data(ui.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
+               graph_add_xy_data(ui.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
+
                free(rate_str[0]);
                free(rate_str[1]);
                free(iops_str[0]);
@@ -1197,6 +1280,24 @@ static void start_job_thread(struct gui *ui)
        }
 }
 
+static void *server_thread(void *arg)
+{
+       is_backend = 1;
+       gfio_server_running = 1;
+       fio_start_server(NULL);
+       gfio_server_running = 0;
+       return NULL;
+}
+
+static void gfio_start_server(struct gui *ui)
+{
+       if (!gfio_server_running) {
+               gfio_server_running = 1;
+               pthread_create(&ui->server_t, NULL, server_thread, NULL);
+               pthread_detach(ui->server_t);
+       }
+}
+
 static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
                 gpointer data)
 {
@@ -1216,9 +1317,11 @@ static void connect_clicked(GtkWidget *widget, gpointer data)
                if (!ui->nr_job_files)
                        file_open(widget, data);
                gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
-               fio_clients_connect();
-               pthread_create(&ui->t, NULL, job_thread, NULL);
-               gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 0);
+               gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
+               if (!fio_clients_connect()) {
+                       pthread_create(&ui->t, NULL, job_thread, NULL);
+                       gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 0);
+               }
        } else {
                fio_clients_terminate();
                gfio_set_connected(ui, 0);
@@ -1321,10 +1424,10 @@ static int get_connection_details(char **host, int *port, int *type,
        hbox = gtk_hbox_new(TRUE, 4);
        gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
 
-       combo = gtk_combo_box_text_new();
-       gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "IPv4");
-       gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "IPv6");
-       gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "local socket");
+       combo = gtk_combo_box_new_text();
+       gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "IPv4");
+       gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "IPv6");
+       gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "local socket");
        gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
 
        gtk_container_add(GTK_CONTAINER(hbox), combo);
@@ -1352,7 +1455,7 @@ static int get_connection_details(char **host, int *port, int *type,
        *host = strdup(gtk_entry_get_text(GTK_ENTRY(hentry)));
        *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
 
-       typeentry = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
+       typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo));
        if (!typeentry || !strncmp(typeentry, "IPv4", 4))
                *type = Fio_client_ipv4;
        else if (!strncmp(typeentry, "IPv6", 4))
@@ -1381,13 +1484,14 @@ static void gfio_client_added(struct gui *ui, struct fio_client *client)
 static void file_open(GtkWidget *w, gpointer data)
 {
        GtkWidget *dialog;
+       struct gui *ui = data;
        GSList *filenames, *fn_glist;
        GtkFileFilter *filter;
        char *host;
        int port, type, server_start;
 
        dialog = gtk_file_chooser_dialog_new("Open File",
-               GTK_WINDOW(ui.window),
+               GTK_WINDOW(ui->window),
                GTK_FILE_CHOOSER_ACTION_OPEN,
                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
@@ -1397,6 +1501,7 @@ static void file_open(GtkWidget *w, gpointer data)
        filter = gtk_file_filter_new();
        gtk_file_filter_add_pattern(filter, "*.fio");
        gtk_file_filter_add_pattern(filter, "*.job");
+       gtk_file_filter_add_pattern(filter, "*.ini");
        gtk_file_filter_add_mime_type(filter, "text/fio");
        gtk_file_filter_set_name(filter, "Fio job file");
        gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
@@ -1417,9 +1522,9 @@ static void file_open(GtkWidget *w, gpointer data)
        while (filenames != NULL) {
                struct fio_client *client;
 
-               ui.job_files = realloc(ui.job_files, (ui.nr_job_files + 1) * sizeof(char *));
-               ui.job_files[ui.nr_job_files] = strdup(filenames->data);
-               ui.nr_job_files++;
+               ui->job_files = realloc(ui->job_files, (ui->nr_job_files + 1) * sizeof(char *));
+               ui->job_files[ui->nr_job_files] = strdup(filenames->data);
+               ui->nr_job_files++;
 
                client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
                if (!client) {
@@ -1430,22 +1535,26 @@ static void file_open(GtkWidget *w, gpointer data)
                        report_error(error);
                        g_error_free(error);
                }
-               gfio_client_added(&ui, client);
+               gfio_client_added(ui, client);
                        
                g_free(filenames->data);
                filenames = g_slist_next(filenames);
        }
        free(host);
+
+       if (server_start)
+               gfio_start_server(ui);
 err:
        g_slist_free(fn_glist);
 }
 
 static void file_save(GtkWidget *w, gpointer data)
 {
+       struct gui *ui = data;
        GtkWidget *dialog;
 
        dialog = gtk_file_chooser_dialog_new("Save File",
-               GTK_WINDOW(ui.window),
+               GTK_WINDOW(ui->window),
                GTK_FILE_CHOOSER_ACTION_SAVE,
                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
@@ -1705,20 +1814,24 @@ static void init_ui(int *argc, char **argv[], struct gui *ui)
 #endif
 
        /*
-        * Add a text box for text op messages 
+        * Set up a drawing area and IOPS and bandwidth graphs
         */
-       ui->textview = gtk_text_view_new();
-       ui->text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ui->textview));
-       gtk_text_buffer_set_text(ui->text, "", -1);
-       gtk_text_view_set_editable(GTK_TEXT_VIEW(ui->textview), FALSE);
-       gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ui->textview), FALSE);
+       ui->drawing_area = gtk_drawing_area_new();
+       gtk_widget_set_size_request(GTK_WIDGET(ui->drawing_area), 
+                       DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
+       g_signal_connect(G_OBJECT(ui->drawing_area), "expose_event",
+                               G_CALLBACK (on_expose_drawing_area), ui);
        ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-       gtk_container_add(GTK_CONTAINER(ui->scrolled_window), ui->textview);
+       gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ui->scrolled_window),
+                                       ui->drawing_area);
        gtk_box_pack_start(GTK_BOX(ui->vbox), ui->scrolled_window,
                        TRUE, TRUE, 0);
 
+       setup_iops_graph(ui);
+       setup_bandwidth_graph(ui);
+
        /*
         * Set up alignments for widgets at the bottom of ui, 
         * align bottom left, expand horizontally but not vertically