blob: 936e41db2117c22d16a68ea09eb1770b7ddd74f9 [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;
Jens Axboe2f99deb2012-03-09 14:37:29 +010092 struct graph *iops_graph;
93 struct graph *bandwidth_graph;
94};
95
96/*
97 * Main window widgets and data
98 */
Stephen M. Cameronff1f3282012-02-24 08:17:30 +010099struct gui {
100 GtkWidget *window;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100101 GtkWidget *vbox;
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +0100102 GtkWidget *topvbox;
103 GtkWidget *topalign;
104 GtkWidget *bottomalign;
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +0100105 GtkWidget *thread_status_pb;
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100106 GtkWidget *buttonbox;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100107 GtkWidget *scrolled_window;
108 GtkWidget *notebook;
109 GtkWidget *error_info_bar;
110 GtkWidget *error_label;
111 GtkListStore *log_model;
112 GtkWidget *log_tree;
113 GtkWidget *log_view;
114 struct gfio_graphs graphs;
115 struct probe_widget probe;
116 struct eta_widget eta;
117 pthread_t server_t;
118
Jens Axboea9eccde2012-03-09 14:59:42 +0100119 pthread_t t;
120 int handler_running;
121
Jens Axboe2f99deb2012-03-09 14:37:29 +0100122 struct flist_head list;
123} main_ui;
124
125/*
126 * Notebook entry
127 */
128struct gui_entry {
129 struct flist_head list;
130 struct gui *ui;
131
132 GtkWidget *vbox;
133 GtkWidget *topvbox;
134 GtkWidget *topalign;
135 GtkWidget *bottomalign;
136 GtkWidget *thread_status_pb;
137 GtkWidget *buttonbox;
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100138 GtkWidget *button[ARRAYSIZE(buttonspeclist)];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100139 GtkWidget *scrolled_window;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100140 GtkWidget *notebook;
Jens Axboe0420ba62012-02-29 11:16:52 +0100141 GtkWidget *error_info_bar;
142 GtkWidget *error_label;
Jens Axboef9d40b42012-03-06 09:52:49 +0100143 GtkWidget *results_notebook;
144 GtkWidget *results_window;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100145 GtkListStore *log_model;
146 GtkWidget *log_tree;
Jens Axboe4cbe7212012-03-06 13:36:17 +0100147 GtkWidget *log_view;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100148 struct gfio_graphs graphs;
Jens Axboe843ad232012-02-29 11:44:53 +0100149 struct probe_widget probe;
Jens Axboe3e47bd22012-02-29 13:45:02 +0100150 struct eta_widget eta;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100151 GtkWidget *page_label;
152 gint page_num;
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100153 int connected;
Jens Axboe0420ba62012-02-29 11:16:52 +0100154
Jens Axboeb9d2f302012-03-08 20:36:28 +0100155 struct gfio_client *client;
Jens Axboe0420ba62012-02-29 11:16:52 +0100156 int nr_job_files;
157 char **job_files;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100158};
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100159
Jens Axboee0681f32012-03-06 12:14:42 +0100160struct gfio_client {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100161 struct gui_entry *ge;
Jens Axboeb9d2f302012-03-08 20:36:28 +0100162 struct fio_client *client;
Jens Axboee0681f32012-03-06 12:14:42 +0100163 GtkWidget *results_widget;
164 GtkWidget *disk_util_frame;
Jens Axboe6b79c802012-03-08 10:51:36 +0100165 GtkWidget *err_entry;
Jens Axboedcaeb602012-03-08 19:45:37 +0100166 unsigned int job_added;
167 struct thread_options o;
Jens Axboee0681f32012-03-06 12:14:42 +0100168};
169
Jens Axboe9988ca72012-03-09 15:14:06 +0100170static void gfio_update_thread_status(struct gui_entry *ge, char *status_message, double perc);
171static void gfio_update_thread_status_all(char *status_message, double perc);
Jens Axboec7249262012-03-09 17:11:04 +0100172void report_error(GError *error);
Jens Axboe9988ca72012-03-09 15:14:06 +0100173
Stephen M. Cameronf0af9f82012-03-11 11:35:50 +0100174static void iops_graph_y_axis_unit_change(struct graph *g, int power_of_ten)
175{
176 switch (power_of_ten) {
177 case 9: graph_y_title(g, "Billions of IOs / sec");
178 break;
179 case 6: graph_y_title(g, "Millions of IOs / sec");
180 break;
181 case 3: graph_y_title(g, "Thousands of IOs / sec");
182 break;
183 case 0:
184 default: graph_y_title(g, "IOs / sec");
185 break;
186 }
187}
188
Jens Axboe2f99deb2012-03-09 14:37:29 +0100189static struct graph *setup_iops_graph(void)
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100190{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100191 struct graph *g;
192
193 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
194 graph_title(g, "IOPS");
195 graph_x_title(g, "Time (secs)");
196 graph_y_title(g, "IOs / sec");
197 graph_add_label(g, "Read IOPS");
198 graph_add_label(g, "Write IOPS");
199 graph_set_color(g, "Read IOPS", 0.13, 0.54, 0.13);
200 graph_set_color(g, "Write IOPS", 1.0, 0.0, 0.0);
Jens Axboe8577f4f2012-03-09 19:28:27 +0100201 line_graph_set_data_count_limit(g, gfio_graph_limit);
Stephen M. Cameronf0af9f82012-03-11 11:35:50 +0100202 graph_y_axis_unit_change_notify(g, iops_graph_y_axis_unit_change);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100203 return g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100204}
205
Stephen M. Cameronf0af9f82012-03-11 11:35:50 +0100206static void bandwidth_graph_y_axis_unit_change(struct graph *g, int power_of_ten)
207{
208 switch (power_of_ten) {
209 case 9: graph_y_title(g, "Petabytes / sec");
210 break;
211 case 6: graph_y_title(g, "Gigabytes / sec");
212 break;
213 case 3: graph_y_title(g, "Megabytes / sec");
214 break;
215 case 0:
216 default: graph_y_title(g, "Kilobytes / sec");
217 break;
218 }
219}
220
Jens Axboe2f99deb2012-03-09 14:37:29 +0100221static struct graph *setup_bandwidth_graph(void)
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100222{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100223 struct graph *g;
224
225 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
226 graph_title(g, "Bandwidth");
227 graph_x_title(g, "Time (secs)");
228 graph_y_title(g, "Kbytes / sec");
229 graph_add_label(g, "Read Bandwidth");
230 graph_add_label(g, "Write Bandwidth");
231 graph_set_color(g, "Read Bandwidth", 0.13, 0.54, 0.13);
232 graph_set_color(g, "Write Bandwidth", 1.0, 0.0, 0.0);
233 line_graph_set_data_count_limit(g, 100);
Stephen M. Cameronf0af9f82012-03-11 11:35:50 +0100234 graph_y_axis_unit_change_notify(g, bandwidth_graph_y_axis_unit_change);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100235 return g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100236}
237
Jens Axboe2f99deb2012-03-09 14:37:29 +0100238static void setup_graphs(struct gfio_graphs *g)
Jens Axboe8663ea62012-03-02 14:04:30 +0100239{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100240 g->iops_graph = setup_iops_graph();
241 g->bandwidth_graph = setup_bandwidth_graph();
242}
243
244static void clear_ge_ui_info(struct gui_entry *ge)
245{
246 gtk_label_set_text(GTK_LABEL(ge->probe.hostname), "");
247 gtk_label_set_text(GTK_LABEL(ge->probe.os), "");
248 gtk_label_set_text(GTK_LABEL(ge->probe.arch), "");
249 gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100250#if 0
251 /* should we empty it... */
Jens Axboe2f99deb2012-03-09 14:37:29 +0100252 gtk_entry_set_text(GTK_ENTRY(ge->eta.name), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100253#endif
Jens Axboe2f99deb2012-03-09 14:37:29 +0100254 gtk_entry_set_text(GTK_ENTRY(ge->eta.iotype), "");
255 gtk_entry_set_text(GTK_ENTRY(ge->eta.ioengine), "");
256 gtk_entry_set_text(GTK_ENTRY(ge->eta.iodepth), "");
257 gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), "");
258 gtk_entry_set_text(GTK_ENTRY(ge->eta.files), "");
259 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), "");
260 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), "");
261 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), "");
262 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100263}
264
Jens Axboe3863d1a2012-03-09 17:39:05 +0100265static GtkWidget *new_combo_entry_in_frame(GtkWidget *box, const char *label)
266{
267 GtkWidget *entry, *frame;
268
269 frame = gtk_frame_new(label);
270 entry = gtk_combo_box_new_text();
271 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
272 gtk_container_add(GTK_CONTAINER(frame), entry);
273
274 return entry;
275}
276
Jens Axboe3650a3c2012-03-05 14:09:03 +0100277static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
278{
279 GtkWidget *entry, *frame;
280
281 frame = gtk_frame_new(label);
282 entry = gtk_entry_new();
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100283 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100284 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
285 gtk_container_add(GTK_CONTAINER(frame), entry);
286
287 return entry;
288}
289
290static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
291{
292 GtkWidget *label_widget;
293 GtkWidget *frame;
294
295 frame = gtk_frame_new(label);
296 label_widget = gtk_label_new(NULL);
297 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
298 gtk_container_add(GTK_CONTAINER(frame), label_widget);
299
300 return label_widget;
301}
302
303static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
304{
305 GtkWidget *button, *box;
306
307 box = gtk_hbox_new(FALSE, 3);
308 gtk_container_add(GTK_CONTAINER(hbox), box);
309
310 button = gtk_spin_button_new_with_range(min, max, 1.0);
311 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
312
313 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
314 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
315
316 return button;
317}
318
Jens Axboe2f99deb2012-03-09 14:37:29 +0100319static void gfio_set_connected(struct gui_entry *ge, int connected)
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100320{
321 if (connected) {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100322 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 1);
323 ge->connected = 1;
324 gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), "Disconnect");
325 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100326 } else {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100327 ge->connected = 0;
328 gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), "Connect");
329 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 0);
330 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 0);
331 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100332 }
333}
334
Jens Axboe3650a3c2012-03-05 14:09:03 +0100335static void label_set_int_value(GtkWidget *entry, unsigned int val)
336{
337 char tmp[80];
338
339 sprintf(tmp, "%u", val);
340 gtk_label_set_text(GTK_LABEL(entry), tmp);
341}
342
343static void entry_set_int_value(GtkWidget *entry, unsigned int val)
344{
345 char tmp[80];
346
347 sprintf(tmp, "%u", val);
348 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
349}
350
Jens Axboea2697902012-03-05 16:43:49 +0100351#define ALIGN_LEFT 1
352#define ALIGN_RIGHT 2
353#define INVISIBLE 4
354#define UNSORTABLE 8
355
356GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
357{
358 GtkCellRenderer *renderer;
359 GtkTreeViewColumn *col;
360 double xalign = 0.0; /* left as default */
361 PangoAlignment align;
362 gboolean visible;
363
364 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
365 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
366 PANGO_ALIGN_CENTER;
367 visible = !(flags & INVISIBLE);
368
369 renderer = gtk_cell_renderer_text_new();
370 col = gtk_tree_view_column_new();
371
372 gtk_tree_view_column_set_title(col, title);
373 if (!(flags & UNSORTABLE))
374 gtk_tree_view_column_set_sort_column_id(col, index);
375 gtk_tree_view_column_set_resizable(col, TRUE);
376 gtk_tree_view_column_pack_start(col, renderer, TRUE);
377 gtk_tree_view_column_add_attribute(col, renderer, "text", index);
378 gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
379 switch (align) {
380 case PANGO_ALIGN_LEFT:
381 xalign = 0.0;
382 break;
383 case PANGO_ALIGN_CENTER:
384 xalign = 0.5;
385 break;
386 case PANGO_ALIGN_RIGHT:
387 xalign = 1.0;
388 break;
389 }
390 gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
391 gtk_tree_view_column_set_visible(col, visible);
392 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
393 return col;
394}
395
Jens Axboe9b260bd2012-03-06 11:02:52 +0100396static void gfio_ui_setup_log(struct gui *ui)
397{
398 GtkTreeSelection *selection;
399 GtkListStore *model;
400 GtkWidget *tree_view;
401
402 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
403
404 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
405 gtk_widget_set_can_focus(tree_view, FALSE);
406
407 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
408 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
Jens Axboe661f7412012-03-06 13:55:45 +0100409 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
410 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100411
412 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
413 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
414 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
Jens Axboef095d562012-03-06 13:49:12 +0100415 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100416
417 ui->log_model = model;
418 ui->log_tree = tree_view;
419}
420
Jens Axboea2697902012-03-05 16:43:49 +0100421static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
422 fio_fp64_t *plist,
423 unsigned int len,
424 const char *base,
425 unsigned int scale)
426{
427 GType types[FIO_IO_U_LIST_MAX_LEN];
428 GtkWidget *tree_view;
429 GtkTreeSelection *selection;
430 GtkListStore *model;
431 GtkTreeIter iter;
432 int i;
433
434 for (i = 0; i < len; i++)
435 types[i] = G_TYPE_INT;
436
437 model = gtk_list_store_newv(len, types);
438
439 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
440 gtk_widget_set_can_focus(tree_view, FALSE);
441
Jens Axboe661f7412012-03-06 13:55:45 +0100442 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
443 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
444
Jens Axboea2697902012-03-05 16:43:49 +0100445 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
446 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
447
448 for (i = 0; i < len; i++) {
449 char fbuf[8];
450
451 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
452 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
453 }
454
455 gtk_list_store_append(model, &iter);
456
Jens Axboee0681f32012-03-06 12:14:42 +0100457 for (i = 0; i < len; i++) {
458 if (scale)
459 ovals[i] = (ovals[i] + 999) / 1000;
Jens Axboea2697902012-03-05 16:43:49 +0100460 gtk_list_store_set(model, &iter, i, ovals[i], -1);
Jens Axboee0681f32012-03-06 12:14:42 +0100461 }
Jens Axboea2697902012-03-05 16:43:49 +0100462
463 return tree_view;
464}
465
466static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
467 int ddir)
468{
469 unsigned int *io_u_plat = ts->io_u_plat[ddir];
470 unsigned long nr = ts->clat_stat[ddir].samples;
471 fio_fp64_t *plist = ts->percentile_list;
472 unsigned int *ovals, len, minv, maxv, scale_down;
473 const char *base;
474 GtkWidget *tree_view, *frame, *hbox;
475 char tmp[64];
476
477 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
478 if (!len)
479 goto out;
480
481 /*
482 * We default to usecs, but if the value range is such that we
483 * should scale down to msecs, do that.
484 */
485 if (minv > 2000 && maxv > 99999) {
486 scale_down = 1;
487 base = "msec";
488 } else {
489 scale_down = 0;
490 base = "usec";
491 }
492
493 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
494
495 sprintf(tmp, "Completion percentiles (%s)", base);
496 frame = gtk_frame_new(tmp);
497 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
498
499 hbox = gtk_hbox_new(FALSE, 3);
500 gtk_container_add(GTK_CONTAINER(frame), hbox);
501
502 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
503out:
504 if (ovals)
505 free(ovals);
506}
507
Jens Axboe3650a3c2012-03-05 14:09:03 +0100508static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
509 unsigned long max, double mean, double dev)
510{
511 const char *base = "(usec)";
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100512 GtkWidget *hbox, *label, *frame;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100513 char *minp, *maxp;
514 char tmp[64];
515
516 if (!usec_to_msec(&min, &max, &mean, &dev))
517 base = "(msec)";
518
519 minp = num2str(min, 6, 1, 0);
520 maxp = num2str(max, 6, 1, 0);
521
Jens Axboe3650a3c2012-03-05 14:09:03 +0100522 sprintf(tmp, "%s %s", name, base);
523 frame = gtk_frame_new(tmp);
524 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
525
Jens Axboe3650a3c2012-03-05 14:09:03 +0100526 hbox = gtk_hbox_new(FALSE, 3);
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100527 gtk_container_add(GTK_CONTAINER(frame), hbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100528
529 label = new_info_label_in_frame(hbox, "Minimum");
530 gtk_label_set_text(GTK_LABEL(label), minp);
531 label = new_info_label_in_frame(hbox, "Maximum");
532 gtk_label_set_text(GTK_LABEL(label), maxp);
533 label = new_info_label_in_frame(hbox, "Average");
534 sprintf(tmp, "%5.02f", mean);
535 gtk_label_set_text(GTK_LABEL(label), tmp);
536 label = new_info_label_in_frame(hbox, "Standard deviation");
537 sprintf(tmp, "%5.02f", dev);
538 gtk_label_set_text(GTK_LABEL(label), tmp);
539
540 free(minp);
541 free(maxp);
542
543}
544
Jens Axboeca850992012-03-05 20:04:43 +0100545#define GFIO_CLAT 1
546#define GFIO_SLAT 2
547#define GFIO_LAT 4
548
Jens Axboe3650a3c2012-03-05 14:09:03 +0100549static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
550 struct thread_stat *ts, int ddir)
551{
552 const char *ddir_label[2] = { "Read", "Write" };
Jens Axboe0b761302012-03-05 20:44:11 +0100553 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
Jens Axboee0681f32012-03-06 12:14:42 +0100554 unsigned long min[3], max[3], runt;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100555 unsigned long long bw, iops;
Jens Axboeca850992012-03-05 20:04:43 +0100556 unsigned int flags = 0;
Jens Axboee0681f32012-03-06 12:14:42 +0100557 double mean[3], dev[3];
Jens Axboe3650a3c2012-03-05 14:09:03 +0100558 char *io_p, *bw_p, *iops_p;
559 int i2p;
560
561 if (!ts->runtime[ddir])
562 return;
563
564 i2p = is_power_of_2(rs->kb_base);
565 runt = ts->runtime[ddir];
566
567 bw = (1000 * ts->io_bytes[ddir]) / runt;
568 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
569 bw_p = num2str(bw, 6, 1, i2p);
570
571 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
572 iops_p = num2str(iops, 6, 1, 0);
573
574 box = gtk_hbox_new(FALSE, 3);
575 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
576
577 frame = gtk_frame_new(ddir_label[ddir]);
578 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
579
Jens Axboe0b761302012-03-05 20:44:11 +0100580 main_vbox = gtk_vbox_new(FALSE, 3);
581 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100582
583 box = gtk_hbox_new(FALSE, 3);
Jens Axboe0b761302012-03-05 20:44:11 +0100584 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100585
586 label = new_info_label_in_frame(box, "IO");
587 gtk_label_set_text(GTK_LABEL(label), io_p);
588 label = new_info_label_in_frame(box, "Bandwidth");
589 gtk_label_set_text(GTK_LABEL(label), bw_p);
590 label = new_info_label_in_frame(box, "IOPS");
591 gtk_label_set_text(GTK_LABEL(label), iops_p);
592 label = new_info_label_in_frame(box, "Runtime (msec)");
593 label_set_int_value(label, ts->runtime[ddir]);
594
Jens Axboee0681f32012-03-06 12:14:42 +0100595 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
Jens Axboeca850992012-03-05 20:04:43 +0100596 double p_of_agg = 100.0;
597 const char *bw_str = "KB";
598 char tmp[32];
599
600 if (rs->agg[ddir]) {
Jens Axboee0681f32012-03-06 12:14:42 +0100601 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
Jens Axboeca850992012-03-05 20:04:43 +0100602 if (p_of_agg > 100.0)
603 p_of_agg = 100.0;
604 }
605
Jens Axboee0681f32012-03-06 12:14:42 +0100606 if (mean[0] > 999999.9) {
607 min[0] /= 1000.0;
608 max[0] /= 1000.0;
609 mean[0] /= 1000.0;
610 dev[0] /= 1000.0;
Jens Axboeca850992012-03-05 20:04:43 +0100611 bw_str = "MB";
612 }
613
Jens Axboe0b761302012-03-05 20:44:11 +0100614 sprintf(tmp, "Bandwidth (%s)", bw_str);
615 frame = gtk_frame_new(tmp);
616 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
Jens Axboeca850992012-03-05 20:04:43 +0100617
Jens Axboe0b761302012-03-05 20:44:11 +0100618 box = gtk_hbox_new(FALSE, 3);
619 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboeca850992012-03-05 20:04:43 +0100620
Jens Axboe0b761302012-03-05 20:44:11 +0100621 label = new_info_label_in_frame(box, "Minimum");
Jens Axboee0681f32012-03-06 12:14:42 +0100622 label_set_int_value(label, min[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100623 label = new_info_label_in_frame(box, "Maximum");
Jens Axboee0681f32012-03-06 12:14:42 +0100624 label_set_int_value(label, max[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100625 label = new_info_label_in_frame(box, "Percentage of jobs");
Jens Axboeca850992012-03-05 20:04:43 +0100626 sprintf(tmp, "%3.2f%%", p_of_agg);
627 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100628 label = new_info_label_in_frame(box, "Average");
Jens Axboee0681f32012-03-06 12:14:42 +0100629 sprintf(tmp, "%5.02f", mean[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100630 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100631 label = new_info_label_in_frame(box, "Standard deviation");
Jens Axboee0681f32012-03-06 12:14:42 +0100632 sprintf(tmp, "%5.02f", dev[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100633 gtk_label_set_text(GTK_LABEL(label), tmp);
634 }
635
Jens Axboee0681f32012-03-06 12:14:42 +0100636 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
Jens Axboe2b089892012-03-06 08:09:17 +0100637 flags |= GFIO_SLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100638 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
Jens Axboe2b089892012-03-06 08:09:17 +0100639 flags |= GFIO_CLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100640 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
Jens Axboe2b089892012-03-06 08:09:17 +0100641 flags |= GFIO_LAT;
642
643 if (flags) {
644 frame = gtk_frame_new("Latency");
645 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
646
647 vbox = gtk_vbox_new(FALSE, 3);
648 gtk_container_add(GTK_CONTAINER(frame), vbox);
649
650 if (flags & GFIO_SLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100651 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
Jens Axboe2b089892012-03-06 08:09:17 +0100652 if (flags & GFIO_CLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100653 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
Jens Axboe2b089892012-03-06 08:09:17 +0100654 if (flags & GFIO_LAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100655 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
Jens Axboe2b089892012-03-06 08:09:17 +0100656 }
657
658 if (ts->clat_percentiles)
659 gfio_show_clat_percentiles(main_vbox, ts, ddir);
660
661
Jens Axboe3650a3c2012-03-05 14:09:03 +0100662 free(io_p);
663 free(bw_p);
664 free(iops_p);
665}
666
Jens Axboee5bd1342012-03-05 21:38:12 +0100667static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
668 const char **labels)
669{
670 GtkWidget *tree_view;
671 GtkTreeSelection *selection;
672 GtkListStore *model;
673 GtkTreeIter iter;
674 GType *types;
675 int i, skipped;
676
677 /*
678 * Check if all are empty, in which case don't bother
679 */
680 for (i = 0, skipped = 0; i < num; i++)
681 if (lat[i] <= 0.0)
682 skipped++;
683
684 if (skipped == num)
685 return NULL;
686
687 types = malloc(num * sizeof(GType));
688
689 for (i = 0; i < num; i++)
690 types[i] = G_TYPE_STRING;
691
692 model = gtk_list_store_newv(num, types);
693 free(types);
694 types = NULL;
695
696 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
697 gtk_widget_set_can_focus(tree_view, FALSE);
698
Jens Axboe661f7412012-03-06 13:55:45 +0100699 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
700 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
701
Jens Axboee5bd1342012-03-05 21:38:12 +0100702 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
703 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
704
705 for (i = 0; i < num; i++)
706 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
707
708 gtk_list_store_append(model, &iter);
709
710 for (i = 0; i < num; i++) {
711 char fbuf[32];
712
713 if (lat[i] <= 0.0)
714 sprintf(fbuf, "0.00");
715 else
716 sprintf(fbuf, "%3.2f%%", lat[i]);
717
718 gtk_list_store_set(model, &iter, i, fbuf, -1);
719 }
720
721 return tree_view;
722}
723
724static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
725{
726 GtkWidget *box, *frame, *tree_view;
727 double io_u_lat_u[FIO_IO_U_LAT_U_NR];
728 double io_u_lat_m[FIO_IO_U_LAT_M_NR];
729 const char *uranges[] = { "2", "4", "10", "20", "50", "100",
730 "250", "500", "750", "1000", };
731 const char *mranges[] = { "2", "4", "10", "20", "50", "100",
732 "250", "500", "750", "1000", "2000",
733 ">= 2000", };
734
735 stat_calc_lat_u(ts, io_u_lat_u);
736 stat_calc_lat_m(ts, io_u_lat_m);
737
738 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
739 if (tree_view) {
740 frame = gtk_frame_new("Latency buckets (usec)");
741 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
742
743 box = gtk_hbox_new(FALSE, 3);
744 gtk_container_add(GTK_CONTAINER(frame), box);
745 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
746 }
747
748 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
749 if (tree_view) {
750 frame = gtk_frame_new("Latency buckets (msec)");
751 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
752
753 box = gtk_hbox_new(FALSE, 3);
754 gtk_container_add(GTK_CONTAINER(frame), box);
755 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
756 }
757}
758
Jens Axboe2e331012012-03-05 22:07:54 +0100759static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
760{
761 GtkWidget *box, *frame, *entry;
762 double usr_cpu, sys_cpu;
763 unsigned long runtime;
764 char tmp[32];
765
766 runtime = ts->total_run_time;
767 if (runtime) {
768 double runt = (double) runtime;
769
770 usr_cpu = (double) ts->usr_time * 100 / runt;
771 sys_cpu = (double) ts->sys_time * 100 / runt;
772 } else {
773 usr_cpu = 0;
774 sys_cpu = 0;
775 }
776
777 frame = gtk_frame_new("OS resources");
778 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
779
780 box = gtk_hbox_new(FALSE, 3);
781 gtk_container_add(GTK_CONTAINER(frame), box);
782
783 entry = new_info_entry_in_frame(box, "User CPU");
784 sprintf(tmp, "%3.2f%%", usr_cpu);
785 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
786 entry = new_info_entry_in_frame(box, "System CPU");
787 sprintf(tmp, "%3.2f%%", sys_cpu);
788 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
789 entry = new_info_entry_in_frame(box, "Context switches");
790 entry_set_int_value(entry, ts->ctx);
791 entry = new_info_entry_in_frame(box, "Major faults");
792 entry_set_int_value(entry, ts->majf);
793 entry = new_info_entry_in_frame(box, "Minor faults");
794 entry_set_int_value(entry, ts->minf);
795}
Jens Axboe19998db2012-03-06 09:17:59 +0100796static void gfio_add_sc_depths_tree(GtkListStore *model,
797 struct thread_stat *ts, unsigned int len,
798 int submit)
799{
800 double io_u_dist[FIO_IO_U_MAP_NR];
801 GtkTreeIter iter;
802 /* Bits 0, and 3-8 */
803 const int add_mask = 0x1f9;
804 int i, j;
805
806 if (submit)
807 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
808 else
809 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
810
811 gtk_list_store_append(model, &iter);
812
813 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
814
815 for (i = 1, j = 0; i < len; i++) {
816 char fbuf[32];
817
818 if (!(add_mask & (1UL << (i - 1))))
819 sprintf(fbuf, "0.0%%");
820 else {
821 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
822 j++;
823 }
824
825 gtk_list_store_set(model, &iter, i, fbuf, -1);
826 }
827
828}
829
830static void gfio_add_total_depths_tree(GtkListStore *model,
831 struct thread_stat *ts, unsigned int len)
832{
833 double io_u_dist[FIO_IO_U_MAP_NR];
834 GtkTreeIter iter;
835 /* Bits 1-6, and 8 */
836 const int add_mask = 0x17e;
837 int i, j;
838
839 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
840
841 gtk_list_store_append(model, &iter);
842
843 gtk_list_store_set(model, &iter, 0, "Total", -1);
844
845 for (i = 1, j = 0; i < len; i++) {
846 char fbuf[32];
847
848 if (!(add_mask & (1UL << (i - 1))))
849 sprintf(fbuf, "0.0%%");
850 else {
851 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
852 j++;
853 }
854
855 gtk_list_store_set(model, &iter, i, fbuf, -1);
856 }
857
858}
Jens Axboe2e331012012-03-05 22:07:54 +0100859
860static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
861{
Jens Axboe2e331012012-03-05 22:07:54 +0100862 GtkWidget *frame, *box, *tree_view;
863 GtkTreeSelection *selection;
864 GtkListStore *model;
Jens Axboe2e331012012-03-05 22:07:54 +0100865 GType types[FIO_IO_U_MAP_NR + 1];
866 int i;
Jens Axboe19998db2012-03-06 09:17:59 +0100867#define NR_LABELS 10
868 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
Jens Axboe2e331012012-03-05 22:07:54 +0100869
870 frame = gtk_frame_new("IO depths");
871 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
872
873 box = gtk_hbox_new(FALSE, 3);
874 gtk_container_add(GTK_CONTAINER(frame), box);
875
Jens Axboe19998db2012-03-06 09:17:59 +0100876 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100877 types[i] = G_TYPE_STRING;
878
Jens Axboe19998db2012-03-06 09:17:59 +0100879 model = gtk_list_store_newv(NR_LABELS, types);
Jens Axboe2e331012012-03-05 22:07:54 +0100880
881 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
882 gtk_widget_set_can_focus(tree_view, FALSE);
883
Jens Axboe661f7412012-03-06 13:55:45 +0100884 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
885 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
886
Jens Axboe2e331012012-03-05 22:07:54 +0100887 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
888 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
889
Jens Axboe19998db2012-03-06 09:17:59 +0100890 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100891 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
892
Jens Axboe19998db2012-03-06 09:17:59 +0100893 gfio_add_total_depths_tree(model, ts, NR_LABELS);
894 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 1);
895 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 0);
Jens Axboe2e331012012-03-05 22:07:54 +0100896
897 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
898}
899
Jens Axboef9d40b42012-03-06 09:52:49 +0100900static gboolean results_window_delete(GtkWidget *w, gpointer data)
901{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100902 struct gui_entry *ge = (struct gui_entry *) data;
Jens Axboef9d40b42012-03-06 09:52:49 +0100903
904 gtk_widget_destroy(w);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100905 ge->results_window = NULL;
906 ge->results_notebook = NULL;
Jens Axboef9d40b42012-03-06 09:52:49 +0100907 return TRUE;
908}
909
Jens Axboe2f99deb2012-03-09 14:37:29 +0100910static GtkWidget *get_results_window(struct gui_entry *ge)
Jens Axboef9d40b42012-03-06 09:52:49 +0100911{
912 GtkWidget *win, *notebook;
913
Jens Axboe2f99deb2012-03-09 14:37:29 +0100914 if (ge->results_window)
915 return ge->results_notebook;
Jens Axboef9d40b42012-03-06 09:52:49 +0100916
917 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
918 gtk_window_set_title(GTK_WINDOW(win), "Results");
Jens Axboeb01329d2012-03-07 20:31:28 +0100919 gtk_window_set_default_size(GTK_WINDOW(win), 1024, 768);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100920 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ge);
921 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ge);
Jens Axboef9d40b42012-03-06 09:52:49 +0100922
923 notebook = gtk_notebook_new();
Jens Axboe0aa928c2012-03-09 17:24:07 +0100924 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), 1);
925 gtk_notebook_popup_enable(GTK_NOTEBOOK(notebook));
Jens Axboef9d40b42012-03-06 09:52:49 +0100926 gtk_container_add(GTK_CONTAINER(win), notebook);
927
Jens Axboe2f99deb2012-03-09 14:37:29 +0100928 ge->results_window = win;
929 ge->results_notebook = notebook;
930 return ge->results_notebook;
Jens Axboef9d40b42012-03-06 09:52:49 +0100931}
932
Jens Axboe3650a3c2012-03-05 14:09:03 +0100933static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
934 struct group_run_stats *rs)
935{
Jens Axboeb01329d2012-03-07 20:31:28 +0100936 GtkWidget *res_win, *box, *vbox, *entry, *scroll;
Jens Axboee0681f32012-03-06 12:14:42 +0100937 struct gfio_client *gc = client->client_data;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100938
939 gdk_threads_enter();
940
Jens Axboe2f99deb2012-03-09 14:37:29 +0100941 res_win = get_results_window(gc->ge);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100942
Jens Axboeb01329d2012-03-07 20:31:28 +0100943 scroll = gtk_scrolled_window_new(NULL, NULL);
944 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
945 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
946
Jens Axboe3650a3c2012-03-05 14:09:03 +0100947 vbox = gtk_vbox_new(FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100948
Jens Axboeb01329d2012-03-07 20:31:28 +0100949 box = gtk_hbox_new(FALSE, 0);
950 gtk_box_pack_start(GTK_BOX(vbox), box, TRUE, FALSE, 5);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100951
Jens Axboeb01329d2012-03-07 20:31:28 +0100952 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
953
954 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), scroll, gtk_label_new(ts->name));
Jens Axboef9d40b42012-03-06 09:52:49 +0100955
Jens Axboee0681f32012-03-06 12:14:42 +0100956 gc->results_widget = vbox;
957
Jens Axboe3650a3c2012-03-05 14:09:03 +0100958 entry = new_info_entry_in_frame(box, "Name");
959 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
960 if (strlen(ts->description)) {
961 entry = new_info_entry_in_frame(box, "Description");
962 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
963 }
964 entry = new_info_entry_in_frame(box, "Group ID");
965 entry_set_int_value(entry, ts->groupid);
966 entry = new_info_entry_in_frame(box, "Jobs");
967 entry_set_int_value(entry, ts->members);
Jens Axboe6b79c802012-03-08 10:51:36 +0100968 gc->err_entry = entry = new_info_entry_in_frame(box, "Error");
Jens Axboe3650a3c2012-03-05 14:09:03 +0100969 entry_set_int_value(entry, ts->error);
970 entry = new_info_entry_in_frame(box, "PID");
971 entry_set_int_value(entry, ts->pid);
972
973 if (ts->io_bytes[DDIR_READ])
974 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
975 if (ts->io_bytes[DDIR_WRITE])
976 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
977
Jens Axboee5bd1342012-03-05 21:38:12 +0100978 gfio_show_latency_buckets(vbox, ts);
Jens Axboe2e331012012-03-05 22:07:54 +0100979 gfio_show_cpu_usage(vbox, ts);
980 gfio_show_io_depths(vbox, ts);
Jens Axboee5bd1342012-03-05 21:38:12 +0100981
Jens Axboe2f99deb2012-03-09 14:37:29 +0100982 gtk_widget_show_all(gc->ge->results_window);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100983 gdk_threads_leave();
984}
985
Jens Axboe084d1c62012-03-03 20:28:07 +0100986static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100987{
Jens Axboe9b260bd2012-03-06 11:02:52 +0100988 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100989 struct gui *ui = &main_ui;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100990 GtkTreeIter iter;
991 struct tm *tm;
992 time_t sec;
993 char tmp[64], timebuf[80];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100994
Jens Axboe9b260bd2012-03-06 11:02:52 +0100995 sec = p->log_sec;
996 tm = localtime(&sec);
997 strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", tm);
998 sprintf(timebuf, "%s.%03ld", tmp, p->log_usec / 1000);
999
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001000 gdk_threads_enter();
Jens Axboe9b260bd2012-03-06 11:02:52 +01001001
Jens Axboe2f99deb2012-03-09 14:37:29 +01001002 gtk_list_store_append(ui->log_model, &iter);
1003 gtk_list_store_set(ui->log_model, &iter, 0, timebuf, -1);
1004 gtk_list_store_set(ui->log_model, &iter, 1, client->hostname, -1);
1005 gtk_list_store_set(ui->log_model, &iter, 2, p->level, -1);
1006 gtk_list_store_set(ui->log_model, &iter, 3, p->buf, -1);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001007
Jens Axboe6b79c802012-03-08 10:51:36 +01001008 if (p->level == FIO_LOG_ERR)
Jens Axboe2f99deb2012-03-09 14:37:29 +01001009 view_log(NULL, (gpointer) ui);
Jens Axboe6b79c802012-03-08 10:51:36 +01001010
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001011 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001012}
1013
1014static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
1015{
Jens Axboee0681f32012-03-06 12:14:42 +01001016 struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
1017 struct gfio_client *gc = client->client_data;
1018 GtkWidget *box, *frame, *entry, *vbox;
Jens Axboe604cfe32012-03-07 19:51:36 +01001019 double util;
1020 char tmp[16];
Jens Axboee0681f32012-03-06 12:14:42 +01001021
Jens Axboe0050e5f2012-03-06 09:23:27 +01001022 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +01001023
Jens Axboe45dcb2e2012-03-07 16:16:50 +01001024 if (!gc->results_widget)
Jens Axboee0681f32012-03-06 12:14:42 +01001025 goto out;
Jens Axboee0681f32012-03-06 12:14:42 +01001026
1027 if (!gc->disk_util_frame) {
1028 gc->disk_util_frame = gtk_frame_new("Disk utilization");
1029 gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
1030 }
1031
1032 vbox = gtk_vbox_new(FALSE, 3);
1033 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
1034
1035 frame = gtk_frame_new((char *) p->dus.name);
1036 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
1037
1038 box = gtk_vbox_new(FALSE, 3);
1039 gtk_container_add(GTK_CONTAINER(frame), box);
1040
1041 frame = gtk_frame_new("Read");
1042 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1043 vbox = gtk_hbox_new(TRUE, 3);
1044 gtk_container_add(GTK_CONTAINER(frame), vbox);
1045 entry = new_info_entry_in_frame(vbox, "IOs");
1046 entry_set_int_value(entry, p->dus.ios[0]);
1047 entry = new_info_entry_in_frame(vbox, "Merges");
1048 entry_set_int_value(entry, p->dus.merges[0]);
1049 entry = new_info_entry_in_frame(vbox, "Sectors");
1050 entry_set_int_value(entry, p->dus.sectors[0]);
1051 entry = new_info_entry_in_frame(vbox, "Ticks");
1052 entry_set_int_value(entry, p->dus.ticks[0]);
1053
1054 frame = gtk_frame_new("Write");
1055 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1056 vbox = gtk_hbox_new(TRUE, 3);
1057 gtk_container_add(GTK_CONTAINER(frame), vbox);
1058 entry = new_info_entry_in_frame(vbox, "IOs");
1059 entry_set_int_value(entry, p->dus.ios[1]);
1060 entry = new_info_entry_in_frame(vbox, "Merges");
1061 entry_set_int_value(entry, p->dus.merges[1]);
1062 entry = new_info_entry_in_frame(vbox, "Sectors");
1063 entry_set_int_value(entry, p->dus.sectors[1]);
1064 entry = new_info_entry_in_frame(vbox, "Ticks");
1065 entry_set_int_value(entry, p->dus.ticks[1]);
1066
1067 frame = gtk_frame_new("Shared");
1068 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1069 vbox = gtk_hbox_new(TRUE, 3);
1070 gtk_container_add(GTK_CONTAINER(frame), vbox);
1071 entry = new_info_entry_in_frame(vbox, "IO ticks");
1072 entry_set_int_value(entry, p->dus.io_ticks);
1073 entry = new_info_entry_in_frame(vbox, "Time in queue");
1074 entry_set_int_value(entry, p->dus.time_in_queue);
1075
Jens Axboe604cfe32012-03-07 19:51:36 +01001076 util = 0.0;
1077 if (p->dus.msec)
1078 util = (double) 100 * p->dus.io_ticks / (double) p->dus.msec;
1079 if (util > 100.0)
1080 util = 100.0;
1081
1082 sprintf(tmp, "%3.2f%%", util);
1083 entry = new_info_entry_in_frame(vbox, "Disk utilization");
1084 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
1085
Jens Axboee0681f32012-03-06 12:14:42 +01001086 gtk_widget_show_all(gc->results_widget);
1087out:
Jens Axboe0050e5f2012-03-06 09:23:27 +01001088 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001089}
1090
Jens Axboe3650a3c2012-03-05 14:09:03 +01001091extern int sum_stat_clients;
1092extern struct thread_stat client_ts;
1093extern struct group_run_stats client_gs;
1094
1095static int sum_stat_nr;
1096
Jens Axboe89e5fad2012-03-05 09:21:12 +01001097static void gfio_thread_status_op(struct fio_client *client,
1098 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001099{
Jens Axboe3650a3c2012-03-05 14:09:03 +01001100 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
1101
1102 gfio_display_ts(client, &p->ts, &p->rs);
1103
1104 if (sum_stat_clients == 1)
1105 return;
1106
1107 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
1108 sum_group_stats(&client_gs, &p->rs);
1109
1110 client_ts.members++;
1111 client_ts.groupid = p->ts.groupid;
1112
1113 if (++sum_stat_nr == sum_stat_clients) {
1114 strcpy(client_ts.name, "All clients");
1115 gfio_display_ts(client, &client_ts, &client_gs);
1116 }
Stephen M. Camerona1820202012-02-24 08:17:31 +01001117}
1118
Jens Axboe89e5fad2012-03-05 09:21:12 +01001119static void gfio_group_stats_op(struct fio_client *client,
1120 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001121{
Jens Axboe98ceabd2012-03-09 08:53:28 +01001122 /* We're ignoring group stats for now */
Stephen M. Camerona1820202012-02-24 08:17:31 +01001123}
1124
Jens Axboe2f99deb2012-03-09 14:37:29 +01001125static gint on_config_drawing_area(GtkWidget *w, GdkEventConfigure *event,
1126 gpointer data)
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001127{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001128 struct gfio_graphs *g = data;
1129
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001130 graph_set_size(g->iops_graph, w->allocation.width / 2.0, w->allocation.height);
1131 graph_set_position(g->iops_graph, w->allocation.width / 2.0, 0.0);
1132 graph_set_size(g->bandwidth_graph, w->allocation.width / 2.0, w->allocation.height);
1133 graph_set_position(g->bandwidth_graph, 0, 0);
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001134 return TRUE;
1135}
1136
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001137static void draw_graph(struct graph *g, cairo_t *cr)
1138{
1139 line_graph_draw(g, cr);
1140 cairo_stroke(cr);
1141}
1142
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001143static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
1144{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001145 struct gfio_graphs *g = p;
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001146 cairo_t *cr;
1147
1148 cr = gdk_cairo_create(w->window);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001149 cairo_set_source_rgb(cr, 0, 0, 0);
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001150 draw_graph(g->iops_graph, cr);
1151 draw_graph(g->bandwidth_graph, cr);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001152 cairo_destroy(cr);
1153
1154 return FALSE;
1155}
1156
Jens Axboe2f99deb2012-03-09 14:37:29 +01001157/*
1158 * Client specific ETA
1159 */
1160static void gfio_update_client_eta(struct fio_client *client, struct jobs_eta *je)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001161{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001162 struct gfio_client *gc = client->client_data;
1163 struct gui_entry *ge = gc->ge;
Jens Axboe3e47bd22012-02-29 13:45:02 +01001164 static int eta_good;
1165 char eta_str[128];
1166 char output[256];
1167 char tmp[32];
1168 double perc = 0.0;
1169 int i2p = 0;
1170
Jens Axboe0050e5f2012-03-06 09:23:27 +01001171 gdk_threads_enter();
1172
Jens Axboe3e47bd22012-02-29 13:45:02 +01001173 eta_str[0] = '\0';
1174 output[0] = '\0';
1175
1176 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1177 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1178 eta_to_str(eta_str, je->eta_sec);
1179 }
1180
1181 sprintf(tmp, "%u", je->nr_running);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001182 gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001183 sprintf(tmp, "%u", je->files_open);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001184 gtk_entry_set_text(GTK_ENTRY(ge->eta.files), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001185
1186#if 0
1187 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1188 if (je->m_rate || je->t_rate) {
1189 char *tr, *mr;
1190
1191 mr = num2str(je->m_rate, 4, 0, i2p);
1192 tr = num2str(je->t_rate, 4, 0, i2p);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001193 gtk_entry_set_text(GTK_ENTRY(ge->eta);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001194 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1195 free(tr);
1196 free(mr);
1197 } else if (je->m_iops || je->t_iops)
1198 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
Jens Axboeebbd89c2012-03-02 11:21:13 +01001199
Jens Axboe2f99deb2012-03-09 14:37:29 +01001200 gtk_entry_set_text(GTK_ENTRY(ge->eta.cr_bw), "---");
1201 gtk_entry_set_text(GTK_ENTRY(ge->eta.cr_iops), "---");
1202 gtk_entry_set_text(GTK_ENTRY(ge->eta.cw_bw), "---");
1203 gtk_entry_set_text(GTK_ENTRY(ge->eta.cw_iops), "---");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001204#endif
1205
1206 if (je->eta_sec != INT_MAX && je->nr_running) {
1207 char *iops_str[2];
1208 char *rate_str[2];
1209
1210 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1211 strcpy(output, "-.-% done");
1212 else {
1213 eta_good = 1;
1214 perc *= 100.0;
1215 sprintf(output, "%3.1f%% done", perc);
1216 }
1217
1218 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1219 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1220
1221 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1222 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1223
Jens Axboe2f99deb2012-03-09 14:37:29 +01001224 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), rate_str[0]);
1225 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), iops_str[0]);
1226 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), rate_str[1]);
1227 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), iops_str[1]);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001228
Jens Axboe2f99deb2012-03-09 14:37:29 +01001229 graph_add_xy_data(ge->graphs.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1230 graph_add_xy_data(ge->graphs.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1231 graph_add_xy_data(ge->graphs.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1232 graph_add_xy_data(ge->graphs.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
1233
1234 free(rate_str[0]);
1235 free(rate_str[1]);
1236 free(iops_str[0]);
1237 free(iops_str[1]);
1238 }
1239
1240 if (eta_str[0]) {
1241 char *dst = output + strlen(output);
1242
1243 sprintf(dst, " - %s", eta_str);
1244 }
1245
Jens Axboe9988ca72012-03-09 15:14:06 +01001246 gfio_update_thread_status(ge, output, perc);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001247 gdk_threads_leave();
1248}
1249
1250/*
1251 * Update ETA in main window for all clients
1252 */
1253static void gfio_update_all_eta(struct jobs_eta *je)
1254{
1255 struct gui *ui = &main_ui;
1256 static int eta_good;
1257 char eta_str[128];
1258 char output[256];
1259 double perc = 0.0;
1260 int i2p = 0;
1261
1262 gdk_threads_enter();
1263
1264 eta_str[0] = '\0';
1265 output[0] = '\0';
1266
1267 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1268 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1269 eta_to_str(eta_str, je->eta_sec);
1270 }
1271
1272#if 0
1273 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1274 if (je->m_rate || je->t_rate) {
1275 char *tr, *mr;
1276
1277 mr = num2str(je->m_rate, 4, 0, i2p);
1278 tr = num2str(je->t_rate, 4, 0, i2p);
1279 gtk_entry_set_text(GTK_ENTRY(ui->eta);
1280 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1281 free(tr);
1282 free(mr);
1283 } else if (je->m_iops || je->t_iops)
1284 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
1285
1286 gtk_entry_set_text(GTK_ENTRY(ui->eta.cr_bw), "---");
1287 gtk_entry_set_text(GTK_ENTRY(ui->eta.cr_iops), "---");
1288 gtk_entry_set_text(GTK_ENTRY(ui->eta.cw_bw), "---");
1289 gtk_entry_set_text(GTK_ENTRY(ui->eta.cw_iops), "---");
1290#endif
1291
Jens Axboe3863d1a2012-03-09 17:39:05 +01001292 entry_set_int_value(ui->eta.jobs, je->nr_running);
1293
Jens Axboe2f99deb2012-03-09 14:37:29 +01001294 if (je->eta_sec != INT_MAX && je->nr_running) {
1295 char *iops_str[2];
1296 char *rate_str[2];
1297
1298 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1299 strcpy(output, "-.-% done");
1300 else {
1301 eta_good = 1;
1302 perc *= 100.0;
1303 sprintf(output, "%3.1f%% done", perc);
1304 }
1305
1306 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1307 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1308
1309 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1310 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1311
1312 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), rate_str[0]);
1313 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), iops_str[0]);
1314 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), rate_str[1]);
1315 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), iops_str[1]);
1316
1317 graph_add_xy_data(ui->graphs.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1318 graph_add_xy_data(ui->graphs.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1319 graph_add_xy_data(ui->graphs.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1320 graph_add_xy_data(ui->graphs.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001321
Jens Axboe3e47bd22012-02-29 13:45:02 +01001322 free(rate_str[0]);
1323 free(rate_str[1]);
1324 free(iops_str[0]);
1325 free(iops_str[1]);
1326 }
1327
1328 if (eta_str[0]) {
1329 char *dst = output + strlen(output);
1330
1331 sprintf(dst, " - %s", eta_str);
1332 }
1333
Jens Axboe9988ca72012-03-09 15:14:06 +01001334 gfio_update_thread_status_all(output, perc);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001335 gdk_threads_leave();
Jens Axboe3e47bd22012-02-29 13:45:02 +01001336}
1337
Stephen M. Camerona1820202012-02-24 08:17:31 +01001338static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1339{
Jens Axboe843ad232012-02-29 11:44:53 +01001340 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001341 struct gfio_client *gc = client->client_data;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001342 struct gui_entry *ge = gc->ge;
Jens Axboe843ad232012-02-29 11:44:53 +01001343 const char *os, *arch;
1344 char buf[64];
1345
1346 os = fio_get_os_string(probe->os);
1347 if (!os)
1348 os = "unknown";
1349
1350 arch = fio_get_arch_string(probe->arch);
1351 if (!arch)
1352 os = "unknown";
1353
1354 if (!client->name)
1355 client->name = strdup((char *) probe->hostname);
1356
Jens Axboe0050e5f2012-03-06 09:23:27 +01001357 gdk_threads_enter();
1358
Jens Axboe2f99deb2012-03-09 14:37:29 +01001359 gtk_label_set_text(GTK_LABEL(ge->probe.hostname), (char *) probe->hostname);
1360 gtk_label_set_text(GTK_LABEL(ge->probe.os), os);
1361 gtk_label_set_text(GTK_LABEL(ge->probe.arch), arch);
Jens Axboe843ad232012-02-29 11:44:53 +01001362 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001363 gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), buf);
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001364
Jens Axboe2f99deb2012-03-09 14:37:29 +01001365 gfio_set_connected(ge, 1);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001366
1367 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001368}
1369
Jens Axboe9988ca72012-03-09 15:14:06 +01001370static void gfio_update_thread_status(struct gui_entry *ge,
1371 char *status_message, double perc)
1372{
1373 static char message[100];
1374 const char *m = message;
1375
1376 strncpy(message, status_message, sizeof(message) - 1);
1377 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), m);
1378 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), perc / 100.0);
1379 gtk_widget_queue_draw(main_ui.window);
1380}
1381
1382static void gfio_update_thread_status_all(char *status_message, double perc)
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001383{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001384 struct gui *ui = &main_ui;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001385 static char message[100];
1386 const char *m = message;
1387
1388 strncpy(message, status_message, sizeof(message) - 1);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001389 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), m);
1390 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), perc / 100.0);
1391 gtk_widget_queue_draw(ui->window);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001392}
1393
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001394static void gfio_quit_op(struct fio_client *client)
1395{
Jens Axboee0681f32012-03-06 12:14:42 +01001396 struct gfio_client *gc = client->client_data;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001397
Jens Axboe0050e5f2012-03-06 09:23:27 +01001398 gdk_threads_enter();
Jens Axboe2f99deb2012-03-09 14:37:29 +01001399 gfio_set_connected(gc->ge, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001400 gdk_threads_leave();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001401}
1402
Jens Axboe807f9972012-03-02 10:25:24 +01001403static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1404{
1405 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +01001406 struct gfio_client *gc = client->client_data;
Jens Axboedcaeb602012-03-08 19:45:37 +01001407 struct thread_options *o = &gc->o;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001408 struct gui_entry *ge = gc->ge;
Jens Axboe807f9972012-03-02 10:25:24 +01001409 char tmp[8];
Jens Axboe807f9972012-03-02 10:25:24 +01001410
Jens Axboedcaeb602012-03-08 19:45:37 +01001411 convert_thread_options_to_cpu(o, &p->top);
Jens Axboe807f9972012-03-02 10:25:24 +01001412
Jens Axboe0050e5f2012-03-06 09:23:27 +01001413 gdk_threads_enter();
1414
Jens Axboe2f99deb2012-03-09 14:37:29 +01001415 gtk_label_set_text(GTK_LABEL(ge->page_label), (gchar *) o->name);
1416
Jens Axboe3863d1a2012-03-09 17:39:05 +01001417 gtk_combo_box_append_text(GTK_COMBO_BOX(ge->eta.names), (gchar *) o->name);
1418 gtk_combo_box_set_active(GTK_COMBO_BOX(ge->eta.names), 0);
1419
Jens Axboe2f99deb2012-03-09 14:37:29 +01001420 gtk_entry_set_text(GTK_ENTRY(ge->eta.iotype), ddir_str(o->td_ddir));
1421 gtk_entry_set_text(GTK_ENTRY(ge->eta.ioengine), (gchar *) o->ioengine);
Jens Axboe807f9972012-03-02 10:25:24 +01001422
Jens Axboedcaeb602012-03-08 19:45:37 +01001423 sprintf(tmp, "%u", o->iodepth);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001424 gtk_entry_set_text(GTK_ENTRY(ge->eta.iodepth), tmp);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001425
Jens Axboedcaeb602012-03-08 19:45:37 +01001426 gc->job_added++;
1427
Jens Axboe0050e5f2012-03-06 09:23:27 +01001428 gdk_threads_leave();
Jens Axboe807f9972012-03-02 10:25:24 +01001429}
1430
Jens Axboeed727a42012-03-02 12:14:40 +01001431static void gfio_client_timed_out(struct fio_client *client)
1432{
Jens Axboee0681f32012-03-06 12:14:42 +01001433 struct gfio_client *gc = client->client_data;
Jens Axboeed727a42012-03-02 12:14:40 +01001434 GtkWidget *dialog, *label, *content;
1435 char buf[256];
1436
1437 gdk_threads_enter();
1438
Jens Axboe2f99deb2012-03-09 14:37:29 +01001439 gfio_set_connected(gc->ge, 0);
1440 clear_ge_ui_info(gc->ge);
Jens Axboeed727a42012-03-02 12:14:40 +01001441
1442 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
1443
1444 dialog = gtk_dialog_new_with_buttons("Timed out!",
Jens Axboe2f99deb2012-03-09 14:37:29 +01001445 GTK_WINDOW(main_ui.window),
Jens Axboeed727a42012-03-02 12:14:40 +01001446 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1447 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1448
Jens Axboef1299092012-03-07 20:00:02 +01001449 /* gtk_dialog_get_content_area() is 2.14 and newer */
1450 content = GTK_DIALOG(dialog)->vbox;
1451
Jens Axboeed727a42012-03-02 12:14:40 +01001452 label = gtk_label_new((const gchar *) buf);
1453 gtk_container_add(GTK_CONTAINER(content), label);
1454 gtk_widget_show_all(dialog);
1455 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1456
1457 gtk_dialog_run(GTK_DIALOG(dialog));
1458 gtk_widget_destroy(dialog);
1459
1460 gdk_threads_leave();
1461}
1462
Jens Axboe6b79c802012-03-08 10:51:36 +01001463static void gfio_client_stop(struct fio_client *client, struct fio_net_cmd *cmd)
1464{
1465 struct gfio_client *gc = client->client_data;
1466
1467 gdk_threads_enter();
1468
Jens Axboe2f99deb2012-03-09 14:37:29 +01001469 gfio_set_connected(gc->ge, 0);
Jens Axboe6b79c802012-03-08 10:51:36 +01001470
1471 if (gc->err_entry)
1472 entry_set_int_value(gc->err_entry, client->error);
1473
1474 gdk_threads_leave();
1475}
1476
Stephen M. Camerona1820202012-02-24 08:17:31 +01001477struct client_ops gfio_client_ops = {
Jens Axboe0420ba62012-02-29 11:16:52 +01001478 .text_op = gfio_text_op,
1479 .disk_util = gfio_disk_util_op,
1480 .thread_status = gfio_thread_status_op,
1481 .group_stats = gfio_group_stats_op,
Jens Axboe2f99deb2012-03-09 14:37:29 +01001482 .jobs_eta = gfio_update_client_eta,
1483 .eta = gfio_update_all_eta,
Jens Axboe0420ba62012-02-29 11:16:52 +01001484 .probe = gfio_probe_op,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001485 .quit = gfio_quit_op,
Jens Axboe807f9972012-03-02 10:25:24 +01001486 .add_job = gfio_add_job_op,
Jens Axboeed727a42012-03-02 12:14:40 +01001487 .timed_out = gfio_client_timed_out,
Jens Axboe6b79c802012-03-08 10:51:36 +01001488 .stop = gfio_client_stop,
Jens Axboe6433ee02012-03-09 20:10:51 +01001489 .eta_msec = FIO_CLIENT_DEF_ETA_MSEC,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001490 .stay_connected = 1,
Stephen M. Camerona1820202012-02-24 08:17:31 +01001491};
1492
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001493static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1494 __attribute__((unused)) gpointer data)
1495{
1496 gtk_main_quit();
1497}
1498
Stephen M. Cameron25927252012-02-24 08:17:31 +01001499static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001500{
Jens Axboea9eccde2012-03-09 14:59:42 +01001501 struct gui *ui = arg;
1502
1503 ui->handler_running = 1;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001504 fio_handle_clients(&gfio_client_ops);
Jens Axboea9eccde2012-03-09 14:59:42 +01001505 ui->handler_running = 0;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001506 return NULL;
1507}
1508
Jens Axboe2f99deb2012-03-09 14:37:29 +01001509static int send_job_files(struct gui_entry *ge)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001510{
Jens Axboe9988ca72012-03-09 15:14:06 +01001511 struct gfio_client *gc = ge->client;
Jens Axboe441013b2012-03-01 08:01:52 +01001512 int i, ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001513
Jens Axboe2f99deb2012-03-09 14:37:29 +01001514 for (i = 0; i < ge->nr_job_files; i++) {
Jens Axboe9988ca72012-03-09 15:14:06 +01001515 ret = fio_client_send_ini(gc->client, ge->job_files[i]);
Jens Axboec7249262012-03-09 17:11:04 +01001516 if (ret < 0) {
1517 GError *error;
1518
1519 error = g_error_new(g_quark_from_string("fio"), 1, "Failed to send file %s: %s\n", ge->job_files[i], strerror(-ret));
1520 report_error(error);
1521 g_error_free(error);
1522 break;
1523 } else if (ret)
Jens Axboe441013b2012-03-01 08:01:52 +01001524 break;
1525
Jens Axboe2f99deb2012-03-09 14:37:29 +01001526 free(ge->job_files[i]);
1527 ge->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001528 }
Jens Axboe2f99deb2012-03-09 14:37:29 +01001529 while (i < ge->nr_job_files) {
1530 free(ge->job_files[i]);
1531 ge->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001532 i++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001533 }
1534
Jens Axboe441013b2012-03-01 08:01:52 +01001535 return ret;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001536}
1537
Jens Axboe63a130b2012-03-06 20:08:59 +01001538static void *server_thread(void *arg)
1539{
1540 is_backend = 1;
1541 gfio_server_running = 1;
1542 fio_start_server(NULL);
1543 gfio_server_running = 0;
1544 return NULL;
1545}
1546
Jens Axboe2f99deb2012-03-09 14:37:29 +01001547static void gfio_start_server(void)
Jens Axboe63a130b2012-03-06 20:08:59 +01001548{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001549 struct gui *ui = &main_ui;
1550
Jens Axboe63a130b2012-03-06 20:08:59 +01001551 if (!gfio_server_running) {
1552 gfio_server_running = 1;
1553 pthread_create(&ui->server_t, NULL, server_thread, NULL);
Jens Axboee34f6ad2012-03-06 20:47:15 +01001554 pthread_detach(ui->server_t);
Jens Axboe63a130b2012-03-06 20:08:59 +01001555 }
1556}
1557
Stephen M. Cameron25927252012-02-24 08:17:31 +01001558static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1559 gpointer data)
1560{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001561 struct gui_entry *ge = data;
1562 struct gfio_client *gc = ge->client;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001563
Jens Axboe2f99deb2012-03-09 14:37:29 +01001564 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 0);
1565 fio_start_client(gc->client);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001566}
1567
Jens Axboedf06f222012-03-02 13:32:04 +01001568static void file_open(GtkWidget *w, gpointer data);
1569
1570static void connect_clicked(GtkWidget *widget, gpointer data)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001571{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001572 struct gui_entry *ge = data;
1573 struct gfio_client *gc = ge->client;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001574
Jens Axboe2f99deb2012-03-09 14:37:29 +01001575 if (!ge->connected) {
Jens Axboec7249262012-03-09 17:11:04 +01001576 int ret;
1577
Jens Axboe2f99deb2012-03-09 14:37:29 +01001578 if (!ge->nr_job_files)
Jens Axboedf06f222012-03-02 13:32:04 +01001579 file_open(widget, data);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001580 if (!ge->nr_job_files)
1581 return;
1582
1583 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No jobs running");
1584 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
Jens Axboec7249262012-03-09 17:11:04 +01001585 ret = fio_client_connect(gc->client);
1586 if (!ret) {
Jens Axboea9eccde2012-03-09 14:59:42 +01001587 if (!ge->ui->handler_running)
1588 pthread_create(&ge->ui->t, NULL, job_thread, ge->ui);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001589 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 0);
1590 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 1);
Jens Axboec7249262012-03-09 17:11:04 +01001591 } else {
1592 GError *error;
1593
1594 error = g_error_new(g_quark_from_string("fio"), 1, "Failed to connect to %s: %s\n", ge->client->client->hostname, strerror(-ret));
1595 report_error(error);
1596 g_error_free(error);
Jens Axboe69406b92012-03-06 14:00:42 +01001597 }
Jens Axboedf06f222012-03-02 13:32:04 +01001598 } else {
Jens Axboe2f99deb2012-03-09 14:37:29 +01001599 fio_client_terminate(gc->client);
1600 gfio_set_connected(ge, 0);
1601 clear_ge_ui_info(ge);
Jens Axboedf06f222012-03-02 13:32:04 +01001602 }
Jens Axboe3e47bd22012-02-29 13:45:02 +01001603}
1604
Jens Axboeb9d2f302012-03-08 20:36:28 +01001605static void send_clicked(GtkWidget *widget, gpointer data)
1606{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001607 struct gui_entry *ge = data;
Jens Axboeb9d2f302012-03-08 20:36:28 +01001608
Jens Axboe2f99deb2012-03-09 14:37:29 +01001609 if (send_job_files(ge)) {
Jens Axboec7249262012-03-09 17:11:04 +01001610 GError *error;
1611
1612 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);
1613 report_error(error);
1614 g_error_free(error);
1615
Jens Axboe2f99deb2012-03-09 14:37:29 +01001616 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 1);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001617 }
1618
Jens Axboe2f99deb2012-03-09 14:37:29 +01001619 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 0);
1620 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 1);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001621}
1622
Jens Axboe2f99deb2012-03-09 14:37:29 +01001623static GtkWidget *add_button(GtkWidget *buttonbox,
1624 struct button_spec *buttonspec, gpointer data)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001625{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001626 GtkWidget *button = gtk_button_new_with_label(buttonspec->buttontext);
1627
1628 g_signal_connect(button, "clicked", G_CALLBACK(buttonspec->f), data);
1629 gtk_box_pack_start(GTK_BOX(buttonbox), button, FALSE, FALSE, 3);
1630 gtk_widget_set_tooltip_text(button, buttonspec->tooltiptext);
1631 gtk_widget_set_sensitive(button, !buttonspec->start_insensitive);
1632
1633 return button;
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001634}
1635
Jens Axboe2f99deb2012-03-09 14:37:29 +01001636static void add_buttons(struct gui_entry *ge, struct button_spec *buttonlist,
1637 int nbuttons)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001638{
1639 int i;
1640
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001641 for (i = 0; i < nbuttons; i++)
Jens Axboe2f99deb2012-03-09 14:37:29 +01001642 ge->button[i] = add_button(ge->buttonbox, &buttonlist[i], ge);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001643}
1644
Jens Axboe0420ba62012-02-29 11:16:52 +01001645static void on_info_bar_response(GtkWidget *widget, gint response,
1646 gpointer data)
1647{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001648 struct gui *ui = &main_ui;
1649
Jens Axboe0420ba62012-02-29 11:16:52 +01001650 if (response == GTK_RESPONSE_OK) {
1651 gtk_widget_destroy(widget);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001652 ui->error_info_bar = NULL;
Jens Axboe0420ba62012-02-29 11:16:52 +01001653 }
1654}
1655
Jens Axboedf06f222012-03-02 13:32:04 +01001656void report_error(GError *error)
Jens Axboe0420ba62012-02-29 11:16:52 +01001657{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001658 struct gui *ui = &main_ui;
1659
1660 if (ui->error_info_bar == NULL) {
1661 ui->error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
Jens Axboe0420ba62012-02-29 11:16:52 +01001662 GTK_RESPONSE_OK,
1663 NULL);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001664 g_signal_connect(ui->error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1665 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui->error_info_bar),
Jens Axboe0420ba62012-02-29 11:16:52 +01001666 GTK_MESSAGE_ERROR);
1667
Jens Axboe2f99deb2012-03-09 14:37:29 +01001668 ui->error_label = gtk_label_new(error->message);
1669 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui->error_info_bar));
1670 gtk_container_add(GTK_CONTAINER(container), ui->error_label);
Jens Axboe0420ba62012-02-29 11:16:52 +01001671
Jens Axboe2f99deb2012-03-09 14:37:29 +01001672 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->error_info_bar, FALSE, FALSE, 0);
1673 gtk_widget_show_all(ui->vbox);
Jens Axboe0420ba62012-02-29 11:16:52 +01001674 } else {
1675 char buffer[256];
1676 snprintf(buffer, sizeof(buffer), "Failed to open file.");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001677 gtk_label_set(GTK_LABEL(ui->error_label), buffer);
Jens Axboe0420ba62012-02-29 11:16:52 +01001678 }
1679}
1680
Jens Axboe62bc9372012-03-07 11:45:07 +01001681struct connection_widgets
1682{
1683 GtkWidget *hentry;
1684 GtkWidget *combo;
1685 GtkWidget *button;
1686};
1687
1688static void hostname_cb(GtkEntry *entry, gpointer data)
1689{
1690 struct connection_widgets *cw = data;
1691 int uses_net = 0, is_localhost = 0;
1692 const gchar *text;
1693 gchar *ctext;
1694
1695 /*
1696 * Check whether to display the 'auto start backend' box
1697 * or not. Show it if we are a localhost and using network,
1698 * or using a socket.
1699 */
1700 ctext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->combo));
1701 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
1702 uses_net = 1;
1703 g_free(ctext);
1704
1705 if (uses_net) {
1706 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
1707 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
1708 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
1709 !strcmp(text, "ip6-loopback"))
1710 is_localhost = 1;
1711 }
1712
1713 if (!uses_net || is_localhost) {
1714 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
1715 gtk_widget_set_sensitive(cw->button, 1);
1716 } else {
1717 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
1718 gtk_widget_set_sensitive(cw->button, 0);
1719 }
1720}
1721
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001722static int get_connection_details(char **host, int *port, int *type,
1723 int *server_start)
Jens Axboea7a42ce2012-03-02 13:12:04 +01001724{
Jens Axboe62bc9372012-03-07 11:45:07 +01001725 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
1726 struct connection_widgets cw;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001727 char *typeentry;
1728
1729 dialog = gtk_dialog_new_with_buttons("Connection details",
Jens Axboe2f99deb2012-03-09 14:37:29 +01001730 GTK_WINDOW(main_ui.window),
Jens Axboea7a42ce2012-03-02 13:12:04 +01001731 GTK_DIALOG_DESTROY_WITH_PARENT,
1732 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1733 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1734
1735 frame = gtk_frame_new("Hostname / socket name");
Jens Axboef1299092012-03-07 20:00:02 +01001736 /* gtk_dialog_get_content_area() is 2.14 and newer */
1737 vbox = GTK_DIALOG(dialog)->vbox;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001738 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1739
1740 box = gtk_vbox_new(FALSE, 6);
1741 gtk_container_add(GTK_CONTAINER(frame), box);
1742
1743 hbox = gtk_hbox_new(TRUE, 10);
1744 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe62bc9372012-03-07 11:45:07 +01001745 cw.hentry = gtk_entry_new();
1746 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
1747 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001748
1749 frame = gtk_frame_new("Port");
1750 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1751 box = gtk_vbox_new(FALSE, 10);
1752 gtk_container_add(GTK_CONTAINER(frame), box);
1753
1754 hbox = gtk_hbox_new(TRUE, 4);
1755 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1756 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1757
1758 frame = gtk_frame_new("Type");
1759 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1760 box = gtk_vbox_new(FALSE, 10);
1761 gtk_container_add(GTK_CONTAINER(frame), box);
1762
1763 hbox = gtk_hbox_new(TRUE, 4);
1764 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1765
Jens Axboe62bc9372012-03-07 11:45:07 +01001766 cw.combo = gtk_combo_box_new_text();
1767 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv4");
1768 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv6");
1769 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "local socket");
1770 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001771
Jens Axboe62bc9372012-03-07 11:45:07 +01001772 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001773
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001774 frame = gtk_frame_new("Options");
1775 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1776 box = gtk_vbox_new(FALSE, 10);
1777 gtk_container_add(GTK_CONTAINER(frame), box);
1778
1779 hbox = gtk_hbox_new(TRUE, 4);
1780 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1781
Jens Axboe62bc9372012-03-07 11:45:07 +01001782 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1783 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
1784 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.");
1785 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
1786
1787 /*
1788 * Connect edit signal, so we can show/not-show the auto start button
1789 */
1790 g_signal_connect(GTK_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
1791 g_signal_connect(GTK_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001792
Jens Axboea7a42ce2012-03-02 13:12:04 +01001793 gtk_widget_show_all(dialog);
1794
1795 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1796 gtk_widget_destroy(dialog);
1797 return 1;
1798 }
1799
Jens Axboe62bc9372012-03-07 11:45:07 +01001800 *host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001801 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1802
Jens Axboe62bc9372012-03-07 11:45:07 +01001803 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw.combo));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001804 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1805 *type = Fio_client_ipv4;
1806 else if (!strncmp(typeentry, "IPv6", 4))
1807 *type = Fio_client_ipv6;
1808 else
1809 *type = Fio_client_socket;
1810 g_free(typeentry);
1811
Jens Axboe62bc9372012-03-07 11:45:07 +01001812 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001813
Jens Axboea7a42ce2012-03-02 13:12:04 +01001814 gtk_widget_destroy(dialog);
1815 return 0;
1816}
1817
Jens Axboe2f99deb2012-03-09 14:37:29 +01001818static void gfio_client_added(struct gui_entry *ge, struct fio_client *client)
Jens Axboee0681f32012-03-06 12:14:42 +01001819{
1820 struct gfio_client *gc;
1821
1822 gc = malloc(sizeof(*gc));
1823 memset(gc, 0, sizeof(*gc));
Jens Axboe2f99deb2012-03-09 14:37:29 +01001824 gc->ge = ge;
Jens Axboe343cb4a2012-03-09 17:16:51 +01001825 gc->client = fio_get_client(client);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001826
Jens Axboe2f99deb2012-03-09 14:37:29 +01001827 ge->client = gc;
Jens Axboee0681f32012-03-06 12:14:42 +01001828
1829 client->client_data = gc;
1830}
1831
Jens Axboe2f99deb2012-03-09 14:37:29 +01001832static GtkWidget *new_client_page(struct gui_entry *ge);
1833
1834static struct gui_entry *alloc_new_gui_entry(struct gui *ui)
1835{
1836 struct gui_entry *ge;
1837
1838 ge = malloc(sizeof(*ge));
1839 memset(ge, 0, sizeof(*ge));
1840 INIT_FLIST_HEAD(&ge->list);
1841 flist_add_tail(&ge->list, &ui->list);
1842 ge->ui = ui;
1843 return ge;
1844}
1845
1846/*
1847 * FIXME: need more handling here
1848 */
1849static void ge_destroy(GtkWidget *w, gpointer data)
1850{
1851 struct gui_entry *ge = data;
Jens Axboe343cb4a2012-03-09 17:16:51 +01001852 struct gfio_client *gc = ge->client;
1853
1854 if (gc->client)
1855 fio_put_client(gc->client);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001856
1857 flist_del(&ge->list);
1858 free(ge);
1859}
1860
1861static struct gui_entry *get_new_ge_with_tab(const char *name)
1862{
1863 struct gui_entry *ge;
1864
1865 ge = alloc_new_gui_entry(&main_ui);
1866
1867 ge->vbox = new_client_page(ge);
1868 g_signal_connect(ge->vbox, "destroy", G_CALLBACK(ge_destroy), ge);
1869
1870 ge->page_label = gtk_label_new(name);
1871 ge->page_num = gtk_notebook_append_page(GTK_NOTEBOOK(main_ui.notebook), ge->vbox, ge->page_label);
1872
1873 gtk_widget_show_all(main_ui.window);
1874 return ge;
1875}
1876
1877static void file_new(GtkWidget *w, gpointer data)
1878{
1879 get_new_ge_with_tab("Untitled");
1880}
1881
1882/*
1883 * Return the 'ge' corresponding to the tab. If the active tab is the
1884 * main tab, open a new tab.
1885 */
1886static struct gui_entry *get_ge_from_page(unsigned int cur_page)
1887{
1888 struct flist_head *entry;
1889 struct gui_entry *ge;
1890
1891 if (!cur_page)
1892 return get_new_ge_with_tab("Untitled");
1893
1894 flist_for_each(entry, &main_ui.list) {
1895 ge = flist_entry(entry, struct gui_entry, list);
1896 if (ge->page_num == cur_page)
1897 return ge;
1898 }
1899
1900 return NULL;
1901}
1902
Jens Axboe0420ba62012-02-29 11:16:52 +01001903static void file_open(GtkWidget *w, gpointer data)
1904{
Jens Axboe63a130b2012-03-06 20:08:59 +01001905 struct gui *ui = data;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001906 GtkWidget *dialog;
Jens Axboe0420ba62012-02-29 11:16:52 +01001907 GSList *filenames, *fn_glist;
1908 GtkFileFilter *filter;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001909 char *host;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001910 int port, type, server_start;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001911 struct gui_entry *ge;
1912 gint cur_page;
1913
1914 /*
1915 * Creates new tab if current tab is the main window, or the
1916 * current tab already has a client.
1917 */
1918 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
1919 ge = get_ge_from_page(cur_page);
1920 if (ge->client)
1921 ge = get_new_ge_with_tab("Untitled");
1922
1923 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
Jens Axboe0420ba62012-02-29 11:16:52 +01001924
1925 dialog = gtk_file_chooser_dialog_new("Open File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001926 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001927 GTK_FILE_CHOOSER_ACTION_OPEN,
1928 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1929 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1930 NULL);
1931 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1932
1933 filter = gtk_file_filter_new();
1934 gtk_file_filter_add_pattern(filter, "*.fio");
1935 gtk_file_filter_add_pattern(filter, "*.job");
Jens Axboe2d262992012-03-07 08:19:30 +01001936 gtk_file_filter_add_pattern(filter, "*.ini");
Jens Axboe0420ba62012-02-29 11:16:52 +01001937 gtk_file_filter_add_mime_type(filter, "text/fio");
1938 gtk_file_filter_set_name(filter, "Fio job file");
1939 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
1940
1941 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1942 gtk_widget_destroy(dialog);
1943 return;
1944 }
1945
1946 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001947
1948 gtk_widget_destroy(dialog);
1949
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001950 if (get_connection_details(&host, &port, &type, &server_start))
Jens Axboea7a42ce2012-03-02 13:12:04 +01001951 goto err;
1952
Jens Axboe0420ba62012-02-29 11:16:52 +01001953 filenames = fn_glist;
1954 while (filenames != NULL) {
Jens Axboee0681f32012-03-06 12:14:42 +01001955 struct fio_client *client;
1956
Jens Axboe2f99deb2012-03-09 14:37:29 +01001957 ge->job_files = realloc(ge->job_files, (ge->nr_job_files + 1) * sizeof(char *));
1958 ge->job_files[ge->nr_job_files] = strdup(filenames->data);
1959 ge->nr_job_files++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001960
Jens Axboee0681f32012-03-06 12:14:42 +01001961 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
1962 if (!client) {
Jens Axboedf06f222012-03-02 13:32:04 +01001963 GError *error;
1964
1965 error = g_error_new(g_quark_from_string("fio"), 1,
1966 "Failed to add client %s", host);
Jens Axboe0420ba62012-02-29 11:16:52 +01001967 report_error(error);
1968 g_error_free(error);
Jens Axboe0420ba62012-02-29 11:16:52 +01001969 }
Jens Axboe2f99deb2012-03-09 14:37:29 +01001970 gfio_client_added(ge, client);
Jens Axboe0420ba62012-02-29 11:16:52 +01001971
1972 g_free(filenames->data);
1973 filenames = g_slist_next(filenames);
1974 }
Jens Axboea7a42ce2012-03-02 13:12:04 +01001975 free(host);
Jens Axboe63a130b2012-03-06 20:08:59 +01001976
1977 if (server_start)
Jens Axboe2f99deb2012-03-09 14:37:29 +01001978 gfio_start_server();
Jens Axboea7a42ce2012-03-02 13:12:04 +01001979err:
Jens Axboe0420ba62012-02-29 11:16:52 +01001980 g_slist_free(fn_glist);
Jens Axboe0420ba62012-02-29 11:16:52 +01001981}
1982
1983static void file_save(GtkWidget *w, gpointer data)
1984{
Jens Axboe63a130b2012-03-06 20:08:59 +01001985 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01001986 GtkWidget *dialog;
1987
1988 dialog = gtk_file_chooser_dialog_new("Save File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001989 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001990 GTK_FILE_CHOOSER_ACTION_SAVE,
1991 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1992 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1993 NULL);
1994
1995 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1996 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
1997
1998 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1999 char *filename;
2000
2001 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
2002 // save_job_file(filename);
2003 g_free(filename);
2004 }
2005 gtk_widget_destroy(dialog);
2006}
2007
Jens Axboe9b260bd2012-03-06 11:02:52 +01002008static void view_log_destroy(GtkWidget *w, gpointer data)
2009{
2010 struct gui *ui = (struct gui *) data;
2011
2012 gtk_widget_ref(ui->log_tree);
2013 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
2014 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +01002015 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +01002016}
2017
2018static void view_log(GtkWidget *w, gpointer data)
2019{
Jens Axboe4cbe7212012-03-06 13:36:17 +01002020 GtkWidget *win, *scroll, *vbox, *box;
2021 struct gui *ui = (struct gui *) data;
Jens Axboe9b260bd2012-03-06 11:02:52 +01002022
Jens Axboe4cbe7212012-03-06 13:36:17 +01002023 if (ui->log_view)
2024 return;
2025
2026 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002027 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +01002028 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002029
Jens Axboe4cbe7212012-03-06 13:36:17 +01002030 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002031
Jens Axboe4cbe7212012-03-06 13:36:17 +01002032 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
2033
2034 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2035
2036 box = gtk_hbox_new(TRUE, 0);
2037 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
2038 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
2039 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
2040
2041 vbox = gtk_vbox_new(TRUE, 5);
2042 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
2043
2044 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002045 gtk_widget_show_all(win);
2046}
2047
Jens Axboe8577f4f2012-03-09 19:28:27 +01002048static void __update_graph_limits(struct gfio_graphs *g)
2049{
2050 line_graph_set_data_count_limit(g->iops_graph, gfio_graph_limit);
2051 line_graph_set_data_count_limit(g->bandwidth_graph, gfio_graph_limit);
2052}
2053
2054static void update_graph_limits(void)
2055{
2056 struct flist_head *entry;
2057 struct gui_entry *ge;
2058
2059 __update_graph_limits(&main_ui.graphs);
2060
2061 flist_for_each(entry, &main_ui.list) {
2062 ge = flist_entry(entry, struct gui_entry, list);
2063 __update_graph_limits(&ge->graphs);
2064 }
2065}
2066
Jens Axboe46974a72012-03-02 19:34:13 +01002067static void preferences(GtkWidget *w, gpointer data)
2068{
Jens Axboef3e84402012-03-07 13:14:32 +01002069 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002070 GtkWidget *hbox, *spin, *entry, *spin_int;
Jens Axboe46974a72012-03-02 19:34:13 +01002071 int i;
2072
2073 dialog = gtk_dialog_new_with_buttons("Preferences",
Jens Axboe2f99deb2012-03-09 14:37:29 +01002074 GTK_WINDOW(main_ui.window),
Jens Axboe46974a72012-03-02 19:34:13 +01002075 GTK_DIALOG_DESTROY_WITH_PARENT,
2076 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2077 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2078 NULL);
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
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002085 hbox = gtk_hbox_new(FALSE, 5);
2086 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
2087 entry = gtk_label_new("Font face to use for graph labels");
2088 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 5);
2089
Jens Axboef3e84402012-03-07 13:14:32 +01002090 font = gtk_font_button_new();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002091 gtk_box_pack_start(GTK_BOX(hbox), font, FALSE, FALSE, 5);
Jens Axboef3e84402012-03-07 13:14:32 +01002092
Jens Axboe8577f4f2012-03-09 19:28:27 +01002093 box = gtk_vbox_new(FALSE, 6);
2094 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
2095
2096 hbox = gtk_hbox_new(FALSE, 5);
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002097 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
Jens Axboe8577f4f2012-03-09 19:28:27 +01002098 entry = gtk_label_new("Maximum number of data points in graph (seconds)");
2099 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
2100
2101 spin = create_spinbutton(hbox, 10, 1000000, 100);
2102
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002103 box = gtk_vbox_new(FALSE, 6);
2104 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
2105
2106 hbox = gtk_hbox_new(FALSE, 5);
2107 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
2108 entry = gtk_label_new("Client ETA request interval (msec)");
2109 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
2110
2111 spin_int = create_spinbutton(hbox, 100, 100000, gfio_client_ops.eta_msec);
Jens Axboea31d9fa2012-03-09 20:23:05 +01002112 frame = gtk_frame_new("Debug logging");
2113 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
2114 vbox = gtk_vbox_new(FALSE, 6);
2115 gtk_container_add(GTK_CONTAINER(frame), vbox);
2116
2117 box = gtk_hbox_new(FALSE, 6);
2118 gtk_container_add(GTK_CONTAINER(vbox), box);
2119
2120 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
2121
2122 for (i = 0; i < FD_DEBUG_MAX; i++) {
2123 if (i == 7) {
2124 box = gtk_hbox_new(FALSE, 6);
2125 gtk_container_add(GTK_CONTAINER(vbox), box);
2126 }
2127
2128
2129 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
2130 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
2131 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
2132 }
2133
Jens Axboe46974a72012-03-02 19:34:13 +01002134 gtk_widget_show_all(dialog);
2135
2136 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
2137 gtk_widget_destroy(dialog);
2138 return;
2139 }
2140
2141 for (i = 0; i < FD_DEBUG_MAX; i++) {
2142 int set;
2143
2144 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
2145 if (set)
2146 fio_debug |= (1UL << i);
2147 }
2148
Jens Axboef3e84402012-03-07 13:14:32 +01002149 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
Jens Axboe8577f4f2012-03-09 19:28:27 +01002150 gfio_graph_limit = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
2151 update_graph_limits();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002152 gfio_client_ops.eta_msec = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_int));
Jens Axboe8577f4f2012-03-09 19:28:27 +01002153
Jens Axboe46974a72012-03-02 19:34:13 +01002154 gtk_widget_destroy(dialog);
2155}
2156
Jens Axboe0420ba62012-02-29 11:16:52 +01002157static void about_dialog(GtkWidget *w, gpointer data)
2158{
Jens Axboe81e4ea62012-03-07 14:18:28 +01002159 const char *authors[] = {
2160 "Jens Axboe <axboe@kernel.dk>",
2161 "Stephen Carmeron <stephenmcameron@gmail.com>",
2162 NULL
2163 };
Jens Axboe84a72ed2012-03-07 14:24:57 +01002164 const char *license[] = {
2165 "Fio is free software; you can redistribute it and/or modify "
2166 "it under the terms of the GNU General Public License as published by "
2167 "the Free Software Foundation; either version 2 of the License, or "
2168 "(at your option) any later version.\n",
2169 "Fio is distributed in the hope that it will be useful, "
2170 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
2171 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
2172 "GNU General Public License for more details.\n",
2173 "You should have received a copy of the GNU General Public License "
2174 "along with Fio; if not, write to the Free Software Foundation, Inc., "
2175 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
2176 };
2177 char *license_trans;
2178
2179 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
2180 license[2], "\n", NULL);
Jens Axboe81e4ea62012-03-07 14:18:28 +01002181
Jens Axboe0420ba62012-02-29 11:16:52 +01002182 gtk_show_about_dialog(NULL,
2183 "program-name", "gfio",
2184 "comments", "Gtk2 UI for fio",
Jens Axboe84a72ed2012-03-07 14:24:57 +01002185 "license", license_trans,
Jens Axboe81e4ea62012-03-07 14:18:28 +01002186 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
2187 "authors", authors,
Jens Axboe0420ba62012-02-29 11:16:52 +01002188 "version", fio_version_string,
Jens Axboe81e4ea62012-03-07 14:18:28 +01002189 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
Jens Axboe0420ba62012-02-29 11:16:52 +01002190 "logo-icon-name", "fio",
2191 /* Must be last: */
Jens Axboe81e4ea62012-03-07 14:18:28 +01002192 "wrap-license", TRUE,
Jens Axboe0420ba62012-02-29 11:16:52 +01002193 NULL);
Jens Axboe84a72ed2012-03-07 14:24:57 +01002194
Jens Axboe2f99deb2012-03-09 14:37:29 +01002195 g_free(license_trans);
Jens Axboe0420ba62012-02-29 11:16:52 +01002196}
2197
2198static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01002199 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01002200 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01002201 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
Jens Axboe2f99deb2012-03-09 14:37:29 +01002202 { "NewFile", GTK_STOCK_NEW, "New", "<Control>N", NULL, G_CALLBACK(file_new) },
Jens Axboe46974a72012-03-02 19:34:13 +01002203 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
2204 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
2205 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01002206 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe46974a72012-03-02 19:34:13 +01002207 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
2208 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01002209};
Jens Axboe3e47bd22012-02-29 13:45:02 +01002210static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01002211
2212static const gchar *ui_string = " \
2213 <ui> \
2214 <menubar name=\"MainMenu\"> \
2215 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01002216 <menuitem name=\"New\" action=\"NewFile\" /> \
2217 <separator name=\"Separator1\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01002218 <menuitem name=\"Open\" action=\"OpenFile\" /> \
2219 <menuitem name=\"Save\" action=\"SaveFile\" /> \
Jens Axboe46974a72012-03-02 19:34:13 +01002220 <separator name=\"Separator2\"/> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01002221 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
2222 <separator name=\"Separator3\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01002223 <menuitem name=\"Quit\" action=\"Quit\" /> \
2224 </menu> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01002225 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
2226 <menuitem name=\"Log\" action=\"ViewLog\" /> \
2227 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01002228 <menu name=\"Help\" action=\"HelpMenuAction\"> \
2229 <menuitem name=\"About\" action=\"About\" /> \
2230 </menu> \
2231 </menubar> \
2232 </ui> \
2233";
2234
Jens Axboe4cbe7212012-03-06 13:36:17 +01002235static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
2236 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01002237{
2238 GtkActionGroup *action_group = gtk_action_group_new("Menu");
2239 GError *error = 0;
2240
2241 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01002242 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01002243
2244 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
2245 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
2246
2247 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
2248 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
2249}
2250
2251void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
2252 GtkWidget *vbox, GtkUIManager *ui_manager)
2253{
2254 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
2255}
2256
Jens Axboe2f99deb2012-03-09 14:37:29 +01002257static GtkWidget *new_client_page(struct gui_entry *ge)
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002258{
Jens Axboe2f99deb2012-03-09 14:37:29 +01002259 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01002260 GdkColor white;
Jens Axboe0420ba62012-02-29 11:16:52 +01002261
Jens Axboe2f99deb2012-03-09 14:37:29 +01002262 main_vbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01002263
Jens Axboe2f99deb2012-03-09 14:37:29 +01002264 ge->topalign = gtk_alignment_new(0, 0, 1, 0);
2265 ge->topvbox = gtk_vbox_new(FALSE, 3);
2266 gtk_container_add(GTK_CONTAINER(ge->topalign), ge->topvbox);
2267 gtk_box_pack_start(GTK_BOX(main_vbox), ge->topalign, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002268
Jens Axboe3e47bd22012-02-29 13:45:02 +01002269 probe = gtk_frame_new("Job");
Jens Axboe2f99deb2012-03-09 14:37:29 +01002270 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01002271 probe_frame = gtk_vbox_new(FALSE, 3);
2272 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
2273
2274 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002275 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2276 ge->probe.hostname = new_info_label_in_frame(probe_box, "Host");
2277 ge->probe.os = new_info_label_in_frame(probe_box, "OS");
2278 ge->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
2279 ge->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
Jens Axboe843ad232012-02-29 11:44:53 +01002280
Jens Axboe3e47bd22012-02-29 13:45:02 +01002281 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002282 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2283
Jens Axboe3863d1a2012-03-09 17:39:05 +01002284 ge->eta.names = new_combo_entry_in_frame(probe_box, "Jobs");
Jens Axboe2f99deb2012-03-09 14:37:29 +01002285 ge->eta.iotype = new_info_entry_in_frame(probe_box, "IO");
2286 ge->eta.ioengine = new_info_entry_in_frame(probe_box, "IO Engine");
2287 ge->eta.iodepth = new_info_entry_in_frame(probe_box, "IO Depth");
2288 ge->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
2289 ge->eta.files = new_info_entry_in_frame(probe_box, "Open files");
2290
2291 probe_box = gtk_hbox_new(FALSE, 3);
2292 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2293 ge->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
2294 ge->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
2295 ge->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
2296 ge->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
2297
2298 /*
2299 * Only add this if we have a commit rate
2300 */
2301#if 0
2302 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe3e47bd22012-02-29 13:45:02 +01002303 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01002304
Jens Axboe2f99deb2012-03-09 14:37:29 +01002305 ge->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
2306 ge->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2307
2308 ge->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
2309 ge->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2310#endif
2311
2312 /*
2313 * Set up a drawing area and IOPS and bandwidth graphs
2314 */
2315 gdk_color_parse("white", &white);
2316 ge->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01002317 gtk_widget_set_size_request(GTK_WIDGET(ge->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01002318 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002319 gtk_widget_modify_bg(ge->graphs.drawing_area, GTK_STATE_NORMAL, &white);
2320 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "expose_event",
2321 G_CALLBACK(on_expose_drawing_area), &ge->graphs);
2322 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "configure_event",
2323 G_CALLBACK(on_config_drawing_area), &ge->graphs);
2324 ge->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2325 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ge->scrolled_window),
2326 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2327 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ge->scrolled_window),
2328 ge->graphs.drawing_area);
2329 gtk_box_pack_start(GTK_BOX(main_vbox), ge->scrolled_window,
2330 TRUE, TRUE, 0);
2331
2332 setup_graphs(&ge->graphs);
2333
2334 /*
2335 * Set up alignments for widgets at the bottom of ui,
2336 * align bottom left, expand horizontally but not vertically
2337 */
2338 ge->bottomalign = gtk_alignment_new(0, 1, 1, 0);
2339 ge->buttonbox = gtk_hbox_new(FALSE, 0);
2340 gtk_container_add(GTK_CONTAINER(ge->bottomalign), ge->buttonbox);
2341 gtk_box_pack_start(GTK_BOX(main_vbox), ge->bottomalign,
2342 FALSE, FALSE, 0);
2343
2344 add_buttons(ge, buttonspeclist, ARRAYSIZE(buttonspeclist));
2345
2346 /*
2347 * Set up thread status progress bar
2348 */
2349 ge->thread_status_pb = gtk_progress_bar_new();
2350 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
2351 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No connections");
2352 gtk_container_add(GTK_CONTAINER(ge->buttonbox), ge->thread_status_pb);
2353
2354
2355 return main_vbox;
2356}
2357
2358static GtkWidget *new_main_page(struct gui *ui)
2359{
2360 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
2361 GdkColor white;
2362
2363 main_vbox = gtk_vbox_new(FALSE, 3);
2364
2365 /*
2366 * Set up alignments for widgets at the top of ui,
2367 * align top left, expand horizontally but not vertically
2368 */
2369 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
2370 ui->topvbox = gtk_vbox_new(FALSE, 0);
2371 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
2372 gtk_box_pack_start(GTK_BOX(main_vbox), ui->topalign, FALSE, FALSE, 0);
2373
2374 probe = gtk_frame_new("Run statistics");
2375 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
2376 probe_frame = gtk_vbox_new(FALSE, 3);
2377 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
Jens Axboe3e47bd22012-02-29 13:45:02 +01002378
2379 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002380 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
Jens Axboe3863d1a2012-03-09 17:39:05 +01002381 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Running");
Jens Axboeca850992012-03-05 20:04:43 +01002382 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
2383 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
2384 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
2385 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01002386
2387 /*
2388 * Only add this if we have a commit rate
2389 */
2390#if 0
2391 probe_box = gtk_hbox_new(FALSE, 3);
2392 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
2393
Jens Axboe3e47bd22012-02-29 13:45:02 +01002394 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
2395 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2396
Jens Axboe3e47bd22012-02-29 13:45:02 +01002397 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
2398 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01002399#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01002400
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01002401 /*
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002402 * Set up a drawing area and IOPS and bandwidth graphs
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002403 */
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01002404 gdk_color_parse("white", &white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002405 ui->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01002406 gtk_widget_set_size_request(GTK_WIDGET(ui->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01002407 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002408 gtk_widget_modify_bg(ui->graphs.drawing_area, GTK_STATE_NORMAL, &white);
2409 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "expose_event",
2410 G_CALLBACK(on_expose_drawing_area), &ui->graphs);
2411 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "configure_event",
2412 G_CALLBACK(on_config_drawing_area), &ui->graphs);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002413 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2414 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
2415 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002416 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ui->scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01002417 ui->graphs.drawing_area);
2418 gtk_box_pack_start(GTK_BOX(main_vbox), ui->scrolled_window,
Stephen M. Camerone1645342012-02-24 08:17:32 +01002419 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002420
Jens Axboe2f99deb2012-03-09 14:37:29 +01002421 setup_graphs(&ui->graphs);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002422
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002423 /*
2424 * Set up alignments for widgets at the bottom of ui,
2425 * align bottom left, expand horizontally but not vertically
2426 */
2427 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
2428 ui->buttonbox = gtk_hbox_new(FALSE, 0);
2429 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002430 gtk_box_pack_start(GTK_BOX(main_vbox), ui->bottomalign,
Stephen M. Camerone1645342012-02-24 08:17:32 +01002431 FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002432
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002433 /*
2434 * Set up thread status progress bar
2435 */
2436 ui->thread_status_pb = gtk_progress_bar_new();
2437 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01002438 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002439 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
2440
Jens Axboe2f99deb2012-03-09 14:37:29 +01002441 return main_vbox;
2442}
2443
2444static gboolean notebook_switch_page(GtkNotebook *notebook, GtkWidget *widget,
2445 guint page, gpointer data)
2446
2447{
2448 return TRUE;
2449}
2450
2451static void init_ui(int *argc, char **argv[], struct gui *ui)
2452{
2453 GtkSettings *settings;
2454 GtkUIManager *uimanager;
2455 GtkWidget *menu, *vbox;
2456
2457 /* Magical g*thread incantation, you just need this thread stuff.
2458 * Without it, the update that happens in gfio_update_thread_status
2459 * doesn't really happen in a timely fashion, you need expose events
2460 */
2461 if (!g_thread_supported())
2462 g_thread_init(NULL);
2463 gdk_threads_init();
2464
2465 gtk_init(argc, argv);
2466 settings = gtk_settings_get_default();
2467 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
2468 g_type_init();
2469
2470 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2471 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
2472 gtk_window_set_default_size(GTK_WINDOW(ui->window), 1024, 768);
2473
2474 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
2475 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
2476
2477 ui->vbox = gtk_vbox_new(FALSE, 0);
2478 gtk_container_add(GTK_CONTAINER(ui->window), ui->vbox);
2479
2480 uimanager = gtk_ui_manager_new();
2481 menu = get_menubar_menu(ui->window, uimanager, ui);
2482 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
2483
2484 ui->notebook = gtk_notebook_new();
2485 g_signal_connect(ui->notebook, "switch-page", G_CALLBACK(notebook_switch_page), ui);
Jens Axboeb870c312012-03-09 17:22:01 +01002486 gtk_notebook_set_scrollable(GTK_NOTEBOOK(ui->notebook), 1);
Jens Axboe0aa928c2012-03-09 17:24:07 +01002487 gtk_notebook_popup_enable(GTK_NOTEBOOK(ui->notebook));
Jens Axboe2f99deb2012-03-09 14:37:29 +01002488 gtk_container_add(GTK_CONTAINER(ui->vbox), ui->notebook);
2489
2490 vbox = new_main_page(ui);
2491
2492 gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), vbox, gtk_label_new("Main"));
2493
Jens Axboe9b260bd2012-03-06 11:02:52 +01002494 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002495
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002496 gtk_widget_show_all(ui->window);
2497}
2498
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002499int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002500{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002501 if (initialize_fio(envp))
2502 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01002503 if (fio_init_options())
2504 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01002505
Jens Axboe2f99deb2012-03-09 14:37:29 +01002506 memset(&main_ui, 0, sizeof(main_ui));
2507 INIT_FLIST_HEAD(&main_ui.list);
2508
2509 init_ui(&argc, &argv, &main_ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01002510
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002511 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002512 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002513 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002514 return 0;
2515}