blob: 6a227772800aeda32647b82d034747f9422bddca [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 Axboec80b74b2012-03-12 10:23:28 +010071struct multitext_widget {
72 GtkWidget *entry;
73 char **text;
74 unsigned int cur_text;
75 unsigned int max_text;
76};
77
Jens Axboe3e47bd22012-02-29 13:45:02 +010078struct eta_widget {
Jens Axboe3863d1a2012-03-09 17:39:05 +010079 GtkWidget *names;
Jens Axboec80b74b2012-03-12 10:23:28 +010080 struct multitext_widget iotype;
81 struct multitext_widget ioengine;
82 struct multitext_widget iodepth;
Jens Axboe3e47bd22012-02-29 13:45:02 +010083 GtkWidget *jobs;
84 GtkWidget *files;
85 GtkWidget *read_bw;
86 GtkWidget *read_iops;
87 GtkWidget *cr_bw;
88 GtkWidget *cr_iops;
89 GtkWidget *write_bw;
90 GtkWidget *write_iops;
91 GtkWidget *cw_bw;
92 GtkWidget *cw_iops;
93};
94
Jens Axboe2f99deb2012-03-09 14:37:29 +010095struct gfio_graphs {
96#define DRAWING_AREA_XDIM 1000
97#define DRAWING_AREA_YDIM 400
98 GtkWidget *drawing_area;
Jens Axboe2f99deb2012-03-09 14:37:29 +010099 struct graph *iops_graph;
100 struct graph *bandwidth_graph;
101};
102
103/*
104 * Main window widgets and data
105 */
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100106struct gui {
107 GtkWidget *window;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100108 GtkWidget *vbox;
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +0100109 GtkWidget *topvbox;
110 GtkWidget *topalign;
111 GtkWidget *bottomalign;
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +0100112 GtkWidget *thread_status_pb;
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100113 GtkWidget *buttonbox;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100114 GtkWidget *scrolled_window;
115 GtkWidget *notebook;
116 GtkWidget *error_info_bar;
117 GtkWidget *error_label;
118 GtkListStore *log_model;
119 GtkWidget *log_tree;
120 GtkWidget *log_view;
121 struct gfio_graphs graphs;
122 struct probe_widget probe;
123 struct eta_widget eta;
124 pthread_t server_t;
125
Jens Axboea9eccde2012-03-09 14:59:42 +0100126 pthread_t t;
127 int handler_running;
128
Jens Axboe2f99deb2012-03-09 14:37:29 +0100129 struct flist_head list;
130} main_ui;
131
132/*
133 * Notebook entry
134 */
135struct gui_entry {
136 struct flist_head list;
137 struct gui *ui;
138
139 GtkWidget *vbox;
140 GtkWidget *topvbox;
141 GtkWidget *topalign;
142 GtkWidget *bottomalign;
Jens Axboec80b74b2012-03-12 10:23:28 +0100143 GtkWidget *job_notebook;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100144 GtkWidget *thread_status_pb;
145 GtkWidget *buttonbox;
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100146 GtkWidget *button[ARRAYSIZE(buttonspeclist)];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100147 GtkWidget *scrolled_window;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100148 GtkWidget *notebook;
Jens Axboe0420ba62012-02-29 11:16:52 +0100149 GtkWidget *error_info_bar;
150 GtkWidget *error_label;
Jens Axboef9d40b42012-03-06 09:52:49 +0100151 GtkWidget *results_notebook;
152 GtkWidget *results_window;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100153 GtkListStore *log_model;
154 GtkWidget *log_tree;
Jens Axboe4cbe7212012-03-06 13:36:17 +0100155 GtkWidget *log_view;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100156 struct gfio_graphs graphs;
Jens Axboe843ad232012-02-29 11:44:53 +0100157 struct probe_widget probe;
Jens Axboe3e47bd22012-02-29 13:45:02 +0100158 struct eta_widget eta;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100159 GtkWidget *page_label;
160 gint page_num;
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100161 int connected;
Jens Axboe0420ba62012-02-29 11:16:52 +0100162
Jens Axboeb9d2f302012-03-08 20:36:28 +0100163 struct gfio_client *client;
Jens Axboe0420ba62012-02-29 11:16:52 +0100164 int nr_job_files;
165 char **job_files;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100166};
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100167
Jens Axboee0681f32012-03-06 12:14:42 +0100168struct gfio_client {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100169 struct gui_entry *ge;
Jens Axboeb9d2f302012-03-08 20:36:28 +0100170 struct fio_client *client;
Jens Axboee0681f32012-03-06 12:14:42 +0100171 GtkWidget *results_widget;
172 GtkWidget *disk_util_frame;
Jens Axboe6b79c802012-03-08 10:51:36 +0100173 GtkWidget *err_entry;
Jens Axboedcaeb602012-03-08 19:45:37 +0100174 unsigned int job_added;
175 struct thread_options o;
Jens Axboee0681f32012-03-06 12:14:42 +0100176};
177
Jens Axboe9988ca72012-03-09 15:14:06 +0100178static void gfio_update_thread_status(struct gui_entry *ge, char *status_message, double perc);
179static void gfio_update_thread_status_all(char *status_message, double perc);
Jens Axboec7249262012-03-09 17:11:04 +0100180void report_error(GError *error);
Jens Axboe9988ca72012-03-09 15:14:06 +0100181
Stephen M. Cameronf0af9f82012-03-11 11:35:50 +0100182static void iops_graph_y_axis_unit_change(struct graph *g, int power_of_ten)
183{
184 switch (power_of_ten) {
185 case 9: graph_y_title(g, "Billions of IOs / sec");
186 break;
187 case 6: graph_y_title(g, "Millions of IOs / sec");
188 break;
189 case 3: graph_y_title(g, "Thousands of IOs / sec");
190 break;
191 case 0:
192 default: graph_y_title(g, "IOs / sec");
193 break;
194 }
195}
196
Jens Axboe2f99deb2012-03-09 14:37:29 +0100197static struct graph *setup_iops_graph(void)
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100198{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100199 struct graph *g;
200
201 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
202 graph_title(g, "IOPS");
203 graph_x_title(g, "Time (secs)");
204 graph_y_title(g, "IOs / sec");
205 graph_add_label(g, "Read IOPS");
206 graph_add_label(g, "Write IOPS");
207 graph_set_color(g, "Read IOPS", 0.13, 0.54, 0.13);
208 graph_set_color(g, "Write IOPS", 1.0, 0.0, 0.0);
Jens Axboe8577f4f2012-03-09 19:28:27 +0100209 line_graph_set_data_count_limit(g, gfio_graph_limit);
Stephen M. Cameronf0af9f82012-03-11 11:35:50 +0100210 graph_y_axis_unit_change_notify(g, iops_graph_y_axis_unit_change);
Stephen M. Camerondef0ac22012-03-12 07:32:57 +0100211 graph_add_extra_space(g, 0.005, 0.005, 0.03, 0.03);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100212 return g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100213}
214
Stephen M. Cameronf0af9f82012-03-11 11:35:50 +0100215static void bandwidth_graph_y_axis_unit_change(struct graph *g, int power_of_ten)
216{
217 switch (power_of_ten) {
218 case 9: graph_y_title(g, "Petabytes / sec");
219 break;
220 case 6: graph_y_title(g, "Gigabytes / sec");
221 break;
222 case 3: graph_y_title(g, "Megabytes / sec");
223 break;
224 case 0:
225 default: graph_y_title(g, "Kilobytes / sec");
226 break;
227 }
228}
229
Jens Axboe2f99deb2012-03-09 14:37:29 +0100230static struct graph *setup_bandwidth_graph(void)
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100231{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100232 struct graph *g;
233
234 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
235 graph_title(g, "Bandwidth");
236 graph_x_title(g, "Time (secs)");
237 graph_y_title(g, "Kbytes / sec");
238 graph_add_label(g, "Read Bandwidth");
239 graph_add_label(g, "Write Bandwidth");
240 graph_set_color(g, "Read Bandwidth", 0.13, 0.54, 0.13);
241 graph_set_color(g, "Write Bandwidth", 1.0, 0.0, 0.0);
242 line_graph_set_data_count_limit(g, 100);
Stephen M. Cameronf0af9f82012-03-11 11:35:50 +0100243 graph_y_axis_unit_change_notify(g, bandwidth_graph_y_axis_unit_change);
Stephen M. Camerondef0ac22012-03-12 07:32:57 +0100244 graph_add_extra_space(g, 0.005, 0.005, 0.03, 0.03);
245
Jens Axboe2f99deb2012-03-09 14:37:29 +0100246 return g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100247}
248
Jens Axboe2f99deb2012-03-09 14:37:29 +0100249static void setup_graphs(struct gfio_graphs *g)
Jens Axboe8663ea62012-03-02 14:04:30 +0100250{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100251 g->iops_graph = setup_iops_graph();
252 g->bandwidth_graph = setup_bandwidth_graph();
253}
254
Jens Axboec80b74b2012-03-12 10:23:28 +0100255static void multitext_add_entry(struct multitext_widget *mt, const char *text)
256{
257 mt->text = realloc(mt->text, (mt->max_text + 1) * sizeof(char *));
258 mt->text[mt->max_text] = strdup(text);
259 mt->max_text++;
260}
261
262static void multitext_set_entry(struct multitext_widget *mt, unsigned int index)
263{
264 if (index >= mt->max_text)
265 return;
266 if (!mt->text[index])
267 return;
268
269 mt->cur_text = index;
270 gtk_entry_set_text(GTK_ENTRY(mt->entry), mt->text[index]);
271}
272
273static void multitext_update_entry(struct multitext_widget *mt,
274 unsigned int index, const char *text)
275{
276 if (mt->text[index])
277 free(mt->text[index]);
278
279 mt->text[index] = strdup(text);
280 if (mt->cur_text == index)
281 gtk_entry_set_text(GTK_ENTRY(mt->entry), mt->text[index]);
282}
283
284static void multitext_free(struct multitext_widget *mt)
285{
286 int i;
287
288 gtk_entry_set_text(GTK_ENTRY(mt->entry), "");
289
290 for (i = 0; i < mt->max_text; i++) {
291 if (mt->text[i])
292 free(mt->text[i]);
293 }
294
295 free(mt->text);
296 mt->cur_text = -1;
297 mt->max_text = 0;
298}
299
Jens Axboe2f99deb2012-03-09 14:37:29 +0100300static void clear_ge_ui_info(struct gui_entry *ge)
301{
302 gtk_label_set_text(GTK_LABEL(ge->probe.hostname), "");
303 gtk_label_set_text(GTK_LABEL(ge->probe.os), "");
304 gtk_label_set_text(GTK_LABEL(ge->probe.arch), "");
305 gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100306#if 0
307 /* should we empty it... */
Jens Axboe2f99deb2012-03-09 14:37:29 +0100308 gtk_entry_set_text(GTK_ENTRY(ge->eta.name), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100309#endif
Jens Axboec80b74b2012-03-12 10:23:28 +0100310 multitext_update_entry(&ge->eta.iotype, 0, "");
311 multitext_update_entry(&ge->eta.ioengine, 0, "");
312 multitext_update_entry(&ge->eta.iodepth, 0, "");
Jens Axboe2f99deb2012-03-09 14:37:29 +0100313 gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), "");
314 gtk_entry_set_text(GTK_ENTRY(ge->eta.files), "");
315 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), "");
316 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), "");
317 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), "");
318 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100319}
320
Jens Axboe3863d1a2012-03-09 17:39:05 +0100321static GtkWidget *new_combo_entry_in_frame(GtkWidget *box, const char *label)
322{
323 GtkWidget *entry, *frame;
324
325 frame = gtk_frame_new(label);
326 entry = gtk_combo_box_new_text();
327 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
328 gtk_container_add(GTK_CONTAINER(frame), entry);
329
330 return entry;
331}
332
Jens Axboe3650a3c2012-03-05 14:09:03 +0100333static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
334{
335 GtkWidget *entry, *frame;
336
337 frame = gtk_frame_new(label);
338 entry = gtk_entry_new();
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100339 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100340 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
341 gtk_container_add(GTK_CONTAINER(frame), entry);
342
343 return entry;
344}
345
346static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
347{
348 GtkWidget *label_widget;
349 GtkWidget *frame;
350
351 frame = gtk_frame_new(label);
352 label_widget = gtk_label_new(NULL);
353 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
354 gtk_container_add(GTK_CONTAINER(frame), label_widget);
355
356 return label_widget;
357}
358
359static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
360{
361 GtkWidget *button, *box;
362
363 box = gtk_hbox_new(FALSE, 3);
364 gtk_container_add(GTK_CONTAINER(hbox), box);
365
366 button = gtk_spin_button_new_with_range(min, max, 1.0);
367 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
368
369 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
370 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
371
372 return button;
373}
374
Jens Axboe2f99deb2012-03-09 14:37:29 +0100375static void gfio_set_connected(struct gui_entry *ge, int connected)
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100376{
377 if (connected) {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100378 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 1);
379 ge->connected = 1;
380 gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), "Disconnect");
381 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100382 } else {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100383 ge->connected = 0;
384 gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), "Connect");
385 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 0);
386 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 0);
387 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100388 }
389}
390
Jens Axboe3650a3c2012-03-05 14:09:03 +0100391static void label_set_int_value(GtkWidget *entry, unsigned int val)
392{
393 char tmp[80];
394
395 sprintf(tmp, "%u", val);
396 gtk_label_set_text(GTK_LABEL(entry), tmp);
397}
398
399static void entry_set_int_value(GtkWidget *entry, unsigned int val)
400{
401 char tmp[80];
402
403 sprintf(tmp, "%u", val);
404 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
405}
406
Jens Axboea2697902012-03-05 16:43:49 +0100407#define ALIGN_LEFT 1
408#define ALIGN_RIGHT 2
409#define INVISIBLE 4
410#define UNSORTABLE 8
411
412GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
413{
414 GtkCellRenderer *renderer;
415 GtkTreeViewColumn *col;
416 double xalign = 0.0; /* left as default */
417 PangoAlignment align;
418 gboolean visible;
419
420 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
421 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
422 PANGO_ALIGN_CENTER;
423 visible = !(flags & INVISIBLE);
424
425 renderer = gtk_cell_renderer_text_new();
426 col = gtk_tree_view_column_new();
427
428 gtk_tree_view_column_set_title(col, title);
429 if (!(flags & UNSORTABLE))
430 gtk_tree_view_column_set_sort_column_id(col, index);
431 gtk_tree_view_column_set_resizable(col, TRUE);
432 gtk_tree_view_column_pack_start(col, renderer, TRUE);
433 gtk_tree_view_column_add_attribute(col, renderer, "text", index);
434 gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
435 switch (align) {
436 case PANGO_ALIGN_LEFT:
437 xalign = 0.0;
438 break;
439 case PANGO_ALIGN_CENTER:
440 xalign = 0.5;
441 break;
442 case PANGO_ALIGN_RIGHT:
443 xalign = 1.0;
444 break;
445 }
446 gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
447 gtk_tree_view_column_set_visible(col, visible);
448 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
449 return col;
450}
451
Jens Axboe9b260bd2012-03-06 11:02:52 +0100452static void gfio_ui_setup_log(struct gui *ui)
453{
454 GtkTreeSelection *selection;
455 GtkListStore *model;
456 GtkWidget *tree_view;
457
458 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
459
460 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
461 gtk_widget_set_can_focus(tree_view, FALSE);
462
463 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
464 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
Jens Axboe661f7412012-03-06 13:55:45 +0100465 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
466 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100467
468 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
469 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
470 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
Jens Axboef095d562012-03-06 13:49:12 +0100471 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100472
473 ui->log_model = model;
474 ui->log_tree = tree_view;
475}
476
Jens Axboea2697902012-03-05 16:43:49 +0100477static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
478 fio_fp64_t *plist,
479 unsigned int len,
480 const char *base,
481 unsigned int scale)
482{
483 GType types[FIO_IO_U_LIST_MAX_LEN];
484 GtkWidget *tree_view;
485 GtkTreeSelection *selection;
486 GtkListStore *model;
487 GtkTreeIter iter;
488 int i;
489
490 for (i = 0; i < len; i++)
491 types[i] = G_TYPE_INT;
492
493 model = gtk_list_store_newv(len, types);
494
495 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
496 gtk_widget_set_can_focus(tree_view, FALSE);
497
Jens Axboe661f7412012-03-06 13:55:45 +0100498 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
499 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
500
Jens Axboea2697902012-03-05 16:43:49 +0100501 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
502 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
503
504 for (i = 0; i < len; i++) {
505 char fbuf[8];
506
507 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
508 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
509 }
510
511 gtk_list_store_append(model, &iter);
512
Jens Axboee0681f32012-03-06 12:14:42 +0100513 for (i = 0; i < len; i++) {
514 if (scale)
515 ovals[i] = (ovals[i] + 999) / 1000;
Jens Axboea2697902012-03-05 16:43:49 +0100516 gtk_list_store_set(model, &iter, i, ovals[i], -1);
Jens Axboee0681f32012-03-06 12:14:42 +0100517 }
Jens Axboea2697902012-03-05 16:43:49 +0100518
519 return tree_view;
520}
521
522static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
523 int ddir)
524{
525 unsigned int *io_u_plat = ts->io_u_plat[ddir];
526 unsigned long nr = ts->clat_stat[ddir].samples;
527 fio_fp64_t *plist = ts->percentile_list;
528 unsigned int *ovals, len, minv, maxv, scale_down;
529 const char *base;
530 GtkWidget *tree_view, *frame, *hbox;
531 char tmp[64];
532
533 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
534 if (!len)
535 goto out;
536
537 /*
538 * We default to usecs, but if the value range is such that we
539 * should scale down to msecs, do that.
540 */
541 if (minv > 2000 && maxv > 99999) {
542 scale_down = 1;
543 base = "msec";
544 } else {
545 scale_down = 0;
546 base = "usec";
547 }
548
549 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
550
551 sprintf(tmp, "Completion percentiles (%s)", base);
552 frame = gtk_frame_new(tmp);
553 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
554
555 hbox = gtk_hbox_new(FALSE, 3);
556 gtk_container_add(GTK_CONTAINER(frame), hbox);
557
558 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
559out:
560 if (ovals)
561 free(ovals);
562}
563
Jens Axboe3650a3c2012-03-05 14:09:03 +0100564static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
565 unsigned long max, double mean, double dev)
566{
567 const char *base = "(usec)";
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100568 GtkWidget *hbox, *label, *frame;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100569 char *minp, *maxp;
570 char tmp[64];
571
572 if (!usec_to_msec(&min, &max, &mean, &dev))
573 base = "(msec)";
574
575 minp = num2str(min, 6, 1, 0);
576 maxp = num2str(max, 6, 1, 0);
577
Jens Axboe3650a3c2012-03-05 14:09:03 +0100578 sprintf(tmp, "%s %s", name, base);
579 frame = gtk_frame_new(tmp);
580 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
581
Jens Axboe3650a3c2012-03-05 14:09:03 +0100582 hbox = gtk_hbox_new(FALSE, 3);
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100583 gtk_container_add(GTK_CONTAINER(frame), hbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100584
585 label = new_info_label_in_frame(hbox, "Minimum");
586 gtk_label_set_text(GTK_LABEL(label), minp);
587 label = new_info_label_in_frame(hbox, "Maximum");
588 gtk_label_set_text(GTK_LABEL(label), maxp);
589 label = new_info_label_in_frame(hbox, "Average");
590 sprintf(tmp, "%5.02f", mean);
591 gtk_label_set_text(GTK_LABEL(label), tmp);
592 label = new_info_label_in_frame(hbox, "Standard deviation");
593 sprintf(tmp, "%5.02f", dev);
594 gtk_label_set_text(GTK_LABEL(label), tmp);
595
596 free(minp);
597 free(maxp);
598
599}
600
Jens Axboeca850992012-03-05 20:04:43 +0100601#define GFIO_CLAT 1
602#define GFIO_SLAT 2
603#define GFIO_LAT 4
604
Jens Axboe3650a3c2012-03-05 14:09:03 +0100605static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
606 struct thread_stat *ts, int ddir)
607{
608 const char *ddir_label[2] = { "Read", "Write" };
Jens Axboe0b761302012-03-05 20:44:11 +0100609 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
Jens Axboee0681f32012-03-06 12:14:42 +0100610 unsigned long min[3], max[3], runt;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100611 unsigned long long bw, iops;
Jens Axboeca850992012-03-05 20:04:43 +0100612 unsigned int flags = 0;
Jens Axboee0681f32012-03-06 12:14:42 +0100613 double mean[3], dev[3];
Jens Axboe3650a3c2012-03-05 14:09:03 +0100614 char *io_p, *bw_p, *iops_p;
615 int i2p;
616
617 if (!ts->runtime[ddir])
618 return;
619
620 i2p = is_power_of_2(rs->kb_base);
621 runt = ts->runtime[ddir];
622
623 bw = (1000 * ts->io_bytes[ddir]) / runt;
624 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
625 bw_p = num2str(bw, 6, 1, i2p);
626
627 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
628 iops_p = num2str(iops, 6, 1, 0);
629
630 box = gtk_hbox_new(FALSE, 3);
631 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
632
633 frame = gtk_frame_new(ddir_label[ddir]);
634 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
635
Jens Axboe0b761302012-03-05 20:44:11 +0100636 main_vbox = gtk_vbox_new(FALSE, 3);
637 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100638
639 box = gtk_hbox_new(FALSE, 3);
Jens Axboe0b761302012-03-05 20:44:11 +0100640 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100641
642 label = new_info_label_in_frame(box, "IO");
643 gtk_label_set_text(GTK_LABEL(label), io_p);
644 label = new_info_label_in_frame(box, "Bandwidth");
645 gtk_label_set_text(GTK_LABEL(label), bw_p);
646 label = new_info_label_in_frame(box, "IOPS");
647 gtk_label_set_text(GTK_LABEL(label), iops_p);
648 label = new_info_label_in_frame(box, "Runtime (msec)");
649 label_set_int_value(label, ts->runtime[ddir]);
650
Jens Axboee0681f32012-03-06 12:14:42 +0100651 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
Jens Axboeca850992012-03-05 20:04:43 +0100652 double p_of_agg = 100.0;
653 const char *bw_str = "KB";
654 char tmp[32];
655
656 if (rs->agg[ddir]) {
Jens Axboee0681f32012-03-06 12:14:42 +0100657 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
Jens Axboeca850992012-03-05 20:04:43 +0100658 if (p_of_agg > 100.0)
659 p_of_agg = 100.0;
660 }
661
Jens Axboee0681f32012-03-06 12:14:42 +0100662 if (mean[0] > 999999.9) {
663 min[0] /= 1000.0;
664 max[0] /= 1000.0;
665 mean[0] /= 1000.0;
666 dev[0] /= 1000.0;
Jens Axboeca850992012-03-05 20:04:43 +0100667 bw_str = "MB";
668 }
669
Jens Axboe0b761302012-03-05 20:44:11 +0100670 sprintf(tmp, "Bandwidth (%s)", bw_str);
671 frame = gtk_frame_new(tmp);
672 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
Jens Axboeca850992012-03-05 20:04:43 +0100673
Jens Axboe0b761302012-03-05 20:44:11 +0100674 box = gtk_hbox_new(FALSE, 3);
675 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboeca850992012-03-05 20:04:43 +0100676
Jens Axboe0b761302012-03-05 20:44:11 +0100677 label = new_info_label_in_frame(box, "Minimum");
Jens Axboee0681f32012-03-06 12:14:42 +0100678 label_set_int_value(label, min[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100679 label = new_info_label_in_frame(box, "Maximum");
Jens Axboee0681f32012-03-06 12:14:42 +0100680 label_set_int_value(label, max[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100681 label = new_info_label_in_frame(box, "Percentage of jobs");
Jens Axboeca850992012-03-05 20:04:43 +0100682 sprintf(tmp, "%3.2f%%", p_of_agg);
683 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100684 label = new_info_label_in_frame(box, "Average");
Jens Axboee0681f32012-03-06 12:14:42 +0100685 sprintf(tmp, "%5.02f", mean[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100686 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100687 label = new_info_label_in_frame(box, "Standard deviation");
Jens Axboee0681f32012-03-06 12:14:42 +0100688 sprintf(tmp, "%5.02f", dev[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100689 gtk_label_set_text(GTK_LABEL(label), tmp);
690 }
691
Jens Axboee0681f32012-03-06 12:14:42 +0100692 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
Jens Axboe2b089892012-03-06 08:09:17 +0100693 flags |= GFIO_SLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100694 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
Jens Axboe2b089892012-03-06 08:09:17 +0100695 flags |= GFIO_CLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100696 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
Jens Axboe2b089892012-03-06 08:09:17 +0100697 flags |= GFIO_LAT;
698
699 if (flags) {
700 frame = gtk_frame_new("Latency");
701 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
702
703 vbox = gtk_vbox_new(FALSE, 3);
704 gtk_container_add(GTK_CONTAINER(frame), vbox);
705
706 if (flags & GFIO_SLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100707 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
Jens Axboe2b089892012-03-06 08:09:17 +0100708 if (flags & GFIO_CLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100709 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
Jens Axboe2b089892012-03-06 08:09:17 +0100710 if (flags & GFIO_LAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100711 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
Jens Axboe2b089892012-03-06 08:09:17 +0100712 }
713
714 if (ts->clat_percentiles)
715 gfio_show_clat_percentiles(main_vbox, ts, ddir);
716
717
Jens Axboe3650a3c2012-03-05 14:09:03 +0100718 free(io_p);
719 free(bw_p);
720 free(iops_p);
721}
722
Jens Axboee5bd1342012-03-05 21:38:12 +0100723static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
724 const char **labels)
725{
726 GtkWidget *tree_view;
727 GtkTreeSelection *selection;
728 GtkListStore *model;
729 GtkTreeIter iter;
730 GType *types;
731 int i, skipped;
732
733 /*
734 * Check if all are empty, in which case don't bother
735 */
736 for (i = 0, skipped = 0; i < num; i++)
737 if (lat[i] <= 0.0)
738 skipped++;
739
740 if (skipped == num)
741 return NULL;
742
743 types = malloc(num * sizeof(GType));
744
745 for (i = 0; i < num; i++)
746 types[i] = G_TYPE_STRING;
747
748 model = gtk_list_store_newv(num, types);
749 free(types);
750 types = NULL;
751
752 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
753 gtk_widget_set_can_focus(tree_view, FALSE);
754
Jens Axboe661f7412012-03-06 13:55:45 +0100755 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
756 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
757
Jens Axboee5bd1342012-03-05 21:38:12 +0100758 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
759 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
760
761 for (i = 0; i < num; i++)
762 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
763
764 gtk_list_store_append(model, &iter);
765
766 for (i = 0; i < num; i++) {
767 char fbuf[32];
768
769 if (lat[i] <= 0.0)
770 sprintf(fbuf, "0.00");
771 else
772 sprintf(fbuf, "%3.2f%%", lat[i]);
773
774 gtk_list_store_set(model, &iter, i, fbuf, -1);
775 }
776
777 return tree_view;
778}
779
780static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
781{
782 GtkWidget *box, *frame, *tree_view;
783 double io_u_lat_u[FIO_IO_U_LAT_U_NR];
784 double io_u_lat_m[FIO_IO_U_LAT_M_NR];
785 const char *uranges[] = { "2", "4", "10", "20", "50", "100",
786 "250", "500", "750", "1000", };
787 const char *mranges[] = { "2", "4", "10", "20", "50", "100",
788 "250", "500", "750", "1000", "2000",
789 ">= 2000", };
790
791 stat_calc_lat_u(ts, io_u_lat_u);
792 stat_calc_lat_m(ts, io_u_lat_m);
793
794 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
795 if (tree_view) {
796 frame = gtk_frame_new("Latency buckets (usec)");
797 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
798
799 box = gtk_hbox_new(FALSE, 3);
800 gtk_container_add(GTK_CONTAINER(frame), box);
801 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
802 }
803
804 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
805 if (tree_view) {
806 frame = gtk_frame_new("Latency buckets (msec)");
807 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
808
809 box = gtk_hbox_new(FALSE, 3);
810 gtk_container_add(GTK_CONTAINER(frame), box);
811 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
812 }
813}
814
Jens Axboe2e331012012-03-05 22:07:54 +0100815static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
816{
817 GtkWidget *box, *frame, *entry;
818 double usr_cpu, sys_cpu;
819 unsigned long runtime;
820 char tmp[32];
821
822 runtime = ts->total_run_time;
823 if (runtime) {
824 double runt = (double) runtime;
825
826 usr_cpu = (double) ts->usr_time * 100 / runt;
827 sys_cpu = (double) ts->sys_time * 100 / runt;
828 } else {
829 usr_cpu = 0;
830 sys_cpu = 0;
831 }
832
833 frame = gtk_frame_new("OS resources");
834 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
835
836 box = gtk_hbox_new(FALSE, 3);
837 gtk_container_add(GTK_CONTAINER(frame), box);
838
839 entry = new_info_entry_in_frame(box, "User CPU");
840 sprintf(tmp, "%3.2f%%", usr_cpu);
841 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
842 entry = new_info_entry_in_frame(box, "System CPU");
843 sprintf(tmp, "%3.2f%%", sys_cpu);
844 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
845 entry = new_info_entry_in_frame(box, "Context switches");
846 entry_set_int_value(entry, ts->ctx);
847 entry = new_info_entry_in_frame(box, "Major faults");
848 entry_set_int_value(entry, ts->majf);
849 entry = new_info_entry_in_frame(box, "Minor faults");
850 entry_set_int_value(entry, ts->minf);
851}
Jens Axboe19998db2012-03-06 09:17:59 +0100852static void gfio_add_sc_depths_tree(GtkListStore *model,
853 struct thread_stat *ts, unsigned int len,
854 int submit)
855{
856 double io_u_dist[FIO_IO_U_MAP_NR];
857 GtkTreeIter iter;
858 /* Bits 0, and 3-8 */
859 const int add_mask = 0x1f9;
860 int i, j;
861
862 if (submit)
863 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
864 else
865 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
866
867 gtk_list_store_append(model, &iter);
868
869 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
870
871 for (i = 1, j = 0; i < len; i++) {
872 char fbuf[32];
873
874 if (!(add_mask & (1UL << (i - 1))))
875 sprintf(fbuf, "0.0%%");
876 else {
877 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
878 j++;
879 }
880
881 gtk_list_store_set(model, &iter, i, fbuf, -1);
882 }
883
884}
885
886static void gfio_add_total_depths_tree(GtkListStore *model,
887 struct thread_stat *ts, unsigned int len)
888{
889 double io_u_dist[FIO_IO_U_MAP_NR];
890 GtkTreeIter iter;
891 /* Bits 1-6, and 8 */
892 const int add_mask = 0x17e;
893 int i, j;
894
895 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
896
897 gtk_list_store_append(model, &iter);
898
899 gtk_list_store_set(model, &iter, 0, "Total", -1);
900
901 for (i = 1, j = 0; i < len; i++) {
902 char fbuf[32];
903
904 if (!(add_mask & (1UL << (i - 1))))
905 sprintf(fbuf, "0.0%%");
906 else {
907 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
908 j++;
909 }
910
911 gtk_list_store_set(model, &iter, i, fbuf, -1);
912 }
913
914}
Jens Axboe2e331012012-03-05 22:07:54 +0100915
916static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
917{
Jens Axboe2e331012012-03-05 22:07:54 +0100918 GtkWidget *frame, *box, *tree_view;
919 GtkTreeSelection *selection;
920 GtkListStore *model;
Jens Axboe2e331012012-03-05 22:07:54 +0100921 GType types[FIO_IO_U_MAP_NR + 1];
922 int i;
Jens Axboe19998db2012-03-06 09:17:59 +0100923#define NR_LABELS 10
924 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
Jens Axboe2e331012012-03-05 22:07:54 +0100925
926 frame = gtk_frame_new("IO depths");
927 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
928
929 box = gtk_hbox_new(FALSE, 3);
930 gtk_container_add(GTK_CONTAINER(frame), box);
931
Jens Axboe19998db2012-03-06 09:17:59 +0100932 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100933 types[i] = G_TYPE_STRING;
934
Jens Axboe19998db2012-03-06 09:17:59 +0100935 model = gtk_list_store_newv(NR_LABELS, types);
Jens Axboe2e331012012-03-05 22:07:54 +0100936
937 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
938 gtk_widget_set_can_focus(tree_view, FALSE);
939
Jens Axboe661f7412012-03-06 13:55:45 +0100940 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
941 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
942
Jens Axboe2e331012012-03-05 22:07:54 +0100943 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
944 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
945
Jens Axboe19998db2012-03-06 09:17:59 +0100946 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100947 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
948
Jens Axboe19998db2012-03-06 09:17:59 +0100949 gfio_add_total_depths_tree(model, ts, NR_LABELS);
950 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 1);
951 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 0);
Jens Axboe2e331012012-03-05 22:07:54 +0100952
953 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
954}
955
Jens Axboef9d40b42012-03-06 09:52:49 +0100956static gboolean results_window_delete(GtkWidget *w, gpointer data)
957{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100958 struct gui_entry *ge = (struct gui_entry *) data;
Jens Axboef9d40b42012-03-06 09:52:49 +0100959
960 gtk_widget_destroy(w);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100961 ge->results_window = NULL;
962 ge->results_notebook = NULL;
Jens Axboef9d40b42012-03-06 09:52:49 +0100963 return TRUE;
964}
965
Jens Axboe2f99deb2012-03-09 14:37:29 +0100966static GtkWidget *get_results_window(struct gui_entry *ge)
Jens Axboef9d40b42012-03-06 09:52:49 +0100967{
968 GtkWidget *win, *notebook;
969
Jens Axboe2f99deb2012-03-09 14:37:29 +0100970 if (ge->results_window)
971 return ge->results_notebook;
Jens Axboef9d40b42012-03-06 09:52:49 +0100972
973 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
974 gtk_window_set_title(GTK_WINDOW(win), "Results");
Jens Axboeb01329d2012-03-07 20:31:28 +0100975 gtk_window_set_default_size(GTK_WINDOW(win), 1024, 768);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100976 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ge);
977 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ge);
Jens Axboef9d40b42012-03-06 09:52:49 +0100978
979 notebook = gtk_notebook_new();
Jens Axboe0aa928c2012-03-09 17:24:07 +0100980 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), 1);
981 gtk_notebook_popup_enable(GTK_NOTEBOOK(notebook));
Jens Axboef9d40b42012-03-06 09:52:49 +0100982 gtk_container_add(GTK_CONTAINER(win), notebook);
983
Jens Axboe2f99deb2012-03-09 14:37:29 +0100984 ge->results_window = win;
985 ge->results_notebook = notebook;
986 return ge->results_notebook;
Jens Axboef9d40b42012-03-06 09:52:49 +0100987}
988
Jens Axboe3650a3c2012-03-05 14:09:03 +0100989static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
990 struct group_run_stats *rs)
991{
Jens Axboeb01329d2012-03-07 20:31:28 +0100992 GtkWidget *res_win, *box, *vbox, *entry, *scroll;
Jens Axboee0681f32012-03-06 12:14:42 +0100993 struct gfio_client *gc = client->client_data;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100994
995 gdk_threads_enter();
996
Jens Axboe2f99deb2012-03-09 14:37:29 +0100997 res_win = get_results_window(gc->ge);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100998
Jens Axboeb01329d2012-03-07 20:31:28 +0100999 scroll = gtk_scrolled_window_new(NULL, NULL);
1000 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
1001 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1002
Jens Axboe3650a3c2012-03-05 14:09:03 +01001003 vbox = gtk_vbox_new(FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +01001004
Jens Axboeb01329d2012-03-07 20:31:28 +01001005 box = gtk_hbox_new(FALSE, 0);
1006 gtk_box_pack_start(GTK_BOX(vbox), box, TRUE, FALSE, 5);
Jens Axboe3650a3c2012-03-05 14:09:03 +01001007
Jens Axboeb01329d2012-03-07 20:31:28 +01001008 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
1009
1010 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), scroll, gtk_label_new(ts->name));
Jens Axboef9d40b42012-03-06 09:52:49 +01001011
Jens Axboee0681f32012-03-06 12:14:42 +01001012 gc->results_widget = vbox;
1013
Jens Axboe3650a3c2012-03-05 14:09:03 +01001014 entry = new_info_entry_in_frame(box, "Name");
1015 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
1016 if (strlen(ts->description)) {
1017 entry = new_info_entry_in_frame(box, "Description");
1018 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
1019 }
1020 entry = new_info_entry_in_frame(box, "Group ID");
1021 entry_set_int_value(entry, ts->groupid);
1022 entry = new_info_entry_in_frame(box, "Jobs");
1023 entry_set_int_value(entry, ts->members);
Jens Axboe6b79c802012-03-08 10:51:36 +01001024 gc->err_entry = entry = new_info_entry_in_frame(box, "Error");
Jens Axboe3650a3c2012-03-05 14:09:03 +01001025 entry_set_int_value(entry, ts->error);
1026 entry = new_info_entry_in_frame(box, "PID");
1027 entry_set_int_value(entry, ts->pid);
1028
1029 if (ts->io_bytes[DDIR_READ])
1030 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
1031 if (ts->io_bytes[DDIR_WRITE])
1032 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
1033
Jens Axboee5bd1342012-03-05 21:38:12 +01001034 gfio_show_latency_buckets(vbox, ts);
Jens Axboe2e331012012-03-05 22:07:54 +01001035 gfio_show_cpu_usage(vbox, ts);
1036 gfio_show_io_depths(vbox, ts);
Jens Axboee5bd1342012-03-05 21:38:12 +01001037
Jens Axboe2f99deb2012-03-09 14:37:29 +01001038 gtk_widget_show_all(gc->ge->results_window);
Jens Axboe3650a3c2012-03-05 14:09:03 +01001039 gdk_threads_leave();
1040}
1041
Jens Axboe084d1c62012-03-03 20:28:07 +01001042static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001043{
Jens Axboe9b260bd2012-03-06 11:02:52 +01001044 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001045 struct gui *ui = &main_ui;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001046 GtkTreeIter iter;
1047 struct tm *tm;
1048 time_t sec;
1049 char tmp[64], timebuf[80];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001050
Jens Axboe9b260bd2012-03-06 11:02:52 +01001051 sec = p->log_sec;
1052 tm = localtime(&sec);
1053 strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", tm);
1054 sprintf(timebuf, "%s.%03ld", tmp, p->log_usec / 1000);
1055
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001056 gdk_threads_enter();
Jens Axboe9b260bd2012-03-06 11:02:52 +01001057
Jens Axboe2f99deb2012-03-09 14:37:29 +01001058 gtk_list_store_append(ui->log_model, &iter);
1059 gtk_list_store_set(ui->log_model, &iter, 0, timebuf, -1);
1060 gtk_list_store_set(ui->log_model, &iter, 1, client->hostname, -1);
1061 gtk_list_store_set(ui->log_model, &iter, 2, p->level, -1);
1062 gtk_list_store_set(ui->log_model, &iter, 3, p->buf, -1);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001063
Jens Axboe6b79c802012-03-08 10:51:36 +01001064 if (p->level == FIO_LOG_ERR)
Jens Axboe2f99deb2012-03-09 14:37:29 +01001065 view_log(NULL, (gpointer) ui);
Jens Axboe6b79c802012-03-08 10:51:36 +01001066
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001067 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001068}
1069
1070static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
1071{
Jens Axboee0681f32012-03-06 12:14:42 +01001072 struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
1073 struct gfio_client *gc = client->client_data;
1074 GtkWidget *box, *frame, *entry, *vbox;
Jens Axboe604cfe32012-03-07 19:51:36 +01001075 double util;
1076 char tmp[16];
Jens Axboee0681f32012-03-06 12:14:42 +01001077
Jens Axboe0050e5f2012-03-06 09:23:27 +01001078 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +01001079
Jens Axboe45dcb2e2012-03-07 16:16:50 +01001080 if (!gc->results_widget)
Jens Axboee0681f32012-03-06 12:14:42 +01001081 goto out;
Jens Axboee0681f32012-03-06 12:14:42 +01001082
1083 if (!gc->disk_util_frame) {
1084 gc->disk_util_frame = gtk_frame_new("Disk utilization");
1085 gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
1086 }
1087
1088 vbox = gtk_vbox_new(FALSE, 3);
1089 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
1090
1091 frame = gtk_frame_new((char *) p->dus.name);
1092 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
1093
1094 box = gtk_vbox_new(FALSE, 3);
1095 gtk_container_add(GTK_CONTAINER(frame), box);
1096
1097 frame = gtk_frame_new("Read");
1098 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1099 vbox = gtk_hbox_new(TRUE, 3);
1100 gtk_container_add(GTK_CONTAINER(frame), vbox);
1101 entry = new_info_entry_in_frame(vbox, "IOs");
1102 entry_set_int_value(entry, p->dus.ios[0]);
1103 entry = new_info_entry_in_frame(vbox, "Merges");
1104 entry_set_int_value(entry, p->dus.merges[0]);
1105 entry = new_info_entry_in_frame(vbox, "Sectors");
1106 entry_set_int_value(entry, p->dus.sectors[0]);
1107 entry = new_info_entry_in_frame(vbox, "Ticks");
1108 entry_set_int_value(entry, p->dus.ticks[0]);
1109
1110 frame = gtk_frame_new("Write");
1111 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1112 vbox = gtk_hbox_new(TRUE, 3);
1113 gtk_container_add(GTK_CONTAINER(frame), vbox);
1114 entry = new_info_entry_in_frame(vbox, "IOs");
1115 entry_set_int_value(entry, p->dus.ios[1]);
1116 entry = new_info_entry_in_frame(vbox, "Merges");
1117 entry_set_int_value(entry, p->dus.merges[1]);
1118 entry = new_info_entry_in_frame(vbox, "Sectors");
1119 entry_set_int_value(entry, p->dus.sectors[1]);
1120 entry = new_info_entry_in_frame(vbox, "Ticks");
1121 entry_set_int_value(entry, p->dus.ticks[1]);
1122
1123 frame = gtk_frame_new("Shared");
1124 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1125 vbox = gtk_hbox_new(TRUE, 3);
1126 gtk_container_add(GTK_CONTAINER(frame), vbox);
1127 entry = new_info_entry_in_frame(vbox, "IO ticks");
1128 entry_set_int_value(entry, p->dus.io_ticks);
1129 entry = new_info_entry_in_frame(vbox, "Time in queue");
1130 entry_set_int_value(entry, p->dus.time_in_queue);
1131
Jens Axboe604cfe32012-03-07 19:51:36 +01001132 util = 0.0;
1133 if (p->dus.msec)
1134 util = (double) 100 * p->dus.io_ticks / (double) p->dus.msec;
1135 if (util > 100.0)
1136 util = 100.0;
1137
1138 sprintf(tmp, "%3.2f%%", util);
1139 entry = new_info_entry_in_frame(vbox, "Disk utilization");
1140 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
1141
Jens Axboee0681f32012-03-06 12:14:42 +01001142 gtk_widget_show_all(gc->results_widget);
1143out:
Jens Axboe0050e5f2012-03-06 09:23:27 +01001144 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001145}
1146
Jens Axboe3650a3c2012-03-05 14:09:03 +01001147extern int sum_stat_clients;
1148extern struct thread_stat client_ts;
1149extern struct group_run_stats client_gs;
1150
1151static int sum_stat_nr;
1152
Jens Axboe89e5fad2012-03-05 09:21:12 +01001153static void gfio_thread_status_op(struct fio_client *client,
1154 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001155{
Jens Axboe3650a3c2012-03-05 14:09:03 +01001156 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
1157
1158 gfio_display_ts(client, &p->ts, &p->rs);
1159
1160 if (sum_stat_clients == 1)
1161 return;
1162
1163 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
1164 sum_group_stats(&client_gs, &p->rs);
1165
1166 client_ts.members++;
1167 client_ts.groupid = p->ts.groupid;
1168
1169 if (++sum_stat_nr == sum_stat_clients) {
1170 strcpy(client_ts.name, "All clients");
1171 gfio_display_ts(client, &client_ts, &client_gs);
1172 }
Stephen M. Camerona1820202012-02-24 08:17:31 +01001173}
1174
Jens Axboe89e5fad2012-03-05 09:21:12 +01001175static void gfio_group_stats_op(struct fio_client *client,
1176 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001177{
Jens Axboe98ceabd2012-03-09 08:53:28 +01001178 /* We're ignoring group stats for now */
Stephen M. Camerona1820202012-02-24 08:17:31 +01001179}
1180
Jens Axboe2f99deb2012-03-09 14:37:29 +01001181static gint on_config_drawing_area(GtkWidget *w, GdkEventConfigure *event,
1182 gpointer data)
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001183{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001184 struct gfio_graphs *g = data;
1185
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001186 graph_set_size(g->iops_graph, w->allocation.width / 2.0, w->allocation.height);
1187 graph_set_position(g->iops_graph, w->allocation.width / 2.0, 0.0);
1188 graph_set_size(g->bandwidth_graph, w->allocation.width / 2.0, w->allocation.height);
1189 graph_set_position(g->bandwidth_graph, 0, 0);
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001190 return TRUE;
1191}
1192
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001193static void draw_graph(struct graph *g, cairo_t *cr)
1194{
1195 line_graph_draw(g, cr);
1196 cairo_stroke(cr);
1197}
1198
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001199static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
1200{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001201 struct gfio_graphs *g = p;
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001202 cairo_t *cr;
1203
1204 cr = gdk_cairo_create(w->window);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001205 cairo_set_source_rgb(cr, 0, 0, 0);
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001206 draw_graph(g->iops_graph, cr);
1207 draw_graph(g->bandwidth_graph, cr);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001208 cairo_destroy(cr);
1209
1210 return FALSE;
1211}
1212
Jens Axboe2f99deb2012-03-09 14:37:29 +01001213/*
1214 * Client specific ETA
1215 */
1216static void gfio_update_client_eta(struct fio_client *client, struct jobs_eta *je)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001217{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001218 struct gfio_client *gc = client->client_data;
1219 struct gui_entry *ge = gc->ge;
Jens Axboe3e47bd22012-02-29 13:45:02 +01001220 static int eta_good;
1221 char eta_str[128];
1222 char output[256];
1223 char tmp[32];
1224 double perc = 0.0;
1225 int i2p = 0;
1226
Jens Axboe0050e5f2012-03-06 09:23:27 +01001227 gdk_threads_enter();
1228
Jens Axboe3e47bd22012-02-29 13:45:02 +01001229 eta_str[0] = '\0';
1230 output[0] = '\0';
1231
1232 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1233 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1234 eta_to_str(eta_str, je->eta_sec);
1235 }
1236
1237 sprintf(tmp, "%u", je->nr_running);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001238 gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001239 sprintf(tmp, "%u", je->files_open);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001240 gtk_entry_set_text(GTK_ENTRY(ge->eta.files), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001241
1242#if 0
1243 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1244 if (je->m_rate || je->t_rate) {
1245 char *tr, *mr;
1246
1247 mr = num2str(je->m_rate, 4, 0, i2p);
1248 tr = num2str(je->t_rate, 4, 0, i2p);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001249 gtk_entry_set_text(GTK_ENTRY(ge->eta);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001250 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1251 free(tr);
1252 free(mr);
1253 } else if (je->m_iops || je->t_iops)
1254 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
Jens Axboeebbd89c2012-03-02 11:21:13 +01001255
Jens Axboe2f99deb2012-03-09 14:37:29 +01001256 gtk_entry_set_text(GTK_ENTRY(ge->eta.cr_bw), "---");
1257 gtk_entry_set_text(GTK_ENTRY(ge->eta.cr_iops), "---");
1258 gtk_entry_set_text(GTK_ENTRY(ge->eta.cw_bw), "---");
1259 gtk_entry_set_text(GTK_ENTRY(ge->eta.cw_iops), "---");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001260#endif
1261
1262 if (je->eta_sec != INT_MAX && je->nr_running) {
1263 char *iops_str[2];
1264 char *rate_str[2];
1265
1266 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1267 strcpy(output, "-.-% done");
1268 else {
1269 eta_good = 1;
1270 perc *= 100.0;
1271 sprintf(output, "%3.1f%% done", perc);
1272 }
1273
1274 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1275 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1276
1277 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1278 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1279
Jens Axboe2f99deb2012-03-09 14:37:29 +01001280 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), rate_str[0]);
1281 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), iops_str[0]);
1282 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), rate_str[1]);
1283 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), iops_str[1]);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001284
Jens Axboe2f99deb2012-03-09 14:37:29 +01001285 graph_add_xy_data(ge->graphs.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1286 graph_add_xy_data(ge->graphs.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1287 graph_add_xy_data(ge->graphs.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1288 graph_add_xy_data(ge->graphs.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
1289
1290 free(rate_str[0]);
1291 free(rate_str[1]);
1292 free(iops_str[0]);
1293 free(iops_str[1]);
1294 }
1295
1296 if (eta_str[0]) {
1297 char *dst = output + strlen(output);
1298
1299 sprintf(dst, " - %s", eta_str);
1300 }
1301
Jens Axboe9988ca72012-03-09 15:14:06 +01001302 gfio_update_thread_status(ge, output, perc);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001303 gdk_threads_leave();
1304}
1305
1306/*
1307 * Update ETA in main window for all clients
1308 */
1309static void gfio_update_all_eta(struct jobs_eta *je)
1310{
1311 struct gui *ui = &main_ui;
1312 static int eta_good;
1313 char eta_str[128];
1314 char output[256];
1315 double perc = 0.0;
1316 int i2p = 0;
1317
1318 gdk_threads_enter();
1319
1320 eta_str[0] = '\0';
1321 output[0] = '\0';
1322
1323 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1324 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1325 eta_to_str(eta_str, je->eta_sec);
1326 }
1327
1328#if 0
1329 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1330 if (je->m_rate || je->t_rate) {
1331 char *tr, *mr;
1332
1333 mr = num2str(je->m_rate, 4, 0, i2p);
1334 tr = num2str(je->t_rate, 4, 0, i2p);
1335 gtk_entry_set_text(GTK_ENTRY(ui->eta);
1336 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1337 free(tr);
1338 free(mr);
1339 } else if (je->m_iops || je->t_iops)
1340 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
1341
1342 gtk_entry_set_text(GTK_ENTRY(ui->eta.cr_bw), "---");
1343 gtk_entry_set_text(GTK_ENTRY(ui->eta.cr_iops), "---");
1344 gtk_entry_set_text(GTK_ENTRY(ui->eta.cw_bw), "---");
1345 gtk_entry_set_text(GTK_ENTRY(ui->eta.cw_iops), "---");
1346#endif
1347
Jens Axboe3863d1a2012-03-09 17:39:05 +01001348 entry_set_int_value(ui->eta.jobs, je->nr_running);
1349
Jens Axboe2f99deb2012-03-09 14:37:29 +01001350 if (je->eta_sec != INT_MAX && je->nr_running) {
1351 char *iops_str[2];
1352 char *rate_str[2];
1353
1354 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1355 strcpy(output, "-.-% done");
1356 else {
1357 eta_good = 1;
1358 perc *= 100.0;
1359 sprintf(output, "%3.1f%% done", perc);
1360 }
1361
1362 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1363 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1364
1365 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1366 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1367
1368 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), rate_str[0]);
1369 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), iops_str[0]);
1370 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), rate_str[1]);
1371 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), iops_str[1]);
1372
1373 graph_add_xy_data(ui->graphs.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1374 graph_add_xy_data(ui->graphs.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1375 graph_add_xy_data(ui->graphs.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1376 graph_add_xy_data(ui->graphs.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001377
Jens Axboe3e47bd22012-02-29 13:45:02 +01001378 free(rate_str[0]);
1379 free(rate_str[1]);
1380 free(iops_str[0]);
1381 free(iops_str[1]);
1382 }
1383
1384 if (eta_str[0]) {
1385 char *dst = output + strlen(output);
1386
1387 sprintf(dst, " - %s", eta_str);
1388 }
1389
Jens Axboe9988ca72012-03-09 15:14:06 +01001390 gfio_update_thread_status_all(output, perc);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001391 gdk_threads_leave();
Jens Axboe3e47bd22012-02-29 13:45:02 +01001392}
1393
Stephen M. Camerona1820202012-02-24 08:17:31 +01001394static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1395{
Jens Axboe843ad232012-02-29 11:44:53 +01001396 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001397 struct gfio_client *gc = client->client_data;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001398 struct gui_entry *ge = gc->ge;
Jens Axboe843ad232012-02-29 11:44:53 +01001399 const char *os, *arch;
1400 char buf[64];
1401
1402 os = fio_get_os_string(probe->os);
1403 if (!os)
1404 os = "unknown";
1405
1406 arch = fio_get_arch_string(probe->arch);
1407 if (!arch)
1408 os = "unknown";
1409
1410 if (!client->name)
1411 client->name = strdup((char *) probe->hostname);
1412
Jens Axboe0050e5f2012-03-06 09:23:27 +01001413 gdk_threads_enter();
1414
Jens Axboe2f99deb2012-03-09 14:37:29 +01001415 gtk_label_set_text(GTK_LABEL(ge->probe.hostname), (char *) probe->hostname);
1416 gtk_label_set_text(GTK_LABEL(ge->probe.os), os);
1417 gtk_label_set_text(GTK_LABEL(ge->probe.arch), arch);
Jens Axboe843ad232012-02-29 11:44:53 +01001418 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001419 gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), buf);
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001420
Jens Axboe2f99deb2012-03-09 14:37:29 +01001421 gfio_set_connected(ge, 1);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001422
1423 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001424}
1425
Jens Axboe9988ca72012-03-09 15:14:06 +01001426static void gfio_update_thread_status(struct gui_entry *ge,
1427 char *status_message, double perc)
1428{
1429 static char message[100];
1430 const char *m = message;
1431
1432 strncpy(message, status_message, sizeof(message) - 1);
1433 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), m);
1434 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), perc / 100.0);
1435 gtk_widget_queue_draw(main_ui.window);
1436}
1437
1438static void gfio_update_thread_status_all(char *status_message, double perc)
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001439{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001440 struct gui *ui = &main_ui;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001441 static char message[100];
1442 const char *m = message;
1443
1444 strncpy(message, status_message, sizeof(message) - 1);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001445 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), m);
1446 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), perc / 100.0);
1447 gtk_widget_queue_draw(ui->window);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001448}
1449
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001450static void gfio_quit_op(struct fio_client *client)
1451{
Jens Axboee0681f32012-03-06 12:14:42 +01001452 struct gfio_client *gc = client->client_data;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001453
Jens Axboe0050e5f2012-03-06 09:23:27 +01001454 gdk_threads_enter();
Jens Axboe2f99deb2012-03-09 14:37:29 +01001455 gfio_set_connected(gc->ge, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001456 gdk_threads_leave();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001457}
1458
Jens Axboe807f9972012-03-02 10:25:24 +01001459static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1460{
1461 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +01001462 struct gfio_client *gc = client->client_data;
Jens Axboedcaeb602012-03-08 19:45:37 +01001463 struct thread_options *o = &gc->o;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001464 struct gui_entry *ge = gc->ge;
Jens Axboe807f9972012-03-02 10:25:24 +01001465 char tmp[8];
Jens Axboe807f9972012-03-02 10:25:24 +01001466
Jens Axboedcaeb602012-03-08 19:45:37 +01001467 convert_thread_options_to_cpu(o, &p->top);
Jens Axboe807f9972012-03-02 10:25:24 +01001468
Jens Axboe0050e5f2012-03-06 09:23:27 +01001469 gdk_threads_enter();
1470
Jens Axboe2f99deb2012-03-09 14:37:29 +01001471 gtk_label_set_text(GTK_LABEL(ge->page_label), (gchar *) o->name);
1472
Jens Axboe3863d1a2012-03-09 17:39:05 +01001473 gtk_combo_box_append_text(GTK_COMBO_BOX(ge->eta.names), (gchar *) o->name);
1474 gtk_combo_box_set_active(GTK_COMBO_BOX(ge->eta.names), 0);
1475
Jens Axboec80b74b2012-03-12 10:23:28 +01001476 multitext_add_entry(&ge->eta.iotype, ddir_str(o->td_ddir));
1477 multitext_add_entry(&ge->eta.ioengine, (const char *) o->ioengine);
Jens Axboe807f9972012-03-02 10:25:24 +01001478
Jens Axboedcaeb602012-03-08 19:45:37 +01001479 sprintf(tmp, "%u", o->iodepth);
Jens Axboec80b74b2012-03-12 10:23:28 +01001480 multitext_add_entry(&ge->eta.iodepth, tmp);
1481
1482 multitext_set_entry(&ge->eta.iotype, 0);
1483 multitext_set_entry(&ge->eta.ioengine, 0);
1484 multitext_set_entry(&ge->eta.iodepth, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001485
Jens Axboedcaeb602012-03-08 19:45:37 +01001486 gc->job_added++;
1487
Jens Axboe0050e5f2012-03-06 09:23:27 +01001488 gdk_threads_leave();
Jens Axboe807f9972012-03-02 10:25:24 +01001489}
1490
Jens Axboeed727a42012-03-02 12:14:40 +01001491static void gfio_client_timed_out(struct fio_client *client)
1492{
Jens Axboee0681f32012-03-06 12:14:42 +01001493 struct gfio_client *gc = client->client_data;
Jens Axboeed727a42012-03-02 12:14:40 +01001494 GtkWidget *dialog, *label, *content;
1495 char buf[256];
1496
1497 gdk_threads_enter();
1498
Jens Axboe2f99deb2012-03-09 14:37:29 +01001499 gfio_set_connected(gc->ge, 0);
1500 clear_ge_ui_info(gc->ge);
Jens Axboeed727a42012-03-02 12:14:40 +01001501
1502 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
1503
1504 dialog = gtk_dialog_new_with_buttons("Timed out!",
Jens Axboe2f99deb2012-03-09 14:37:29 +01001505 GTK_WINDOW(main_ui.window),
Jens Axboeed727a42012-03-02 12:14:40 +01001506 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1507 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1508
Jens Axboef1299092012-03-07 20:00:02 +01001509 /* gtk_dialog_get_content_area() is 2.14 and newer */
1510 content = GTK_DIALOG(dialog)->vbox;
1511
Jens Axboeed727a42012-03-02 12:14:40 +01001512 label = gtk_label_new((const gchar *) buf);
1513 gtk_container_add(GTK_CONTAINER(content), label);
1514 gtk_widget_show_all(dialog);
1515 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1516
1517 gtk_dialog_run(GTK_DIALOG(dialog));
1518 gtk_widget_destroy(dialog);
1519
1520 gdk_threads_leave();
1521}
1522
Jens Axboe6b79c802012-03-08 10:51:36 +01001523static void gfio_client_stop(struct fio_client *client, struct fio_net_cmd *cmd)
1524{
1525 struct gfio_client *gc = client->client_data;
1526
1527 gdk_threads_enter();
1528
Jens Axboe2f99deb2012-03-09 14:37:29 +01001529 gfio_set_connected(gc->ge, 0);
Jens Axboe6b79c802012-03-08 10:51:36 +01001530
1531 if (gc->err_entry)
1532 entry_set_int_value(gc->err_entry, client->error);
1533
1534 gdk_threads_leave();
1535}
1536
Stephen M. Camerona1820202012-02-24 08:17:31 +01001537struct client_ops gfio_client_ops = {
Jens Axboe0420ba62012-02-29 11:16:52 +01001538 .text_op = gfio_text_op,
1539 .disk_util = gfio_disk_util_op,
1540 .thread_status = gfio_thread_status_op,
1541 .group_stats = gfio_group_stats_op,
Jens Axboe2f99deb2012-03-09 14:37:29 +01001542 .jobs_eta = gfio_update_client_eta,
1543 .eta = gfio_update_all_eta,
Jens Axboe0420ba62012-02-29 11:16:52 +01001544 .probe = gfio_probe_op,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001545 .quit = gfio_quit_op,
Jens Axboe807f9972012-03-02 10:25:24 +01001546 .add_job = gfio_add_job_op,
Jens Axboeed727a42012-03-02 12:14:40 +01001547 .timed_out = gfio_client_timed_out,
Jens Axboe6b79c802012-03-08 10:51:36 +01001548 .stop = gfio_client_stop,
Jens Axboe6433ee02012-03-09 20:10:51 +01001549 .eta_msec = FIO_CLIENT_DEF_ETA_MSEC,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001550 .stay_connected = 1,
Stephen M. Camerona1820202012-02-24 08:17:31 +01001551};
1552
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001553static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1554 __attribute__((unused)) gpointer data)
1555{
1556 gtk_main_quit();
1557}
1558
Stephen M. Cameron25927252012-02-24 08:17:31 +01001559static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001560{
Jens Axboea9eccde2012-03-09 14:59:42 +01001561 struct gui *ui = arg;
1562
1563 ui->handler_running = 1;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001564 fio_handle_clients(&gfio_client_ops);
Jens Axboea9eccde2012-03-09 14:59:42 +01001565 ui->handler_running = 0;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001566 return NULL;
1567}
1568
Jens Axboe2f99deb2012-03-09 14:37:29 +01001569static int send_job_files(struct gui_entry *ge)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001570{
Jens Axboe9988ca72012-03-09 15:14:06 +01001571 struct gfio_client *gc = ge->client;
Jens Axboe441013b2012-03-01 08:01:52 +01001572 int i, ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001573
Jens Axboe2f99deb2012-03-09 14:37:29 +01001574 for (i = 0; i < ge->nr_job_files; i++) {
Jens Axboe9988ca72012-03-09 15:14:06 +01001575 ret = fio_client_send_ini(gc->client, ge->job_files[i]);
Jens Axboec7249262012-03-09 17:11:04 +01001576 if (ret < 0) {
1577 GError *error;
1578
1579 error = g_error_new(g_quark_from_string("fio"), 1, "Failed to send file %s: %s\n", ge->job_files[i], strerror(-ret));
1580 report_error(error);
1581 g_error_free(error);
1582 break;
1583 } else if (ret)
Jens Axboe441013b2012-03-01 08:01:52 +01001584 break;
1585
Jens Axboe2f99deb2012-03-09 14:37:29 +01001586 free(ge->job_files[i]);
1587 ge->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001588 }
Jens Axboe2f99deb2012-03-09 14:37:29 +01001589 while (i < ge->nr_job_files) {
1590 free(ge->job_files[i]);
1591 ge->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001592 i++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001593 }
1594
Jens Axboe441013b2012-03-01 08:01:52 +01001595 return ret;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001596}
1597
Jens Axboe63a130b2012-03-06 20:08:59 +01001598static void *server_thread(void *arg)
1599{
1600 is_backend = 1;
1601 gfio_server_running = 1;
1602 fio_start_server(NULL);
1603 gfio_server_running = 0;
1604 return NULL;
1605}
1606
Jens Axboe2f99deb2012-03-09 14:37:29 +01001607static void gfio_start_server(void)
Jens Axboe63a130b2012-03-06 20:08:59 +01001608{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001609 struct gui *ui = &main_ui;
1610
Jens Axboe63a130b2012-03-06 20:08:59 +01001611 if (!gfio_server_running) {
1612 gfio_server_running = 1;
1613 pthread_create(&ui->server_t, NULL, server_thread, NULL);
Jens Axboee34f6ad2012-03-06 20:47:15 +01001614 pthread_detach(ui->server_t);
Jens Axboe63a130b2012-03-06 20:08:59 +01001615 }
1616}
1617
Stephen M. Cameron25927252012-02-24 08:17:31 +01001618static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1619 gpointer data)
1620{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001621 struct gui_entry *ge = data;
1622 struct gfio_client *gc = ge->client;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001623
Jens Axboe2f99deb2012-03-09 14:37:29 +01001624 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 0);
1625 fio_start_client(gc->client);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001626}
1627
Jens Axboedf06f222012-03-02 13:32:04 +01001628static void file_open(GtkWidget *w, gpointer data);
1629
1630static void connect_clicked(GtkWidget *widget, gpointer data)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001631{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001632 struct gui_entry *ge = data;
1633 struct gfio_client *gc = ge->client;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001634
Jens Axboe2f99deb2012-03-09 14:37:29 +01001635 if (!ge->connected) {
Jens Axboec7249262012-03-09 17:11:04 +01001636 int ret;
1637
Jens Axboe2f99deb2012-03-09 14:37:29 +01001638 if (!ge->nr_job_files)
Jens Axboedf06f222012-03-02 13:32:04 +01001639 file_open(widget, data);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001640 if (!ge->nr_job_files)
1641 return;
1642
1643 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No jobs running");
1644 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
Jens Axboec7249262012-03-09 17:11:04 +01001645 ret = fio_client_connect(gc->client);
1646 if (!ret) {
Jens Axboea9eccde2012-03-09 14:59:42 +01001647 if (!ge->ui->handler_running)
1648 pthread_create(&ge->ui->t, NULL, job_thread, ge->ui);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001649 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 0);
1650 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 1);
Jens Axboec7249262012-03-09 17:11:04 +01001651 } else {
1652 GError *error;
1653
1654 error = g_error_new(g_quark_from_string("fio"), 1, "Failed to connect to %s: %s\n", ge->client->client->hostname, strerror(-ret));
1655 report_error(error);
1656 g_error_free(error);
Jens Axboe69406b92012-03-06 14:00:42 +01001657 }
Jens Axboedf06f222012-03-02 13:32:04 +01001658 } else {
Jens Axboe2f99deb2012-03-09 14:37:29 +01001659 fio_client_terminate(gc->client);
1660 gfio_set_connected(ge, 0);
1661 clear_ge_ui_info(ge);
Jens Axboedf06f222012-03-02 13:32:04 +01001662 }
Jens Axboe3e47bd22012-02-29 13:45:02 +01001663}
1664
Jens Axboeb9d2f302012-03-08 20:36:28 +01001665static void send_clicked(GtkWidget *widget, gpointer data)
1666{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001667 struct gui_entry *ge = data;
Jens Axboeb9d2f302012-03-08 20:36:28 +01001668
Jens Axboe2f99deb2012-03-09 14:37:29 +01001669 if (send_job_files(ge)) {
Jens Axboec7249262012-03-09 17:11:04 +01001670 GError *error;
1671
1672 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);
1673 report_error(error);
1674 g_error_free(error);
1675
Jens Axboe2f99deb2012-03-09 14:37:29 +01001676 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 1);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001677 }
1678
Jens Axboe2f99deb2012-03-09 14:37:29 +01001679 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 0);
1680 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 1);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001681}
1682
Jens Axboe2f99deb2012-03-09 14:37:29 +01001683static GtkWidget *add_button(GtkWidget *buttonbox,
1684 struct button_spec *buttonspec, gpointer data)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001685{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001686 GtkWidget *button = gtk_button_new_with_label(buttonspec->buttontext);
1687
1688 g_signal_connect(button, "clicked", G_CALLBACK(buttonspec->f), data);
1689 gtk_box_pack_start(GTK_BOX(buttonbox), button, FALSE, FALSE, 3);
1690 gtk_widget_set_tooltip_text(button, buttonspec->tooltiptext);
1691 gtk_widget_set_sensitive(button, !buttonspec->start_insensitive);
1692
1693 return button;
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001694}
1695
Jens Axboe2f99deb2012-03-09 14:37:29 +01001696static void add_buttons(struct gui_entry *ge, struct button_spec *buttonlist,
1697 int nbuttons)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001698{
1699 int i;
1700
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001701 for (i = 0; i < nbuttons; i++)
Jens Axboe2f99deb2012-03-09 14:37:29 +01001702 ge->button[i] = add_button(ge->buttonbox, &buttonlist[i], ge);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001703}
1704
Jens Axboe0420ba62012-02-29 11:16:52 +01001705static void on_info_bar_response(GtkWidget *widget, gint response,
1706 gpointer data)
1707{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001708 struct gui *ui = &main_ui;
1709
Jens Axboe0420ba62012-02-29 11:16:52 +01001710 if (response == GTK_RESPONSE_OK) {
1711 gtk_widget_destroy(widget);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001712 ui->error_info_bar = NULL;
Jens Axboe0420ba62012-02-29 11:16:52 +01001713 }
1714}
1715
Jens Axboedf06f222012-03-02 13:32:04 +01001716void report_error(GError *error)
Jens Axboe0420ba62012-02-29 11:16:52 +01001717{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001718 struct gui *ui = &main_ui;
1719
1720 if (ui->error_info_bar == NULL) {
1721 ui->error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
Jens Axboe0420ba62012-02-29 11:16:52 +01001722 GTK_RESPONSE_OK,
1723 NULL);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001724 g_signal_connect(ui->error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1725 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui->error_info_bar),
Jens Axboe0420ba62012-02-29 11:16:52 +01001726 GTK_MESSAGE_ERROR);
1727
Jens Axboe2f99deb2012-03-09 14:37:29 +01001728 ui->error_label = gtk_label_new(error->message);
1729 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui->error_info_bar));
1730 gtk_container_add(GTK_CONTAINER(container), ui->error_label);
Jens Axboe0420ba62012-02-29 11:16:52 +01001731
Jens Axboe2f99deb2012-03-09 14:37:29 +01001732 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->error_info_bar, FALSE, FALSE, 0);
1733 gtk_widget_show_all(ui->vbox);
Jens Axboe0420ba62012-02-29 11:16:52 +01001734 } else {
1735 char buffer[256];
1736 snprintf(buffer, sizeof(buffer), "Failed to open file.");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001737 gtk_label_set(GTK_LABEL(ui->error_label), buffer);
Jens Axboe0420ba62012-02-29 11:16:52 +01001738 }
1739}
1740
Jens Axboe62bc9372012-03-07 11:45:07 +01001741struct connection_widgets
1742{
1743 GtkWidget *hentry;
1744 GtkWidget *combo;
1745 GtkWidget *button;
1746};
1747
1748static void hostname_cb(GtkEntry *entry, gpointer data)
1749{
1750 struct connection_widgets *cw = data;
1751 int uses_net = 0, is_localhost = 0;
1752 const gchar *text;
1753 gchar *ctext;
1754
1755 /*
1756 * Check whether to display the 'auto start backend' box
1757 * or not. Show it if we are a localhost and using network,
1758 * or using a socket.
1759 */
1760 ctext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->combo));
1761 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
1762 uses_net = 1;
1763 g_free(ctext);
1764
1765 if (uses_net) {
1766 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
1767 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
1768 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
1769 !strcmp(text, "ip6-loopback"))
1770 is_localhost = 1;
1771 }
1772
1773 if (!uses_net || is_localhost) {
1774 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
1775 gtk_widget_set_sensitive(cw->button, 1);
1776 } else {
1777 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
1778 gtk_widget_set_sensitive(cw->button, 0);
1779 }
1780}
1781
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001782static int get_connection_details(char **host, int *port, int *type,
1783 int *server_start)
Jens Axboea7a42ce2012-03-02 13:12:04 +01001784{
Jens Axboe62bc9372012-03-07 11:45:07 +01001785 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
1786 struct connection_widgets cw;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001787 char *typeentry;
1788
1789 dialog = gtk_dialog_new_with_buttons("Connection details",
Jens Axboe2f99deb2012-03-09 14:37:29 +01001790 GTK_WINDOW(main_ui.window),
Jens Axboea7a42ce2012-03-02 13:12:04 +01001791 GTK_DIALOG_DESTROY_WITH_PARENT,
1792 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1793 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1794
1795 frame = gtk_frame_new("Hostname / socket name");
Jens Axboef1299092012-03-07 20:00:02 +01001796 /* gtk_dialog_get_content_area() is 2.14 and newer */
1797 vbox = GTK_DIALOG(dialog)->vbox;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001798 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1799
1800 box = gtk_vbox_new(FALSE, 6);
1801 gtk_container_add(GTK_CONTAINER(frame), box);
1802
1803 hbox = gtk_hbox_new(TRUE, 10);
1804 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe62bc9372012-03-07 11:45:07 +01001805 cw.hentry = gtk_entry_new();
1806 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
1807 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001808
1809 frame = gtk_frame_new("Port");
1810 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1811 box = gtk_vbox_new(FALSE, 10);
1812 gtk_container_add(GTK_CONTAINER(frame), box);
1813
1814 hbox = gtk_hbox_new(TRUE, 4);
1815 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1816 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1817
1818 frame = gtk_frame_new("Type");
1819 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1820 box = gtk_vbox_new(FALSE, 10);
1821 gtk_container_add(GTK_CONTAINER(frame), box);
1822
1823 hbox = gtk_hbox_new(TRUE, 4);
1824 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1825
Jens Axboe62bc9372012-03-07 11:45:07 +01001826 cw.combo = gtk_combo_box_new_text();
1827 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv4");
1828 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv6");
1829 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "local socket");
1830 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001831
Jens Axboe62bc9372012-03-07 11:45:07 +01001832 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001833
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001834 frame = gtk_frame_new("Options");
1835 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1836 box = gtk_vbox_new(FALSE, 10);
1837 gtk_container_add(GTK_CONTAINER(frame), box);
1838
1839 hbox = gtk_hbox_new(TRUE, 4);
1840 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1841
Jens Axboe62bc9372012-03-07 11:45:07 +01001842 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1843 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
1844 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.");
1845 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
1846
1847 /*
1848 * Connect edit signal, so we can show/not-show the auto start button
1849 */
1850 g_signal_connect(GTK_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
1851 g_signal_connect(GTK_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001852
Jens Axboea7a42ce2012-03-02 13:12:04 +01001853 gtk_widget_show_all(dialog);
1854
1855 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1856 gtk_widget_destroy(dialog);
1857 return 1;
1858 }
1859
Jens Axboe62bc9372012-03-07 11:45:07 +01001860 *host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001861 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1862
Jens Axboe62bc9372012-03-07 11:45:07 +01001863 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw.combo));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001864 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1865 *type = Fio_client_ipv4;
1866 else if (!strncmp(typeentry, "IPv6", 4))
1867 *type = Fio_client_ipv6;
1868 else
1869 *type = Fio_client_socket;
1870 g_free(typeentry);
1871
Jens Axboe62bc9372012-03-07 11:45:07 +01001872 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001873
Jens Axboea7a42ce2012-03-02 13:12:04 +01001874 gtk_widget_destroy(dialog);
1875 return 0;
1876}
1877
Jens Axboe2f99deb2012-03-09 14:37:29 +01001878static void gfio_client_added(struct gui_entry *ge, struct fio_client *client)
Jens Axboee0681f32012-03-06 12:14:42 +01001879{
1880 struct gfio_client *gc;
1881
1882 gc = malloc(sizeof(*gc));
1883 memset(gc, 0, sizeof(*gc));
Jens Axboe2f99deb2012-03-09 14:37:29 +01001884 gc->ge = ge;
Jens Axboe343cb4a2012-03-09 17:16:51 +01001885 gc->client = fio_get_client(client);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001886
Jens Axboe2f99deb2012-03-09 14:37:29 +01001887 ge->client = gc;
Jens Axboee0681f32012-03-06 12:14:42 +01001888
1889 client->client_data = gc;
1890}
1891
Jens Axboe2f99deb2012-03-09 14:37:29 +01001892static GtkWidget *new_client_page(struct gui_entry *ge);
1893
1894static struct gui_entry *alloc_new_gui_entry(struct gui *ui)
1895{
1896 struct gui_entry *ge;
1897
1898 ge = malloc(sizeof(*ge));
1899 memset(ge, 0, sizeof(*ge));
1900 INIT_FLIST_HEAD(&ge->list);
1901 flist_add_tail(&ge->list, &ui->list);
1902 ge->ui = ui;
1903 return ge;
1904}
1905
1906/*
1907 * FIXME: need more handling here
1908 */
1909static void ge_destroy(GtkWidget *w, gpointer data)
1910{
1911 struct gui_entry *ge = data;
Jens Axboe343cb4a2012-03-09 17:16:51 +01001912 struct gfio_client *gc = ge->client;
1913
1914 if (gc->client)
1915 fio_put_client(gc->client);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001916
1917 flist_del(&ge->list);
1918 free(ge);
1919}
1920
1921static struct gui_entry *get_new_ge_with_tab(const char *name)
1922{
1923 struct gui_entry *ge;
1924
1925 ge = alloc_new_gui_entry(&main_ui);
1926
1927 ge->vbox = new_client_page(ge);
1928 g_signal_connect(ge->vbox, "destroy", G_CALLBACK(ge_destroy), ge);
1929
1930 ge->page_label = gtk_label_new(name);
1931 ge->page_num = gtk_notebook_append_page(GTK_NOTEBOOK(main_ui.notebook), ge->vbox, ge->page_label);
1932
1933 gtk_widget_show_all(main_ui.window);
1934 return ge;
1935}
1936
1937static void file_new(GtkWidget *w, gpointer data)
1938{
1939 get_new_ge_with_tab("Untitled");
1940}
1941
1942/*
1943 * Return the 'ge' corresponding to the tab. If the active tab is the
1944 * main tab, open a new tab.
1945 */
1946static struct gui_entry *get_ge_from_page(unsigned int cur_page)
1947{
1948 struct flist_head *entry;
1949 struct gui_entry *ge;
1950
1951 if (!cur_page)
1952 return get_new_ge_with_tab("Untitled");
1953
1954 flist_for_each(entry, &main_ui.list) {
1955 ge = flist_entry(entry, struct gui_entry, list);
1956 if (ge->page_num == cur_page)
1957 return ge;
1958 }
1959
1960 return NULL;
1961}
1962
Jens Axboe0420ba62012-02-29 11:16:52 +01001963static void file_open(GtkWidget *w, gpointer data)
1964{
Jens Axboe63a130b2012-03-06 20:08:59 +01001965 struct gui *ui = data;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001966 GtkWidget *dialog;
Jens Axboe0420ba62012-02-29 11:16:52 +01001967 GSList *filenames, *fn_glist;
1968 GtkFileFilter *filter;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001969 char *host;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001970 int port, type, server_start;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001971 struct gui_entry *ge;
1972 gint cur_page;
1973
1974 /*
1975 * Creates new tab if current tab is the main window, or the
1976 * current tab already has a client.
1977 */
1978 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
1979 ge = get_ge_from_page(cur_page);
1980 if (ge->client)
1981 ge = get_new_ge_with_tab("Untitled");
1982
1983 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
Jens Axboe0420ba62012-02-29 11:16:52 +01001984
1985 dialog = gtk_file_chooser_dialog_new("Open File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001986 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001987 GTK_FILE_CHOOSER_ACTION_OPEN,
1988 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1989 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1990 NULL);
1991 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1992
1993 filter = gtk_file_filter_new();
1994 gtk_file_filter_add_pattern(filter, "*.fio");
1995 gtk_file_filter_add_pattern(filter, "*.job");
Jens Axboe2d262992012-03-07 08:19:30 +01001996 gtk_file_filter_add_pattern(filter, "*.ini");
Jens Axboe0420ba62012-02-29 11:16:52 +01001997 gtk_file_filter_add_mime_type(filter, "text/fio");
1998 gtk_file_filter_set_name(filter, "Fio job file");
1999 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
2000
2001 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
2002 gtk_widget_destroy(dialog);
2003 return;
2004 }
2005
2006 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Jens Axboea7a42ce2012-03-02 13:12:04 +01002007
2008 gtk_widget_destroy(dialog);
2009
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01002010 if (get_connection_details(&host, &port, &type, &server_start))
Jens Axboea7a42ce2012-03-02 13:12:04 +01002011 goto err;
2012
Jens Axboe0420ba62012-02-29 11:16:52 +01002013 filenames = fn_glist;
2014 while (filenames != NULL) {
Jens Axboee0681f32012-03-06 12:14:42 +01002015 struct fio_client *client;
2016
Jens Axboe2f99deb2012-03-09 14:37:29 +01002017 ge->job_files = realloc(ge->job_files, (ge->nr_job_files + 1) * sizeof(char *));
2018 ge->job_files[ge->nr_job_files] = strdup(filenames->data);
2019 ge->nr_job_files++;
Jens Axboe0420ba62012-02-29 11:16:52 +01002020
Jens Axboee0681f32012-03-06 12:14:42 +01002021 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
2022 if (!client) {
Jens Axboedf06f222012-03-02 13:32:04 +01002023 GError *error;
2024
2025 error = g_error_new(g_quark_from_string("fio"), 1,
2026 "Failed to add client %s", host);
Jens Axboe0420ba62012-02-29 11:16:52 +01002027 report_error(error);
2028 g_error_free(error);
Jens Axboe0420ba62012-02-29 11:16:52 +01002029 }
Jens Axboe2f99deb2012-03-09 14:37:29 +01002030 gfio_client_added(ge, client);
Jens Axboe0420ba62012-02-29 11:16:52 +01002031
2032 g_free(filenames->data);
2033 filenames = g_slist_next(filenames);
2034 }
Jens Axboea7a42ce2012-03-02 13:12:04 +01002035 free(host);
Jens Axboe63a130b2012-03-06 20:08:59 +01002036
2037 if (server_start)
Jens Axboe2f99deb2012-03-09 14:37:29 +01002038 gfio_start_server();
Jens Axboea7a42ce2012-03-02 13:12:04 +01002039err:
Jens Axboe0420ba62012-02-29 11:16:52 +01002040 g_slist_free(fn_glist);
Jens Axboe0420ba62012-02-29 11:16:52 +01002041}
2042
2043static void file_save(GtkWidget *w, gpointer data)
2044{
Jens Axboe63a130b2012-03-06 20:08:59 +01002045 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01002046 GtkWidget *dialog;
2047
2048 dialog = gtk_file_chooser_dialog_new("Save File",
Jens Axboe63a130b2012-03-06 20:08:59 +01002049 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01002050 GTK_FILE_CHOOSER_ACTION_SAVE,
2051 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2052 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
2053 NULL);
2054
2055 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
2056 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
2057
2058 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
2059 char *filename;
2060
2061 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
2062 // save_job_file(filename);
2063 g_free(filename);
2064 }
2065 gtk_widget_destroy(dialog);
2066}
2067
Jens Axboe9b260bd2012-03-06 11:02:52 +01002068static void view_log_destroy(GtkWidget *w, gpointer data)
2069{
2070 struct gui *ui = (struct gui *) data;
2071
2072 gtk_widget_ref(ui->log_tree);
2073 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
2074 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +01002075 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +01002076}
2077
2078static void view_log(GtkWidget *w, gpointer data)
2079{
Jens Axboe4cbe7212012-03-06 13:36:17 +01002080 GtkWidget *win, *scroll, *vbox, *box;
2081 struct gui *ui = (struct gui *) data;
Jens Axboe9b260bd2012-03-06 11:02:52 +01002082
Jens Axboe4cbe7212012-03-06 13:36:17 +01002083 if (ui->log_view)
2084 return;
2085
2086 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002087 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +01002088 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002089
Jens Axboe4cbe7212012-03-06 13:36:17 +01002090 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002091
Jens Axboe4cbe7212012-03-06 13:36:17 +01002092 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
2093
2094 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2095
2096 box = gtk_hbox_new(TRUE, 0);
2097 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
2098 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
2099 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
2100
2101 vbox = gtk_vbox_new(TRUE, 5);
2102 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
2103
2104 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002105 gtk_widget_show_all(win);
2106}
2107
Jens Axboe8577f4f2012-03-09 19:28:27 +01002108static void __update_graph_limits(struct gfio_graphs *g)
2109{
2110 line_graph_set_data_count_limit(g->iops_graph, gfio_graph_limit);
2111 line_graph_set_data_count_limit(g->bandwidth_graph, gfio_graph_limit);
2112}
2113
2114static void update_graph_limits(void)
2115{
2116 struct flist_head *entry;
2117 struct gui_entry *ge;
2118
2119 __update_graph_limits(&main_ui.graphs);
2120
2121 flist_for_each(entry, &main_ui.list) {
2122 ge = flist_entry(entry, struct gui_entry, list);
2123 __update_graph_limits(&ge->graphs);
2124 }
2125}
2126
Jens Axboe46974a72012-03-02 19:34:13 +01002127static void preferences(GtkWidget *w, gpointer data)
2128{
Jens Axboef3e84402012-03-07 13:14:32 +01002129 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002130 GtkWidget *hbox, *spin, *entry, *spin_int;
Jens Axboe46974a72012-03-02 19:34:13 +01002131 int i;
2132
2133 dialog = gtk_dialog_new_with_buttons("Preferences",
Jens Axboe2f99deb2012-03-09 14:37:29 +01002134 GTK_WINDOW(main_ui.window),
Jens Axboe46974a72012-03-02 19:34:13 +01002135 GTK_DIALOG_DESTROY_WITH_PARENT,
2136 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2137 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2138 NULL);
2139
Jens Axboe8577f4f2012-03-09 19:28:27 +01002140 frame = gtk_frame_new("Graphing");
Jens Axboef3e84402012-03-07 13:14:32 +01002141 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
2142 vbox = gtk_vbox_new(FALSE, 6);
2143 gtk_container_add(GTK_CONTAINER(frame), vbox);
2144
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002145 hbox = gtk_hbox_new(FALSE, 5);
2146 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
2147 entry = gtk_label_new("Font face to use for graph labels");
2148 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 5);
2149
Jens Axboef3e84402012-03-07 13:14:32 +01002150 font = gtk_font_button_new();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002151 gtk_box_pack_start(GTK_BOX(hbox), font, FALSE, FALSE, 5);
Jens Axboef3e84402012-03-07 13:14:32 +01002152
Jens Axboe8577f4f2012-03-09 19:28:27 +01002153 box = gtk_vbox_new(FALSE, 6);
2154 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
2155
2156 hbox = gtk_hbox_new(FALSE, 5);
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002157 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
Jens Axboe8577f4f2012-03-09 19:28:27 +01002158 entry = gtk_label_new("Maximum number of data points in graph (seconds)");
2159 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
2160
Jens Axboec05d9052012-03-11 13:05:35 +01002161 spin = create_spinbutton(hbox, 10, 1000000, gfio_graph_limit);
Jens Axboe8577f4f2012-03-09 19:28:27 +01002162
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002163 box = gtk_vbox_new(FALSE, 6);
2164 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
2165
2166 hbox = gtk_hbox_new(FALSE, 5);
2167 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
2168 entry = gtk_label_new("Client ETA request interval (msec)");
2169 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
2170
2171 spin_int = create_spinbutton(hbox, 100, 100000, gfio_client_ops.eta_msec);
Jens Axboea31d9fa2012-03-09 20:23:05 +01002172 frame = gtk_frame_new("Debug logging");
2173 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
2174 vbox = gtk_vbox_new(FALSE, 6);
2175 gtk_container_add(GTK_CONTAINER(frame), vbox);
2176
2177 box = gtk_hbox_new(FALSE, 6);
2178 gtk_container_add(GTK_CONTAINER(vbox), box);
2179
2180 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
2181
2182 for (i = 0; i < FD_DEBUG_MAX; i++) {
2183 if (i == 7) {
2184 box = gtk_hbox_new(FALSE, 6);
2185 gtk_container_add(GTK_CONTAINER(vbox), box);
2186 }
2187
2188
2189 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
2190 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
2191 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
2192 }
2193
Jens Axboe46974a72012-03-02 19:34:13 +01002194 gtk_widget_show_all(dialog);
2195
2196 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
2197 gtk_widget_destroy(dialog);
2198 return;
2199 }
2200
2201 for (i = 0; i < FD_DEBUG_MAX; i++) {
2202 int set;
2203
2204 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
2205 if (set)
2206 fio_debug |= (1UL << i);
2207 }
2208
Jens Axboef3e84402012-03-07 13:14:32 +01002209 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
Jens Axboe8577f4f2012-03-09 19:28:27 +01002210 gfio_graph_limit = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
2211 update_graph_limits();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002212 gfio_client_ops.eta_msec = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_int));
Jens Axboe8577f4f2012-03-09 19:28:27 +01002213
Jens Axboe46974a72012-03-02 19:34:13 +01002214 gtk_widget_destroy(dialog);
2215}
2216
Jens Axboe0420ba62012-02-29 11:16:52 +01002217static void about_dialog(GtkWidget *w, gpointer data)
2218{
Jens Axboe81e4ea62012-03-07 14:18:28 +01002219 const char *authors[] = {
2220 "Jens Axboe <axboe@kernel.dk>",
2221 "Stephen Carmeron <stephenmcameron@gmail.com>",
2222 NULL
2223 };
Jens Axboe84a72ed2012-03-07 14:24:57 +01002224 const char *license[] = {
2225 "Fio is free software; you can redistribute it and/or modify "
2226 "it under the terms of the GNU General Public License as published by "
2227 "the Free Software Foundation; either version 2 of the License, or "
2228 "(at your option) any later version.\n",
2229 "Fio is distributed in the hope that it will be useful, "
2230 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
2231 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
2232 "GNU General Public License for more details.\n",
2233 "You should have received a copy of the GNU General Public License "
2234 "along with Fio; if not, write to the Free Software Foundation, Inc., "
2235 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
2236 };
2237 char *license_trans;
2238
2239 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
2240 license[2], "\n", NULL);
Jens Axboe81e4ea62012-03-07 14:18:28 +01002241
Jens Axboe0420ba62012-02-29 11:16:52 +01002242 gtk_show_about_dialog(NULL,
2243 "program-name", "gfio",
2244 "comments", "Gtk2 UI for fio",
Jens Axboe84a72ed2012-03-07 14:24:57 +01002245 "license", license_trans,
Jens Axboe81e4ea62012-03-07 14:18:28 +01002246 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
2247 "authors", authors,
Jens Axboe0420ba62012-02-29 11:16:52 +01002248 "version", fio_version_string,
Jens Axboe81e4ea62012-03-07 14:18:28 +01002249 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
Jens Axboe0420ba62012-02-29 11:16:52 +01002250 "logo-icon-name", "fio",
2251 /* Must be last: */
Jens Axboe81e4ea62012-03-07 14:18:28 +01002252 "wrap-license", TRUE,
Jens Axboe0420ba62012-02-29 11:16:52 +01002253 NULL);
Jens Axboe84a72ed2012-03-07 14:24:57 +01002254
Jens Axboe2f99deb2012-03-09 14:37:29 +01002255 g_free(license_trans);
Jens Axboe0420ba62012-02-29 11:16:52 +01002256}
2257
2258static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01002259 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01002260 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01002261 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
Jens Axboe2f99deb2012-03-09 14:37:29 +01002262 { "NewFile", GTK_STOCK_NEW, "New", "<Control>N", NULL, G_CALLBACK(file_new) },
Jens Axboe46974a72012-03-02 19:34:13 +01002263 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
2264 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
2265 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01002266 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe46974a72012-03-02 19:34:13 +01002267 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
2268 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01002269};
Jens Axboe3e47bd22012-02-29 13:45:02 +01002270static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01002271
2272static const gchar *ui_string = " \
2273 <ui> \
2274 <menubar name=\"MainMenu\"> \
2275 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01002276 <menuitem name=\"New\" action=\"NewFile\" /> \
2277 <separator name=\"Separator1\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01002278 <menuitem name=\"Open\" action=\"OpenFile\" /> \
2279 <menuitem name=\"Save\" action=\"SaveFile\" /> \
Jens Axboe46974a72012-03-02 19:34:13 +01002280 <separator name=\"Separator2\"/> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01002281 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
2282 <separator name=\"Separator3\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01002283 <menuitem name=\"Quit\" action=\"Quit\" /> \
2284 </menu> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01002285 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
2286 <menuitem name=\"Log\" action=\"ViewLog\" /> \
2287 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01002288 <menu name=\"Help\" action=\"HelpMenuAction\"> \
2289 <menuitem name=\"About\" action=\"About\" /> \
2290 </menu> \
2291 </menubar> \
2292 </ui> \
2293";
2294
Jens Axboe4cbe7212012-03-06 13:36:17 +01002295static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
2296 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01002297{
2298 GtkActionGroup *action_group = gtk_action_group_new("Menu");
2299 GError *error = 0;
2300
2301 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01002302 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01002303
2304 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
2305 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
2306
2307 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
2308 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
2309}
2310
2311void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
2312 GtkWidget *vbox, GtkUIManager *ui_manager)
2313{
2314 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
2315}
2316
Jens Axboec80b74b2012-03-12 10:23:28 +01002317static void combo_entry_changed(GtkComboBox *box, gpointer data)
2318{
2319 struct gui_entry *ge = (struct gui_entry *) data;
2320 gint index;
2321
2322 index = gtk_combo_box_get_active(box);
2323
2324 multitext_set_entry(&ge->eta.iotype, index);
2325 multitext_set_entry(&ge->eta.ioengine, index);
2326 multitext_set_entry(&ge->eta.iodepth, index);
2327}
2328
2329static void combo_entry_destroy(GtkWidget *widget, gpointer data)
2330{
2331 struct gui_entry *ge = (struct gui_entry *) data;
2332
2333 multitext_free(&ge->eta.iotype);
2334 multitext_free(&ge->eta.ioengine);
2335 multitext_free(&ge->eta.iodepth);
2336}
2337
Jens Axboe2f99deb2012-03-09 14:37:29 +01002338static GtkWidget *new_client_page(struct gui_entry *ge)
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002339{
Jens Axboe2f99deb2012-03-09 14:37:29 +01002340 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01002341 GdkColor white;
Jens Axboe0420ba62012-02-29 11:16:52 +01002342
Jens Axboe2f99deb2012-03-09 14:37:29 +01002343 main_vbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01002344
Jens Axboe2f99deb2012-03-09 14:37:29 +01002345 ge->topalign = gtk_alignment_new(0, 0, 1, 0);
2346 ge->topvbox = gtk_vbox_new(FALSE, 3);
2347 gtk_container_add(GTK_CONTAINER(ge->topalign), ge->topvbox);
2348 gtk_box_pack_start(GTK_BOX(main_vbox), ge->topalign, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002349
Jens Axboe3e47bd22012-02-29 13:45:02 +01002350 probe = gtk_frame_new("Job");
Jens Axboe2f99deb2012-03-09 14:37:29 +01002351 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01002352 probe_frame = gtk_vbox_new(FALSE, 3);
2353 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
2354
2355 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002356 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2357 ge->probe.hostname = new_info_label_in_frame(probe_box, "Host");
2358 ge->probe.os = new_info_label_in_frame(probe_box, "OS");
2359 ge->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
2360 ge->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
Jens Axboe843ad232012-02-29 11:44:53 +01002361
Jens Axboe3e47bd22012-02-29 13:45:02 +01002362 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002363 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2364
Jens Axboe3863d1a2012-03-09 17:39:05 +01002365 ge->eta.names = new_combo_entry_in_frame(probe_box, "Jobs");
Jens Axboec80b74b2012-03-12 10:23:28 +01002366 g_signal_connect(ge->eta.names, "changed", G_CALLBACK(combo_entry_changed), ge);
2367 g_signal_connect(ge->eta.names, "destroy", G_CALLBACK(combo_entry_destroy), ge);
2368 ge->eta.iotype.entry = new_info_entry_in_frame(probe_box, "IO");
2369 ge->eta.ioengine.entry = new_info_entry_in_frame(probe_box, "IO Engine");
2370 ge->eta.iodepth.entry = new_info_entry_in_frame(probe_box, "IO Depth");
Jens Axboe2f99deb2012-03-09 14:37:29 +01002371 ge->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
2372 ge->eta.files = new_info_entry_in_frame(probe_box, "Open files");
2373
2374 probe_box = gtk_hbox_new(FALSE, 3);
2375 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2376 ge->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
2377 ge->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
2378 ge->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
2379 ge->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
2380
2381 /*
2382 * Only add this if we have a commit rate
2383 */
2384#if 0
2385 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe3e47bd22012-02-29 13:45:02 +01002386 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01002387
Jens Axboe2f99deb2012-03-09 14:37:29 +01002388 ge->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
2389 ge->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2390
2391 ge->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
2392 ge->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2393#endif
2394
2395 /*
2396 * Set up a drawing area and IOPS and bandwidth graphs
2397 */
2398 gdk_color_parse("white", &white);
2399 ge->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01002400 gtk_widget_set_size_request(GTK_WIDGET(ge->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01002401 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002402 gtk_widget_modify_bg(ge->graphs.drawing_area, GTK_STATE_NORMAL, &white);
2403 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "expose_event",
2404 G_CALLBACK(on_expose_drawing_area), &ge->graphs);
2405 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "configure_event",
2406 G_CALLBACK(on_config_drawing_area), &ge->graphs);
2407 ge->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2408 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ge->scrolled_window),
2409 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2410 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ge->scrolled_window),
2411 ge->graphs.drawing_area);
2412 gtk_box_pack_start(GTK_BOX(main_vbox), ge->scrolled_window,
2413 TRUE, TRUE, 0);
2414
2415 setup_graphs(&ge->graphs);
2416
2417 /*
2418 * Set up alignments for widgets at the bottom of ui,
2419 * align bottom left, expand horizontally but not vertically
2420 */
2421 ge->bottomalign = gtk_alignment_new(0, 1, 1, 0);
2422 ge->buttonbox = gtk_hbox_new(FALSE, 0);
2423 gtk_container_add(GTK_CONTAINER(ge->bottomalign), ge->buttonbox);
2424 gtk_box_pack_start(GTK_BOX(main_vbox), ge->bottomalign,
2425 FALSE, FALSE, 0);
2426
2427 add_buttons(ge, buttonspeclist, ARRAYSIZE(buttonspeclist));
2428
2429 /*
2430 * Set up thread status progress bar
2431 */
2432 ge->thread_status_pb = gtk_progress_bar_new();
2433 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
2434 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No connections");
2435 gtk_container_add(GTK_CONTAINER(ge->buttonbox), ge->thread_status_pb);
2436
2437
2438 return main_vbox;
2439}
2440
2441static GtkWidget *new_main_page(struct gui *ui)
2442{
2443 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
2444 GdkColor white;
2445
2446 main_vbox = gtk_vbox_new(FALSE, 3);
2447
2448 /*
2449 * Set up alignments for widgets at the top of ui,
2450 * align top left, expand horizontally but not vertically
2451 */
2452 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
2453 ui->topvbox = gtk_vbox_new(FALSE, 0);
2454 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
2455 gtk_box_pack_start(GTK_BOX(main_vbox), ui->topalign, FALSE, FALSE, 0);
2456
2457 probe = gtk_frame_new("Run statistics");
2458 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
2459 probe_frame = gtk_vbox_new(FALSE, 3);
2460 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
Jens Axboe3e47bd22012-02-29 13:45:02 +01002461
2462 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002463 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
Jens Axboe3863d1a2012-03-09 17:39:05 +01002464 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Running");
Jens Axboeca850992012-03-05 20:04:43 +01002465 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
2466 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
2467 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
2468 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01002469
2470 /*
2471 * Only add this if we have a commit rate
2472 */
2473#if 0
2474 probe_box = gtk_hbox_new(FALSE, 3);
2475 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
2476
Jens Axboe3e47bd22012-02-29 13:45:02 +01002477 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
2478 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2479
Jens Axboe3e47bd22012-02-29 13:45:02 +01002480 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
2481 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01002482#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01002483
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01002484 /*
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002485 * Set up a drawing area and IOPS and bandwidth graphs
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002486 */
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01002487 gdk_color_parse("white", &white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002488 ui->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01002489 gtk_widget_set_size_request(GTK_WIDGET(ui->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01002490 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002491 gtk_widget_modify_bg(ui->graphs.drawing_area, GTK_STATE_NORMAL, &white);
2492 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "expose_event",
2493 G_CALLBACK(on_expose_drawing_area), &ui->graphs);
2494 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "configure_event",
2495 G_CALLBACK(on_config_drawing_area), &ui->graphs);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002496 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2497 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
2498 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002499 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ui->scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01002500 ui->graphs.drawing_area);
2501 gtk_box_pack_start(GTK_BOX(main_vbox), ui->scrolled_window,
Stephen M. Camerone1645342012-02-24 08:17:32 +01002502 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002503
Jens Axboe2f99deb2012-03-09 14:37:29 +01002504 setup_graphs(&ui->graphs);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002505
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002506 /*
2507 * Set up alignments for widgets at the bottom of ui,
2508 * align bottom left, expand horizontally but not vertically
2509 */
2510 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
2511 ui->buttonbox = gtk_hbox_new(FALSE, 0);
2512 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002513 gtk_box_pack_start(GTK_BOX(main_vbox), ui->bottomalign,
Stephen M. Camerone1645342012-02-24 08:17:32 +01002514 FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002515
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002516 /*
2517 * Set up thread status progress bar
2518 */
2519 ui->thread_status_pb = gtk_progress_bar_new();
2520 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01002521 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002522 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
2523
Jens Axboe2f99deb2012-03-09 14:37:29 +01002524 return main_vbox;
2525}
2526
2527static gboolean notebook_switch_page(GtkNotebook *notebook, GtkWidget *widget,
2528 guint page, gpointer data)
2529
2530{
2531 return TRUE;
2532}
2533
2534static void init_ui(int *argc, char **argv[], struct gui *ui)
2535{
2536 GtkSettings *settings;
2537 GtkUIManager *uimanager;
2538 GtkWidget *menu, *vbox;
2539
2540 /* Magical g*thread incantation, you just need this thread stuff.
2541 * Without it, the update that happens in gfio_update_thread_status
2542 * doesn't really happen in a timely fashion, you need expose events
2543 */
2544 if (!g_thread_supported())
2545 g_thread_init(NULL);
2546 gdk_threads_init();
2547
2548 gtk_init(argc, argv);
2549 settings = gtk_settings_get_default();
2550 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
2551 g_type_init();
2552
2553 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2554 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
2555 gtk_window_set_default_size(GTK_WINDOW(ui->window), 1024, 768);
2556
2557 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
2558 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
2559
2560 ui->vbox = gtk_vbox_new(FALSE, 0);
2561 gtk_container_add(GTK_CONTAINER(ui->window), ui->vbox);
2562
2563 uimanager = gtk_ui_manager_new();
2564 menu = get_menubar_menu(ui->window, uimanager, ui);
2565 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
2566
2567 ui->notebook = gtk_notebook_new();
2568 g_signal_connect(ui->notebook, "switch-page", G_CALLBACK(notebook_switch_page), ui);
Jens Axboeb870c312012-03-09 17:22:01 +01002569 gtk_notebook_set_scrollable(GTK_NOTEBOOK(ui->notebook), 1);
Jens Axboe0aa928c2012-03-09 17:24:07 +01002570 gtk_notebook_popup_enable(GTK_NOTEBOOK(ui->notebook));
Jens Axboe2f99deb2012-03-09 14:37:29 +01002571 gtk_container_add(GTK_CONTAINER(ui->vbox), ui->notebook);
2572
2573 vbox = new_main_page(ui);
2574
2575 gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), vbox, gtk_label_new("Main"));
2576
Jens Axboe9b260bd2012-03-06 11:02:52 +01002577 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002578
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002579 gtk_widget_show_all(ui->window);
2580}
2581
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002582int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002583{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002584 if (initialize_fio(envp))
2585 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01002586 if (fio_init_options())
2587 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01002588
Jens Axboe2f99deb2012-03-09 14:37:29 +01002589 memset(&main_ui, 0, sizeof(main_ui));
2590 INIT_FLIST_HEAD(&main_ui.list);
2591
2592 init_ui(&argc, &argv, &main_ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01002593
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002594 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002595 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002596 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002597 return 0;
2598}