};
struct eta_widget {
+ GtkWidget *name;
+ GtkWidget *iotype;
+ GtkWidget *ioengine;
+ GtkWidget *iodepth;
GtkWidget *jobs;
GtkWidget *files;
GtkWidget *read_bw;
GtkWidget *thread_status_pb;
GtkWidget *buttonbox;
GtkWidget *button[ARRAYSIZE(buttonspeclist)];
- GtkWidget *hostname_hbox;
- GtkWidget *hostname_label;
- GtkWidget *hostname_entry;
- GtkWidget *port_label;
- GtkWidget *port_entry;
- GtkWidget *hostname_combo_box; /* ipv4, ipv6 or socket */
GtkWidget *scrolled_window;
GtkWidget *textview;
GtkWidget *error_info_bar;
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 clear_ui_info(struct gui *ui)
+{
+ gtk_label_set_text(GTK_LABEL(ui->probe.hostname), "");
+ gtk_label_set_text(GTK_LABEL(ui->probe.os), "");
+ gtk_label_set_text(GTK_LABEL(ui->probe.arch), "");
+ gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), "");
+ gtk_label_set_text(GTK_LABEL(ui->eta.name), "");
+ gtk_label_set_text(GTK_LABEL(ui->eta.iotype), "");
+ gtk_label_set_text(GTK_LABEL(ui->eta.ioengine), "");
+ gtk_label_set_text(GTK_LABEL(ui->eta.iodepth), "");
+ gtk_label_set_text(GTK_LABEL(ui->eta.jobs), "");
+ gtk_label_set_text(GTK_LABEL(ui->eta.files), "");
+ gtk_label_set_text(GTK_LABEL(ui->eta.read_bw), "");
+ gtk_label_set_text(GTK_LABEL(ui->eta.read_iops), "");
+ gtk_label_set_text(GTK_LABEL(ui->eta.write_bw), "");
+ gtk_label_set_text(GTK_LABEL(ui->eta.write_iops), "");
+}
+
+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)
{
+#if 0
GtkTextBuffer *buffer;
GtkTextIter end;
gdk_threads_leave();
gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ui.textview),
&end, 0.0, FALSE, 0.0,0.0);
+#else
+ fio_client_ops.text_op(client, f, pdu_len, buf);
+#endif
}
static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
free(mr);
} else if (je->m_iops || je->t_iops)
p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
-#else
+
gtk_label_set_text(GTK_LABEL(ui.eta.cr_bw), "---");
gtk_label_set_text(GTK_LABEL(ui.eta.cr_iops), "---");
gtk_label_set_text(GTK_LABEL(ui.eta.cw_bw), "---");
gdk_threads_leave();
}
+static void gfio_quit_op(struct fio_client *client)
+{
+ struct gui *ui = client->client_data;
+
+ gfio_set_connected(ui, 0);
+}
+
+static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
+{
+ struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
+ struct gui *ui = client->client_data;
+ char tmp[8];
+ int i;
+
+ p->iodepth = le32_to_cpu(p->iodepth);
+ p->rw = le32_to_cpu(p->rw);
+
+ for (i = 0; i < 2; i++) {
+ p->min_bs[i] = le32_to_cpu(p->min_bs[i]);
+ p->max_bs[i] = le32_to_cpu(p->max_bs[i]);
+ }
+
+ p->numjobs = le32_to_cpu(p->numjobs);
+ p->group_reporting = le32_to_cpu(p->group_reporting);
+
+ gtk_label_set_text(GTK_LABEL(ui->eta.name), (gchar *) p->jobname);
+ gtk_label_set_text(GTK_LABEL(ui->eta.iotype), ddir_str(p->rw));
+ gtk_label_set_text(GTK_LABEL(ui->eta.ioengine), (gchar *) p->ioengine);
+
+ sprintf(tmp, "%u", p->iodepth);
+ gtk_label_set_text(GTK_LABEL(ui->eta.iodepth), tmp);
+}
+
+static void gfio_client_timed_out(struct fio_client *client)
+{
+ struct gui *ui = client->client_data;
+ GtkWidget *dialog, *label, *content;
+ char buf[256];
+
+ gdk_threads_enter();
+
+ gfio_set_connected(ui, 0);
+ clear_ui_info(ui);
+
+ sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
+
+ dialog = gtk_dialog_new_with_buttons("Timed out!",
+ GTK_WINDOW(ui->window),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+ content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ label = gtk_label_new((const gchar *) buf);
+ gtk_container_add(GTK_CONTAINER(content), label);
+ gtk_widget_show_all(dialog);
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
+
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+
+ gdk_threads_leave();
+}
+
struct client_ops gfio_client_ops = {
.text_op = gfio_text_op,
.disk_util = gfio_disk_util_op,
.group_stats = gfio_group_stats_op,
.eta = gfio_eta_op,
.probe = gfio_probe_op,
+ .quit = gfio_quit_op,
+ .add_job = gfio_add_job_op,
+ .timed_out = gfio_client_timed_out,
+ .stay_connected = 1,
};
static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
static void *job_thread(void *arg)
{
- struct gui *ui = arg;
-
fio_handle_clients(&gfio_client_ops);
- gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
return NULL;
}
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 GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
+{
+ GtkWidget *label_widget;
+ GtkWidget *frame;
+
+ frame = gtk_frame_new(label);
+ label_widget = gtk_label_new(NULL);
+ gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
+ gtk_container_add(GTK_CONTAINER(frame), label_widget);
+
+ return label_widget;
+}
+
+static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
+{
+ GtkWidget *button, *box;
+
+ 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 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)
+static void file_open(GtkWidget *w, gpointer data);
+
+static void connect_clicked(GtkWidget *widget, gpointer data)
{
- fio_clients_connect();
- gtk_widget_set_sensitive(ui.button[START_JOB_BUTTON], 1);
+ struct gui *ui = data;
+
+ if (!ui->connected) {
+ 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);
+ gfio_set_connected(ui, 1);
+ } else {
+ fio_clients_terminate();
+ gfio_set_connected(ui, 0);
+ clear_ui_info(ui);
+ }
}
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);
}
}
}
-void report_error(GError* error)
+void report_error(GError *error)
{
if (ui.error_info_bar == NULL) {
ui.error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
}
}
+static int get_connection_details(char **host, int *port, int *type,
+ int *server_start)
+{
+ GtkWidget *dialog, *box, *vbox, *hentry, *hbox, *frame, *pentry, *combo;
+ GtkWidget *button;
+ char *typeentry;
+
+ dialog = gtk_dialog_new_with_buttons("Connection details",
+ GTK_WINDOW(ui.window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
+
+ frame = gtk_frame_new("Hostname / socket name");
+ vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
+
+ box = gtk_vbox_new(FALSE, 6);
+ gtk_container_add(GTK_CONTAINER(frame), box);
+
+ hbox = gtk_hbox_new(TRUE, 10);
+ gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
+ hentry = gtk_entry_new();
+ gtk_entry_set_text(GTK_ENTRY(hentry), "localhost");
+ gtk_box_pack_start(GTK_BOX(hbox), hentry, TRUE, TRUE, 0);
+
+ frame = gtk_frame_new("Port");
+ gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
+ box = gtk_vbox_new(FALSE, 10);
+ gtk_container_add(GTK_CONTAINER(frame), box);
+
+ hbox = gtk_hbox_new(TRUE, 4);
+ gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
+ pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
+
+ frame = gtk_frame_new("Type");
+ gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
+ box = gtk_vbox_new(FALSE, 10);
+ gtk_container_add(GTK_CONTAINER(frame), box);
+
+ 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");
+ gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
+
+ gtk_container_add(GTK_CONTAINER(hbox), combo);
+
+ frame = gtk_frame_new("Options");
+ gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
+ box = gtk_vbox_new(FALSE, 10);
+ gtk_container_add(GTK_CONTAINER(frame), box);
+
+ hbox = gtk_hbox_new(TRUE, 4);
+ gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
+
+ button = gtk_check_button_new_with_label("Auto-spawn fio backend");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), 1);
+ gtk_widget_set_tooltip_text(button, "When running fio locally, it is necessary to have the backend running on the same system. If this is checked, gfio will start the backend automatically for you if it isn't already running.");
+ gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 6);
+
+ gtk_widget_show_all(dialog);
+
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
+ gtk_widget_destroy(dialog);
+ return 1;
+ }
+
+ *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));
+ 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);
+
+ *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
+
+ gtk_widget_destroy(dialog);
+ return 0;
+}
+
static void file_open(GtkWidget *w, gpointer data)
{
GtkWidget *dialog;
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),
}
fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
+
+ gtk_widget_destroy(dialog);
+
+ if (get_connection_details(&host, &port, &type, &server_start))
+ goto err;
+
filenames = fn_glist;
while (filenames != NULL) {
- const char *hostname;
-
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);
-#if 0
- if (error) {
+ ui.client = fio_client_add_explicit(host, type, port);
+ if (!ui.client) {
+ GError *error;
+
+ error = g_error_new(g_quark_from_string("fio"), 1,
+ "Failed to add client %s", host);
report_error(error);
g_error_free(error);
- error = NULL;
}
-#endif
+ ui.client->client_data = &ui;
g_free(filenames->data);
filenames = g_slist_next(filenames);
}
+ free(host);
+err:
g_slist_free(fn_glist);
- gtk_widget_destroy(dialog);
}
static void file_save(GtkWidget *w, gpointer data)
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
}
-static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
-{
- GtkWidget *label_widget;
- GtkWidget *frame;
-
- frame = gtk_frame_new(label);
- label_widget = gtk_label_new(NULL);
- gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
- gtk_container_add(GTK_CONTAINER(frame), label_widget);
-
- return label_widget;
-}
-
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;
* Without it, the update that happens in gfio_update_thread_status
* doesn't really happen in a timely fashion, you need expose events
*/
- if (!g_thread_supported ())
+ if (!g_thread_supported())
g_thread_init(NULL);
gdk_threads_init();
* 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);
- /*
- * 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->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);
-
- /*
- * 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);
-
probe = gtk_frame_new("Job");
gtk_box_pack_start(GTK_BOX(ui->topvbox), probe, TRUE, FALSE, 3);
probe_frame = gtk_vbox_new(FALSE, 3);
probe_box = gtk_hbox_new(FALSE, 3);
gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
+
+ ui->eta.name = new_info_label_in_frame(probe_box, "Name");
+ ui->eta.iotype = new_info_label_in_frame(probe_box, "IO");
+ ui->eta.ioengine = new_info_label_in_frame(probe_box, "IO Engine");
+ ui->eta.iodepth = new_info_label_in_frame(probe_box, "IO Depth");
ui->eta.jobs = new_info_label_in_frame(probe_box, "Jobs");
ui->eta.files = new_info_label_in_frame(probe_box, "Open files");
gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
ui->eta.read_bw = new_info_label_in_frame(probe_box, "Read BW");
ui->eta.read_iops = new_info_label_in_frame(probe_box, "IOPS");
- ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
- ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
-
- probe_box = gtk_hbox_new(FALSE, 3);
- gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
ui->eta.write_bw = new_info_label_in_frame(probe_box, "Write BW");
ui->eta.write_iops = new_info_label_in_frame(probe_box, "IOPS");
- 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
+ * Only add this if we have a commit rate
*/
- 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);
+#if 0
+ probe_box = gtk_hbox_new(FALSE, 3);
+ gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
+
+ ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
+ ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
+
+ 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");
+#endif
/*
* Add a text box for text op messages
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 connections");
+ gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
+
+
gtk_widget_show_all(ui->window);
}