More gui changes
authorJens Axboe <axboe@kernel.dk>
Thu, 1 Mar 2012 11:01:29 +0000 (12:01 +0100)
committerJens Axboe <axboe@kernel.dk>
Thu, 1 Mar 2012 11:01:29 +0000 (12:01 +0100)
- Move progress bar into connect/start field
- Pretty up port/type boxes
- Hook better into adding clients
- Add ->quit hook for client ops
- Ensure fio_handle_clients() stays connected for GUI clients
- Stop server from repeatedly sending RUN commands

Signed-off-by: Jens Axboe <axboe@kernel.dk>
client.c
client.h
gfio.c
server.c
server.h

index 842f225cf05801cdc39858c76ba71fd5cb0d35fd..d80123648207b13ec13e1896783c895f2c7cda31 100644 (file)
--- a/client.c
+++ b/client.c
@@ -169,6 +169,49 @@ void fio_client_add_cmd_option(void *cookie, const char *opt)
        }
 }
 
+struct fio_client *fio_client_add_explicit(const char *hostname, int type,
+                                          int port)
+{
+       struct fio_client *client;
+
+       client = malloc(sizeof(*client));
+       memset(client, 0, sizeof(*client));
+
+       INIT_FLIST_HEAD(&client->list);
+       INIT_FLIST_HEAD(&client->hash_list);
+       INIT_FLIST_HEAD(&client->arg_list);
+       INIT_FLIST_HEAD(&client->eta_list);
+       INIT_FLIST_HEAD(&client->cmd_list);
+
+       client->hostname = strdup(hostname);
+
+       if (type == Fio_client_socket)
+               client->is_sock = 1;
+       else {
+               int ipv6;
+
+               ipv6 = type == Fio_client_ipv6;
+               if (fio_server_parse_host(hostname, &ipv6,
+                                               &client->addr.sin_addr,
+                                               &client->addr6.sin6_addr))
+                       goto err;
+
+               client->port = port;
+       }
+
+       client->fd = -1;
+
+       __fio_client_add_cmd_option(client, "fio");
+
+       flist_add(&client->list, &client_list);
+       nr_clients++;
+       dprint(FD_NET, "client: added <%s>\n", client->hostname);
+       return client;
+err:
+       free(client);
+       return NULL;
+}
+
 int fio_client_add(const char *hostname, void **cookie)
 {
        struct fio_client *existing = *cookie;
@@ -823,6 +866,8 @@ int fio_handle_client(struct fio_client *client, struct client_ops *ops)
 
        switch (cmd->opcode) {
        case FIO_NET_CMD_QUIT:
+               if (ops->quit)
+                       ops->quit(client);
                remove_client(client);
                free(cmd);
                break;
@@ -981,7 +1026,7 @@ int fio_handle_clients(struct client_ops *ops)
                flist_for_each_safe(entry, tmp, &client_list) {
                        client = flist_entry(entry, struct fio_client, list);
 
-                       if (!client->sent_job &&
+                       if (!client->sent_job && !ops->stay_connected &&
                            flist_empty(&client->cmd_list)) {
                                remove_client(client);
                                continue;
index 4146607ea6c35df036763cfc220f4f04839fad45..0071484121c38136d457f367dc907cedd49fb171 100644 (file)
--- a/client.h
+++ b/client.h
@@ -42,6 +42,8 @@ struct fio_client {
 
        uint16_t argc;
        char **argv;
+
+       void *client_data;
 };
 
 typedef void (*client_text_op_func)(struct fio_client *client,
@@ -59,6 +61,8 @@ typedef void (*client_probe_op)(struct fio_client *client, struct fio_net_cmd *c
 
 typedef void (*client_thread_status_display_op)(char *status_message, double perc);
 
+typedef void (*client_quit_op)(struct fio_client *);
+
 struct client_ops {
        client_text_op_func text_op;
        client_disk_util_op_func disk_util;
@@ -66,6 +70,8 @@ struct client_ops {
        client_group_stats_op group_stats;
        client_eta_op eta;
        client_probe_op probe;
+       client_quit_op quit;
+       int stay_connected;
 };
 
 extern struct client_ops fio_client_ops;
@@ -80,5 +86,18 @@ extern void fio_client_dec_jobs_eta(struct client_eta *eta, void (*fn)(struct jo
 extern void fio_client_sum_jobs_eta(struct jobs_eta *dst, struct jobs_eta *je);
 extern void fio_client_convert_jobs_eta(struct jobs_eta *je);
 
+enum {
+       Fio_client_ipv4 = 1,
+       Fio_client_ipv6,
+       Fio_client_socket,
+};
+
+extern int fio_clients_connect(void);
+extern int fio_clients_send_ini(const char *);
+extern int fio_handle_clients(struct client_ops *ops);
+extern int fio_client_add(const char *, void **);
+extern struct fio_client *fio_client_add_explicit(const char *, int, int);
+extern void fio_client_add_cmd_option(void *, const char *);
+
 #endif
 
diff --git a/gfio.c b/gfio.c
index 34b578d29c320abf3330857b3cbfcc937b1f67bf..848e511a8157c975355d36e5a2580fe701e116f4 100644 (file)
--- a/gfio.c
+++ b/gfio.c
@@ -83,8 +83,8 @@ struct gui {
        GtkWidget *hostname_hbox;
        GtkWidget *hostname_label;
        GtkWidget *hostname_entry;
+       GtkWidget *port_button;
        GtkWidget *port_label;
-       GtkWidget *port_entry;
        GtkWidget *hostname_combo_box; /* ipv4, ipv6 or socket */
        GtkWidget *scrolled_window;
        GtkWidget *textview;
@@ -93,13 +93,27 @@ struct gui {
        GtkTextBuffer *text;
        struct probe_widget probe;
        struct eta_widget eta;
+       int connected;
        pthread_t t;
 
-       void *cookie;
+       struct fio_client *client;
        int nr_job_files;
        char **job_files;
 } ui;
 
+static void gfio_set_connected(struct gui *ui, int connected)
+{
+       if (connected) {
+               gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
+               ui->connected = 1;
+               gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Disconnect");
+       } else {
+               ui->connected = 0;
+               gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Connect");
+               gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
+       }
+}
+
 static void gfio_text_op(struct fio_client *client,
                 FILE *f, __u16 pdu_len, const char *buf)
 {
@@ -265,6 +279,13 @@ static void gfio_update_thread_status(char *status_message, double perc)
        gdk_threads_leave();
 }
 
+static void gfio_quit_op(struct fio_client *client)
+{
+       struct gui *ui = client->client_data;
+
+       gfio_set_connected(ui, 0);
+}
+
 struct client_ops gfio_client_ops = {
        .text_op                = gfio_text_op,
        .disk_util              = gfio_disk_util_op,
@@ -272,6 +293,8 @@ struct client_ops gfio_client_ops = {
        .group_stats            = gfio_group_stats_op,
        .eta                    = gfio_eta_op,
        .probe                  = gfio_probe_op,
+       .quit                   = gfio_quit_op,
+       .stay_connected         = 1,
 };
 
 static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
@@ -282,10 +305,9 @@ static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
 
 static void *job_thread(void *arg)
 {
-       struct gui *ui = arg;
-
+       printf("job thread starts\n");
        fio_handle_clients(&gfio_client_ops);
-       gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
+       printf("job thread exits\n");
        return NULL;
 }
 
@@ -310,15 +332,13 @@ static int send_job_files(struct gui *ui)
        return ret;
 }
 
-static void start_job_thread(pthread_t *t, struct gui *ui)
+static void start_job_thread(struct gui *ui)
 {
        if (send_job_files(ui)) {
                printf("Yeah, I didn't really like those options too much.\n");
                gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
                return;
        }
-               
-       pthread_create(t, NULL, job_thread, ui);
 }
 
 static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
@@ -327,14 +347,20 @@ static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
        struct gui *ui = data;
 
        gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
-       start_job_thread(&ui->t, ui);
+       start_job_thread(ui);
 }
 
 static void connect_clicked(__attribute__((unused)) GtkWidget *widget,
                 gpointer data)
 {
-       fio_clients_connect();
-       gtk_widget_set_sensitive(ui.button[START_JOB_BUTTON], 1);
+       struct gui *ui = data;
+
+       if (!ui->connected) {
+               fio_clients_connect();
+               pthread_create(&ui->t, NULL, job_thread, NULL);
+               gfio_set_connected(ui, 1);
+       } else
+               gfio_set_connected(ui, 0);
 }
 
 static void add_button(struct gui *ui, int i, GtkWidget *buttonbox,
@@ -342,7 +368,7 @@ static void add_button(struct gui *ui, int i, GtkWidget *buttonbox,
 {
        ui->button[i] = gtk_button_new_with_label(buttonspec->buttontext);
        g_signal_connect(ui->button[i], "clicked", G_CALLBACK (buttonspec->f), ui);
-       gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], TRUE, TRUE, 0);
+       gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], FALSE, FALSE, 3);
        gtk_widget_set_tooltip_text(ui->button[i], buttonspeclist[i].tooltiptext);
        gtk_widget_set_sensitive(ui->button[i], !buttonspec->start_insensitive);
 }
@@ -419,13 +445,27 @@ static void file_open(GtkWidget *w, gpointer data)
        filenames = fn_glist;
        while (filenames != NULL) {
                const char *hostname;
+               char *typeentry;
+               gint port;
+               int type;
 
                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++;
 
                hostname = gtk_entry_get_text(GTK_ENTRY(ui.hostname_entry));
-               fio_client_add(hostname, &ui.cookie);
+               port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ui.port_button));
+               typeentry = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(ui.hostname_combo_box));
+               if (!typeentry || !strncmp(typeentry, "IPv4", 4))
+                       type = Fio_client_ipv4;
+               else if (!strncmp(typeentry, "IPv6", 4))
+                       type = Fio_client_ipv6;
+               else
+                       type = Fio_client_socket;
+               g_free(typeentry);
+
+               ui.client = fio_client_add_explicit(hostname, type, port);
+               ui.client->client_data = &ui;
 #if 0
                if (error) {
                        report_error(error);
@@ -539,10 +579,42 @@ static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
        return label_widget;
 }
 
+static GtkWidget *create_text_entry(GtkWidget *hbox, GtkWidget *label, const char *defval)
+{
+       GtkWidget *text, *box;
+
+       gtk_container_add(GTK_CONTAINER(hbox), label);
+
+       box = gtk_hbox_new(FALSE, 3);
+       gtk_container_add(GTK_CONTAINER(hbox), box);
+
+       text = gtk_entry_new();
+       gtk_box_pack_start(GTK_BOX(box), text, TRUE, TRUE, 0);
+       gtk_entry_set_text(GTK_ENTRY(text), "localhost");
+
+       return text;
+}
+
+static GtkWidget *create_spinbutton(GtkWidget *hbox, GtkWidget *label, double min, double max, double defval)
+{
+       GtkWidget *button, *box;
+
+       gtk_container_add(GTK_CONTAINER(hbox), label);
+
+       box = gtk_hbox_new(FALSE, 3);
+       gtk_container_add(GTK_CONTAINER(hbox), box);
+
+       button = gtk_spin_button_new_with_range(min, max, 1.0);
+       gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
+
+       gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
+       gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
+
+       return button;
+}
+
 static void init_ui(int *argc, char **argv[], struct gui *ui)
 {
-       GList *hostname_type_list = NULL;
-       char portnum[20];
        GtkSettings *settings;
        GtkUIManager *uimanager;
        GtkWidget *menu, *probe, *probe_frame, *probe_box;
@@ -581,7 +653,7 @@ static void init_ui(int *argc, char **argv[], struct gui *ui)
         * align top left, expand horizontally but not vertically
         */
        ui->topalign = gtk_alignment_new(0, 0, 1, 0);
-       ui->topvbox = gtk_vbox_new(FALSE, 0);
+       ui->topvbox = gtk_vbox_new(FALSE, 3);
        gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
        gtk_box_pack_start(GTK_BOX(ui->vbox), ui->topalign, FALSE, FALSE, 0);
 
@@ -589,31 +661,24 @@ static void init_ui(int *argc, char **argv[], struct gui *ui)
         * Set up hostname label + entry, port label + entry,
         */
        ui->hostname_hbox = gtk_hbox_new(FALSE, 0);
-       ui->hostname_label = gtk_label_new("Host:");
-       ui->hostname_entry = gtk_entry_new();
-       gtk_entry_set_text(GTK_ENTRY(ui->hostname_entry), "localhost");
+
+       ui->hostname_label = gtk_label_new("Hostname:");
+       ui->hostname_entry = create_text_entry(ui->hostname_hbox, ui->hostname_label, "localhost");
+
        ui->port_label = gtk_label_new("Port:");
-       ui->port_entry = gtk_entry_new();
-       snprintf(portnum, sizeof(portnum) - 1, "%d", FIO_NET_PORT);
-       gtk_entry_set_text(GTK_ENTRY(ui->port_entry), (gchar *) portnum);
+       ui->port_button = create_spinbutton(ui->hostname_hbox, ui->port_label, 1, 65535, FIO_NET_PORT);
 
        /*
         * Set up combo box for address type
         */
-       ui->hostname_combo_box = gtk_combo_new();
-       gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(ui->hostname_combo_box)->entry), "IPv4");
-       hostname_type_list = g_list_append(hostname_type_list, (gpointer) "IPv4"); 
-       hostname_type_list = g_list_append(hostname_type_list, (gpointer) "local socket"); 
-       hostname_type_list = g_list_append(hostname_type_list, (gpointer) "IPv6"); 
-       gtk_combo_set_popdown_strings(GTK_COMBO(ui->hostname_combo_box), hostname_type_list);
-       g_list_free(hostname_type_list);
-
-       gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->hostname_label);
-       gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->hostname_entry);
-       gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->port_label);
-       gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->port_entry);
-       gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->hostname_combo_box);
-       gtk_container_add(GTK_CONTAINER (ui->topvbox), ui->hostname_hbox);
+       ui->hostname_combo_box = gtk_combo_box_text_new();
+       gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(ui->hostname_combo_box), "IPv4");
+       gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(ui->hostname_combo_box), "IPv6");
+       gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(ui->hostname_combo_box), "local socket");
+       gtk_combo_box_set_active(GTK_COMBO_BOX(ui->hostname_combo_box), 0);
+
+       gtk_container_add(GTK_CONTAINER(ui->hostname_hbox), ui->hostname_combo_box);
+       gtk_container_add(GTK_CONTAINER(ui->topvbox), ui->hostname_hbox);
 
        probe = gtk_frame_new("Job");
        gtk_box_pack_start(GTK_BOX(ui->topvbox), probe, TRUE, FALSE, 3);
@@ -646,14 +711,6 @@ static void init_ui(int *argc, char **argv[], struct gui *ui)
        ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
        ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
 
-       /*
-        * Set up thread status progress bar
-        */
-       ui->thread_status_pb = gtk_progress_bar_new();
-       gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
-       gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
-       gtk_container_add(GTK_CONTAINER(ui->topvbox), ui->thread_status_pb);
-
        /*
         * Add a text box for text op messages 
         */
@@ -680,6 +737,16 @@ static void init_ui(int *argc, char **argv[], struct gui *ui)
                                        FALSE, FALSE, 0);
 
        add_buttons(ui, buttonspeclist, ARRAYSIZE(buttonspeclist));
+
+       /*
+        * Set up thread status progress bar
+        */
+       ui->thread_status_pb = gtk_progress_bar_new();
+       gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
+       gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
+       gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
+
+
        gtk_widget_show_all(ui->window);
 }
 
@@ -690,6 +757,7 @@ int main(int argc, char *argv[], char *envp[])
        if (fio_init_options())
                return 1;
 
+       fio_debug = ~0UL;
        init_ui(&argc, &argv, &ui);
 
        gdk_threads_enter();
index 2d9b009f2495431c6e8074c7a392621f43acfb65..a2db9dd5ccfdd5352894e0a1a4451d1ece22ebe6 100644 (file)
--- a/server.c
+++ b/server.c
@@ -554,8 +554,10 @@ static int handle_connection(int sk, int block)
 
 void fio_server_idle_loop(void)
 {
-       if (!first_cmd_check)
+       if (!first_cmd_check) {
                fio_net_send_simple_cmd(server_fd, FIO_NET_CMD_RUN, 0, NULL);
+               first_cmd_check = 1;
+       }
        if (server_fd != -1)
                handle_connection(server_fd, 0);
 }
@@ -943,6 +945,46 @@ static int fio_init_server_connection(void)
        return sk;
 }
 
+int fio_server_parse_host(const char *host, int *ipv6, struct in_addr *inp,
+                         struct in6_addr *inp6)
+
+{
+       int ret = 0;
+
+       if (*ipv6)
+               ret = inet_pton(AF_INET6, host, inp6);
+       else
+               ret = inet_pton(AF_INET, host, inp);
+
+       if (ret != 1) {
+               struct hostent *hent;
+
+               hent = gethostbyname(host);
+               if (!hent) {
+                       log_err("fio: failed to resolve <%s>\n", host);
+                       return 0;
+               }
+
+               if (*ipv6) {
+                       if (hent->h_addrtype != AF_INET6) {
+                               log_info("fio: falling back to IPv4\n");
+                               *ipv6 = 0;
+                       } else
+                               memcpy(inp6, hent->h_addr_list[0], 16);
+               }
+               if (!*ipv6) {
+                       if (hent->h_addrtype != AF_INET) {
+                               log_err("fio: lookup type mismatch\n");
+                               return 0;
+                       }
+                       memcpy(inp, hent->h_addr_list[0], 4);
+               }
+               ret = 1;
+       }
+
+       return !(ret == 1);
+}
+
 /*
  * Parse a host/ip/port string. Reads from 'str'.
  *
@@ -961,7 +1003,7 @@ int fio_server_parse_string(const char *str, char **ptr, int *is_sock,
 {
        const char *host = str;
        char *portp;
-       int ret, lport = 0;
+       int lport = 0;
 
        *ptr = NULL;
        *is_sock = 0;
@@ -1022,38 +1064,10 @@ int fio_server_parse_string(const char *str, char **ptr, int *is_sock,
 
        *ptr = strdup(host);
 
-       if (*ipv6)
-               ret = inet_pton(AF_INET6, host, inp6);
-       else
-               ret = inet_pton(AF_INET, host, inp);
-
-       if (ret != 1) {
-               struct hostent *hent;
-
-               hent = gethostbyname(host);
-               if (!hent) {
-                       log_err("fio: failed to resolve <%s>\n", host);
-                       free(*ptr);
-                       *ptr = NULL;
-                       return 1;
-               }
-
-               if (*ipv6) {
-                       if (hent->h_addrtype != AF_INET6) {
-                               log_info("fio: falling back to IPv4\n");
-                               *ipv6 = 0;
-                       } else
-                               memcpy(inp6, hent->h_addr_list[0], 16);
-               }
-               if (!*ipv6) {
-                       if (hent->h_addrtype != AF_INET) {
-                               log_err("fio: lookup type mismatch\n");
-                               free(*ptr);
-                               *ptr = NULL;
-                               return 1;
-                       }
-                       memcpy(inp, hent->h_addr_list[0], 4);
-               }
+       if (fio_server_parse_host(*ptr, ipv6, inp, inp6)) {
+               free(*ptr);
+               *ptr = NULL;
+               return 1;
        }
 
        if (*port == 0)
index f2dd29fa79d1ddd9065ee0b50902b1a60e7cba8f..d17c0cea1486347d58b86aac2ed3ddba80a7fb23 100644 (file)
--- a/server.h
+++ b/server.h
@@ -113,6 +113,7 @@ extern int fio_net_send_cmd(int, uint16_t, const void *, off_t, uint64_t);
 extern int fio_net_send_simple_cmd(int, uint16_t, uint64_t, struct flist_head *);
 extern void fio_server_set_arg(const char *);
 extern int fio_server_parse_string(const char *, char **, int *, int *, struct in_addr *, struct in6_addr *, int *);
+extern int fio_server_parse_host(const char *, int *, struct in_addr *, struct in6_addr *);
 extern const char *fio_server_op(unsigned int);
 extern void fio_server_got_signal(int);
 
@@ -123,12 +124,6 @@ extern void fio_server_send_gs(struct group_run_stats *);
 extern void fio_server_send_du(void);
 extern void fio_server_idle_loop(void);
 
-extern int fio_clients_connect(void);
-extern int fio_clients_send_ini(const char *);
-extern int fio_handle_clients(struct client_ops *ops);
-extern int fio_client_add(const char *, void **);
-extern void fio_client_add_cmd_option(void *, const char *);
-
 extern int fio_recv_data(int sk, void *p, unsigned int len);
 extern int fio_send_data(int sk, const void *p, unsigned int len);
 extern void fio_net_cmd_crc(struct fio_net_cmd *);