gfio.c revision 45032dd83a49ffd76aa5db4c2ef65a832c413c1c
1/* 2 * gfio - gui front end for fio - the flexible io tester 3 * 4 * Copyright (C) 2012 Stephen M. Cameron <stephenmcameron@gmail.com> 5 * 6 * The license below covers all files distributed with fio unless otherwise 7 * noted in the file itself. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23#include <locale.h> 24 25#include <glib.h> 26#include <gtk/gtk.h> 27 28#include "fio_initialization.h" 29#include "fio.h" 30 31#define ARRAYSIZE(x) (sizeof((x)) / (sizeof((x)[0]))) 32 33typedef void (*clickfunction)(GtkWidget *widget, gpointer data); 34 35static void quit_clicked(GtkWidget *widget, gpointer data); 36static void start_job_clicked(GtkWidget *widget, gpointer data); 37 38static struct button_spec { 39 const char *buttontext; 40 clickfunction f; 41 const char *tooltiptext; 42} buttonspeclist[] = { 43#define START_JOB_BUTTON 0 44 { "Start Job", 45 start_job_clicked, 46 "Send current fio job to fio server to be executed" }, 47#define QUIT_BUTTON 1 48 { "Quit", quit_clicked, "Quit gfio" }, 49}; 50 51struct gui { 52 GtkWidget *window; 53 GtkWidget *vbox; 54 GtkWidget *thread_status_pb; 55 GtkWidget *buttonbox; 56 GtkWidget *button[ARRAYSIZE(buttonspeclist)]; 57 GtkWidget *hostname_hbox; 58 GtkWidget *hostname_label; 59 GtkWidget *hostname_entry; 60 GtkWidget *port_label; 61 GtkWidget *port_entry; 62 GtkWidget *hostname_combo_box; /* ipv4, ipv6 or socket */ 63 pthread_t t; 64} ui; 65 66static void gfio_text_op(struct fio_client *client, 67 FILE *f, __u16 pdu_len, const char *buf) 68{ 69 printf("gfio_text_op called\n"); 70 fio_client_ops.text_op(client, f, pdu_len, buf); 71} 72 73static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd) 74{ 75 printf("gfio_disk_util_op called\n"); 76 fio_client_ops.disk_util(client, cmd); 77} 78 79static void gfio_thread_status_op(struct fio_net_cmd *cmd) 80{ 81 printf("gfio_thread_status_op called\n"); 82 fio_client_ops.thread_status(cmd); 83} 84 85static void gfio_group_stats_op(struct fio_net_cmd *cmd) 86{ 87 printf("gfio_group_stats_op called\n"); 88 fio_client_ops.group_stats(cmd); 89} 90 91static void gfio_eta_op(struct fio_client *client, struct fio_net_cmd *cmd) 92{ 93 fio_client_ops.eta(client, cmd); 94} 95 96static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd) 97{ 98 printf("gfio_probe_op called\n"); 99 fio_client_ops.probe(client, cmd); 100} 101 102static void gfio_update_thread_status(char *status_message, double perc) 103{ 104 static char message[100]; 105 const char *m = message; 106 107 strncpy(message, status_message, sizeof(message) - 1); 108 gtk_progress_bar_set_text( 109 GTK_PROGRESS_BAR(ui.thread_status_pb), m); 110 gtk_progress_bar_set_fraction( 111 GTK_PROGRESS_BAR(ui.thread_status_pb), perc / 100.0); 112 gdk_threads_enter(); 113 gtk_widget_queue_draw(ui.window); 114 gdk_threads_leave(); 115} 116 117struct client_ops gfio_client_ops = { 118 gfio_text_op, 119 gfio_disk_util_op, 120 gfio_thread_status_op, 121 gfio_group_stats_op, 122 gfio_eta_op, 123 gfio_probe_op, 124 gfio_update_thread_status, 125}; 126 127static void quit_clicked(__attribute__((unused)) GtkWidget *widget, 128 __attribute__((unused)) gpointer data) 129{ 130 gtk_main_quit(); 131} 132 133static void *job_thread(void *arg) 134{ 135 struct gui *ui = arg; 136 137 fio_handle_clients(&gfio_client_ops); 138 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1); 139 return NULL; 140} 141 142static void start_job_thread(pthread_t *t, struct gui *ui) 143{ 144 pthread_create(t, NULL, job_thread, ui); 145} 146 147static void start_job_clicked(__attribute__((unused)) GtkWidget *widget, 148 gpointer data) 149{ 150 struct gui *ui = data; 151 152 printf("Start job button was clicked.\n"); 153 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0); 154 start_job_thread(&ui->t, ui); 155} 156 157static void add_button(struct gui *ui, int i, GtkWidget *buttonbox, 158 struct button_spec *buttonspec) 159{ 160 ui->button[i] = gtk_button_new_with_label(buttonspec->buttontext); 161 g_signal_connect(ui->button[i], "clicked", G_CALLBACK (buttonspec->f), ui); 162 gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], TRUE, TRUE, 0); 163 gtk_widget_set_tooltip_text(ui->button[i], buttonspeclist[i].tooltiptext); 164} 165 166static void add_buttons(struct gui *ui, 167 struct button_spec *buttonlist, 168 int nbuttons) 169{ 170 int i; 171 172 ui->buttonbox = gtk_hbox_new(FALSE, 0); 173 gtk_container_add(GTK_CONTAINER (ui->vbox), ui->buttonbox); 174 for (i = 0; i < nbuttons; i++) 175 add_button(ui, i, ui->buttonbox, &buttonlist[i]); 176} 177 178static void init_ui(int *argc, char **argv[], struct gui *ui) 179{ 180 GList *hostname_type_list = NULL; 181 char portnum[20]; 182 183 /* Magical g*thread incantation, you just need this thread stuff. 184 * Without it, the update that happens in gfio_update_thread_status 185 * doesn't really happen in a timely fashion, you need expose events 186 */ 187 if (!g_thread_supported ()) 188 g_thread_init(NULL); 189 gdk_threads_init(); 190 191 gtk_init(argc, argv); 192 193 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 194 gtk_window_set_title(GTK_WINDOW(ui->window), "fio"); 195 gtk_window_set_default_size(GTK_WINDOW(ui->window), 700, 500); 196 197 g_signal_connect(ui->window, "delete-event", G_CALLBACK (quit_clicked), NULL); 198 g_signal_connect(ui->window, "destroy", G_CALLBACK (quit_clicked), NULL); 199 200 ui->vbox = gtk_vbox_new(FALSE, 0); 201 gtk_container_add(GTK_CONTAINER (ui->window), ui->vbox); 202 203 /* 204 * Set up hostname label + entry, port label + entry, 205 */ 206 ui->hostname_hbox = gtk_hbox_new(FALSE, 0); 207 ui->hostname_label = gtk_label_new("Host:"); 208 ui->hostname_entry = gtk_entry_new(); 209 gtk_entry_set_text(GTK_ENTRY(ui->hostname_entry), "localhost"); 210 ui->port_label = gtk_label_new("Port:"); 211 ui->port_entry = gtk_entry_new(); 212 snprintf(portnum, sizeof(portnum) - 1, "%d", FIO_NET_PORT); 213 gtk_entry_set_text(GTK_ENTRY(ui->port_entry), (gchar *) portnum); 214 215 /* 216 * Set up combo box for address type 217 */ 218 ui->hostname_combo_box = gtk_combo_new(); 219 gtk_entry_set_text(GTK_ENTRY (GTK_COMBO(ui->hostname_combo_box)->entry), "IPv4"); 220 hostname_type_list = g_list_append(hostname_type_list, (gpointer) "IPv4"); 221 hostname_type_list = g_list_append(hostname_type_list, (gpointer) "local socket"); 222 hostname_type_list = g_list_append(hostname_type_list, (gpointer) "IPv6"); 223 gtk_combo_set_popdown_strings (GTK_COMBO (ui->hostname_combo_box), hostname_type_list); 224 g_list_free(hostname_type_list); 225 226 gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->hostname_label); 227 gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->hostname_entry); 228 gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->port_label); 229 gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->port_entry); 230 gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->hostname_combo_box); 231 gtk_container_add(GTK_CONTAINER (ui->vbox), ui->hostname_hbox); 232 233 /* 234 * Set up thread status progress bar 235 */ 236 ui->thread_status_pb = gtk_progress_bar_new(); 237 gtk_progress_bar_set_fraction( 238 GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0); 239 gtk_progress_bar_set_text( 240 GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running"); 241 gtk_container_add(GTK_CONTAINER (ui->vbox), ui->thread_status_pb); 242 243 add_buttons(ui, buttonspeclist, ARRAYSIZE(buttonspeclist)); 244 gtk_widget_show_all(ui->window); 245} 246 247int main(int argc, char *argv[], char *envp[]) 248{ 249 if (initialize_fio(envp)) 250 return 1; 251 252 if (parse_options(argc, argv)) 253 return 1; 254 255 init_ui(&argc, &argv, &ui); 256 257 gdk_threads_enter(); 258 gtk_main(); 259 gdk_threads_leave(); 260 return 0; 261} 262