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