blob: b383f7147be2fedeabca07c5cf76543d40d61d18 [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>
Stephen M. Cameron8232e282012-02-24 08:17:31 +010026
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +010027#include <glib.h>
Jens Axboe2fd3bb02012-03-07 08:07:39 +010028#include <cairo.h>
Stephen M. Cameronff1f3282012-02-24 08:17:30 +010029#include <gtk/gtk.h>
30
Stephen M. Cameron8232e282012-02-24 08:17:31 +010031#include "fio.h"
Jens Axboe2fd3bb02012-03-07 08:07:39 +010032#include "graph.h"
Stephen M. Cameron8232e282012-02-24 08:17:31 +010033
Jens Axboe63a130b2012-03-06 20:08:59 +010034static int gfio_server_running;
35
Jens Axboe3e47bd22012-02-29 13:45:02 +010036static void gfio_update_thread_status(char *status_message, double perc);
37
Stephen M. Cameronf3074002012-02-24 08:17:30 +010038#define ARRAYSIZE(x) (sizeof((x)) / (sizeof((x)[0])))
39
40typedef void (*clickfunction)(GtkWidget *widget, gpointer data);
41
Jens Axboe3e47bd22012-02-29 13:45:02 +010042static void connect_clicked(GtkWidget *widget, gpointer data);
Stephen M. Cameronf3074002012-02-24 08:17:30 +010043static void start_job_clicked(GtkWidget *widget, gpointer data);
44
45static struct button_spec {
46 const char *buttontext;
47 clickfunction f;
48 const char *tooltiptext;
Jens Axboe3e47bd22012-02-29 13:45:02 +010049 const int start_insensitive;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010050} buttonspeclist[] = {
Jens Axboe3e47bd22012-02-29 13:45:02 +010051#define CONNECT_BUTTON 0
52#define START_JOB_BUTTON 1
53 { "Connect", connect_clicked, "Connect to host", 0 },
Stephen M. Cameronf3074002012-02-24 08:17:30 +010054 { "Start Job",
55 start_job_clicked,
Jens Axboe3e47bd22012-02-29 13:45:02 +010056 "Send current fio job to fio server to be executed", 1 },
Stephen M. Cameronf3074002012-02-24 08:17:30 +010057};
58
Jens Axboe843ad232012-02-29 11:44:53 +010059struct probe_widget {
60 GtkWidget *hostname;
61 GtkWidget *os;
62 GtkWidget *arch;
63 GtkWidget *fio_ver;
64};
65
Jens Axboe3e47bd22012-02-29 13:45:02 +010066struct eta_widget {
Jens Axboe807f9972012-03-02 10:25:24 +010067 GtkWidget *name;
68 GtkWidget *iotype;
69 GtkWidget *ioengine;
70 GtkWidget *iodepth;
Jens Axboe3e47bd22012-02-29 13:45:02 +010071 GtkWidget *jobs;
72 GtkWidget *files;
73 GtkWidget *read_bw;
74 GtkWidget *read_iops;
75 GtkWidget *cr_bw;
76 GtkWidget *cr_iops;
77 GtkWidget *write_bw;
78 GtkWidget *write_iops;
79 GtkWidget *cw_bw;
80 GtkWidget *cw_iops;
81};
82
Stephen M. Cameronff1f3282012-02-24 08:17:30 +010083struct gui {
84 GtkWidget *window;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +010085 GtkWidget *vbox;
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +010086 GtkWidget *topvbox;
87 GtkWidget *topalign;
88 GtkWidget *bottomalign;
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +010089 GtkWidget *thread_status_pb;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010090 GtkWidget *buttonbox;
91 GtkWidget *button[ARRAYSIZE(buttonspeclist)];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +010092 GtkWidget *scrolled_window;
Jens Axboe2fd3bb02012-03-07 08:07:39 +010093#define DRAWING_AREA_XDIM 1000
94#define DRAWING_AREA_YDIM 400
95 GtkWidget *drawing_area;
Jens Axboe0420ba62012-02-29 11:16:52 +010096 GtkWidget *error_info_bar;
97 GtkWidget *error_label;
Jens Axboef9d40b42012-03-06 09:52:49 +010098 GtkWidget *results_notebook;
99 GtkWidget *results_window;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100100 GtkListStore *log_model;
101 GtkWidget *log_tree;
Jens Axboe4cbe7212012-03-06 13:36:17 +0100102 GtkWidget *log_view;
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100103 GtkTextBuffer *text;
Jens Axboe843ad232012-02-29 11:44:53 +0100104 struct probe_widget probe;
Jens Axboe3e47bd22012-02-29 13:45:02 +0100105 struct eta_widget eta;
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100106 int connected;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100107 pthread_t t;
Jens Axboe63a130b2012-03-06 20:08:59 +0100108 pthread_t server_t;
Jens Axboe0420ba62012-02-29 11:16:52 +0100109
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100110 struct graph *iops_graph;
111 struct graph *bandwidth_graph;
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100112 struct fio_client *client;
Jens Axboe0420ba62012-02-29 11:16:52 +0100113 int nr_job_files;
114 char **job_files;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100115} ui;
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100116
Jens Axboee0681f32012-03-06 12:14:42 +0100117struct gfio_client {
118 struct gui *ui;
119 GtkWidget *results_widget;
120 GtkWidget *disk_util_frame;
121};
122
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100123static void setup_iops_graph(struct gui *ui)
124{
125 if (ui->iops_graph)
126 graph_free(ui->iops_graph);
127 ui->iops_graph = graph_new((int) DRAWING_AREA_XDIM / 2.0,
128 (int) DRAWING_AREA_YDIM);
129 graph_title(ui->iops_graph, "IOPS");
130 graph_x_title(ui->iops_graph, "Time");
131 graph_y_title(ui->iops_graph, "IOPS");
132 graph_add_label(ui->iops_graph, "Read IOPS");
133 graph_add_label(ui->iops_graph, "Write IOPS");
134 graph_set_color(ui->iops_graph, "Read IOPS", 0.7, 0.0, 0.0);
135 graph_set_color(ui->iops_graph, "Write IOPS", 0.0, 0.0, 0.7);
136}
137
138static void setup_bandwidth_graph(struct gui *ui)
139{
140 if (ui->bandwidth_graph)
141 graph_free(ui->bandwidth_graph);
142 ui->bandwidth_graph = graph_new((int) DRAWING_AREA_XDIM / 2.0,
143 (int) DRAWING_AREA_YDIM);
144 graph_title(ui->bandwidth_graph, "Bandwidth");
145 graph_x_title(ui->bandwidth_graph, "Time");
146 graph_y_title(ui->bandwidth_graph, "Bandwidth");
147 graph_add_label(ui->bandwidth_graph, "Read Bandwidth");
148 graph_add_label(ui->bandwidth_graph, "Write Bandwidth");
149 graph_set_color(ui->bandwidth_graph, "Read Bandwidth", 0.7, 0.0, 0.0);
150 graph_set_color(ui->bandwidth_graph, "Write Bandwidth", 0.0, 0.0, 0.7);
151}
152
Jens Axboe8663ea62012-03-02 14:04:30 +0100153static void clear_ui_info(struct gui *ui)
154{
155 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), "");
156 gtk_label_set_text(GTK_LABEL(ui->probe.os), "");
157 gtk_label_set_text(GTK_LABEL(ui->probe.arch), "");
158 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), "");
Jens Axboeca850992012-03-05 20:04:43 +0100159 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), "");
160 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), "");
161 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), "");
162 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), "");
163 gtk_entry_set_text(GTK_ENTRY(ui->eta.jobs), "");
164 gtk_entry_set_text(GTK_ENTRY(ui->eta.files), "");
165 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), "");
166 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), "");
167 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), "");
168 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100169}
170
Jens Axboe3650a3c2012-03-05 14:09:03 +0100171static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
172{
173 GtkWidget *entry, *frame;
174
175 frame = gtk_frame_new(label);
176 entry = gtk_entry_new();
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100177 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100178 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
179 gtk_container_add(GTK_CONTAINER(frame), entry);
180
181 return entry;
182}
183
184static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
185{
186 GtkWidget *label_widget;
187 GtkWidget *frame;
188
189 frame = gtk_frame_new(label);
190 label_widget = gtk_label_new(NULL);
191 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
192 gtk_container_add(GTK_CONTAINER(frame), label_widget);
193
194 return label_widget;
195}
196
197static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
198{
199 GtkWidget *button, *box;
200
201 box = gtk_hbox_new(FALSE, 3);
202 gtk_container_add(GTK_CONTAINER(hbox), box);
203
204 button = gtk_spin_button_new_with_range(min, max, 1.0);
205 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
206
207 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
208 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
209
210 return button;
211}
212
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100213static void gfio_set_connected(struct gui *ui, int connected)
214{
215 if (connected) {
216 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
217 ui->connected = 1;
218 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Disconnect");
Jens Axboe88f6e7a2012-03-06 12:55:29 +0100219 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100220 } else {
221 ui->connected = 0;
222 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Connect");
223 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
Jens Axboe63a130b2012-03-06 20:08:59 +0100224 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100225 }
226}
227
Jens Axboe3650a3c2012-03-05 14:09:03 +0100228static void label_set_int_value(GtkWidget *entry, unsigned int val)
229{
230 char tmp[80];
231
232 sprintf(tmp, "%u", val);
233 gtk_label_set_text(GTK_LABEL(entry), tmp);
234}
235
236static void entry_set_int_value(GtkWidget *entry, unsigned int val)
237{
238 char tmp[80];
239
240 sprintf(tmp, "%u", val);
241 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
242}
243
Jens Axboea2697902012-03-05 16:43:49 +0100244#define ALIGN_LEFT 1
245#define ALIGN_RIGHT 2
246#define INVISIBLE 4
247#define UNSORTABLE 8
248
249GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
250{
251 GtkCellRenderer *renderer;
252 GtkTreeViewColumn *col;
253 double xalign = 0.0; /* left as default */
254 PangoAlignment align;
255 gboolean visible;
256
257 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
258 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
259 PANGO_ALIGN_CENTER;
260 visible = !(flags & INVISIBLE);
261
262 renderer = gtk_cell_renderer_text_new();
263 col = gtk_tree_view_column_new();
264
265 gtk_tree_view_column_set_title(col, title);
266 if (!(flags & UNSORTABLE))
267 gtk_tree_view_column_set_sort_column_id(col, index);
268 gtk_tree_view_column_set_resizable(col, TRUE);
269 gtk_tree_view_column_pack_start(col, renderer, TRUE);
270 gtk_tree_view_column_add_attribute(col, renderer, "text", index);
271 gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
272 switch (align) {
273 case PANGO_ALIGN_LEFT:
274 xalign = 0.0;
275 break;
276 case PANGO_ALIGN_CENTER:
277 xalign = 0.5;
278 break;
279 case PANGO_ALIGN_RIGHT:
280 xalign = 1.0;
281 break;
282 }
283 gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
284 gtk_tree_view_column_set_visible(col, visible);
285 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
286 return col;
287}
288
Jens Axboe9b260bd2012-03-06 11:02:52 +0100289static void gfio_ui_setup_log(struct gui *ui)
290{
291 GtkTreeSelection *selection;
292 GtkListStore *model;
293 GtkWidget *tree_view;
294
295 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
296
297 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
298 gtk_widget_set_can_focus(tree_view, FALSE);
299
300 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
301 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
Jens Axboe661f7412012-03-06 13:55:45 +0100302 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
303 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100304
305 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
306 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
307 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
Jens Axboef095d562012-03-06 13:49:12 +0100308 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100309
310 ui->log_model = model;
311 ui->log_tree = tree_view;
312}
313
Jens Axboea2697902012-03-05 16:43:49 +0100314static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
315 fio_fp64_t *plist,
316 unsigned int len,
317 const char *base,
318 unsigned int scale)
319{
320 GType types[FIO_IO_U_LIST_MAX_LEN];
321 GtkWidget *tree_view;
322 GtkTreeSelection *selection;
323 GtkListStore *model;
324 GtkTreeIter iter;
325 int i;
326
327 for (i = 0; i < len; i++)
328 types[i] = G_TYPE_INT;
329
330 model = gtk_list_store_newv(len, types);
331
332 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
333 gtk_widget_set_can_focus(tree_view, FALSE);
334
Jens Axboe661f7412012-03-06 13:55:45 +0100335 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
336 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
337
Jens Axboea2697902012-03-05 16:43:49 +0100338 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
339 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
340
341 for (i = 0; i < len; i++) {
342 char fbuf[8];
343
344 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
345 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
346 }
347
348 gtk_list_store_append(model, &iter);
349
Jens Axboee0681f32012-03-06 12:14:42 +0100350 for (i = 0; i < len; i++) {
351 if (scale)
352 ovals[i] = (ovals[i] + 999) / 1000;
Jens Axboea2697902012-03-05 16:43:49 +0100353 gtk_list_store_set(model, &iter, i, ovals[i], -1);
Jens Axboee0681f32012-03-06 12:14:42 +0100354 }
Jens Axboea2697902012-03-05 16:43:49 +0100355
356 return tree_view;
357}
358
359static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
360 int ddir)
361{
362 unsigned int *io_u_plat = ts->io_u_plat[ddir];
363 unsigned long nr = ts->clat_stat[ddir].samples;
364 fio_fp64_t *plist = ts->percentile_list;
365 unsigned int *ovals, len, minv, maxv, scale_down;
366 const char *base;
367 GtkWidget *tree_view, *frame, *hbox;
368 char tmp[64];
369
370 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
371 if (!len)
372 goto out;
373
374 /*
375 * We default to usecs, but if the value range is such that we
376 * should scale down to msecs, do that.
377 */
378 if (minv > 2000 && maxv > 99999) {
379 scale_down = 1;
380 base = "msec";
381 } else {
382 scale_down = 0;
383 base = "usec";
384 }
385
386 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
387
388 sprintf(tmp, "Completion percentiles (%s)", base);
389 frame = gtk_frame_new(tmp);
390 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
391
392 hbox = gtk_hbox_new(FALSE, 3);
393 gtk_container_add(GTK_CONTAINER(frame), hbox);
394
395 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
396out:
397 if (ovals)
398 free(ovals);
399}
400
Jens Axboe3650a3c2012-03-05 14:09:03 +0100401static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
402 unsigned long max, double mean, double dev)
403{
404 const char *base = "(usec)";
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100405 GtkWidget *hbox, *label, *frame;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100406 char *minp, *maxp;
407 char tmp[64];
408
409 if (!usec_to_msec(&min, &max, &mean, &dev))
410 base = "(msec)";
411
412 minp = num2str(min, 6, 1, 0);
413 maxp = num2str(max, 6, 1, 0);
414
Jens Axboe3650a3c2012-03-05 14:09:03 +0100415 sprintf(tmp, "%s %s", name, base);
416 frame = gtk_frame_new(tmp);
417 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
418
Jens Axboe3650a3c2012-03-05 14:09:03 +0100419 hbox = gtk_hbox_new(FALSE, 3);
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100420 gtk_container_add(GTK_CONTAINER(frame), hbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100421
422 label = new_info_label_in_frame(hbox, "Minimum");
423 gtk_label_set_text(GTK_LABEL(label), minp);
424 label = new_info_label_in_frame(hbox, "Maximum");
425 gtk_label_set_text(GTK_LABEL(label), maxp);
426 label = new_info_label_in_frame(hbox, "Average");
427 sprintf(tmp, "%5.02f", mean);
428 gtk_label_set_text(GTK_LABEL(label), tmp);
429 label = new_info_label_in_frame(hbox, "Standard deviation");
430 sprintf(tmp, "%5.02f", dev);
431 gtk_label_set_text(GTK_LABEL(label), tmp);
432
433 free(minp);
434 free(maxp);
435
436}
437
Jens Axboeca850992012-03-05 20:04:43 +0100438#define GFIO_CLAT 1
439#define GFIO_SLAT 2
440#define GFIO_LAT 4
441
Jens Axboe3650a3c2012-03-05 14:09:03 +0100442static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
443 struct thread_stat *ts, int ddir)
444{
445 const char *ddir_label[2] = { "Read", "Write" };
Jens Axboe0b761302012-03-05 20:44:11 +0100446 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
Jens Axboee0681f32012-03-06 12:14:42 +0100447 unsigned long min[3], max[3], runt;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100448 unsigned long long bw, iops;
Jens Axboeca850992012-03-05 20:04:43 +0100449 unsigned int flags = 0;
Jens Axboee0681f32012-03-06 12:14:42 +0100450 double mean[3], dev[3];
Jens Axboe3650a3c2012-03-05 14:09:03 +0100451 char *io_p, *bw_p, *iops_p;
452 int i2p;
453
454 if (!ts->runtime[ddir])
455 return;
456
457 i2p = is_power_of_2(rs->kb_base);
458 runt = ts->runtime[ddir];
459
460 bw = (1000 * ts->io_bytes[ddir]) / runt;
461 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
462 bw_p = num2str(bw, 6, 1, i2p);
463
464 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
465 iops_p = num2str(iops, 6, 1, 0);
466
467 box = gtk_hbox_new(FALSE, 3);
468 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
469
470 frame = gtk_frame_new(ddir_label[ddir]);
471 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
472
Jens Axboe0b761302012-03-05 20:44:11 +0100473 main_vbox = gtk_vbox_new(FALSE, 3);
474 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100475
476 box = gtk_hbox_new(FALSE, 3);
Jens Axboe0b761302012-03-05 20:44:11 +0100477 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100478
479 label = new_info_label_in_frame(box, "IO");
480 gtk_label_set_text(GTK_LABEL(label), io_p);
481 label = new_info_label_in_frame(box, "Bandwidth");
482 gtk_label_set_text(GTK_LABEL(label), bw_p);
483 label = new_info_label_in_frame(box, "IOPS");
484 gtk_label_set_text(GTK_LABEL(label), iops_p);
485 label = new_info_label_in_frame(box, "Runtime (msec)");
486 label_set_int_value(label, ts->runtime[ddir]);
487
Jens Axboee0681f32012-03-06 12:14:42 +0100488 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
Jens Axboeca850992012-03-05 20:04:43 +0100489 double p_of_agg = 100.0;
490 const char *bw_str = "KB";
491 char tmp[32];
492
493 if (rs->agg[ddir]) {
Jens Axboee0681f32012-03-06 12:14:42 +0100494 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
Jens Axboeca850992012-03-05 20:04:43 +0100495 if (p_of_agg > 100.0)
496 p_of_agg = 100.0;
497 }
498
Jens Axboee0681f32012-03-06 12:14:42 +0100499 if (mean[0] > 999999.9) {
500 min[0] /= 1000.0;
501 max[0] /= 1000.0;
502 mean[0] /= 1000.0;
503 dev[0] /= 1000.0;
Jens Axboeca850992012-03-05 20:04:43 +0100504 bw_str = "MB";
505 }
506
Jens Axboe0b761302012-03-05 20:44:11 +0100507 sprintf(tmp, "Bandwidth (%s)", bw_str);
508 frame = gtk_frame_new(tmp);
509 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
Jens Axboeca850992012-03-05 20:04:43 +0100510
Jens Axboe0b761302012-03-05 20:44:11 +0100511 box = gtk_hbox_new(FALSE, 3);
512 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboeca850992012-03-05 20:04:43 +0100513
Jens Axboe0b761302012-03-05 20:44:11 +0100514 label = new_info_label_in_frame(box, "Minimum");
Jens Axboee0681f32012-03-06 12:14:42 +0100515 label_set_int_value(label, min[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100516 label = new_info_label_in_frame(box, "Maximum");
Jens Axboee0681f32012-03-06 12:14:42 +0100517 label_set_int_value(label, max[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100518 label = new_info_label_in_frame(box, "Percentage of jobs");
Jens Axboeca850992012-03-05 20:04:43 +0100519 sprintf(tmp, "%3.2f%%", p_of_agg);
520 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100521 label = new_info_label_in_frame(box, "Average");
Jens Axboee0681f32012-03-06 12:14:42 +0100522 sprintf(tmp, "%5.02f", mean[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100523 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100524 label = new_info_label_in_frame(box, "Standard deviation");
Jens Axboee0681f32012-03-06 12:14:42 +0100525 sprintf(tmp, "%5.02f", dev[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100526 gtk_label_set_text(GTK_LABEL(label), tmp);
527 }
528
Jens Axboee0681f32012-03-06 12:14:42 +0100529 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
Jens Axboe2b089892012-03-06 08:09:17 +0100530 flags |= GFIO_SLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100531 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
Jens Axboe2b089892012-03-06 08:09:17 +0100532 flags |= GFIO_CLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100533 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
Jens Axboe2b089892012-03-06 08:09:17 +0100534 flags |= GFIO_LAT;
535
536 if (flags) {
537 frame = gtk_frame_new("Latency");
538 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
539
540 vbox = gtk_vbox_new(FALSE, 3);
541 gtk_container_add(GTK_CONTAINER(frame), vbox);
542
543 if (flags & GFIO_SLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100544 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
Jens Axboe2b089892012-03-06 08:09:17 +0100545 if (flags & GFIO_CLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100546 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
Jens Axboe2b089892012-03-06 08:09:17 +0100547 if (flags & GFIO_LAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100548 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
Jens Axboe2b089892012-03-06 08:09:17 +0100549 }
550
551 if (ts->clat_percentiles)
552 gfio_show_clat_percentiles(main_vbox, ts, ddir);
553
554
Jens Axboe3650a3c2012-03-05 14:09:03 +0100555 free(io_p);
556 free(bw_p);
557 free(iops_p);
558}
559
Jens Axboee5bd1342012-03-05 21:38:12 +0100560static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
561 const char **labels)
562{
563 GtkWidget *tree_view;
564 GtkTreeSelection *selection;
565 GtkListStore *model;
566 GtkTreeIter iter;
567 GType *types;
568 int i, skipped;
569
570 /*
571 * Check if all are empty, in which case don't bother
572 */
573 for (i = 0, skipped = 0; i < num; i++)
574 if (lat[i] <= 0.0)
575 skipped++;
576
577 if (skipped == num)
578 return NULL;
579
580 types = malloc(num * sizeof(GType));
581
582 for (i = 0; i < num; i++)
583 types[i] = G_TYPE_STRING;
584
585 model = gtk_list_store_newv(num, types);
586 free(types);
587 types = NULL;
588
589 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
590 gtk_widget_set_can_focus(tree_view, FALSE);
591
Jens Axboe661f7412012-03-06 13:55:45 +0100592 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
593 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
594
Jens Axboee5bd1342012-03-05 21:38:12 +0100595 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
596 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
597
598 for (i = 0; i < num; i++)
599 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
600
601 gtk_list_store_append(model, &iter);
602
603 for (i = 0; i < num; i++) {
604 char fbuf[32];
605
606 if (lat[i] <= 0.0)
607 sprintf(fbuf, "0.00");
608 else
609 sprintf(fbuf, "%3.2f%%", lat[i]);
610
611 gtk_list_store_set(model, &iter, i, fbuf, -1);
612 }
613
614 return tree_view;
615}
616
617static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
618{
619 GtkWidget *box, *frame, *tree_view;
620 double io_u_lat_u[FIO_IO_U_LAT_U_NR];
621 double io_u_lat_m[FIO_IO_U_LAT_M_NR];
622 const char *uranges[] = { "2", "4", "10", "20", "50", "100",
623 "250", "500", "750", "1000", };
624 const char *mranges[] = { "2", "4", "10", "20", "50", "100",
625 "250", "500", "750", "1000", "2000",
626 ">= 2000", };
627
628 stat_calc_lat_u(ts, io_u_lat_u);
629 stat_calc_lat_m(ts, io_u_lat_m);
630
631 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
632 if (tree_view) {
633 frame = gtk_frame_new("Latency buckets (usec)");
634 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
635
636 box = gtk_hbox_new(FALSE, 3);
637 gtk_container_add(GTK_CONTAINER(frame), box);
638 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
639 }
640
641 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
642 if (tree_view) {
643 frame = gtk_frame_new("Latency buckets (msec)");
644 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
645
646 box = gtk_hbox_new(FALSE, 3);
647 gtk_container_add(GTK_CONTAINER(frame), box);
648 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
649 }
650}
651
Jens Axboe2e331012012-03-05 22:07:54 +0100652static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
653{
654 GtkWidget *box, *frame, *entry;
655 double usr_cpu, sys_cpu;
656 unsigned long runtime;
657 char tmp[32];
658
659 runtime = ts->total_run_time;
660 if (runtime) {
661 double runt = (double) runtime;
662
663 usr_cpu = (double) ts->usr_time * 100 / runt;
664 sys_cpu = (double) ts->sys_time * 100 / runt;
665 } else {
666 usr_cpu = 0;
667 sys_cpu = 0;
668 }
669
670 frame = gtk_frame_new("OS resources");
671 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
672
673 box = gtk_hbox_new(FALSE, 3);
674 gtk_container_add(GTK_CONTAINER(frame), box);
675
676 entry = new_info_entry_in_frame(box, "User CPU");
677 sprintf(tmp, "%3.2f%%", usr_cpu);
678 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
679 entry = new_info_entry_in_frame(box, "System CPU");
680 sprintf(tmp, "%3.2f%%", sys_cpu);
681 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
682 entry = new_info_entry_in_frame(box, "Context switches");
683 entry_set_int_value(entry, ts->ctx);
684 entry = new_info_entry_in_frame(box, "Major faults");
685 entry_set_int_value(entry, ts->majf);
686 entry = new_info_entry_in_frame(box, "Minor faults");
687 entry_set_int_value(entry, ts->minf);
688}
Jens Axboe19998db2012-03-06 09:17:59 +0100689static void gfio_add_sc_depths_tree(GtkListStore *model,
690 struct thread_stat *ts, unsigned int len,
691 int submit)
692{
693 double io_u_dist[FIO_IO_U_MAP_NR];
694 GtkTreeIter iter;
695 /* Bits 0, and 3-8 */
696 const int add_mask = 0x1f9;
697 int i, j;
698
699 if (submit)
700 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
701 else
702 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
703
704 gtk_list_store_append(model, &iter);
705
706 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
707
708 for (i = 1, j = 0; i < len; i++) {
709 char fbuf[32];
710
711 if (!(add_mask & (1UL << (i - 1))))
712 sprintf(fbuf, "0.0%%");
713 else {
714 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
715 j++;
716 }
717
718 gtk_list_store_set(model, &iter, i, fbuf, -1);
719 }
720
721}
722
723static void gfio_add_total_depths_tree(GtkListStore *model,
724 struct thread_stat *ts, unsigned int len)
725{
726 double io_u_dist[FIO_IO_U_MAP_NR];
727 GtkTreeIter iter;
728 /* Bits 1-6, and 8 */
729 const int add_mask = 0x17e;
730 int i, j;
731
732 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
733
734 gtk_list_store_append(model, &iter);
735
736 gtk_list_store_set(model, &iter, 0, "Total", -1);
737
738 for (i = 1, j = 0; i < len; i++) {
739 char fbuf[32];
740
741 if (!(add_mask & (1UL << (i - 1))))
742 sprintf(fbuf, "0.0%%");
743 else {
744 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
745 j++;
746 }
747
748 gtk_list_store_set(model, &iter, i, fbuf, -1);
749 }
750
751}
Jens Axboe2e331012012-03-05 22:07:54 +0100752
753static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
754{
Jens Axboe2e331012012-03-05 22:07:54 +0100755 GtkWidget *frame, *box, *tree_view;
756 GtkTreeSelection *selection;
757 GtkListStore *model;
Jens Axboe2e331012012-03-05 22:07:54 +0100758 GType types[FIO_IO_U_MAP_NR + 1];
759 int i;
Jens Axboe19998db2012-03-06 09:17:59 +0100760#define NR_LABELS 10
761 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
Jens Axboe2e331012012-03-05 22:07:54 +0100762
763 frame = gtk_frame_new("IO depths");
764 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
765
766 box = gtk_hbox_new(FALSE, 3);
767 gtk_container_add(GTK_CONTAINER(frame), box);
768
Jens Axboe19998db2012-03-06 09:17:59 +0100769 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100770 types[i] = G_TYPE_STRING;
771
Jens Axboe19998db2012-03-06 09:17:59 +0100772 model = gtk_list_store_newv(NR_LABELS, types);
Jens Axboe2e331012012-03-05 22:07:54 +0100773
774 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
775 gtk_widget_set_can_focus(tree_view, FALSE);
776
Jens Axboe661f7412012-03-06 13:55:45 +0100777 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
778 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
779
Jens Axboe2e331012012-03-05 22:07:54 +0100780 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
781 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
782
Jens Axboe19998db2012-03-06 09:17:59 +0100783 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100784 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
785
Jens Axboe19998db2012-03-06 09:17:59 +0100786 gfio_add_total_depths_tree(model, ts, NR_LABELS);
787 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 1);
788 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 0);
Jens Axboe2e331012012-03-05 22:07:54 +0100789
790 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
791}
792
Jens Axboef9d40b42012-03-06 09:52:49 +0100793static gboolean results_window_delete(GtkWidget *w, gpointer data)
794{
795 struct gui *ui = (struct gui *) data;
796
797 gtk_widget_destroy(w);
798 ui->results_window = NULL;
799 ui->results_notebook = NULL;
800 return TRUE;
801}
802
803static GtkWidget *get_results_window(struct gui *ui)
804{
805 GtkWidget *win, *notebook;
806
807 if (ui->results_window)
808 return ui->results_notebook;
809
810 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
811 gtk_window_set_title(GTK_WINDOW(win), "Results");
812 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ui);
813 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ui);
814
815 notebook = gtk_notebook_new();
816 gtk_container_add(GTK_CONTAINER(win), notebook);
817
818 ui->results_window = win;
819 ui->results_notebook = notebook;
820 return ui->results_notebook;
821}
822
Jens Axboe3650a3c2012-03-05 14:09:03 +0100823static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
824 struct group_run_stats *rs)
825{
Jens Axboef9d40b42012-03-06 09:52:49 +0100826 GtkWidget *res_win, *box, *vbox, *entry;
Jens Axboee0681f32012-03-06 12:14:42 +0100827 struct gfio_client *gc = client->client_data;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100828
829 gdk_threads_enter();
830
Jens Axboee0681f32012-03-06 12:14:42 +0100831 res_win = get_results_window(gc->ui);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100832
833 vbox = gtk_vbox_new(FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100834
835 box = gtk_hbox_new(TRUE, 3);
836 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
837
Jens Axboef9d40b42012-03-06 09:52:49 +0100838 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), vbox, gtk_label_new(ts->name));
839
Jens Axboee0681f32012-03-06 12:14:42 +0100840 gc->results_widget = vbox;
841
Jens Axboe3650a3c2012-03-05 14:09:03 +0100842 entry = new_info_entry_in_frame(box, "Name");
843 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
844 if (strlen(ts->description)) {
845 entry = new_info_entry_in_frame(box, "Description");
846 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
847 }
848 entry = new_info_entry_in_frame(box, "Group ID");
849 entry_set_int_value(entry, ts->groupid);
850 entry = new_info_entry_in_frame(box, "Jobs");
851 entry_set_int_value(entry, ts->members);
852 entry = new_info_entry_in_frame(box, "Error");
853 entry_set_int_value(entry, ts->error);
854 entry = new_info_entry_in_frame(box, "PID");
855 entry_set_int_value(entry, ts->pid);
856
857 if (ts->io_bytes[DDIR_READ])
858 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
859 if (ts->io_bytes[DDIR_WRITE])
860 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
861
Jens Axboee5bd1342012-03-05 21:38:12 +0100862 gfio_show_latency_buckets(vbox, ts);
Jens Axboe2e331012012-03-05 22:07:54 +0100863 gfio_show_cpu_usage(vbox, ts);
864 gfio_show_io_depths(vbox, ts);
Jens Axboee5bd1342012-03-05 21:38:12 +0100865
Jens Axboee0681f32012-03-06 12:14:42 +0100866 gtk_widget_show_all(gc->ui->results_window);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100867 gdk_threads_leave();
868}
869
Jens Axboe084d1c62012-03-03 20:28:07 +0100870static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100871{
Jens Axboe9b260bd2012-03-06 11:02:52 +0100872 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +0100873 struct gfio_client *gc = client->client_data;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100874 GtkTreeIter iter;
875 struct tm *tm;
876 time_t sec;
877 char tmp[64], timebuf[80];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100878
Jens Axboe9b260bd2012-03-06 11:02:52 +0100879 sec = p->log_sec;
880 tm = localtime(&sec);
881 strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", tm);
882 sprintf(timebuf, "%s.%03ld", tmp, p->log_usec / 1000);
883
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100884 gdk_threads_enter();
Jens Axboe9b260bd2012-03-06 11:02:52 +0100885
Jens Axboee0681f32012-03-06 12:14:42 +0100886 gtk_list_store_append(gc->ui->log_model, &iter);
887 gtk_list_store_set(gc->ui->log_model, &iter, 0, timebuf, -1);
888 gtk_list_store_set(gc->ui->log_model, &iter, 1, client->hostname, -1);
889 gtk_list_store_set(gc->ui->log_model, &iter, 2, p->level, -1);
890 gtk_list_store_set(gc->ui->log_model, &iter, 3, p->buf, -1);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100891
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100892 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100893}
894
895static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
896{
Jens Axboee0681f32012-03-06 12:14:42 +0100897 struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
898 struct gfio_client *gc = client->client_data;
899 GtkWidget *box, *frame, *entry, *vbox;
900
Jens Axboe0050e5f2012-03-06 09:23:27 +0100901 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +0100902
903 if (!gc->results_widget) {
904 printf("no results!\n");
905 goto out;
906 }
907
908 if (!gc->disk_util_frame) {
909 gc->disk_util_frame = gtk_frame_new("Disk utilization");
910 gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
911 }
912
913 vbox = gtk_vbox_new(FALSE, 3);
914 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
915
916 frame = gtk_frame_new((char *) p->dus.name);
917 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
918
919 box = gtk_vbox_new(FALSE, 3);
920 gtk_container_add(GTK_CONTAINER(frame), box);
921
922 frame = gtk_frame_new("Read");
923 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
924 vbox = gtk_hbox_new(TRUE, 3);
925 gtk_container_add(GTK_CONTAINER(frame), vbox);
926 entry = new_info_entry_in_frame(vbox, "IOs");
927 entry_set_int_value(entry, p->dus.ios[0]);
928 entry = new_info_entry_in_frame(vbox, "Merges");
929 entry_set_int_value(entry, p->dus.merges[0]);
930 entry = new_info_entry_in_frame(vbox, "Sectors");
931 entry_set_int_value(entry, p->dus.sectors[0]);
932 entry = new_info_entry_in_frame(vbox, "Ticks");
933 entry_set_int_value(entry, p->dus.ticks[0]);
934
935 frame = gtk_frame_new("Write");
936 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
937 vbox = gtk_hbox_new(TRUE, 3);
938 gtk_container_add(GTK_CONTAINER(frame), vbox);
939 entry = new_info_entry_in_frame(vbox, "IOs");
940 entry_set_int_value(entry, p->dus.ios[1]);
941 entry = new_info_entry_in_frame(vbox, "Merges");
942 entry_set_int_value(entry, p->dus.merges[1]);
943 entry = new_info_entry_in_frame(vbox, "Sectors");
944 entry_set_int_value(entry, p->dus.sectors[1]);
945 entry = new_info_entry_in_frame(vbox, "Ticks");
946 entry_set_int_value(entry, p->dus.ticks[1]);
947
948 frame = gtk_frame_new("Shared");
949 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
950 vbox = gtk_hbox_new(TRUE, 3);
951 gtk_container_add(GTK_CONTAINER(frame), vbox);
952 entry = new_info_entry_in_frame(vbox, "IO ticks");
953 entry_set_int_value(entry, p->dus.io_ticks);
954 entry = new_info_entry_in_frame(vbox, "Time in queue");
955 entry_set_int_value(entry, p->dus.time_in_queue);
956
957 gtk_widget_show_all(gc->results_widget);
958out:
Jens Axboe0050e5f2012-03-06 09:23:27 +0100959 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100960}
961
Jens Axboe3650a3c2012-03-05 14:09:03 +0100962extern int sum_stat_clients;
963extern struct thread_stat client_ts;
964extern struct group_run_stats client_gs;
965
966static int sum_stat_nr;
967
Jens Axboe89e5fad2012-03-05 09:21:12 +0100968static void gfio_thread_status_op(struct fio_client *client,
969 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100970{
Jens Axboe3650a3c2012-03-05 14:09:03 +0100971 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
972
973 gfio_display_ts(client, &p->ts, &p->rs);
974
975 if (sum_stat_clients == 1)
976 return;
977
978 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
979 sum_group_stats(&client_gs, &p->rs);
980
981 client_ts.members++;
982 client_ts.groupid = p->ts.groupid;
983
984 if (++sum_stat_nr == sum_stat_clients) {
985 strcpy(client_ts.name, "All clients");
986 gfio_display_ts(client, &client_ts, &client_gs);
987 }
Stephen M. Camerona1820202012-02-24 08:17:31 +0100988}
989
Jens Axboe89e5fad2012-03-05 09:21:12 +0100990static void gfio_group_stats_op(struct fio_client *client,
991 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100992{
Jens Axboe0050e5f2012-03-06 09:23:27 +0100993 gdk_threads_enter();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100994 printf("gfio_group_stats_op called\n");
Jens Axboe89e5fad2012-03-05 09:21:12 +0100995 fio_client_ops.group_stats(client, cmd);
Jens Axboe0050e5f2012-03-06 09:23:27 +0100996 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100997}
998
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100999static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
1000{
1001 struct gui *ui = (struct gui *) p;
1002 cairo_t *cr;
1003
1004 cr = gdk_cairo_create(w->window);
1005
1006 cairo_set_source_rgb(cr, 0, 0, 0);
1007
1008 cairo_save(cr);
1009 cairo_translate(cr, 0, 0);
1010 line_graph_draw(ui->bandwidth_graph, cr);
1011 cairo_stroke(cr);
1012 cairo_restore(cr);
1013
1014 cairo_save(cr);
1015 cairo_translate(cr, DRAWING_AREA_XDIM / 2.0, 0);
1016 // DRAWING_AREA_YDIM * 0.05);
1017 line_graph_draw(ui->iops_graph, cr);
1018 cairo_stroke(cr);
1019 cairo_restore(cr);
1020 cairo_destroy(cr);
1021
1022 return FALSE;
1023}
1024
Jens Axboe3e47bd22012-02-29 13:45:02 +01001025static void gfio_update_eta(struct jobs_eta *je)
1026{
1027 static int eta_good;
1028 char eta_str[128];
1029 char output[256];
1030 char tmp[32];
1031 double perc = 0.0;
1032 int i2p = 0;
1033
Jens Axboe0050e5f2012-03-06 09:23:27 +01001034 gdk_threads_enter();
1035
Jens Axboe3e47bd22012-02-29 13:45:02 +01001036 eta_str[0] = '\0';
1037 output[0] = '\0';
1038
1039 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1040 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1041 eta_to_str(eta_str, je->eta_sec);
1042 }
1043
1044 sprintf(tmp, "%u", je->nr_running);
Jens Axboeca850992012-03-05 20:04:43 +01001045 gtk_entry_set_text(GTK_ENTRY(ui.eta.jobs), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001046 sprintf(tmp, "%u", je->files_open);
Jens Axboeca850992012-03-05 20:04:43 +01001047 gtk_entry_set_text(GTK_ENTRY(ui.eta.files), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001048
1049#if 0
1050 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1051 if (je->m_rate || je->t_rate) {
1052 char *tr, *mr;
1053
1054 mr = num2str(je->m_rate, 4, 0, i2p);
1055 tr = num2str(je->t_rate, 4, 0, i2p);
Jens Axboeca850992012-03-05 20:04:43 +01001056 gtk_entry_set_text(GTK_ENTRY(ui.eta);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001057 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1058 free(tr);
1059 free(mr);
1060 } else if (je->m_iops || je->t_iops)
1061 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
Jens Axboeebbd89c2012-03-02 11:21:13 +01001062
Jens Axboeca850992012-03-05 20:04:43 +01001063 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_bw), "---");
1064 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_iops), "---");
1065 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_bw), "---");
1066 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_iops), "---");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001067#endif
1068
1069 if (je->eta_sec != INT_MAX && je->nr_running) {
1070 char *iops_str[2];
1071 char *rate_str[2];
1072
1073 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1074 strcpy(output, "-.-% done");
1075 else {
1076 eta_good = 1;
1077 perc *= 100.0;
1078 sprintf(output, "%3.1f%% done", perc);
1079 }
1080
1081 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1082 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1083
1084 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1085 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1086
Jens Axboeca850992012-03-05 20:04:43 +01001087 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_bw), rate_str[0]);
1088 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_iops), iops_str[0]);
1089 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_bw), rate_str[1]);
1090 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_iops), iops_str[1]);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001091
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001092 graph_add_xy_data(ui.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1093 graph_add_xy_data(ui.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1094 graph_add_xy_data(ui.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1095 graph_add_xy_data(ui.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
1096
Jens Axboe3e47bd22012-02-29 13:45:02 +01001097 free(rate_str[0]);
1098 free(rate_str[1]);
1099 free(iops_str[0]);
1100 free(iops_str[1]);
1101 }
1102
1103 if (eta_str[0]) {
1104 char *dst = output + strlen(output);
1105
1106 sprintf(dst, " - %s", eta_str);
1107 }
1108
1109 gfio_update_thread_status(output, perc);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001110 gdk_threads_leave();
Jens Axboe3e47bd22012-02-29 13:45:02 +01001111}
1112
Stephen M. Camerona1820202012-02-24 08:17:31 +01001113static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1114{
Jens Axboe843ad232012-02-29 11:44:53 +01001115 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001116 struct gfio_client *gc = client->client_data;
1117 struct gui *ui = gc->ui;
Jens Axboe843ad232012-02-29 11:44:53 +01001118 const char *os, *arch;
1119 char buf[64];
1120
1121 os = fio_get_os_string(probe->os);
1122 if (!os)
1123 os = "unknown";
1124
1125 arch = fio_get_arch_string(probe->arch);
1126 if (!arch)
1127 os = "unknown";
1128
1129 if (!client->name)
1130 client->name = strdup((char *) probe->hostname);
1131
Jens Axboe0050e5f2012-03-06 09:23:27 +01001132 gdk_threads_enter();
1133
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001134 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), (char *) probe->hostname);
1135 gtk_label_set_text(GTK_LABEL(ui->probe.os), os);
1136 gtk_label_set_text(GTK_LABEL(ui->probe.arch), arch);
Jens Axboe843ad232012-02-29 11:44:53 +01001137 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001138 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), buf);
1139
1140 gfio_set_connected(ui, 1);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001141
1142 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001143}
1144
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001145static void gfio_update_thread_status(char *status_message, double perc)
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001146{
1147 static char message[100];
1148 const char *m = message;
1149
1150 strncpy(message, status_message, sizeof(message) - 1);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001151 gtk_progress_bar_set_text(
1152 GTK_PROGRESS_BAR(ui.thread_status_pb), m);
1153 gtk_progress_bar_set_fraction(
1154 GTK_PROGRESS_BAR(ui.thread_status_pb), perc / 100.0);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001155 gtk_widget_queue_draw(ui.window);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001156}
1157
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001158static void gfio_quit_op(struct fio_client *client)
1159{
Jens Axboee0681f32012-03-06 12:14:42 +01001160 struct gfio_client *gc = client->client_data;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001161
Jens Axboe0050e5f2012-03-06 09:23:27 +01001162 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +01001163 gfio_set_connected(gc->ui, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001164 gdk_threads_leave();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001165}
1166
Jens Axboe807f9972012-03-02 10:25:24 +01001167static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1168{
1169 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +01001170 struct gfio_client *gc = client->client_data;
1171 struct gui *ui = gc->ui;
Jens Axboe807f9972012-03-02 10:25:24 +01001172 char tmp[8];
1173 int i;
1174
1175 p->iodepth = le32_to_cpu(p->iodepth);
1176 p->rw = le32_to_cpu(p->rw);
1177
1178 for (i = 0; i < 2; i++) {
1179 p->min_bs[i] = le32_to_cpu(p->min_bs[i]);
1180 p->max_bs[i] = le32_to_cpu(p->max_bs[i]);
1181 }
1182
1183 p->numjobs = le32_to_cpu(p->numjobs);
1184 p->group_reporting = le32_to_cpu(p->group_reporting);
1185
Jens Axboe0050e5f2012-03-06 09:23:27 +01001186 gdk_threads_enter();
1187
Jens Axboeca850992012-03-05 20:04:43 +01001188 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), (gchar *) p->jobname);
1189 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), ddir_str(p->rw));
1190 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), (gchar *) p->ioengine);
Jens Axboe807f9972012-03-02 10:25:24 +01001191
1192 sprintf(tmp, "%u", p->iodepth);
Jens Axboeca850992012-03-05 20:04:43 +01001193 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), tmp);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001194
1195 gdk_threads_leave();
Jens Axboe807f9972012-03-02 10:25:24 +01001196}
1197
Jens Axboeed727a42012-03-02 12:14:40 +01001198static void gfio_client_timed_out(struct fio_client *client)
1199{
Jens Axboee0681f32012-03-06 12:14:42 +01001200 struct gfio_client *gc = client->client_data;
Jens Axboeed727a42012-03-02 12:14:40 +01001201 GtkWidget *dialog, *label, *content;
1202 char buf[256];
1203
1204 gdk_threads_enter();
1205
Jens Axboee0681f32012-03-06 12:14:42 +01001206 gfio_set_connected(gc->ui, 0);
1207 clear_ui_info(gc->ui);
Jens Axboeed727a42012-03-02 12:14:40 +01001208
1209 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
1210
1211 dialog = gtk_dialog_new_with_buttons("Timed out!",
Jens Axboee0681f32012-03-06 12:14:42 +01001212 GTK_WINDOW(gc->ui->window),
Jens Axboeed727a42012-03-02 12:14:40 +01001213 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1214 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1215
1216 content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1217 label = gtk_label_new((const gchar *) buf);
1218 gtk_container_add(GTK_CONTAINER(content), label);
1219 gtk_widget_show_all(dialog);
1220 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1221
1222 gtk_dialog_run(GTK_DIALOG(dialog));
1223 gtk_widget_destroy(dialog);
1224
1225 gdk_threads_leave();
1226}
1227
Stephen M. Camerona1820202012-02-24 08:17:31 +01001228struct client_ops gfio_client_ops = {
Jens Axboe0420ba62012-02-29 11:16:52 +01001229 .text_op = gfio_text_op,
1230 .disk_util = gfio_disk_util_op,
1231 .thread_status = gfio_thread_status_op,
1232 .group_stats = gfio_group_stats_op,
Jens Axboea5276612012-03-04 15:15:08 +01001233 .eta = gfio_update_eta,
Jens Axboe0420ba62012-02-29 11:16:52 +01001234 .probe = gfio_probe_op,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001235 .quit = gfio_quit_op,
Jens Axboe807f9972012-03-02 10:25:24 +01001236 .add_job = gfio_add_job_op,
Jens Axboeed727a42012-03-02 12:14:40 +01001237 .timed_out = gfio_client_timed_out,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001238 .stay_connected = 1,
Stephen M. Camerona1820202012-02-24 08:17:31 +01001239};
1240
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001241static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1242 __attribute__((unused)) gpointer data)
1243{
1244 gtk_main_quit();
1245}
1246
Stephen M. Cameron25927252012-02-24 08:17:31 +01001247static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001248{
Stephen M. Cameron25927252012-02-24 08:17:31 +01001249 fio_handle_clients(&gfio_client_ops);
Stephen M. Cameron25927252012-02-24 08:17:31 +01001250 return NULL;
1251}
1252
Jens Axboe0420ba62012-02-29 11:16:52 +01001253static int send_job_files(struct gui *ui)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001254{
Jens Axboe441013b2012-03-01 08:01:52 +01001255 int i, ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001256
Jens Axboe0420ba62012-02-29 11:16:52 +01001257 for (i = 0; i < ui->nr_job_files; i++) {
1258 ret = fio_clients_send_ini(ui->job_files[i]);
Jens Axboe441013b2012-03-01 08:01:52 +01001259 if (ret)
1260 break;
1261
Jens Axboe0420ba62012-02-29 11:16:52 +01001262 free(ui->job_files[i]);
1263 ui->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001264 }
1265 while (i < ui->nr_job_files) {
1266 free(ui->job_files[i]);
1267 ui->job_files[i] = NULL;
1268 i++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001269 }
1270
Jens Axboe441013b2012-03-01 08:01:52 +01001271 return ret;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001272}
1273
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001274static void start_job_thread(struct gui *ui)
Stephen M. Cameron25927252012-02-24 08:17:31 +01001275{
Jens Axboe0420ba62012-02-29 11:16:52 +01001276 if (send_job_files(ui)) {
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001277 printf("Yeah, I didn't really like those options too much.\n");
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001278 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
1279 return;
1280 }
Stephen M. Cameron25927252012-02-24 08:17:31 +01001281}
1282
Jens Axboe63a130b2012-03-06 20:08:59 +01001283static void *server_thread(void *arg)
1284{
1285 is_backend = 1;
1286 gfio_server_running = 1;
1287 fio_start_server(NULL);
1288 gfio_server_running = 0;
1289 return NULL;
1290}
1291
1292static void gfio_start_server(struct gui *ui)
1293{
1294 if (!gfio_server_running) {
1295 gfio_server_running = 1;
1296 pthread_create(&ui->server_t, NULL, server_thread, NULL);
Jens Axboee34f6ad2012-03-06 20:47:15 +01001297 pthread_detach(ui->server_t);
Jens Axboe63a130b2012-03-06 20:08:59 +01001298 }
1299}
1300
Stephen M. Cameron25927252012-02-24 08:17:31 +01001301static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1302 gpointer data)
1303{
1304 struct gui *ui = data;
1305
Stephen M. Cameron25927252012-02-24 08:17:31 +01001306 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001307 start_job_thread(ui);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001308}
1309
Jens Axboedf06f222012-03-02 13:32:04 +01001310static void file_open(GtkWidget *w, gpointer data);
1311
1312static void connect_clicked(GtkWidget *widget, gpointer data)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001313{
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001314 struct gui *ui = data;
1315
1316 if (!ui->connected) {
Jens Axboedf06f222012-03-02 13:32:04 +01001317 if (!ui->nr_job_files)
1318 file_open(widget, data);
Jens Axboe8663ea62012-03-02 14:04:30 +01001319 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
Jens Axboee34f6ad2012-03-06 20:47:15 +01001320 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe69406b92012-03-06 14:00:42 +01001321 if (!fio_clients_connect()) {
1322 pthread_create(&ui->t, NULL, job_thread, NULL);
1323 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 0);
1324 }
Jens Axboedf06f222012-03-02 13:32:04 +01001325 } else {
1326 fio_clients_terminate();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001327 gfio_set_connected(ui, 0);
Jens Axboe88432652012-03-02 19:09:31 +01001328 clear_ui_info(ui);
Jens Axboedf06f222012-03-02 13:32:04 +01001329 }
Jens Axboe3e47bd22012-02-29 13:45:02 +01001330}
1331
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001332static void add_button(struct gui *ui, int i, GtkWidget *buttonbox,
1333 struct button_spec *buttonspec)
1334{
1335 ui->button[i] = gtk_button_new_with_label(buttonspec->buttontext);
1336 g_signal_connect(ui->button[i], "clicked", G_CALLBACK (buttonspec->f), ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001337 gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], FALSE, FALSE, 3);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001338 gtk_widget_set_tooltip_text(ui->button[i], buttonspeclist[i].tooltiptext);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001339 gtk_widget_set_sensitive(ui->button[i], !buttonspec->start_insensitive);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001340}
1341
1342static void add_buttons(struct gui *ui,
1343 struct button_spec *buttonlist,
1344 int nbuttons)
1345{
1346 int i;
1347
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001348 for (i = 0; i < nbuttons; i++)
1349 add_button(ui, i, ui->buttonbox, &buttonlist[i]);
1350}
1351
Jens Axboe0420ba62012-02-29 11:16:52 +01001352static void on_info_bar_response(GtkWidget *widget, gint response,
1353 gpointer data)
1354{
1355 if (response == GTK_RESPONSE_OK) {
1356 gtk_widget_destroy(widget);
1357 ui.error_info_bar = NULL;
1358 }
1359}
1360
Jens Axboedf06f222012-03-02 13:32:04 +01001361void report_error(GError *error)
Jens Axboe0420ba62012-02-29 11:16:52 +01001362{
1363 if (ui.error_info_bar == NULL) {
1364 ui.error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
1365 GTK_RESPONSE_OK,
1366 NULL);
1367 g_signal_connect(ui.error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1368 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui.error_info_bar),
1369 GTK_MESSAGE_ERROR);
1370
1371 ui.error_label = gtk_label_new(error->message);
1372 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui.error_info_bar));
1373 gtk_container_add(GTK_CONTAINER(container), ui.error_label);
1374
1375 gtk_box_pack_start(GTK_BOX(ui.vbox), ui.error_info_bar, FALSE, FALSE, 0);
1376 gtk_widget_show_all(ui.vbox);
1377 } else {
1378 char buffer[256];
1379 snprintf(buffer, sizeof(buffer), "Failed to open file.");
1380 gtk_label_set(GTK_LABEL(ui.error_label), buffer);
1381 }
1382}
1383
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001384static int get_connection_details(char **host, int *port, int *type,
1385 int *server_start)
Jens Axboea7a42ce2012-03-02 13:12:04 +01001386{
1387 GtkWidget *dialog, *box, *vbox, *hentry, *hbox, *frame, *pentry, *combo;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001388 GtkWidget *button;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001389 char *typeentry;
1390
1391 dialog = gtk_dialog_new_with_buttons("Connection details",
1392 GTK_WINDOW(ui.window),
1393 GTK_DIALOG_DESTROY_WITH_PARENT,
1394 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1395 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1396
1397 frame = gtk_frame_new("Hostname / socket name");
1398 vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1399 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1400
1401 box = gtk_vbox_new(FALSE, 6);
1402 gtk_container_add(GTK_CONTAINER(frame), box);
1403
1404 hbox = gtk_hbox_new(TRUE, 10);
1405 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1406 hentry = gtk_entry_new();
1407 gtk_entry_set_text(GTK_ENTRY(hentry), "localhost");
1408 gtk_box_pack_start(GTK_BOX(hbox), hentry, TRUE, TRUE, 0);
1409
1410 frame = gtk_frame_new("Port");
1411 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1412 box = gtk_vbox_new(FALSE, 10);
1413 gtk_container_add(GTK_CONTAINER(frame), box);
1414
1415 hbox = gtk_hbox_new(TRUE, 4);
1416 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1417 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1418
1419 frame = gtk_frame_new("Type");
1420 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1421 box = gtk_vbox_new(FALSE, 10);
1422 gtk_container_add(GTK_CONTAINER(frame), box);
1423
1424 hbox = gtk_hbox_new(TRUE, 4);
1425 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1426
Jens Axboeb4655622012-03-06 13:46:21 +01001427 combo = gtk_combo_box_new_text();
1428 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "IPv4");
1429 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "IPv6");
1430 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "local socket");
Jens Axboea7a42ce2012-03-02 13:12:04 +01001431 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
1432
1433 gtk_container_add(GTK_CONTAINER(hbox), combo);
1434
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001435 frame = gtk_frame_new("Options");
1436 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1437 box = gtk_vbox_new(FALSE, 10);
1438 gtk_container_add(GTK_CONTAINER(frame), box);
1439
1440 hbox = gtk_hbox_new(TRUE, 4);
1441 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1442
1443 button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1444 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), 1);
1445 gtk_widget_set_tooltip_text(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.");
1446 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 6);
1447
Jens Axboea7a42ce2012-03-02 13:12:04 +01001448 gtk_widget_show_all(dialog);
1449
1450 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1451 gtk_widget_destroy(dialog);
1452 return 1;
1453 }
1454
1455 *host = strdup(gtk_entry_get_text(GTK_ENTRY(hentry)));
1456 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1457
Jens Axboeb4655622012-03-06 13:46:21 +01001458 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001459 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1460 *type = Fio_client_ipv4;
1461 else if (!strncmp(typeentry, "IPv6", 4))
1462 *type = Fio_client_ipv6;
1463 else
1464 *type = Fio_client_socket;
1465 g_free(typeentry);
1466
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001467 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
1468
Jens Axboea7a42ce2012-03-02 13:12:04 +01001469 gtk_widget_destroy(dialog);
1470 return 0;
1471}
1472
Jens Axboee0681f32012-03-06 12:14:42 +01001473static void gfio_client_added(struct gui *ui, struct fio_client *client)
1474{
1475 struct gfio_client *gc;
1476
1477 gc = malloc(sizeof(*gc));
1478 memset(gc, 0, sizeof(*gc));
1479 gc->ui = ui;
1480
1481 client->client_data = gc;
1482}
1483
Jens Axboe0420ba62012-02-29 11:16:52 +01001484static void file_open(GtkWidget *w, gpointer data)
1485{
1486 GtkWidget *dialog;
Jens Axboe63a130b2012-03-06 20:08:59 +01001487 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01001488 GSList *filenames, *fn_glist;
1489 GtkFileFilter *filter;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001490 char *host;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001491 int port, type, server_start;
Jens Axboe0420ba62012-02-29 11:16:52 +01001492
1493 dialog = gtk_file_chooser_dialog_new("Open File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001494 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001495 GTK_FILE_CHOOSER_ACTION_OPEN,
1496 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1497 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1498 NULL);
1499 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1500
1501 filter = gtk_file_filter_new();
1502 gtk_file_filter_add_pattern(filter, "*.fio");
1503 gtk_file_filter_add_pattern(filter, "*.job");
1504 gtk_file_filter_add_mime_type(filter, "text/fio");
1505 gtk_file_filter_set_name(filter, "Fio job file");
1506 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
1507
1508 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1509 gtk_widget_destroy(dialog);
1510 return;
1511 }
1512
1513 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001514
1515 gtk_widget_destroy(dialog);
1516
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001517 if (get_connection_details(&host, &port, &type, &server_start))
Jens Axboea7a42ce2012-03-02 13:12:04 +01001518 goto err;
1519
Jens Axboe0420ba62012-02-29 11:16:52 +01001520 filenames = fn_glist;
1521 while (filenames != NULL) {
Jens Axboee0681f32012-03-06 12:14:42 +01001522 struct fio_client *client;
1523
Jens Axboe63a130b2012-03-06 20:08:59 +01001524 ui->job_files = realloc(ui->job_files, (ui->nr_job_files + 1) * sizeof(char *));
1525 ui->job_files[ui->nr_job_files] = strdup(filenames->data);
1526 ui->nr_job_files++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001527
Jens Axboee0681f32012-03-06 12:14:42 +01001528 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
1529 if (!client) {
Jens Axboedf06f222012-03-02 13:32:04 +01001530 GError *error;
1531
1532 error = g_error_new(g_quark_from_string("fio"), 1,
1533 "Failed to add client %s", host);
Jens Axboe0420ba62012-02-29 11:16:52 +01001534 report_error(error);
1535 g_error_free(error);
Jens Axboe0420ba62012-02-29 11:16:52 +01001536 }
Jens Axboe63a130b2012-03-06 20:08:59 +01001537 gfio_client_added(ui, client);
Jens Axboe0420ba62012-02-29 11:16:52 +01001538
1539 g_free(filenames->data);
1540 filenames = g_slist_next(filenames);
1541 }
Jens Axboea7a42ce2012-03-02 13:12:04 +01001542 free(host);
Jens Axboe63a130b2012-03-06 20:08:59 +01001543
1544 if (server_start)
1545 gfio_start_server(ui);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001546err:
Jens Axboe0420ba62012-02-29 11:16:52 +01001547 g_slist_free(fn_glist);
Jens Axboe0420ba62012-02-29 11:16:52 +01001548}
1549
1550static void file_save(GtkWidget *w, gpointer data)
1551{
Jens Axboe63a130b2012-03-06 20:08:59 +01001552 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01001553 GtkWidget *dialog;
1554
1555 dialog = gtk_file_chooser_dialog_new("Save File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001556 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001557 GTK_FILE_CHOOSER_ACTION_SAVE,
1558 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1559 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1560 NULL);
1561
1562 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1563 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
1564
1565 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1566 char *filename;
1567
1568 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1569 // save_job_file(filename);
1570 g_free(filename);
1571 }
1572 gtk_widget_destroy(dialog);
1573}
1574
Jens Axboe9b260bd2012-03-06 11:02:52 +01001575static void view_log_destroy(GtkWidget *w, gpointer data)
1576{
1577 struct gui *ui = (struct gui *) data;
1578
1579 gtk_widget_ref(ui->log_tree);
1580 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
1581 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +01001582 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001583}
1584
1585static void view_log(GtkWidget *w, gpointer data)
1586{
Jens Axboe4cbe7212012-03-06 13:36:17 +01001587 GtkWidget *win, *scroll, *vbox, *box;
1588 struct gui *ui = (struct gui *) data;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001589
Jens Axboe4cbe7212012-03-06 13:36:17 +01001590 if (ui->log_view)
1591 return;
1592
1593 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001594 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001595 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001596
Jens Axboe4cbe7212012-03-06 13:36:17 +01001597 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001598
Jens Axboe4cbe7212012-03-06 13:36:17 +01001599 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
1600
1601 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1602
1603 box = gtk_hbox_new(TRUE, 0);
1604 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
1605 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
1606 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
1607
1608 vbox = gtk_vbox_new(TRUE, 5);
1609 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
1610
1611 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001612 gtk_widget_show_all(win);
1613}
1614
Jens Axboe46974a72012-03-02 19:34:13 +01001615static void preferences(GtkWidget *w, gpointer data)
1616{
1617 GtkWidget *dialog, *frame, *box, **buttons;
1618 int i;
1619
1620 dialog = gtk_dialog_new_with_buttons("Preferences",
1621 GTK_WINDOW(ui.window),
1622 GTK_DIALOG_DESTROY_WITH_PARENT,
1623 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1624 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1625 NULL);
1626
Jens Axboe0b8d11e2012-03-02 19:44:15 +01001627 frame = gtk_frame_new("Debug logging");
Jens Axboe46974a72012-03-02 19:34:13 +01001628 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1629 box = gtk_hbox_new(FALSE, 6);
1630 gtk_container_add(GTK_CONTAINER(frame), box);
1631
1632 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
1633
1634 for (i = 0; i < FD_DEBUG_MAX; i++) {
1635 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
Jens Axboe0b8d11e2012-03-02 19:44:15 +01001636 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
Jens Axboe46974a72012-03-02 19:34:13 +01001637 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
1638 }
1639
1640 gtk_widget_show_all(dialog);
1641
1642 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1643 gtk_widget_destroy(dialog);
1644 return;
1645 }
1646
1647 for (i = 0; i < FD_DEBUG_MAX; i++) {
1648 int set;
1649
1650 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
1651 if (set)
1652 fio_debug |= (1UL << i);
1653 }
1654
1655 gtk_widget_destroy(dialog);
1656}
1657
Jens Axboe0420ba62012-02-29 11:16:52 +01001658static void about_dialog(GtkWidget *w, gpointer data)
1659{
1660 gtk_show_about_dialog(NULL,
1661 "program-name", "gfio",
1662 "comments", "Gtk2 UI for fio",
1663 "license", "GPLv2",
1664 "version", fio_version_string,
1665 "copyright", "Jens Axboe <axboe@kernel.dk> 2012",
1666 "logo-icon-name", "fio",
1667 /* Must be last: */
1668 NULL, NULL,
1669 NULL);
1670}
1671
1672static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01001673 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01001674 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01001675 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
1676 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
1677 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
1678 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01001679 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe46974a72012-03-02 19:34:13 +01001680 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
1681 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01001682};
Jens Axboe3e47bd22012-02-29 13:45:02 +01001683static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01001684
1685static const gchar *ui_string = " \
1686 <ui> \
1687 <menubar name=\"MainMenu\"> \
1688 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
1689 <menuitem name=\"Open\" action=\"OpenFile\" /> \
1690 <menuitem name=\"Save\" action=\"SaveFile\" /> \
1691 <separator name=\"Separator\"/> \
Jens Axboe46974a72012-03-02 19:34:13 +01001692 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
1693 <separator name=\"Separator2\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001694 <menuitem name=\"Quit\" action=\"Quit\" /> \
1695 </menu> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01001696 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
1697 <menuitem name=\"Log\" action=\"ViewLog\" /> \
1698 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01001699 <menu name=\"Help\" action=\"HelpMenuAction\"> \
1700 <menuitem name=\"About\" action=\"About\" /> \
1701 </menu> \
1702 </menubar> \
1703 </ui> \
1704";
1705
Jens Axboe4cbe7212012-03-06 13:36:17 +01001706static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
1707 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01001708{
1709 GtkActionGroup *action_group = gtk_action_group_new("Menu");
1710 GError *error = 0;
1711
1712 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001713 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001714
1715 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1716 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
1717
1718 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
1719 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
1720}
1721
1722void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
1723 GtkWidget *vbox, GtkUIManager *ui_manager)
1724{
1725 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
1726}
1727
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001728static void init_ui(int *argc, char **argv[], struct gui *ui)
1729{
Jens Axboe0420ba62012-02-29 11:16:52 +01001730 GtkSettings *settings;
1731 GtkUIManager *uimanager;
Jens Axboe843ad232012-02-29 11:44:53 +01001732 GtkWidget *menu, *probe, *probe_frame, *probe_box;
Jens Axboe0420ba62012-02-29 11:16:52 +01001733
1734 memset(ui, 0, sizeof(*ui));
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001735
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001736 /* Magical g*thread incantation, you just need this thread stuff.
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001737 * Without it, the update that happens in gfio_update_thread_status
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001738 * doesn't really happen in a timely fashion, you need expose events
1739 */
Jens Axboeed727a42012-03-02 12:14:40 +01001740 if (!g_thread_supported())
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001741 g_thread_init(NULL);
1742 gdk_threads_init();
1743
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001744 gtk_init(argc, argv);
Jens Axboe0420ba62012-02-29 11:16:52 +01001745 settings = gtk_settings_get_default();
1746 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
1747 g_type_init();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001748
1749 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1750 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
1751 gtk_window_set_default_size(GTK_WINDOW(ui->window), 700, 500);
1752
Jens Axboe0420ba62012-02-29 11:16:52 +01001753 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
1754 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001755
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001756 ui->vbox = gtk_vbox_new(FALSE, 0);
1757 gtk_container_add(GTK_CONTAINER (ui->window), ui->vbox);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001758
Jens Axboe0420ba62012-02-29 11:16:52 +01001759 uimanager = gtk_ui_manager_new();
Jens Axboe4cbe7212012-03-06 13:36:17 +01001760 menu = get_menubar_menu(ui->window, uimanager, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001761 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
1762
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001763 /*
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001764 * Set up alignments for widgets at the top of ui,
1765 * align top left, expand horizontally but not vertically
1766 */
1767 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001768 ui->topvbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001769 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001770 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->topalign, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001771
Jens Axboe3e47bd22012-02-29 13:45:02 +01001772 probe = gtk_frame_new("Job");
Jens Axboe843ad232012-02-29 11:44:53 +01001773 gtk_box_pack_start(GTK_BOX(ui->topvbox), probe, TRUE, FALSE, 3);
1774 probe_frame = gtk_vbox_new(FALSE, 3);
1775 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
1776
1777 probe_box = gtk_hbox_new(FALSE, 3);
1778 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01001779 ui->probe.hostname = new_info_label_in_frame(probe_box, "Host");
1780 ui->probe.os = new_info_label_in_frame(probe_box, "OS");
1781 ui->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
1782 ui->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
1783
Jens Axboe3e47bd22012-02-29 13:45:02 +01001784 probe_box = gtk_hbox_new(FALSE, 3);
1785 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01001786
Jens Axboeca850992012-03-05 20:04:43 +01001787 ui->eta.name = new_info_entry_in_frame(probe_box, "Name");
1788 ui->eta.iotype = new_info_entry_in_frame(probe_box, "IO");
1789 ui->eta.ioengine = new_info_entry_in_frame(probe_box, "IO Engine");
1790 ui->eta.iodepth = new_info_entry_in_frame(probe_box, "IO Depth");
1791 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
1792 ui->eta.files = new_info_entry_in_frame(probe_box, "Open files");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001793
1794 probe_box = gtk_hbox_new(FALSE, 3);
1795 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboeca850992012-03-05 20:04:43 +01001796 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1797 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1798 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1799 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001800
1801 /*
1802 * Only add this if we have a commit rate
1803 */
1804#if 0
1805 probe_box = gtk_hbox_new(FALSE, 3);
1806 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1807
Jens Axboe3e47bd22012-02-29 13:45:02 +01001808 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1809 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1810
Jens Axboe3e47bd22012-02-29 13:45:02 +01001811 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1812 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001813#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01001814
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001815 /*
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001816 * Set up a drawing area and IOPS and bandwidth graphs
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001817 */
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001818 ui->drawing_area = gtk_drawing_area_new();
1819 gtk_widget_set_size_request(GTK_WIDGET(ui->drawing_area),
1820 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
1821 g_signal_connect(G_OBJECT(ui->drawing_area), "expose_event",
1822 G_CALLBACK (on_expose_drawing_area), ui);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001823 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1824 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1825 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001826 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1827 ui->drawing_area);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001828 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->scrolled_window,
1829 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001830
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001831 setup_iops_graph(ui);
1832 setup_bandwidth_graph(ui);
1833
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001834 /*
1835 * Set up alignments for widgets at the bottom of ui,
1836 * align bottom left, expand horizontally but not vertically
1837 */
1838 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
1839 ui->buttonbox = gtk_hbox_new(FALSE, 0);
1840 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001841 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->bottomalign,
1842 FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001843
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001844 add_buttons(ui, buttonspeclist, ARRAYSIZE(buttonspeclist));
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001845
1846 /*
1847 * Set up thread status progress bar
1848 */
1849 ui->thread_status_pb = gtk_progress_bar_new();
1850 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01001851 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001852 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
1853
Jens Axboe9b260bd2012-03-06 11:02:52 +01001854 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001855
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001856 gtk_widget_show_all(ui->window);
1857}
1858
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001859int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001860{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001861 if (initialize_fio(envp))
1862 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01001863 if (fio_init_options())
1864 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01001865
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001866 init_ui(&argc, &argv, &ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001867
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001868 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001869 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001870 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001871 return 0;
1872}