blob: 4bf8fbe9066b0c504a3930e03f4b80cd0b45a691 [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);
Stephen M. Camerondef0ac22012-03-12 07:32:57 +0100203 graph_add_extra_space(g, 0.005, 0.005, 0.03, 0.03);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100204 return g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100205}
206
Stephen M. Cameronf0af9f82012-03-11 11:35:50 +0100207static void bandwidth_graph_y_axis_unit_change(struct graph *g, int power_of_ten)
208{
209 switch (power_of_ten) {
210 case 9: graph_y_title(g, "Petabytes / sec");
211 break;
212 case 6: graph_y_title(g, "Gigabytes / sec");
213 break;
214 case 3: graph_y_title(g, "Megabytes / sec");
215 break;
216 case 0:
217 default: graph_y_title(g, "Kilobytes / sec");
218 break;
219 }
220}
221
Jens Axboe2f99deb2012-03-09 14:37:29 +0100222static struct graph *setup_bandwidth_graph(void)
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100223{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100224 struct graph *g;
225
226 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
227 graph_title(g, "Bandwidth");
228 graph_x_title(g, "Time (secs)");
229 graph_y_title(g, "Kbytes / sec");
230 graph_add_label(g, "Read Bandwidth");
231 graph_add_label(g, "Write Bandwidth");
232 graph_set_color(g, "Read Bandwidth", 0.13, 0.54, 0.13);
233 graph_set_color(g, "Write Bandwidth", 1.0, 0.0, 0.0);
234 line_graph_set_data_count_limit(g, 100);
Stephen M. Cameronf0af9f82012-03-11 11:35:50 +0100235 graph_y_axis_unit_change_notify(g, bandwidth_graph_y_axis_unit_change);
Stephen M. Camerondef0ac22012-03-12 07:32:57 +0100236 graph_add_extra_space(g, 0.005, 0.005, 0.03, 0.03);
237
Jens Axboe2f99deb2012-03-09 14:37:29 +0100238 return g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100239}
240
Jens Axboe2f99deb2012-03-09 14:37:29 +0100241static void setup_graphs(struct gfio_graphs *g)
Jens Axboe8663ea62012-03-02 14:04:30 +0100242{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100243 g->iops_graph = setup_iops_graph();
244 g->bandwidth_graph = setup_bandwidth_graph();
245}
246
247static void clear_ge_ui_info(struct gui_entry *ge)
248{
249 gtk_label_set_text(GTK_LABEL(ge->probe.hostname), "");
250 gtk_label_set_text(GTK_LABEL(ge->probe.os), "");
251 gtk_label_set_text(GTK_LABEL(ge->probe.arch), "");
252 gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100253#if 0
254 /* should we empty it... */
Jens Axboe2f99deb2012-03-09 14:37:29 +0100255 gtk_entry_set_text(GTK_ENTRY(ge->eta.name), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100256#endif
Jens Axboe2f99deb2012-03-09 14:37:29 +0100257 gtk_entry_set_text(GTK_ENTRY(ge->eta.iotype), "");
258 gtk_entry_set_text(GTK_ENTRY(ge->eta.ioengine), "");
259 gtk_entry_set_text(GTK_ENTRY(ge->eta.iodepth), "");
260 gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), "");
261 gtk_entry_set_text(GTK_ENTRY(ge->eta.files), "");
262 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), "");
263 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), "");
264 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), "");
265 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100266}
267
Jens Axboe3863d1a2012-03-09 17:39:05 +0100268static GtkWidget *new_combo_entry_in_frame(GtkWidget *box, const char *label)
269{
270 GtkWidget *entry, *frame;
271
272 frame = gtk_frame_new(label);
273 entry = gtk_combo_box_new_text();
274 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
275 gtk_container_add(GTK_CONTAINER(frame), entry);
276
277 return entry;
278}
279
Jens Axboe3650a3c2012-03-05 14:09:03 +0100280static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
281{
282 GtkWidget *entry, *frame;
283
284 frame = gtk_frame_new(label);
285 entry = gtk_entry_new();
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100286 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100287 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
288 gtk_container_add(GTK_CONTAINER(frame), entry);
289
290 return entry;
291}
292
293static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
294{
295 GtkWidget *label_widget;
296 GtkWidget *frame;
297
298 frame = gtk_frame_new(label);
299 label_widget = gtk_label_new(NULL);
300 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
301 gtk_container_add(GTK_CONTAINER(frame), label_widget);
302
303 return label_widget;
304}
305
306static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
307{
308 GtkWidget *button, *box;
309
310 box = gtk_hbox_new(FALSE, 3);
311 gtk_container_add(GTK_CONTAINER(hbox), box);
312
313 button = gtk_spin_button_new_with_range(min, max, 1.0);
314 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
315
316 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
317 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
318
319 return button;
320}
321
Jens Axboe2f99deb2012-03-09 14:37:29 +0100322static void gfio_set_connected(struct gui_entry *ge, int connected)
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100323{
324 if (connected) {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100325 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 1);
326 ge->connected = 1;
327 gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), "Disconnect");
328 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100329 } else {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100330 ge->connected = 0;
331 gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), "Connect");
332 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 0);
333 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 0);
334 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100335 }
336}
337
Jens Axboe3650a3c2012-03-05 14:09:03 +0100338static void label_set_int_value(GtkWidget *entry, unsigned int val)
339{
340 char tmp[80];
341
342 sprintf(tmp, "%u", val);
343 gtk_label_set_text(GTK_LABEL(entry), tmp);
344}
345
346static void entry_set_int_value(GtkWidget *entry, unsigned int val)
347{
348 char tmp[80];
349
350 sprintf(tmp, "%u", val);
351 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
352}
353
Jens Axboea2697902012-03-05 16:43:49 +0100354#define ALIGN_LEFT 1
355#define ALIGN_RIGHT 2
356#define INVISIBLE 4
357#define UNSORTABLE 8
358
359GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
360{
361 GtkCellRenderer *renderer;
362 GtkTreeViewColumn *col;
363 double xalign = 0.0; /* left as default */
364 PangoAlignment align;
365 gboolean visible;
366
367 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
368 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
369 PANGO_ALIGN_CENTER;
370 visible = !(flags & INVISIBLE);
371
372 renderer = gtk_cell_renderer_text_new();
373 col = gtk_tree_view_column_new();
374
375 gtk_tree_view_column_set_title(col, title);
376 if (!(flags & UNSORTABLE))
377 gtk_tree_view_column_set_sort_column_id(col, index);
378 gtk_tree_view_column_set_resizable(col, TRUE);
379 gtk_tree_view_column_pack_start(col, renderer, TRUE);
380 gtk_tree_view_column_add_attribute(col, renderer, "text", index);
381 gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
382 switch (align) {
383 case PANGO_ALIGN_LEFT:
384 xalign = 0.0;
385 break;
386 case PANGO_ALIGN_CENTER:
387 xalign = 0.5;
388 break;
389 case PANGO_ALIGN_RIGHT:
390 xalign = 1.0;
391 break;
392 }
393 gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
394 gtk_tree_view_column_set_visible(col, visible);
395 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
396 return col;
397}
398
Jens Axboe9b260bd2012-03-06 11:02:52 +0100399static void gfio_ui_setup_log(struct gui *ui)
400{
401 GtkTreeSelection *selection;
402 GtkListStore *model;
403 GtkWidget *tree_view;
404
405 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
406
407 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
408 gtk_widget_set_can_focus(tree_view, FALSE);
409
410 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
411 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
Jens Axboe661f7412012-03-06 13:55:45 +0100412 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
413 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100414
415 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
416 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
417 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
Jens Axboef095d562012-03-06 13:49:12 +0100418 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100419
420 ui->log_model = model;
421 ui->log_tree = tree_view;
422}
423
Jens Axboea2697902012-03-05 16:43:49 +0100424static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
425 fio_fp64_t *plist,
426 unsigned int len,
427 const char *base,
428 unsigned int scale)
429{
430 GType types[FIO_IO_U_LIST_MAX_LEN];
431 GtkWidget *tree_view;
432 GtkTreeSelection *selection;
433 GtkListStore *model;
434 GtkTreeIter iter;
435 int i;
436
437 for (i = 0; i < len; i++)
438 types[i] = G_TYPE_INT;
439
440 model = gtk_list_store_newv(len, types);
441
442 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
443 gtk_widget_set_can_focus(tree_view, FALSE);
444
Jens Axboe661f7412012-03-06 13:55:45 +0100445 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
446 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
447
Jens Axboea2697902012-03-05 16:43:49 +0100448 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
449 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
450
451 for (i = 0; i < len; i++) {
452 char fbuf[8];
453
454 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
455 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
456 }
457
458 gtk_list_store_append(model, &iter);
459
Jens Axboee0681f32012-03-06 12:14:42 +0100460 for (i = 0; i < len; i++) {
461 if (scale)
462 ovals[i] = (ovals[i] + 999) / 1000;
Jens Axboea2697902012-03-05 16:43:49 +0100463 gtk_list_store_set(model, &iter, i, ovals[i], -1);
Jens Axboee0681f32012-03-06 12:14:42 +0100464 }
Jens Axboea2697902012-03-05 16:43:49 +0100465
466 return tree_view;
467}
468
469static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
470 int ddir)
471{
472 unsigned int *io_u_plat = ts->io_u_plat[ddir];
473 unsigned long nr = ts->clat_stat[ddir].samples;
474 fio_fp64_t *plist = ts->percentile_list;
475 unsigned int *ovals, len, minv, maxv, scale_down;
476 const char *base;
477 GtkWidget *tree_view, *frame, *hbox;
478 char tmp[64];
479
480 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
481 if (!len)
482 goto out;
483
484 /*
485 * We default to usecs, but if the value range is such that we
486 * should scale down to msecs, do that.
487 */
488 if (minv > 2000 && maxv > 99999) {
489 scale_down = 1;
490 base = "msec";
491 } else {
492 scale_down = 0;
493 base = "usec";
494 }
495
496 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
497
498 sprintf(tmp, "Completion percentiles (%s)", base);
499 frame = gtk_frame_new(tmp);
500 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
501
502 hbox = gtk_hbox_new(FALSE, 3);
503 gtk_container_add(GTK_CONTAINER(frame), hbox);
504
505 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
506out:
507 if (ovals)
508 free(ovals);
509}
510
Jens Axboe3650a3c2012-03-05 14:09:03 +0100511static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
512 unsigned long max, double mean, double dev)
513{
514 const char *base = "(usec)";
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100515 GtkWidget *hbox, *label, *frame;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100516 char *minp, *maxp;
517 char tmp[64];
518
519 if (!usec_to_msec(&min, &max, &mean, &dev))
520 base = "(msec)";
521
522 minp = num2str(min, 6, 1, 0);
523 maxp = num2str(max, 6, 1, 0);
524
Jens Axboe3650a3c2012-03-05 14:09:03 +0100525 sprintf(tmp, "%s %s", name, base);
526 frame = gtk_frame_new(tmp);
527 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
528
Jens Axboe3650a3c2012-03-05 14:09:03 +0100529 hbox = gtk_hbox_new(FALSE, 3);
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100530 gtk_container_add(GTK_CONTAINER(frame), hbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100531
532 label = new_info_label_in_frame(hbox, "Minimum");
533 gtk_label_set_text(GTK_LABEL(label), minp);
534 label = new_info_label_in_frame(hbox, "Maximum");
535 gtk_label_set_text(GTK_LABEL(label), maxp);
536 label = new_info_label_in_frame(hbox, "Average");
537 sprintf(tmp, "%5.02f", mean);
538 gtk_label_set_text(GTK_LABEL(label), tmp);
539 label = new_info_label_in_frame(hbox, "Standard deviation");
540 sprintf(tmp, "%5.02f", dev);
541 gtk_label_set_text(GTK_LABEL(label), tmp);
542
543 free(minp);
544 free(maxp);
545
546}
547
Jens Axboeca850992012-03-05 20:04:43 +0100548#define GFIO_CLAT 1
549#define GFIO_SLAT 2
550#define GFIO_LAT 4
551
Jens Axboe3650a3c2012-03-05 14:09:03 +0100552static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
553 struct thread_stat *ts, int ddir)
554{
555 const char *ddir_label[2] = { "Read", "Write" };
Jens Axboe0b761302012-03-05 20:44:11 +0100556 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
Jens Axboee0681f32012-03-06 12:14:42 +0100557 unsigned long min[3], max[3], runt;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100558 unsigned long long bw, iops;
Jens Axboeca850992012-03-05 20:04:43 +0100559 unsigned int flags = 0;
Jens Axboee0681f32012-03-06 12:14:42 +0100560 double mean[3], dev[3];
Jens Axboe3650a3c2012-03-05 14:09:03 +0100561 char *io_p, *bw_p, *iops_p;
562 int i2p;
563
564 if (!ts->runtime[ddir])
565 return;
566
567 i2p = is_power_of_2(rs->kb_base);
568 runt = ts->runtime[ddir];
569
570 bw = (1000 * ts->io_bytes[ddir]) / runt;
571 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
572 bw_p = num2str(bw, 6, 1, i2p);
573
574 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
575 iops_p = num2str(iops, 6, 1, 0);
576
577 box = gtk_hbox_new(FALSE, 3);
578 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
579
580 frame = gtk_frame_new(ddir_label[ddir]);
581 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
582
Jens Axboe0b761302012-03-05 20:44:11 +0100583 main_vbox = gtk_vbox_new(FALSE, 3);
584 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100585
586 box = gtk_hbox_new(FALSE, 3);
Jens Axboe0b761302012-03-05 20:44:11 +0100587 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100588
589 label = new_info_label_in_frame(box, "IO");
590 gtk_label_set_text(GTK_LABEL(label), io_p);
591 label = new_info_label_in_frame(box, "Bandwidth");
592 gtk_label_set_text(GTK_LABEL(label), bw_p);
593 label = new_info_label_in_frame(box, "IOPS");
594 gtk_label_set_text(GTK_LABEL(label), iops_p);
595 label = new_info_label_in_frame(box, "Runtime (msec)");
596 label_set_int_value(label, ts->runtime[ddir]);
597
Jens Axboee0681f32012-03-06 12:14:42 +0100598 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
Jens Axboeca850992012-03-05 20:04:43 +0100599 double p_of_agg = 100.0;
600 const char *bw_str = "KB";
601 char tmp[32];
602
603 if (rs->agg[ddir]) {
Jens Axboee0681f32012-03-06 12:14:42 +0100604 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
Jens Axboeca850992012-03-05 20:04:43 +0100605 if (p_of_agg > 100.0)
606 p_of_agg = 100.0;
607 }
608
Jens Axboee0681f32012-03-06 12:14:42 +0100609 if (mean[0] > 999999.9) {
610 min[0] /= 1000.0;
611 max[0] /= 1000.0;
612 mean[0] /= 1000.0;
613 dev[0] /= 1000.0;
Jens Axboeca850992012-03-05 20:04:43 +0100614 bw_str = "MB";
615 }
616
Jens Axboe0b761302012-03-05 20:44:11 +0100617 sprintf(tmp, "Bandwidth (%s)", bw_str);
618 frame = gtk_frame_new(tmp);
619 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
Jens Axboeca850992012-03-05 20:04:43 +0100620
Jens Axboe0b761302012-03-05 20:44:11 +0100621 box = gtk_hbox_new(FALSE, 3);
622 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboeca850992012-03-05 20:04:43 +0100623
Jens Axboe0b761302012-03-05 20:44:11 +0100624 label = new_info_label_in_frame(box, "Minimum");
Jens Axboee0681f32012-03-06 12:14:42 +0100625 label_set_int_value(label, min[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100626 label = new_info_label_in_frame(box, "Maximum");
Jens Axboee0681f32012-03-06 12:14:42 +0100627 label_set_int_value(label, max[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100628 label = new_info_label_in_frame(box, "Percentage of jobs");
Jens Axboeca850992012-03-05 20:04:43 +0100629 sprintf(tmp, "%3.2f%%", p_of_agg);
630 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100631 label = new_info_label_in_frame(box, "Average");
Jens Axboee0681f32012-03-06 12:14:42 +0100632 sprintf(tmp, "%5.02f", mean[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100633 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100634 label = new_info_label_in_frame(box, "Standard deviation");
Jens Axboee0681f32012-03-06 12:14:42 +0100635 sprintf(tmp, "%5.02f", dev[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100636 gtk_label_set_text(GTK_LABEL(label), tmp);
637 }
638
Jens Axboee0681f32012-03-06 12:14:42 +0100639 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
Jens Axboe2b089892012-03-06 08:09:17 +0100640 flags |= GFIO_SLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100641 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
Jens Axboe2b089892012-03-06 08:09:17 +0100642 flags |= GFIO_CLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100643 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
Jens Axboe2b089892012-03-06 08:09:17 +0100644 flags |= GFIO_LAT;
645
646 if (flags) {
647 frame = gtk_frame_new("Latency");
648 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
649
650 vbox = gtk_vbox_new(FALSE, 3);
651 gtk_container_add(GTK_CONTAINER(frame), vbox);
652
653 if (flags & GFIO_SLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100654 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
Jens Axboe2b089892012-03-06 08:09:17 +0100655 if (flags & GFIO_CLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100656 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
Jens Axboe2b089892012-03-06 08:09:17 +0100657 if (flags & GFIO_LAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100658 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
Jens Axboe2b089892012-03-06 08:09:17 +0100659 }
660
661 if (ts->clat_percentiles)
662 gfio_show_clat_percentiles(main_vbox, ts, ddir);
663
664
Jens Axboe3650a3c2012-03-05 14:09:03 +0100665 free(io_p);
666 free(bw_p);
667 free(iops_p);
668}
669
Jens Axboee5bd1342012-03-05 21:38:12 +0100670static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
671 const char **labels)
672{
673 GtkWidget *tree_view;
674 GtkTreeSelection *selection;
675 GtkListStore *model;
676 GtkTreeIter iter;
677 GType *types;
678 int i, skipped;
679
680 /*
681 * Check if all are empty, in which case don't bother
682 */
683 for (i = 0, skipped = 0; i < num; i++)
684 if (lat[i] <= 0.0)
685 skipped++;
686
687 if (skipped == num)
688 return NULL;
689
690 types = malloc(num * sizeof(GType));
691
692 for (i = 0; i < num; i++)
693 types[i] = G_TYPE_STRING;
694
695 model = gtk_list_store_newv(num, types);
696 free(types);
697 types = NULL;
698
699 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
700 gtk_widget_set_can_focus(tree_view, FALSE);
701
Jens Axboe661f7412012-03-06 13:55:45 +0100702 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
703 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
704
Jens Axboee5bd1342012-03-05 21:38:12 +0100705 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
706 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
707
708 for (i = 0; i < num; i++)
709 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
710
711 gtk_list_store_append(model, &iter);
712
713 for (i = 0; i < num; i++) {
714 char fbuf[32];
715
716 if (lat[i] <= 0.0)
717 sprintf(fbuf, "0.00");
718 else
719 sprintf(fbuf, "%3.2f%%", lat[i]);
720
721 gtk_list_store_set(model, &iter, i, fbuf, -1);
722 }
723
724 return tree_view;
725}
726
727static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
728{
729 GtkWidget *box, *frame, *tree_view;
730 double io_u_lat_u[FIO_IO_U_LAT_U_NR];
731 double io_u_lat_m[FIO_IO_U_LAT_M_NR];
732 const char *uranges[] = { "2", "4", "10", "20", "50", "100",
733 "250", "500", "750", "1000", };
734 const char *mranges[] = { "2", "4", "10", "20", "50", "100",
735 "250", "500", "750", "1000", "2000",
736 ">= 2000", };
737
738 stat_calc_lat_u(ts, io_u_lat_u);
739 stat_calc_lat_m(ts, io_u_lat_m);
740
741 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
742 if (tree_view) {
743 frame = gtk_frame_new("Latency buckets (usec)");
744 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
745
746 box = gtk_hbox_new(FALSE, 3);
747 gtk_container_add(GTK_CONTAINER(frame), box);
748 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
749 }
750
751 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
752 if (tree_view) {
753 frame = gtk_frame_new("Latency buckets (msec)");
754 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
755
756 box = gtk_hbox_new(FALSE, 3);
757 gtk_container_add(GTK_CONTAINER(frame), box);
758 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
759 }
760}
761
Jens Axboe2e331012012-03-05 22:07:54 +0100762static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
763{
764 GtkWidget *box, *frame, *entry;
765 double usr_cpu, sys_cpu;
766 unsigned long runtime;
767 char tmp[32];
768
769 runtime = ts->total_run_time;
770 if (runtime) {
771 double runt = (double) runtime;
772
773 usr_cpu = (double) ts->usr_time * 100 / runt;
774 sys_cpu = (double) ts->sys_time * 100 / runt;
775 } else {
776 usr_cpu = 0;
777 sys_cpu = 0;
778 }
779
780 frame = gtk_frame_new("OS resources");
781 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
782
783 box = gtk_hbox_new(FALSE, 3);
784 gtk_container_add(GTK_CONTAINER(frame), box);
785
786 entry = new_info_entry_in_frame(box, "User CPU");
787 sprintf(tmp, "%3.2f%%", usr_cpu);
788 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
789 entry = new_info_entry_in_frame(box, "System CPU");
790 sprintf(tmp, "%3.2f%%", sys_cpu);
791 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
792 entry = new_info_entry_in_frame(box, "Context switches");
793 entry_set_int_value(entry, ts->ctx);
794 entry = new_info_entry_in_frame(box, "Major faults");
795 entry_set_int_value(entry, ts->majf);
796 entry = new_info_entry_in_frame(box, "Minor faults");
797 entry_set_int_value(entry, ts->minf);
798}
Jens Axboe19998db2012-03-06 09:17:59 +0100799static void gfio_add_sc_depths_tree(GtkListStore *model,
800 struct thread_stat *ts, unsigned int len,
801 int submit)
802{
803 double io_u_dist[FIO_IO_U_MAP_NR];
804 GtkTreeIter iter;
805 /* Bits 0, and 3-8 */
806 const int add_mask = 0x1f9;
807 int i, j;
808
809 if (submit)
810 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
811 else
812 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
813
814 gtk_list_store_append(model, &iter);
815
816 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
817
818 for (i = 1, j = 0; i < len; i++) {
819 char fbuf[32];
820
821 if (!(add_mask & (1UL << (i - 1))))
822 sprintf(fbuf, "0.0%%");
823 else {
824 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
825 j++;
826 }
827
828 gtk_list_store_set(model, &iter, i, fbuf, -1);
829 }
830
831}
832
833static void gfio_add_total_depths_tree(GtkListStore *model,
834 struct thread_stat *ts, unsigned int len)
835{
836 double io_u_dist[FIO_IO_U_MAP_NR];
837 GtkTreeIter iter;
838 /* Bits 1-6, and 8 */
839 const int add_mask = 0x17e;
840 int i, j;
841
842 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
843
844 gtk_list_store_append(model, &iter);
845
846 gtk_list_store_set(model, &iter, 0, "Total", -1);
847
848 for (i = 1, j = 0; i < len; i++) {
849 char fbuf[32];
850
851 if (!(add_mask & (1UL << (i - 1))))
852 sprintf(fbuf, "0.0%%");
853 else {
854 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
855 j++;
856 }
857
858 gtk_list_store_set(model, &iter, i, fbuf, -1);
859 }
860
861}
Jens Axboe2e331012012-03-05 22:07:54 +0100862
863static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
864{
Jens Axboe2e331012012-03-05 22:07:54 +0100865 GtkWidget *frame, *box, *tree_view;
866 GtkTreeSelection *selection;
867 GtkListStore *model;
Jens Axboe2e331012012-03-05 22:07:54 +0100868 GType types[FIO_IO_U_MAP_NR + 1];
869 int i;
Jens Axboe19998db2012-03-06 09:17:59 +0100870#define NR_LABELS 10
871 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
Jens Axboe2e331012012-03-05 22:07:54 +0100872
873 frame = gtk_frame_new("IO depths");
874 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
875
876 box = gtk_hbox_new(FALSE, 3);
877 gtk_container_add(GTK_CONTAINER(frame), box);
878
Jens Axboe19998db2012-03-06 09:17:59 +0100879 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100880 types[i] = G_TYPE_STRING;
881
Jens Axboe19998db2012-03-06 09:17:59 +0100882 model = gtk_list_store_newv(NR_LABELS, types);
Jens Axboe2e331012012-03-05 22:07:54 +0100883
884 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
885 gtk_widget_set_can_focus(tree_view, FALSE);
886
Jens Axboe661f7412012-03-06 13:55:45 +0100887 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
888 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
889
Jens Axboe2e331012012-03-05 22:07:54 +0100890 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
891 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
892
Jens Axboe19998db2012-03-06 09:17:59 +0100893 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100894 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
895
Jens Axboe19998db2012-03-06 09:17:59 +0100896 gfio_add_total_depths_tree(model, ts, NR_LABELS);
897 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 1);
898 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 0);
Jens Axboe2e331012012-03-05 22:07:54 +0100899
900 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
901}
902
Jens Axboef9d40b42012-03-06 09:52:49 +0100903static gboolean results_window_delete(GtkWidget *w, gpointer data)
904{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100905 struct gui_entry *ge = (struct gui_entry *) data;
Jens Axboef9d40b42012-03-06 09:52:49 +0100906
907 gtk_widget_destroy(w);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100908 ge->results_window = NULL;
909 ge->results_notebook = NULL;
Jens Axboef9d40b42012-03-06 09:52:49 +0100910 return TRUE;
911}
912
Jens Axboe2f99deb2012-03-09 14:37:29 +0100913static GtkWidget *get_results_window(struct gui_entry *ge)
Jens Axboef9d40b42012-03-06 09:52:49 +0100914{
915 GtkWidget *win, *notebook;
916
Jens Axboe2f99deb2012-03-09 14:37:29 +0100917 if (ge->results_window)
918 return ge->results_notebook;
Jens Axboef9d40b42012-03-06 09:52:49 +0100919
920 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
921 gtk_window_set_title(GTK_WINDOW(win), "Results");
Jens Axboeb01329d2012-03-07 20:31:28 +0100922 gtk_window_set_default_size(GTK_WINDOW(win), 1024, 768);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100923 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ge);
924 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ge);
Jens Axboef9d40b42012-03-06 09:52:49 +0100925
926 notebook = gtk_notebook_new();
Jens Axboe0aa928c2012-03-09 17:24:07 +0100927 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), 1);
928 gtk_notebook_popup_enable(GTK_NOTEBOOK(notebook));
Jens Axboef9d40b42012-03-06 09:52:49 +0100929 gtk_container_add(GTK_CONTAINER(win), notebook);
930
Jens Axboe2f99deb2012-03-09 14:37:29 +0100931 ge->results_window = win;
932 ge->results_notebook = notebook;
933 return ge->results_notebook;
Jens Axboef9d40b42012-03-06 09:52:49 +0100934}
935
Jens Axboe3650a3c2012-03-05 14:09:03 +0100936static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
937 struct group_run_stats *rs)
938{
Jens Axboeb01329d2012-03-07 20:31:28 +0100939 GtkWidget *res_win, *box, *vbox, *entry, *scroll;
Jens Axboee0681f32012-03-06 12:14:42 +0100940 struct gfio_client *gc = client->client_data;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100941
942 gdk_threads_enter();
943
Jens Axboe2f99deb2012-03-09 14:37:29 +0100944 res_win = get_results_window(gc->ge);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100945
Jens Axboeb01329d2012-03-07 20:31:28 +0100946 scroll = gtk_scrolled_window_new(NULL, NULL);
947 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
948 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
949
Jens Axboe3650a3c2012-03-05 14:09:03 +0100950 vbox = gtk_vbox_new(FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100951
Jens Axboeb01329d2012-03-07 20:31:28 +0100952 box = gtk_hbox_new(FALSE, 0);
953 gtk_box_pack_start(GTK_BOX(vbox), box, TRUE, FALSE, 5);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100954
Jens Axboeb01329d2012-03-07 20:31:28 +0100955 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
956
957 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), scroll, gtk_label_new(ts->name));
Jens Axboef9d40b42012-03-06 09:52:49 +0100958
Jens Axboee0681f32012-03-06 12:14:42 +0100959 gc->results_widget = vbox;
960
Jens Axboe3650a3c2012-03-05 14:09:03 +0100961 entry = new_info_entry_in_frame(box, "Name");
962 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
963 if (strlen(ts->description)) {
964 entry = new_info_entry_in_frame(box, "Description");
965 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
966 }
967 entry = new_info_entry_in_frame(box, "Group ID");
968 entry_set_int_value(entry, ts->groupid);
969 entry = new_info_entry_in_frame(box, "Jobs");
970 entry_set_int_value(entry, ts->members);
Jens Axboe6b79c802012-03-08 10:51:36 +0100971 gc->err_entry = entry = new_info_entry_in_frame(box, "Error");
Jens Axboe3650a3c2012-03-05 14:09:03 +0100972 entry_set_int_value(entry, ts->error);
973 entry = new_info_entry_in_frame(box, "PID");
974 entry_set_int_value(entry, ts->pid);
975
976 if (ts->io_bytes[DDIR_READ])
977 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
978 if (ts->io_bytes[DDIR_WRITE])
979 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
980
Jens Axboee5bd1342012-03-05 21:38:12 +0100981 gfio_show_latency_buckets(vbox, ts);
Jens Axboe2e331012012-03-05 22:07:54 +0100982 gfio_show_cpu_usage(vbox, ts);
983 gfio_show_io_depths(vbox, ts);
Jens Axboee5bd1342012-03-05 21:38:12 +0100984
Jens Axboe2f99deb2012-03-09 14:37:29 +0100985 gtk_widget_show_all(gc->ge->results_window);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100986 gdk_threads_leave();
987}
988
Jens Axboe084d1c62012-03-03 20:28:07 +0100989static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100990{
Jens Axboe9b260bd2012-03-06 11:02:52 +0100991 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100992 struct gui *ui = &main_ui;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100993 GtkTreeIter iter;
994 struct tm *tm;
995 time_t sec;
996 char tmp[64], timebuf[80];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100997
Jens Axboe9b260bd2012-03-06 11:02:52 +0100998 sec = p->log_sec;
999 tm = localtime(&sec);
1000 strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", tm);
1001 sprintf(timebuf, "%s.%03ld", tmp, p->log_usec / 1000);
1002
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001003 gdk_threads_enter();
Jens Axboe9b260bd2012-03-06 11:02:52 +01001004
Jens Axboe2f99deb2012-03-09 14:37:29 +01001005 gtk_list_store_append(ui->log_model, &iter);
1006 gtk_list_store_set(ui->log_model, &iter, 0, timebuf, -1);
1007 gtk_list_store_set(ui->log_model, &iter, 1, client->hostname, -1);
1008 gtk_list_store_set(ui->log_model, &iter, 2, p->level, -1);
1009 gtk_list_store_set(ui->log_model, &iter, 3, p->buf, -1);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001010
Jens Axboe6b79c802012-03-08 10:51:36 +01001011 if (p->level == FIO_LOG_ERR)
Jens Axboe2f99deb2012-03-09 14:37:29 +01001012 view_log(NULL, (gpointer) ui);
Jens Axboe6b79c802012-03-08 10:51:36 +01001013
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001014 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001015}
1016
1017static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
1018{
Jens Axboee0681f32012-03-06 12:14:42 +01001019 struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
1020 struct gfio_client *gc = client->client_data;
1021 GtkWidget *box, *frame, *entry, *vbox;
Jens Axboe604cfe32012-03-07 19:51:36 +01001022 double util;
1023 char tmp[16];
Jens Axboee0681f32012-03-06 12:14:42 +01001024
Jens Axboe0050e5f2012-03-06 09:23:27 +01001025 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +01001026
Jens Axboe45dcb2e2012-03-07 16:16:50 +01001027 if (!gc->results_widget)
Jens Axboee0681f32012-03-06 12:14:42 +01001028 goto out;
Jens Axboee0681f32012-03-06 12:14:42 +01001029
1030 if (!gc->disk_util_frame) {
1031 gc->disk_util_frame = gtk_frame_new("Disk utilization");
1032 gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
1033 }
1034
1035 vbox = gtk_vbox_new(FALSE, 3);
1036 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
1037
1038 frame = gtk_frame_new((char *) p->dus.name);
1039 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
1040
1041 box = gtk_vbox_new(FALSE, 3);
1042 gtk_container_add(GTK_CONTAINER(frame), box);
1043
1044 frame = gtk_frame_new("Read");
1045 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1046 vbox = gtk_hbox_new(TRUE, 3);
1047 gtk_container_add(GTK_CONTAINER(frame), vbox);
1048 entry = new_info_entry_in_frame(vbox, "IOs");
1049 entry_set_int_value(entry, p->dus.ios[0]);
1050 entry = new_info_entry_in_frame(vbox, "Merges");
1051 entry_set_int_value(entry, p->dus.merges[0]);
1052 entry = new_info_entry_in_frame(vbox, "Sectors");
1053 entry_set_int_value(entry, p->dus.sectors[0]);
1054 entry = new_info_entry_in_frame(vbox, "Ticks");
1055 entry_set_int_value(entry, p->dus.ticks[0]);
1056
1057 frame = gtk_frame_new("Write");
1058 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1059 vbox = gtk_hbox_new(TRUE, 3);
1060 gtk_container_add(GTK_CONTAINER(frame), vbox);
1061 entry = new_info_entry_in_frame(vbox, "IOs");
1062 entry_set_int_value(entry, p->dus.ios[1]);
1063 entry = new_info_entry_in_frame(vbox, "Merges");
1064 entry_set_int_value(entry, p->dus.merges[1]);
1065 entry = new_info_entry_in_frame(vbox, "Sectors");
1066 entry_set_int_value(entry, p->dus.sectors[1]);
1067 entry = new_info_entry_in_frame(vbox, "Ticks");
1068 entry_set_int_value(entry, p->dus.ticks[1]);
1069
1070 frame = gtk_frame_new("Shared");
1071 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1072 vbox = gtk_hbox_new(TRUE, 3);
1073 gtk_container_add(GTK_CONTAINER(frame), vbox);
1074 entry = new_info_entry_in_frame(vbox, "IO ticks");
1075 entry_set_int_value(entry, p->dus.io_ticks);
1076 entry = new_info_entry_in_frame(vbox, "Time in queue");
1077 entry_set_int_value(entry, p->dus.time_in_queue);
1078
Jens Axboe604cfe32012-03-07 19:51:36 +01001079 util = 0.0;
1080 if (p->dus.msec)
1081 util = (double) 100 * p->dus.io_ticks / (double) p->dus.msec;
1082 if (util > 100.0)
1083 util = 100.0;
1084
1085 sprintf(tmp, "%3.2f%%", util);
1086 entry = new_info_entry_in_frame(vbox, "Disk utilization");
1087 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
1088
Jens Axboee0681f32012-03-06 12:14:42 +01001089 gtk_widget_show_all(gc->results_widget);
1090out:
Jens Axboe0050e5f2012-03-06 09:23:27 +01001091 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001092}
1093
Jens Axboe3650a3c2012-03-05 14:09:03 +01001094extern int sum_stat_clients;
1095extern struct thread_stat client_ts;
1096extern struct group_run_stats client_gs;
1097
1098static int sum_stat_nr;
1099
Jens Axboe89e5fad2012-03-05 09:21:12 +01001100static void gfio_thread_status_op(struct fio_client *client,
1101 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001102{
Jens Axboe3650a3c2012-03-05 14:09:03 +01001103 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
1104
1105 gfio_display_ts(client, &p->ts, &p->rs);
1106
1107 if (sum_stat_clients == 1)
1108 return;
1109
1110 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
1111 sum_group_stats(&client_gs, &p->rs);
1112
1113 client_ts.members++;
1114 client_ts.groupid = p->ts.groupid;
1115
1116 if (++sum_stat_nr == sum_stat_clients) {
1117 strcpy(client_ts.name, "All clients");
1118 gfio_display_ts(client, &client_ts, &client_gs);
1119 }
Stephen M. Camerona1820202012-02-24 08:17:31 +01001120}
1121
Jens Axboe89e5fad2012-03-05 09:21:12 +01001122static void gfio_group_stats_op(struct fio_client *client,
1123 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001124{
Jens Axboe98ceabd2012-03-09 08:53:28 +01001125 /* We're ignoring group stats for now */
Stephen M. Camerona1820202012-02-24 08:17:31 +01001126}
1127
Jens Axboe2f99deb2012-03-09 14:37:29 +01001128static gint on_config_drawing_area(GtkWidget *w, GdkEventConfigure *event,
1129 gpointer data)
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001130{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001131 struct gfio_graphs *g = data;
1132
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001133 graph_set_size(g->iops_graph, w->allocation.width / 2.0, w->allocation.height);
1134 graph_set_position(g->iops_graph, w->allocation.width / 2.0, 0.0);
1135 graph_set_size(g->bandwidth_graph, w->allocation.width / 2.0, w->allocation.height);
1136 graph_set_position(g->bandwidth_graph, 0, 0);
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001137 return TRUE;
1138}
1139
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001140static void draw_graph(struct graph *g, cairo_t *cr)
1141{
1142 line_graph_draw(g, cr);
1143 cairo_stroke(cr);
1144}
1145
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001146static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
1147{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001148 struct gfio_graphs *g = p;
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001149 cairo_t *cr;
1150
1151 cr = gdk_cairo_create(w->window);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001152 cairo_set_source_rgb(cr, 0, 0, 0);
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001153 draw_graph(g->iops_graph, cr);
1154 draw_graph(g->bandwidth_graph, cr);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001155 cairo_destroy(cr);
1156
1157 return FALSE;
1158}
1159
Jens Axboe2f99deb2012-03-09 14:37:29 +01001160/*
1161 * Client specific ETA
1162 */
1163static void gfio_update_client_eta(struct fio_client *client, struct jobs_eta *je)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001164{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001165 struct gfio_client *gc = client->client_data;
1166 struct gui_entry *ge = gc->ge;
Jens Axboe3e47bd22012-02-29 13:45:02 +01001167 static int eta_good;
1168 char eta_str[128];
1169 char output[256];
1170 char tmp[32];
1171 double perc = 0.0;
1172 int i2p = 0;
1173
Jens Axboe0050e5f2012-03-06 09:23:27 +01001174 gdk_threads_enter();
1175
Jens Axboe3e47bd22012-02-29 13:45:02 +01001176 eta_str[0] = '\0';
1177 output[0] = '\0';
1178
1179 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1180 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1181 eta_to_str(eta_str, je->eta_sec);
1182 }
1183
1184 sprintf(tmp, "%u", je->nr_running);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001185 gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001186 sprintf(tmp, "%u", je->files_open);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001187 gtk_entry_set_text(GTK_ENTRY(ge->eta.files), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001188
1189#if 0
1190 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1191 if (je->m_rate || je->t_rate) {
1192 char *tr, *mr;
1193
1194 mr = num2str(je->m_rate, 4, 0, i2p);
1195 tr = num2str(je->t_rate, 4, 0, i2p);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001196 gtk_entry_set_text(GTK_ENTRY(ge->eta);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001197 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1198 free(tr);
1199 free(mr);
1200 } else if (je->m_iops || je->t_iops)
1201 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
Jens Axboeebbd89c2012-03-02 11:21:13 +01001202
Jens Axboe2f99deb2012-03-09 14:37:29 +01001203 gtk_entry_set_text(GTK_ENTRY(ge->eta.cr_bw), "---");
1204 gtk_entry_set_text(GTK_ENTRY(ge->eta.cr_iops), "---");
1205 gtk_entry_set_text(GTK_ENTRY(ge->eta.cw_bw), "---");
1206 gtk_entry_set_text(GTK_ENTRY(ge->eta.cw_iops), "---");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001207#endif
1208
1209 if (je->eta_sec != INT_MAX && je->nr_running) {
1210 char *iops_str[2];
1211 char *rate_str[2];
1212
1213 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1214 strcpy(output, "-.-% done");
1215 else {
1216 eta_good = 1;
1217 perc *= 100.0;
1218 sprintf(output, "%3.1f%% done", perc);
1219 }
1220
1221 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1222 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1223
1224 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1225 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1226
Jens Axboe2f99deb2012-03-09 14:37:29 +01001227 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), rate_str[0]);
1228 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), iops_str[0]);
1229 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), rate_str[1]);
1230 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), iops_str[1]);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001231
Jens Axboe2f99deb2012-03-09 14:37:29 +01001232 graph_add_xy_data(ge->graphs.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1233 graph_add_xy_data(ge->graphs.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1234 graph_add_xy_data(ge->graphs.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1235 graph_add_xy_data(ge->graphs.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
1236
1237 free(rate_str[0]);
1238 free(rate_str[1]);
1239 free(iops_str[0]);
1240 free(iops_str[1]);
1241 }
1242
1243 if (eta_str[0]) {
1244 char *dst = output + strlen(output);
1245
1246 sprintf(dst, " - %s", eta_str);
1247 }
1248
Jens Axboe9988ca72012-03-09 15:14:06 +01001249 gfio_update_thread_status(ge, output, perc);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001250 gdk_threads_leave();
1251}
1252
1253/*
1254 * Update ETA in main window for all clients
1255 */
1256static void gfio_update_all_eta(struct jobs_eta *je)
1257{
1258 struct gui *ui = &main_ui;
1259 static int eta_good;
1260 char eta_str[128];
1261 char output[256];
1262 double perc = 0.0;
1263 int i2p = 0;
1264
1265 gdk_threads_enter();
1266
1267 eta_str[0] = '\0';
1268 output[0] = '\0';
1269
1270 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1271 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1272 eta_to_str(eta_str, je->eta_sec);
1273 }
1274
1275#if 0
1276 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1277 if (je->m_rate || je->t_rate) {
1278 char *tr, *mr;
1279
1280 mr = num2str(je->m_rate, 4, 0, i2p);
1281 tr = num2str(je->t_rate, 4, 0, i2p);
1282 gtk_entry_set_text(GTK_ENTRY(ui->eta);
1283 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1284 free(tr);
1285 free(mr);
1286 } else if (je->m_iops || je->t_iops)
1287 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
1288
1289 gtk_entry_set_text(GTK_ENTRY(ui->eta.cr_bw), "---");
1290 gtk_entry_set_text(GTK_ENTRY(ui->eta.cr_iops), "---");
1291 gtk_entry_set_text(GTK_ENTRY(ui->eta.cw_bw), "---");
1292 gtk_entry_set_text(GTK_ENTRY(ui->eta.cw_iops), "---");
1293#endif
1294
Jens Axboe3863d1a2012-03-09 17:39:05 +01001295 entry_set_int_value(ui->eta.jobs, je->nr_running);
1296
Jens Axboe2f99deb2012-03-09 14:37:29 +01001297 if (je->eta_sec != INT_MAX && je->nr_running) {
1298 char *iops_str[2];
1299 char *rate_str[2];
1300
1301 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1302 strcpy(output, "-.-% done");
1303 else {
1304 eta_good = 1;
1305 perc *= 100.0;
1306 sprintf(output, "%3.1f%% done", perc);
1307 }
1308
1309 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1310 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1311
1312 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1313 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1314
1315 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), rate_str[0]);
1316 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), iops_str[0]);
1317 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), rate_str[1]);
1318 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), iops_str[1]);
1319
1320 graph_add_xy_data(ui->graphs.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1321 graph_add_xy_data(ui->graphs.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1322 graph_add_xy_data(ui->graphs.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1323 graph_add_xy_data(ui->graphs.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001324
Jens Axboe3e47bd22012-02-29 13:45:02 +01001325 free(rate_str[0]);
1326 free(rate_str[1]);
1327 free(iops_str[0]);
1328 free(iops_str[1]);
1329 }
1330
1331 if (eta_str[0]) {
1332 char *dst = output + strlen(output);
1333
1334 sprintf(dst, " - %s", eta_str);
1335 }
1336
Jens Axboe9988ca72012-03-09 15:14:06 +01001337 gfio_update_thread_status_all(output, perc);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001338 gdk_threads_leave();
Jens Axboe3e47bd22012-02-29 13:45:02 +01001339}
1340
Stephen M. Camerona1820202012-02-24 08:17:31 +01001341static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1342{
Jens Axboe843ad232012-02-29 11:44:53 +01001343 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001344 struct gfio_client *gc = client->client_data;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001345 struct gui_entry *ge = gc->ge;
Jens Axboe843ad232012-02-29 11:44:53 +01001346 const char *os, *arch;
1347 char buf[64];
1348
1349 os = fio_get_os_string(probe->os);
1350 if (!os)
1351 os = "unknown";
1352
1353 arch = fio_get_arch_string(probe->arch);
1354 if (!arch)
1355 os = "unknown";
1356
1357 if (!client->name)
1358 client->name = strdup((char *) probe->hostname);
1359
Jens Axboe0050e5f2012-03-06 09:23:27 +01001360 gdk_threads_enter();
1361
Jens Axboe2f99deb2012-03-09 14:37:29 +01001362 gtk_label_set_text(GTK_LABEL(ge->probe.hostname), (char *) probe->hostname);
1363 gtk_label_set_text(GTK_LABEL(ge->probe.os), os);
1364 gtk_label_set_text(GTK_LABEL(ge->probe.arch), arch);
Jens Axboe843ad232012-02-29 11:44:53 +01001365 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001366 gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), buf);
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001367
Jens Axboe2f99deb2012-03-09 14:37:29 +01001368 gfio_set_connected(ge, 1);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001369
1370 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001371}
1372
Jens Axboe9988ca72012-03-09 15:14:06 +01001373static void gfio_update_thread_status(struct gui_entry *ge,
1374 char *status_message, double perc)
1375{
1376 static char message[100];
1377 const char *m = message;
1378
1379 strncpy(message, status_message, sizeof(message) - 1);
1380 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), m);
1381 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), perc / 100.0);
1382 gtk_widget_queue_draw(main_ui.window);
1383}
1384
1385static void gfio_update_thread_status_all(char *status_message, double perc)
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001386{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001387 struct gui *ui = &main_ui;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001388 static char message[100];
1389 const char *m = message;
1390
1391 strncpy(message, status_message, sizeof(message) - 1);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001392 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), m);
1393 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), perc / 100.0);
1394 gtk_widget_queue_draw(ui->window);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001395}
1396
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001397static void gfio_quit_op(struct fio_client *client)
1398{
Jens Axboee0681f32012-03-06 12:14:42 +01001399 struct gfio_client *gc = client->client_data;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001400
Jens Axboe0050e5f2012-03-06 09:23:27 +01001401 gdk_threads_enter();
Jens Axboe2f99deb2012-03-09 14:37:29 +01001402 gfio_set_connected(gc->ge, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001403 gdk_threads_leave();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001404}
1405
Jens Axboe807f9972012-03-02 10:25:24 +01001406static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1407{
1408 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +01001409 struct gfio_client *gc = client->client_data;
Jens Axboedcaeb602012-03-08 19:45:37 +01001410 struct thread_options *o = &gc->o;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001411 struct gui_entry *ge = gc->ge;
Jens Axboe807f9972012-03-02 10:25:24 +01001412 char tmp[8];
Jens Axboe807f9972012-03-02 10:25:24 +01001413
Jens Axboedcaeb602012-03-08 19:45:37 +01001414 convert_thread_options_to_cpu(o, &p->top);
Jens Axboe807f9972012-03-02 10:25:24 +01001415
Jens Axboe0050e5f2012-03-06 09:23:27 +01001416 gdk_threads_enter();
1417
Jens Axboe2f99deb2012-03-09 14:37:29 +01001418 gtk_label_set_text(GTK_LABEL(ge->page_label), (gchar *) o->name);
1419
Jens Axboe3863d1a2012-03-09 17:39:05 +01001420 gtk_combo_box_append_text(GTK_COMBO_BOX(ge->eta.names), (gchar *) o->name);
1421 gtk_combo_box_set_active(GTK_COMBO_BOX(ge->eta.names), 0);
1422
Jens Axboe2f99deb2012-03-09 14:37:29 +01001423 gtk_entry_set_text(GTK_ENTRY(ge->eta.iotype), ddir_str(o->td_ddir));
1424 gtk_entry_set_text(GTK_ENTRY(ge->eta.ioengine), (gchar *) o->ioengine);
Jens Axboe807f9972012-03-02 10:25:24 +01001425
Jens Axboedcaeb602012-03-08 19:45:37 +01001426 sprintf(tmp, "%u", o->iodepth);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001427 gtk_entry_set_text(GTK_ENTRY(ge->eta.iodepth), tmp);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001428
Jens Axboedcaeb602012-03-08 19:45:37 +01001429 gc->job_added++;
1430
Jens Axboe0050e5f2012-03-06 09:23:27 +01001431 gdk_threads_leave();
Jens Axboe807f9972012-03-02 10:25:24 +01001432}
1433
Jens Axboeed727a42012-03-02 12:14:40 +01001434static void gfio_client_timed_out(struct fio_client *client)
1435{
Jens Axboee0681f32012-03-06 12:14:42 +01001436 struct gfio_client *gc = client->client_data;
Jens Axboeed727a42012-03-02 12:14:40 +01001437 GtkWidget *dialog, *label, *content;
1438 char buf[256];
1439
1440 gdk_threads_enter();
1441
Jens Axboe2f99deb2012-03-09 14:37:29 +01001442 gfio_set_connected(gc->ge, 0);
1443 clear_ge_ui_info(gc->ge);
Jens Axboeed727a42012-03-02 12:14:40 +01001444
1445 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
1446
1447 dialog = gtk_dialog_new_with_buttons("Timed out!",
Jens Axboe2f99deb2012-03-09 14:37:29 +01001448 GTK_WINDOW(main_ui.window),
Jens Axboeed727a42012-03-02 12:14:40 +01001449 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1450 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1451
Jens Axboef1299092012-03-07 20:00:02 +01001452 /* gtk_dialog_get_content_area() is 2.14 and newer */
1453 content = GTK_DIALOG(dialog)->vbox;
1454
Jens Axboeed727a42012-03-02 12:14:40 +01001455 label = gtk_label_new((const gchar *) buf);
1456 gtk_container_add(GTK_CONTAINER(content), label);
1457 gtk_widget_show_all(dialog);
1458 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1459
1460 gtk_dialog_run(GTK_DIALOG(dialog));
1461 gtk_widget_destroy(dialog);
1462
1463 gdk_threads_leave();
1464}
1465
Jens Axboe6b79c802012-03-08 10:51:36 +01001466static void gfio_client_stop(struct fio_client *client, struct fio_net_cmd *cmd)
1467{
1468 struct gfio_client *gc = client->client_data;
1469
1470 gdk_threads_enter();
1471
Jens Axboe2f99deb2012-03-09 14:37:29 +01001472 gfio_set_connected(gc->ge, 0);
Jens Axboe6b79c802012-03-08 10:51:36 +01001473
1474 if (gc->err_entry)
1475 entry_set_int_value(gc->err_entry, client->error);
1476
1477 gdk_threads_leave();
1478}
1479
Stephen M. Camerona1820202012-02-24 08:17:31 +01001480struct client_ops gfio_client_ops = {
Jens Axboe0420ba62012-02-29 11:16:52 +01001481 .text_op = gfio_text_op,
1482 .disk_util = gfio_disk_util_op,
1483 .thread_status = gfio_thread_status_op,
1484 .group_stats = gfio_group_stats_op,
Jens Axboe2f99deb2012-03-09 14:37:29 +01001485 .jobs_eta = gfio_update_client_eta,
1486 .eta = gfio_update_all_eta,
Jens Axboe0420ba62012-02-29 11:16:52 +01001487 .probe = gfio_probe_op,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001488 .quit = gfio_quit_op,
Jens Axboe807f9972012-03-02 10:25:24 +01001489 .add_job = gfio_add_job_op,
Jens Axboeed727a42012-03-02 12:14:40 +01001490 .timed_out = gfio_client_timed_out,
Jens Axboe6b79c802012-03-08 10:51:36 +01001491 .stop = gfio_client_stop,
Jens Axboe6433ee02012-03-09 20:10:51 +01001492 .eta_msec = FIO_CLIENT_DEF_ETA_MSEC,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001493 .stay_connected = 1,
Stephen M. Camerona1820202012-02-24 08:17:31 +01001494};
1495
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001496static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1497 __attribute__((unused)) gpointer data)
1498{
1499 gtk_main_quit();
1500}
1501
Stephen M. Cameron25927252012-02-24 08:17:31 +01001502static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001503{
Jens Axboea9eccde2012-03-09 14:59:42 +01001504 struct gui *ui = arg;
1505
1506 ui->handler_running = 1;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001507 fio_handle_clients(&gfio_client_ops);
Jens Axboea9eccde2012-03-09 14:59:42 +01001508 ui->handler_running = 0;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001509 return NULL;
1510}
1511
Jens Axboe2f99deb2012-03-09 14:37:29 +01001512static int send_job_files(struct gui_entry *ge)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001513{
Jens Axboe9988ca72012-03-09 15:14:06 +01001514 struct gfio_client *gc = ge->client;
Jens Axboe441013b2012-03-01 08:01:52 +01001515 int i, ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001516
Jens Axboe2f99deb2012-03-09 14:37:29 +01001517 for (i = 0; i < ge->nr_job_files; i++) {
Jens Axboe9988ca72012-03-09 15:14:06 +01001518 ret = fio_client_send_ini(gc->client, ge->job_files[i]);
Jens Axboec7249262012-03-09 17:11:04 +01001519 if (ret < 0) {
1520 GError *error;
1521
1522 error = g_error_new(g_quark_from_string("fio"), 1, "Failed to send file %s: %s\n", ge->job_files[i], strerror(-ret));
1523 report_error(error);
1524 g_error_free(error);
1525 break;
1526 } else if (ret)
Jens Axboe441013b2012-03-01 08:01:52 +01001527 break;
1528
Jens Axboe2f99deb2012-03-09 14:37:29 +01001529 free(ge->job_files[i]);
1530 ge->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001531 }
Jens Axboe2f99deb2012-03-09 14:37:29 +01001532 while (i < ge->nr_job_files) {
1533 free(ge->job_files[i]);
1534 ge->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001535 i++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001536 }
1537
Jens Axboe441013b2012-03-01 08:01:52 +01001538 return ret;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001539}
1540
Jens Axboe63a130b2012-03-06 20:08:59 +01001541static void *server_thread(void *arg)
1542{
1543 is_backend = 1;
1544 gfio_server_running = 1;
1545 fio_start_server(NULL);
1546 gfio_server_running = 0;
1547 return NULL;
1548}
1549
Jens Axboe2f99deb2012-03-09 14:37:29 +01001550static void gfio_start_server(void)
Jens Axboe63a130b2012-03-06 20:08:59 +01001551{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001552 struct gui *ui = &main_ui;
1553
Jens Axboe63a130b2012-03-06 20:08:59 +01001554 if (!gfio_server_running) {
1555 gfio_server_running = 1;
1556 pthread_create(&ui->server_t, NULL, server_thread, NULL);
Jens Axboee34f6ad2012-03-06 20:47:15 +01001557 pthread_detach(ui->server_t);
Jens Axboe63a130b2012-03-06 20:08:59 +01001558 }
1559}
1560
Stephen M. Cameron25927252012-02-24 08:17:31 +01001561static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1562 gpointer data)
1563{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001564 struct gui_entry *ge = data;
1565 struct gfio_client *gc = ge->client;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001566
Jens Axboe2f99deb2012-03-09 14:37:29 +01001567 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 0);
1568 fio_start_client(gc->client);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001569}
1570
Jens Axboedf06f222012-03-02 13:32:04 +01001571static void file_open(GtkWidget *w, gpointer data);
1572
1573static void connect_clicked(GtkWidget *widget, gpointer data)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001574{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001575 struct gui_entry *ge = data;
1576 struct gfio_client *gc = ge->client;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001577
Jens Axboe2f99deb2012-03-09 14:37:29 +01001578 if (!ge->connected) {
Jens Axboec7249262012-03-09 17:11:04 +01001579 int ret;
1580
Jens Axboe2f99deb2012-03-09 14:37:29 +01001581 if (!ge->nr_job_files)
Jens Axboedf06f222012-03-02 13:32:04 +01001582 file_open(widget, data);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001583 if (!ge->nr_job_files)
1584 return;
1585
1586 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No jobs running");
1587 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
Jens Axboec7249262012-03-09 17:11:04 +01001588 ret = fio_client_connect(gc->client);
1589 if (!ret) {
Jens Axboea9eccde2012-03-09 14:59:42 +01001590 if (!ge->ui->handler_running)
1591 pthread_create(&ge->ui->t, NULL, job_thread, ge->ui);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001592 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 0);
1593 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 1);
Jens Axboec7249262012-03-09 17:11:04 +01001594 } else {
1595 GError *error;
1596
1597 error = g_error_new(g_quark_from_string("fio"), 1, "Failed to connect to %s: %s\n", ge->client->client->hostname, strerror(-ret));
1598 report_error(error);
1599 g_error_free(error);
Jens Axboe69406b92012-03-06 14:00:42 +01001600 }
Jens Axboedf06f222012-03-02 13:32:04 +01001601 } else {
Jens Axboe2f99deb2012-03-09 14:37:29 +01001602 fio_client_terminate(gc->client);
1603 gfio_set_connected(ge, 0);
1604 clear_ge_ui_info(ge);
Jens Axboedf06f222012-03-02 13:32:04 +01001605 }
Jens Axboe3e47bd22012-02-29 13:45:02 +01001606}
1607
Jens Axboeb9d2f302012-03-08 20:36:28 +01001608static void send_clicked(GtkWidget *widget, gpointer data)
1609{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001610 struct gui_entry *ge = data;
Jens Axboeb9d2f302012-03-08 20:36:28 +01001611
Jens Axboe2f99deb2012-03-09 14:37:29 +01001612 if (send_job_files(ge)) {
Jens Axboec7249262012-03-09 17:11:04 +01001613 GError *error;
1614
1615 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);
1616 report_error(error);
1617 g_error_free(error);
1618
Jens Axboe2f99deb2012-03-09 14:37:29 +01001619 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 1);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001620 }
1621
Jens Axboe2f99deb2012-03-09 14:37:29 +01001622 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 0);
1623 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 1);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001624}
1625
Jens Axboe2f99deb2012-03-09 14:37:29 +01001626static GtkWidget *add_button(GtkWidget *buttonbox,
1627 struct button_spec *buttonspec, gpointer data)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001628{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001629 GtkWidget *button = gtk_button_new_with_label(buttonspec->buttontext);
1630
1631 g_signal_connect(button, "clicked", G_CALLBACK(buttonspec->f), data);
1632 gtk_box_pack_start(GTK_BOX(buttonbox), button, FALSE, FALSE, 3);
1633 gtk_widget_set_tooltip_text(button, buttonspec->tooltiptext);
1634 gtk_widget_set_sensitive(button, !buttonspec->start_insensitive);
1635
1636 return button;
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001637}
1638
Jens Axboe2f99deb2012-03-09 14:37:29 +01001639static void add_buttons(struct gui_entry *ge, struct button_spec *buttonlist,
1640 int nbuttons)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001641{
1642 int i;
1643
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001644 for (i = 0; i < nbuttons; i++)
Jens Axboe2f99deb2012-03-09 14:37:29 +01001645 ge->button[i] = add_button(ge->buttonbox, &buttonlist[i], ge);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001646}
1647
Jens Axboe0420ba62012-02-29 11:16:52 +01001648static void on_info_bar_response(GtkWidget *widget, gint response,
1649 gpointer data)
1650{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001651 struct gui *ui = &main_ui;
1652
Jens Axboe0420ba62012-02-29 11:16:52 +01001653 if (response == GTK_RESPONSE_OK) {
1654 gtk_widget_destroy(widget);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001655 ui->error_info_bar = NULL;
Jens Axboe0420ba62012-02-29 11:16:52 +01001656 }
1657}
1658
Jens Axboedf06f222012-03-02 13:32:04 +01001659void report_error(GError *error)
Jens Axboe0420ba62012-02-29 11:16:52 +01001660{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001661 struct gui *ui = &main_ui;
1662
1663 if (ui->error_info_bar == NULL) {
1664 ui->error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
Jens Axboe0420ba62012-02-29 11:16:52 +01001665 GTK_RESPONSE_OK,
1666 NULL);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001667 g_signal_connect(ui->error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1668 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui->error_info_bar),
Jens Axboe0420ba62012-02-29 11:16:52 +01001669 GTK_MESSAGE_ERROR);
1670
Jens Axboe2f99deb2012-03-09 14:37:29 +01001671 ui->error_label = gtk_label_new(error->message);
1672 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui->error_info_bar));
1673 gtk_container_add(GTK_CONTAINER(container), ui->error_label);
Jens Axboe0420ba62012-02-29 11:16:52 +01001674
Jens Axboe2f99deb2012-03-09 14:37:29 +01001675 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->error_info_bar, FALSE, FALSE, 0);
1676 gtk_widget_show_all(ui->vbox);
Jens Axboe0420ba62012-02-29 11:16:52 +01001677 } else {
1678 char buffer[256];
1679 snprintf(buffer, sizeof(buffer), "Failed to open file.");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001680 gtk_label_set(GTK_LABEL(ui->error_label), buffer);
Jens Axboe0420ba62012-02-29 11:16:52 +01001681 }
1682}
1683
Jens Axboe62bc9372012-03-07 11:45:07 +01001684struct connection_widgets
1685{
1686 GtkWidget *hentry;
1687 GtkWidget *combo;
1688 GtkWidget *button;
1689};
1690
1691static void hostname_cb(GtkEntry *entry, gpointer data)
1692{
1693 struct connection_widgets *cw = data;
1694 int uses_net = 0, is_localhost = 0;
1695 const gchar *text;
1696 gchar *ctext;
1697
1698 /*
1699 * Check whether to display the 'auto start backend' box
1700 * or not. Show it if we are a localhost and using network,
1701 * or using a socket.
1702 */
1703 ctext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->combo));
1704 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
1705 uses_net = 1;
1706 g_free(ctext);
1707
1708 if (uses_net) {
1709 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
1710 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
1711 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
1712 !strcmp(text, "ip6-loopback"))
1713 is_localhost = 1;
1714 }
1715
1716 if (!uses_net || is_localhost) {
1717 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
1718 gtk_widget_set_sensitive(cw->button, 1);
1719 } else {
1720 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
1721 gtk_widget_set_sensitive(cw->button, 0);
1722 }
1723}
1724
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001725static int get_connection_details(char **host, int *port, int *type,
1726 int *server_start)
Jens Axboea7a42ce2012-03-02 13:12:04 +01001727{
Jens Axboe62bc9372012-03-07 11:45:07 +01001728 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
1729 struct connection_widgets cw;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001730 char *typeentry;
1731
1732 dialog = gtk_dialog_new_with_buttons("Connection details",
Jens Axboe2f99deb2012-03-09 14:37:29 +01001733 GTK_WINDOW(main_ui.window),
Jens Axboea7a42ce2012-03-02 13:12:04 +01001734 GTK_DIALOG_DESTROY_WITH_PARENT,
1735 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1736 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1737
1738 frame = gtk_frame_new("Hostname / socket name");
Jens Axboef1299092012-03-07 20:00:02 +01001739 /* gtk_dialog_get_content_area() is 2.14 and newer */
1740 vbox = GTK_DIALOG(dialog)->vbox;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001741 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1742
1743 box = gtk_vbox_new(FALSE, 6);
1744 gtk_container_add(GTK_CONTAINER(frame), box);
1745
1746 hbox = gtk_hbox_new(TRUE, 10);
1747 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe62bc9372012-03-07 11:45:07 +01001748 cw.hentry = gtk_entry_new();
1749 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
1750 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001751
1752 frame = gtk_frame_new("Port");
1753 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1754 box = gtk_vbox_new(FALSE, 10);
1755 gtk_container_add(GTK_CONTAINER(frame), box);
1756
1757 hbox = gtk_hbox_new(TRUE, 4);
1758 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1759 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1760
1761 frame = gtk_frame_new("Type");
1762 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1763 box = gtk_vbox_new(FALSE, 10);
1764 gtk_container_add(GTK_CONTAINER(frame), box);
1765
1766 hbox = gtk_hbox_new(TRUE, 4);
1767 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1768
Jens Axboe62bc9372012-03-07 11:45:07 +01001769 cw.combo = gtk_combo_box_new_text();
1770 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv4");
1771 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv6");
1772 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "local socket");
1773 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001774
Jens Axboe62bc9372012-03-07 11:45:07 +01001775 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001776
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001777 frame = gtk_frame_new("Options");
1778 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1779 box = gtk_vbox_new(FALSE, 10);
1780 gtk_container_add(GTK_CONTAINER(frame), box);
1781
1782 hbox = gtk_hbox_new(TRUE, 4);
1783 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1784
Jens Axboe62bc9372012-03-07 11:45:07 +01001785 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1786 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
1787 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.");
1788 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
1789
1790 /*
1791 * Connect edit signal, so we can show/not-show the auto start button
1792 */
1793 g_signal_connect(GTK_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
1794 g_signal_connect(GTK_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001795
Jens Axboea7a42ce2012-03-02 13:12:04 +01001796 gtk_widget_show_all(dialog);
1797
1798 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1799 gtk_widget_destroy(dialog);
1800 return 1;
1801 }
1802
Jens Axboe62bc9372012-03-07 11:45:07 +01001803 *host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001804 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1805
Jens Axboe62bc9372012-03-07 11:45:07 +01001806 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw.combo));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001807 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1808 *type = Fio_client_ipv4;
1809 else if (!strncmp(typeentry, "IPv6", 4))
1810 *type = Fio_client_ipv6;
1811 else
1812 *type = Fio_client_socket;
1813 g_free(typeentry);
1814
Jens Axboe62bc9372012-03-07 11:45:07 +01001815 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001816
Jens Axboea7a42ce2012-03-02 13:12:04 +01001817 gtk_widget_destroy(dialog);
1818 return 0;
1819}
1820
Jens Axboe2f99deb2012-03-09 14:37:29 +01001821static void gfio_client_added(struct gui_entry *ge, struct fio_client *client)
Jens Axboee0681f32012-03-06 12:14:42 +01001822{
1823 struct gfio_client *gc;
1824
1825 gc = malloc(sizeof(*gc));
1826 memset(gc, 0, sizeof(*gc));
Jens Axboe2f99deb2012-03-09 14:37:29 +01001827 gc->ge = ge;
Jens Axboe343cb4a2012-03-09 17:16:51 +01001828 gc->client = fio_get_client(client);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001829
Jens Axboe2f99deb2012-03-09 14:37:29 +01001830 ge->client = gc;
Jens Axboee0681f32012-03-06 12:14:42 +01001831
1832 client->client_data = gc;
1833}
1834
Jens Axboe2f99deb2012-03-09 14:37:29 +01001835static GtkWidget *new_client_page(struct gui_entry *ge);
1836
1837static struct gui_entry *alloc_new_gui_entry(struct gui *ui)
1838{
1839 struct gui_entry *ge;
1840
1841 ge = malloc(sizeof(*ge));
1842 memset(ge, 0, sizeof(*ge));
1843 INIT_FLIST_HEAD(&ge->list);
1844 flist_add_tail(&ge->list, &ui->list);
1845 ge->ui = ui;
1846 return ge;
1847}
1848
1849/*
1850 * FIXME: need more handling here
1851 */
1852static void ge_destroy(GtkWidget *w, gpointer data)
1853{
1854 struct gui_entry *ge = data;
Jens Axboe343cb4a2012-03-09 17:16:51 +01001855 struct gfio_client *gc = ge->client;
1856
1857 if (gc->client)
1858 fio_put_client(gc->client);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001859
1860 flist_del(&ge->list);
1861 free(ge);
1862}
1863
1864static struct gui_entry *get_new_ge_with_tab(const char *name)
1865{
1866 struct gui_entry *ge;
1867
1868 ge = alloc_new_gui_entry(&main_ui);
1869
1870 ge->vbox = new_client_page(ge);
1871 g_signal_connect(ge->vbox, "destroy", G_CALLBACK(ge_destroy), ge);
1872
1873 ge->page_label = gtk_label_new(name);
1874 ge->page_num = gtk_notebook_append_page(GTK_NOTEBOOK(main_ui.notebook), ge->vbox, ge->page_label);
1875
1876 gtk_widget_show_all(main_ui.window);
1877 return ge;
1878}
1879
1880static void file_new(GtkWidget *w, gpointer data)
1881{
1882 get_new_ge_with_tab("Untitled");
1883}
1884
1885/*
1886 * Return the 'ge' corresponding to the tab. If the active tab is the
1887 * main tab, open a new tab.
1888 */
1889static struct gui_entry *get_ge_from_page(unsigned int cur_page)
1890{
1891 struct flist_head *entry;
1892 struct gui_entry *ge;
1893
1894 if (!cur_page)
1895 return get_new_ge_with_tab("Untitled");
1896
1897 flist_for_each(entry, &main_ui.list) {
1898 ge = flist_entry(entry, struct gui_entry, list);
1899 if (ge->page_num == cur_page)
1900 return ge;
1901 }
1902
1903 return NULL;
1904}
1905
Jens Axboe0420ba62012-02-29 11:16:52 +01001906static void file_open(GtkWidget *w, gpointer data)
1907{
Jens Axboe63a130b2012-03-06 20:08:59 +01001908 struct gui *ui = data;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001909 GtkWidget *dialog;
Jens Axboe0420ba62012-02-29 11:16:52 +01001910 GSList *filenames, *fn_glist;
1911 GtkFileFilter *filter;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001912 char *host;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001913 int port, type, server_start;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001914 struct gui_entry *ge;
1915 gint cur_page;
1916
1917 /*
1918 * Creates new tab if current tab is the main window, or the
1919 * current tab already has a client.
1920 */
1921 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
1922 ge = get_ge_from_page(cur_page);
1923 if (ge->client)
1924 ge = get_new_ge_with_tab("Untitled");
1925
1926 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
Jens Axboe0420ba62012-02-29 11:16:52 +01001927
1928 dialog = gtk_file_chooser_dialog_new("Open File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001929 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001930 GTK_FILE_CHOOSER_ACTION_OPEN,
1931 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1932 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1933 NULL);
1934 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1935
1936 filter = gtk_file_filter_new();
1937 gtk_file_filter_add_pattern(filter, "*.fio");
1938 gtk_file_filter_add_pattern(filter, "*.job");
Jens Axboe2d262992012-03-07 08:19:30 +01001939 gtk_file_filter_add_pattern(filter, "*.ini");
Jens Axboe0420ba62012-02-29 11:16:52 +01001940 gtk_file_filter_add_mime_type(filter, "text/fio");
1941 gtk_file_filter_set_name(filter, "Fio job file");
1942 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
1943
1944 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1945 gtk_widget_destroy(dialog);
1946 return;
1947 }
1948
1949 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001950
1951 gtk_widget_destroy(dialog);
1952
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001953 if (get_connection_details(&host, &port, &type, &server_start))
Jens Axboea7a42ce2012-03-02 13:12:04 +01001954 goto err;
1955
Jens Axboe0420ba62012-02-29 11:16:52 +01001956 filenames = fn_glist;
1957 while (filenames != NULL) {
Jens Axboee0681f32012-03-06 12:14:42 +01001958 struct fio_client *client;
1959
Jens Axboe2f99deb2012-03-09 14:37:29 +01001960 ge->job_files = realloc(ge->job_files, (ge->nr_job_files + 1) * sizeof(char *));
1961 ge->job_files[ge->nr_job_files] = strdup(filenames->data);
1962 ge->nr_job_files++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001963
Jens Axboee0681f32012-03-06 12:14:42 +01001964 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
1965 if (!client) {
Jens Axboedf06f222012-03-02 13:32:04 +01001966 GError *error;
1967
1968 error = g_error_new(g_quark_from_string("fio"), 1,
1969 "Failed to add client %s", host);
Jens Axboe0420ba62012-02-29 11:16:52 +01001970 report_error(error);
1971 g_error_free(error);
Jens Axboe0420ba62012-02-29 11:16:52 +01001972 }
Jens Axboe2f99deb2012-03-09 14:37:29 +01001973 gfio_client_added(ge, client);
Jens Axboe0420ba62012-02-29 11:16:52 +01001974
1975 g_free(filenames->data);
1976 filenames = g_slist_next(filenames);
1977 }
Jens Axboea7a42ce2012-03-02 13:12:04 +01001978 free(host);
Jens Axboe63a130b2012-03-06 20:08:59 +01001979
1980 if (server_start)
Jens Axboe2f99deb2012-03-09 14:37:29 +01001981 gfio_start_server();
Jens Axboea7a42ce2012-03-02 13:12:04 +01001982err:
Jens Axboe0420ba62012-02-29 11:16:52 +01001983 g_slist_free(fn_glist);
Jens Axboe0420ba62012-02-29 11:16:52 +01001984}
1985
1986static void file_save(GtkWidget *w, gpointer data)
1987{
Jens Axboe63a130b2012-03-06 20:08:59 +01001988 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01001989 GtkWidget *dialog;
1990
1991 dialog = gtk_file_chooser_dialog_new("Save File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001992 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001993 GTK_FILE_CHOOSER_ACTION_SAVE,
1994 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1995 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1996 NULL);
1997
1998 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1999 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
2000
2001 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
2002 char *filename;
2003
2004 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
2005 // save_job_file(filename);
2006 g_free(filename);
2007 }
2008 gtk_widget_destroy(dialog);
2009}
2010
Jens Axboe9b260bd2012-03-06 11:02:52 +01002011static void view_log_destroy(GtkWidget *w, gpointer data)
2012{
2013 struct gui *ui = (struct gui *) data;
2014
2015 gtk_widget_ref(ui->log_tree);
2016 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
2017 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +01002018 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +01002019}
2020
2021static void view_log(GtkWidget *w, gpointer data)
2022{
Jens Axboe4cbe7212012-03-06 13:36:17 +01002023 GtkWidget *win, *scroll, *vbox, *box;
2024 struct gui *ui = (struct gui *) data;
Jens Axboe9b260bd2012-03-06 11:02:52 +01002025
Jens Axboe4cbe7212012-03-06 13:36:17 +01002026 if (ui->log_view)
2027 return;
2028
2029 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002030 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +01002031 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002032
Jens Axboe4cbe7212012-03-06 13:36:17 +01002033 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002034
Jens Axboe4cbe7212012-03-06 13:36:17 +01002035 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
2036
2037 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2038
2039 box = gtk_hbox_new(TRUE, 0);
2040 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
2041 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
2042 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
2043
2044 vbox = gtk_vbox_new(TRUE, 5);
2045 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
2046
2047 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002048 gtk_widget_show_all(win);
2049}
2050
Jens Axboe8577f4f2012-03-09 19:28:27 +01002051static void __update_graph_limits(struct gfio_graphs *g)
2052{
2053 line_graph_set_data_count_limit(g->iops_graph, gfio_graph_limit);
2054 line_graph_set_data_count_limit(g->bandwidth_graph, gfio_graph_limit);
2055}
2056
2057static void update_graph_limits(void)
2058{
2059 struct flist_head *entry;
2060 struct gui_entry *ge;
2061
2062 __update_graph_limits(&main_ui.graphs);
2063
2064 flist_for_each(entry, &main_ui.list) {
2065 ge = flist_entry(entry, struct gui_entry, list);
2066 __update_graph_limits(&ge->graphs);
2067 }
2068}
2069
Jens Axboe46974a72012-03-02 19:34:13 +01002070static void preferences(GtkWidget *w, gpointer data)
2071{
Jens Axboef3e84402012-03-07 13:14:32 +01002072 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002073 GtkWidget *hbox, *spin, *entry, *spin_int;
Jens Axboe46974a72012-03-02 19:34:13 +01002074 int i;
2075
2076 dialog = gtk_dialog_new_with_buttons("Preferences",
Jens Axboe2f99deb2012-03-09 14:37:29 +01002077 GTK_WINDOW(main_ui.window),
Jens Axboe46974a72012-03-02 19:34:13 +01002078 GTK_DIALOG_DESTROY_WITH_PARENT,
2079 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2080 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2081 NULL);
2082
Jens Axboe8577f4f2012-03-09 19:28:27 +01002083 frame = gtk_frame_new("Graphing");
Jens Axboef3e84402012-03-07 13:14:32 +01002084 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
2085 vbox = gtk_vbox_new(FALSE, 6);
2086 gtk_container_add(GTK_CONTAINER(frame), vbox);
2087
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002088 hbox = gtk_hbox_new(FALSE, 5);
2089 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
2090 entry = gtk_label_new("Font face to use for graph labels");
2091 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 5);
2092
Jens Axboef3e84402012-03-07 13:14:32 +01002093 font = gtk_font_button_new();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002094 gtk_box_pack_start(GTK_BOX(hbox), font, FALSE, FALSE, 5);
Jens Axboef3e84402012-03-07 13:14:32 +01002095
Jens Axboe8577f4f2012-03-09 19:28:27 +01002096 box = gtk_vbox_new(FALSE, 6);
2097 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
2098
2099 hbox = gtk_hbox_new(FALSE, 5);
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002100 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
Jens Axboe8577f4f2012-03-09 19:28:27 +01002101 entry = gtk_label_new("Maximum number of data points in graph (seconds)");
2102 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
2103
Jens Axboec05d9052012-03-11 13:05:35 +01002104 spin = create_spinbutton(hbox, 10, 1000000, gfio_graph_limit);
Jens Axboe8577f4f2012-03-09 19:28:27 +01002105
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002106 box = gtk_vbox_new(FALSE, 6);
2107 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
2108
2109 hbox = gtk_hbox_new(FALSE, 5);
2110 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
2111 entry = gtk_label_new("Client ETA request interval (msec)");
2112 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
2113
2114 spin_int = create_spinbutton(hbox, 100, 100000, gfio_client_ops.eta_msec);
Jens Axboea31d9fa2012-03-09 20:23:05 +01002115 frame = gtk_frame_new("Debug logging");
2116 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
2117 vbox = gtk_vbox_new(FALSE, 6);
2118 gtk_container_add(GTK_CONTAINER(frame), vbox);
2119
2120 box = gtk_hbox_new(FALSE, 6);
2121 gtk_container_add(GTK_CONTAINER(vbox), box);
2122
2123 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
2124
2125 for (i = 0; i < FD_DEBUG_MAX; i++) {
2126 if (i == 7) {
2127 box = gtk_hbox_new(FALSE, 6);
2128 gtk_container_add(GTK_CONTAINER(vbox), box);
2129 }
2130
2131
2132 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
2133 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
2134 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
2135 }
2136
Jens Axboe46974a72012-03-02 19:34:13 +01002137 gtk_widget_show_all(dialog);
2138
2139 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
2140 gtk_widget_destroy(dialog);
2141 return;
2142 }
2143
2144 for (i = 0; i < FD_DEBUG_MAX; i++) {
2145 int set;
2146
2147 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
2148 if (set)
2149 fio_debug |= (1UL << i);
2150 }
2151
Jens Axboef3e84402012-03-07 13:14:32 +01002152 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
Jens Axboe8577f4f2012-03-09 19:28:27 +01002153 gfio_graph_limit = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
2154 update_graph_limits();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002155 gfio_client_ops.eta_msec = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_int));
Jens Axboe8577f4f2012-03-09 19:28:27 +01002156
Jens Axboe46974a72012-03-02 19:34:13 +01002157 gtk_widget_destroy(dialog);
2158}
2159
Jens Axboe0420ba62012-02-29 11:16:52 +01002160static void about_dialog(GtkWidget *w, gpointer data)
2161{
Jens Axboe81e4ea62012-03-07 14:18:28 +01002162 const char *authors[] = {
2163 "Jens Axboe <axboe@kernel.dk>",
2164 "Stephen Carmeron <stephenmcameron@gmail.com>",
2165 NULL
2166 };
Jens Axboe84a72ed2012-03-07 14:24:57 +01002167 const char *license[] = {
2168 "Fio is free software; you can redistribute it and/or modify "
2169 "it under the terms of the GNU General Public License as published by "
2170 "the Free Software Foundation; either version 2 of the License, or "
2171 "(at your option) any later version.\n",
2172 "Fio is distributed in the hope that it will be useful, "
2173 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
2174 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
2175 "GNU General Public License for more details.\n",
2176 "You should have received a copy of the GNU General Public License "
2177 "along with Fio; if not, write to the Free Software Foundation, Inc., "
2178 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
2179 };
2180 char *license_trans;
2181
2182 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
2183 license[2], "\n", NULL);
Jens Axboe81e4ea62012-03-07 14:18:28 +01002184
Jens Axboe0420ba62012-02-29 11:16:52 +01002185 gtk_show_about_dialog(NULL,
2186 "program-name", "gfio",
2187 "comments", "Gtk2 UI for fio",
Jens Axboe84a72ed2012-03-07 14:24:57 +01002188 "license", license_trans,
Jens Axboe81e4ea62012-03-07 14:18:28 +01002189 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
2190 "authors", authors,
Jens Axboe0420ba62012-02-29 11:16:52 +01002191 "version", fio_version_string,
Jens Axboe81e4ea62012-03-07 14:18:28 +01002192 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
Jens Axboe0420ba62012-02-29 11:16:52 +01002193 "logo-icon-name", "fio",
2194 /* Must be last: */
Jens Axboe81e4ea62012-03-07 14:18:28 +01002195 "wrap-license", TRUE,
Jens Axboe0420ba62012-02-29 11:16:52 +01002196 NULL);
Jens Axboe84a72ed2012-03-07 14:24:57 +01002197
Jens Axboe2f99deb2012-03-09 14:37:29 +01002198 g_free(license_trans);
Jens Axboe0420ba62012-02-29 11:16:52 +01002199}
2200
2201static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01002202 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01002203 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01002204 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
Jens Axboe2f99deb2012-03-09 14:37:29 +01002205 { "NewFile", GTK_STOCK_NEW, "New", "<Control>N", NULL, G_CALLBACK(file_new) },
Jens Axboe46974a72012-03-02 19:34:13 +01002206 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
2207 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
2208 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01002209 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe46974a72012-03-02 19:34:13 +01002210 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
2211 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01002212};
Jens Axboe3e47bd22012-02-29 13:45:02 +01002213static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01002214
2215static const gchar *ui_string = " \
2216 <ui> \
2217 <menubar name=\"MainMenu\"> \
2218 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01002219 <menuitem name=\"New\" action=\"NewFile\" /> \
2220 <separator name=\"Separator1\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01002221 <menuitem name=\"Open\" action=\"OpenFile\" /> \
2222 <menuitem name=\"Save\" action=\"SaveFile\" /> \
Jens Axboe46974a72012-03-02 19:34:13 +01002223 <separator name=\"Separator2\"/> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01002224 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
2225 <separator name=\"Separator3\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01002226 <menuitem name=\"Quit\" action=\"Quit\" /> \
2227 </menu> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01002228 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
2229 <menuitem name=\"Log\" action=\"ViewLog\" /> \
2230 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01002231 <menu name=\"Help\" action=\"HelpMenuAction\"> \
2232 <menuitem name=\"About\" action=\"About\" /> \
2233 </menu> \
2234 </menubar> \
2235 </ui> \
2236";
2237
Jens Axboe4cbe7212012-03-06 13:36:17 +01002238static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
2239 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01002240{
2241 GtkActionGroup *action_group = gtk_action_group_new("Menu");
2242 GError *error = 0;
2243
2244 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01002245 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01002246
2247 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
2248 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
2249
2250 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
2251 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
2252}
2253
2254void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
2255 GtkWidget *vbox, GtkUIManager *ui_manager)
2256{
2257 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
2258}
2259
Jens Axboe2f99deb2012-03-09 14:37:29 +01002260static GtkWidget *new_client_page(struct gui_entry *ge)
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002261{
Jens Axboe2f99deb2012-03-09 14:37:29 +01002262 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01002263 GdkColor white;
Jens Axboe0420ba62012-02-29 11:16:52 +01002264
Jens Axboe2f99deb2012-03-09 14:37:29 +01002265 main_vbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01002266
Jens Axboe2f99deb2012-03-09 14:37:29 +01002267 ge->topalign = gtk_alignment_new(0, 0, 1, 0);
2268 ge->topvbox = gtk_vbox_new(FALSE, 3);
2269 gtk_container_add(GTK_CONTAINER(ge->topalign), ge->topvbox);
2270 gtk_box_pack_start(GTK_BOX(main_vbox), ge->topalign, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002271
Jens Axboe3e47bd22012-02-29 13:45:02 +01002272 probe = gtk_frame_new("Job");
Jens Axboe2f99deb2012-03-09 14:37:29 +01002273 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01002274 probe_frame = gtk_vbox_new(FALSE, 3);
2275 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
2276
2277 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002278 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2279 ge->probe.hostname = new_info_label_in_frame(probe_box, "Host");
2280 ge->probe.os = new_info_label_in_frame(probe_box, "OS");
2281 ge->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
2282 ge->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
Jens Axboe843ad232012-02-29 11:44:53 +01002283
Jens Axboe3e47bd22012-02-29 13:45:02 +01002284 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002285 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2286
Jens Axboe3863d1a2012-03-09 17:39:05 +01002287 ge->eta.names = new_combo_entry_in_frame(probe_box, "Jobs");
Jens Axboe2f99deb2012-03-09 14:37:29 +01002288 ge->eta.iotype = new_info_entry_in_frame(probe_box, "IO");
2289 ge->eta.ioengine = new_info_entry_in_frame(probe_box, "IO Engine");
2290 ge->eta.iodepth = new_info_entry_in_frame(probe_box, "IO Depth");
2291 ge->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
2292 ge->eta.files = new_info_entry_in_frame(probe_box, "Open files");
2293
2294 probe_box = gtk_hbox_new(FALSE, 3);
2295 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2296 ge->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
2297 ge->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
2298 ge->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
2299 ge->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
2300
2301 /*
2302 * Only add this if we have a commit rate
2303 */
2304#if 0
2305 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe3e47bd22012-02-29 13:45:02 +01002306 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01002307
Jens Axboe2f99deb2012-03-09 14:37:29 +01002308 ge->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
2309 ge->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2310
2311 ge->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
2312 ge->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2313#endif
2314
2315 /*
2316 * Set up a drawing area and IOPS and bandwidth graphs
2317 */
2318 gdk_color_parse("white", &white);
2319 ge->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01002320 gtk_widget_set_size_request(GTK_WIDGET(ge->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01002321 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002322 gtk_widget_modify_bg(ge->graphs.drawing_area, GTK_STATE_NORMAL, &white);
2323 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "expose_event",
2324 G_CALLBACK(on_expose_drawing_area), &ge->graphs);
2325 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "configure_event",
2326 G_CALLBACK(on_config_drawing_area), &ge->graphs);
2327 ge->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2328 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ge->scrolled_window),
2329 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2330 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ge->scrolled_window),
2331 ge->graphs.drawing_area);
2332 gtk_box_pack_start(GTK_BOX(main_vbox), ge->scrolled_window,
2333 TRUE, TRUE, 0);
2334
2335 setup_graphs(&ge->graphs);
2336
2337 /*
2338 * Set up alignments for widgets at the bottom of ui,
2339 * align bottom left, expand horizontally but not vertically
2340 */
2341 ge->bottomalign = gtk_alignment_new(0, 1, 1, 0);
2342 ge->buttonbox = gtk_hbox_new(FALSE, 0);
2343 gtk_container_add(GTK_CONTAINER(ge->bottomalign), ge->buttonbox);
2344 gtk_box_pack_start(GTK_BOX(main_vbox), ge->bottomalign,
2345 FALSE, FALSE, 0);
2346
2347 add_buttons(ge, buttonspeclist, ARRAYSIZE(buttonspeclist));
2348
2349 /*
2350 * Set up thread status progress bar
2351 */
2352 ge->thread_status_pb = gtk_progress_bar_new();
2353 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
2354 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No connections");
2355 gtk_container_add(GTK_CONTAINER(ge->buttonbox), ge->thread_status_pb);
2356
2357
2358 return main_vbox;
2359}
2360
2361static GtkWidget *new_main_page(struct gui *ui)
2362{
2363 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
2364 GdkColor white;
2365
2366 main_vbox = gtk_vbox_new(FALSE, 3);
2367
2368 /*
2369 * Set up alignments for widgets at the top of ui,
2370 * align top left, expand horizontally but not vertically
2371 */
2372 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
2373 ui->topvbox = gtk_vbox_new(FALSE, 0);
2374 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
2375 gtk_box_pack_start(GTK_BOX(main_vbox), ui->topalign, FALSE, FALSE, 0);
2376
2377 probe = gtk_frame_new("Run statistics");
2378 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
2379 probe_frame = gtk_vbox_new(FALSE, 3);
2380 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
Jens Axboe3e47bd22012-02-29 13:45:02 +01002381
2382 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002383 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
Jens Axboe3863d1a2012-03-09 17:39:05 +01002384 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Running");
Jens Axboeca850992012-03-05 20:04:43 +01002385 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
2386 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
2387 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
2388 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01002389
2390 /*
2391 * Only add this if we have a commit rate
2392 */
2393#if 0
2394 probe_box = gtk_hbox_new(FALSE, 3);
2395 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
2396
Jens Axboe3e47bd22012-02-29 13:45:02 +01002397 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
2398 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2399
Jens Axboe3e47bd22012-02-29 13:45:02 +01002400 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
2401 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01002402#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01002403
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01002404 /*
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002405 * Set up a drawing area and IOPS and bandwidth graphs
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002406 */
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01002407 gdk_color_parse("white", &white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002408 ui->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01002409 gtk_widget_set_size_request(GTK_WIDGET(ui->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01002410 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002411 gtk_widget_modify_bg(ui->graphs.drawing_area, GTK_STATE_NORMAL, &white);
2412 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "expose_event",
2413 G_CALLBACK(on_expose_drawing_area), &ui->graphs);
2414 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "configure_event",
2415 G_CALLBACK(on_config_drawing_area), &ui->graphs);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002416 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2417 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
2418 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002419 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ui->scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01002420 ui->graphs.drawing_area);
2421 gtk_box_pack_start(GTK_BOX(main_vbox), ui->scrolled_window,
Stephen M. Camerone1645342012-02-24 08:17:32 +01002422 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002423
Jens Axboe2f99deb2012-03-09 14:37:29 +01002424 setup_graphs(&ui->graphs);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002425
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002426 /*
2427 * Set up alignments for widgets at the bottom of ui,
2428 * align bottom left, expand horizontally but not vertically
2429 */
2430 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
2431 ui->buttonbox = gtk_hbox_new(FALSE, 0);
2432 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002433 gtk_box_pack_start(GTK_BOX(main_vbox), ui->bottomalign,
Stephen M. Camerone1645342012-02-24 08:17:32 +01002434 FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002435
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002436 /*
2437 * Set up thread status progress bar
2438 */
2439 ui->thread_status_pb = gtk_progress_bar_new();
2440 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01002441 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002442 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
2443
Jens Axboe2f99deb2012-03-09 14:37:29 +01002444 return main_vbox;
2445}
2446
2447static gboolean notebook_switch_page(GtkNotebook *notebook, GtkWidget *widget,
2448 guint page, gpointer data)
2449
2450{
2451 return TRUE;
2452}
2453
2454static void init_ui(int *argc, char **argv[], struct gui *ui)
2455{
2456 GtkSettings *settings;
2457 GtkUIManager *uimanager;
2458 GtkWidget *menu, *vbox;
2459
2460 /* Magical g*thread incantation, you just need this thread stuff.
2461 * Without it, the update that happens in gfio_update_thread_status
2462 * doesn't really happen in a timely fashion, you need expose events
2463 */
2464 if (!g_thread_supported())
2465 g_thread_init(NULL);
2466 gdk_threads_init();
2467
2468 gtk_init(argc, argv);
2469 settings = gtk_settings_get_default();
2470 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
2471 g_type_init();
2472
2473 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2474 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
2475 gtk_window_set_default_size(GTK_WINDOW(ui->window), 1024, 768);
2476
2477 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
2478 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
2479
2480 ui->vbox = gtk_vbox_new(FALSE, 0);
2481 gtk_container_add(GTK_CONTAINER(ui->window), ui->vbox);
2482
2483 uimanager = gtk_ui_manager_new();
2484 menu = get_menubar_menu(ui->window, uimanager, ui);
2485 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
2486
2487 ui->notebook = gtk_notebook_new();
2488 g_signal_connect(ui->notebook, "switch-page", G_CALLBACK(notebook_switch_page), ui);
Jens Axboeb870c312012-03-09 17:22:01 +01002489 gtk_notebook_set_scrollable(GTK_NOTEBOOK(ui->notebook), 1);
Jens Axboe0aa928c2012-03-09 17:24:07 +01002490 gtk_notebook_popup_enable(GTK_NOTEBOOK(ui->notebook));
Jens Axboe2f99deb2012-03-09 14:37:29 +01002491 gtk_container_add(GTK_CONTAINER(ui->vbox), ui->notebook);
2492
2493 vbox = new_main_page(ui);
2494
2495 gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), vbox, gtk_label_new("Main"));
2496
Jens Axboe9b260bd2012-03-06 11:02:52 +01002497 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002498
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002499 gtk_widget_show_all(ui->window);
2500}
2501
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002502int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002503{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002504 if (initialize_fio(envp))
2505 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01002506 if (fio_init_options())
2507 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01002508
Jens Axboe2f99deb2012-03-09 14:37:29 +01002509 memset(&main_ui, 0, sizeof(main_ui));
2510 INIT_FLIST_HEAD(&main_ui.list);
2511
2512 init_ui(&argc, &argv, &main_ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01002513
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002514 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002515 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002516 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002517 return 0;
2518}