blob: c78d3af10ba7261084fdae7124d50751c99556ac [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 Axboe8577f4f2012-03-09 19:28:27 +010037static unsigned int gfio_graph_limit = 100;
Jens Axboe63a130b2012-03-06 20:08:59 +010038
Jens Axboe6b79c802012-03-08 10:51:36 +010039static void view_log(GtkWidget *w, gpointer data);
Jens Axboe3e47bd22012-02-29 13:45:02 +010040
Stephen M. Cameronf3074002012-02-24 08:17:30 +010041#define ARRAYSIZE(x) (sizeof((x)) / (sizeof((x)[0])))
42
43typedef void (*clickfunction)(GtkWidget *widget, gpointer data);
44
Jens Axboe3e47bd22012-02-29 13:45:02 +010045static void connect_clicked(GtkWidget *widget, gpointer data);
Stephen M. Cameronf3074002012-02-24 08:17:30 +010046static void start_job_clicked(GtkWidget *widget, gpointer data);
Jens Axboeb9d2f302012-03-08 20:36:28 +010047static void send_clicked(GtkWidget *widget, gpointer data);
Stephen M. Cameronf3074002012-02-24 08:17:30 +010048
49static struct button_spec {
50 const char *buttontext;
51 clickfunction f;
52 const char *tooltiptext;
Jens Axboe3e47bd22012-02-29 13:45:02 +010053 const int start_insensitive;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010054} buttonspeclist[] = {
Jens Axboe3e47bd22012-02-29 13:45:02 +010055#define CONNECT_BUTTON 0
Jens Axboeb9d2f302012-03-08 20:36:28 +010056#define SEND_BUTTON 1
57#define START_JOB_BUTTON 2
Jens Axboe3e47bd22012-02-29 13:45:02 +010058 { "Connect", connect_clicked, "Connect to host", 0 },
Jens Axboeb9d2f302012-03-08 20:36:28 +010059 { "Send", send_clicked, "Send job description to host", 1 },
60 { "Start Job", start_job_clicked,
Jens Axboe2f99deb2012-03-09 14:37:29 +010061 "Start the current job on the server", 1 },
Stephen M. Cameronf3074002012-02-24 08:17:30 +010062};
63
Jens Axboe843ad232012-02-29 11:44:53 +010064struct probe_widget {
65 GtkWidget *hostname;
66 GtkWidget *os;
67 GtkWidget *arch;
68 GtkWidget *fio_ver;
69};
70
Jens Axboe3e47bd22012-02-29 13:45:02 +010071struct eta_widget {
Jens Axboe3863d1a2012-03-09 17:39:05 +010072 GtkWidget *names;
Jens Axboe807f9972012-03-02 10:25:24 +010073 GtkWidget *iotype;
74 GtkWidget *ioengine;
75 GtkWidget *iodepth;
Jens Axboe3e47bd22012-02-29 13:45:02 +010076 GtkWidget *jobs;
77 GtkWidget *files;
78 GtkWidget *read_bw;
79 GtkWidget *read_iops;
80 GtkWidget *cr_bw;
81 GtkWidget *cr_iops;
82 GtkWidget *write_bw;
83 GtkWidget *write_iops;
84 GtkWidget *cw_bw;
85 GtkWidget *cw_iops;
86};
87
Jens Axboe2f99deb2012-03-09 14:37:29 +010088struct gfio_graphs {
89#define DRAWING_AREA_XDIM 1000
90#define DRAWING_AREA_YDIM 400
91 GtkWidget *drawing_area;
92 int drawing_area_xdim;
93 int drawing_area_ydim;
94
95 struct graph *iops_graph;
96 struct graph *bandwidth_graph;
97};
98
99/*
100 * Main window widgets and data
101 */
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100102struct gui {
103 GtkWidget *window;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100104 GtkWidget *vbox;
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +0100105 GtkWidget *topvbox;
106 GtkWidget *topalign;
107 GtkWidget *bottomalign;
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +0100108 GtkWidget *thread_status_pb;
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100109 GtkWidget *buttonbox;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100110 GtkWidget *scrolled_window;
111 GtkWidget *notebook;
112 GtkWidget *error_info_bar;
113 GtkWidget *error_label;
114 GtkListStore *log_model;
115 GtkWidget *log_tree;
116 GtkWidget *log_view;
117 struct gfio_graphs graphs;
118 struct probe_widget probe;
119 struct eta_widget eta;
120 pthread_t server_t;
121
Jens Axboea9eccde2012-03-09 14:59:42 +0100122 pthread_t t;
123 int handler_running;
124
Jens Axboe2f99deb2012-03-09 14:37:29 +0100125 struct flist_head list;
126} main_ui;
127
128/*
129 * Notebook entry
130 */
131struct gui_entry {
132 struct flist_head list;
133 struct gui *ui;
134
135 GtkWidget *vbox;
136 GtkWidget *topvbox;
137 GtkWidget *topalign;
138 GtkWidget *bottomalign;
139 GtkWidget *thread_status_pb;
140 GtkWidget *buttonbox;
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100141 GtkWidget *button[ARRAYSIZE(buttonspeclist)];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100142 GtkWidget *scrolled_window;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100143 GtkWidget *notebook;
Jens Axboe0420ba62012-02-29 11:16:52 +0100144 GtkWidget *error_info_bar;
145 GtkWidget *error_label;
Jens Axboef9d40b42012-03-06 09:52:49 +0100146 GtkWidget *results_notebook;
147 GtkWidget *results_window;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100148 GtkListStore *log_model;
149 GtkWidget *log_tree;
Jens Axboe4cbe7212012-03-06 13:36:17 +0100150 GtkWidget *log_view;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100151 struct gfio_graphs graphs;
Jens Axboe843ad232012-02-29 11:44:53 +0100152 struct probe_widget probe;
Jens Axboe3e47bd22012-02-29 13:45:02 +0100153 struct eta_widget eta;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100154 GtkWidget *page_label;
155 gint page_num;
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100156 int connected;
Jens Axboe0420ba62012-02-29 11:16:52 +0100157
Jens Axboeb9d2f302012-03-08 20:36:28 +0100158 struct gfio_client *client;
Jens Axboe0420ba62012-02-29 11:16:52 +0100159 int nr_job_files;
160 char **job_files;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100161};
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100162
Jens Axboee0681f32012-03-06 12:14:42 +0100163struct gfio_client {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100164 struct gui_entry *ge;
Jens Axboeb9d2f302012-03-08 20:36:28 +0100165 struct fio_client *client;
Jens Axboee0681f32012-03-06 12:14:42 +0100166 GtkWidget *results_widget;
167 GtkWidget *disk_util_frame;
Jens Axboe6b79c802012-03-08 10:51:36 +0100168 GtkWidget *err_entry;
Jens Axboedcaeb602012-03-08 19:45:37 +0100169 unsigned int job_added;
170 struct thread_options o;
Jens Axboee0681f32012-03-06 12:14:42 +0100171};
172
Jens Axboe9988ca72012-03-09 15:14:06 +0100173static void gfio_update_thread_status(struct gui_entry *ge, char *status_message, double perc);
174static void gfio_update_thread_status_all(char *status_message, double perc);
Jens Axboec7249262012-03-09 17:11:04 +0100175void report_error(GError *error);
Jens Axboe9988ca72012-03-09 15:14:06 +0100176
Jens Axboe2f99deb2012-03-09 14:37:29 +0100177static struct graph *setup_iops_graph(void)
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100178{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100179 struct graph *g;
180
181 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
182 graph_title(g, "IOPS");
183 graph_x_title(g, "Time (secs)");
184 graph_y_title(g, "IOs / sec");
185 graph_add_label(g, "Read IOPS");
186 graph_add_label(g, "Write IOPS");
187 graph_set_color(g, "Read IOPS", 0.13, 0.54, 0.13);
188 graph_set_color(g, "Write IOPS", 1.0, 0.0, 0.0);
Jens Axboe8577f4f2012-03-09 19:28:27 +0100189 line_graph_set_data_count_limit(g, gfio_graph_limit);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100190 return g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100191}
192
Jens Axboe2f99deb2012-03-09 14:37:29 +0100193static struct graph *setup_bandwidth_graph(void)
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100194{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100195 struct graph *g;
196
197 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
198 graph_title(g, "Bandwidth");
199 graph_x_title(g, "Time (secs)");
200 graph_y_title(g, "Kbytes / sec");
201 graph_add_label(g, "Read Bandwidth");
202 graph_add_label(g, "Write Bandwidth");
203 graph_set_color(g, "Read Bandwidth", 0.13, 0.54, 0.13);
204 graph_set_color(g, "Write Bandwidth", 1.0, 0.0, 0.0);
205 line_graph_set_data_count_limit(g, 100);
206 return g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100207}
208
Jens Axboe2f99deb2012-03-09 14:37:29 +0100209static void setup_graphs(struct gfio_graphs *g)
Jens Axboe8663ea62012-03-02 14:04:30 +0100210{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100211 g->iops_graph = setup_iops_graph();
212 g->bandwidth_graph = setup_bandwidth_graph();
213}
214
215static void clear_ge_ui_info(struct gui_entry *ge)
216{
217 gtk_label_set_text(GTK_LABEL(ge->probe.hostname), "");
218 gtk_label_set_text(GTK_LABEL(ge->probe.os), "");
219 gtk_label_set_text(GTK_LABEL(ge->probe.arch), "");
220 gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100221#if 0
222 /* should we empty it... */
Jens Axboe2f99deb2012-03-09 14:37:29 +0100223 gtk_entry_set_text(GTK_ENTRY(ge->eta.name), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100224#endif
Jens Axboe2f99deb2012-03-09 14:37:29 +0100225 gtk_entry_set_text(GTK_ENTRY(ge->eta.iotype), "");
226 gtk_entry_set_text(GTK_ENTRY(ge->eta.ioengine), "");
227 gtk_entry_set_text(GTK_ENTRY(ge->eta.iodepth), "");
228 gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), "");
229 gtk_entry_set_text(GTK_ENTRY(ge->eta.files), "");
230 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), "");
231 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), "");
232 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), "");
233 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100234}
235
Jens Axboe3863d1a2012-03-09 17:39:05 +0100236static GtkWidget *new_combo_entry_in_frame(GtkWidget *box, const char *label)
237{
238 GtkWidget *entry, *frame;
239
240 frame = gtk_frame_new(label);
241 entry = gtk_combo_box_new_text();
242 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
243 gtk_container_add(GTK_CONTAINER(frame), entry);
244
245 return entry;
246}
247
Jens Axboe3650a3c2012-03-05 14:09:03 +0100248static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
249{
250 GtkWidget *entry, *frame;
251
252 frame = gtk_frame_new(label);
253 entry = gtk_entry_new();
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100254 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100255 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
256 gtk_container_add(GTK_CONTAINER(frame), entry);
257
258 return entry;
259}
260
261static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
262{
263 GtkWidget *label_widget;
264 GtkWidget *frame;
265
266 frame = gtk_frame_new(label);
267 label_widget = gtk_label_new(NULL);
268 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
269 gtk_container_add(GTK_CONTAINER(frame), label_widget);
270
271 return label_widget;
272}
273
274static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
275{
276 GtkWidget *button, *box;
277
278 box = gtk_hbox_new(FALSE, 3);
279 gtk_container_add(GTK_CONTAINER(hbox), box);
280
281 button = gtk_spin_button_new_with_range(min, max, 1.0);
282 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
283
284 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
285 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
286
287 return button;
288}
289
Jens Axboe2f99deb2012-03-09 14:37:29 +0100290static void gfio_set_connected(struct gui_entry *ge, int connected)
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100291{
292 if (connected) {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100293 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 1);
294 ge->connected = 1;
295 gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), "Disconnect");
296 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100297 } else {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100298 ge->connected = 0;
299 gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), "Connect");
300 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 0);
301 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 0);
302 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100303 }
304}
305
Jens Axboe3650a3c2012-03-05 14:09:03 +0100306static void label_set_int_value(GtkWidget *entry, unsigned int val)
307{
308 char tmp[80];
309
310 sprintf(tmp, "%u", val);
311 gtk_label_set_text(GTK_LABEL(entry), tmp);
312}
313
314static void entry_set_int_value(GtkWidget *entry, unsigned int val)
315{
316 char tmp[80];
317
318 sprintf(tmp, "%u", val);
319 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
320}
321
Jens Axboea2697902012-03-05 16:43:49 +0100322#define ALIGN_LEFT 1
323#define ALIGN_RIGHT 2
324#define INVISIBLE 4
325#define UNSORTABLE 8
326
327GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
328{
329 GtkCellRenderer *renderer;
330 GtkTreeViewColumn *col;
331 double xalign = 0.0; /* left as default */
332 PangoAlignment align;
333 gboolean visible;
334
335 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
336 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
337 PANGO_ALIGN_CENTER;
338 visible = !(flags & INVISIBLE);
339
340 renderer = gtk_cell_renderer_text_new();
341 col = gtk_tree_view_column_new();
342
343 gtk_tree_view_column_set_title(col, title);
344 if (!(flags & UNSORTABLE))
345 gtk_tree_view_column_set_sort_column_id(col, index);
346 gtk_tree_view_column_set_resizable(col, TRUE);
347 gtk_tree_view_column_pack_start(col, renderer, TRUE);
348 gtk_tree_view_column_add_attribute(col, renderer, "text", index);
349 gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
350 switch (align) {
351 case PANGO_ALIGN_LEFT:
352 xalign = 0.0;
353 break;
354 case PANGO_ALIGN_CENTER:
355 xalign = 0.5;
356 break;
357 case PANGO_ALIGN_RIGHT:
358 xalign = 1.0;
359 break;
360 }
361 gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
362 gtk_tree_view_column_set_visible(col, visible);
363 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
364 return col;
365}
366
Jens Axboe9b260bd2012-03-06 11:02:52 +0100367static void gfio_ui_setup_log(struct gui *ui)
368{
369 GtkTreeSelection *selection;
370 GtkListStore *model;
371 GtkWidget *tree_view;
372
373 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
374
375 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
376 gtk_widget_set_can_focus(tree_view, FALSE);
377
378 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
379 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
Jens Axboe661f7412012-03-06 13:55:45 +0100380 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
381 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100382
383 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
384 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
385 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
Jens Axboef095d562012-03-06 13:49:12 +0100386 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100387
388 ui->log_model = model;
389 ui->log_tree = tree_view;
390}
391
Jens Axboea2697902012-03-05 16:43:49 +0100392static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
393 fio_fp64_t *plist,
394 unsigned int len,
395 const char *base,
396 unsigned int scale)
397{
398 GType types[FIO_IO_U_LIST_MAX_LEN];
399 GtkWidget *tree_view;
400 GtkTreeSelection *selection;
401 GtkListStore *model;
402 GtkTreeIter iter;
403 int i;
404
405 for (i = 0; i < len; i++)
406 types[i] = G_TYPE_INT;
407
408 model = gtk_list_store_newv(len, types);
409
410 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
411 gtk_widget_set_can_focus(tree_view, FALSE);
412
Jens Axboe661f7412012-03-06 13:55:45 +0100413 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
414 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
415
Jens Axboea2697902012-03-05 16:43:49 +0100416 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
417 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
418
419 for (i = 0; i < len; i++) {
420 char fbuf[8];
421
422 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
423 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
424 }
425
426 gtk_list_store_append(model, &iter);
427
Jens Axboee0681f32012-03-06 12:14:42 +0100428 for (i = 0; i < len; i++) {
429 if (scale)
430 ovals[i] = (ovals[i] + 999) / 1000;
Jens Axboea2697902012-03-05 16:43:49 +0100431 gtk_list_store_set(model, &iter, i, ovals[i], -1);
Jens Axboee0681f32012-03-06 12:14:42 +0100432 }
Jens Axboea2697902012-03-05 16:43:49 +0100433
434 return tree_view;
435}
436
437static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
438 int ddir)
439{
440 unsigned int *io_u_plat = ts->io_u_plat[ddir];
441 unsigned long nr = ts->clat_stat[ddir].samples;
442 fio_fp64_t *plist = ts->percentile_list;
443 unsigned int *ovals, len, minv, maxv, scale_down;
444 const char *base;
445 GtkWidget *tree_view, *frame, *hbox;
446 char tmp[64];
447
448 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
449 if (!len)
450 goto out;
451
452 /*
453 * We default to usecs, but if the value range is such that we
454 * should scale down to msecs, do that.
455 */
456 if (minv > 2000 && maxv > 99999) {
457 scale_down = 1;
458 base = "msec";
459 } else {
460 scale_down = 0;
461 base = "usec";
462 }
463
464 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
465
466 sprintf(tmp, "Completion percentiles (%s)", base);
467 frame = gtk_frame_new(tmp);
468 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
469
470 hbox = gtk_hbox_new(FALSE, 3);
471 gtk_container_add(GTK_CONTAINER(frame), hbox);
472
473 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
474out:
475 if (ovals)
476 free(ovals);
477}
478
Jens Axboe3650a3c2012-03-05 14:09:03 +0100479static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
480 unsigned long max, double mean, double dev)
481{
482 const char *base = "(usec)";
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100483 GtkWidget *hbox, *label, *frame;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100484 char *minp, *maxp;
485 char tmp[64];
486
487 if (!usec_to_msec(&min, &max, &mean, &dev))
488 base = "(msec)";
489
490 minp = num2str(min, 6, 1, 0);
491 maxp = num2str(max, 6, 1, 0);
492
Jens Axboe3650a3c2012-03-05 14:09:03 +0100493 sprintf(tmp, "%s %s", name, base);
494 frame = gtk_frame_new(tmp);
495 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
496
Jens Axboe3650a3c2012-03-05 14:09:03 +0100497 hbox = gtk_hbox_new(FALSE, 3);
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100498 gtk_container_add(GTK_CONTAINER(frame), hbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100499
500 label = new_info_label_in_frame(hbox, "Minimum");
501 gtk_label_set_text(GTK_LABEL(label), minp);
502 label = new_info_label_in_frame(hbox, "Maximum");
503 gtk_label_set_text(GTK_LABEL(label), maxp);
504 label = new_info_label_in_frame(hbox, "Average");
505 sprintf(tmp, "%5.02f", mean);
506 gtk_label_set_text(GTK_LABEL(label), tmp);
507 label = new_info_label_in_frame(hbox, "Standard deviation");
508 sprintf(tmp, "%5.02f", dev);
509 gtk_label_set_text(GTK_LABEL(label), tmp);
510
511 free(minp);
512 free(maxp);
513
514}
515
Jens Axboeca850992012-03-05 20:04:43 +0100516#define GFIO_CLAT 1
517#define GFIO_SLAT 2
518#define GFIO_LAT 4
519
Jens Axboe3650a3c2012-03-05 14:09:03 +0100520static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
521 struct thread_stat *ts, int ddir)
522{
523 const char *ddir_label[2] = { "Read", "Write" };
Jens Axboe0b761302012-03-05 20:44:11 +0100524 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
Jens Axboee0681f32012-03-06 12:14:42 +0100525 unsigned long min[3], max[3], runt;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100526 unsigned long long bw, iops;
Jens Axboeca850992012-03-05 20:04:43 +0100527 unsigned int flags = 0;
Jens Axboee0681f32012-03-06 12:14:42 +0100528 double mean[3], dev[3];
Jens Axboe3650a3c2012-03-05 14:09:03 +0100529 char *io_p, *bw_p, *iops_p;
530 int i2p;
531
532 if (!ts->runtime[ddir])
533 return;
534
535 i2p = is_power_of_2(rs->kb_base);
536 runt = ts->runtime[ddir];
537
538 bw = (1000 * ts->io_bytes[ddir]) / runt;
539 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
540 bw_p = num2str(bw, 6, 1, i2p);
541
542 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
543 iops_p = num2str(iops, 6, 1, 0);
544
545 box = gtk_hbox_new(FALSE, 3);
546 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
547
548 frame = gtk_frame_new(ddir_label[ddir]);
549 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
550
Jens Axboe0b761302012-03-05 20:44:11 +0100551 main_vbox = gtk_vbox_new(FALSE, 3);
552 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100553
554 box = gtk_hbox_new(FALSE, 3);
Jens Axboe0b761302012-03-05 20:44:11 +0100555 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100556
557 label = new_info_label_in_frame(box, "IO");
558 gtk_label_set_text(GTK_LABEL(label), io_p);
559 label = new_info_label_in_frame(box, "Bandwidth");
560 gtk_label_set_text(GTK_LABEL(label), bw_p);
561 label = new_info_label_in_frame(box, "IOPS");
562 gtk_label_set_text(GTK_LABEL(label), iops_p);
563 label = new_info_label_in_frame(box, "Runtime (msec)");
564 label_set_int_value(label, ts->runtime[ddir]);
565
Jens Axboee0681f32012-03-06 12:14:42 +0100566 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
Jens Axboeca850992012-03-05 20:04:43 +0100567 double p_of_agg = 100.0;
568 const char *bw_str = "KB";
569 char tmp[32];
570
571 if (rs->agg[ddir]) {
Jens Axboee0681f32012-03-06 12:14:42 +0100572 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
Jens Axboeca850992012-03-05 20:04:43 +0100573 if (p_of_agg > 100.0)
574 p_of_agg = 100.0;
575 }
576
Jens Axboee0681f32012-03-06 12:14:42 +0100577 if (mean[0] > 999999.9) {
578 min[0] /= 1000.0;
579 max[0] /= 1000.0;
580 mean[0] /= 1000.0;
581 dev[0] /= 1000.0;
Jens Axboeca850992012-03-05 20:04:43 +0100582 bw_str = "MB";
583 }
584
Jens Axboe0b761302012-03-05 20:44:11 +0100585 sprintf(tmp, "Bandwidth (%s)", bw_str);
586 frame = gtk_frame_new(tmp);
587 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
Jens Axboeca850992012-03-05 20:04:43 +0100588
Jens Axboe0b761302012-03-05 20:44:11 +0100589 box = gtk_hbox_new(FALSE, 3);
590 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboeca850992012-03-05 20:04:43 +0100591
Jens Axboe0b761302012-03-05 20:44:11 +0100592 label = new_info_label_in_frame(box, "Minimum");
Jens Axboee0681f32012-03-06 12:14:42 +0100593 label_set_int_value(label, min[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100594 label = new_info_label_in_frame(box, "Maximum");
Jens Axboee0681f32012-03-06 12:14:42 +0100595 label_set_int_value(label, max[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100596 label = new_info_label_in_frame(box, "Percentage of jobs");
Jens Axboeca850992012-03-05 20:04:43 +0100597 sprintf(tmp, "%3.2f%%", p_of_agg);
598 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100599 label = new_info_label_in_frame(box, "Average");
Jens Axboee0681f32012-03-06 12:14:42 +0100600 sprintf(tmp, "%5.02f", mean[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100601 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100602 label = new_info_label_in_frame(box, "Standard deviation");
Jens Axboee0681f32012-03-06 12:14:42 +0100603 sprintf(tmp, "%5.02f", dev[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100604 gtk_label_set_text(GTK_LABEL(label), tmp);
605 }
606
Jens Axboee0681f32012-03-06 12:14:42 +0100607 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
Jens Axboe2b089892012-03-06 08:09:17 +0100608 flags |= GFIO_SLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100609 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
Jens Axboe2b089892012-03-06 08:09:17 +0100610 flags |= GFIO_CLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100611 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
Jens Axboe2b089892012-03-06 08:09:17 +0100612 flags |= GFIO_LAT;
613
614 if (flags) {
615 frame = gtk_frame_new("Latency");
616 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
617
618 vbox = gtk_vbox_new(FALSE, 3);
619 gtk_container_add(GTK_CONTAINER(frame), vbox);
620
621 if (flags & GFIO_SLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100622 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
Jens Axboe2b089892012-03-06 08:09:17 +0100623 if (flags & GFIO_CLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100624 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
Jens Axboe2b089892012-03-06 08:09:17 +0100625 if (flags & GFIO_LAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100626 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
Jens Axboe2b089892012-03-06 08:09:17 +0100627 }
628
629 if (ts->clat_percentiles)
630 gfio_show_clat_percentiles(main_vbox, ts, ddir);
631
632
Jens Axboe3650a3c2012-03-05 14:09:03 +0100633 free(io_p);
634 free(bw_p);
635 free(iops_p);
636}
637
Jens Axboee5bd1342012-03-05 21:38:12 +0100638static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
639 const char **labels)
640{
641 GtkWidget *tree_view;
642 GtkTreeSelection *selection;
643 GtkListStore *model;
644 GtkTreeIter iter;
645 GType *types;
646 int i, skipped;
647
648 /*
649 * Check if all are empty, in which case don't bother
650 */
651 for (i = 0, skipped = 0; i < num; i++)
652 if (lat[i] <= 0.0)
653 skipped++;
654
655 if (skipped == num)
656 return NULL;
657
658 types = malloc(num * sizeof(GType));
659
660 for (i = 0; i < num; i++)
661 types[i] = G_TYPE_STRING;
662
663 model = gtk_list_store_newv(num, types);
664 free(types);
665 types = NULL;
666
667 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
668 gtk_widget_set_can_focus(tree_view, FALSE);
669
Jens Axboe661f7412012-03-06 13:55:45 +0100670 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
671 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
672
Jens Axboee5bd1342012-03-05 21:38:12 +0100673 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
674 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
675
676 for (i = 0; i < num; i++)
677 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
678
679 gtk_list_store_append(model, &iter);
680
681 for (i = 0; i < num; i++) {
682 char fbuf[32];
683
684 if (lat[i] <= 0.0)
685 sprintf(fbuf, "0.00");
686 else
687 sprintf(fbuf, "%3.2f%%", lat[i]);
688
689 gtk_list_store_set(model, &iter, i, fbuf, -1);
690 }
691
692 return tree_view;
693}
694
695static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
696{
697 GtkWidget *box, *frame, *tree_view;
698 double io_u_lat_u[FIO_IO_U_LAT_U_NR];
699 double io_u_lat_m[FIO_IO_U_LAT_M_NR];
700 const char *uranges[] = { "2", "4", "10", "20", "50", "100",
701 "250", "500", "750", "1000", };
702 const char *mranges[] = { "2", "4", "10", "20", "50", "100",
703 "250", "500", "750", "1000", "2000",
704 ">= 2000", };
705
706 stat_calc_lat_u(ts, io_u_lat_u);
707 stat_calc_lat_m(ts, io_u_lat_m);
708
709 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
710 if (tree_view) {
711 frame = gtk_frame_new("Latency buckets (usec)");
712 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
713
714 box = gtk_hbox_new(FALSE, 3);
715 gtk_container_add(GTK_CONTAINER(frame), box);
716 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
717 }
718
719 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
720 if (tree_view) {
721 frame = gtk_frame_new("Latency buckets (msec)");
722 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
723
724 box = gtk_hbox_new(FALSE, 3);
725 gtk_container_add(GTK_CONTAINER(frame), box);
726 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
727 }
728}
729
Jens Axboe2e331012012-03-05 22:07:54 +0100730static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
731{
732 GtkWidget *box, *frame, *entry;
733 double usr_cpu, sys_cpu;
734 unsigned long runtime;
735 char tmp[32];
736
737 runtime = ts->total_run_time;
738 if (runtime) {
739 double runt = (double) runtime;
740
741 usr_cpu = (double) ts->usr_time * 100 / runt;
742 sys_cpu = (double) ts->sys_time * 100 / runt;
743 } else {
744 usr_cpu = 0;
745 sys_cpu = 0;
746 }
747
748 frame = gtk_frame_new("OS resources");
749 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
750
751 box = gtk_hbox_new(FALSE, 3);
752 gtk_container_add(GTK_CONTAINER(frame), box);
753
754 entry = new_info_entry_in_frame(box, "User CPU");
755 sprintf(tmp, "%3.2f%%", usr_cpu);
756 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
757 entry = new_info_entry_in_frame(box, "System CPU");
758 sprintf(tmp, "%3.2f%%", sys_cpu);
759 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
760 entry = new_info_entry_in_frame(box, "Context switches");
761 entry_set_int_value(entry, ts->ctx);
762 entry = new_info_entry_in_frame(box, "Major faults");
763 entry_set_int_value(entry, ts->majf);
764 entry = new_info_entry_in_frame(box, "Minor faults");
765 entry_set_int_value(entry, ts->minf);
766}
Jens Axboe19998db2012-03-06 09:17:59 +0100767static void gfio_add_sc_depths_tree(GtkListStore *model,
768 struct thread_stat *ts, unsigned int len,
769 int submit)
770{
771 double io_u_dist[FIO_IO_U_MAP_NR];
772 GtkTreeIter iter;
773 /* Bits 0, and 3-8 */
774 const int add_mask = 0x1f9;
775 int i, j;
776
777 if (submit)
778 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
779 else
780 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
781
782 gtk_list_store_append(model, &iter);
783
784 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
785
786 for (i = 1, j = 0; i < len; i++) {
787 char fbuf[32];
788
789 if (!(add_mask & (1UL << (i - 1))))
790 sprintf(fbuf, "0.0%%");
791 else {
792 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
793 j++;
794 }
795
796 gtk_list_store_set(model, &iter, i, fbuf, -1);
797 }
798
799}
800
801static void gfio_add_total_depths_tree(GtkListStore *model,
802 struct thread_stat *ts, unsigned int len)
803{
804 double io_u_dist[FIO_IO_U_MAP_NR];
805 GtkTreeIter iter;
806 /* Bits 1-6, and 8 */
807 const int add_mask = 0x17e;
808 int i, j;
809
810 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
811
812 gtk_list_store_append(model, &iter);
813
814 gtk_list_store_set(model, &iter, 0, "Total", -1);
815
816 for (i = 1, j = 0; i < len; i++) {
817 char fbuf[32];
818
819 if (!(add_mask & (1UL << (i - 1))))
820 sprintf(fbuf, "0.0%%");
821 else {
822 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
823 j++;
824 }
825
826 gtk_list_store_set(model, &iter, i, fbuf, -1);
827 }
828
829}
Jens Axboe2e331012012-03-05 22:07:54 +0100830
831static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
832{
Jens Axboe2e331012012-03-05 22:07:54 +0100833 GtkWidget *frame, *box, *tree_view;
834 GtkTreeSelection *selection;
835 GtkListStore *model;
Jens Axboe2e331012012-03-05 22:07:54 +0100836 GType types[FIO_IO_U_MAP_NR + 1];
837 int i;
Jens Axboe19998db2012-03-06 09:17:59 +0100838#define NR_LABELS 10
839 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
Jens Axboe2e331012012-03-05 22:07:54 +0100840
841 frame = gtk_frame_new("IO depths");
842 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
843
844 box = gtk_hbox_new(FALSE, 3);
845 gtk_container_add(GTK_CONTAINER(frame), box);
846
Jens Axboe19998db2012-03-06 09:17:59 +0100847 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100848 types[i] = G_TYPE_STRING;
849
Jens Axboe19998db2012-03-06 09:17:59 +0100850 model = gtk_list_store_newv(NR_LABELS, types);
Jens Axboe2e331012012-03-05 22:07:54 +0100851
852 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
853 gtk_widget_set_can_focus(tree_view, FALSE);
854
Jens Axboe661f7412012-03-06 13:55:45 +0100855 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
856 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
857
Jens Axboe2e331012012-03-05 22:07:54 +0100858 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
859 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
860
Jens Axboe19998db2012-03-06 09:17:59 +0100861 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100862 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
863
Jens Axboe19998db2012-03-06 09:17:59 +0100864 gfio_add_total_depths_tree(model, ts, NR_LABELS);
865 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 1);
866 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 0);
Jens Axboe2e331012012-03-05 22:07:54 +0100867
868 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
869}
870
Jens Axboef9d40b42012-03-06 09:52:49 +0100871static gboolean results_window_delete(GtkWidget *w, gpointer data)
872{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100873 struct gui_entry *ge = (struct gui_entry *) data;
Jens Axboef9d40b42012-03-06 09:52:49 +0100874
875 gtk_widget_destroy(w);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100876 ge->results_window = NULL;
877 ge->results_notebook = NULL;
Jens Axboef9d40b42012-03-06 09:52:49 +0100878 return TRUE;
879}
880
Jens Axboe2f99deb2012-03-09 14:37:29 +0100881static GtkWidget *get_results_window(struct gui_entry *ge)
Jens Axboef9d40b42012-03-06 09:52:49 +0100882{
883 GtkWidget *win, *notebook;
884
Jens Axboe2f99deb2012-03-09 14:37:29 +0100885 if (ge->results_window)
886 return ge->results_notebook;
Jens Axboef9d40b42012-03-06 09:52:49 +0100887
888 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
889 gtk_window_set_title(GTK_WINDOW(win), "Results");
Jens Axboeb01329d2012-03-07 20:31:28 +0100890 gtk_window_set_default_size(GTK_WINDOW(win), 1024, 768);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100891 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ge);
892 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ge);
Jens Axboef9d40b42012-03-06 09:52:49 +0100893
894 notebook = gtk_notebook_new();
Jens Axboe0aa928c2012-03-09 17:24:07 +0100895 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), 1);
896 gtk_notebook_popup_enable(GTK_NOTEBOOK(notebook));
Jens Axboef9d40b42012-03-06 09:52:49 +0100897 gtk_container_add(GTK_CONTAINER(win), notebook);
898
Jens Axboe2f99deb2012-03-09 14:37:29 +0100899 ge->results_window = win;
900 ge->results_notebook = notebook;
901 return ge->results_notebook;
Jens Axboef9d40b42012-03-06 09:52:49 +0100902}
903
Jens Axboe3650a3c2012-03-05 14:09:03 +0100904static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
905 struct group_run_stats *rs)
906{
Jens Axboeb01329d2012-03-07 20:31:28 +0100907 GtkWidget *res_win, *box, *vbox, *entry, *scroll;
Jens Axboee0681f32012-03-06 12:14:42 +0100908 struct gfio_client *gc = client->client_data;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100909
910 gdk_threads_enter();
911
Jens Axboe2f99deb2012-03-09 14:37:29 +0100912 res_win = get_results_window(gc->ge);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100913
Jens Axboeb01329d2012-03-07 20:31:28 +0100914 scroll = gtk_scrolled_window_new(NULL, NULL);
915 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
916 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
917
Jens Axboe3650a3c2012-03-05 14:09:03 +0100918 vbox = gtk_vbox_new(FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100919
Jens Axboeb01329d2012-03-07 20:31:28 +0100920 box = gtk_hbox_new(FALSE, 0);
921 gtk_box_pack_start(GTK_BOX(vbox), box, TRUE, FALSE, 5);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100922
Jens Axboeb01329d2012-03-07 20:31:28 +0100923 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
924
925 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), scroll, gtk_label_new(ts->name));
Jens Axboef9d40b42012-03-06 09:52:49 +0100926
Jens Axboee0681f32012-03-06 12:14:42 +0100927 gc->results_widget = vbox;
928
Jens Axboe3650a3c2012-03-05 14:09:03 +0100929 entry = new_info_entry_in_frame(box, "Name");
930 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
931 if (strlen(ts->description)) {
932 entry = new_info_entry_in_frame(box, "Description");
933 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
934 }
935 entry = new_info_entry_in_frame(box, "Group ID");
936 entry_set_int_value(entry, ts->groupid);
937 entry = new_info_entry_in_frame(box, "Jobs");
938 entry_set_int_value(entry, ts->members);
Jens Axboe6b79c802012-03-08 10:51:36 +0100939 gc->err_entry = entry = new_info_entry_in_frame(box, "Error");
Jens Axboe3650a3c2012-03-05 14:09:03 +0100940 entry_set_int_value(entry, ts->error);
941 entry = new_info_entry_in_frame(box, "PID");
942 entry_set_int_value(entry, ts->pid);
943
944 if (ts->io_bytes[DDIR_READ])
945 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
946 if (ts->io_bytes[DDIR_WRITE])
947 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
948
Jens Axboee5bd1342012-03-05 21:38:12 +0100949 gfio_show_latency_buckets(vbox, ts);
Jens Axboe2e331012012-03-05 22:07:54 +0100950 gfio_show_cpu_usage(vbox, ts);
951 gfio_show_io_depths(vbox, ts);
Jens Axboee5bd1342012-03-05 21:38:12 +0100952
Jens Axboe2f99deb2012-03-09 14:37:29 +0100953 gtk_widget_show_all(gc->ge->results_window);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100954 gdk_threads_leave();
955}
956
Jens Axboe084d1c62012-03-03 20:28:07 +0100957static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100958{
Jens Axboe9b260bd2012-03-06 11:02:52 +0100959 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100960 struct gui *ui = &main_ui;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100961 GtkTreeIter iter;
962 struct tm *tm;
963 time_t sec;
964 char tmp[64], timebuf[80];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100965
Jens Axboe9b260bd2012-03-06 11:02:52 +0100966 sec = p->log_sec;
967 tm = localtime(&sec);
968 strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", tm);
969 sprintf(timebuf, "%s.%03ld", tmp, p->log_usec / 1000);
970
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100971 gdk_threads_enter();
Jens Axboe9b260bd2012-03-06 11:02:52 +0100972
Jens Axboe2f99deb2012-03-09 14:37:29 +0100973 gtk_list_store_append(ui->log_model, &iter);
974 gtk_list_store_set(ui->log_model, &iter, 0, timebuf, -1);
975 gtk_list_store_set(ui->log_model, &iter, 1, client->hostname, -1);
976 gtk_list_store_set(ui->log_model, &iter, 2, p->level, -1);
977 gtk_list_store_set(ui->log_model, &iter, 3, p->buf, -1);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100978
Jens Axboe6b79c802012-03-08 10:51:36 +0100979 if (p->level == FIO_LOG_ERR)
Jens Axboe2f99deb2012-03-09 14:37:29 +0100980 view_log(NULL, (gpointer) ui);
Jens Axboe6b79c802012-03-08 10:51:36 +0100981
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100982 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100983}
984
985static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
986{
Jens Axboee0681f32012-03-06 12:14:42 +0100987 struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
988 struct gfio_client *gc = client->client_data;
989 GtkWidget *box, *frame, *entry, *vbox;
Jens Axboe604cfe32012-03-07 19:51:36 +0100990 double util;
991 char tmp[16];
Jens Axboee0681f32012-03-06 12:14:42 +0100992
Jens Axboe0050e5f2012-03-06 09:23:27 +0100993 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +0100994
Jens Axboe45dcb2e2012-03-07 16:16:50 +0100995 if (!gc->results_widget)
Jens Axboee0681f32012-03-06 12:14:42 +0100996 goto out;
Jens Axboee0681f32012-03-06 12:14:42 +0100997
998 if (!gc->disk_util_frame) {
999 gc->disk_util_frame = gtk_frame_new("Disk utilization");
1000 gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
1001 }
1002
1003 vbox = gtk_vbox_new(FALSE, 3);
1004 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
1005
1006 frame = gtk_frame_new((char *) p->dus.name);
1007 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
1008
1009 box = gtk_vbox_new(FALSE, 3);
1010 gtk_container_add(GTK_CONTAINER(frame), box);
1011
1012 frame = gtk_frame_new("Read");
1013 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1014 vbox = gtk_hbox_new(TRUE, 3);
1015 gtk_container_add(GTK_CONTAINER(frame), vbox);
1016 entry = new_info_entry_in_frame(vbox, "IOs");
1017 entry_set_int_value(entry, p->dus.ios[0]);
1018 entry = new_info_entry_in_frame(vbox, "Merges");
1019 entry_set_int_value(entry, p->dus.merges[0]);
1020 entry = new_info_entry_in_frame(vbox, "Sectors");
1021 entry_set_int_value(entry, p->dus.sectors[0]);
1022 entry = new_info_entry_in_frame(vbox, "Ticks");
1023 entry_set_int_value(entry, p->dus.ticks[0]);
1024
1025 frame = gtk_frame_new("Write");
1026 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1027 vbox = gtk_hbox_new(TRUE, 3);
1028 gtk_container_add(GTK_CONTAINER(frame), vbox);
1029 entry = new_info_entry_in_frame(vbox, "IOs");
1030 entry_set_int_value(entry, p->dus.ios[1]);
1031 entry = new_info_entry_in_frame(vbox, "Merges");
1032 entry_set_int_value(entry, p->dus.merges[1]);
1033 entry = new_info_entry_in_frame(vbox, "Sectors");
1034 entry_set_int_value(entry, p->dus.sectors[1]);
1035 entry = new_info_entry_in_frame(vbox, "Ticks");
1036 entry_set_int_value(entry, p->dus.ticks[1]);
1037
1038 frame = gtk_frame_new("Shared");
1039 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1040 vbox = gtk_hbox_new(TRUE, 3);
1041 gtk_container_add(GTK_CONTAINER(frame), vbox);
1042 entry = new_info_entry_in_frame(vbox, "IO ticks");
1043 entry_set_int_value(entry, p->dus.io_ticks);
1044 entry = new_info_entry_in_frame(vbox, "Time in queue");
1045 entry_set_int_value(entry, p->dus.time_in_queue);
1046
Jens Axboe604cfe32012-03-07 19:51:36 +01001047 util = 0.0;
1048 if (p->dus.msec)
1049 util = (double) 100 * p->dus.io_ticks / (double) p->dus.msec;
1050 if (util > 100.0)
1051 util = 100.0;
1052
1053 sprintf(tmp, "%3.2f%%", util);
1054 entry = new_info_entry_in_frame(vbox, "Disk utilization");
1055 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
1056
Jens Axboee0681f32012-03-06 12:14:42 +01001057 gtk_widget_show_all(gc->results_widget);
1058out:
Jens Axboe0050e5f2012-03-06 09:23:27 +01001059 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001060}
1061
Jens Axboe3650a3c2012-03-05 14:09:03 +01001062extern int sum_stat_clients;
1063extern struct thread_stat client_ts;
1064extern struct group_run_stats client_gs;
1065
1066static int sum_stat_nr;
1067
Jens Axboe89e5fad2012-03-05 09:21:12 +01001068static void gfio_thread_status_op(struct fio_client *client,
1069 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001070{
Jens Axboe3650a3c2012-03-05 14:09:03 +01001071 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
1072
1073 gfio_display_ts(client, &p->ts, &p->rs);
1074
1075 if (sum_stat_clients == 1)
1076 return;
1077
1078 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
1079 sum_group_stats(&client_gs, &p->rs);
1080
1081 client_ts.members++;
1082 client_ts.groupid = p->ts.groupid;
1083
1084 if (++sum_stat_nr == sum_stat_clients) {
1085 strcpy(client_ts.name, "All clients");
1086 gfio_display_ts(client, &client_ts, &client_gs);
1087 }
Stephen M. Camerona1820202012-02-24 08:17:31 +01001088}
1089
Jens Axboe89e5fad2012-03-05 09:21:12 +01001090static void gfio_group_stats_op(struct fio_client *client,
1091 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001092{
Jens Axboe98ceabd2012-03-09 08:53:28 +01001093 /* We're ignoring group stats for now */
Stephen M. Camerona1820202012-02-24 08:17:31 +01001094}
1095
Jens Axboe2f99deb2012-03-09 14:37:29 +01001096static gint on_config_drawing_area(GtkWidget *w, GdkEventConfigure *event,
1097 gpointer data)
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001098{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001099 struct gfio_graphs *g = data;
1100
1101 g->drawing_area_xdim = w->allocation.width;
1102 g->drawing_area_ydim = w->allocation.height;
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001103 return TRUE;
1104}
1105
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001106static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
1107{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001108 struct gfio_graphs *g = p;
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001109 cairo_t *cr;
1110
Jens Axboe2f99deb2012-03-09 14:37:29 +01001111 graph_set_size(g->iops_graph, g->drawing_area_xdim / 2.0,
1112 g->drawing_area_ydim);
1113 graph_set_size(g->bandwidth_graph, g->drawing_area_xdim / 2.0,
1114 g->drawing_area_ydim);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001115 cr = gdk_cairo_create(w->window);
1116
1117 cairo_set_source_rgb(cr, 0, 0, 0);
1118
1119 cairo_save(cr);
1120 cairo_translate(cr, 0, 0);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001121 line_graph_draw(g->bandwidth_graph, cr);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001122 cairo_stroke(cr);
1123 cairo_restore(cr);
1124
1125 cairo_save(cr);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001126 cairo_translate(cr, g->drawing_area_xdim / 2.0, 0);
1127 line_graph_draw(g->iops_graph, cr);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001128 cairo_stroke(cr);
1129 cairo_restore(cr);
1130 cairo_destroy(cr);
1131
1132 return FALSE;
1133}
1134
Jens Axboe2f99deb2012-03-09 14:37:29 +01001135/*
1136 * Client specific ETA
1137 */
1138static void gfio_update_client_eta(struct fio_client *client, struct jobs_eta *je)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001139{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001140 struct gfio_client *gc = client->client_data;
1141 struct gui_entry *ge = gc->ge;
Jens Axboe3e47bd22012-02-29 13:45:02 +01001142 static int eta_good;
1143 char eta_str[128];
1144 char output[256];
1145 char tmp[32];
1146 double perc = 0.0;
1147 int i2p = 0;
1148
Jens Axboe0050e5f2012-03-06 09:23:27 +01001149 gdk_threads_enter();
1150
Jens Axboe3e47bd22012-02-29 13:45:02 +01001151 eta_str[0] = '\0';
1152 output[0] = '\0';
1153
1154 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1155 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1156 eta_to_str(eta_str, je->eta_sec);
1157 }
1158
1159 sprintf(tmp, "%u", je->nr_running);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001160 gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001161 sprintf(tmp, "%u", je->files_open);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001162 gtk_entry_set_text(GTK_ENTRY(ge->eta.files), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001163
1164#if 0
1165 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1166 if (je->m_rate || je->t_rate) {
1167 char *tr, *mr;
1168
1169 mr = num2str(je->m_rate, 4, 0, i2p);
1170 tr = num2str(je->t_rate, 4, 0, i2p);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001171 gtk_entry_set_text(GTK_ENTRY(ge->eta);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001172 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1173 free(tr);
1174 free(mr);
1175 } else if (je->m_iops || je->t_iops)
1176 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
Jens Axboeebbd89c2012-03-02 11:21:13 +01001177
Jens Axboe2f99deb2012-03-09 14:37:29 +01001178 gtk_entry_set_text(GTK_ENTRY(ge->eta.cr_bw), "---");
1179 gtk_entry_set_text(GTK_ENTRY(ge->eta.cr_iops), "---");
1180 gtk_entry_set_text(GTK_ENTRY(ge->eta.cw_bw), "---");
1181 gtk_entry_set_text(GTK_ENTRY(ge->eta.cw_iops), "---");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001182#endif
1183
1184 if (je->eta_sec != INT_MAX && je->nr_running) {
1185 char *iops_str[2];
1186 char *rate_str[2];
1187
1188 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1189 strcpy(output, "-.-% done");
1190 else {
1191 eta_good = 1;
1192 perc *= 100.0;
1193 sprintf(output, "%3.1f%% done", perc);
1194 }
1195
1196 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1197 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1198
1199 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1200 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1201
Jens Axboe2f99deb2012-03-09 14:37:29 +01001202 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), rate_str[0]);
1203 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), iops_str[0]);
1204 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), rate_str[1]);
1205 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), iops_str[1]);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001206
Jens Axboe2f99deb2012-03-09 14:37:29 +01001207 graph_add_xy_data(ge->graphs.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1208 graph_add_xy_data(ge->graphs.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1209 graph_add_xy_data(ge->graphs.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1210 graph_add_xy_data(ge->graphs.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
1211
1212 free(rate_str[0]);
1213 free(rate_str[1]);
1214 free(iops_str[0]);
1215 free(iops_str[1]);
1216 }
1217
1218 if (eta_str[0]) {
1219 char *dst = output + strlen(output);
1220
1221 sprintf(dst, " - %s", eta_str);
1222 }
1223
Jens Axboe9988ca72012-03-09 15:14:06 +01001224 gfio_update_thread_status(ge, output, perc);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001225 gdk_threads_leave();
1226}
1227
1228/*
1229 * Update ETA in main window for all clients
1230 */
1231static void gfio_update_all_eta(struct jobs_eta *je)
1232{
1233 struct gui *ui = &main_ui;
1234 static int eta_good;
1235 char eta_str[128];
1236 char output[256];
1237 double perc = 0.0;
1238 int i2p = 0;
1239
1240 gdk_threads_enter();
1241
1242 eta_str[0] = '\0';
1243 output[0] = '\0';
1244
1245 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1246 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1247 eta_to_str(eta_str, je->eta_sec);
1248 }
1249
1250#if 0
1251 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1252 if (je->m_rate || je->t_rate) {
1253 char *tr, *mr;
1254
1255 mr = num2str(je->m_rate, 4, 0, i2p);
1256 tr = num2str(je->t_rate, 4, 0, i2p);
1257 gtk_entry_set_text(GTK_ENTRY(ui->eta);
1258 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1259 free(tr);
1260 free(mr);
1261 } else if (je->m_iops || je->t_iops)
1262 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
1263
1264 gtk_entry_set_text(GTK_ENTRY(ui->eta.cr_bw), "---");
1265 gtk_entry_set_text(GTK_ENTRY(ui->eta.cr_iops), "---");
1266 gtk_entry_set_text(GTK_ENTRY(ui->eta.cw_bw), "---");
1267 gtk_entry_set_text(GTK_ENTRY(ui->eta.cw_iops), "---");
1268#endif
1269
Jens Axboe3863d1a2012-03-09 17:39:05 +01001270 entry_set_int_value(ui->eta.jobs, je->nr_running);
1271
Jens Axboe2f99deb2012-03-09 14:37:29 +01001272 if (je->eta_sec != INT_MAX && je->nr_running) {
1273 char *iops_str[2];
1274 char *rate_str[2];
1275
1276 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1277 strcpy(output, "-.-% done");
1278 else {
1279 eta_good = 1;
1280 perc *= 100.0;
1281 sprintf(output, "%3.1f%% done", perc);
1282 }
1283
1284 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1285 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1286
1287 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1288 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1289
1290 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), rate_str[0]);
1291 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), iops_str[0]);
1292 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), rate_str[1]);
1293 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), iops_str[1]);
1294
1295 graph_add_xy_data(ui->graphs.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1296 graph_add_xy_data(ui->graphs.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1297 graph_add_xy_data(ui->graphs.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1298 graph_add_xy_data(ui->graphs.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001299
Jens Axboe3e47bd22012-02-29 13:45:02 +01001300 free(rate_str[0]);
1301 free(rate_str[1]);
1302 free(iops_str[0]);
1303 free(iops_str[1]);
1304 }
1305
1306 if (eta_str[0]) {
1307 char *dst = output + strlen(output);
1308
1309 sprintf(dst, " - %s", eta_str);
1310 }
1311
Jens Axboe9988ca72012-03-09 15:14:06 +01001312 gfio_update_thread_status_all(output, perc);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001313 gdk_threads_leave();
Jens Axboe3e47bd22012-02-29 13:45:02 +01001314}
1315
Stephen M. Camerona1820202012-02-24 08:17:31 +01001316static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1317{
Jens Axboe843ad232012-02-29 11:44:53 +01001318 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001319 struct gfio_client *gc = client->client_data;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001320 struct gui_entry *ge = gc->ge;
Jens Axboe843ad232012-02-29 11:44:53 +01001321 const char *os, *arch;
1322 char buf[64];
1323
1324 os = fio_get_os_string(probe->os);
1325 if (!os)
1326 os = "unknown";
1327
1328 arch = fio_get_arch_string(probe->arch);
1329 if (!arch)
1330 os = "unknown";
1331
1332 if (!client->name)
1333 client->name = strdup((char *) probe->hostname);
1334
Jens Axboe0050e5f2012-03-06 09:23:27 +01001335 gdk_threads_enter();
1336
Jens Axboe2f99deb2012-03-09 14:37:29 +01001337 gtk_label_set_text(GTK_LABEL(ge->probe.hostname), (char *) probe->hostname);
1338 gtk_label_set_text(GTK_LABEL(ge->probe.os), os);
1339 gtk_label_set_text(GTK_LABEL(ge->probe.arch), arch);
Jens Axboe843ad232012-02-29 11:44:53 +01001340 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001341 gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), buf);
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001342
Jens Axboe2f99deb2012-03-09 14:37:29 +01001343 gfio_set_connected(ge, 1);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001344
1345 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001346}
1347
Jens Axboe9988ca72012-03-09 15:14:06 +01001348static void gfio_update_thread_status(struct gui_entry *ge,
1349 char *status_message, double perc)
1350{
1351 static char message[100];
1352 const char *m = message;
1353
1354 strncpy(message, status_message, sizeof(message) - 1);
1355 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), m);
1356 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), perc / 100.0);
1357 gtk_widget_queue_draw(main_ui.window);
1358}
1359
1360static void gfio_update_thread_status_all(char *status_message, double perc)
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001361{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001362 struct gui *ui = &main_ui;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001363 static char message[100];
1364 const char *m = message;
1365
1366 strncpy(message, status_message, sizeof(message) - 1);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001367 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), m);
1368 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), perc / 100.0);
1369 gtk_widget_queue_draw(ui->window);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001370}
1371
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001372static void gfio_quit_op(struct fio_client *client)
1373{
Jens Axboee0681f32012-03-06 12:14:42 +01001374 struct gfio_client *gc = client->client_data;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001375
Jens Axboe0050e5f2012-03-06 09:23:27 +01001376 gdk_threads_enter();
Jens Axboe2f99deb2012-03-09 14:37:29 +01001377 gfio_set_connected(gc->ge, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001378 gdk_threads_leave();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001379}
1380
Jens Axboe807f9972012-03-02 10:25:24 +01001381static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1382{
1383 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +01001384 struct gfio_client *gc = client->client_data;
Jens Axboedcaeb602012-03-08 19:45:37 +01001385 struct thread_options *o = &gc->o;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001386 struct gui_entry *ge = gc->ge;
Jens Axboe807f9972012-03-02 10:25:24 +01001387 char tmp[8];
Jens Axboe807f9972012-03-02 10:25:24 +01001388
Jens Axboedcaeb602012-03-08 19:45:37 +01001389 convert_thread_options_to_cpu(o, &p->top);
Jens Axboe807f9972012-03-02 10:25:24 +01001390
Jens Axboe0050e5f2012-03-06 09:23:27 +01001391 gdk_threads_enter();
1392
Jens Axboe2f99deb2012-03-09 14:37:29 +01001393 gtk_label_set_text(GTK_LABEL(ge->page_label), (gchar *) o->name);
1394
Jens Axboe3863d1a2012-03-09 17:39:05 +01001395 gtk_combo_box_append_text(GTK_COMBO_BOX(ge->eta.names), (gchar *) o->name);
1396 gtk_combo_box_set_active(GTK_COMBO_BOX(ge->eta.names), 0);
1397
Jens Axboe2f99deb2012-03-09 14:37:29 +01001398 gtk_entry_set_text(GTK_ENTRY(ge->eta.iotype), ddir_str(o->td_ddir));
1399 gtk_entry_set_text(GTK_ENTRY(ge->eta.ioengine), (gchar *) o->ioengine);
Jens Axboe807f9972012-03-02 10:25:24 +01001400
Jens Axboedcaeb602012-03-08 19:45:37 +01001401 sprintf(tmp, "%u", o->iodepth);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001402 gtk_entry_set_text(GTK_ENTRY(ge->eta.iodepth), tmp);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001403
Jens Axboedcaeb602012-03-08 19:45:37 +01001404 gc->job_added++;
1405
Jens Axboe0050e5f2012-03-06 09:23:27 +01001406 gdk_threads_leave();
Jens Axboe807f9972012-03-02 10:25:24 +01001407}
1408
Jens Axboeed727a42012-03-02 12:14:40 +01001409static void gfio_client_timed_out(struct fio_client *client)
1410{
Jens Axboee0681f32012-03-06 12:14:42 +01001411 struct gfio_client *gc = client->client_data;
Jens Axboeed727a42012-03-02 12:14:40 +01001412 GtkWidget *dialog, *label, *content;
1413 char buf[256];
1414
1415 gdk_threads_enter();
1416
Jens Axboe2f99deb2012-03-09 14:37:29 +01001417 gfio_set_connected(gc->ge, 0);
1418 clear_ge_ui_info(gc->ge);
Jens Axboeed727a42012-03-02 12:14:40 +01001419
1420 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
1421
1422 dialog = gtk_dialog_new_with_buttons("Timed out!",
Jens Axboe2f99deb2012-03-09 14:37:29 +01001423 GTK_WINDOW(main_ui.window),
Jens Axboeed727a42012-03-02 12:14:40 +01001424 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1425 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1426
Jens Axboef1299092012-03-07 20:00:02 +01001427 /* gtk_dialog_get_content_area() is 2.14 and newer */
1428 content = GTK_DIALOG(dialog)->vbox;
1429
Jens Axboeed727a42012-03-02 12:14:40 +01001430 label = gtk_label_new((const gchar *) buf);
1431 gtk_container_add(GTK_CONTAINER(content), label);
1432 gtk_widget_show_all(dialog);
1433 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1434
1435 gtk_dialog_run(GTK_DIALOG(dialog));
1436 gtk_widget_destroy(dialog);
1437
1438 gdk_threads_leave();
1439}
1440
Jens Axboe6b79c802012-03-08 10:51:36 +01001441static void gfio_client_stop(struct fio_client *client, struct fio_net_cmd *cmd)
1442{
1443 struct gfio_client *gc = client->client_data;
1444
1445 gdk_threads_enter();
1446
Jens Axboe2f99deb2012-03-09 14:37:29 +01001447 gfio_set_connected(gc->ge, 0);
Jens Axboe6b79c802012-03-08 10:51:36 +01001448
1449 if (gc->err_entry)
1450 entry_set_int_value(gc->err_entry, client->error);
1451
1452 gdk_threads_leave();
1453}
1454
Stephen M. Camerona1820202012-02-24 08:17:31 +01001455struct client_ops gfio_client_ops = {
Jens Axboe0420ba62012-02-29 11:16:52 +01001456 .text_op = gfio_text_op,
1457 .disk_util = gfio_disk_util_op,
1458 .thread_status = gfio_thread_status_op,
1459 .group_stats = gfio_group_stats_op,
Jens Axboe2f99deb2012-03-09 14:37:29 +01001460 .jobs_eta = gfio_update_client_eta,
1461 .eta = gfio_update_all_eta,
Jens Axboe0420ba62012-02-29 11:16:52 +01001462 .probe = gfio_probe_op,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001463 .quit = gfio_quit_op,
Jens Axboe807f9972012-03-02 10:25:24 +01001464 .add_job = gfio_add_job_op,
Jens Axboeed727a42012-03-02 12:14:40 +01001465 .timed_out = gfio_client_timed_out,
Jens Axboe6b79c802012-03-08 10:51:36 +01001466 .stop = gfio_client_stop,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001467 .stay_connected = 1,
Stephen M. Camerona1820202012-02-24 08:17:31 +01001468};
1469
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001470static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1471 __attribute__((unused)) gpointer data)
1472{
1473 gtk_main_quit();
1474}
1475
Stephen M. Cameron25927252012-02-24 08:17:31 +01001476static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001477{
Jens Axboea9eccde2012-03-09 14:59:42 +01001478 struct gui *ui = arg;
1479
1480 ui->handler_running = 1;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001481 fio_handle_clients(&gfio_client_ops);
Jens Axboea9eccde2012-03-09 14:59:42 +01001482 ui->handler_running = 0;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001483 return NULL;
1484}
1485
Jens Axboe2f99deb2012-03-09 14:37:29 +01001486static int send_job_files(struct gui_entry *ge)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001487{
Jens Axboe9988ca72012-03-09 15:14:06 +01001488 struct gfio_client *gc = ge->client;
Jens Axboe441013b2012-03-01 08:01:52 +01001489 int i, ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001490
Jens Axboe2f99deb2012-03-09 14:37:29 +01001491 for (i = 0; i < ge->nr_job_files; i++) {
Jens Axboe9988ca72012-03-09 15:14:06 +01001492 ret = fio_client_send_ini(gc->client, ge->job_files[i]);
Jens Axboec7249262012-03-09 17:11:04 +01001493 if (ret < 0) {
1494 GError *error;
1495
1496 error = g_error_new(g_quark_from_string("fio"), 1, "Failed to send file %s: %s\n", ge->job_files[i], strerror(-ret));
1497 report_error(error);
1498 g_error_free(error);
1499 break;
1500 } else if (ret)
Jens Axboe441013b2012-03-01 08:01:52 +01001501 break;
1502
Jens Axboe2f99deb2012-03-09 14:37:29 +01001503 free(ge->job_files[i]);
1504 ge->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001505 }
Jens Axboe2f99deb2012-03-09 14:37:29 +01001506 while (i < ge->nr_job_files) {
1507 free(ge->job_files[i]);
1508 ge->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001509 i++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001510 }
1511
Jens Axboe441013b2012-03-01 08:01:52 +01001512 return ret;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001513}
1514
Jens Axboe63a130b2012-03-06 20:08:59 +01001515static void *server_thread(void *arg)
1516{
1517 is_backend = 1;
1518 gfio_server_running = 1;
1519 fio_start_server(NULL);
1520 gfio_server_running = 0;
1521 return NULL;
1522}
1523
Jens Axboe2f99deb2012-03-09 14:37:29 +01001524static void gfio_start_server(void)
Jens Axboe63a130b2012-03-06 20:08:59 +01001525{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001526 struct gui *ui = &main_ui;
1527
Jens Axboe63a130b2012-03-06 20:08:59 +01001528 if (!gfio_server_running) {
1529 gfio_server_running = 1;
1530 pthread_create(&ui->server_t, NULL, server_thread, NULL);
Jens Axboee34f6ad2012-03-06 20:47:15 +01001531 pthread_detach(ui->server_t);
Jens Axboe63a130b2012-03-06 20:08:59 +01001532 }
1533}
1534
Stephen M. Cameron25927252012-02-24 08:17:31 +01001535static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1536 gpointer data)
1537{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001538 struct gui_entry *ge = data;
1539 struct gfio_client *gc = ge->client;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001540
Jens Axboe2f99deb2012-03-09 14:37:29 +01001541 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 0);
1542 fio_start_client(gc->client);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001543}
1544
Jens Axboedf06f222012-03-02 13:32:04 +01001545static void file_open(GtkWidget *w, gpointer data);
1546
1547static void connect_clicked(GtkWidget *widget, gpointer data)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001548{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001549 struct gui_entry *ge = data;
1550 struct gfio_client *gc = ge->client;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001551
Jens Axboe2f99deb2012-03-09 14:37:29 +01001552 if (!ge->connected) {
Jens Axboec7249262012-03-09 17:11:04 +01001553 int ret;
1554
Jens Axboe2f99deb2012-03-09 14:37:29 +01001555 if (!ge->nr_job_files)
Jens Axboedf06f222012-03-02 13:32:04 +01001556 file_open(widget, data);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001557 if (!ge->nr_job_files)
1558 return;
1559
1560 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No jobs running");
1561 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
Jens Axboec7249262012-03-09 17:11:04 +01001562 ret = fio_client_connect(gc->client);
1563 if (!ret) {
Jens Axboea9eccde2012-03-09 14:59:42 +01001564 if (!ge->ui->handler_running)
1565 pthread_create(&ge->ui->t, NULL, job_thread, ge->ui);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001566 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 0);
1567 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 1);
Jens Axboec7249262012-03-09 17:11:04 +01001568 } else {
1569 GError *error;
1570
1571 error = g_error_new(g_quark_from_string("fio"), 1, "Failed to connect to %s: %s\n", ge->client->client->hostname, strerror(-ret));
1572 report_error(error);
1573 g_error_free(error);
Jens Axboe69406b92012-03-06 14:00:42 +01001574 }
Jens Axboedf06f222012-03-02 13:32:04 +01001575 } else {
Jens Axboe2f99deb2012-03-09 14:37:29 +01001576 fio_client_terminate(gc->client);
1577 gfio_set_connected(ge, 0);
1578 clear_ge_ui_info(ge);
Jens Axboedf06f222012-03-02 13:32:04 +01001579 }
Jens Axboe3e47bd22012-02-29 13:45:02 +01001580}
1581
Jens Axboeb9d2f302012-03-08 20:36:28 +01001582static void send_clicked(GtkWidget *widget, gpointer data)
1583{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001584 struct gui_entry *ge = data;
Jens Axboeb9d2f302012-03-08 20:36:28 +01001585
Jens Axboe2f99deb2012-03-09 14:37:29 +01001586 if (send_job_files(ge)) {
Jens Axboec7249262012-03-09 17:11:04 +01001587 GError *error;
1588
1589 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);
1590 report_error(error);
1591 g_error_free(error);
1592
Jens Axboe2f99deb2012-03-09 14:37:29 +01001593 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 1);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001594 }
1595
Jens Axboe2f99deb2012-03-09 14:37:29 +01001596 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 0);
1597 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 1);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001598}
1599
Jens Axboe2f99deb2012-03-09 14:37:29 +01001600static GtkWidget *add_button(GtkWidget *buttonbox,
1601 struct button_spec *buttonspec, gpointer data)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001602{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001603 GtkWidget *button = gtk_button_new_with_label(buttonspec->buttontext);
1604
1605 g_signal_connect(button, "clicked", G_CALLBACK(buttonspec->f), data);
1606 gtk_box_pack_start(GTK_BOX(buttonbox), button, FALSE, FALSE, 3);
1607 gtk_widget_set_tooltip_text(button, buttonspec->tooltiptext);
1608 gtk_widget_set_sensitive(button, !buttonspec->start_insensitive);
1609
1610 return button;
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001611}
1612
Jens Axboe2f99deb2012-03-09 14:37:29 +01001613static void add_buttons(struct gui_entry *ge, struct button_spec *buttonlist,
1614 int nbuttons)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001615{
1616 int i;
1617
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001618 for (i = 0; i < nbuttons; i++)
Jens Axboe2f99deb2012-03-09 14:37:29 +01001619 ge->button[i] = add_button(ge->buttonbox, &buttonlist[i], ge);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001620}
1621
Jens Axboe0420ba62012-02-29 11:16:52 +01001622static void on_info_bar_response(GtkWidget *widget, gint response,
1623 gpointer data)
1624{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001625 struct gui *ui = &main_ui;
1626
Jens Axboe0420ba62012-02-29 11:16:52 +01001627 if (response == GTK_RESPONSE_OK) {
1628 gtk_widget_destroy(widget);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001629 ui->error_info_bar = NULL;
Jens Axboe0420ba62012-02-29 11:16:52 +01001630 }
1631}
1632
Jens Axboedf06f222012-03-02 13:32:04 +01001633void report_error(GError *error)
Jens Axboe0420ba62012-02-29 11:16:52 +01001634{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001635 struct gui *ui = &main_ui;
1636
1637 if (ui->error_info_bar == NULL) {
1638 ui->error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
Jens Axboe0420ba62012-02-29 11:16:52 +01001639 GTK_RESPONSE_OK,
1640 NULL);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001641 g_signal_connect(ui->error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1642 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui->error_info_bar),
Jens Axboe0420ba62012-02-29 11:16:52 +01001643 GTK_MESSAGE_ERROR);
1644
Jens Axboe2f99deb2012-03-09 14:37:29 +01001645 ui->error_label = gtk_label_new(error->message);
1646 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui->error_info_bar));
1647 gtk_container_add(GTK_CONTAINER(container), ui->error_label);
Jens Axboe0420ba62012-02-29 11:16:52 +01001648
Jens Axboe2f99deb2012-03-09 14:37:29 +01001649 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->error_info_bar, FALSE, FALSE, 0);
1650 gtk_widget_show_all(ui->vbox);
Jens Axboe0420ba62012-02-29 11:16:52 +01001651 } else {
1652 char buffer[256];
1653 snprintf(buffer, sizeof(buffer), "Failed to open file.");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001654 gtk_label_set(GTK_LABEL(ui->error_label), buffer);
Jens Axboe0420ba62012-02-29 11:16:52 +01001655 }
1656}
1657
Jens Axboe62bc9372012-03-07 11:45:07 +01001658struct connection_widgets
1659{
1660 GtkWidget *hentry;
1661 GtkWidget *combo;
1662 GtkWidget *button;
1663};
1664
1665static void hostname_cb(GtkEntry *entry, gpointer data)
1666{
1667 struct connection_widgets *cw = data;
1668 int uses_net = 0, is_localhost = 0;
1669 const gchar *text;
1670 gchar *ctext;
1671
1672 /*
1673 * Check whether to display the 'auto start backend' box
1674 * or not. Show it if we are a localhost and using network,
1675 * or using a socket.
1676 */
1677 ctext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->combo));
1678 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
1679 uses_net = 1;
1680 g_free(ctext);
1681
1682 if (uses_net) {
1683 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
1684 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
1685 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
1686 !strcmp(text, "ip6-loopback"))
1687 is_localhost = 1;
1688 }
1689
1690 if (!uses_net || is_localhost) {
1691 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
1692 gtk_widget_set_sensitive(cw->button, 1);
1693 } else {
1694 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
1695 gtk_widget_set_sensitive(cw->button, 0);
1696 }
1697}
1698
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001699static int get_connection_details(char **host, int *port, int *type,
1700 int *server_start)
Jens Axboea7a42ce2012-03-02 13:12:04 +01001701{
Jens Axboe62bc9372012-03-07 11:45:07 +01001702 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
1703 struct connection_widgets cw;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001704 char *typeentry;
1705
1706 dialog = gtk_dialog_new_with_buttons("Connection details",
Jens Axboe2f99deb2012-03-09 14:37:29 +01001707 GTK_WINDOW(main_ui.window),
Jens Axboea7a42ce2012-03-02 13:12:04 +01001708 GTK_DIALOG_DESTROY_WITH_PARENT,
1709 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1710 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1711
1712 frame = gtk_frame_new("Hostname / socket name");
Jens Axboef1299092012-03-07 20:00:02 +01001713 /* gtk_dialog_get_content_area() is 2.14 and newer */
1714 vbox = GTK_DIALOG(dialog)->vbox;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001715 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1716
1717 box = gtk_vbox_new(FALSE, 6);
1718 gtk_container_add(GTK_CONTAINER(frame), box);
1719
1720 hbox = gtk_hbox_new(TRUE, 10);
1721 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe62bc9372012-03-07 11:45:07 +01001722 cw.hentry = gtk_entry_new();
1723 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
1724 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001725
1726 frame = gtk_frame_new("Port");
1727 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1728 box = gtk_vbox_new(FALSE, 10);
1729 gtk_container_add(GTK_CONTAINER(frame), box);
1730
1731 hbox = gtk_hbox_new(TRUE, 4);
1732 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1733 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1734
1735 frame = gtk_frame_new("Type");
1736 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1737 box = gtk_vbox_new(FALSE, 10);
1738 gtk_container_add(GTK_CONTAINER(frame), box);
1739
1740 hbox = gtk_hbox_new(TRUE, 4);
1741 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1742
Jens Axboe62bc9372012-03-07 11:45:07 +01001743 cw.combo = gtk_combo_box_new_text();
1744 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv4");
1745 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv6");
1746 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "local socket");
1747 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001748
Jens Axboe62bc9372012-03-07 11:45:07 +01001749 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001750
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001751 frame = gtk_frame_new("Options");
1752 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1753 box = gtk_vbox_new(FALSE, 10);
1754 gtk_container_add(GTK_CONTAINER(frame), box);
1755
1756 hbox = gtk_hbox_new(TRUE, 4);
1757 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1758
Jens Axboe62bc9372012-03-07 11:45:07 +01001759 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1760 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
1761 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.");
1762 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
1763
1764 /*
1765 * Connect edit signal, so we can show/not-show the auto start button
1766 */
1767 g_signal_connect(GTK_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
1768 g_signal_connect(GTK_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001769
Jens Axboea7a42ce2012-03-02 13:12:04 +01001770 gtk_widget_show_all(dialog);
1771
1772 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1773 gtk_widget_destroy(dialog);
1774 return 1;
1775 }
1776
Jens Axboe62bc9372012-03-07 11:45:07 +01001777 *host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001778 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1779
Jens Axboe62bc9372012-03-07 11:45:07 +01001780 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw.combo));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001781 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1782 *type = Fio_client_ipv4;
1783 else if (!strncmp(typeentry, "IPv6", 4))
1784 *type = Fio_client_ipv6;
1785 else
1786 *type = Fio_client_socket;
1787 g_free(typeentry);
1788
Jens Axboe62bc9372012-03-07 11:45:07 +01001789 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001790
Jens Axboea7a42ce2012-03-02 13:12:04 +01001791 gtk_widget_destroy(dialog);
1792 return 0;
1793}
1794
Jens Axboe2f99deb2012-03-09 14:37:29 +01001795static void gfio_client_added(struct gui_entry *ge, struct fio_client *client)
Jens Axboee0681f32012-03-06 12:14:42 +01001796{
1797 struct gfio_client *gc;
1798
1799 gc = malloc(sizeof(*gc));
1800 memset(gc, 0, sizeof(*gc));
Jens Axboe2f99deb2012-03-09 14:37:29 +01001801 gc->ge = ge;
Jens Axboe343cb4a2012-03-09 17:16:51 +01001802 gc->client = fio_get_client(client);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001803
Jens Axboe2f99deb2012-03-09 14:37:29 +01001804 ge->client = gc;
Jens Axboee0681f32012-03-06 12:14:42 +01001805
1806 client->client_data = gc;
1807}
1808
Jens Axboe2f99deb2012-03-09 14:37:29 +01001809static GtkWidget *new_client_page(struct gui_entry *ge);
1810
1811static struct gui_entry *alloc_new_gui_entry(struct gui *ui)
1812{
1813 struct gui_entry *ge;
1814
1815 ge = malloc(sizeof(*ge));
1816 memset(ge, 0, sizeof(*ge));
1817 INIT_FLIST_HEAD(&ge->list);
1818 flist_add_tail(&ge->list, &ui->list);
1819 ge->ui = ui;
1820 return ge;
1821}
1822
1823/*
1824 * FIXME: need more handling here
1825 */
1826static void ge_destroy(GtkWidget *w, gpointer data)
1827{
1828 struct gui_entry *ge = data;
Jens Axboe343cb4a2012-03-09 17:16:51 +01001829 struct gfio_client *gc = ge->client;
1830
1831 if (gc->client)
1832 fio_put_client(gc->client);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001833
1834 flist_del(&ge->list);
1835 free(ge);
1836}
1837
1838static struct gui_entry *get_new_ge_with_tab(const char *name)
1839{
1840 struct gui_entry *ge;
1841
1842 ge = alloc_new_gui_entry(&main_ui);
1843
1844 ge->vbox = new_client_page(ge);
1845 g_signal_connect(ge->vbox, "destroy", G_CALLBACK(ge_destroy), ge);
1846
1847 ge->page_label = gtk_label_new(name);
1848 ge->page_num = gtk_notebook_append_page(GTK_NOTEBOOK(main_ui.notebook), ge->vbox, ge->page_label);
1849
1850 gtk_widget_show_all(main_ui.window);
1851 return ge;
1852}
1853
1854static void file_new(GtkWidget *w, gpointer data)
1855{
1856 get_new_ge_with_tab("Untitled");
1857}
1858
1859/*
1860 * Return the 'ge' corresponding to the tab. If the active tab is the
1861 * main tab, open a new tab.
1862 */
1863static struct gui_entry *get_ge_from_page(unsigned int cur_page)
1864{
1865 struct flist_head *entry;
1866 struct gui_entry *ge;
1867
1868 if (!cur_page)
1869 return get_new_ge_with_tab("Untitled");
1870
1871 flist_for_each(entry, &main_ui.list) {
1872 ge = flist_entry(entry, struct gui_entry, list);
1873 if (ge->page_num == cur_page)
1874 return ge;
1875 }
1876
1877 return NULL;
1878}
1879
Jens Axboe0420ba62012-02-29 11:16:52 +01001880static void file_open(GtkWidget *w, gpointer data)
1881{
Jens Axboe63a130b2012-03-06 20:08:59 +01001882 struct gui *ui = data;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001883 GtkWidget *dialog;
Jens Axboe0420ba62012-02-29 11:16:52 +01001884 GSList *filenames, *fn_glist;
1885 GtkFileFilter *filter;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001886 char *host;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001887 int port, type, server_start;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001888 struct gui_entry *ge;
1889 gint cur_page;
1890
1891 /*
1892 * Creates new tab if current tab is the main window, or the
1893 * current tab already has a client.
1894 */
1895 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
1896 ge = get_ge_from_page(cur_page);
1897 if (ge->client)
1898 ge = get_new_ge_with_tab("Untitled");
1899
1900 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
Jens Axboe0420ba62012-02-29 11:16:52 +01001901
1902 dialog = gtk_file_chooser_dialog_new("Open File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001903 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001904 GTK_FILE_CHOOSER_ACTION_OPEN,
1905 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1906 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1907 NULL);
1908 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1909
1910 filter = gtk_file_filter_new();
1911 gtk_file_filter_add_pattern(filter, "*.fio");
1912 gtk_file_filter_add_pattern(filter, "*.job");
Jens Axboe2d262992012-03-07 08:19:30 +01001913 gtk_file_filter_add_pattern(filter, "*.ini");
Jens Axboe0420ba62012-02-29 11:16:52 +01001914 gtk_file_filter_add_mime_type(filter, "text/fio");
1915 gtk_file_filter_set_name(filter, "Fio job file");
1916 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
1917
1918 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1919 gtk_widget_destroy(dialog);
1920 return;
1921 }
1922
1923 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001924
1925 gtk_widget_destroy(dialog);
1926
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001927 if (get_connection_details(&host, &port, &type, &server_start))
Jens Axboea7a42ce2012-03-02 13:12:04 +01001928 goto err;
1929
Jens Axboe0420ba62012-02-29 11:16:52 +01001930 filenames = fn_glist;
1931 while (filenames != NULL) {
Jens Axboee0681f32012-03-06 12:14:42 +01001932 struct fio_client *client;
1933
Jens Axboe2f99deb2012-03-09 14:37:29 +01001934 ge->job_files = realloc(ge->job_files, (ge->nr_job_files + 1) * sizeof(char *));
1935 ge->job_files[ge->nr_job_files] = strdup(filenames->data);
1936 ge->nr_job_files++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001937
Jens Axboee0681f32012-03-06 12:14:42 +01001938 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
1939 if (!client) {
Jens Axboedf06f222012-03-02 13:32:04 +01001940 GError *error;
1941
1942 error = g_error_new(g_quark_from_string("fio"), 1,
1943 "Failed to add client %s", host);
Jens Axboe0420ba62012-02-29 11:16:52 +01001944 report_error(error);
1945 g_error_free(error);
Jens Axboe0420ba62012-02-29 11:16:52 +01001946 }
Jens Axboe2f99deb2012-03-09 14:37:29 +01001947 gfio_client_added(ge, client);
Jens Axboe0420ba62012-02-29 11:16:52 +01001948
1949 g_free(filenames->data);
1950 filenames = g_slist_next(filenames);
1951 }
Jens Axboea7a42ce2012-03-02 13:12:04 +01001952 free(host);
Jens Axboe63a130b2012-03-06 20:08:59 +01001953
1954 if (server_start)
Jens Axboe2f99deb2012-03-09 14:37:29 +01001955 gfio_start_server();
Jens Axboea7a42ce2012-03-02 13:12:04 +01001956err:
Jens Axboe0420ba62012-02-29 11:16:52 +01001957 g_slist_free(fn_glist);
Jens Axboe0420ba62012-02-29 11:16:52 +01001958}
1959
1960static void file_save(GtkWidget *w, gpointer data)
1961{
Jens Axboe63a130b2012-03-06 20:08:59 +01001962 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01001963 GtkWidget *dialog;
1964
1965 dialog = gtk_file_chooser_dialog_new("Save File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001966 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001967 GTK_FILE_CHOOSER_ACTION_SAVE,
1968 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1969 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1970 NULL);
1971
1972 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1973 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
1974
1975 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1976 char *filename;
1977
1978 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1979 // save_job_file(filename);
1980 g_free(filename);
1981 }
1982 gtk_widget_destroy(dialog);
1983}
1984
Jens Axboe9b260bd2012-03-06 11:02:52 +01001985static void view_log_destroy(GtkWidget *w, gpointer data)
1986{
1987 struct gui *ui = (struct gui *) data;
1988
1989 gtk_widget_ref(ui->log_tree);
1990 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
1991 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +01001992 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001993}
1994
1995static void view_log(GtkWidget *w, gpointer data)
1996{
Jens Axboe4cbe7212012-03-06 13:36:17 +01001997 GtkWidget *win, *scroll, *vbox, *box;
1998 struct gui *ui = (struct gui *) data;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001999
Jens Axboe4cbe7212012-03-06 13:36:17 +01002000 if (ui->log_view)
2001 return;
2002
2003 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002004 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +01002005 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002006
Jens Axboe4cbe7212012-03-06 13:36:17 +01002007 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002008
Jens Axboe4cbe7212012-03-06 13:36:17 +01002009 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
2010
2011 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2012
2013 box = gtk_hbox_new(TRUE, 0);
2014 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
2015 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
2016 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
2017
2018 vbox = gtk_vbox_new(TRUE, 5);
2019 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
2020
2021 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002022 gtk_widget_show_all(win);
2023}
2024
Jens Axboe8577f4f2012-03-09 19:28:27 +01002025static void __update_graph_limits(struct gfio_graphs *g)
2026{
2027 line_graph_set_data_count_limit(g->iops_graph, gfio_graph_limit);
2028 line_graph_set_data_count_limit(g->bandwidth_graph, gfio_graph_limit);
2029}
2030
2031static void update_graph_limits(void)
2032{
2033 struct flist_head *entry;
2034 struct gui_entry *ge;
2035
2036 __update_graph_limits(&main_ui.graphs);
2037
2038 flist_for_each(entry, &main_ui.list) {
2039 ge = flist_entry(entry, struct gui_entry, list);
2040 __update_graph_limits(&ge->graphs);
2041 }
2042}
2043
Jens Axboe46974a72012-03-02 19:34:13 +01002044static void preferences(GtkWidget *w, gpointer data)
2045{
Jens Axboef3e84402012-03-07 13:14:32 +01002046 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
Jens Axboe8577f4f2012-03-09 19:28:27 +01002047 GtkWidget *hbox, *spin, *entry;
Jens Axboe46974a72012-03-02 19:34:13 +01002048 int i;
2049
2050 dialog = gtk_dialog_new_with_buttons("Preferences",
Jens Axboe2f99deb2012-03-09 14:37:29 +01002051 GTK_WINDOW(main_ui.window),
Jens Axboe46974a72012-03-02 19:34:13 +01002052 GTK_DIALOG_DESTROY_WITH_PARENT,
2053 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2054 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2055 NULL);
2056
Jens Axboe0b8d11e2012-03-02 19:44:15 +01002057 frame = gtk_frame_new("Debug logging");
Jens Axboe46974a72012-03-02 19:34:13 +01002058 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
Jens Axboef3e84402012-03-07 13:14:32 +01002059
2060 vbox = gtk_vbox_new(FALSE, 6);
2061 gtk_container_add(GTK_CONTAINER(frame), vbox);
2062
Jens Axboe46974a72012-03-02 19:34:13 +01002063 box = gtk_hbox_new(FALSE, 6);
Jens Axboef3e84402012-03-07 13:14:32 +01002064 gtk_container_add(GTK_CONTAINER(vbox), box);
Jens Axboe46974a72012-03-02 19:34:13 +01002065
2066 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
2067
2068 for (i = 0; i < FD_DEBUG_MAX; i++) {
Jens Axboef3e84402012-03-07 13:14:32 +01002069 if (i == 7) {
2070 box = gtk_hbox_new(FALSE, 6);
2071 gtk_container_add(GTK_CONTAINER(vbox), box);
2072 }
2073
2074
Jens Axboe46974a72012-03-02 19:34:13 +01002075 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
Jens Axboe0b8d11e2012-03-02 19:44:15 +01002076 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
Jens Axboe46974a72012-03-02 19:34:13 +01002077 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
2078 }
2079
Jens Axboe8577f4f2012-03-09 19:28:27 +01002080 frame = gtk_frame_new("Graphing");
Jens Axboef3e84402012-03-07 13:14:32 +01002081 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
2082 vbox = gtk_vbox_new(FALSE, 6);
2083 gtk_container_add(GTK_CONTAINER(frame), vbox);
2084
2085 font = gtk_font_button_new();
2086 gtk_box_pack_start(GTK_BOX(vbox), font, FALSE, FALSE, 5);
2087
Jens Axboe8577f4f2012-03-09 19:28:27 +01002088 box = gtk_vbox_new(FALSE, 6);
2089 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
2090
2091 hbox = gtk_hbox_new(FALSE, 5);
2092 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 5);
2093 entry = gtk_label_new("Maximum number of data points in graph (seconds)");
2094 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
2095
2096 spin = create_spinbutton(hbox, 10, 1000000, 100);
2097
Jens Axboe46974a72012-03-02 19:34:13 +01002098 gtk_widget_show_all(dialog);
2099
2100 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
2101 gtk_widget_destroy(dialog);
2102 return;
2103 }
2104
2105 for (i = 0; i < FD_DEBUG_MAX; i++) {
2106 int set;
2107
2108 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
2109 if (set)
2110 fio_debug |= (1UL << i);
2111 }
2112
Jens Axboef3e84402012-03-07 13:14:32 +01002113 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
Jens Axboe8577f4f2012-03-09 19:28:27 +01002114 gfio_graph_limit = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
2115 update_graph_limits();
2116
Jens Axboe46974a72012-03-02 19:34:13 +01002117 gtk_widget_destroy(dialog);
2118}
2119
Jens Axboe0420ba62012-02-29 11:16:52 +01002120static void about_dialog(GtkWidget *w, gpointer data)
2121{
Jens Axboe81e4ea62012-03-07 14:18:28 +01002122 const char *authors[] = {
2123 "Jens Axboe <axboe@kernel.dk>",
2124 "Stephen Carmeron <stephenmcameron@gmail.com>",
2125 NULL
2126 };
Jens Axboe84a72ed2012-03-07 14:24:57 +01002127 const char *license[] = {
2128 "Fio is free software; you can redistribute it and/or modify "
2129 "it under the terms of the GNU General Public License as published by "
2130 "the Free Software Foundation; either version 2 of the License, or "
2131 "(at your option) any later version.\n",
2132 "Fio is distributed in the hope that it will be useful, "
2133 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
2134 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
2135 "GNU General Public License for more details.\n",
2136 "You should have received a copy of the GNU General Public License "
2137 "along with Fio; if not, write to the Free Software Foundation, Inc., "
2138 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
2139 };
2140 char *license_trans;
2141
2142 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
2143 license[2], "\n", NULL);
Jens Axboe81e4ea62012-03-07 14:18:28 +01002144
Jens Axboe0420ba62012-02-29 11:16:52 +01002145 gtk_show_about_dialog(NULL,
2146 "program-name", "gfio",
2147 "comments", "Gtk2 UI for fio",
Jens Axboe84a72ed2012-03-07 14:24:57 +01002148 "license", license_trans,
Jens Axboe81e4ea62012-03-07 14:18:28 +01002149 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
2150 "authors", authors,
Jens Axboe0420ba62012-02-29 11:16:52 +01002151 "version", fio_version_string,
Jens Axboe81e4ea62012-03-07 14:18:28 +01002152 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
Jens Axboe0420ba62012-02-29 11:16:52 +01002153 "logo-icon-name", "fio",
2154 /* Must be last: */
Jens Axboe81e4ea62012-03-07 14:18:28 +01002155 "wrap-license", TRUE,
Jens Axboe0420ba62012-02-29 11:16:52 +01002156 NULL);
Jens Axboe84a72ed2012-03-07 14:24:57 +01002157
Jens Axboe2f99deb2012-03-09 14:37:29 +01002158 g_free(license_trans);
Jens Axboe0420ba62012-02-29 11:16:52 +01002159}
2160
2161static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01002162 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01002163 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01002164 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
Jens Axboe2f99deb2012-03-09 14:37:29 +01002165 { "NewFile", GTK_STOCK_NEW, "New", "<Control>N", NULL, G_CALLBACK(file_new) },
Jens Axboe46974a72012-03-02 19:34:13 +01002166 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
2167 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
2168 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01002169 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe46974a72012-03-02 19:34:13 +01002170 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
2171 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01002172};
Jens Axboe3e47bd22012-02-29 13:45:02 +01002173static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01002174
2175static const gchar *ui_string = " \
2176 <ui> \
2177 <menubar name=\"MainMenu\"> \
2178 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01002179 <menuitem name=\"New\" action=\"NewFile\" /> \
2180 <separator name=\"Separator1\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01002181 <menuitem name=\"Open\" action=\"OpenFile\" /> \
2182 <menuitem name=\"Save\" action=\"SaveFile\" /> \
Jens Axboe46974a72012-03-02 19:34:13 +01002183 <separator name=\"Separator2\"/> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01002184 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
2185 <separator name=\"Separator3\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01002186 <menuitem name=\"Quit\" action=\"Quit\" /> \
2187 </menu> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01002188 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
2189 <menuitem name=\"Log\" action=\"ViewLog\" /> \
2190 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01002191 <menu name=\"Help\" action=\"HelpMenuAction\"> \
2192 <menuitem name=\"About\" action=\"About\" /> \
2193 </menu> \
2194 </menubar> \
2195 </ui> \
2196";
2197
Jens Axboe4cbe7212012-03-06 13:36:17 +01002198static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
2199 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01002200{
2201 GtkActionGroup *action_group = gtk_action_group_new("Menu");
2202 GError *error = 0;
2203
2204 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01002205 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01002206
2207 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
2208 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
2209
2210 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
2211 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
2212}
2213
2214void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
2215 GtkWidget *vbox, GtkUIManager *ui_manager)
2216{
2217 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
2218}
2219
Jens Axboe2f99deb2012-03-09 14:37:29 +01002220static GtkWidget *new_client_page(struct gui_entry *ge)
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002221{
Jens Axboe2f99deb2012-03-09 14:37:29 +01002222 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01002223 GdkColor white;
Jens Axboe0420ba62012-02-29 11:16:52 +01002224
Jens Axboe2f99deb2012-03-09 14:37:29 +01002225 main_vbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01002226
Jens Axboe2f99deb2012-03-09 14:37:29 +01002227 ge->topalign = gtk_alignment_new(0, 0, 1, 0);
2228 ge->topvbox = gtk_vbox_new(FALSE, 3);
2229 gtk_container_add(GTK_CONTAINER(ge->topalign), ge->topvbox);
2230 gtk_box_pack_start(GTK_BOX(main_vbox), ge->topalign, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002231
Jens Axboe3e47bd22012-02-29 13:45:02 +01002232 probe = gtk_frame_new("Job");
Jens Axboe2f99deb2012-03-09 14:37:29 +01002233 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01002234 probe_frame = gtk_vbox_new(FALSE, 3);
2235 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
2236
2237 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002238 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2239 ge->probe.hostname = new_info_label_in_frame(probe_box, "Host");
2240 ge->probe.os = new_info_label_in_frame(probe_box, "OS");
2241 ge->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
2242 ge->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
Jens Axboe843ad232012-02-29 11:44:53 +01002243
Jens Axboe3e47bd22012-02-29 13:45:02 +01002244 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002245 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2246
Jens Axboe3863d1a2012-03-09 17:39:05 +01002247 ge->eta.names = new_combo_entry_in_frame(probe_box, "Jobs");
Jens Axboe2f99deb2012-03-09 14:37:29 +01002248 ge->eta.iotype = new_info_entry_in_frame(probe_box, "IO");
2249 ge->eta.ioengine = new_info_entry_in_frame(probe_box, "IO Engine");
2250 ge->eta.iodepth = new_info_entry_in_frame(probe_box, "IO Depth");
2251 ge->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
2252 ge->eta.files = new_info_entry_in_frame(probe_box, "Open files");
2253
2254 probe_box = gtk_hbox_new(FALSE, 3);
2255 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2256 ge->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
2257 ge->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
2258 ge->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
2259 ge->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
2260
2261 /*
2262 * Only add this if we have a commit rate
2263 */
2264#if 0
2265 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe3e47bd22012-02-29 13:45:02 +01002266 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01002267
Jens Axboe2f99deb2012-03-09 14:37:29 +01002268 ge->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
2269 ge->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2270
2271 ge->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
2272 ge->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2273#endif
2274
2275 /*
2276 * Set up a drawing area and IOPS and bandwidth graphs
2277 */
2278 gdk_color_parse("white", &white);
2279 ge->graphs.drawing_area = gtk_drawing_area_new();
2280 ge->graphs.drawing_area_xdim = DRAWING_AREA_XDIM;
2281 ge->graphs.drawing_area_ydim = DRAWING_AREA_YDIM;
2282 gtk_widget_set_size_request(GTK_WIDGET(ge->graphs.drawing_area),
2283 ge->graphs.drawing_area_xdim, ge->graphs.drawing_area_ydim);
2284 gtk_widget_modify_bg(ge->graphs.drawing_area, GTK_STATE_NORMAL, &white);
2285 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "expose_event",
2286 G_CALLBACK(on_expose_drawing_area), &ge->graphs);
2287 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "configure_event",
2288 G_CALLBACK(on_config_drawing_area), &ge->graphs);
2289 ge->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2290 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ge->scrolled_window),
2291 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2292 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ge->scrolled_window),
2293 ge->graphs.drawing_area);
2294 gtk_box_pack_start(GTK_BOX(main_vbox), ge->scrolled_window,
2295 TRUE, TRUE, 0);
2296
2297 setup_graphs(&ge->graphs);
2298
2299 /*
2300 * Set up alignments for widgets at the bottom of ui,
2301 * align bottom left, expand horizontally but not vertically
2302 */
2303 ge->bottomalign = gtk_alignment_new(0, 1, 1, 0);
2304 ge->buttonbox = gtk_hbox_new(FALSE, 0);
2305 gtk_container_add(GTK_CONTAINER(ge->bottomalign), ge->buttonbox);
2306 gtk_box_pack_start(GTK_BOX(main_vbox), ge->bottomalign,
2307 FALSE, FALSE, 0);
2308
2309 add_buttons(ge, buttonspeclist, ARRAYSIZE(buttonspeclist));
2310
2311 /*
2312 * Set up thread status progress bar
2313 */
2314 ge->thread_status_pb = gtk_progress_bar_new();
2315 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
2316 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No connections");
2317 gtk_container_add(GTK_CONTAINER(ge->buttonbox), ge->thread_status_pb);
2318
2319
2320 return main_vbox;
2321}
2322
2323static GtkWidget *new_main_page(struct gui *ui)
2324{
2325 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
2326 GdkColor white;
2327
2328 main_vbox = gtk_vbox_new(FALSE, 3);
2329
2330 /*
2331 * Set up alignments for widgets at the top of ui,
2332 * align top left, expand horizontally but not vertically
2333 */
2334 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
2335 ui->topvbox = gtk_vbox_new(FALSE, 0);
2336 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
2337 gtk_box_pack_start(GTK_BOX(main_vbox), ui->topalign, FALSE, FALSE, 0);
2338
2339 probe = gtk_frame_new("Run statistics");
2340 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
2341 probe_frame = gtk_vbox_new(FALSE, 3);
2342 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
Jens Axboe3e47bd22012-02-29 13:45:02 +01002343
2344 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002345 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
Jens Axboe3863d1a2012-03-09 17:39:05 +01002346 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Running");
Jens Axboeca850992012-03-05 20:04:43 +01002347 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
2348 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
2349 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
2350 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01002351
2352 /*
2353 * Only add this if we have a commit rate
2354 */
2355#if 0
2356 probe_box = gtk_hbox_new(FALSE, 3);
2357 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
2358
Jens Axboe3e47bd22012-02-29 13:45:02 +01002359 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
2360 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2361
Jens Axboe3e47bd22012-02-29 13:45:02 +01002362 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
2363 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01002364#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01002365
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01002366 /*
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002367 * Set up a drawing area and IOPS and bandwidth graphs
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002368 */
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01002369 gdk_color_parse("white", &white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002370 ui->graphs.drawing_area = gtk_drawing_area_new();
2371 ui->graphs.drawing_area_xdim = DRAWING_AREA_XDIM;
2372 ui->graphs.drawing_area_ydim = DRAWING_AREA_YDIM;
2373 gtk_widget_set_size_request(GTK_WIDGET(ui->graphs.drawing_area),
2374 ui->graphs.drawing_area_xdim, ui->graphs.drawing_area_ydim);
2375 gtk_widget_modify_bg(ui->graphs.drawing_area, GTK_STATE_NORMAL, &white);
2376 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "expose_event",
2377 G_CALLBACK(on_expose_drawing_area), &ui->graphs);
2378 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "configure_event",
2379 G_CALLBACK(on_config_drawing_area), &ui->graphs);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002380 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2381 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
2382 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002383 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ui->scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01002384 ui->graphs.drawing_area);
2385 gtk_box_pack_start(GTK_BOX(main_vbox), ui->scrolled_window,
Stephen M. Camerone1645342012-02-24 08:17:32 +01002386 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002387
Jens Axboe2f99deb2012-03-09 14:37:29 +01002388 setup_graphs(&ui->graphs);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002389
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002390 /*
2391 * Set up alignments for widgets at the bottom of ui,
2392 * align bottom left, expand horizontally but not vertically
2393 */
2394 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
2395 ui->buttonbox = gtk_hbox_new(FALSE, 0);
2396 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002397 gtk_box_pack_start(GTK_BOX(main_vbox), ui->bottomalign,
Stephen M. Camerone1645342012-02-24 08:17:32 +01002398 FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002399
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002400 /*
2401 * Set up thread status progress bar
2402 */
2403 ui->thread_status_pb = gtk_progress_bar_new();
2404 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01002405 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002406 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
2407
Jens Axboe2f99deb2012-03-09 14:37:29 +01002408 return main_vbox;
2409}
2410
2411static gboolean notebook_switch_page(GtkNotebook *notebook, GtkWidget *widget,
2412 guint page, gpointer data)
2413
2414{
2415 return TRUE;
2416}
2417
2418static void init_ui(int *argc, char **argv[], struct gui *ui)
2419{
2420 GtkSettings *settings;
2421 GtkUIManager *uimanager;
2422 GtkWidget *menu, *vbox;
2423
2424 /* Magical g*thread incantation, you just need this thread stuff.
2425 * Without it, the update that happens in gfio_update_thread_status
2426 * doesn't really happen in a timely fashion, you need expose events
2427 */
2428 if (!g_thread_supported())
2429 g_thread_init(NULL);
2430 gdk_threads_init();
2431
2432 gtk_init(argc, argv);
2433 settings = gtk_settings_get_default();
2434 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
2435 g_type_init();
2436
2437 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2438 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
2439 gtk_window_set_default_size(GTK_WINDOW(ui->window), 1024, 768);
2440
2441 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
2442 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
2443
2444 ui->vbox = gtk_vbox_new(FALSE, 0);
2445 gtk_container_add(GTK_CONTAINER(ui->window), ui->vbox);
2446
2447 uimanager = gtk_ui_manager_new();
2448 menu = get_menubar_menu(ui->window, uimanager, ui);
2449 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
2450
2451 ui->notebook = gtk_notebook_new();
2452 g_signal_connect(ui->notebook, "switch-page", G_CALLBACK(notebook_switch_page), ui);
Jens Axboeb870c312012-03-09 17:22:01 +01002453 gtk_notebook_set_scrollable(GTK_NOTEBOOK(ui->notebook), 1);
Jens Axboe0aa928c2012-03-09 17:24:07 +01002454 gtk_notebook_popup_enable(GTK_NOTEBOOK(ui->notebook));
Jens Axboe2f99deb2012-03-09 14:37:29 +01002455 gtk_container_add(GTK_CONTAINER(ui->vbox), ui->notebook);
2456
2457 vbox = new_main_page(ui);
2458
2459 gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), vbox, gtk_label_new("Main"));
2460
Jens Axboe9b260bd2012-03-06 11:02:52 +01002461 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002462
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002463 gtk_widget_show_all(ui->window);
2464}
2465
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002466int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002467{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002468 if (initialize_fio(envp))
2469 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01002470 if (fio_init_options())
2471 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01002472
Jens Axboe2f99deb2012-03-09 14:37:29 +01002473 memset(&main_ui, 0, sizeof(main_ui));
2474 INIT_FLIST_HEAD(&main_ui.list);
2475
2476 init_ui(&argc, &argv, &main_ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01002477
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002478 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002479 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002480 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002481 return 0;
2482}