blob: 2c9a125d48294a60c43f933f29b95bfc4a9b426e [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 Axboe63a130b2012-03-06 20:08:59 +010037
Jens Axboe3e47bd22012-02-29 13:45:02 +010038static void gfio_update_thread_status(char *status_message, double perc);
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);
47
48static struct button_spec {
49 const char *buttontext;
50 clickfunction f;
51 const char *tooltiptext;
Jens Axboe3e47bd22012-02-29 13:45:02 +010052 const int start_insensitive;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010053} buttonspeclist[] = {
Jens Axboe3e47bd22012-02-29 13:45:02 +010054#define CONNECT_BUTTON 0
55#define START_JOB_BUTTON 1
56 { "Connect", connect_clicked, "Connect to host", 0 },
Stephen M. Cameronf3074002012-02-24 08:17:30 +010057 { "Start Job",
58 start_job_clicked,
Jens Axboe3e47bd22012-02-29 13:45:02 +010059 "Send current fio job to fio server to be executed", 1 },
Stephen M. Cameronf3074002012-02-24 08:17:30 +010060};
61
Jens Axboe843ad232012-02-29 11:44:53 +010062struct probe_widget {
63 GtkWidget *hostname;
64 GtkWidget *os;
65 GtkWidget *arch;
66 GtkWidget *fio_ver;
67};
68
Jens Axboe3e47bd22012-02-29 13:45:02 +010069struct eta_widget {
Jens Axboe807f9972012-03-02 10:25:24 +010070 GtkWidget *name;
71 GtkWidget *iotype;
72 GtkWidget *ioengine;
73 GtkWidget *iodepth;
Jens Axboe3e47bd22012-02-29 13:45:02 +010074 GtkWidget *jobs;
75 GtkWidget *files;
76 GtkWidget *read_bw;
77 GtkWidget *read_iops;
78 GtkWidget *cr_bw;
79 GtkWidget *cr_iops;
80 GtkWidget *write_bw;
81 GtkWidget *write_iops;
82 GtkWidget *cw_bw;
83 GtkWidget *cw_iops;
84};
85
Stephen M. Cameronff1f3282012-02-24 08:17:30 +010086struct gui {
87 GtkWidget *window;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +010088 GtkWidget *vbox;
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +010089 GtkWidget *topvbox;
90 GtkWidget *topalign;
91 GtkWidget *bottomalign;
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +010092 GtkWidget *thread_status_pb;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010093 GtkWidget *buttonbox;
94 GtkWidget *button[ARRAYSIZE(buttonspeclist)];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +010095 GtkWidget *scrolled_window;
Jens Axboe2fd3bb02012-03-07 08:07:39 +010096#define DRAWING_AREA_XDIM 1000
97#define DRAWING_AREA_YDIM 400
98 GtkWidget *drawing_area;
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +010099 int drawing_area_xdim;
100 int drawing_area_ydim;
Jens Axboe0420ba62012-02-29 11:16:52 +0100101 GtkWidget *error_info_bar;
102 GtkWidget *error_label;
Jens Axboef9d40b42012-03-06 09:52:49 +0100103 GtkWidget *results_notebook;
104 GtkWidget *results_window;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100105 GtkListStore *log_model;
106 GtkWidget *log_tree;
Jens Axboe4cbe7212012-03-06 13:36:17 +0100107 GtkWidget *log_view;
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100108 GtkTextBuffer *text;
Jens Axboe843ad232012-02-29 11:44:53 +0100109 struct probe_widget probe;
Jens Axboe3e47bd22012-02-29 13:45:02 +0100110 struct eta_widget eta;
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100111 int connected;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100112 pthread_t t;
Jens Axboe63a130b2012-03-06 20:08:59 +0100113 pthread_t server_t;
Jens Axboe0420ba62012-02-29 11:16:52 +0100114
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100115 struct graph *iops_graph;
116 struct graph *bandwidth_graph;
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100117 struct fio_client *client;
Jens Axboe0420ba62012-02-29 11:16:52 +0100118 int nr_job_files;
119 char **job_files;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100120} ui;
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100121
Jens Axboee0681f32012-03-06 12:14:42 +0100122struct gfio_client {
123 struct gui *ui;
124 GtkWidget *results_widget;
125 GtkWidget *disk_util_frame;
Jens Axboe6b79c802012-03-08 10:51:36 +0100126 GtkWidget *err_entry;
Jens Axboee0681f32012-03-06 12:14:42 +0100127};
128
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100129static void setup_iops_graph(struct gui *ui)
130{
131 if (ui->iops_graph)
132 graph_free(ui->iops_graph);
Jens Axboe87d5f272012-03-07 12:31:40 +0100133 ui->iops_graph = graph_new(DRAWING_AREA_XDIM / 2.0,
Jens Axboef3e84402012-03-07 13:14:32 +0100134 DRAWING_AREA_YDIM, gfio_graph_font);
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100135 graph_title(ui->iops_graph, "IOPS");
Stephen M. Cameronb04ad8d2012-03-07 14:49:37 +0100136 graph_x_title(ui->iops_graph, "Time (secs)");
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100137 graph_add_label(ui->iops_graph, "Read IOPS");
138 graph_add_label(ui->iops_graph, "Write IOPS");
Jens Axboe9f4883a2012-03-07 16:22:50 +0100139 graph_set_color(ui->iops_graph, "Read IOPS", 0.13, 0.54, 0.13);
140 graph_set_color(ui->iops_graph, "Write IOPS", 1.0, 0.0, 0.0);
Stephen M. Cameronfe8afdd2012-03-07 19:34:19 +0100141 line_graph_set_data_count_limit(ui->iops_graph, 100);
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100142}
143
144static void setup_bandwidth_graph(struct gui *ui)
145{
146 if (ui->bandwidth_graph)
147 graph_free(ui->bandwidth_graph);
Jens Axboe87d5f272012-03-07 12:31:40 +0100148 ui->bandwidth_graph = graph_new(DRAWING_AREA_XDIM / 2.0,
Jens Axboef3e84402012-03-07 13:14:32 +0100149 DRAWING_AREA_YDIM, gfio_graph_font);
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100150 graph_title(ui->bandwidth_graph, "Bandwidth");
Stephen M. Cameronb04ad8d2012-03-07 14:49:37 +0100151 graph_x_title(ui->bandwidth_graph, "Time (secs)");
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100152 graph_add_label(ui->bandwidth_graph, "Read Bandwidth");
153 graph_add_label(ui->bandwidth_graph, "Write Bandwidth");
Jens Axboe9f4883a2012-03-07 16:22:50 +0100154 graph_set_color(ui->bandwidth_graph, "Read Bandwidth", 0.13, 0.54, 0.13);
155 graph_set_color(ui->bandwidth_graph, "Write Bandwidth", 1.0, 0.0, 0.0);
Stephen M. Cameronfe8afdd2012-03-07 19:34:19 +0100156 line_graph_set_data_count_limit(ui->bandwidth_graph, 100);
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100157}
158
Jens Axboe8663ea62012-03-02 14:04:30 +0100159static void clear_ui_info(struct gui *ui)
160{
161 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), "");
162 gtk_label_set_text(GTK_LABEL(ui->probe.os), "");
163 gtk_label_set_text(GTK_LABEL(ui->probe.arch), "");
164 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), "");
Jens Axboeca850992012-03-05 20:04:43 +0100165 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), "");
166 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), "");
167 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), "");
168 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), "");
169 gtk_entry_set_text(GTK_ENTRY(ui->eta.jobs), "");
170 gtk_entry_set_text(GTK_ENTRY(ui->eta.files), "");
171 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), "");
172 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), "");
173 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), "");
174 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100175}
176
Jens Axboe3650a3c2012-03-05 14:09:03 +0100177static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
178{
179 GtkWidget *entry, *frame;
180
181 frame = gtk_frame_new(label);
182 entry = gtk_entry_new();
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100183 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100184 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
185 gtk_container_add(GTK_CONTAINER(frame), entry);
186
187 return entry;
188}
189
190static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
191{
192 GtkWidget *label_widget;
193 GtkWidget *frame;
194
195 frame = gtk_frame_new(label);
196 label_widget = gtk_label_new(NULL);
197 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
198 gtk_container_add(GTK_CONTAINER(frame), label_widget);
199
200 return label_widget;
201}
202
203static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
204{
205 GtkWidget *button, *box;
206
207 box = gtk_hbox_new(FALSE, 3);
208 gtk_container_add(GTK_CONTAINER(hbox), box);
209
210 button = gtk_spin_button_new_with_range(min, max, 1.0);
211 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
212
213 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
214 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
215
216 return button;
217}
218
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100219static void gfio_set_connected(struct gui *ui, int connected)
220{
221 if (connected) {
222 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
223 ui->connected = 1;
224 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Disconnect");
Jens Axboe88f6e7a2012-03-06 12:55:29 +0100225 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100226 } else {
227 ui->connected = 0;
228 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Connect");
229 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
Jens Axboe63a130b2012-03-06 20:08:59 +0100230 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100231 }
232}
233
Jens Axboe3650a3c2012-03-05 14:09:03 +0100234static void label_set_int_value(GtkWidget *entry, unsigned int val)
235{
236 char tmp[80];
237
238 sprintf(tmp, "%u", val);
239 gtk_label_set_text(GTK_LABEL(entry), tmp);
240}
241
242static void entry_set_int_value(GtkWidget *entry, unsigned int val)
243{
244 char tmp[80];
245
246 sprintf(tmp, "%u", val);
247 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
248}
249
Jens Axboea2697902012-03-05 16:43:49 +0100250#define ALIGN_LEFT 1
251#define ALIGN_RIGHT 2
252#define INVISIBLE 4
253#define UNSORTABLE 8
254
255GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
256{
257 GtkCellRenderer *renderer;
258 GtkTreeViewColumn *col;
259 double xalign = 0.0; /* left as default */
260 PangoAlignment align;
261 gboolean visible;
262
263 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
264 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
265 PANGO_ALIGN_CENTER;
266 visible = !(flags & INVISIBLE);
267
268 renderer = gtk_cell_renderer_text_new();
269 col = gtk_tree_view_column_new();
270
271 gtk_tree_view_column_set_title(col, title);
272 if (!(flags & UNSORTABLE))
273 gtk_tree_view_column_set_sort_column_id(col, index);
274 gtk_tree_view_column_set_resizable(col, TRUE);
275 gtk_tree_view_column_pack_start(col, renderer, TRUE);
276 gtk_tree_view_column_add_attribute(col, renderer, "text", index);
277 gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
278 switch (align) {
279 case PANGO_ALIGN_LEFT:
280 xalign = 0.0;
281 break;
282 case PANGO_ALIGN_CENTER:
283 xalign = 0.5;
284 break;
285 case PANGO_ALIGN_RIGHT:
286 xalign = 1.0;
287 break;
288 }
289 gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
290 gtk_tree_view_column_set_visible(col, visible);
291 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
292 return col;
293}
294
Jens Axboe9b260bd2012-03-06 11:02:52 +0100295static void gfio_ui_setup_log(struct gui *ui)
296{
297 GtkTreeSelection *selection;
298 GtkListStore *model;
299 GtkWidget *tree_view;
300
301 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
302
303 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
304 gtk_widget_set_can_focus(tree_view, FALSE);
305
306 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
307 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
Jens Axboe661f7412012-03-06 13:55:45 +0100308 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
309 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100310
311 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
312 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
313 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
Jens Axboef095d562012-03-06 13:49:12 +0100314 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100315
316 ui->log_model = model;
317 ui->log_tree = tree_view;
318}
319
Jens Axboea2697902012-03-05 16:43:49 +0100320static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
321 fio_fp64_t *plist,
322 unsigned int len,
323 const char *base,
324 unsigned int scale)
325{
326 GType types[FIO_IO_U_LIST_MAX_LEN];
327 GtkWidget *tree_view;
328 GtkTreeSelection *selection;
329 GtkListStore *model;
330 GtkTreeIter iter;
331 int i;
332
333 for (i = 0; i < len; i++)
334 types[i] = G_TYPE_INT;
335
336 model = gtk_list_store_newv(len, types);
337
338 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
339 gtk_widget_set_can_focus(tree_view, FALSE);
340
Jens Axboe661f7412012-03-06 13:55:45 +0100341 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
342 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
343
Jens Axboea2697902012-03-05 16:43:49 +0100344 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
345 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
346
347 for (i = 0; i < len; i++) {
348 char fbuf[8];
349
350 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
351 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
352 }
353
354 gtk_list_store_append(model, &iter);
355
Jens Axboee0681f32012-03-06 12:14:42 +0100356 for (i = 0; i < len; i++) {
357 if (scale)
358 ovals[i] = (ovals[i] + 999) / 1000;
Jens Axboea2697902012-03-05 16:43:49 +0100359 gtk_list_store_set(model, &iter, i, ovals[i], -1);
Jens Axboee0681f32012-03-06 12:14:42 +0100360 }
Jens Axboea2697902012-03-05 16:43:49 +0100361
362 return tree_view;
363}
364
365static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
366 int ddir)
367{
368 unsigned int *io_u_plat = ts->io_u_plat[ddir];
369 unsigned long nr = ts->clat_stat[ddir].samples;
370 fio_fp64_t *plist = ts->percentile_list;
371 unsigned int *ovals, len, minv, maxv, scale_down;
372 const char *base;
373 GtkWidget *tree_view, *frame, *hbox;
374 char tmp[64];
375
376 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
377 if (!len)
378 goto out;
379
380 /*
381 * We default to usecs, but if the value range is such that we
382 * should scale down to msecs, do that.
383 */
384 if (minv > 2000 && maxv > 99999) {
385 scale_down = 1;
386 base = "msec";
387 } else {
388 scale_down = 0;
389 base = "usec";
390 }
391
392 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
393
394 sprintf(tmp, "Completion percentiles (%s)", base);
395 frame = gtk_frame_new(tmp);
396 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
397
398 hbox = gtk_hbox_new(FALSE, 3);
399 gtk_container_add(GTK_CONTAINER(frame), hbox);
400
401 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
402out:
403 if (ovals)
404 free(ovals);
405}
406
Jens Axboe3650a3c2012-03-05 14:09:03 +0100407static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
408 unsigned long max, double mean, double dev)
409{
410 const char *base = "(usec)";
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100411 GtkWidget *hbox, *label, *frame;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100412 char *minp, *maxp;
413 char tmp[64];
414
415 if (!usec_to_msec(&min, &max, &mean, &dev))
416 base = "(msec)";
417
418 minp = num2str(min, 6, 1, 0);
419 maxp = num2str(max, 6, 1, 0);
420
Jens Axboe3650a3c2012-03-05 14:09:03 +0100421 sprintf(tmp, "%s %s", name, base);
422 frame = gtk_frame_new(tmp);
423 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
424
Jens Axboe3650a3c2012-03-05 14:09:03 +0100425 hbox = gtk_hbox_new(FALSE, 3);
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100426 gtk_container_add(GTK_CONTAINER(frame), hbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100427
428 label = new_info_label_in_frame(hbox, "Minimum");
429 gtk_label_set_text(GTK_LABEL(label), minp);
430 label = new_info_label_in_frame(hbox, "Maximum");
431 gtk_label_set_text(GTK_LABEL(label), maxp);
432 label = new_info_label_in_frame(hbox, "Average");
433 sprintf(tmp, "%5.02f", mean);
434 gtk_label_set_text(GTK_LABEL(label), tmp);
435 label = new_info_label_in_frame(hbox, "Standard deviation");
436 sprintf(tmp, "%5.02f", dev);
437 gtk_label_set_text(GTK_LABEL(label), tmp);
438
439 free(minp);
440 free(maxp);
441
442}
443
Jens Axboeca850992012-03-05 20:04:43 +0100444#define GFIO_CLAT 1
445#define GFIO_SLAT 2
446#define GFIO_LAT 4
447
Jens Axboe3650a3c2012-03-05 14:09:03 +0100448static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
449 struct thread_stat *ts, int ddir)
450{
451 const char *ddir_label[2] = { "Read", "Write" };
Jens Axboe0b761302012-03-05 20:44:11 +0100452 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
Jens Axboee0681f32012-03-06 12:14:42 +0100453 unsigned long min[3], max[3], runt;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100454 unsigned long long bw, iops;
Jens Axboeca850992012-03-05 20:04:43 +0100455 unsigned int flags = 0;
Jens Axboee0681f32012-03-06 12:14:42 +0100456 double mean[3], dev[3];
Jens Axboe3650a3c2012-03-05 14:09:03 +0100457 char *io_p, *bw_p, *iops_p;
458 int i2p;
459
460 if (!ts->runtime[ddir])
461 return;
462
463 i2p = is_power_of_2(rs->kb_base);
464 runt = ts->runtime[ddir];
465
466 bw = (1000 * ts->io_bytes[ddir]) / runt;
467 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
468 bw_p = num2str(bw, 6, 1, i2p);
469
470 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
471 iops_p = num2str(iops, 6, 1, 0);
472
473 box = gtk_hbox_new(FALSE, 3);
474 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
475
476 frame = gtk_frame_new(ddir_label[ddir]);
477 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
478
Jens Axboe0b761302012-03-05 20:44:11 +0100479 main_vbox = gtk_vbox_new(FALSE, 3);
480 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100481
482 box = gtk_hbox_new(FALSE, 3);
Jens Axboe0b761302012-03-05 20:44:11 +0100483 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100484
485 label = new_info_label_in_frame(box, "IO");
486 gtk_label_set_text(GTK_LABEL(label), io_p);
487 label = new_info_label_in_frame(box, "Bandwidth");
488 gtk_label_set_text(GTK_LABEL(label), bw_p);
489 label = new_info_label_in_frame(box, "IOPS");
490 gtk_label_set_text(GTK_LABEL(label), iops_p);
491 label = new_info_label_in_frame(box, "Runtime (msec)");
492 label_set_int_value(label, ts->runtime[ddir]);
493
Jens Axboee0681f32012-03-06 12:14:42 +0100494 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
Jens Axboeca850992012-03-05 20:04:43 +0100495 double p_of_agg = 100.0;
496 const char *bw_str = "KB";
497 char tmp[32];
498
499 if (rs->agg[ddir]) {
Jens Axboee0681f32012-03-06 12:14:42 +0100500 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
Jens Axboeca850992012-03-05 20:04:43 +0100501 if (p_of_agg > 100.0)
502 p_of_agg = 100.0;
503 }
504
Jens Axboee0681f32012-03-06 12:14:42 +0100505 if (mean[0] > 999999.9) {
506 min[0] /= 1000.0;
507 max[0] /= 1000.0;
508 mean[0] /= 1000.0;
509 dev[0] /= 1000.0;
Jens Axboeca850992012-03-05 20:04:43 +0100510 bw_str = "MB";
511 }
512
Jens Axboe0b761302012-03-05 20:44:11 +0100513 sprintf(tmp, "Bandwidth (%s)", bw_str);
514 frame = gtk_frame_new(tmp);
515 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
Jens Axboeca850992012-03-05 20:04:43 +0100516
Jens Axboe0b761302012-03-05 20:44:11 +0100517 box = gtk_hbox_new(FALSE, 3);
518 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboeca850992012-03-05 20:04:43 +0100519
Jens Axboe0b761302012-03-05 20:44:11 +0100520 label = new_info_label_in_frame(box, "Minimum");
Jens Axboee0681f32012-03-06 12:14:42 +0100521 label_set_int_value(label, min[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100522 label = new_info_label_in_frame(box, "Maximum");
Jens Axboee0681f32012-03-06 12:14:42 +0100523 label_set_int_value(label, max[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100524 label = new_info_label_in_frame(box, "Percentage of jobs");
Jens Axboeca850992012-03-05 20:04:43 +0100525 sprintf(tmp, "%3.2f%%", p_of_agg);
526 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100527 label = new_info_label_in_frame(box, "Average");
Jens Axboee0681f32012-03-06 12:14:42 +0100528 sprintf(tmp, "%5.02f", mean[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100529 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100530 label = new_info_label_in_frame(box, "Standard deviation");
Jens Axboee0681f32012-03-06 12:14:42 +0100531 sprintf(tmp, "%5.02f", dev[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100532 gtk_label_set_text(GTK_LABEL(label), tmp);
533 }
534
Jens Axboee0681f32012-03-06 12:14:42 +0100535 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
Jens Axboe2b089892012-03-06 08:09:17 +0100536 flags |= GFIO_SLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100537 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
Jens Axboe2b089892012-03-06 08:09:17 +0100538 flags |= GFIO_CLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100539 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
Jens Axboe2b089892012-03-06 08:09:17 +0100540 flags |= GFIO_LAT;
541
542 if (flags) {
543 frame = gtk_frame_new("Latency");
544 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
545
546 vbox = gtk_vbox_new(FALSE, 3);
547 gtk_container_add(GTK_CONTAINER(frame), vbox);
548
549 if (flags & GFIO_SLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100550 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
Jens Axboe2b089892012-03-06 08:09:17 +0100551 if (flags & GFIO_CLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100552 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
Jens Axboe2b089892012-03-06 08:09:17 +0100553 if (flags & GFIO_LAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100554 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
Jens Axboe2b089892012-03-06 08:09:17 +0100555 }
556
557 if (ts->clat_percentiles)
558 gfio_show_clat_percentiles(main_vbox, ts, ddir);
559
560
Jens Axboe3650a3c2012-03-05 14:09:03 +0100561 free(io_p);
562 free(bw_p);
563 free(iops_p);
564}
565
Jens Axboee5bd1342012-03-05 21:38:12 +0100566static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
567 const char **labels)
568{
569 GtkWidget *tree_view;
570 GtkTreeSelection *selection;
571 GtkListStore *model;
572 GtkTreeIter iter;
573 GType *types;
574 int i, skipped;
575
576 /*
577 * Check if all are empty, in which case don't bother
578 */
579 for (i = 0, skipped = 0; i < num; i++)
580 if (lat[i] <= 0.0)
581 skipped++;
582
583 if (skipped == num)
584 return NULL;
585
586 types = malloc(num * sizeof(GType));
587
588 for (i = 0; i < num; i++)
589 types[i] = G_TYPE_STRING;
590
591 model = gtk_list_store_newv(num, types);
592 free(types);
593 types = NULL;
594
595 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
596 gtk_widget_set_can_focus(tree_view, FALSE);
597
Jens Axboe661f7412012-03-06 13:55:45 +0100598 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
599 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
600
Jens Axboee5bd1342012-03-05 21:38:12 +0100601 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
602 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
603
604 for (i = 0; i < num; i++)
605 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
606
607 gtk_list_store_append(model, &iter);
608
609 for (i = 0; i < num; i++) {
610 char fbuf[32];
611
612 if (lat[i] <= 0.0)
613 sprintf(fbuf, "0.00");
614 else
615 sprintf(fbuf, "%3.2f%%", lat[i]);
616
617 gtk_list_store_set(model, &iter, i, fbuf, -1);
618 }
619
620 return tree_view;
621}
622
623static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
624{
625 GtkWidget *box, *frame, *tree_view;
626 double io_u_lat_u[FIO_IO_U_LAT_U_NR];
627 double io_u_lat_m[FIO_IO_U_LAT_M_NR];
628 const char *uranges[] = { "2", "4", "10", "20", "50", "100",
629 "250", "500", "750", "1000", };
630 const char *mranges[] = { "2", "4", "10", "20", "50", "100",
631 "250", "500", "750", "1000", "2000",
632 ">= 2000", };
633
634 stat_calc_lat_u(ts, io_u_lat_u);
635 stat_calc_lat_m(ts, io_u_lat_m);
636
637 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
638 if (tree_view) {
639 frame = gtk_frame_new("Latency buckets (usec)");
640 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
641
642 box = gtk_hbox_new(FALSE, 3);
643 gtk_container_add(GTK_CONTAINER(frame), box);
644 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
645 }
646
647 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
648 if (tree_view) {
649 frame = gtk_frame_new("Latency buckets (msec)");
650 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
651
652 box = gtk_hbox_new(FALSE, 3);
653 gtk_container_add(GTK_CONTAINER(frame), box);
654 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
655 }
656}
657
Jens Axboe2e331012012-03-05 22:07:54 +0100658static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
659{
660 GtkWidget *box, *frame, *entry;
661 double usr_cpu, sys_cpu;
662 unsigned long runtime;
663 char tmp[32];
664
665 runtime = ts->total_run_time;
666 if (runtime) {
667 double runt = (double) runtime;
668
669 usr_cpu = (double) ts->usr_time * 100 / runt;
670 sys_cpu = (double) ts->sys_time * 100 / runt;
671 } else {
672 usr_cpu = 0;
673 sys_cpu = 0;
674 }
675
676 frame = gtk_frame_new("OS resources");
677 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
678
679 box = gtk_hbox_new(FALSE, 3);
680 gtk_container_add(GTK_CONTAINER(frame), box);
681
682 entry = new_info_entry_in_frame(box, "User CPU");
683 sprintf(tmp, "%3.2f%%", usr_cpu);
684 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
685 entry = new_info_entry_in_frame(box, "System CPU");
686 sprintf(tmp, "%3.2f%%", sys_cpu);
687 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
688 entry = new_info_entry_in_frame(box, "Context switches");
689 entry_set_int_value(entry, ts->ctx);
690 entry = new_info_entry_in_frame(box, "Major faults");
691 entry_set_int_value(entry, ts->majf);
692 entry = new_info_entry_in_frame(box, "Minor faults");
693 entry_set_int_value(entry, ts->minf);
694}
Jens Axboe19998db2012-03-06 09:17:59 +0100695static void gfio_add_sc_depths_tree(GtkListStore *model,
696 struct thread_stat *ts, unsigned int len,
697 int submit)
698{
699 double io_u_dist[FIO_IO_U_MAP_NR];
700 GtkTreeIter iter;
701 /* Bits 0, and 3-8 */
702 const int add_mask = 0x1f9;
703 int i, j;
704
705 if (submit)
706 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
707 else
708 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
709
710 gtk_list_store_append(model, &iter);
711
712 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
713
714 for (i = 1, j = 0; i < len; i++) {
715 char fbuf[32];
716
717 if (!(add_mask & (1UL << (i - 1))))
718 sprintf(fbuf, "0.0%%");
719 else {
720 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
721 j++;
722 }
723
724 gtk_list_store_set(model, &iter, i, fbuf, -1);
725 }
726
727}
728
729static void gfio_add_total_depths_tree(GtkListStore *model,
730 struct thread_stat *ts, unsigned int len)
731{
732 double io_u_dist[FIO_IO_U_MAP_NR];
733 GtkTreeIter iter;
734 /* Bits 1-6, and 8 */
735 const int add_mask = 0x17e;
736 int i, j;
737
738 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
739
740 gtk_list_store_append(model, &iter);
741
742 gtk_list_store_set(model, &iter, 0, "Total", -1);
743
744 for (i = 1, j = 0; i < len; i++) {
745 char fbuf[32];
746
747 if (!(add_mask & (1UL << (i - 1))))
748 sprintf(fbuf, "0.0%%");
749 else {
750 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
751 j++;
752 }
753
754 gtk_list_store_set(model, &iter, i, fbuf, -1);
755 }
756
757}
Jens Axboe2e331012012-03-05 22:07:54 +0100758
759static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
760{
Jens Axboe2e331012012-03-05 22:07:54 +0100761 GtkWidget *frame, *box, *tree_view;
762 GtkTreeSelection *selection;
763 GtkListStore *model;
Jens Axboe2e331012012-03-05 22:07:54 +0100764 GType types[FIO_IO_U_MAP_NR + 1];
765 int i;
Jens Axboe19998db2012-03-06 09:17:59 +0100766#define NR_LABELS 10
767 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
Jens Axboe2e331012012-03-05 22:07:54 +0100768
769 frame = gtk_frame_new("IO depths");
770 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
771
772 box = gtk_hbox_new(FALSE, 3);
773 gtk_container_add(GTK_CONTAINER(frame), box);
774
Jens Axboe19998db2012-03-06 09:17:59 +0100775 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100776 types[i] = G_TYPE_STRING;
777
Jens Axboe19998db2012-03-06 09:17:59 +0100778 model = gtk_list_store_newv(NR_LABELS, types);
Jens Axboe2e331012012-03-05 22:07:54 +0100779
780 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
781 gtk_widget_set_can_focus(tree_view, FALSE);
782
Jens Axboe661f7412012-03-06 13:55:45 +0100783 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
784 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
785
Jens Axboe2e331012012-03-05 22:07:54 +0100786 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
787 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
788
Jens Axboe19998db2012-03-06 09:17:59 +0100789 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100790 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
791
Jens Axboe19998db2012-03-06 09:17:59 +0100792 gfio_add_total_depths_tree(model, ts, NR_LABELS);
793 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 1);
794 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 0);
Jens Axboe2e331012012-03-05 22:07:54 +0100795
796 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
797}
798
Jens Axboef9d40b42012-03-06 09:52:49 +0100799static gboolean results_window_delete(GtkWidget *w, gpointer data)
800{
801 struct gui *ui = (struct gui *) data;
802
803 gtk_widget_destroy(w);
804 ui->results_window = NULL;
805 ui->results_notebook = NULL;
806 return TRUE;
807}
808
809static GtkWidget *get_results_window(struct gui *ui)
810{
811 GtkWidget *win, *notebook;
812
813 if (ui->results_window)
814 return ui->results_notebook;
815
816 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
817 gtk_window_set_title(GTK_WINDOW(win), "Results");
Jens Axboeb01329d2012-03-07 20:31:28 +0100818 gtk_window_set_default_size(GTK_WINDOW(win), 1024, 768);
Jens Axboef9d40b42012-03-06 09:52:49 +0100819 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ui);
820 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ui);
821
822 notebook = gtk_notebook_new();
823 gtk_container_add(GTK_CONTAINER(win), notebook);
824
825 ui->results_window = win;
826 ui->results_notebook = notebook;
827 return ui->results_notebook;
828}
829
Jens Axboe3650a3c2012-03-05 14:09:03 +0100830static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
831 struct group_run_stats *rs)
832{
Jens Axboeb01329d2012-03-07 20:31:28 +0100833 GtkWidget *res_win, *box, *vbox, *entry, *scroll;
Jens Axboee0681f32012-03-06 12:14:42 +0100834 struct gfio_client *gc = client->client_data;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100835
836 gdk_threads_enter();
837
Jens Axboee0681f32012-03-06 12:14:42 +0100838 res_win = get_results_window(gc->ui);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100839
Jens Axboeb01329d2012-03-07 20:31:28 +0100840 scroll = gtk_scrolled_window_new(NULL, NULL);
841 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
842 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
843
Jens Axboe3650a3c2012-03-05 14:09:03 +0100844 vbox = gtk_vbox_new(FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100845
Jens Axboeb01329d2012-03-07 20:31:28 +0100846 box = gtk_hbox_new(FALSE, 0);
847 gtk_box_pack_start(GTK_BOX(vbox), box, TRUE, FALSE, 5);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100848
Jens Axboeb01329d2012-03-07 20:31:28 +0100849 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
850
851 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), scroll, gtk_label_new(ts->name));
Jens Axboef9d40b42012-03-06 09:52:49 +0100852
Jens Axboee0681f32012-03-06 12:14:42 +0100853 gc->results_widget = vbox;
854
Jens Axboe3650a3c2012-03-05 14:09:03 +0100855 entry = new_info_entry_in_frame(box, "Name");
856 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
857 if (strlen(ts->description)) {
858 entry = new_info_entry_in_frame(box, "Description");
859 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
860 }
861 entry = new_info_entry_in_frame(box, "Group ID");
862 entry_set_int_value(entry, ts->groupid);
863 entry = new_info_entry_in_frame(box, "Jobs");
864 entry_set_int_value(entry, ts->members);
Jens Axboe6b79c802012-03-08 10:51:36 +0100865 gc->err_entry = entry = new_info_entry_in_frame(box, "Error");
Jens Axboe3650a3c2012-03-05 14:09:03 +0100866 entry_set_int_value(entry, ts->error);
867 entry = new_info_entry_in_frame(box, "PID");
868 entry_set_int_value(entry, ts->pid);
869
870 if (ts->io_bytes[DDIR_READ])
871 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
872 if (ts->io_bytes[DDIR_WRITE])
873 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
874
Jens Axboee5bd1342012-03-05 21:38:12 +0100875 gfio_show_latency_buckets(vbox, ts);
Jens Axboe2e331012012-03-05 22:07:54 +0100876 gfio_show_cpu_usage(vbox, ts);
877 gfio_show_io_depths(vbox, ts);
Jens Axboee5bd1342012-03-05 21:38:12 +0100878
Jens Axboee0681f32012-03-06 12:14:42 +0100879 gtk_widget_show_all(gc->ui->results_window);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100880 gdk_threads_leave();
881}
882
Jens Axboe084d1c62012-03-03 20:28:07 +0100883static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100884{
Jens Axboe9b260bd2012-03-06 11:02:52 +0100885 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +0100886 struct gfio_client *gc = client->client_data;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100887 GtkTreeIter iter;
888 struct tm *tm;
889 time_t sec;
890 char tmp[64], timebuf[80];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100891
Jens Axboe9b260bd2012-03-06 11:02:52 +0100892 sec = p->log_sec;
893 tm = localtime(&sec);
894 strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", tm);
895 sprintf(timebuf, "%s.%03ld", tmp, p->log_usec / 1000);
896
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100897 gdk_threads_enter();
Jens Axboe9b260bd2012-03-06 11:02:52 +0100898
Jens Axboee0681f32012-03-06 12:14:42 +0100899 gtk_list_store_append(gc->ui->log_model, &iter);
900 gtk_list_store_set(gc->ui->log_model, &iter, 0, timebuf, -1);
901 gtk_list_store_set(gc->ui->log_model, &iter, 1, client->hostname, -1);
902 gtk_list_store_set(gc->ui->log_model, &iter, 2, p->level, -1);
903 gtk_list_store_set(gc->ui->log_model, &iter, 3, p->buf, -1);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100904
Jens Axboe6b79c802012-03-08 10:51:36 +0100905 if (p->level == FIO_LOG_ERR)
906 view_log(NULL, (gpointer) gc->ui);
907
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100908 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100909}
910
911static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
912{
Jens Axboee0681f32012-03-06 12:14:42 +0100913 struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
914 struct gfio_client *gc = client->client_data;
915 GtkWidget *box, *frame, *entry, *vbox;
Jens Axboe604cfe32012-03-07 19:51:36 +0100916 double util;
917 char tmp[16];
Jens Axboee0681f32012-03-06 12:14:42 +0100918
Jens Axboe0050e5f2012-03-06 09:23:27 +0100919 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +0100920
Jens Axboe45dcb2e2012-03-07 16:16:50 +0100921 if (!gc->results_widget)
Jens Axboee0681f32012-03-06 12:14:42 +0100922 goto out;
Jens Axboee0681f32012-03-06 12:14:42 +0100923
924 if (!gc->disk_util_frame) {
925 gc->disk_util_frame = gtk_frame_new("Disk utilization");
926 gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
927 }
928
929 vbox = gtk_vbox_new(FALSE, 3);
930 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
931
932 frame = gtk_frame_new((char *) p->dus.name);
933 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
934
935 box = gtk_vbox_new(FALSE, 3);
936 gtk_container_add(GTK_CONTAINER(frame), box);
937
938 frame = gtk_frame_new("Read");
939 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
940 vbox = gtk_hbox_new(TRUE, 3);
941 gtk_container_add(GTK_CONTAINER(frame), vbox);
942 entry = new_info_entry_in_frame(vbox, "IOs");
943 entry_set_int_value(entry, p->dus.ios[0]);
944 entry = new_info_entry_in_frame(vbox, "Merges");
945 entry_set_int_value(entry, p->dus.merges[0]);
946 entry = new_info_entry_in_frame(vbox, "Sectors");
947 entry_set_int_value(entry, p->dus.sectors[0]);
948 entry = new_info_entry_in_frame(vbox, "Ticks");
949 entry_set_int_value(entry, p->dus.ticks[0]);
950
951 frame = gtk_frame_new("Write");
952 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
953 vbox = gtk_hbox_new(TRUE, 3);
954 gtk_container_add(GTK_CONTAINER(frame), vbox);
955 entry = new_info_entry_in_frame(vbox, "IOs");
956 entry_set_int_value(entry, p->dus.ios[1]);
957 entry = new_info_entry_in_frame(vbox, "Merges");
958 entry_set_int_value(entry, p->dus.merges[1]);
959 entry = new_info_entry_in_frame(vbox, "Sectors");
960 entry_set_int_value(entry, p->dus.sectors[1]);
961 entry = new_info_entry_in_frame(vbox, "Ticks");
962 entry_set_int_value(entry, p->dus.ticks[1]);
963
964 frame = gtk_frame_new("Shared");
965 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
966 vbox = gtk_hbox_new(TRUE, 3);
967 gtk_container_add(GTK_CONTAINER(frame), vbox);
968 entry = new_info_entry_in_frame(vbox, "IO ticks");
969 entry_set_int_value(entry, p->dus.io_ticks);
970 entry = new_info_entry_in_frame(vbox, "Time in queue");
971 entry_set_int_value(entry, p->dus.time_in_queue);
972
Jens Axboe604cfe32012-03-07 19:51:36 +0100973 util = 0.0;
974 if (p->dus.msec)
975 util = (double) 100 * p->dus.io_ticks / (double) p->dus.msec;
976 if (util > 100.0)
977 util = 100.0;
978
979 sprintf(tmp, "%3.2f%%", util);
980 entry = new_info_entry_in_frame(vbox, "Disk utilization");
981 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
982
Jens Axboee0681f32012-03-06 12:14:42 +0100983 gtk_widget_show_all(gc->results_widget);
984out:
Jens Axboe0050e5f2012-03-06 09:23:27 +0100985 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100986}
987
Jens Axboe3650a3c2012-03-05 14:09:03 +0100988extern int sum_stat_clients;
989extern struct thread_stat client_ts;
990extern struct group_run_stats client_gs;
991
992static int sum_stat_nr;
993
Jens Axboe89e5fad2012-03-05 09:21:12 +0100994static void gfio_thread_status_op(struct fio_client *client,
995 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100996{
Jens Axboe3650a3c2012-03-05 14:09:03 +0100997 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
998
999 gfio_display_ts(client, &p->ts, &p->rs);
1000
1001 if (sum_stat_clients == 1)
1002 return;
1003
1004 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
1005 sum_group_stats(&client_gs, &p->rs);
1006
1007 client_ts.members++;
1008 client_ts.groupid = p->ts.groupid;
1009
1010 if (++sum_stat_nr == sum_stat_clients) {
1011 strcpy(client_ts.name, "All clients");
1012 gfio_display_ts(client, &client_ts, &client_gs);
1013 }
Stephen M. Camerona1820202012-02-24 08:17:31 +01001014}
1015
Jens Axboe89e5fad2012-03-05 09:21:12 +01001016static void gfio_group_stats_op(struct fio_client *client,
1017 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001018{
Jens Axboe0050e5f2012-03-06 09:23:27 +01001019 gdk_threads_enter();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001020 printf("gfio_group_stats_op called\n");
Jens Axboe89e5fad2012-03-05 09:21:12 +01001021 fio_client_ops.group_stats(client, cmd);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001022 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001023}
1024
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001025static gint on_config_drawing_area(GtkWidget *w, GdkEventConfigure *event)
1026{
1027 ui.drawing_area_xdim = w->allocation.width;
1028 ui.drawing_area_ydim = w->allocation.height;
1029 return TRUE;
1030}
1031
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001032static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
1033{
1034 struct gui *ui = (struct gui *) p;
1035 cairo_t *cr;
1036
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001037 graph_set_size(ui->iops_graph, ui->drawing_area_xdim / 2.0,
1038 ui->drawing_area_ydim);
1039 graph_set_size(ui->bandwidth_graph, ui->drawing_area_xdim / 2.0,
1040 ui->drawing_area_ydim);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001041 cr = gdk_cairo_create(w->window);
1042
1043 cairo_set_source_rgb(cr, 0, 0, 0);
1044
1045 cairo_save(cr);
1046 cairo_translate(cr, 0, 0);
1047 line_graph_draw(ui->bandwidth_graph, cr);
1048 cairo_stroke(cr);
1049 cairo_restore(cr);
1050
1051 cairo_save(cr);
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001052 cairo_translate(cr, ui->drawing_area_xdim / 2.0, 0);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001053 line_graph_draw(ui->iops_graph, cr);
1054 cairo_stroke(cr);
1055 cairo_restore(cr);
1056 cairo_destroy(cr);
1057
1058 return FALSE;
1059}
1060
Jens Axboe3e47bd22012-02-29 13:45:02 +01001061static void gfio_update_eta(struct jobs_eta *je)
1062{
1063 static int eta_good;
1064 char eta_str[128];
1065 char output[256];
1066 char tmp[32];
1067 double perc = 0.0;
1068 int i2p = 0;
1069
Jens Axboe0050e5f2012-03-06 09:23:27 +01001070 gdk_threads_enter();
1071
Jens Axboe3e47bd22012-02-29 13:45:02 +01001072 eta_str[0] = '\0';
1073 output[0] = '\0';
1074
1075 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1076 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1077 eta_to_str(eta_str, je->eta_sec);
1078 }
1079
1080 sprintf(tmp, "%u", je->nr_running);
Jens Axboeca850992012-03-05 20:04:43 +01001081 gtk_entry_set_text(GTK_ENTRY(ui.eta.jobs), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001082 sprintf(tmp, "%u", je->files_open);
Jens Axboeca850992012-03-05 20:04:43 +01001083 gtk_entry_set_text(GTK_ENTRY(ui.eta.files), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001084
1085#if 0
1086 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1087 if (je->m_rate || je->t_rate) {
1088 char *tr, *mr;
1089
1090 mr = num2str(je->m_rate, 4, 0, i2p);
1091 tr = num2str(je->t_rate, 4, 0, i2p);
Jens Axboeca850992012-03-05 20:04:43 +01001092 gtk_entry_set_text(GTK_ENTRY(ui.eta);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001093 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1094 free(tr);
1095 free(mr);
1096 } else if (je->m_iops || je->t_iops)
1097 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
Jens Axboeebbd89c2012-03-02 11:21:13 +01001098
Jens Axboeca850992012-03-05 20:04:43 +01001099 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_bw), "---");
1100 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_iops), "---");
1101 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_bw), "---");
1102 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_iops), "---");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001103#endif
1104
1105 if (je->eta_sec != INT_MAX && je->nr_running) {
1106 char *iops_str[2];
1107 char *rate_str[2];
1108
1109 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1110 strcpy(output, "-.-% done");
1111 else {
1112 eta_good = 1;
1113 perc *= 100.0;
1114 sprintf(output, "%3.1f%% done", perc);
1115 }
1116
1117 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1118 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1119
1120 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1121 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1122
Jens Axboeca850992012-03-05 20:04:43 +01001123 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_bw), rate_str[0]);
1124 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_iops), iops_str[0]);
1125 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_bw), rate_str[1]);
1126 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_iops), iops_str[1]);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001127
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001128 graph_add_xy_data(ui.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1129 graph_add_xy_data(ui.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1130 graph_add_xy_data(ui.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1131 graph_add_xy_data(ui.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
1132
Jens Axboe3e47bd22012-02-29 13:45:02 +01001133 free(rate_str[0]);
1134 free(rate_str[1]);
1135 free(iops_str[0]);
1136 free(iops_str[1]);
1137 }
1138
1139 if (eta_str[0]) {
1140 char *dst = output + strlen(output);
1141
1142 sprintf(dst, " - %s", eta_str);
1143 }
1144
1145 gfio_update_thread_status(output, perc);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001146 gdk_threads_leave();
Jens Axboe3e47bd22012-02-29 13:45:02 +01001147}
1148
Stephen M. Camerona1820202012-02-24 08:17:31 +01001149static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1150{
Jens Axboe843ad232012-02-29 11:44:53 +01001151 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001152 struct gfio_client *gc = client->client_data;
1153 struct gui *ui = gc->ui;
Jens Axboe843ad232012-02-29 11:44:53 +01001154 const char *os, *arch;
1155 char buf[64];
1156
1157 os = fio_get_os_string(probe->os);
1158 if (!os)
1159 os = "unknown";
1160
1161 arch = fio_get_arch_string(probe->arch);
1162 if (!arch)
1163 os = "unknown";
1164
1165 if (!client->name)
1166 client->name = strdup((char *) probe->hostname);
1167
Jens Axboe0050e5f2012-03-06 09:23:27 +01001168 gdk_threads_enter();
1169
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001170 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), (char *) probe->hostname);
1171 gtk_label_set_text(GTK_LABEL(ui->probe.os), os);
1172 gtk_label_set_text(GTK_LABEL(ui->probe.arch), arch);
Jens Axboe843ad232012-02-29 11:44:53 +01001173 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001174 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), buf);
1175
1176 gfio_set_connected(ui, 1);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001177
1178 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001179}
1180
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001181static void gfio_update_thread_status(char *status_message, double perc)
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001182{
1183 static char message[100];
1184 const char *m = message;
1185
1186 strncpy(message, status_message, sizeof(message) - 1);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001187 gtk_progress_bar_set_text(
1188 GTK_PROGRESS_BAR(ui.thread_status_pb), m);
1189 gtk_progress_bar_set_fraction(
1190 GTK_PROGRESS_BAR(ui.thread_status_pb), perc / 100.0);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001191 gtk_widget_queue_draw(ui.window);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001192}
1193
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001194static void gfio_quit_op(struct fio_client *client)
1195{
Jens Axboee0681f32012-03-06 12:14:42 +01001196 struct gfio_client *gc = client->client_data;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001197
Jens Axboe0050e5f2012-03-06 09:23:27 +01001198 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +01001199 gfio_set_connected(gc->ui, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001200 gdk_threads_leave();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001201}
1202
Jens Axboe807f9972012-03-02 10:25:24 +01001203static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1204{
1205 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +01001206 struct gfio_client *gc = client->client_data;
1207 struct gui *ui = gc->ui;
Jens Axboe807f9972012-03-02 10:25:24 +01001208 char tmp[8];
1209 int i;
1210
1211 p->iodepth = le32_to_cpu(p->iodepth);
1212 p->rw = le32_to_cpu(p->rw);
1213
1214 for (i = 0; i < 2; i++) {
1215 p->min_bs[i] = le32_to_cpu(p->min_bs[i]);
1216 p->max_bs[i] = le32_to_cpu(p->max_bs[i]);
1217 }
1218
1219 p->numjobs = le32_to_cpu(p->numjobs);
1220 p->group_reporting = le32_to_cpu(p->group_reporting);
1221
Jens Axboe0050e5f2012-03-06 09:23:27 +01001222 gdk_threads_enter();
1223
Jens Axboeca850992012-03-05 20:04:43 +01001224 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), (gchar *) p->jobname);
1225 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), ddir_str(p->rw));
1226 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), (gchar *) p->ioengine);
Jens Axboe807f9972012-03-02 10:25:24 +01001227
1228 sprintf(tmp, "%u", p->iodepth);
Jens Axboeca850992012-03-05 20:04:43 +01001229 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), tmp);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001230
1231 gdk_threads_leave();
Jens Axboe807f9972012-03-02 10:25:24 +01001232}
1233
Jens Axboeed727a42012-03-02 12:14:40 +01001234static void gfio_client_timed_out(struct fio_client *client)
1235{
Jens Axboee0681f32012-03-06 12:14:42 +01001236 struct gfio_client *gc = client->client_data;
Jens Axboeed727a42012-03-02 12:14:40 +01001237 GtkWidget *dialog, *label, *content;
1238 char buf[256];
1239
1240 gdk_threads_enter();
1241
Jens Axboee0681f32012-03-06 12:14:42 +01001242 gfio_set_connected(gc->ui, 0);
1243 clear_ui_info(gc->ui);
Jens Axboeed727a42012-03-02 12:14:40 +01001244
1245 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
1246
1247 dialog = gtk_dialog_new_with_buttons("Timed out!",
Jens Axboee0681f32012-03-06 12:14:42 +01001248 GTK_WINDOW(gc->ui->window),
Jens Axboeed727a42012-03-02 12:14:40 +01001249 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1250 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1251
Jens Axboef1299092012-03-07 20:00:02 +01001252 /* gtk_dialog_get_content_area() is 2.14 and newer */
1253 content = GTK_DIALOG(dialog)->vbox;
1254
Jens Axboeed727a42012-03-02 12:14:40 +01001255 label = gtk_label_new((const gchar *) buf);
1256 gtk_container_add(GTK_CONTAINER(content), label);
1257 gtk_widget_show_all(dialog);
1258 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1259
1260 gtk_dialog_run(GTK_DIALOG(dialog));
1261 gtk_widget_destroy(dialog);
1262
1263 gdk_threads_leave();
1264}
1265
Jens Axboe6b79c802012-03-08 10:51:36 +01001266static void gfio_client_stop(struct fio_client *client, struct fio_net_cmd *cmd)
1267{
1268 struct gfio_client *gc = client->client_data;
1269
1270 gdk_threads_enter();
1271
1272 gfio_set_connected(gc->ui, 0);
1273
1274 if (gc->err_entry)
1275 entry_set_int_value(gc->err_entry, client->error);
1276
1277 gdk_threads_leave();
1278}
1279
Stephen M. Camerona1820202012-02-24 08:17:31 +01001280struct client_ops gfio_client_ops = {
Jens Axboe0420ba62012-02-29 11:16:52 +01001281 .text_op = gfio_text_op,
1282 .disk_util = gfio_disk_util_op,
1283 .thread_status = gfio_thread_status_op,
1284 .group_stats = gfio_group_stats_op,
Jens Axboea5276612012-03-04 15:15:08 +01001285 .eta = gfio_update_eta,
Jens Axboe0420ba62012-02-29 11:16:52 +01001286 .probe = gfio_probe_op,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001287 .quit = gfio_quit_op,
Jens Axboe807f9972012-03-02 10:25:24 +01001288 .add_job = gfio_add_job_op,
Jens Axboeed727a42012-03-02 12:14:40 +01001289 .timed_out = gfio_client_timed_out,
Jens Axboe6b79c802012-03-08 10:51:36 +01001290 .stop = gfio_client_stop,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001291 .stay_connected = 1,
Stephen M. Camerona1820202012-02-24 08:17:31 +01001292};
1293
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001294static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1295 __attribute__((unused)) gpointer data)
1296{
1297 gtk_main_quit();
1298}
1299
Stephen M. Cameron25927252012-02-24 08:17:31 +01001300static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001301{
Stephen M. Cameron25927252012-02-24 08:17:31 +01001302 fio_handle_clients(&gfio_client_ops);
Stephen M. Cameron25927252012-02-24 08:17:31 +01001303 return NULL;
1304}
1305
Jens Axboe0420ba62012-02-29 11:16:52 +01001306static int send_job_files(struct gui *ui)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001307{
Jens Axboe441013b2012-03-01 08:01:52 +01001308 int i, ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001309
Jens Axboe0420ba62012-02-29 11:16:52 +01001310 for (i = 0; i < ui->nr_job_files; i++) {
1311 ret = fio_clients_send_ini(ui->job_files[i]);
Jens Axboe441013b2012-03-01 08:01:52 +01001312 if (ret)
1313 break;
1314
Jens Axboe0420ba62012-02-29 11:16:52 +01001315 free(ui->job_files[i]);
1316 ui->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001317 }
1318 while (i < ui->nr_job_files) {
1319 free(ui->job_files[i]);
1320 ui->job_files[i] = NULL;
1321 i++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001322 }
1323
Jens Axboe441013b2012-03-01 08:01:52 +01001324 return ret;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001325}
1326
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001327static void start_job_thread(struct gui *ui)
Stephen M. Cameron25927252012-02-24 08:17:31 +01001328{
Jens Axboe0420ba62012-02-29 11:16:52 +01001329 if (send_job_files(ui)) {
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001330 printf("Yeah, I didn't really like those options too much.\n");
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001331 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
1332 return;
1333 }
Stephen M. Cameron25927252012-02-24 08:17:31 +01001334}
1335
Jens Axboe63a130b2012-03-06 20:08:59 +01001336static void *server_thread(void *arg)
1337{
1338 is_backend = 1;
1339 gfio_server_running = 1;
1340 fio_start_server(NULL);
1341 gfio_server_running = 0;
1342 return NULL;
1343}
1344
1345static void gfio_start_server(struct gui *ui)
1346{
1347 if (!gfio_server_running) {
1348 gfio_server_running = 1;
1349 pthread_create(&ui->server_t, NULL, server_thread, NULL);
Jens Axboee34f6ad2012-03-06 20:47:15 +01001350 pthread_detach(ui->server_t);
Jens Axboe63a130b2012-03-06 20:08:59 +01001351 }
1352}
1353
Stephen M. Cameron25927252012-02-24 08:17:31 +01001354static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1355 gpointer data)
1356{
1357 struct gui *ui = data;
1358
Stephen M. Cameron25927252012-02-24 08:17:31 +01001359 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001360 start_job_thread(ui);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001361}
1362
Jens Axboedf06f222012-03-02 13:32:04 +01001363static void file_open(GtkWidget *w, gpointer data);
1364
1365static void connect_clicked(GtkWidget *widget, gpointer data)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001366{
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001367 struct gui *ui = data;
1368
1369 if (!ui->connected) {
Jens Axboedf06f222012-03-02 13:32:04 +01001370 if (!ui->nr_job_files)
1371 file_open(widget, data);
Jens Axboe8663ea62012-03-02 14:04:30 +01001372 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
Jens Axboee34f6ad2012-03-06 20:47:15 +01001373 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe69406b92012-03-06 14:00:42 +01001374 if (!fio_clients_connect()) {
1375 pthread_create(&ui->t, NULL, job_thread, NULL);
1376 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 0);
1377 }
Jens Axboedf06f222012-03-02 13:32:04 +01001378 } else {
1379 fio_clients_terminate();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001380 gfio_set_connected(ui, 0);
Jens Axboe88432652012-03-02 19:09:31 +01001381 clear_ui_info(ui);
Jens Axboedf06f222012-03-02 13:32:04 +01001382 }
Jens Axboe3e47bd22012-02-29 13:45:02 +01001383}
1384
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001385static void add_button(struct gui *ui, int i, GtkWidget *buttonbox,
1386 struct button_spec *buttonspec)
1387{
1388 ui->button[i] = gtk_button_new_with_label(buttonspec->buttontext);
1389 g_signal_connect(ui->button[i], "clicked", G_CALLBACK (buttonspec->f), ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001390 gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], FALSE, FALSE, 3);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001391 gtk_widget_set_tooltip_text(ui->button[i], buttonspeclist[i].tooltiptext);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001392 gtk_widget_set_sensitive(ui->button[i], !buttonspec->start_insensitive);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001393}
1394
1395static void add_buttons(struct gui *ui,
1396 struct button_spec *buttonlist,
1397 int nbuttons)
1398{
1399 int i;
1400
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001401 for (i = 0; i < nbuttons; i++)
1402 add_button(ui, i, ui->buttonbox, &buttonlist[i]);
1403}
1404
Jens Axboe0420ba62012-02-29 11:16:52 +01001405static void on_info_bar_response(GtkWidget *widget, gint response,
1406 gpointer data)
1407{
1408 if (response == GTK_RESPONSE_OK) {
1409 gtk_widget_destroy(widget);
1410 ui.error_info_bar = NULL;
1411 }
1412}
1413
Jens Axboedf06f222012-03-02 13:32:04 +01001414void report_error(GError *error)
Jens Axboe0420ba62012-02-29 11:16:52 +01001415{
1416 if (ui.error_info_bar == NULL) {
1417 ui.error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
1418 GTK_RESPONSE_OK,
1419 NULL);
1420 g_signal_connect(ui.error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1421 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui.error_info_bar),
1422 GTK_MESSAGE_ERROR);
1423
1424 ui.error_label = gtk_label_new(error->message);
1425 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui.error_info_bar));
1426 gtk_container_add(GTK_CONTAINER(container), ui.error_label);
1427
1428 gtk_box_pack_start(GTK_BOX(ui.vbox), ui.error_info_bar, FALSE, FALSE, 0);
1429 gtk_widget_show_all(ui.vbox);
1430 } else {
1431 char buffer[256];
1432 snprintf(buffer, sizeof(buffer), "Failed to open file.");
1433 gtk_label_set(GTK_LABEL(ui.error_label), buffer);
1434 }
1435}
1436
Jens Axboe62bc9372012-03-07 11:45:07 +01001437struct connection_widgets
1438{
1439 GtkWidget *hentry;
1440 GtkWidget *combo;
1441 GtkWidget *button;
1442};
1443
1444static void hostname_cb(GtkEntry *entry, gpointer data)
1445{
1446 struct connection_widgets *cw = data;
1447 int uses_net = 0, is_localhost = 0;
1448 const gchar *text;
1449 gchar *ctext;
1450
1451 /*
1452 * Check whether to display the 'auto start backend' box
1453 * or not. Show it if we are a localhost and using network,
1454 * or using a socket.
1455 */
1456 ctext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->combo));
1457 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
1458 uses_net = 1;
1459 g_free(ctext);
1460
1461 if (uses_net) {
1462 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
1463 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
1464 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
1465 !strcmp(text, "ip6-loopback"))
1466 is_localhost = 1;
1467 }
1468
1469 if (!uses_net || is_localhost) {
1470 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
1471 gtk_widget_set_sensitive(cw->button, 1);
1472 } else {
1473 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
1474 gtk_widget_set_sensitive(cw->button, 0);
1475 }
1476}
1477
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001478static int get_connection_details(char **host, int *port, int *type,
1479 int *server_start)
Jens Axboea7a42ce2012-03-02 13:12:04 +01001480{
Jens Axboe62bc9372012-03-07 11:45:07 +01001481 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
1482 struct connection_widgets cw;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001483 char *typeentry;
1484
1485 dialog = gtk_dialog_new_with_buttons("Connection details",
1486 GTK_WINDOW(ui.window),
1487 GTK_DIALOG_DESTROY_WITH_PARENT,
1488 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1489 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1490
1491 frame = gtk_frame_new("Hostname / socket name");
Jens Axboef1299092012-03-07 20:00:02 +01001492 /* gtk_dialog_get_content_area() is 2.14 and newer */
1493 vbox = GTK_DIALOG(dialog)->vbox;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001494 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1495
1496 box = gtk_vbox_new(FALSE, 6);
1497 gtk_container_add(GTK_CONTAINER(frame), box);
1498
1499 hbox = gtk_hbox_new(TRUE, 10);
1500 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe62bc9372012-03-07 11:45:07 +01001501 cw.hentry = gtk_entry_new();
1502 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
1503 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001504
1505 frame = gtk_frame_new("Port");
1506 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1507 box = gtk_vbox_new(FALSE, 10);
1508 gtk_container_add(GTK_CONTAINER(frame), box);
1509
1510 hbox = gtk_hbox_new(TRUE, 4);
1511 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1512 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1513
1514 frame = gtk_frame_new("Type");
1515 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1516 box = gtk_vbox_new(FALSE, 10);
1517 gtk_container_add(GTK_CONTAINER(frame), box);
1518
1519 hbox = gtk_hbox_new(TRUE, 4);
1520 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1521
Jens Axboe62bc9372012-03-07 11:45:07 +01001522 cw.combo = gtk_combo_box_new_text();
1523 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv4");
1524 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv6");
1525 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "local socket");
1526 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001527
Jens Axboe62bc9372012-03-07 11:45:07 +01001528 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001529
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001530 frame = gtk_frame_new("Options");
1531 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1532 box = gtk_vbox_new(FALSE, 10);
1533 gtk_container_add(GTK_CONTAINER(frame), box);
1534
1535 hbox = gtk_hbox_new(TRUE, 4);
1536 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1537
Jens Axboe62bc9372012-03-07 11:45:07 +01001538 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1539 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
1540 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.");
1541 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
1542
1543 /*
1544 * Connect edit signal, so we can show/not-show the auto start button
1545 */
1546 g_signal_connect(GTK_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
1547 g_signal_connect(GTK_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001548
Jens Axboea7a42ce2012-03-02 13:12:04 +01001549 gtk_widget_show_all(dialog);
1550
1551 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1552 gtk_widget_destroy(dialog);
1553 return 1;
1554 }
1555
Jens Axboe62bc9372012-03-07 11:45:07 +01001556 *host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001557 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1558
Jens Axboe62bc9372012-03-07 11:45:07 +01001559 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw.combo));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001560 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1561 *type = Fio_client_ipv4;
1562 else if (!strncmp(typeentry, "IPv6", 4))
1563 *type = Fio_client_ipv6;
1564 else
1565 *type = Fio_client_socket;
1566 g_free(typeentry);
1567
Jens Axboe62bc9372012-03-07 11:45:07 +01001568 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001569
Jens Axboea7a42ce2012-03-02 13:12:04 +01001570 gtk_widget_destroy(dialog);
1571 return 0;
1572}
1573
Jens Axboee0681f32012-03-06 12:14:42 +01001574static void gfio_client_added(struct gui *ui, struct fio_client *client)
1575{
1576 struct gfio_client *gc;
1577
1578 gc = malloc(sizeof(*gc));
1579 memset(gc, 0, sizeof(*gc));
1580 gc->ui = ui;
1581
1582 client->client_data = gc;
1583}
1584
Jens Axboe0420ba62012-02-29 11:16:52 +01001585static void file_open(GtkWidget *w, gpointer data)
1586{
1587 GtkWidget *dialog;
Jens Axboe63a130b2012-03-06 20:08:59 +01001588 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01001589 GSList *filenames, *fn_glist;
1590 GtkFileFilter *filter;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001591 char *host;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001592 int port, type, server_start;
Jens Axboe0420ba62012-02-29 11:16:52 +01001593
1594 dialog = gtk_file_chooser_dialog_new("Open File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001595 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001596 GTK_FILE_CHOOSER_ACTION_OPEN,
1597 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1598 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1599 NULL);
1600 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1601
1602 filter = gtk_file_filter_new();
1603 gtk_file_filter_add_pattern(filter, "*.fio");
1604 gtk_file_filter_add_pattern(filter, "*.job");
Jens Axboe2d262992012-03-07 08:19:30 +01001605 gtk_file_filter_add_pattern(filter, "*.ini");
Jens Axboe0420ba62012-02-29 11:16:52 +01001606 gtk_file_filter_add_mime_type(filter, "text/fio");
1607 gtk_file_filter_set_name(filter, "Fio job file");
1608 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
1609
1610 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1611 gtk_widget_destroy(dialog);
1612 return;
1613 }
1614
1615 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001616
1617 gtk_widget_destroy(dialog);
1618
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001619 if (get_connection_details(&host, &port, &type, &server_start))
Jens Axboea7a42ce2012-03-02 13:12:04 +01001620 goto err;
1621
Jens Axboe0420ba62012-02-29 11:16:52 +01001622 filenames = fn_glist;
1623 while (filenames != NULL) {
Jens Axboee0681f32012-03-06 12:14:42 +01001624 struct fio_client *client;
1625
Jens Axboe63a130b2012-03-06 20:08:59 +01001626 ui->job_files = realloc(ui->job_files, (ui->nr_job_files + 1) * sizeof(char *));
1627 ui->job_files[ui->nr_job_files] = strdup(filenames->data);
1628 ui->nr_job_files++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001629
Jens Axboee0681f32012-03-06 12:14:42 +01001630 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
1631 if (!client) {
Jens Axboedf06f222012-03-02 13:32:04 +01001632 GError *error;
1633
1634 error = g_error_new(g_quark_from_string("fio"), 1,
1635 "Failed to add client %s", host);
Jens Axboe0420ba62012-02-29 11:16:52 +01001636 report_error(error);
1637 g_error_free(error);
Jens Axboe0420ba62012-02-29 11:16:52 +01001638 }
Jens Axboe63a130b2012-03-06 20:08:59 +01001639 gfio_client_added(ui, client);
Jens Axboe0420ba62012-02-29 11:16:52 +01001640
1641 g_free(filenames->data);
1642 filenames = g_slist_next(filenames);
1643 }
Jens Axboea7a42ce2012-03-02 13:12:04 +01001644 free(host);
Jens Axboe63a130b2012-03-06 20:08:59 +01001645
1646 if (server_start)
1647 gfio_start_server(ui);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001648err:
Jens Axboe0420ba62012-02-29 11:16:52 +01001649 g_slist_free(fn_glist);
Jens Axboe0420ba62012-02-29 11:16:52 +01001650}
1651
1652static void file_save(GtkWidget *w, gpointer data)
1653{
Jens Axboe63a130b2012-03-06 20:08:59 +01001654 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01001655 GtkWidget *dialog;
1656
1657 dialog = gtk_file_chooser_dialog_new("Save File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001658 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001659 GTK_FILE_CHOOSER_ACTION_SAVE,
1660 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1661 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1662 NULL);
1663
1664 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1665 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
1666
1667 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1668 char *filename;
1669
1670 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1671 // save_job_file(filename);
1672 g_free(filename);
1673 }
1674 gtk_widget_destroy(dialog);
1675}
1676
Jens Axboe9b260bd2012-03-06 11:02:52 +01001677static void view_log_destroy(GtkWidget *w, gpointer data)
1678{
1679 struct gui *ui = (struct gui *) data;
1680
1681 gtk_widget_ref(ui->log_tree);
1682 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
1683 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +01001684 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001685}
1686
1687static void view_log(GtkWidget *w, gpointer data)
1688{
Jens Axboe4cbe7212012-03-06 13:36:17 +01001689 GtkWidget *win, *scroll, *vbox, *box;
1690 struct gui *ui = (struct gui *) data;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001691
Jens Axboe4cbe7212012-03-06 13:36:17 +01001692 if (ui->log_view)
1693 return;
1694
1695 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001696 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001697 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001698
Jens Axboe4cbe7212012-03-06 13:36:17 +01001699 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001700
Jens Axboe4cbe7212012-03-06 13:36:17 +01001701 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
1702
1703 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1704
1705 box = gtk_hbox_new(TRUE, 0);
1706 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
1707 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
1708 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
1709
1710 vbox = gtk_vbox_new(TRUE, 5);
1711 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
1712
1713 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001714 gtk_widget_show_all(win);
1715}
1716
Jens Axboe46974a72012-03-02 19:34:13 +01001717static void preferences(GtkWidget *w, gpointer data)
1718{
Jens Axboef3e84402012-03-07 13:14:32 +01001719 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
Jens Axboe46974a72012-03-02 19:34:13 +01001720 int i;
1721
1722 dialog = gtk_dialog_new_with_buttons("Preferences",
1723 GTK_WINDOW(ui.window),
1724 GTK_DIALOG_DESTROY_WITH_PARENT,
1725 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1726 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1727 NULL);
1728
Jens Axboe0b8d11e2012-03-02 19:44:15 +01001729 frame = gtk_frame_new("Debug logging");
Jens Axboe46974a72012-03-02 19:34:13 +01001730 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
Jens Axboef3e84402012-03-07 13:14:32 +01001731
1732 vbox = gtk_vbox_new(FALSE, 6);
1733 gtk_container_add(GTK_CONTAINER(frame), vbox);
1734
Jens Axboe46974a72012-03-02 19:34:13 +01001735 box = gtk_hbox_new(FALSE, 6);
Jens Axboef3e84402012-03-07 13:14:32 +01001736 gtk_container_add(GTK_CONTAINER(vbox), box);
Jens Axboe46974a72012-03-02 19:34:13 +01001737
1738 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
1739
1740 for (i = 0; i < FD_DEBUG_MAX; i++) {
Jens Axboef3e84402012-03-07 13:14:32 +01001741 if (i == 7) {
1742 box = gtk_hbox_new(FALSE, 6);
1743 gtk_container_add(GTK_CONTAINER(vbox), box);
1744 }
1745
1746
Jens Axboe46974a72012-03-02 19:34:13 +01001747 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
Jens Axboe0b8d11e2012-03-02 19:44:15 +01001748 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
Jens Axboe46974a72012-03-02 19:34:13 +01001749 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
1750 }
1751
Jens Axboef3e84402012-03-07 13:14:32 +01001752 frame = gtk_frame_new("Graph font");
1753 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1754 vbox = gtk_vbox_new(FALSE, 6);
1755 gtk_container_add(GTK_CONTAINER(frame), vbox);
1756
1757 font = gtk_font_button_new();
1758 gtk_box_pack_start(GTK_BOX(vbox), font, FALSE, FALSE, 5);
1759
Jens Axboe46974a72012-03-02 19:34:13 +01001760 gtk_widget_show_all(dialog);
1761
1762 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1763 gtk_widget_destroy(dialog);
1764 return;
1765 }
1766
1767 for (i = 0; i < FD_DEBUG_MAX; i++) {
1768 int set;
1769
1770 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
1771 if (set)
1772 fio_debug |= (1UL << i);
1773 }
1774
Jens Axboef3e84402012-03-07 13:14:32 +01001775 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
Jens Axboe46974a72012-03-02 19:34:13 +01001776 gtk_widget_destroy(dialog);
1777}
1778
Jens Axboe0420ba62012-02-29 11:16:52 +01001779static void about_dialog(GtkWidget *w, gpointer data)
1780{
Jens Axboe81e4ea62012-03-07 14:18:28 +01001781 const char *authors[] = {
1782 "Jens Axboe <axboe@kernel.dk>",
1783 "Stephen Carmeron <stephenmcameron@gmail.com>",
1784 NULL
1785 };
Jens Axboe84a72ed2012-03-07 14:24:57 +01001786 const char *license[] = {
1787 "Fio is free software; you can redistribute it and/or modify "
1788 "it under the terms of the GNU General Public License as published by "
1789 "the Free Software Foundation; either version 2 of the License, or "
1790 "(at your option) any later version.\n",
1791 "Fio is distributed in the hope that it will be useful, "
1792 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
1793 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
1794 "GNU General Public License for more details.\n",
1795 "You should have received a copy of the GNU General Public License "
1796 "along with Fio; if not, write to the Free Software Foundation, Inc., "
1797 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
1798 };
1799 char *license_trans;
1800
1801 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
1802 license[2], "\n", NULL);
Jens Axboe81e4ea62012-03-07 14:18:28 +01001803
Jens Axboe0420ba62012-02-29 11:16:52 +01001804 gtk_show_about_dialog(NULL,
1805 "program-name", "gfio",
1806 "comments", "Gtk2 UI for fio",
Jens Axboe84a72ed2012-03-07 14:24:57 +01001807 "license", license_trans,
Jens Axboe81e4ea62012-03-07 14:18:28 +01001808 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
1809 "authors", authors,
Jens Axboe0420ba62012-02-29 11:16:52 +01001810 "version", fio_version_string,
Jens Axboe81e4ea62012-03-07 14:18:28 +01001811 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
Jens Axboe0420ba62012-02-29 11:16:52 +01001812 "logo-icon-name", "fio",
1813 /* Must be last: */
Jens Axboe81e4ea62012-03-07 14:18:28 +01001814 "wrap-license", TRUE,
Jens Axboe0420ba62012-02-29 11:16:52 +01001815 NULL);
Jens Axboe84a72ed2012-03-07 14:24:57 +01001816
1817 g_free (license_trans);
Jens Axboe0420ba62012-02-29 11:16:52 +01001818}
1819
1820static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01001821 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01001822 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01001823 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
1824 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
1825 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
1826 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01001827 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe46974a72012-03-02 19:34:13 +01001828 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
1829 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01001830};
Jens Axboe3e47bd22012-02-29 13:45:02 +01001831static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01001832
1833static const gchar *ui_string = " \
1834 <ui> \
1835 <menubar name=\"MainMenu\"> \
1836 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
1837 <menuitem name=\"Open\" action=\"OpenFile\" /> \
1838 <menuitem name=\"Save\" action=\"SaveFile\" /> \
1839 <separator name=\"Separator\"/> \
Jens Axboe46974a72012-03-02 19:34:13 +01001840 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
1841 <separator name=\"Separator2\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001842 <menuitem name=\"Quit\" action=\"Quit\" /> \
1843 </menu> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01001844 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
1845 <menuitem name=\"Log\" action=\"ViewLog\" /> \
1846 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01001847 <menu name=\"Help\" action=\"HelpMenuAction\"> \
1848 <menuitem name=\"About\" action=\"About\" /> \
1849 </menu> \
1850 </menubar> \
1851 </ui> \
1852";
1853
Jens Axboe4cbe7212012-03-06 13:36:17 +01001854static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
1855 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01001856{
1857 GtkActionGroup *action_group = gtk_action_group_new("Menu");
1858 GError *error = 0;
1859
1860 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001861 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001862
1863 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1864 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
1865
1866 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
1867 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
1868}
1869
1870void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
1871 GtkWidget *vbox, GtkUIManager *ui_manager)
1872{
1873 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
1874}
1875
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001876static void init_ui(int *argc, char **argv[], struct gui *ui)
1877{
Jens Axboe0420ba62012-02-29 11:16:52 +01001878 GtkSettings *settings;
1879 GtkUIManager *uimanager;
Jens Axboe843ad232012-02-29 11:44:53 +01001880 GtkWidget *menu, *probe, *probe_frame, *probe_box;
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01001881 GdkColor white;
Jens Axboe0420ba62012-02-29 11:16:52 +01001882
1883 memset(ui, 0, sizeof(*ui));
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001884
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001885 /* Magical g*thread incantation, you just need this thread stuff.
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001886 * Without it, the update that happens in gfio_update_thread_status
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001887 * doesn't really happen in a timely fashion, you need expose events
1888 */
Jens Axboeed727a42012-03-02 12:14:40 +01001889 if (!g_thread_supported())
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001890 g_thread_init(NULL);
1891 gdk_threads_init();
1892
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001893 gtk_init(argc, argv);
Jens Axboe0420ba62012-02-29 11:16:52 +01001894 settings = gtk_settings_get_default();
1895 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
1896 g_type_init();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001897
1898 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1899 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
Jens Axboef3e84402012-03-07 13:14:32 +01001900 gtk_window_set_default_size(GTK_WINDOW(ui->window), 700, 700);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001901
Jens Axboe0420ba62012-02-29 11:16:52 +01001902 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
1903 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001904
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001905 ui->vbox = gtk_vbox_new(FALSE, 0);
1906 gtk_container_add(GTK_CONTAINER (ui->window), ui->vbox);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001907
Jens Axboe0420ba62012-02-29 11:16:52 +01001908 uimanager = gtk_ui_manager_new();
Jens Axboe4cbe7212012-03-06 13:36:17 +01001909 menu = get_menubar_menu(ui->window, uimanager, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001910 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
1911
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001912 /*
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001913 * Set up alignments for widgets at the top of ui,
1914 * align top left, expand horizontally but not vertically
1915 */
1916 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001917 ui->topvbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001918 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001919 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->topalign, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001920
Jens Axboe3e47bd22012-02-29 13:45:02 +01001921 probe = gtk_frame_new("Job");
Jens Axboe843ad232012-02-29 11:44:53 +01001922 gtk_box_pack_start(GTK_BOX(ui->topvbox), probe, TRUE, FALSE, 3);
1923 probe_frame = gtk_vbox_new(FALSE, 3);
1924 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
1925
1926 probe_box = gtk_hbox_new(FALSE, 3);
1927 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01001928 ui->probe.hostname = new_info_label_in_frame(probe_box, "Host");
1929 ui->probe.os = new_info_label_in_frame(probe_box, "OS");
1930 ui->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
1931 ui->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
1932
Jens Axboe3e47bd22012-02-29 13:45:02 +01001933 probe_box = gtk_hbox_new(FALSE, 3);
1934 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01001935
Jens Axboeca850992012-03-05 20:04:43 +01001936 ui->eta.name = new_info_entry_in_frame(probe_box, "Name");
1937 ui->eta.iotype = new_info_entry_in_frame(probe_box, "IO");
1938 ui->eta.ioengine = new_info_entry_in_frame(probe_box, "IO Engine");
1939 ui->eta.iodepth = new_info_entry_in_frame(probe_box, "IO Depth");
1940 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
1941 ui->eta.files = new_info_entry_in_frame(probe_box, "Open files");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001942
1943 probe_box = gtk_hbox_new(FALSE, 3);
1944 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboeca850992012-03-05 20:04:43 +01001945 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1946 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1947 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1948 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001949
1950 /*
1951 * Only add this if we have a commit rate
1952 */
1953#if 0
1954 probe_box = gtk_hbox_new(FALSE, 3);
1955 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1956
Jens Axboe3e47bd22012-02-29 13:45:02 +01001957 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1958 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1959
Jens Axboe3e47bd22012-02-29 13:45:02 +01001960 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1961 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001962#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01001963
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001964 /*
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001965 * Set up a drawing area and IOPS and bandwidth graphs
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001966 */
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01001967 gdk_color_parse("white", &white);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001968 ui->drawing_area = gtk_drawing_area_new();
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001969 ui->drawing_area_xdim = DRAWING_AREA_XDIM;
1970 ui->drawing_area_ydim = DRAWING_AREA_YDIM;
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001971 gtk_widget_set_size_request(GTK_WIDGET(ui->drawing_area),
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001972 ui->drawing_area_xdim, ui->drawing_area_ydim);
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01001973 gtk_widget_modify_bg(ui->drawing_area, GTK_STATE_NORMAL, &white);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001974 g_signal_connect(G_OBJECT(ui->drawing_area), "expose_event",
1975 G_CALLBACK (on_expose_drawing_area), ui);
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001976 g_signal_connect(G_OBJECT(ui->drawing_area), "configure_event",
1977 G_CALLBACK (on_config_drawing_area), ui);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001978 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1979 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1980 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001981 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1982 ui->drawing_area);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001983 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->scrolled_window,
1984 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001985
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001986 setup_iops_graph(ui);
1987 setup_bandwidth_graph(ui);
1988
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001989 /*
1990 * Set up alignments for widgets at the bottom of ui,
1991 * align bottom left, expand horizontally but not vertically
1992 */
1993 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
1994 ui->buttonbox = gtk_hbox_new(FALSE, 0);
1995 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001996 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->bottomalign,
1997 FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001998
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001999 add_buttons(ui, buttonspeclist, ARRAYSIZE(buttonspeclist));
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002000
2001 /*
2002 * Set up thread status progress bar
2003 */
2004 ui->thread_status_pb = gtk_progress_bar_new();
2005 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01002006 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002007 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
2008
Jens Axboe9b260bd2012-03-06 11:02:52 +01002009 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002010
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002011 gtk_widget_show_all(ui->window);
2012}
2013
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002014int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002015{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002016 if (initialize_fio(envp))
2017 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01002018 if (fio_init_options())
2019 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01002020
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002021 init_ui(&argc, &argv, &ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01002022
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002023 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002024 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002025 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002026 return 0;
2027}