blob: db59f4f25df8f73e378d908793d4d79344ed6267 [file] [log] [blame]
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001/*
2 * gfio - gui front end for fio - the flexible io tester
3 *
4 * Copyright (C) 2012 Stephen M. Cameron <stephenmcameron@gmail.com>
Jens Axboec0187f32012-03-06 15:39:15 +01005 * Copyright (C) 2012 Jens Axboe <axboe@kernel.dk>
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01006 *
7 * The license below covers all files distributed with fio unless otherwise
8 * noted in the file itself.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
Stephen M. Cameron8232e282012-02-24 08:17:31 +010024#include <locale.h>
Stephen M. Cameron60f6b332012-02-24 08:17:32 +010025#include <malloc.h>
Jens Axboe6b79c802012-03-08 10:51:36 +010026#include <string.h>
Stephen M. Cameron8232e282012-02-24 08:17:31 +010027
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +010028#include <glib.h>
Jens Axboe2fd3bb02012-03-07 08:07:39 +010029#include <cairo.h>
Stephen M. Cameronff1f3282012-02-24 08:17:30 +010030#include <gtk/gtk.h>
31
Stephen M. Cameron8232e282012-02-24 08:17:31 +010032#include "fio.h"
Jens Axboe2fd3bb02012-03-07 08:07:39 +010033#include "graph.h"
Stephen M. Cameron8232e282012-02-24 08:17:31 +010034
Jens Axboe63a130b2012-03-06 20:08:59 +010035static int gfio_server_running;
Jens Axboef3e84402012-03-07 13:14:32 +010036static const char *gfio_graph_font;
Jens Axboe63a130b2012-03-06 20:08:59 +010037
Jens Axboe6b79c802012-03-08 10:51:36 +010038static void view_log(GtkWidget *w, gpointer data);
Jens Axboe3e47bd22012-02-29 13:45:02 +010039
Stephen M. Cameronf3074002012-02-24 08:17:30 +010040#define ARRAYSIZE(x) (sizeof((x)) / (sizeof((x)[0])))
41
42typedef void (*clickfunction)(GtkWidget *widget, gpointer data);
43
Jens Axboe3e47bd22012-02-29 13:45:02 +010044static void connect_clicked(GtkWidget *widget, gpointer data);
Stephen M. Cameronf3074002012-02-24 08:17:30 +010045static void start_job_clicked(GtkWidget *widget, gpointer data);
Jens Axboeb9d2f302012-03-08 20:36:28 +010046static void send_clicked(GtkWidget *widget, gpointer data);
Stephen M. Cameronf3074002012-02-24 08:17:30 +010047
48static struct button_spec {
49 const char *buttontext;
50 clickfunction f;
51 const char *tooltiptext;
Jens Axboe3e47bd22012-02-29 13:45:02 +010052 const int start_insensitive;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010053} buttonspeclist[] = {
Jens Axboe3e47bd22012-02-29 13:45:02 +010054#define CONNECT_BUTTON 0
Jens Axboeb9d2f302012-03-08 20:36:28 +010055#define SEND_BUTTON 1
56#define START_JOB_BUTTON 2
Jens Axboe3e47bd22012-02-29 13:45:02 +010057 { "Connect", connect_clicked, "Connect to host", 0 },
Jens Axboeb9d2f302012-03-08 20:36:28 +010058 { "Send", send_clicked, "Send job description to host", 1 },
59 { "Start Job", start_job_clicked,
Jens Axboe2f99deb2012-03-09 14:37:29 +010060 "Start the current job on the server", 1 },
Stephen M. Cameronf3074002012-02-24 08:17:30 +010061};
62
Jens Axboe843ad232012-02-29 11:44:53 +010063struct probe_widget {
64 GtkWidget *hostname;
65 GtkWidget *os;
66 GtkWidget *arch;
67 GtkWidget *fio_ver;
68};
69
Jens Axboe3e47bd22012-02-29 13:45:02 +010070struct eta_widget {
Jens Axboe3863d1a2012-03-09 17:39:05 +010071 GtkWidget *names;
Jens Axboe807f9972012-03-02 10:25:24 +010072 GtkWidget *iotype;
73 GtkWidget *ioengine;
74 GtkWidget *iodepth;
Jens Axboe3e47bd22012-02-29 13:45:02 +010075 GtkWidget *jobs;
76 GtkWidget *files;
77 GtkWidget *read_bw;
78 GtkWidget *read_iops;
79 GtkWidget *cr_bw;
80 GtkWidget *cr_iops;
81 GtkWidget *write_bw;
82 GtkWidget *write_iops;
83 GtkWidget *cw_bw;
84 GtkWidget *cw_iops;
85};
86
Jens Axboe2f99deb2012-03-09 14:37:29 +010087struct gfio_graphs {
88#define DRAWING_AREA_XDIM 1000
89#define DRAWING_AREA_YDIM 400
90 GtkWidget *drawing_area;
91 int drawing_area_xdim;
92 int drawing_area_ydim;
93
94 struct graph *iops_graph;
95 struct graph *bandwidth_graph;
96};
97
98/*
99 * Main window widgets and data
100 */
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100101struct gui {
102 GtkWidget *window;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100103 GtkWidget *vbox;
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +0100104 GtkWidget *topvbox;
105 GtkWidget *topalign;
106 GtkWidget *bottomalign;
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +0100107 GtkWidget *thread_status_pb;
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100108 GtkWidget *buttonbox;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100109 GtkWidget *scrolled_window;
110 GtkWidget *notebook;
111 GtkWidget *error_info_bar;
112 GtkWidget *error_label;
113 GtkListStore *log_model;
114 GtkWidget *log_tree;
115 GtkWidget *log_view;
116 struct gfio_graphs graphs;
117 struct probe_widget probe;
118 struct eta_widget eta;
119 pthread_t server_t;
120
Jens Axboea9eccde2012-03-09 14:59:42 +0100121 pthread_t t;
122 int handler_running;
123
Jens Axboe2f99deb2012-03-09 14:37:29 +0100124 struct flist_head list;
125} main_ui;
126
127/*
128 * Notebook entry
129 */
130struct gui_entry {
131 struct flist_head list;
132 struct gui *ui;
133
134 GtkWidget *vbox;
135 GtkWidget *topvbox;
136 GtkWidget *topalign;
137 GtkWidget *bottomalign;
138 GtkWidget *thread_status_pb;
139 GtkWidget *buttonbox;
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100140 GtkWidget *button[ARRAYSIZE(buttonspeclist)];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100141 GtkWidget *scrolled_window;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100142 GtkWidget *notebook;
Jens Axboe0420ba62012-02-29 11:16:52 +0100143 GtkWidget *error_info_bar;
144 GtkWidget *error_label;
Jens Axboef9d40b42012-03-06 09:52:49 +0100145 GtkWidget *results_notebook;
146 GtkWidget *results_window;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100147 GtkListStore *log_model;
148 GtkWidget *log_tree;
Jens Axboe4cbe7212012-03-06 13:36:17 +0100149 GtkWidget *log_view;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100150 struct gfio_graphs graphs;
Jens Axboe843ad232012-02-29 11:44:53 +0100151 struct probe_widget probe;
Jens Axboe3e47bd22012-02-29 13:45:02 +0100152 struct eta_widget eta;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100153 GtkWidget *page_label;
154 gint page_num;
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100155 int connected;
Jens Axboe0420ba62012-02-29 11:16:52 +0100156
Jens Axboeb9d2f302012-03-08 20:36:28 +0100157 struct gfio_client *client;
Jens Axboe0420ba62012-02-29 11:16:52 +0100158 int nr_job_files;
159 char **job_files;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100160};
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100161
Jens Axboee0681f32012-03-06 12:14:42 +0100162struct gfio_client {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100163 struct gui_entry *ge;
Jens Axboeb9d2f302012-03-08 20:36:28 +0100164 struct fio_client *client;
Jens Axboee0681f32012-03-06 12:14:42 +0100165 GtkWidget *results_widget;
166 GtkWidget *disk_util_frame;
Jens Axboe6b79c802012-03-08 10:51:36 +0100167 GtkWidget *err_entry;
Jens Axboedcaeb602012-03-08 19:45:37 +0100168 unsigned int job_added;
169 struct thread_options o;
Jens Axboee0681f32012-03-06 12:14:42 +0100170};
171
Jens Axboe9988ca72012-03-09 15:14:06 +0100172static void gfio_update_thread_status(struct gui_entry *ge, char *status_message, double perc);
173static void gfio_update_thread_status_all(char *status_message, double perc);
Jens Axboec7249262012-03-09 17:11:04 +0100174void report_error(GError *error);
Jens Axboe9988ca72012-03-09 15:14:06 +0100175
Jens Axboe2f99deb2012-03-09 14:37:29 +0100176static struct graph *setup_iops_graph(void)
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100177{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100178 struct graph *g;
179
180 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
181 graph_title(g, "IOPS");
182 graph_x_title(g, "Time (secs)");
183 graph_y_title(g, "IOs / sec");
184 graph_add_label(g, "Read IOPS");
185 graph_add_label(g, "Write IOPS");
186 graph_set_color(g, "Read IOPS", 0.13, 0.54, 0.13);
187 graph_set_color(g, "Write IOPS", 1.0, 0.0, 0.0);
188 line_graph_set_data_count_limit(g, 100);
189 return g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100190}
191
Jens Axboe2f99deb2012-03-09 14:37:29 +0100192static struct graph *setup_bandwidth_graph(void)
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100193{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100194 struct graph *g;
195
196 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
197 graph_title(g, "Bandwidth");
198 graph_x_title(g, "Time (secs)");
199 graph_y_title(g, "Kbytes / sec");
200 graph_add_label(g, "Read Bandwidth");
201 graph_add_label(g, "Write Bandwidth");
202 graph_set_color(g, "Read Bandwidth", 0.13, 0.54, 0.13);
203 graph_set_color(g, "Write Bandwidth", 1.0, 0.0, 0.0);
204 line_graph_set_data_count_limit(g, 100);
205 return g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100206}
207
Jens Axboe2f99deb2012-03-09 14:37:29 +0100208static void setup_graphs(struct gfio_graphs *g)
Jens Axboe8663ea62012-03-02 14:04:30 +0100209{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100210 g->iops_graph = setup_iops_graph();
211 g->bandwidth_graph = setup_bandwidth_graph();
212}
213
214static void clear_ge_ui_info(struct gui_entry *ge)
215{
216 gtk_label_set_text(GTK_LABEL(ge->probe.hostname), "");
217 gtk_label_set_text(GTK_LABEL(ge->probe.os), "");
218 gtk_label_set_text(GTK_LABEL(ge->probe.arch), "");
219 gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100220#if 0
221 /* should we empty it... */
Jens Axboe2f99deb2012-03-09 14:37:29 +0100222 gtk_entry_set_text(GTK_ENTRY(ge->eta.name), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100223#endif
Jens Axboe2f99deb2012-03-09 14:37:29 +0100224 gtk_entry_set_text(GTK_ENTRY(ge->eta.iotype), "");
225 gtk_entry_set_text(GTK_ENTRY(ge->eta.ioengine), "");
226 gtk_entry_set_text(GTK_ENTRY(ge->eta.iodepth), "");
227 gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), "");
228 gtk_entry_set_text(GTK_ENTRY(ge->eta.files), "");
229 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), "");
230 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), "");
231 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), "");
232 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100233}
234
Jens Axboe3863d1a2012-03-09 17:39:05 +0100235static GtkWidget *new_combo_entry_in_frame(GtkWidget *box, const char *label)
236{
237 GtkWidget *entry, *frame;
238
239 frame = gtk_frame_new(label);
240 entry = gtk_combo_box_new_text();
241 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
242 gtk_container_add(GTK_CONTAINER(frame), entry);
243
244 return entry;
245}
246
Jens Axboe3650a3c2012-03-05 14:09:03 +0100247static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
248{
249 GtkWidget *entry, *frame;
250
251 frame = gtk_frame_new(label);
252 entry = gtk_entry_new();
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100253 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100254 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
255 gtk_container_add(GTK_CONTAINER(frame), entry);
256
257 return entry;
258}
259
260static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
261{
262 GtkWidget *label_widget;
263 GtkWidget *frame;
264
265 frame = gtk_frame_new(label);
266 label_widget = gtk_label_new(NULL);
267 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
268 gtk_container_add(GTK_CONTAINER(frame), label_widget);
269
270 return label_widget;
271}
272
273static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
274{
275 GtkWidget *button, *box;
276
277 box = gtk_hbox_new(FALSE, 3);
278 gtk_container_add(GTK_CONTAINER(hbox), box);
279
280 button = gtk_spin_button_new_with_range(min, max, 1.0);
281 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
282
283 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
284 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
285
286 return button;
287}
288
Jens Axboe2f99deb2012-03-09 14:37:29 +0100289static void gfio_set_connected(struct gui_entry *ge, int connected)
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100290{
291 if (connected) {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100292 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 1);
293 ge->connected = 1;
294 gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), "Disconnect");
295 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100296 } else {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100297 ge->connected = 0;
298 gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), "Connect");
299 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 0);
300 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 0);
301 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100302 }
303}
304
Jens Axboe3650a3c2012-03-05 14:09:03 +0100305static void label_set_int_value(GtkWidget *entry, unsigned int val)
306{
307 char tmp[80];
308
309 sprintf(tmp, "%u", val);
310 gtk_label_set_text(GTK_LABEL(entry), tmp);
311}
312
313static void entry_set_int_value(GtkWidget *entry, unsigned int val)
314{
315 char tmp[80];
316
317 sprintf(tmp, "%u", val);
318 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
319}
320
Jens Axboea2697902012-03-05 16:43:49 +0100321#define ALIGN_LEFT 1
322#define ALIGN_RIGHT 2
323#define INVISIBLE 4
324#define UNSORTABLE 8
325
326GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
327{
328 GtkCellRenderer *renderer;
329 GtkTreeViewColumn *col;
330 double xalign = 0.0; /* left as default */
331 PangoAlignment align;
332 gboolean visible;
333
334 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
335 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
336 PANGO_ALIGN_CENTER;
337 visible = !(flags & INVISIBLE);
338
339 renderer = gtk_cell_renderer_text_new();
340 col = gtk_tree_view_column_new();
341
342 gtk_tree_view_column_set_title(col, title);
343 if (!(flags & UNSORTABLE))
344 gtk_tree_view_column_set_sort_column_id(col, index);
345 gtk_tree_view_column_set_resizable(col, TRUE);
346 gtk_tree_view_column_pack_start(col, renderer, TRUE);
347 gtk_tree_view_column_add_attribute(col, renderer, "text", index);
348 gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
349 switch (align) {
350 case PANGO_ALIGN_LEFT:
351 xalign = 0.0;
352 break;
353 case PANGO_ALIGN_CENTER:
354 xalign = 0.5;
355 break;
356 case PANGO_ALIGN_RIGHT:
357 xalign = 1.0;
358 break;
359 }
360 gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
361 gtk_tree_view_column_set_visible(col, visible);
362 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
363 return col;
364}
365
Jens Axboe9b260bd2012-03-06 11:02:52 +0100366static void gfio_ui_setup_log(struct gui *ui)
367{
368 GtkTreeSelection *selection;
369 GtkListStore *model;
370 GtkWidget *tree_view;
371
372 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
373
374 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
375 gtk_widget_set_can_focus(tree_view, FALSE);
376
377 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
378 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
Jens Axboe661f7412012-03-06 13:55:45 +0100379 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
380 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100381
382 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
383 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
384 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
Jens Axboef095d562012-03-06 13:49:12 +0100385 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100386
387 ui->log_model = model;
388 ui->log_tree = tree_view;
389}
390
Jens Axboea2697902012-03-05 16:43:49 +0100391static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
392 fio_fp64_t *plist,
393 unsigned int len,
394 const char *base,
395 unsigned int scale)
396{
397 GType types[FIO_IO_U_LIST_MAX_LEN];
398 GtkWidget *tree_view;
399 GtkTreeSelection *selection;
400 GtkListStore *model;
401 GtkTreeIter iter;
402 int i;
403
404 for (i = 0; i < len; i++)
405 types[i] = G_TYPE_INT;
406
407 model = gtk_list_store_newv(len, types);
408
409 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
410 gtk_widget_set_can_focus(tree_view, FALSE);
411
Jens Axboe661f7412012-03-06 13:55:45 +0100412 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
413 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
414
Jens Axboea2697902012-03-05 16:43:49 +0100415 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
416 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
417
418 for (i = 0; i < len; i++) {
419 char fbuf[8];
420
421 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
422 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
423 }
424
425 gtk_list_store_append(model, &iter);
426
Jens Axboee0681f32012-03-06 12:14:42 +0100427 for (i = 0; i < len; i++) {
428 if (scale)
429 ovals[i] = (ovals[i] + 999) / 1000;
Jens Axboea2697902012-03-05 16:43:49 +0100430 gtk_list_store_set(model, &iter, i, ovals[i], -1);
Jens Axboee0681f32012-03-06 12:14:42 +0100431 }
Jens Axboea2697902012-03-05 16:43:49 +0100432
433 return tree_view;
434}
435
436static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
437 int ddir)
438{
439 unsigned int *io_u_plat = ts->io_u_plat[ddir];
440 unsigned long nr = ts->clat_stat[ddir].samples;
441 fio_fp64_t *plist = ts->percentile_list;
442 unsigned int *ovals, len, minv, maxv, scale_down;
443 const char *base;
444 GtkWidget *tree_view, *frame, *hbox;
445 char tmp[64];
446
447 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
448 if (!len)
449 goto out;
450
451 /*
452 * We default to usecs, but if the value range is such that we
453 * should scale down to msecs, do that.
454 */
455 if (minv > 2000 && maxv > 99999) {
456 scale_down = 1;
457 base = "msec";
458 } else {
459 scale_down = 0;
460 base = "usec";
461 }
462
463 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
464
465 sprintf(tmp, "Completion percentiles (%s)", base);
466 frame = gtk_frame_new(tmp);
467 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
468
469 hbox = gtk_hbox_new(FALSE, 3);
470 gtk_container_add(GTK_CONTAINER(frame), hbox);
471
472 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
473out:
474 if (ovals)
475 free(ovals);
476}
477
Jens Axboe3650a3c2012-03-05 14:09:03 +0100478static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
479 unsigned long max, double mean, double dev)
480{
481 const char *base = "(usec)";
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100482 GtkWidget *hbox, *label, *frame;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100483 char *minp, *maxp;
484 char tmp[64];
485
486 if (!usec_to_msec(&min, &max, &mean, &dev))
487 base = "(msec)";
488
489 minp = num2str(min, 6, 1, 0);
490 maxp = num2str(max, 6, 1, 0);
491
Jens Axboe3650a3c2012-03-05 14:09:03 +0100492 sprintf(tmp, "%s %s", name, base);
493 frame = gtk_frame_new(tmp);
494 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
495
Jens Axboe3650a3c2012-03-05 14:09:03 +0100496 hbox = gtk_hbox_new(FALSE, 3);
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100497 gtk_container_add(GTK_CONTAINER(frame), hbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100498
499 label = new_info_label_in_frame(hbox, "Minimum");
500 gtk_label_set_text(GTK_LABEL(label), minp);
501 label = new_info_label_in_frame(hbox, "Maximum");
502 gtk_label_set_text(GTK_LABEL(label), maxp);
503 label = new_info_label_in_frame(hbox, "Average");
504 sprintf(tmp, "%5.02f", mean);
505 gtk_label_set_text(GTK_LABEL(label), tmp);
506 label = new_info_label_in_frame(hbox, "Standard deviation");
507 sprintf(tmp, "%5.02f", dev);
508 gtk_label_set_text(GTK_LABEL(label), tmp);
509
510 free(minp);
511 free(maxp);
512
513}
514
Jens Axboeca850992012-03-05 20:04:43 +0100515#define GFIO_CLAT 1
516#define GFIO_SLAT 2
517#define GFIO_LAT 4
518
Jens Axboe3650a3c2012-03-05 14:09:03 +0100519static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
520 struct thread_stat *ts, int ddir)
521{
522 const char *ddir_label[2] = { "Read", "Write" };
Jens Axboe0b761302012-03-05 20:44:11 +0100523 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
Jens Axboee0681f32012-03-06 12:14:42 +0100524 unsigned long min[3], max[3], runt;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100525 unsigned long long bw, iops;
Jens Axboeca850992012-03-05 20:04:43 +0100526 unsigned int flags = 0;
Jens Axboee0681f32012-03-06 12:14:42 +0100527 double mean[3], dev[3];
Jens Axboe3650a3c2012-03-05 14:09:03 +0100528 char *io_p, *bw_p, *iops_p;
529 int i2p;
530
531 if (!ts->runtime[ddir])
532 return;
533
534 i2p = is_power_of_2(rs->kb_base);
535 runt = ts->runtime[ddir];
536
537 bw = (1000 * ts->io_bytes[ddir]) / runt;
538 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
539 bw_p = num2str(bw, 6, 1, i2p);
540
541 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
542 iops_p = num2str(iops, 6, 1, 0);
543
544 box = gtk_hbox_new(FALSE, 3);
545 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
546
547 frame = gtk_frame_new(ddir_label[ddir]);
548 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
549
Jens Axboe0b761302012-03-05 20:44:11 +0100550 main_vbox = gtk_vbox_new(FALSE, 3);
551 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100552
553 box = gtk_hbox_new(FALSE, 3);
Jens Axboe0b761302012-03-05 20:44:11 +0100554 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100555
556 label = new_info_label_in_frame(box, "IO");
557 gtk_label_set_text(GTK_LABEL(label), io_p);
558 label = new_info_label_in_frame(box, "Bandwidth");
559 gtk_label_set_text(GTK_LABEL(label), bw_p);
560 label = new_info_label_in_frame(box, "IOPS");
561 gtk_label_set_text(GTK_LABEL(label), iops_p);
562 label = new_info_label_in_frame(box, "Runtime (msec)");
563 label_set_int_value(label, ts->runtime[ddir]);
564
Jens Axboee0681f32012-03-06 12:14:42 +0100565 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
Jens Axboeca850992012-03-05 20:04:43 +0100566 double p_of_agg = 100.0;
567 const char *bw_str = "KB";
568 char tmp[32];
569
570 if (rs->agg[ddir]) {
Jens Axboee0681f32012-03-06 12:14:42 +0100571 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
Jens Axboeca850992012-03-05 20:04:43 +0100572 if (p_of_agg > 100.0)
573 p_of_agg = 100.0;
574 }
575
Jens Axboee0681f32012-03-06 12:14:42 +0100576 if (mean[0] > 999999.9) {
577 min[0] /= 1000.0;
578 max[0] /= 1000.0;
579 mean[0] /= 1000.0;
580 dev[0] /= 1000.0;
Jens Axboeca850992012-03-05 20:04:43 +0100581 bw_str = "MB";
582 }
583
Jens Axboe0b761302012-03-05 20:44:11 +0100584 sprintf(tmp, "Bandwidth (%s)", bw_str);
585 frame = gtk_frame_new(tmp);
586 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
Jens Axboeca850992012-03-05 20:04:43 +0100587
Jens Axboe0b761302012-03-05 20:44:11 +0100588 box = gtk_hbox_new(FALSE, 3);
589 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboeca850992012-03-05 20:04:43 +0100590
Jens Axboe0b761302012-03-05 20:44:11 +0100591 label = new_info_label_in_frame(box, "Minimum");
Jens Axboee0681f32012-03-06 12:14:42 +0100592 label_set_int_value(label, min[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100593 label = new_info_label_in_frame(box, "Maximum");
Jens Axboee0681f32012-03-06 12:14:42 +0100594 label_set_int_value(label, max[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100595 label = new_info_label_in_frame(box, "Percentage of jobs");
Jens Axboeca850992012-03-05 20:04:43 +0100596 sprintf(tmp, "%3.2f%%", p_of_agg);
597 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100598 label = new_info_label_in_frame(box, "Average");
Jens Axboee0681f32012-03-06 12:14:42 +0100599 sprintf(tmp, "%5.02f", mean[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100600 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100601 label = new_info_label_in_frame(box, "Standard deviation");
Jens Axboee0681f32012-03-06 12:14:42 +0100602 sprintf(tmp, "%5.02f", dev[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100603 gtk_label_set_text(GTK_LABEL(label), tmp);
604 }
605
Jens Axboee0681f32012-03-06 12:14:42 +0100606 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
Jens Axboe2b089892012-03-06 08:09:17 +0100607 flags |= GFIO_SLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100608 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
Jens Axboe2b089892012-03-06 08:09:17 +0100609 flags |= GFIO_CLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100610 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
Jens Axboe2b089892012-03-06 08:09:17 +0100611 flags |= GFIO_LAT;
612
613 if (flags) {
614 frame = gtk_frame_new("Latency");
615 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
616
617 vbox = gtk_vbox_new(FALSE, 3);
618 gtk_container_add(GTK_CONTAINER(frame), vbox);
619
620 if (flags & GFIO_SLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100621 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
Jens Axboe2b089892012-03-06 08:09:17 +0100622 if (flags & GFIO_CLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100623 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
Jens Axboe2b089892012-03-06 08:09:17 +0100624 if (flags & GFIO_LAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100625 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
Jens Axboe2b089892012-03-06 08:09:17 +0100626 }
627
628 if (ts->clat_percentiles)
629 gfio_show_clat_percentiles(main_vbox, ts, ddir);
630
631
Jens Axboe3650a3c2012-03-05 14:09:03 +0100632 free(io_p);
633 free(bw_p);
634 free(iops_p);
635}
636
Jens Axboee5bd1342012-03-05 21:38:12 +0100637static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
638 const char **labels)
639{
640 GtkWidget *tree_view;
641 GtkTreeSelection *selection;
642 GtkListStore *model;
643 GtkTreeIter iter;
644 GType *types;
645 int i, skipped;
646
647 /*
648 * Check if all are empty, in which case don't bother
649 */
650 for (i = 0, skipped = 0; i < num; i++)
651 if (lat[i] <= 0.0)
652 skipped++;
653
654 if (skipped == num)
655 return NULL;
656
657 types = malloc(num * sizeof(GType));
658
659 for (i = 0; i < num; i++)
660 types[i] = G_TYPE_STRING;
661
662 model = gtk_list_store_newv(num, types);
663 free(types);
664 types = NULL;
665
666 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
667 gtk_widget_set_can_focus(tree_view, FALSE);
668
Jens Axboe661f7412012-03-06 13:55:45 +0100669 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
670 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
671
Jens Axboee5bd1342012-03-05 21:38:12 +0100672 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
673 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
674
675 for (i = 0; i < num; i++)
676 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
677
678 gtk_list_store_append(model, &iter);
679
680 for (i = 0; i < num; i++) {
681 char fbuf[32];
682
683 if (lat[i] <= 0.0)
684 sprintf(fbuf, "0.00");
685 else
686 sprintf(fbuf, "%3.2f%%", lat[i]);
687
688 gtk_list_store_set(model, &iter, i, fbuf, -1);
689 }
690
691 return tree_view;
692}
693
694static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
695{
696 GtkWidget *box, *frame, *tree_view;
697 double io_u_lat_u[FIO_IO_U_LAT_U_NR];
698 double io_u_lat_m[FIO_IO_U_LAT_M_NR];
699 const char *uranges[] = { "2", "4", "10", "20", "50", "100",
700 "250", "500", "750", "1000", };
701 const char *mranges[] = { "2", "4", "10", "20", "50", "100",
702 "250", "500", "750", "1000", "2000",
703 ">= 2000", };
704
705 stat_calc_lat_u(ts, io_u_lat_u);
706 stat_calc_lat_m(ts, io_u_lat_m);
707
708 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
709 if (tree_view) {
710 frame = gtk_frame_new("Latency buckets (usec)");
711 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
712
713 box = gtk_hbox_new(FALSE, 3);
714 gtk_container_add(GTK_CONTAINER(frame), box);
715 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
716 }
717
718 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
719 if (tree_view) {
720 frame = gtk_frame_new("Latency buckets (msec)");
721 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
722
723 box = gtk_hbox_new(FALSE, 3);
724 gtk_container_add(GTK_CONTAINER(frame), box);
725 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
726 }
727}
728
Jens Axboe2e331012012-03-05 22:07:54 +0100729static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
730{
731 GtkWidget *box, *frame, *entry;
732 double usr_cpu, sys_cpu;
733 unsigned long runtime;
734 char tmp[32];
735
736 runtime = ts->total_run_time;
737 if (runtime) {
738 double runt = (double) runtime;
739
740 usr_cpu = (double) ts->usr_time * 100 / runt;
741 sys_cpu = (double) ts->sys_time * 100 / runt;
742 } else {
743 usr_cpu = 0;
744 sys_cpu = 0;
745 }
746
747 frame = gtk_frame_new("OS resources");
748 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
749
750 box = gtk_hbox_new(FALSE, 3);
751 gtk_container_add(GTK_CONTAINER(frame), box);
752
753 entry = new_info_entry_in_frame(box, "User CPU");
754 sprintf(tmp, "%3.2f%%", usr_cpu);
755 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
756 entry = new_info_entry_in_frame(box, "System CPU");
757 sprintf(tmp, "%3.2f%%", sys_cpu);
758 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
759 entry = new_info_entry_in_frame(box, "Context switches");
760 entry_set_int_value(entry, ts->ctx);
761 entry = new_info_entry_in_frame(box, "Major faults");
762 entry_set_int_value(entry, ts->majf);
763 entry = new_info_entry_in_frame(box, "Minor faults");
764 entry_set_int_value(entry, ts->minf);
765}
Jens Axboe19998db2012-03-06 09:17:59 +0100766static void gfio_add_sc_depths_tree(GtkListStore *model,
767 struct thread_stat *ts, unsigned int len,
768 int submit)
769{
770 double io_u_dist[FIO_IO_U_MAP_NR];
771 GtkTreeIter iter;
772 /* Bits 0, and 3-8 */
773 const int add_mask = 0x1f9;
774 int i, j;
775
776 if (submit)
777 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
778 else
779 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
780
781 gtk_list_store_append(model, &iter);
782
783 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
784
785 for (i = 1, j = 0; i < len; i++) {
786 char fbuf[32];
787
788 if (!(add_mask & (1UL << (i - 1))))
789 sprintf(fbuf, "0.0%%");
790 else {
791 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
792 j++;
793 }
794
795 gtk_list_store_set(model, &iter, i, fbuf, -1);
796 }
797
798}
799
800static void gfio_add_total_depths_tree(GtkListStore *model,
801 struct thread_stat *ts, unsigned int len)
802{
803 double io_u_dist[FIO_IO_U_MAP_NR];
804 GtkTreeIter iter;
805 /* Bits 1-6, and 8 */
806 const int add_mask = 0x17e;
807 int i, j;
808
809 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
810
811 gtk_list_store_append(model, &iter);
812
813 gtk_list_store_set(model, &iter, 0, "Total", -1);
814
815 for (i = 1, j = 0; i < len; i++) {
816 char fbuf[32];
817
818 if (!(add_mask & (1UL << (i - 1))))
819 sprintf(fbuf, "0.0%%");
820 else {
821 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
822 j++;
823 }
824
825 gtk_list_store_set(model, &iter, i, fbuf, -1);
826 }
827
828}
Jens Axboe2e331012012-03-05 22:07:54 +0100829
830static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
831{
Jens Axboe2e331012012-03-05 22:07:54 +0100832 GtkWidget *frame, *box, *tree_view;
833 GtkTreeSelection *selection;
834 GtkListStore *model;
Jens Axboe2e331012012-03-05 22:07:54 +0100835 GType types[FIO_IO_U_MAP_NR + 1];
836 int i;
Jens Axboe19998db2012-03-06 09:17:59 +0100837#define NR_LABELS 10
838 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
Jens Axboe2e331012012-03-05 22:07:54 +0100839
840 frame = gtk_frame_new("IO depths");
841 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
842
843 box = gtk_hbox_new(FALSE, 3);
844 gtk_container_add(GTK_CONTAINER(frame), box);
845
Jens Axboe19998db2012-03-06 09:17:59 +0100846 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100847 types[i] = G_TYPE_STRING;
848
Jens Axboe19998db2012-03-06 09:17:59 +0100849 model = gtk_list_store_newv(NR_LABELS, types);
Jens Axboe2e331012012-03-05 22:07:54 +0100850
851 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
852 gtk_widget_set_can_focus(tree_view, FALSE);
853
Jens Axboe661f7412012-03-06 13:55:45 +0100854 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
855 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
856
Jens Axboe2e331012012-03-05 22:07:54 +0100857 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
858 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
859
Jens Axboe19998db2012-03-06 09:17:59 +0100860 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100861 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
862
Jens Axboe19998db2012-03-06 09:17:59 +0100863 gfio_add_total_depths_tree(model, ts, NR_LABELS);
864 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 1);
865 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 0);
Jens Axboe2e331012012-03-05 22:07:54 +0100866
867 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
868}
869
Jens Axboef9d40b42012-03-06 09:52:49 +0100870static gboolean results_window_delete(GtkWidget *w, gpointer data)
871{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100872 struct gui_entry *ge = (struct gui_entry *) data;
Jens Axboef9d40b42012-03-06 09:52:49 +0100873
874 gtk_widget_destroy(w);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100875 ge->results_window = NULL;
876 ge->results_notebook = NULL;
Jens Axboef9d40b42012-03-06 09:52:49 +0100877 return TRUE;
878}
879
Jens Axboe2f99deb2012-03-09 14:37:29 +0100880static GtkWidget *get_results_window(struct gui_entry *ge)
Jens Axboef9d40b42012-03-06 09:52:49 +0100881{
882 GtkWidget *win, *notebook;
883
Jens Axboe2f99deb2012-03-09 14:37:29 +0100884 if (ge->results_window)
885 return ge->results_notebook;
Jens Axboef9d40b42012-03-06 09:52:49 +0100886
887 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
888 gtk_window_set_title(GTK_WINDOW(win), "Results");
Jens Axboeb01329d2012-03-07 20:31:28 +0100889 gtk_window_set_default_size(GTK_WINDOW(win), 1024, 768);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100890 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ge);
891 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ge);
Jens Axboef9d40b42012-03-06 09:52:49 +0100892
893 notebook = gtk_notebook_new();
Jens Axboe0aa928c2012-03-09 17:24:07 +0100894 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), 1);
895 gtk_notebook_popup_enable(GTK_NOTEBOOK(notebook));
Jens Axboef9d40b42012-03-06 09:52:49 +0100896 gtk_container_add(GTK_CONTAINER(win), notebook);
897
Jens Axboe2f99deb2012-03-09 14:37:29 +0100898 ge->results_window = win;
899 ge->results_notebook = notebook;
900 return ge->results_notebook;
Jens Axboef9d40b42012-03-06 09:52:49 +0100901}
902
Jens Axboe3650a3c2012-03-05 14:09:03 +0100903static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
904 struct group_run_stats *rs)
905{
Jens Axboeb01329d2012-03-07 20:31:28 +0100906 GtkWidget *res_win, *box, *vbox, *entry, *scroll;
Jens Axboee0681f32012-03-06 12:14:42 +0100907 struct gfio_client *gc = client->client_data;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100908
909 gdk_threads_enter();
910
Jens Axboe2f99deb2012-03-09 14:37:29 +0100911 res_win = get_results_window(gc->ge);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100912
Jens Axboeb01329d2012-03-07 20:31:28 +0100913 scroll = gtk_scrolled_window_new(NULL, NULL);
914 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
915 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
916
Jens Axboe3650a3c2012-03-05 14:09:03 +0100917 vbox = gtk_vbox_new(FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100918
Jens Axboeb01329d2012-03-07 20:31:28 +0100919 box = gtk_hbox_new(FALSE, 0);
920 gtk_box_pack_start(GTK_BOX(vbox), box, TRUE, FALSE, 5);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100921
Jens Axboeb01329d2012-03-07 20:31:28 +0100922 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
923
924 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), scroll, gtk_label_new(ts->name));
Jens Axboef9d40b42012-03-06 09:52:49 +0100925
Jens Axboee0681f32012-03-06 12:14:42 +0100926 gc->results_widget = vbox;
927
Jens Axboe3650a3c2012-03-05 14:09:03 +0100928 entry = new_info_entry_in_frame(box, "Name");
929 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
930 if (strlen(ts->description)) {
931 entry = new_info_entry_in_frame(box, "Description");
932 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
933 }
934 entry = new_info_entry_in_frame(box, "Group ID");
935 entry_set_int_value(entry, ts->groupid);
936 entry = new_info_entry_in_frame(box, "Jobs");
937 entry_set_int_value(entry, ts->members);
Jens Axboe6b79c802012-03-08 10:51:36 +0100938 gc->err_entry = entry = new_info_entry_in_frame(box, "Error");
Jens Axboe3650a3c2012-03-05 14:09:03 +0100939 entry_set_int_value(entry, ts->error);
940 entry = new_info_entry_in_frame(box, "PID");
941 entry_set_int_value(entry, ts->pid);
942
943 if (ts->io_bytes[DDIR_READ])
944 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
945 if (ts->io_bytes[DDIR_WRITE])
946 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
947
Jens Axboee5bd1342012-03-05 21:38:12 +0100948 gfio_show_latency_buckets(vbox, ts);
Jens Axboe2e331012012-03-05 22:07:54 +0100949 gfio_show_cpu_usage(vbox, ts);
950 gfio_show_io_depths(vbox, ts);
Jens Axboee5bd1342012-03-05 21:38:12 +0100951
Jens Axboe2f99deb2012-03-09 14:37:29 +0100952 gtk_widget_show_all(gc->ge->results_window);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100953 gdk_threads_leave();
954}
955
Jens Axboe084d1c62012-03-03 20:28:07 +0100956static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100957{
Jens Axboe9b260bd2012-03-06 11:02:52 +0100958 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100959 struct gui *ui = &main_ui;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100960 GtkTreeIter iter;
961 struct tm *tm;
962 time_t sec;
963 char tmp[64], timebuf[80];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100964
Jens Axboe9b260bd2012-03-06 11:02:52 +0100965 sec = p->log_sec;
966 tm = localtime(&sec);
967 strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", tm);
968 sprintf(timebuf, "%s.%03ld", tmp, p->log_usec / 1000);
969
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100970 gdk_threads_enter();
Jens Axboe9b260bd2012-03-06 11:02:52 +0100971
Jens Axboe2f99deb2012-03-09 14:37:29 +0100972 gtk_list_store_append(ui->log_model, &iter);
973 gtk_list_store_set(ui->log_model, &iter, 0, timebuf, -1);
974 gtk_list_store_set(ui->log_model, &iter, 1, client->hostname, -1);
975 gtk_list_store_set(ui->log_model, &iter, 2, p->level, -1);
976 gtk_list_store_set(ui->log_model, &iter, 3, p->buf, -1);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100977
Jens Axboe6b79c802012-03-08 10:51:36 +0100978 if (p->level == FIO_LOG_ERR)
Jens Axboe2f99deb2012-03-09 14:37:29 +0100979 view_log(NULL, (gpointer) ui);
Jens Axboe6b79c802012-03-08 10:51:36 +0100980
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100981 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100982}
983
984static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
985{
Jens Axboee0681f32012-03-06 12:14:42 +0100986 struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
987 struct gfio_client *gc = client->client_data;
988 GtkWidget *box, *frame, *entry, *vbox;
Jens Axboe604cfe32012-03-07 19:51:36 +0100989 double util;
990 char tmp[16];
Jens Axboee0681f32012-03-06 12:14:42 +0100991
Jens Axboe0050e5f2012-03-06 09:23:27 +0100992 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +0100993
Jens Axboe45dcb2e2012-03-07 16:16:50 +0100994 if (!gc->results_widget)
Jens Axboee0681f32012-03-06 12:14:42 +0100995 goto out;
Jens Axboee0681f32012-03-06 12:14:42 +0100996
997 if (!gc->disk_util_frame) {
998 gc->disk_util_frame = gtk_frame_new("Disk utilization");
999 gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
1000 }
1001
1002 vbox = gtk_vbox_new(FALSE, 3);
1003 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
1004
1005 frame = gtk_frame_new((char *) p->dus.name);
1006 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
1007
1008 box = gtk_vbox_new(FALSE, 3);
1009 gtk_container_add(GTK_CONTAINER(frame), box);
1010
1011 frame = gtk_frame_new("Read");
1012 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1013 vbox = gtk_hbox_new(TRUE, 3);
1014 gtk_container_add(GTK_CONTAINER(frame), vbox);
1015 entry = new_info_entry_in_frame(vbox, "IOs");
1016 entry_set_int_value(entry, p->dus.ios[0]);
1017 entry = new_info_entry_in_frame(vbox, "Merges");
1018 entry_set_int_value(entry, p->dus.merges[0]);
1019 entry = new_info_entry_in_frame(vbox, "Sectors");
1020 entry_set_int_value(entry, p->dus.sectors[0]);
1021 entry = new_info_entry_in_frame(vbox, "Ticks");
1022 entry_set_int_value(entry, p->dus.ticks[0]);
1023
1024 frame = gtk_frame_new("Write");
1025 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1026 vbox = gtk_hbox_new(TRUE, 3);
1027 gtk_container_add(GTK_CONTAINER(frame), vbox);
1028 entry = new_info_entry_in_frame(vbox, "IOs");
1029 entry_set_int_value(entry, p->dus.ios[1]);
1030 entry = new_info_entry_in_frame(vbox, "Merges");
1031 entry_set_int_value(entry, p->dus.merges[1]);
1032 entry = new_info_entry_in_frame(vbox, "Sectors");
1033 entry_set_int_value(entry, p->dus.sectors[1]);
1034 entry = new_info_entry_in_frame(vbox, "Ticks");
1035 entry_set_int_value(entry, p->dus.ticks[1]);
1036
1037 frame = gtk_frame_new("Shared");
1038 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1039 vbox = gtk_hbox_new(TRUE, 3);
1040 gtk_container_add(GTK_CONTAINER(frame), vbox);
1041 entry = new_info_entry_in_frame(vbox, "IO ticks");
1042 entry_set_int_value(entry, p->dus.io_ticks);
1043 entry = new_info_entry_in_frame(vbox, "Time in queue");
1044 entry_set_int_value(entry, p->dus.time_in_queue);
1045
Jens Axboe604cfe32012-03-07 19:51:36 +01001046 util = 0.0;
1047 if (p->dus.msec)
1048 util = (double) 100 * p->dus.io_ticks / (double) p->dus.msec;
1049 if (util > 100.0)
1050 util = 100.0;
1051
1052 sprintf(tmp, "%3.2f%%", util);
1053 entry = new_info_entry_in_frame(vbox, "Disk utilization");
1054 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
1055
Jens Axboee0681f32012-03-06 12:14:42 +01001056 gtk_widget_show_all(gc->results_widget);
1057out:
Jens Axboe0050e5f2012-03-06 09:23:27 +01001058 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001059}
1060
Jens Axboe3650a3c2012-03-05 14:09:03 +01001061extern int sum_stat_clients;
1062extern struct thread_stat client_ts;
1063extern struct group_run_stats client_gs;
1064
1065static int sum_stat_nr;
1066
Jens Axboe89e5fad2012-03-05 09:21:12 +01001067static void gfio_thread_status_op(struct fio_client *client,
1068 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001069{
Jens Axboe3650a3c2012-03-05 14:09:03 +01001070 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
1071
1072 gfio_display_ts(client, &p->ts, &p->rs);
1073
1074 if (sum_stat_clients == 1)
1075 return;
1076
1077 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
1078 sum_group_stats(&client_gs, &p->rs);
1079
1080 client_ts.members++;
1081 client_ts.groupid = p->ts.groupid;
1082
1083 if (++sum_stat_nr == sum_stat_clients) {
1084 strcpy(client_ts.name, "All clients");
1085 gfio_display_ts(client, &client_ts, &client_gs);
1086 }
Stephen M. Camerona1820202012-02-24 08:17:31 +01001087}
1088
Jens Axboe89e5fad2012-03-05 09:21:12 +01001089static void gfio_group_stats_op(struct fio_client *client,
1090 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001091{
Jens Axboe98ceabd2012-03-09 08:53:28 +01001092 /* We're ignoring group stats for now */
Stephen M. Camerona1820202012-02-24 08:17:31 +01001093}
1094
Jens Axboe2f99deb2012-03-09 14:37:29 +01001095static gint on_config_drawing_area(GtkWidget *w, GdkEventConfigure *event,
1096 gpointer data)
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001097{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001098 struct gfio_graphs *g = data;
1099
1100 g->drawing_area_xdim = w->allocation.width;
1101 g->drawing_area_ydim = w->allocation.height;
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001102 return TRUE;
1103}
1104
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001105static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
1106{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001107 struct gfio_graphs *g = p;
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001108 cairo_t *cr;
1109
Jens Axboe2f99deb2012-03-09 14:37:29 +01001110 graph_set_size(g->iops_graph, g->drawing_area_xdim / 2.0,
1111 g->drawing_area_ydim);
1112 graph_set_size(g->bandwidth_graph, g->drawing_area_xdim / 2.0,
1113 g->drawing_area_ydim);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001114 cr = gdk_cairo_create(w->window);
1115
1116 cairo_set_source_rgb(cr, 0, 0, 0);
1117
1118 cairo_save(cr);
1119 cairo_translate(cr, 0, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001120 line_graph_draw(g->bandwidth_graph, cr);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001121 cairo_stroke(cr);
1122 cairo_restore(cr);
1123
1124 cairo_save(cr);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001125 cairo_translate(cr, g->drawing_area_xdim / 2.0, 0);
1126 line_graph_draw(g->iops_graph, cr);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001127 cairo_stroke(cr);
1128 cairo_restore(cr);
1129 cairo_destroy(cr);
1130
1131 return FALSE;
1132}
1133
Jens Axboe2f99deb2012-03-09 14:37:29 +01001134/*
1135 * Client specific ETA
1136 */
1137static void gfio_update_client_eta(struct fio_client *client, struct jobs_eta *je)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001138{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001139 struct gfio_client *gc = client->client_data;
1140 struct gui_entry *ge = gc->ge;
Jens Axboe3e47bd22012-02-29 13:45:02 +01001141 static int eta_good;
1142 char eta_str[128];
1143 char output[256];
1144 char tmp[32];
1145 double perc = 0.0;
1146 int i2p = 0;
1147
Jens Axboe0050e5f2012-03-06 09:23:27 +01001148 gdk_threads_enter();
1149
Jens Axboe3e47bd22012-02-29 13:45:02 +01001150 eta_str[0] = '\0';
1151 output[0] = '\0';
1152
1153 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1154 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1155 eta_to_str(eta_str, je->eta_sec);
1156 }
1157
1158 sprintf(tmp, "%u", je->nr_running);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001159 gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001160 sprintf(tmp, "%u", je->files_open);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001161 gtk_entry_set_text(GTK_ENTRY(ge->eta.files), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001162
1163#if 0
1164 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1165 if (je->m_rate || je->t_rate) {
1166 char *tr, *mr;
1167
1168 mr = num2str(je->m_rate, 4, 0, i2p);
1169 tr = num2str(je->t_rate, 4, 0, i2p);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001170 gtk_entry_set_text(GTK_ENTRY(ge->eta);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001171 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1172 free(tr);
1173 free(mr);
1174 } else if (je->m_iops || je->t_iops)
1175 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
Jens Axboeebbd89c2012-03-02 11:21:13 +01001176
Jens Axboe2f99deb2012-03-09 14:37:29 +01001177 gtk_entry_set_text(GTK_ENTRY(ge->eta.cr_bw), "---");
1178 gtk_entry_set_text(GTK_ENTRY(ge->eta.cr_iops), "---");
1179 gtk_entry_set_text(GTK_ENTRY(ge->eta.cw_bw), "---");
1180 gtk_entry_set_text(GTK_ENTRY(ge->eta.cw_iops), "---");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001181#endif
1182
1183 if (je->eta_sec != INT_MAX && je->nr_running) {
1184 char *iops_str[2];
1185 char *rate_str[2];
1186
1187 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1188 strcpy(output, "-.-% done");
1189 else {
1190 eta_good = 1;
1191 perc *= 100.0;
1192 sprintf(output, "%3.1f%% done", perc);
1193 }
1194
1195 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1196 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1197
1198 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1199 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1200
Jens Axboe2f99deb2012-03-09 14:37:29 +01001201 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), rate_str[0]);
1202 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), iops_str[0]);
1203 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), rate_str[1]);
1204 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), iops_str[1]);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001205
Jens Axboe2f99deb2012-03-09 14:37:29 +01001206 graph_add_xy_data(ge->graphs.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1207 graph_add_xy_data(ge->graphs.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1208 graph_add_xy_data(ge->graphs.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1209 graph_add_xy_data(ge->graphs.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
1210
1211 free(rate_str[0]);
1212 free(rate_str[1]);
1213 free(iops_str[0]);
1214 free(iops_str[1]);
1215 }
1216
1217 if (eta_str[0]) {
1218 char *dst = output + strlen(output);
1219
1220 sprintf(dst, " - %s", eta_str);
1221 }
1222
Jens Axboe9988ca72012-03-09 15:14:06 +01001223 gfio_update_thread_status(ge, output, perc);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001224 gdk_threads_leave();
1225}
1226
1227/*
1228 * Update ETA in main window for all clients
1229 */
1230static void gfio_update_all_eta(struct jobs_eta *je)
1231{
1232 struct gui *ui = &main_ui;
1233 static int eta_good;
1234 char eta_str[128];
1235 char output[256];
1236 double perc = 0.0;
1237 int i2p = 0;
1238
1239 gdk_threads_enter();
1240
1241 eta_str[0] = '\0';
1242 output[0] = '\0';
1243
1244 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1245 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1246 eta_to_str(eta_str, je->eta_sec);
1247 }
1248
1249#if 0
1250 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1251 if (je->m_rate || je->t_rate) {
1252 char *tr, *mr;
1253
1254 mr = num2str(je->m_rate, 4, 0, i2p);
1255 tr = num2str(je->t_rate, 4, 0, i2p);
1256 gtk_entry_set_text(GTK_ENTRY(ui->eta);
1257 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1258 free(tr);
1259 free(mr);
1260 } else if (je->m_iops || je->t_iops)
1261 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
1262
1263 gtk_entry_set_text(GTK_ENTRY(ui->eta.cr_bw), "---");
1264 gtk_entry_set_text(GTK_ENTRY(ui->eta.cr_iops), "---");
1265 gtk_entry_set_text(GTK_ENTRY(ui->eta.cw_bw), "---");
1266 gtk_entry_set_text(GTK_ENTRY(ui->eta.cw_iops), "---");
1267#endif
1268
Jens Axboe3863d1a2012-03-09 17:39:05 +01001269 entry_set_int_value(ui->eta.jobs, je->nr_running);
1270
Jens Axboe2f99deb2012-03-09 14:37:29 +01001271 if (je->eta_sec != INT_MAX && je->nr_running) {
1272 char *iops_str[2];
1273 char *rate_str[2];
1274
1275 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1276 strcpy(output, "-.-% done");
1277 else {
1278 eta_good = 1;
1279 perc *= 100.0;
1280 sprintf(output, "%3.1f%% done", perc);
1281 }
1282
1283 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1284 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1285
1286 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1287 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1288
1289 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), rate_str[0]);
1290 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), iops_str[0]);
1291 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), rate_str[1]);
1292 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), iops_str[1]);
1293
1294 graph_add_xy_data(ui->graphs.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1295 graph_add_xy_data(ui->graphs.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1296 graph_add_xy_data(ui->graphs.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1297 graph_add_xy_data(ui->graphs.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001298
Jens Axboe3e47bd22012-02-29 13:45:02 +01001299 free(rate_str[0]);
1300 free(rate_str[1]);
1301 free(iops_str[0]);
1302 free(iops_str[1]);
1303 }
1304
1305 if (eta_str[0]) {
1306 char *dst = output + strlen(output);
1307
1308 sprintf(dst, " - %s", eta_str);
1309 }
1310
Jens Axboe9988ca72012-03-09 15:14:06 +01001311 gfio_update_thread_status_all(output, perc);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001312 gdk_threads_leave();
Jens Axboe3e47bd22012-02-29 13:45:02 +01001313}
1314
Stephen M. Camerona1820202012-02-24 08:17:31 +01001315static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1316{
Jens Axboe843ad232012-02-29 11:44:53 +01001317 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001318 struct gfio_client *gc = client->client_data;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001319 struct gui_entry *ge = gc->ge;
Jens Axboe843ad232012-02-29 11:44:53 +01001320 const char *os, *arch;
1321 char buf[64];
1322
1323 os = fio_get_os_string(probe->os);
1324 if (!os)
1325 os = "unknown";
1326
1327 arch = fio_get_arch_string(probe->arch);
1328 if (!arch)
1329 os = "unknown";
1330
1331 if (!client->name)
1332 client->name = strdup((char *) probe->hostname);
1333
Jens Axboe0050e5f2012-03-06 09:23:27 +01001334 gdk_threads_enter();
1335
Jens Axboe2f99deb2012-03-09 14:37:29 +01001336 gtk_label_set_text(GTK_LABEL(ge->probe.hostname), (char *) probe->hostname);
1337 gtk_label_set_text(GTK_LABEL(ge->probe.os), os);
1338 gtk_label_set_text(GTK_LABEL(ge->probe.arch), arch);
Jens Axboe843ad232012-02-29 11:44:53 +01001339 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001340 gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), buf);
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001341
Jens Axboe2f99deb2012-03-09 14:37:29 +01001342 gfio_set_connected(ge, 1);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001343
1344 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001345}
1346
Jens Axboe9988ca72012-03-09 15:14:06 +01001347static void gfio_update_thread_status(struct gui_entry *ge,
1348 char *status_message, double perc)
1349{
1350 static char message[100];
1351 const char *m = message;
1352
1353 strncpy(message, status_message, sizeof(message) - 1);
1354 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), m);
1355 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), perc / 100.0);
1356 gtk_widget_queue_draw(main_ui.window);
1357}
1358
1359static void gfio_update_thread_status_all(char *status_message, double perc)
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001360{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001361 struct gui *ui = &main_ui;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001362 static char message[100];
1363 const char *m = message;
1364
1365 strncpy(message, status_message, sizeof(message) - 1);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001366 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), m);
1367 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), perc / 100.0);
1368 gtk_widget_queue_draw(ui->window);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001369}
1370
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001371static void gfio_quit_op(struct fio_client *client)
1372{
Jens Axboee0681f32012-03-06 12:14:42 +01001373 struct gfio_client *gc = client->client_data;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001374
Jens Axboe0050e5f2012-03-06 09:23:27 +01001375 gdk_threads_enter();
Jens Axboe2f99deb2012-03-09 14:37:29 +01001376 gfio_set_connected(gc->ge, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001377 gdk_threads_leave();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001378}
1379
Jens Axboe807f9972012-03-02 10:25:24 +01001380static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1381{
1382 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +01001383 struct gfio_client *gc = client->client_data;
Jens Axboedcaeb602012-03-08 19:45:37 +01001384 struct thread_options *o = &gc->o;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001385 struct gui_entry *ge = gc->ge;
Jens Axboe807f9972012-03-02 10:25:24 +01001386 char tmp[8];
Jens Axboe807f9972012-03-02 10:25:24 +01001387
Jens Axboedcaeb602012-03-08 19:45:37 +01001388 convert_thread_options_to_cpu(o, &p->top);
Jens Axboe807f9972012-03-02 10:25:24 +01001389
Jens Axboe0050e5f2012-03-06 09:23:27 +01001390 gdk_threads_enter();
1391
Jens Axboe2f99deb2012-03-09 14:37:29 +01001392 gtk_label_set_text(GTK_LABEL(ge->page_label), (gchar *) o->name);
1393
Jens Axboe3863d1a2012-03-09 17:39:05 +01001394 gtk_combo_box_append_text(GTK_COMBO_BOX(ge->eta.names), (gchar *) o->name);
1395 gtk_combo_box_set_active(GTK_COMBO_BOX(ge->eta.names), 0);
1396
Jens Axboe2f99deb2012-03-09 14:37:29 +01001397 gtk_entry_set_text(GTK_ENTRY(ge->eta.iotype), ddir_str(o->td_ddir));
1398 gtk_entry_set_text(GTK_ENTRY(ge->eta.ioengine), (gchar *) o->ioengine);
Jens Axboe807f9972012-03-02 10:25:24 +01001399
Jens Axboedcaeb602012-03-08 19:45:37 +01001400 sprintf(tmp, "%u", o->iodepth);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001401 gtk_entry_set_text(GTK_ENTRY(ge->eta.iodepth), tmp);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001402
Jens Axboedcaeb602012-03-08 19:45:37 +01001403 gc->job_added++;
1404
Jens Axboe0050e5f2012-03-06 09:23:27 +01001405 gdk_threads_leave();
Jens Axboe807f9972012-03-02 10:25:24 +01001406}
1407
Jens Axboeed727a42012-03-02 12:14:40 +01001408static void gfio_client_timed_out(struct fio_client *client)
1409{
Jens Axboee0681f32012-03-06 12:14:42 +01001410 struct gfio_client *gc = client->client_data;
Jens Axboeed727a42012-03-02 12:14:40 +01001411 GtkWidget *dialog, *label, *content;
1412 char buf[256];
1413
1414 gdk_threads_enter();
1415
Jens Axboe2f99deb2012-03-09 14:37:29 +01001416 gfio_set_connected(gc->ge, 0);
1417 clear_ge_ui_info(gc->ge);
Jens Axboeed727a42012-03-02 12:14:40 +01001418
1419 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
1420
1421 dialog = gtk_dialog_new_with_buttons("Timed out!",
Jens Axboe2f99deb2012-03-09 14:37:29 +01001422 GTK_WINDOW(main_ui.window),
Jens Axboeed727a42012-03-02 12:14:40 +01001423 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1424 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1425
Jens Axboef1299092012-03-07 20:00:02 +01001426 /* gtk_dialog_get_content_area() is 2.14 and newer */
1427 content = GTK_DIALOG(dialog)->vbox;
1428
Jens Axboeed727a42012-03-02 12:14:40 +01001429 label = gtk_label_new((const gchar *) buf);
1430 gtk_container_add(GTK_CONTAINER(content), label);
1431 gtk_widget_show_all(dialog);
1432 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1433
1434 gtk_dialog_run(GTK_DIALOG(dialog));
1435 gtk_widget_destroy(dialog);
1436
1437 gdk_threads_leave();
1438}
1439
Jens Axboe6b79c802012-03-08 10:51:36 +01001440static void gfio_client_stop(struct fio_client *client, struct fio_net_cmd *cmd)
1441{
1442 struct gfio_client *gc = client->client_data;
1443
1444 gdk_threads_enter();
1445
Jens Axboe2f99deb2012-03-09 14:37:29 +01001446 gfio_set_connected(gc->ge, 0);
Jens Axboe6b79c802012-03-08 10:51:36 +01001447
1448 if (gc->err_entry)
1449 entry_set_int_value(gc->err_entry, client->error);
1450
1451 gdk_threads_leave();
1452}
1453
Stephen M. Camerona1820202012-02-24 08:17:31 +01001454struct client_ops gfio_client_ops = {
Jens Axboe0420ba62012-02-29 11:16:52 +01001455 .text_op = gfio_text_op,
1456 .disk_util = gfio_disk_util_op,
1457 .thread_status = gfio_thread_status_op,
1458 .group_stats = gfio_group_stats_op,
Jens Axboe2f99deb2012-03-09 14:37:29 +01001459 .jobs_eta = gfio_update_client_eta,
1460 .eta = gfio_update_all_eta,
Jens Axboe0420ba62012-02-29 11:16:52 +01001461 .probe = gfio_probe_op,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001462 .quit = gfio_quit_op,
Jens Axboe807f9972012-03-02 10:25:24 +01001463 .add_job = gfio_add_job_op,
Jens Axboeed727a42012-03-02 12:14:40 +01001464 .timed_out = gfio_client_timed_out,
Jens Axboe6b79c802012-03-08 10:51:36 +01001465 .stop = gfio_client_stop,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001466 .stay_connected = 1,
Stephen M. Camerona1820202012-02-24 08:17:31 +01001467};
1468
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001469static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1470 __attribute__((unused)) gpointer data)
1471{
1472 gtk_main_quit();
1473}
1474
Stephen M. Cameron25927252012-02-24 08:17:31 +01001475static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001476{
Jens Axboea9eccde2012-03-09 14:59:42 +01001477 struct gui *ui = arg;
1478
1479 ui->handler_running = 1;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001480 fio_handle_clients(&gfio_client_ops);
Jens Axboea9eccde2012-03-09 14:59:42 +01001481 ui->handler_running = 0;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001482 return NULL;
1483}
1484
Jens Axboe2f99deb2012-03-09 14:37:29 +01001485static int send_job_files(struct gui_entry *ge)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001486{
Jens Axboe9988ca72012-03-09 15:14:06 +01001487 struct gfio_client *gc = ge->client;
Jens Axboe441013b2012-03-01 08:01:52 +01001488 int i, ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001489
Jens Axboe2f99deb2012-03-09 14:37:29 +01001490 for (i = 0; i < ge->nr_job_files; i++) {
Jens Axboe9988ca72012-03-09 15:14:06 +01001491 ret = fio_client_send_ini(gc->client, ge->job_files[i]);
Jens Axboec7249262012-03-09 17:11:04 +01001492 if (ret < 0) {
1493 GError *error;
1494
1495 error = g_error_new(g_quark_from_string("fio"), 1, "Failed to send file %s: %s\n", ge->job_files[i], strerror(-ret));
1496 report_error(error);
1497 g_error_free(error);
1498 break;
1499 } else if (ret)
Jens Axboe441013b2012-03-01 08:01:52 +01001500 break;
1501
Jens Axboe2f99deb2012-03-09 14:37:29 +01001502 free(ge->job_files[i]);
1503 ge->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001504 }
Jens Axboe2f99deb2012-03-09 14:37:29 +01001505 while (i < ge->nr_job_files) {
1506 free(ge->job_files[i]);
1507 ge->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001508 i++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001509 }
1510
Jens Axboe441013b2012-03-01 08:01:52 +01001511 return ret;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001512}
1513
Jens Axboe63a130b2012-03-06 20:08:59 +01001514static void *server_thread(void *arg)
1515{
1516 is_backend = 1;
1517 gfio_server_running = 1;
1518 fio_start_server(NULL);
1519 gfio_server_running = 0;
1520 return NULL;
1521}
1522
Jens Axboe2f99deb2012-03-09 14:37:29 +01001523static void gfio_start_server(void)
Jens Axboe63a130b2012-03-06 20:08:59 +01001524{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001525 struct gui *ui = &main_ui;
1526
Jens Axboe63a130b2012-03-06 20:08:59 +01001527 if (!gfio_server_running) {
1528 gfio_server_running = 1;
1529 pthread_create(&ui->server_t, NULL, server_thread, NULL);
Jens Axboee34f6ad2012-03-06 20:47:15 +01001530 pthread_detach(ui->server_t);
Jens Axboe63a130b2012-03-06 20:08:59 +01001531 }
1532}
1533
Stephen M. Cameron25927252012-02-24 08:17:31 +01001534static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1535 gpointer data)
1536{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001537 struct gui_entry *ge = data;
1538 struct gfio_client *gc = ge->client;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001539
Jens Axboe2f99deb2012-03-09 14:37:29 +01001540 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 0);
1541 fio_start_client(gc->client);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001542}
1543
Jens Axboedf06f222012-03-02 13:32:04 +01001544static void file_open(GtkWidget *w, gpointer data);
1545
1546static void connect_clicked(GtkWidget *widget, gpointer data)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001547{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001548 struct gui_entry *ge = data;
1549 struct gfio_client *gc = ge->client;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001550
Jens Axboe2f99deb2012-03-09 14:37:29 +01001551 if (!ge->connected) {
Jens Axboec7249262012-03-09 17:11:04 +01001552 int ret;
1553
Jens Axboe2f99deb2012-03-09 14:37:29 +01001554 if (!ge->nr_job_files)
Jens Axboedf06f222012-03-02 13:32:04 +01001555 file_open(widget, data);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001556 if (!ge->nr_job_files)
1557 return;
1558
1559 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No jobs running");
1560 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
Jens Axboec7249262012-03-09 17:11:04 +01001561 ret = fio_client_connect(gc->client);
1562 if (!ret) {
Jens Axboea9eccde2012-03-09 14:59:42 +01001563 if (!ge->ui->handler_running)
1564 pthread_create(&ge->ui->t, NULL, job_thread, ge->ui);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001565 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 0);
1566 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 1);
Jens Axboec7249262012-03-09 17:11:04 +01001567 } else {
1568 GError *error;
1569
1570 error = g_error_new(g_quark_from_string("fio"), 1, "Failed to connect to %s: %s\n", ge->client->client->hostname, strerror(-ret));
1571 report_error(error);
1572 g_error_free(error);
Jens Axboe69406b92012-03-06 14:00:42 +01001573 }
Jens Axboedf06f222012-03-02 13:32:04 +01001574 } else {
Jens Axboe2f99deb2012-03-09 14:37:29 +01001575 fio_client_terminate(gc->client);
1576 gfio_set_connected(ge, 0);
1577 clear_ge_ui_info(ge);
Jens Axboedf06f222012-03-02 13:32:04 +01001578 }
Jens Axboe3e47bd22012-02-29 13:45:02 +01001579}
1580
Jens Axboeb9d2f302012-03-08 20:36:28 +01001581static void send_clicked(GtkWidget *widget, gpointer data)
1582{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001583 struct gui_entry *ge = data;
Jens Axboeb9d2f302012-03-08 20:36:28 +01001584
Jens Axboe2f99deb2012-03-09 14:37:29 +01001585 if (send_job_files(ge)) {
Jens Axboec7249262012-03-09 17:11:04 +01001586 GError *error;
1587
1588 error = g_error_new(g_quark_from_string("fio"), 1, "Failed to send one or more job files for client %s", ge->client->client->hostname);
1589 report_error(error);
1590 g_error_free(error);
1591
Jens Axboe2f99deb2012-03-09 14:37:29 +01001592 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 1);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001593 }
1594
Jens Axboe2f99deb2012-03-09 14:37:29 +01001595 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 0);
1596 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 1);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001597}
1598
Jens Axboe2f99deb2012-03-09 14:37:29 +01001599static GtkWidget *add_button(GtkWidget *buttonbox,
1600 struct button_spec *buttonspec, gpointer data)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001601{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001602 GtkWidget *button = gtk_button_new_with_label(buttonspec->buttontext);
1603
1604 g_signal_connect(button, "clicked", G_CALLBACK(buttonspec->f), data);
1605 gtk_box_pack_start(GTK_BOX(buttonbox), button, FALSE, FALSE, 3);
1606 gtk_widget_set_tooltip_text(button, buttonspec->tooltiptext);
1607 gtk_widget_set_sensitive(button, !buttonspec->start_insensitive);
1608
1609 return button;
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001610}
1611
Jens Axboe2f99deb2012-03-09 14:37:29 +01001612static void add_buttons(struct gui_entry *ge, struct button_spec *buttonlist,
1613 int nbuttons)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001614{
1615 int i;
1616
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001617 for (i = 0; i < nbuttons; i++)
Jens Axboe2f99deb2012-03-09 14:37:29 +01001618 ge->button[i] = add_button(ge->buttonbox, &buttonlist[i], ge);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001619}
1620
Jens Axboe0420ba62012-02-29 11:16:52 +01001621static void on_info_bar_response(GtkWidget *widget, gint response,
1622 gpointer data)
1623{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001624 struct gui *ui = &main_ui;
1625
Jens Axboe0420ba62012-02-29 11:16:52 +01001626 if (response == GTK_RESPONSE_OK) {
1627 gtk_widget_destroy(widget);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001628 ui->error_info_bar = NULL;
Jens Axboe0420ba62012-02-29 11:16:52 +01001629 }
1630}
1631
Jens Axboedf06f222012-03-02 13:32:04 +01001632void report_error(GError *error)
Jens Axboe0420ba62012-02-29 11:16:52 +01001633{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001634 struct gui *ui = &main_ui;
1635
1636 if (ui->error_info_bar == NULL) {
1637 ui->error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
Jens Axboe0420ba62012-02-29 11:16:52 +01001638 GTK_RESPONSE_OK,
1639 NULL);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001640 g_signal_connect(ui->error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1641 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui->error_info_bar),
Jens Axboe0420ba62012-02-29 11:16:52 +01001642 GTK_MESSAGE_ERROR);
1643
Jens Axboe2f99deb2012-03-09 14:37:29 +01001644 ui->error_label = gtk_label_new(error->message);
1645 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui->error_info_bar));
1646 gtk_container_add(GTK_CONTAINER(container), ui->error_label);
Jens Axboe0420ba62012-02-29 11:16:52 +01001647
Jens Axboe2f99deb2012-03-09 14:37:29 +01001648 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->error_info_bar, FALSE, FALSE, 0);
1649 gtk_widget_show_all(ui->vbox);
Jens Axboe0420ba62012-02-29 11:16:52 +01001650 } else {
1651 char buffer[256];
1652 snprintf(buffer, sizeof(buffer), "Failed to open file.");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001653 gtk_label_set(GTK_LABEL(ui->error_label), buffer);
Jens Axboe0420ba62012-02-29 11:16:52 +01001654 }
1655}
1656
Jens Axboe62bc9372012-03-07 11:45:07 +01001657struct connection_widgets
1658{
1659 GtkWidget *hentry;
1660 GtkWidget *combo;
1661 GtkWidget *button;
1662};
1663
1664static void hostname_cb(GtkEntry *entry, gpointer data)
1665{
1666 struct connection_widgets *cw = data;
1667 int uses_net = 0, is_localhost = 0;
1668 const gchar *text;
1669 gchar *ctext;
1670
1671 /*
1672 * Check whether to display the 'auto start backend' box
1673 * or not. Show it if we are a localhost and using network,
1674 * or using a socket.
1675 */
1676 ctext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->combo));
1677 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
1678 uses_net = 1;
1679 g_free(ctext);
1680
1681 if (uses_net) {
1682 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
1683 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
1684 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
1685 !strcmp(text, "ip6-loopback"))
1686 is_localhost = 1;
1687 }
1688
1689 if (!uses_net || is_localhost) {
1690 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
1691 gtk_widget_set_sensitive(cw->button, 1);
1692 } else {
1693 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
1694 gtk_widget_set_sensitive(cw->button, 0);
1695 }
1696}
1697
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001698static int get_connection_details(char **host, int *port, int *type,
1699 int *server_start)
Jens Axboea7a42ce2012-03-02 13:12:04 +01001700{
Jens Axboe62bc9372012-03-07 11:45:07 +01001701 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
1702 struct connection_widgets cw;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001703 char *typeentry;
1704
1705 dialog = gtk_dialog_new_with_buttons("Connection details",
Jens Axboe2f99deb2012-03-09 14:37:29 +01001706 GTK_WINDOW(main_ui.window),
Jens Axboea7a42ce2012-03-02 13:12:04 +01001707 GTK_DIALOG_DESTROY_WITH_PARENT,
1708 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1709 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1710
1711 frame = gtk_frame_new("Hostname / socket name");
Jens Axboef1299092012-03-07 20:00:02 +01001712 /* gtk_dialog_get_content_area() is 2.14 and newer */
1713 vbox = GTK_DIALOG(dialog)->vbox;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001714 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1715
1716 box = gtk_vbox_new(FALSE, 6);
1717 gtk_container_add(GTK_CONTAINER(frame), box);
1718
1719 hbox = gtk_hbox_new(TRUE, 10);
1720 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe62bc9372012-03-07 11:45:07 +01001721 cw.hentry = gtk_entry_new();
1722 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
1723 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001724
1725 frame = gtk_frame_new("Port");
1726 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1727 box = gtk_vbox_new(FALSE, 10);
1728 gtk_container_add(GTK_CONTAINER(frame), box);
1729
1730 hbox = gtk_hbox_new(TRUE, 4);
1731 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1732 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1733
1734 frame = gtk_frame_new("Type");
1735 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1736 box = gtk_vbox_new(FALSE, 10);
1737 gtk_container_add(GTK_CONTAINER(frame), box);
1738
1739 hbox = gtk_hbox_new(TRUE, 4);
1740 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1741
Jens Axboe62bc9372012-03-07 11:45:07 +01001742 cw.combo = gtk_combo_box_new_text();
1743 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv4");
1744 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv6");
1745 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "local socket");
1746 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001747
Jens Axboe62bc9372012-03-07 11:45:07 +01001748 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001749
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001750 frame = gtk_frame_new("Options");
1751 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1752 box = gtk_vbox_new(FALSE, 10);
1753 gtk_container_add(GTK_CONTAINER(frame), box);
1754
1755 hbox = gtk_hbox_new(TRUE, 4);
1756 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1757
Jens Axboe62bc9372012-03-07 11:45:07 +01001758 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1759 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
1760 gtk_widget_set_tooltip_text(cw.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.");
1761 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
1762
1763 /*
1764 * Connect edit signal, so we can show/not-show the auto start button
1765 */
1766 g_signal_connect(GTK_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
1767 g_signal_connect(GTK_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001768
Jens Axboea7a42ce2012-03-02 13:12:04 +01001769 gtk_widget_show_all(dialog);
1770
1771 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1772 gtk_widget_destroy(dialog);
1773 return 1;
1774 }
1775
Jens Axboe62bc9372012-03-07 11:45:07 +01001776 *host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001777 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1778
Jens Axboe62bc9372012-03-07 11:45:07 +01001779 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw.combo));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001780 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1781 *type = Fio_client_ipv4;
1782 else if (!strncmp(typeentry, "IPv6", 4))
1783 *type = Fio_client_ipv6;
1784 else
1785 *type = Fio_client_socket;
1786 g_free(typeentry);
1787
Jens Axboe62bc9372012-03-07 11:45:07 +01001788 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001789
Jens Axboea7a42ce2012-03-02 13:12:04 +01001790 gtk_widget_destroy(dialog);
1791 return 0;
1792}
1793
Jens Axboe2f99deb2012-03-09 14:37:29 +01001794static void gfio_client_added(struct gui_entry *ge, struct fio_client *client)
Jens Axboee0681f32012-03-06 12:14:42 +01001795{
1796 struct gfio_client *gc;
1797
1798 gc = malloc(sizeof(*gc));
1799 memset(gc, 0, sizeof(*gc));
Jens Axboe2f99deb2012-03-09 14:37:29 +01001800 gc->ge = ge;
Jens Axboe343cb4a2012-03-09 17:16:51 +01001801 gc->client = fio_get_client(client);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001802
Jens Axboe2f99deb2012-03-09 14:37:29 +01001803 ge->client = gc;
Jens Axboee0681f32012-03-06 12:14:42 +01001804
1805 client->client_data = gc;
1806}
1807
Jens Axboe2f99deb2012-03-09 14:37:29 +01001808static GtkWidget *new_client_page(struct gui_entry *ge);
1809
1810static struct gui_entry *alloc_new_gui_entry(struct gui *ui)
1811{
1812 struct gui_entry *ge;
1813
1814 ge = malloc(sizeof(*ge));
1815 memset(ge, 0, sizeof(*ge));
1816 INIT_FLIST_HEAD(&ge->list);
1817 flist_add_tail(&ge->list, &ui->list);
1818 ge->ui = ui;
1819 return ge;
1820}
1821
1822/*
1823 * FIXME: need more handling here
1824 */
1825static void ge_destroy(GtkWidget *w, gpointer data)
1826{
1827 struct gui_entry *ge = data;
Jens Axboe343cb4a2012-03-09 17:16:51 +01001828 struct gfio_client *gc = ge->client;
1829
1830 if (gc->client)
1831 fio_put_client(gc->client);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001832
1833 flist_del(&ge->list);
1834 free(ge);
1835}
1836
1837static struct gui_entry *get_new_ge_with_tab(const char *name)
1838{
1839 struct gui_entry *ge;
1840
1841 ge = alloc_new_gui_entry(&main_ui);
1842
1843 ge->vbox = new_client_page(ge);
1844 g_signal_connect(ge->vbox, "destroy", G_CALLBACK(ge_destroy), ge);
1845
1846 ge->page_label = gtk_label_new(name);
1847 ge->page_num = gtk_notebook_append_page(GTK_NOTEBOOK(main_ui.notebook), ge->vbox, ge->page_label);
1848
1849 gtk_widget_show_all(main_ui.window);
1850 return ge;
1851}
1852
1853static void file_new(GtkWidget *w, gpointer data)
1854{
1855 get_new_ge_with_tab("Untitled");
1856}
1857
1858/*
1859 * Return the 'ge' corresponding to the tab. If the active tab is the
1860 * main tab, open a new tab.
1861 */
1862static struct gui_entry *get_ge_from_page(unsigned int cur_page)
1863{
1864 struct flist_head *entry;
1865 struct gui_entry *ge;
1866
1867 if (!cur_page)
1868 return get_new_ge_with_tab("Untitled");
1869
1870 flist_for_each(entry, &main_ui.list) {
1871 ge = flist_entry(entry, struct gui_entry, list);
1872 if (ge->page_num == cur_page)
1873 return ge;
1874 }
1875
1876 return NULL;
1877}
1878
Jens Axboe0420ba62012-02-29 11:16:52 +01001879static void file_open(GtkWidget *w, gpointer data)
1880{
Jens Axboe63a130b2012-03-06 20:08:59 +01001881 struct gui *ui = data;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001882 GtkWidget *dialog;
Jens Axboe0420ba62012-02-29 11:16:52 +01001883 GSList *filenames, *fn_glist;
1884 GtkFileFilter *filter;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001885 char *host;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001886 int port, type, server_start;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001887 struct gui_entry *ge;
1888 gint cur_page;
1889
1890 /*
1891 * Creates new tab if current tab is the main window, or the
1892 * current tab already has a client.
1893 */
1894 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
1895 ge = get_ge_from_page(cur_page);
1896 if (ge->client)
1897 ge = get_new_ge_with_tab("Untitled");
1898
1899 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
Jens Axboe0420ba62012-02-29 11:16:52 +01001900
1901 dialog = gtk_file_chooser_dialog_new("Open File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001902 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001903 GTK_FILE_CHOOSER_ACTION_OPEN,
1904 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1905 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1906 NULL);
1907 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1908
1909 filter = gtk_file_filter_new();
1910 gtk_file_filter_add_pattern(filter, "*.fio");
1911 gtk_file_filter_add_pattern(filter, "*.job");
Jens Axboe2d262992012-03-07 08:19:30 +01001912 gtk_file_filter_add_pattern(filter, "*.ini");
Jens Axboe0420ba62012-02-29 11:16:52 +01001913 gtk_file_filter_add_mime_type(filter, "text/fio");
1914 gtk_file_filter_set_name(filter, "Fio job file");
1915 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
1916
1917 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1918 gtk_widget_destroy(dialog);
1919 return;
1920 }
1921
1922 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001923
1924 gtk_widget_destroy(dialog);
1925
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001926 if (get_connection_details(&host, &port, &type, &server_start))
Jens Axboea7a42ce2012-03-02 13:12:04 +01001927 goto err;
1928
Jens Axboe0420ba62012-02-29 11:16:52 +01001929 filenames = fn_glist;
1930 while (filenames != NULL) {
Jens Axboee0681f32012-03-06 12:14:42 +01001931 struct fio_client *client;
1932
Jens Axboe2f99deb2012-03-09 14:37:29 +01001933 ge->job_files = realloc(ge->job_files, (ge->nr_job_files + 1) * sizeof(char *));
1934 ge->job_files[ge->nr_job_files] = strdup(filenames->data);
1935 ge->nr_job_files++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001936
Jens Axboee0681f32012-03-06 12:14:42 +01001937 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
1938 if (!client) {
Jens Axboedf06f222012-03-02 13:32:04 +01001939 GError *error;
1940
1941 error = g_error_new(g_quark_from_string("fio"), 1,
1942 "Failed to add client %s", host);
Jens Axboe0420ba62012-02-29 11:16:52 +01001943 report_error(error);
1944 g_error_free(error);
Jens Axboe0420ba62012-02-29 11:16:52 +01001945 }
Jens Axboe2f99deb2012-03-09 14:37:29 +01001946 gfio_client_added(ge, client);
Jens Axboe0420ba62012-02-29 11:16:52 +01001947
1948 g_free(filenames->data);
1949 filenames = g_slist_next(filenames);
1950 }
Jens Axboea7a42ce2012-03-02 13:12:04 +01001951 free(host);
Jens Axboe63a130b2012-03-06 20:08:59 +01001952
1953 if (server_start)
Jens Axboe2f99deb2012-03-09 14:37:29 +01001954 gfio_start_server();
Jens Axboea7a42ce2012-03-02 13:12:04 +01001955err:
Jens Axboe0420ba62012-02-29 11:16:52 +01001956 g_slist_free(fn_glist);
Jens Axboe0420ba62012-02-29 11:16:52 +01001957}
1958
1959static void file_save(GtkWidget *w, gpointer data)
1960{
Jens Axboe63a130b2012-03-06 20:08:59 +01001961 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01001962 GtkWidget *dialog;
1963
1964 dialog = gtk_file_chooser_dialog_new("Save File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001965 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001966 GTK_FILE_CHOOSER_ACTION_SAVE,
1967 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1968 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1969 NULL);
1970
1971 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1972 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
1973
1974 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1975 char *filename;
1976
1977 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1978 // save_job_file(filename);
1979 g_free(filename);
1980 }
1981 gtk_widget_destroy(dialog);
1982}
1983
Jens Axboe9b260bd2012-03-06 11:02:52 +01001984static void view_log_destroy(GtkWidget *w, gpointer data)
1985{
1986 struct gui *ui = (struct gui *) data;
1987
1988 gtk_widget_ref(ui->log_tree);
1989 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
1990 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +01001991 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001992}
1993
1994static void view_log(GtkWidget *w, gpointer data)
1995{
Jens Axboe4cbe7212012-03-06 13:36:17 +01001996 GtkWidget *win, *scroll, *vbox, *box;
1997 struct gui *ui = (struct gui *) data;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001998
Jens Axboe4cbe7212012-03-06 13:36:17 +01001999 if (ui->log_view)
2000 return;
2001
2002 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002003 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +01002004 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002005
Jens Axboe4cbe7212012-03-06 13:36:17 +01002006 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002007
Jens Axboe4cbe7212012-03-06 13:36:17 +01002008 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
2009
2010 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2011
2012 box = gtk_hbox_new(TRUE, 0);
2013 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
2014 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
2015 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
2016
2017 vbox = gtk_vbox_new(TRUE, 5);
2018 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
2019
2020 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002021 gtk_widget_show_all(win);
2022}
2023
Jens Axboe46974a72012-03-02 19:34:13 +01002024static void preferences(GtkWidget *w, gpointer data)
2025{
Jens Axboef3e84402012-03-07 13:14:32 +01002026 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
Jens Axboe46974a72012-03-02 19:34:13 +01002027 int i;
2028
2029 dialog = gtk_dialog_new_with_buttons("Preferences",
Jens Axboe2f99deb2012-03-09 14:37:29 +01002030 GTK_WINDOW(main_ui.window),
Jens Axboe46974a72012-03-02 19:34:13 +01002031 GTK_DIALOG_DESTROY_WITH_PARENT,
2032 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2033 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2034 NULL);
2035
Jens Axboe0b8d11e2012-03-02 19:44:15 +01002036 frame = gtk_frame_new("Debug logging");
Jens Axboe46974a72012-03-02 19:34:13 +01002037 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
Jens Axboef3e84402012-03-07 13:14:32 +01002038
2039 vbox = gtk_vbox_new(FALSE, 6);
2040 gtk_container_add(GTK_CONTAINER(frame), vbox);
2041
Jens Axboe46974a72012-03-02 19:34:13 +01002042 box = gtk_hbox_new(FALSE, 6);
Jens Axboef3e84402012-03-07 13:14:32 +01002043 gtk_container_add(GTK_CONTAINER(vbox), box);
Jens Axboe46974a72012-03-02 19:34:13 +01002044
2045 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
2046
2047 for (i = 0; i < FD_DEBUG_MAX; i++) {
Jens Axboef3e84402012-03-07 13:14:32 +01002048 if (i == 7) {
2049 box = gtk_hbox_new(FALSE, 6);
2050 gtk_container_add(GTK_CONTAINER(vbox), box);
2051 }
2052
2053
Jens Axboe46974a72012-03-02 19:34:13 +01002054 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
Jens Axboe0b8d11e2012-03-02 19:44:15 +01002055 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
Jens Axboe46974a72012-03-02 19:34:13 +01002056 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
2057 }
2058
Jens Axboef3e84402012-03-07 13:14:32 +01002059 frame = gtk_frame_new("Graph font");
2060 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
2061 vbox = gtk_vbox_new(FALSE, 6);
2062 gtk_container_add(GTK_CONTAINER(frame), vbox);
2063
2064 font = gtk_font_button_new();
2065 gtk_box_pack_start(GTK_BOX(vbox), font, FALSE, FALSE, 5);
2066
Jens Axboe46974a72012-03-02 19:34:13 +01002067 gtk_widget_show_all(dialog);
2068
2069 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
2070 gtk_widget_destroy(dialog);
2071 return;
2072 }
2073
2074 for (i = 0; i < FD_DEBUG_MAX; i++) {
2075 int set;
2076
2077 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
2078 if (set)
2079 fio_debug |= (1UL << i);
2080 }
2081
Jens Axboef3e84402012-03-07 13:14:32 +01002082 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
Jens Axboe46974a72012-03-02 19:34:13 +01002083 gtk_widget_destroy(dialog);
2084}
2085
Jens Axboe0420ba62012-02-29 11:16:52 +01002086static void about_dialog(GtkWidget *w, gpointer data)
2087{
Jens Axboe81e4ea62012-03-07 14:18:28 +01002088 const char *authors[] = {
2089 "Jens Axboe <axboe@kernel.dk>",
2090 "Stephen Carmeron <stephenmcameron@gmail.com>",
2091 NULL
2092 };
Jens Axboe84a72ed2012-03-07 14:24:57 +01002093 const char *license[] = {
2094 "Fio is free software; you can redistribute it and/or modify "
2095 "it under the terms of the GNU General Public License as published by "
2096 "the Free Software Foundation; either version 2 of the License, or "
2097 "(at your option) any later version.\n",
2098 "Fio is distributed in the hope that it will be useful, "
2099 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
2100 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
2101 "GNU General Public License for more details.\n",
2102 "You should have received a copy of the GNU General Public License "
2103 "along with Fio; if not, write to the Free Software Foundation, Inc., "
2104 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
2105 };
2106 char *license_trans;
2107
2108 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
2109 license[2], "\n", NULL);
Jens Axboe81e4ea62012-03-07 14:18:28 +01002110
Jens Axboe0420ba62012-02-29 11:16:52 +01002111 gtk_show_about_dialog(NULL,
2112 "program-name", "gfio",
2113 "comments", "Gtk2 UI for fio",
Jens Axboe84a72ed2012-03-07 14:24:57 +01002114 "license", license_trans,
Jens Axboe81e4ea62012-03-07 14:18:28 +01002115 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
2116 "authors", authors,
Jens Axboe0420ba62012-02-29 11:16:52 +01002117 "version", fio_version_string,
Jens Axboe81e4ea62012-03-07 14:18:28 +01002118 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
Jens Axboe0420ba62012-02-29 11:16:52 +01002119 "logo-icon-name", "fio",
2120 /* Must be last: */
Jens Axboe81e4ea62012-03-07 14:18:28 +01002121 "wrap-license", TRUE,
Jens Axboe0420ba62012-02-29 11:16:52 +01002122 NULL);
Jens Axboe84a72ed2012-03-07 14:24:57 +01002123
Jens Axboe2f99deb2012-03-09 14:37:29 +01002124 g_free(license_trans);
Jens Axboe0420ba62012-02-29 11:16:52 +01002125}
2126
2127static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01002128 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01002129 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01002130 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
Jens Axboe2f99deb2012-03-09 14:37:29 +01002131 { "NewFile", GTK_STOCK_NEW, "New", "<Control>N", NULL, G_CALLBACK(file_new) },
Jens Axboe46974a72012-03-02 19:34:13 +01002132 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
2133 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
2134 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01002135 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe46974a72012-03-02 19:34:13 +01002136 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
2137 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01002138};
Jens Axboe3e47bd22012-02-29 13:45:02 +01002139static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01002140
2141static const gchar *ui_string = " \
2142 <ui> \
2143 <menubar name=\"MainMenu\"> \
2144 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01002145 <menuitem name=\"New\" action=\"NewFile\" /> \
2146 <separator name=\"Separator1\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01002147 <menuitem name=\"Open\" action=\"OpenFile\" /> \
2148 <menuitem name=\"Save\" action=\"SaveFile\" /> \
Jens Axboe46974a72012-03-02 19:34:13 +01002149 <separator name=\"Separator2\"/> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01002150 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
2151 <separator name=\"Separator3\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01002152 <menuitem name=\"Quit\" action=\"Quit\" /> \
2153 </menu> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01002154 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
2155 <menuitem name=\"Log\" action=\"ViewLog\" /> \
2156 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01002157 <menu name=\"Help\" action=\"HelpMenuAction\"> \
2158 <menuitem name=\"About\" action=\"About\" /> \
2159 </menu> \
2160 </menubar> \
2161 </ui> \
2162";
2163
Jens Axboe4cbe7212012-03-06 13:36:17 +01002164static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
2165 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01002166{
2167 GtkActionGroup *action_group = gtk_action_group_new("Menu");
2168 GError *error = 0;
2169
2170 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01002171 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01002172
2173 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
2174 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
2175
2176 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
2177 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
2178}
2179
2180void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
2181 GtkWidget *vbox, GtkUIManager *ui_manager)
2182{
2183 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
2184}
2185
Jens Axboe2f99deb2012-03-09 14:37:29 +01002186static GtkWidget *new_client_page(struct gui_entry *ge)
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002187{
Jens Axboe2f99deb2012-03-09 14:37:29 +01002188 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01002189 GdkColor white;
Jens Axboe0420ba62012-02-29 11:16:52 +01002190
Jens Axboe2f99deb2012-03-09 14:37:29 +01002191 main_vbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01002192
Jens Axboe2f99deb2012-03-09 14:37:29 +01002193 ge->topalign = gtk_alignment_new(0, 0, 1, 0);
2194 ge->topvbox = gtk_vbox_new(FALSE, 3);
2195 gtk_container_add(GTK_CONTAINER(ge->topalign), ge->topvbox);
2196 gtk_box_pack_start(GTK_BOX(main_vbox), ge->topalign, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002197
Jens Axboe3e47bd22012-02-29 13:45:02 +01002198 probe = gtk_frame_new("Job");
Jens Axboe2f99deb2012-03-09 14:37:29 +01002199 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01002200 probe_frame = gtk_vbox_new(FALSE, 3);
2201 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
2202
2203 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002204 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2205 ge->probe.hostname = new_info_label_in_frame(probe_box, "Host");
2206 ge->probe.os = new_info_label_in_frame(probe_box, "OS");
2207 ge->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
2208 ge->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
Jens Axboe843ad232012-02-29 11:44:53 +01002209
Jens Axboe3e47bd22012-02-29 13:45:02 +01002210 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002211 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2212
Jens Axboe3863d1a2012-03-09 17:39:05 +01002213 ge->eta.names = new_combo_entry_in_frame(probe_box, "Jobs");
Jens Axboe2f99deb2012-03-09 14:37:29 +01002214 ge->eta.iotype = new_info_entry_in_frame(probe_box, "IO");
2215 ge->eta.ioengine = new_info_entry_in_frame(probe_box, "IO Engine");
2216 ge->eta.iodepth = new_info_entry_in_frame(probe_box, "IO Depth");
2217 ge->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
2218 ge->eta.files = new_info_entry_in_frame(probe_box, "Open files");
2219
2220 probe_box = gtk_hbox_new(FALSE, 3);
2221 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2222 ge->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
2223 ge->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
2224 ge->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
2225 ge->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
2226
2227 /*
2228 * Only add this if we have a commit rate
2229 */
2230#if 0
2231 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe3e47bd22012-02-29 13:45:02 +01002232 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01002233
Jens Axboe2f99deb2012-03-09 14:37:29 +01002234 ge->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
2235 ge->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2236
2237 ge->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
2238 ge->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2239#endif
2240
2241 /*
2242 * Set up a drawing area and IOPS and bandwidth graphs
2243 */
2244 gdk_color_parse("white", &white);
2245 ge->graphs.drawing_area = gtk_drawing_area_new();
2246 ge->graphs.drawing_area_xdim = DRAWING_AREA_XDIM;
2247 ge->graphs.drawing_area_ydim = DRAWING_AREA_YDIM;
2248 gtk_widget_set_size_request(GTK_WIDGET(ge->graphs.drawing_area),
2249 ge->graphs.drawing_area_xdim, ge->graphs.drawing_area_ydim);
2250 gtk_widget_modify_bg(ge->graphs.drawing_area, GTK_STATE_NORMAL, &white);
2251 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "expose_event",
2252 G_CALLBACK(on_expose_drawing_area), &ge->graphs);
2253 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "configure_event",
2254 G_CALLBACK(on_config_drawing_area), &ge->graphs);
2255 ge->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2256 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ge->scrolled_window),
2257 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2258 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ge->scrolled_window),
2259 ge->graphs.drawing_area);
2260 gtk_box_pack_start(GTK_BOX(main_vbox), ge->scrolled_window,
2261 TRUE, TRUE, 0);
2262
2263 setup_graphs(&ge->graphs);
2264
2265 /*
2266 * Set up alignments for widgets at the bottom of ui,
2267 * align bottom left, expand horizontally but not vertically
2268 */
2269 ge->bottomalign = gtk_alignment_new(0, 1, 1, 0);
2270 ge->buttonbox = gtk_hbox_new(FALSE, 0);
2271 gtk_container_add(GTK_CONTAINER(ge->bottomalign), ge->buttonbox);
2272 gtk_box_pack_start(GTK_BOX(main_vbox), ge->bottomalign,
2273 FALSE, FALSE, 0);
2274
2275 add_buttons(ge, buttonspeclist, ARRAYSIZE(buttonspeclist));
2276
2277 /*
2278 * Set up thread status progress bar
2279 */
2280 ge->thread_status_pb = gtk_progress_bar_new();
2281 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
2282 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No connections");
2283 gtk_container_add(GTK_CONTAINER(ge->buttonbox), ge->thread_status_pb);
2284
2285
2286 return main_vbox;
2287}
2288
2289static GtkWidget *new_main_page(struct gui *ui)
2290{
2291 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
2292 GdkColor white;
2293
2294 main_vbox = gtk_vbox_new(FALSE, 3);
2295
2296 /*
2297 * Set up alignments for widgets at the top of ui,
2298 * align top left, expand horizontally but not vertically
2299 */
2300 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
2301 ui->topvbox = gtk_vbox_new(FALSE, 0);
2302 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
2303 gtk_box_pack_start(GTK_BOX(main_vbox), ui->topalign, FALSE, FALSE, 0);
2304
2305 probe = gtk_frame_new("Run statistics");
2306 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
2307 probe_frame = gtk_vbox_new(FALSE, 3);
2308 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
Jens Axboe3e47bd22012-02-29 13:45:02 +01002309
2310 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002311 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
Jens Axboe3863d1a2012-03-09 17:39:05 +01002312 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Running");
Jens Axboeca850992012-03-05 20:04:43 +01002313 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
2314 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
2315 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
2316 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01002317
2318 /*
2319 * Only add this if we have a commit rate
2320 */
2321#if 0
2322 probe_box = gtk_hbox_new(FALSE, 3);
2323 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
2324
Jens Axboe3e47bd22012-02-29 13:45:02 +01002325 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
2326 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2327
Jens Axboe3e47bd22012-02-29 13:45:02 +01002328 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
2329 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01002330#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01002331
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01002332 /*
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002333 * Set up a drawing area and IOPS and bandwidth graphs
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002334 */
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01002335 gdk_color_parse("white", &white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002336 ui->graphs.drawing_area = gtk_drawing_area_new();
2337 ui->graphs.drawing_area_xdim = DRAWING_AREA_XDIM;
2338 ui->graphs.drawing_area_ydim = DRAWING_AREA_YDIM;
2339 gtk_widget_set_size_request(GTK_WIDGET(ui->graphs.drawing_area),
2340 ui->graphs.drawing_area_xdim, ui->graphs.drawing_area_ydim);
2341 gtk_widget_modify_bg(ui->graphs.drawing_area, GTK_STATE_NORMAL, &white);
2342 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "expose_event",
2343 G_CALLBACK(on_expose_drawing_area), &ui->graphs);
2344 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "configure_event",
2345 G_CALLBACK(on_config_drawing_area), &ui->graphs);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002346 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2347 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
2348 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002349 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ui->scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01002350 ui->graphs.drawing_area);
2351 gtk_box_pack_start(GTK_BOX(main_vbox), ui->scrolled_window,
Stephen M. Camerone1645342012-02-24 08:17:32 +01002352 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002353
Jens Axboe2f99deb2012-03-09 14:37:29 +01002354 setup_graphs(&ui->graphs);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002355
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002356 /*
2357 * Set up alignments for widgets at the bottom of ui,
2358 * align bottom left, expand horizontally but not vertically
2359 */
2360 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
2361 ui->buttonbox = gtk_hbox_new(FALSE, 0);
2362 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002363 gtk_box_pack_start(GTK_BOX(main_vbox), ui->bottomalign,
Stephen M. Camerone1645342012-02-24 08:17:32 +01002364 FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002365
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002366 /*
2367 * Set up thread status progress bar
2368 */
2369 ui->thread_status_pb = gtk_progress_bar_new();
2370 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01002371 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002372 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
2373
Jens Axboe2f99deb2012-03-09 14:37:29 +01002374 return main_vbox;
2375}
2376
2377static gboolean notebook_switch_page(GtkNotebook *notebook, GtkWidget *widget,
2378 guint page, gpointer data)
2379
2380{
2381 return TRUE;
2382}
2383
2384static void init_ui(int *argc, char **argv[], struct gui *ui)
2385{
2386 GtkSettings *settings;
2387 GtkUIManager *uimanager;
2388 GtkWidget *menu, *vbox;
2389
2390 /* Magical g*thread incantation, you just need this thread stuff.
2391 * Without it, the update that happens in gfio_update_thread_status
2392 * doesn't really happen in a timely fashion, you need expose events
2393 */
2394 if (!g_thread_supported())
2395 g_thread_init(NULL);
2396 gdk_threads_init();
2397
2398 gtk_init(argc, argv);
2399 settings = gtk_settings_get_default();
2400 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
2401 g_type_init();
2402
2403 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2404 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
2405 gtk_window_set_default_size(GTK_WINDOW(ui->window), 1024, 768);
2406
2407 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
2408 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
2409
2410 ui->vbox = gtk_vbox_new(FALSE, 0);
2411 gtk_container_add(GTK_CONTAINER(ui->window), ui->vbox);
2412
2413 uimanager = gtk_ui_manager_new();
2414 menu = get_menubar_menu(ui->window, uimanager, ui);
2415 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
2416
2417 ui->notebook = gtk_notebook_new();
2418 g_signal_connect(ui->notebook, "switch-page", G_CALLBACK(notebook_switch_page), ui);
Jens Axboeb870c312012-03-09 17:22:01 +01002419 gtk_notebook_set_scrollable(GTK_NOTEBOOK(ui->notebook), 1);
Jens Axboe0aa928c2012-03-09 17:24:07 +01002420 gtk_notebook_popup_enable(GTK_NOTEBOOK(ui->notebook));
Jens Axboe2f99deb2012-03-09 14:37:29 +01002421 gtk_container_add(GTK_CONTAINER(ui->vbox), ui->notebook);
2422
2423 vbox = new_main_page(ui);
2424
2425 gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), vbox, gtk_label_new("Main"));
2426
Jens Axboe9b260bd2012-03-06 11:02:52 +01002427 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002428
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002429 gtk_widget_show_all(ui->window);
2430}
2431
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002432int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002433{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002434 if (initialize_fio(envp))
2435 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01002436 if (fio_init_options())
2437 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01002438
Jens Axboe2f99deb2012-03-09 14:37:29 +01002439 memset(&main_ui, 0, sizeof(main_ui));
2440 INIT_FLIST_HEAD(&main_ui.list);
2441
2442 init_ui(&argc, &argv, &main_ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01002443
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002444 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002445 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002446 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002447 return 0;
2448}