blob: 4521f75dfec68c07c54eb33bb80e441b5a55b853 [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 Axboedcaeb602012-03-08 19:45:37 +0100127 unsigned int job_added;
128 struct thread_options o;
Jens Axboee0681f32012-03-06 12:14:42 +0100129};
130
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100131static void setup_iops_graph(struct gui *ui)
132{
133 if (ui->iops_graph)
134 graph_free(ui->iops_graph);
Jens Axboe87d5f272012-03-07 12:31:40 +0100135 ui->iops_graph = graph_new(DRAWING_AREA_XDIM / 2.0,
Jens Axboef3e84402012-03-07 13:14:32 +0100136 DRAWING_AREA_YDIM, gfio_graph_font);
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100137 graph_title(ui->iops_graph, "IOPS");
Stephen M. Cameronb04ad8d2012-03-07 14:49:37 +0100138 graph_x_title(ui->iops_graph, "Time (secs)");
Stephen M. Cameron019dd472012-03-08 17:00:10 +0100139 graph_y_title(ui->iops_graph, "IOs / sec");
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100140 graph_add_label(ui->iops_graph, "Read IOPS");
141 graph_add_label(ui->iops_graph, "Write IOPS");
Jens Axboe9f4883a2012-03-07 16:22:50 +0100142 graph_set_color(ui->iops_graph, "Read IOPS", 0.13, 0.54, 0.13);
143 graph_set_color(ui->iops_graph, "Write IOPS", 1.0, 0.0, 0.0);
Stephen M. Cameronfe8afdd2012-03-07 19:34:19 +0100144 line_graph_set_data_count_limit(ui->iops_graph, 100);
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100145}
146
147static void setup_bandwidth_graph(struct gui *ui)
148{
149 if (ui->bandwidth_graph)
150 graph_free(ui->bandwidth_graph);
Jens Axboe87d5f272012-03-07 12:31:40 +0100151 ui->bandwidth_graph = graph_new(DRAWING_AREA_XDIM / 2.0,
Jens Axboef3e84402012-03-07 13:14:32 +0100152 DRAWING_AREA_YDIM, gfio_graph_font);
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100153 graph_title(ui->bandwidth_graph, "Bandwidth");
Stephen M. Cameronb04ad8d2012-03-07 14:49:37 +0100154 graph_x_title(ui->bandwidth_graph, "Time (secs)");
Stephen M. Cameron019dd472012-03-08 17:00:10 +0100155 graph_y_title(ui->bandwidth_graph, "Kbytes / sec");
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100156 graph_add_label(ui->bandwidth_graph, "Read Bandwidth");
157 graph_add_label(ui->bandwidth_graph, "Write Bandwidth");
Jens Axboe9f4883a2012-03-07 16:22:50 +0100158 graph_set_color(ui->bandwidth_graph, "Read Bandwidth", 0.13, 0.54, 0.13);
159 graph_set_color(ui->bandwidth_graph, "Write Bandwidth", 1.0, 0.0, 0.0);
Stephen M. Cameronfe8afdd2012-03-07 19:34:19 +0100160 line_graph_set_data_count_limit(ui->bandwidth_graph, 100);
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100161}
162
Jens Axboe8663ea62012-03-02 14:04:30 +0100163static void clear_ui_info(struct gui *ui)
164{
165 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), "");
166 gtk_label_set_text(GTK_LABEL(ui->probe.os), "");
167 gtk_label_set_text(GTK_LABEL(ui->probe.arch), "");
168 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), "");
Jens Axboeca850992012-03-05 20:04:43 +0100169 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), "");
170 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), "");
171 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), "");
172 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), "");
173 gtk_entry_set_text(GTK_ENTRY(ui->eta.jobs), "");
174 gtk_entry_set_text(GTK_ENTRY(ui->eta.files), "");
175 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), "");
176 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), "");
177 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), "");
178 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100179}
180
Jens Axboe3650a3c2012-03-05 14:09:03 +0100181static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
182{
183 GtkWidget *entry, *frame;
184
185 frame = gtk_frame_new(label);
186 entry = gtk_entry_new();
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100187 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100188 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
189 gtk_container_add(GTK_CONTAINER(frame), entry);
190
191 return entry;
192}
193
194static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
195{
196 GtkWidget *label_widget;
197 GtkWidget *frame;
198
199 frame = gtk_frame_new(label);
200 label_widget = gtk_label_new(NULL);
201 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
202 gtk_container_add(GTK_CONTAINER(frame), label_widget);
203
204 return label_widget;
205}
206
207static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
208{
209 GtkWidget *button, *box;
210
211 box = gtk_hbox_new(FALSE, 3);
212 gtk_container_add(GTK_CONTAINER(hbox), box);
213
214 button = gtk_spin_button_new_with_range(min, max, 1.0);
215 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
216
217 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
218 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
219
220 return button;
221}
222
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100223static void gfio_set_connected(struct gui *ui, int connected)
224{
225 if (connected) {
226 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
227 ui->connected = 1;
228 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Disconnect");
Jens Axboe88f6e7a2012-03-06 12:55:29 +0100229 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100230 } else {
231 ui->connected = 0;
232 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Connect");
233 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
Jens Axboe63a130b2012-03-06 20:08:59 +0100234 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100235 }
236}
237
Jens Axboe3650a3c2012-03-05 14:09:03 +0100238static void label_set_int_value(GtkWidget *entry, unsigned int val)
239{
240 char tmp[80];
241
242 sprintf(tmp, "%u", val);
243 gtk_label_set_text(GTK_LABEL(entry), tmp);
244}
245
246static void entry_set_int_value(GtkWidget *entry, unsigned int val)
247{
248 char tmp[80];
249
250 sprintf(tmp, "%u", val);
251 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
252}
253
Jens Axboea2697902012-03-05 16:43:49 +0100254#define ALIGN_LEFT 1
255#define ALIGN_RIGHT 2
256#define INVISIBLE 4
257#define UNSORTABLE 8
258
259GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
260{
261 GtkCellRenderer *renderer;
262 GtkTreeViewColumn *col;
263 double xalign = 0.0; /* left as default */
264 PangoAlignment align;
265 gboolean visible;
266
267 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
268 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
269 PANGO_ALIGN_CENTER;
270 visible = !(flags & INVISIBLE);
271
272 renderer = gtk_cell_renderer_text_new();
273 col = gtk_tree_view_column_new();
274
275 gtk_tree_view_column_set_title(col, title);
276 if (!(flags & UNSORTABLE))
277 gtk_tree_view_column_set_sort_column_id(col, index);
278 gtk_tree_view_column_set_resizable(col, TRUE);
279 gtk_tree_view_column_pack_start(col, renderer, TRUE);
280 gtk_tree_view_column_add_attribute(col, renderer, "text", index);
281 gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
282 switch (align) {
283 case PANGO_ALIGN_LEFT:
284 xalign = 0.0;
285 break;
286 case PANGO_ALIGN_CENTER:
287 xalign = 0.5;
288 break;
289 case PANGO_ALIGN_RIGHT:
290 xalign = 1.0;
291 break;
292 }
293 gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
294 gtk_tree_view_column_set_visible(col, visible);
295 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
296 return col;
297}
298
Jens Axboe9b260bd2012-03-06 11:02:52 +0100299static void gfio_ui_setup_log(struct gui *ui)
300{
301 GtkTreeSelection *selection;
302 GtkListStore *model;
303 GtkWidget *tree_view;
304
305 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
306
307 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
308 gtk_widget_set_can_focus(tree_view, FALSE);
309
310 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
311 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
Jens Axboe661f7412012-03-06 13:55:45 +0100312 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
313 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100314
315 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
316 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
317 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
Jens Axboef095d562012-03-06 13:49:12 +0100318 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100319
320 ui->log_model = model;
321 ui->log_tree = tree_view;
322}
323
Jens Axboea2697902012-03-05 16:43:49 +0100324static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
325 fio_fp64_t *plist,
326 unsigned int len,
327 const char *base,
328 unsigned int scale)
329{
330 GType types[FIO_IO_U_LIST_MAX_LEN];
331 GtkWidget *tree_view;
332 GtkTreeSelection *selection;
333 GtkListStore *model;
334 GtkTreeIter iter;
335 int i;
336
337 for (i = 0; i < len; i++)
338 types[i] = G_TYPE_INT;
339
340 model = gtk_list_store_newv(len, types);
341
342 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
343 gtk_widget_set_can_focus(tree_view, FALSE);
344
Jens Axboe661f7412012-03-06 13:55:45 +0100345 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
346 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
347
Jens Axboea2697902012-03-05 16:43:49 +0100348 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
349 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
350
351 for (i = 0; i < len; i++) {
352 char fbuf[8];
353
354 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
355 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
356 }
357
358 gtk_list_store_append(model, &iter);
359
Jens Axboee0681f32012-03-06 12:14:42 +0100360 for (i = 0; i < len; i++) {
361 if (scale)
362 ovals[i] = (ovals[i] + 999) / 1000;
Jens Axboea2697902012-03-05 16:43:49 +0100363 gtk_list_store_set(model, &iter, i, ovals[i], -1);
Jens Axboee0681f32012-03-06 12:14:42 +0100364 }
Jens Axboea2697902012-03-05 16:43:49 +0100365
366 return tree_view;
367}
368
369static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
370 int ddir)
371{
372 unsigned int *io_u_plat = ts->io_u_plat[ddir];
373 unsigned long nr = ts->clat_stat[ddir].samples;
374 fio_fp64_t *plist = ts->percentile_list;
375 unsigned int *ovals, len, minv, maxv, scale_down;
376 const char *base;
377 GtkWidget *tree_view, *frame, *hbox;
378 char tmp[64];
379
380 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
381 if (!len)
382 goto out;
383
384 /*
385 * We default to usecs, but if the value range is such that we
386 * should scale down to msecs, do that.
387 */
388 if (minv > 2000 && maxv > 99999) {
389 scale_down = 1;
390 base = "msec";
391 } else {
392 scale_down = 0;
393 base = "usec";
394 }
395
396 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
397
398 sprintf(tmp, "Completion percentiles (%s)", base);
399 frame = gtk_frame_new(tmp);
400 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
401
402 hbox = gtk_hbox_new(FALSE, 3);
403 gtk_container_add(GTK_CONTAINER(frame), hbox);
404
405 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
406out:
407 if (ovals)
408 free(ovals);
409}
410
Jens Axboe3650a3c2012-03-05 14:09:03 +0100411static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
412 unsigned long max, double mean, double dev)
413{
414 const char *base = "(usec)";
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100415 GtkWidget *hbox, *label, *frame;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100416 char *minp, *maxp;
417 char tmp[64];
418
419 if (!usec_to_msec(&min, &max, &mean, &dev))
420 base = "(msec)";
421
422 minp = num2str(min, 6, 1, 0);
423 maxp = num2str(max, 6, 1, 0);
424
Jens Axboe3650a3c2012-03-05 14:09:03 +0100425 sprintf(tmp, "%s %s", name, base);
426 frame = gtk_frame_new(tmp);
427 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
428
Jens Axboe3650a3c2012-03-05 14:09:03 +0100429 hbox = gtk_hbox_new(FALSE, 3);
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100430 gtk_container_add(GTK_CONTAINER(frame), hbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100431
432 label = new_info_label_in_frame(hbox, "Minimum");
433 gtk_label_set_text(GTK_LABEL(label), minp);
434 label = new_info_label_in_frame(hbox, "Maximum");
435 gtk_label_set_text(GTK_LABEL(label), maxp);
436 label = new_info_label_in_frame(hbox, "Average");
437 sprintf(tmp, "%5.02f", mean);
438 gtk_label_set_text(GTK_LABEL(label), tmp);
439 label = new_info_label_in_frame(hbox, "Standard deviation");
440 sprintf(tmp, "%5.02f", dev);
441 gtk_label_set_text(GTK_LABEL(label), tmp);
442
443 free(minp);
444 free(maxp);
445
446}
447
Jens Axboeca850992012-03-05 20:04:43 +0100448#define GFIO_CLAT 1
449#define GFIO_SLAT 2
450#define GFIO_LAT 4
451
Jens Axboe3650a3c2012-03-05 14:09:03 +0100452static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
453 struct thread_stat *ts, int ddir)
454{
455 const char *ddir_label[2] = { "Read", "Write" };
Jens Axboe0b761302012-03-05 20:44:11 +0100456 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
Jens Axboee0681f32012-03-06 12:14:42 +0100457 unsigned long min[3], max[3], runt;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100458 unsigned long long bw, iops;
Jens Axboeca850992012-03-05 20:04:43 +0100459 unsigned int flags = 0;
Jens Axboee0681f32012-03-06 12:14:42 +0100460 double mean[3], dev[3];
Jens Axboe3650a3c2012-03-05 14:09:03 +0100461 char *io_p, *bw_p, *iops_p;
462 int i2p;
463
464 if (!ts->runtime[ddir])
465 return;
466
467 i2p = is_power_of_2(rs->kb_base);
468 runt = ts->runtime[ddir];
469
470 bw = (1000 * ts->io_bytes[ddir]) / runt;
471 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
472 bw_p = num2str(bw, 6, 1, i2p);
473
474 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
475 iops_p = num2str(iops, 6, 1, 0);
476
477 box = gtk_hbox_new(FALSE, 3);
478 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
479
480 frame = gtk_frame_new(ddir_label[ddir]);
481 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
482
Jens Axboe0b761302012-03-05 20:44:11 +0100483 main_vbox = gtk_vbox_new(FALSE, 3);
484 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100485
486 box = gtk_hbox_new(FALSE, 3);
Jens Axboe0b761302012-03-05 20:44:11 +0100487 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100488
489 label = new_info_label_in_frame(box, "IO");
490 gtk_label_set_text(GTK_LABEL(label), io_p);
491 label = new_info_label_in_frame(box, "Bandwidth");
492 gtk_label_set_text(GTK_LABEL(label), bw_p);
493 label = new_info_label_in_frame(box, "IOPS");
494 gtk_label_set_text(GTK_LABEL(label), iops_p);
495 label = new_info_label_in_frame(box, "Runtime (msec)");
496 label_set_int_value(label, ts->runtime[ddir]);
497
Jens Axboee0681f32012-03-06 12:14:42 +0100498 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
Jens Axboeca850992012-03-05 20:04:43 +0100499 double p_of_agg = 100.0;
500 const char *bw_str = "KB";
501 char tmp[32];
502
503 if (rs->agg[ddir]) {
Jens Axboee0681f32012-03-06 12:14:42 +0100504 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
Jens Axboeca850992012-03-05 20:04:43 +0100505 if (p_of_agg > 100.0)
506 p_of_agg = 100.0;
507 }
508
Jens Axboee0681f32012-03-06 12:14:42 +0100509 if (mean[0] > 999999.9) {
510 min[0] /= 1000.0;
511 max[0] /= 1000.0;
512 mean[0] /= 1000.0;
513 dev[0] /= 1000.0;
Jens Axboeca850992012-03-05 20:04:43 +0100514 bw_str = "MB";
515 }
516
Jens Axboe0b761302012-03-05 20:44:11 +0100517 sprintf(tmp, "Bandwidth (%s)", bw_str);
518 frame = gtk_frame_new(tmp);
519 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
Jens Axboeca850992012-03-05 20:04:43 +0100520
Jens Axboe0b761302012-03-05 20:44:11 +0100521 box = gtk_hbox_new(FALSE, 3);
522 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboeca850992012-03-05 20:04:43 +0100523
Jens Axboe0b761302012-03-05 20:44:11 +0100524 label = new_info_label_in_frame(box, "Minimum");
Jens Axboee0681f32012-03-06 12:14:42 +0100525 label_set_int_value(label, min[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100526 label = new_info_label_in_frame(box, "Maximum");
Jens Axboee0681f32012-03-06 12:14:42 +0100527 label_set_int_value(label, max[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100528 label = new_info_label_in_frame(box, "Percentage of jobs");
Jens Axboeca850992012-03-05 20:04:43 +0100529 sprintf(tmp, "%3.2f%%", p_of_agg);
530 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100531 label = new_info_label_in_frame(box, "Average");
Jens Axboee0681f32012-03-06 12:14:42 +0100532 sprintf(tmp, "%5.02f", mean[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100533 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100534 label = new_info_label_in_frame(box, "Standard deviation");
Jens Axboee0681f32012-03-06 12:14:42 +0100535 sprintf(tmp, "%5.02f", dev[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100536 gtk_label_set_text(GTK_LABEL(label), tmp);
537 }
538
Jens Axboee0681f32012-03-06 12:14:42 +0100539 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
Jens Axboe2b089892012-03-06 08:09:17 +0100540 flags |= GFIO_SLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100541 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
Jens Axboe2b089892012-03-06 08:09:17 +0100542 flags |= GFIO_CLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100543 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
Jens Axboe2b089892012-03-06 08:09:17 +0100544 flags |= GFIO_LAT;
545
546 if (flags) {
547 frame = gtk_frame_new("Latency");
548 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
549
550 vbox = gtk_vbox_new(FALSE, 3);
551 gtk_container_add(GTK_CONTAINER(frame), vbox);
552
553 if (flags & GFIO_SLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100554 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
Jens Axboe2b089892012-03-06 08:09:17 +0100555 if (flags & GFIO_CLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100556 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
Jens Axboe2b089892012-03-06 08:09:17 +0100557 if (flags & GFIO_LAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100558 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
Jens Axboe2b089892012-03-06 08:09:17 +0100559 }
560
561 if (ts->clat_percentiles)
562 gfio_show_clat_percentiles(main_vbox, ts, ddir);
563
564
Jens Axboe3650a3c2012-03-05 14:09:03 +0100565 free(io_p);
566 free(bw_p);
567 free(iops_p);
568}
569
Jens Axboee5bd1342012-03-05 21:38:12 +0100570static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
571 const char **labels)
572{
573 GtkWidget *tree_view;
574 GtkTreeSelection *selection;
575 GtkListStore *model;
576 GtkTreeIter iter;
577 GType *types;
578 int i, skipped;
579
580 /*
581 * Check if all are empty, in which case don't bother
582 */
583 for (i = 0, skipped = 0; i < num; i++)
584 if (lat[i] <= 0.0)
585 skipped++;
586
587 if (skipped == num)
588 return NULL;
589
590 types = malloc(num * sizeof(GType));
591
592 for (i = 0; i < num; i++)
593 types[i] = G_TYPE_STRING;
594
595 model = gtk_list_store_newv(num, types);
596 free(types);
597 types = NULL;
598
599 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
600 gtk_widget_set_can_focus(tree_view, FALSE);
601
Jens Axboe661f7412012-03-06 13:55:45 +0100602 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
603 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
604
Jens Axboee5bd1342012-03-05 21:38:12 +0100605 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
606 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
607
608 for (i = 0; i < num; i++)
609 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
610
611 gtk_list_store_append(model, &iter);
612
613 for (i = 0; i < num; i++) {
614 char fbuf[32];
615
616 if (lat[i] <= 0.0)
617 sprintf(fbuf, "0.00");
618 else
619 sprintf(fbuf, "%3.2f%%", lat[i]);
620
621 gtk_list_store_set(model, &iter, i, fbuf, -1);
622 }
623
624 return tree_view;
625}
626
627static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
628{
629 GtkWidget *box, *frame, *tree_view;
630 double io_u_lat_u[FIO_IO_U_LAT_U_NR];
631 double io_u_lat_m[FIO_IO_U_LAT_M_NR];
632 const char *uranges[] = { "2", "4", "10", "20", "50", "100",
633 "250", "500", "750", "1000", };
634 const char *mranges[] = { "2", "4", "10", "20", "50", "100",
635 "250", "500", "750", "1000", "2000",
636 ">= 2000", };
637
638 stat_calc_lat_u(ts, io_u_lat_u);
639 stat_calc_lat_m(ts, io_u_lat_m);
640
641 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
642 if (tree_view) {
643 frame = gtk_frame_new("Latency buckets (usec)");
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 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
652 if (tree_view) {
653 frame = gtk_frame_new("Latency buckets (msec)");
654 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
655
656 box = gtk_hbox_new(FALSE, 3);
657 gtk_container_add(GTK_CONTAINER(frame), box);
658 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
659 }
660}
661
Jens Axboe2e331012012-03-05 22:07:54 +0100662static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
663{
664 GtkWidget *box, *frame, *entry;
665 double usr_cpu, sys_cpu;
666 unsigned long runtime;
667 char tmp[32];
668
669 runtime = ts->total_run_time;
670 if (runtime) {
671 double runt = (double) runtime;
672
673 usr_cpu = (double) ts->usr_time * 100 / runt;
674 sys_cpu = (double) ts->sys_time * 100 / runt;
675 } else {
676 usr_cpu = 0;
677 sys_cpu = 0;
678 }
679
680 frame = gtk_frame_new("OS resources");
681 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
682
683 box = gtk_hbox_new(FALSE, 3);
684 gtk_container_add(GTK_CONTAINER(frame), box);
685
686 entry = new_info_entry_in_frame(box, "User CPU");
687 sprintf(tmp, "%3.2f%%", usr_cpu);
688 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
689 entry = new_info_entry_in_frame(box, "System CPU");
690 sprintf(tmp, "%3.2f%%", sys_cpu);
691 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
692 entry = new_info_entry_in_frame(box, "Context switches");
693 entry_set_int_value(entry, ts->ctx);
694 entry = new_info_entry_in_frame(box, "Major faults");
695 entry_set_int_value(entry, ts->majf);
696 entry = new_info_entry_in_frame(box, "Minor faults");
697 entry_set_int_value(entry, ts->minf);
698}
Jens Axboe19998db2012-03-06 09:17:59 +0100699static void gfio_add_sc_depths_tree(GtkListStore *model,
700 struct thread_stat *ts, unsigned int len,
701 int submit)
702{
703 double io_u_dist[FIO_IO_U_MAP_NR];
704 GtkTreeIter iter;
705 /* Bits 0, and 3-8 */
706 const int add_mask = 0x1f9;
707 int i, j;
708
709 if (submit)
710 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
711 else
712 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
713
714 gtk_list_store_append(model, &iter);
715
716 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
717
718 for (i = 1, j = 0; i < len; i++) {
719 char fbuf[32];
720
721 if (!(add_mask & (1UL << (i - 1))))
722 sprintf(fbuf, "0.0%%");
723 else {
724 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
725 j++;
726 }
727
728 gtk_list_store_set(model, &iter, i, fbuf, -1);
729 }
730
731}
732
733static void gfio_add_total_depths_tree(GtkListStore *model,
734 struct thread_stat *ts, unsigned int len)
735{
736 double io_u_dist[FIO_IO_U_MAP_NR];
737 GtkTreeIter iter;
738 /* Bits 1-6, and 8 */
739 const int add_mask = 0x17e;
740 int i, j;
741
742 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
743
744 gtk_list_store_append(model, &iter);
745
746 gtk_list_store_set(model, &iter, 0, "Total", -1);
747
748 for (i = 1, j = 0; i < len; i++) {
749 char fbuf[32];
750
751 if (!(add_mask & (1UL << (i - 1))))
752 sprintf(fbuf, "0.0%%");
753 else {
754 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
755 j++;
756 }
757
758 gtk_list_store_set(model, &iter, i, fbuf, -1);
759 }
760
761}
Jens Axboe2e331012012-03-05 22:07:54 +0100762
763static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
764{
Jens Axboe2e331012012-03-05 22:07:54 +0100765 GtkWidget *frame, *box, *tree_view;
766 GtkTreeSelection *selection;
767 GtkListStore *model;
Jens Axboe2e331012012-03-05 22:07:54 +0100768 GType types[FIO_IO_U_MAP_NR + 1];
769 int i;
Jens Axboe19998db2012-03-06 09:17:59 +0100770#define NR_LABELS 10
771 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
Jens Axboe2e331012012-03-05 22:07:54 +0100772
773 frame = gtk_frame_new("IO depths");
774 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
775
776 box = gtk_hbox_new(FALSE, 3);
777 gtk_container_add(GTK_CONTAINER(frame), box);
778
Jens Axboe19998db2012-03-06 09:17:59 +0100779 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100780 types[i] = G_TYPE_STRING;
781
Jens Axboe19998db2012-03-06 09:17:59 +0100782 model = gtk_list_store_newv(NR_LABELS, types);
Jens Axboe2e331012012-03-05 22:07:54 +0100783
784 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
785 gtk_widget_set_can_focus(tree_view, FALSE);
786
Jens Axboe661f7412012-03-06 13:55:45 +0100787 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
788 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
789
Jens Axboe2e331012012-03-05 22:07:54 +0100790 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
791 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
792
Jens Axboe19998db2012-03-06 09:17:59 +0100793 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100794 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
795
Jens Axboe19998db2012-03-06 09:17:59 +0100796 gfio_add_total_depths_tree(model, ts, NR_LABELS);
797 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 1);
798 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 0);
Jens Axboe2e331012012-03-05 22:07:54 +0100799
800 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
801}
802
Jens Axboef9d40b42012-03-06 09:52:49 +0100803static gboolean results_window_delete(GtkWidget *w, gpointer data)
804{
805 struct gui *ui = (struct gui *) data;
806
807 gtk_widget_destroy(w);
808 ui->results_window = NULL;
809 ui->results_notebook = NULL;
810 return TRUE;
811}
812
813static GtkWidget *get_results_window(struct gui *ui)
814{
815 GtkWidget *win, *notebook;
816
817 if (ui->results_window)
818 return ui->results_notebook;
819
820 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
821 gtk_window_set_title(GTK_WINDOW(win), "Results");
Jens Axboeb01329d2012-03-07 20:31:28 +0100822 gtk_window_set_default_size(GTK_WINDOW(win), 1024, 768);
Jens Axboef9d40b42012-03-06 09:52:49 +0100823 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ui);
824 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ui);
825
826 notebook = gtk_notebook_new();
827 gtk_container_add(GTK_CONTAINER(win), notebook);
828
829 ui->results_window = win;
830 ui->results_notebook = notebook;
831 return ui->results_notebook;
832}
833
Jens Axboe3650a3c2012-03-05 14:09:03 +0100834static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
835 struct group_run_stats *rs)
836{
Jens Axboeb01329d2012-03-07 20:31:28 +0100837 GtkWidget *res_win, *box, *vbox, *entry, *scroll;
Jens Axboee0681f32012-03-06 12:14:42 +0100838 struct gfio_client *gc = client->client_data;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100839
840 gdk_threads_enter();
841
Jens Axboee0681f32012-03-06 12:14:42 +0100842 res_win = get_results_window(gc->ui);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100843
Jens Axboeb01329d2012-03-07 20:31:28 +0100844 scroll = gtk_scrolled_window_new(NULL, NULL);
845 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
846 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
847
Jens Axboe3650a3c2012-03-05 14:09:03 +0100848 vbox = gtk_vbox_new(FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100849
Jens Axboeb01329d2012-03-07 20:31:28 +0100850 box = gtk_hbox_new(FALSE, 0);
851 gtk_box_pack_start(GTK_BOX(vbox), box, TRUE, FALSE, 5);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100852
Jens Axboeb01329d2012-03-07 20:31:28 +0100853 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
854
855 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), scroll, gtk_label_new(ts->name));
Jens Axboef9d40b42012-03-06 09:52:49 +0100856
Jens Axboee0681f32012-03-06 12:14:42 +0100857 gc->results_widget = vbox;
858
Jens Axboe3650a3c2012-03-05 14:09:03 +0100859 entry = new_info_entry_in_frame(box, "Name");
860 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
861 if (strlen(ts->description)) {
862 entry = new_info_entry_in_frame(box, "Description");
863 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
864 }
865 entry = new_info_entry_in_frame(box, "Group ID");
866 entry_set_int_value(entry, ts->groupid);
867 entry = new_info_entry_in_frame(box, "Jobs");
868 entry_set_int_value(entry, ts->members);
Jens Axboe6b79c802012-03-08 10:51:36 +0100869 gc->err_entry = entry = new_info_entry_in_frame(box, "Error");
Jens Axboe3650a3c2012-03-05 14:09:03 +0100870 entry_set_int_value(entry, ts->error);
871 entry = new_info_entry_in_frame(box, "PID");
872 entry_set_int_value(entry, ts->pid);
873
874 if (ts->io_bytes[DDIR_READ])
875 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
876 if (ts->io_bytes[DDIR_WRITE])
877 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
878
Jens Axboee5bd1342012-03-05 21:38:12 +0100879 gfio_show_latency_buckets(vbox, ts);
Jens Axboe2e331012012-03-05 22:07:54 +0100880 gfio_show_cpu_usage(vbox, ts);
881 gfio_show_io_depths(vbox, ts);
Jens Axboee5bd1342012-03-05 21:38:12 +0100882
Jens Axboee0681f32012-03-06 12:14:42 +0100883 gtk_widget_show_all(gc->ui->results_window);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100884 gdk_threads_leave();
885}
886
Jens Axboe084d1c62012-03-03 20:28:07 +0100887static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100888{
Jens Axboe9b260bd2012-03-06 11:02:52 +0100889 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +0100890 struct gfio_client *gc = client->client_data;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100891 GtkTreeIter iter;
892 struct tm *tm;
893 time_t sec;
894 char tmp[64], timebuf[80];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100895
Jens Axboe9b260bd2012-03-06 11:02:52 +0100896 sec = p->log_sec;
897 tm = localtime(&sec);
898 strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", tm);
899 sprintf(timebuf, "%s.%03ld", tmp, p->log_usec / 1000);
900
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100901 gdk_threads_enter();
Jens Axboe9b260bd2012-03-06 11:02:52 +0100902
Jens Axboee0681f32012-03-06 12:14:42 +0100903 gtk_list_store_append(gc->ui->log_model, &iter);
904 gtk_list_store_set(gc->ui->log_model, &iter, 0, timebuf, -1);
905 gtk_list_store_set(gc->ui->log_model, &iter, 1, client->hostname, -1);
906 gtk_list_store_set(gc->ui->log_model, &iter, 2, p->level, -1);
907 gtk_list_store_set(gc->ui->log_model, &iter, 3, p->buf, -1);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100908
Jens Axboe6b79c802012-03-08 10:51:36 +0100909 if (p->level == FIO_LOG_ERR)
910 view_log(NULL, (gpointer) gc->ui);
911
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100912 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100913}
914
915static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
916{
Jens Axboee0681f32012-03-06 12:14:42 +0100917 struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
918 struct gfio_client *gc = client->client_data;
919 GtkWidget *box, *frame, *entry, *vbox;
Jens Axboe604cfe32012-03-07 19:51:36 +0100920 double util;
921 char tmp[16];
Jens Axboee0681f32012-03-06 12:14:42 +0100922
Jens Axboe0050e5f2012-03-06 09:23:27 +0100923 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +0100924
Jens Axboe45dcb2e2012-03-07 16:16:50 +0100925 if (!gc->results_widget)
Jens Axboee0681f32012-03-06 12:14:42 +0100926 goto out;
Jens Axboee0681f32012-03-06 12:14:42 +0100927
928 if (!gc->disk_util_frame) {
929 gc->disk_util_frame = gtk_frame_new("Disk utilization");
930 gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
931 }
932
933 vbox = gtk_vbox_new(FALSE, 3);
934 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
935
936 frame = gtk_frame_new((char *) p->dus.name);
937 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
938
939 box = gtk_vbox_new(FALSE, 3);
940 gtk_container_add(GTK_CONTAINER(frame), box);
941
942 frame = gtk_frame_new("Read");
943 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
944 vbox = gtk_hbox_new(TRUE, 3);
945 gtk_container_add(GTK_CONTAINER(frame), vbox);
946 entry = new_info_entry_in_frame(vbox, "IOs");
947 entry_set_int_value(entry, p->dus.ios[0]);
948 entry = new_info_entry_in_frame(vbox, "Merges");
949 entry_set_int_value(entry, p->dus.merges[0]);
950 entry = new_info_entry_in_frame(vbox, "Sectors");
951 entry_set_int_value(entry, p->dus.sectors[0]);
952 entry = new_info_entry_in_frame(vbox, "Ticks");
953 entry_set_int_value(entry, p->dus.ticks[0]);
954
955 frame = gtk_frame_new("Write");
956 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
957 vbox = gtk_hbox_new(TRUE, 3);
958 gtk_container_add(GTK_CONTAINER(frame), vbox);
959 entry = new_info_entry_in_frame(vbox, "IOs");
960 entry_set_int_value(entry, p->dus.ios[1]);
961 entry = new_info_entry_in_frame(vbox, "Merges");
962 entry_set_int_value(entry, p->dus.merges[1]);
963 entry = new_info_entry_in_frame(vbox, "Sectors");
964 entry_set_int_value(entry, p->dus.sectors[1]);
965 entry = new_info_entry_in_frame(vbox, "Ticks");
966 entry_set_int_value(entry, p->dus.ticks[1]);
967
968 frame = gtk_frame_new("Shared");
969 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
970 vbox = gtk_hbox_new(TRUE, 3);
971 gtk_container_add(GTK_CONTAINER(frame), vbox);
972 entry = new_info_entry_in_frame(vbox, "IO ticks");
973 entry_set_int_value(entry, p->dus.io_ticks);
974 entry = new_info_entry_in_frame(vbox, "Time in queue");
975 entry_set_int_value(entry, p->dus.time_in_queue);
976
Jens Axboe604cfe32012-03-07 19:51:36 +0100977 util = 0.0;
978 if (p->dus.msec)
979 util = (double) 100 * p->dus.io_ticks / (double) p->dus.msec;
980 if (util > 100.0)
981 util = 100.0;
982
983 sprintf(tmp, "%3.2f%%", util);
984 entry = new_info_entry_in_frame(vbox, "Disk utilization");
985 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
986
Jens Axboee0681f32012-03-06 12:14:42 +0100987 gtk_widget_show_all(gc->results_widget);
988out:
Jens Axboe0050e5f2012-03-06 09:23:27 +0100989 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100990}
991
Jens Axboe3650a3c2012-03-05 14:09:03 +0100992extern int sum_stat_clients;
993extern struct thread_stat client_ts;
994extern struct group_run_stats client_gs;
995
996static int sum_stat_nr;
997
Jens Axboe89e5fad2012-03-05 09:21:12 +0100998static void gfio_thread_status_op(struct fio_client *client,
999 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001000{
Jens Axboe3650a3c2012-03-05 14:09:03 +01001001 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
1002
1003 gfio_display_ts(client, &p->ts, &p->rs);
1004
1005 if (sum_stat_clients == 1)
1006 return;
1007
1008 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
1009 sum_group_stats(&client_gs, &p->rs);
1010
1011 client_ts.members++;
1012 client_ts.groupid = p->ts.groupid;
1013
1014 if (++sum_stat_nr == sum_stat_clients) {
1015 strcpy(client_ts.name, "All clients");
1016 gfio_display_ts(client, &client_ts, &client_gs);
1017 }
Stephen M. Camerona1820202012-02-24 08:17:31 +01001018}
1019
Jens Axboe89e5fad2012-03-05 09:21:12 +01001020static void gfio_group_stats_op(struct fio_client *client,
1021 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001022{
Jens Axboe0050e5f2012-03-06 09:23:27 +01001023 gdk_threads_enter();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001024 printf("gfio_group_stats_op called\n");
Jens Axboe89e5fad2012-03-05 09:21:12 +01001025 fio_client_ops.group_stats(client, cmd);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001026 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001027}
1028
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001029static gint on_config_drawing_area(GtkWidget *w, GdkEventConfigure *event)
1030{
1031 ui.drawing_area_xdim = w->allocation.width;
1032 ui.drawing_area_ydim = w->allocation.height;
1033 return TRUE;
1034}
1035
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001036static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
1037{
1038 struct gui *ui = (struct gui *) p;
1039 cairo_t *cr;
1040
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001041 graph_set_size(ui->iops_graph, ui->drawing_area_xdim / 2.0,
1042 ui->drawing_area_ydim);
1043 graph_set_size(ui->bandwidth_graph, ui->drawing_area_xdim / 2.0,
1044 ui->drawing_area_ydim);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001045 cr = gdk_cairo_create(w->window);
1046
1047 cairo_set_source_rgb(cr, 0, 0, 0);
1048
1049 cairo_save(cr);
1050 cairo_translate(cr, 0, 0);
1051 line_graph_draw(ui->bandwidth_graph, cr);
1052 cairo_stroke(cr);
1053 cairo_restore(cr);
1054
1055 cairo_save(cr);
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001056 cairo_translate(cr, ui->drawing_area_xdim / 2.0, 0);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001057 line_graph_draw(ui->iops_graph, cr);
1058 cairo_stroke(cr);
1059 cairo_restore(cr);
1060 cairo_destroy(cr);
1061
1062 return FALSE;
1063}
1064
Jens Axboe3e47bd22012-02-29 13:45:02 +01001065static void gfio_update_eta(struct jobs_eta *je)
1066{
1067 static int eta_good;
1068 char eta_str[128];
1069 char output[256];
1070 char tmp[32];
1071 double perc = 0.0;
1072 int i2p = 0;
1073
Jens Axboe0050e5f2012-03-06 09:23:27 +01001074 gdk_threads_enter();
1075
Jens Axboe3e47bd22012-02-29 13:45:02 +01001076 eta_str[0] = '\0';
1077 output[0] = '\0';
1078
1079 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1080 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1081 eta_to_str(eta_str, je->eta_sec);
1082 }
1083
1084 sprintf(tmp, "%u", je->nr_running);
Jens Axboeca850992012-03-05 20:04:43 +01001085 gtk_entry_set_text(GTK_ENTRY(ui.eta.jobs), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001086 sprintf(tmp, "%u", je->files_open);
Jens Axboeca850992012-03-05 20:04:43 +01001087 gtk_entry_set_text(GTK_ENTRY(ui.eta.files), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001088
1089#if 0
1090 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1091 if (je->m_rate || je->t_rate) {
1092 char *tr, *mr;
1093
1094 mr = num2str(je->m_rate, 4, 0, i2p);
1095 tr = num2str(je->t_rate, 4, 0, i2p);
Jens Axboeca850992012-03-05 20:04:43 +01001096 gtk_entry_set_text(GTK_ENTRY(ui.eta);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001097 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1098 free(tr);
1099 free(mr);
1100 } else if (je->m_iops || je->t_iops)
1101 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
Jens Axboeebbd89c2012-03-02 11:21:13 +01001102
Jens Axboeca850992012-03-05 20:04:43 +01001103 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_bw), "---");
1104 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_iops), "---");
1105 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_bw), "---");
1106 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_iops), "---");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001107#endif
1108
1109 if (je->eta_sec != INT_MAX && je->nr_running) {
1110 char *iops_str[2];
1111 char *rate_str[2];
1112
1113 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1114 strcpy(output, "-.-% done");
1115 else {
1116 eta_good = 1;
1117 perc *= 100.0;
1118 sprintf(output, "%3.1f%% done", perc);
1119 }
1120
1121 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1122 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1123
1124 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1125 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1126
Jens Axboeca850992012-03-05 20:04:43 +01001127 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_bw), rate_str[0]);
1128 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_iops), iops_str[0]);
1129 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_bw), rate_str[1]);
1130 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_iops), iops_str[1]);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001131
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001132 graph_add_xy_data(ui.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1133 graph_add_xy_data(ui.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1134 graph_add_xy_data(ui.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1135 graph_add_xy_data(ui.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
1136
Jens Axboe3e47bd22012-02-29 13:45:02 +01001137 free(rate_str[0]);
1138 free(rate_str[1]);
1139 free(iops_str[0]);
1140 free(iops_str[1]);
1141 }
1142
1143 if (eta_str[0]) {
1144 char *dst = output + strlen(output);
1145
1146 sprintf(dst, " - %s", eta_str);
1147 }
1148
1149 gfio_update_thread_status(output, perc);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001150 gdk_threads_leave();
Jens Axboe3e47bd22012-02-29 13:45:02 +01001151}
1152
Stephen M. Camerona1820202012-02-24 08:17:31 +01001153static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1154{
Jens Axboe843ad232012-02-29 11:44:53 +01001155 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001156 struct gfio_client *gc = client->client_data;
1157 struct gui *ui = gc->ui;
Jens Axboe843ad232012-02-29 11:44:53 +01001158 const char *os, *arch;
1159 char buf[64];
1160
1161 os = fio_get_os_string(probe->os);
1162 if (!os)
1163 os = "unknown";
1164
1165 arch = fio_get_arch_string(probe->arch);
1166 if (!arch)
1167 os = "unknown";
1168
1169 if (!client->name)
1170 client->name = strdup((char *) probe->hostname);
1171
Jens Axboe0050e5f2012-03-06 09:23:27 +01001172 gdk_threads_enter();
1173
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001174 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), (char *) probe->hostname);
1175 gtk_label_set_text(GTK_LABEL(ui->probe.os), os);
1176 gtk_label_set_text(GTK_LABEL(ui->probe.arch), arch);
Jens Axboe843ad232012-02-29 11:44:53 +01001177 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001178 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), buf);
1179
1180 gfio_set_connected(ui, 1);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001181
1182 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001183}
1184
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001185static void gfio_update_thread_status(char *status_message, double perc)
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001186{
1187 static char message[100];
1188 const char *m = message;
1189
1190 strncpy(message, status_message, sizeof(message) - 1);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001191 gtk_progress_bar_set_text(
1192 GTK_PROGRESS_BAR(ui.thread_status_pb), m);
1193 gtk_progress_bar_set_fraction(
1194 GTK_PROGRESS_BAR(ui.thread_status_pb), perc / 100.0);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001195 gtk_widget_queue_draw(ui.window);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001196}
1197
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001198static void gfio_quit_op(struct fio_client *client)
1199{
Jens Axboee0681f32012-03-06 12:14:42 +01001200 struct gfio_client *gc = client->client_data;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001201
Jens Axboe0050e5f2012-03-06 09:23:27 +01001202 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +01001203 gfio_set_connected(gc->ui, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001204 gdk_threads_leave();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001205}
1206
Jens Axboe807f9972012-03-02 10:25:24 +01001207static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1208{
1209 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +01001210 struct gfio_client *gc = client->client_data;
Jens Axboedcaeb602012-03-08 19:45:37 +01001211 struct thread_options *o = &gc->o;
Jens Axboee0681f32012-03-06 12:14:42 +01001212 struct gui *ui = gc->ui;
Jens Axboe807f9972012-03-02 10:25:24 +01001213 char tmp[8];
Jens Axboe807f9972012-03-02 10:25:24 +01001214
Jens Axboedcaeb602012-03-08 19:45:37 +01001215 convert_thread_options_to_cpu(o, &p->top);
Jens Axboe807f9972012-03-02 10:25:24 +01001216
Jens Axboe0050e5f2012-03-06 09:23:27 +01001217 gdk_threads_enter();
1218
Jens Axboedcaeb602012-03-08 19:45:37 +01001219 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), (gchar *) o->name);
1220 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), ddir_str(o->td_ddir));
1221 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), (gchar *) o->ioengine);
Jens Axboe807f9972012-03-02 10:25:24 +01001222
Jens Axboedcaeb602012-03-08 19:45:37 +01001223 sprintf(tmp, "%u", o->iodepth);
Jens Axboeca850992012-03-05 20:04:43 +01001224 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), tmp);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001225
Jens Axboedcaeb602012-03-08 19:45:37 +01001226 gc->job_added++;
1227
Jens Axboe0050e5f2012-03-06 09:23:27 +01001228 gdk_threads_leave();
Jens Axboe807f9972012-03-02 10:25:24 +01001229}
1230
Jens Axboeed727a42012-03-02 12:14:40 +01001231static void gfio_client_timed_out(struct fio_client *client)
1232{
Jens Axboee0681f32012-03-06 12:14:42 +01001233 struct gfio_client *gc = client->client_data;
Jens Axboeed727a42012-03-02 12:14:40 +01001234 GtkWidget *dialog, *label, *content;
1235 char buf[256];
1236
1237 gdk_threads_enter();
1238
Jens Axboee0681f32012-03-06 12:14:42 +01001239 gfio_set_connected(gc->ui, 0);
1240 clear_ui_info(gc->ui);
Jens Axboeed727a42012-03-02 12:14:40 +01001241
1242 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
1243
1244 dialog = gtk_dialog_new_with_buttons("Timed out!",
Jens Axboee0681f32012-03-06 12:14:42 +01001245 GTK_WINDOW(gc->ui->window),
Jens Axboeed727a42012-03-02 12:14:40 +01001246 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1247 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1248
Jens Axboef1299092012-03-07 20:00:02 +01001249 /* gtk_dialog_get_content_area() is 2.14 and newer */
1250 content = GTK_DIALOG(dialog)->vbox;
1251
Jens Axboeed727a42012-03-02 12:14:40 +01001252 label = gtk_label_new((const gchar *) buf);
1253 gtk_container_add(GTK_CONTAINER(content), label);
1254 gtk_widget_show_all(dialog);
1255 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1256
1257 gtk_dialog_run(GTK_DIALOG(dialog));
1258 gtk_widget_destroy(dialog);
1259
1260 gdk_threads_leave();
1261}
1262
Jens Axboe6b79c802012-03-08 10:51:36 +01001263static void gfio_client_stop(struct fio_client *client, struct fio_net_cmd *cmd)
1264{
1265 struct gfio_client *gc = client->client_data;
1266
1267 gdk_threads_enter();
1268
1269 gfio_set_connected(gc->ui, 0);
1270
1271 if (gc->err_entry)
1272 entry_set_int_value(gc->err_entry, client->error);
1273
1274 gdk_threads_leave();
1275}
1276
Stephen M. Camerona1820202012-02-24 08:17:31 +01001277struct client_ops gfio_client_ops = {
Jens Axboe0420ba62012-02-29 11:16:52 +01001278 .text_op = gfio_text_op,
1279 .disk_util = gfio_disk_util_op,
1280 .thread_status = gfio_thread_status_op,
1281 .group_stats = gfio_group_stats_op,
Jens Axboea5276612012-03-04 15:15:08 +01001282 .eta = gfio_update_eta,
Jens Axboe0420ba62012-02-29 11:16:52 +01001283 .probe = gfio_probe_op,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001284 .quit = gfio_quit_op,
Jens Axboe807f9972012-03-02 10:25:24 +01001285 .add_job = gfio_add_job_op,
Jens Axboeed727a42012-03-02 12:14:40 +01001286 .timed_out = gfio_client_timed_out,
Jens Axboe6b79c802012-03-08 10:51:36 +01001287 .stop = gfio_client_stop,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001288 .stay_connected = 1,
Stephen M. Camerona1820202012-02-24 08:17:31 +01001289};
1290
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001291static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1292 __attribute__((unused)) gpointer data)
1293{
1294 gtk_main_quit();
1295}
1296
Stephen M. Cameron25927252012-02-24 08:17:31 +01001297static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001298{
Stephen M. Cameron25927252012-02-24 08:17:31 +01001299 fio_handle_clients(&gfio_client_ops);
Stephen M. Cameron25927252012-02-24 08:17:31 +01001300 return NULL;
1301}
1302
Jens Axboe0420ba62012-02-29 11:16:52 +01001303static int send_job_files(struct gui *ui)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001304{
Jens Axboe441013b2012-03-01 08:01:52 +01001305 int i, ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001306
Jens Axboe0420ba62012-02-29 11:16:52 +01001307 for (i = 0; i < ui->nr_job_files; i++) {
1308 ret = fio_clients_send_ini(ui->job_files[i]);
Jens Axboe441013b2012-03-01 08:01:52 +01001309 if (ret)
1310 break;
1311
Jens Axboe0420ba62012-02-29 11:16:52 +01001312 free(ui->job_files[i]);
1313 ui->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001314 }
1315 while (i < ui->nr_job_files) {
1316 free(ui->job_files[i]);
1317 ui->job_files[i] = NULL;
1318 i++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001319 }
1320
Jens Axboe441013b2012-03-01 08:01:52 +01001321 return ret;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001322}
1323
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001324static void start_job_thread(struct gui *ui)
Stephen M. Cameron25927252012-02-24 08:17:31 +01001325{
Jens Axboe0420ba62012-02-29 11:16:52 +01001326 if (send_job_files(ui)) {
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001327 printf("Yeah, I didn't really like those options too much.\n");
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001328 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
1329 return;
1330 }
Stephen M. Cameron25927252012-02-24 08:17:31 +01001331}
1332
Jens Axboe63a130b2012-03-06 20:08:59 +01001333static void *server_thread(void *arg)
1334{
1335 is_backend = 1;
1336 gfio_server_running = 1;
1337 fio_start_server(NULL);
1338 gfio_server_running = 0;
1339 return NULL;
1340}
1341
1342static void gfio_start_server(struct gui *ui)
1343{
1344 if (!gfio_server_running) {
1345 gfio_server_running = 1;
1346 pthread_create(&ui->server_t, NULL, server_thread, NULL);
Jens Axboee34f6ad2012-03-06 20:47:15 +01001347 pthread_detach(ui->server_t);
Jens Axboe63a130b2012-03-06 20:08:59 +01001348 }
1349}
1350
Stephen M. Cameron25927252012-02-24 08:17:31 +01001351static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1352 gpointer data)
1353{
1354 struct gui *ui = data;
1355
Stephen M. Cameron25927252012-02-24 08:17:31 +01001356 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001357 start_job_thread(ui);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001358}
1359
Jens Axboedf06f222012-03-02 13:32:04 +01001360static void file_open(GtkWidget *w, gpointer data);
1361
1362static void connect_clicked(GtkWidget *widget, gpointer data)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001363{
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001364 struct gui *ui = data;
1365
1366 if (!ui->connected) {
Jens Axboedf06f222012-03-02 13:32:04 +01001367 if (!ui->nr_job_files)
1368 file_open(widget, data);
Jens Axboe8663ea62012-03-02 14:04:30 +01001369 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
Jens Axboee34f6ad2012-03-06 20:47:15 +01001370 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe69406b92012-03-06 14:00:42 +01001371 if (!fio_clients_connect()) {
1372 pthread_create(&ui->t, NULL, job_thread, NULL);
1373 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 0);
1374 }
Jens Axboedf06f222012-03-02 13:32:04 +01001375 } else {
1376 fio_clients_terminate();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001377 gfio_set_connected(ui, 0);
Jens Axboe88432652012-03-02 19:09:31 +01001378 clear_ui_info(ui);
Jens Axboedf06f222012-03-02 13:32:04 +01001379 }
Jens Axboe3e47bd22012-02-29 13:45:02 +01001380}
1381
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001382static void add_button(struct gui *ui, int i, GtkWidget *buttonbox,
1383 struct button_spec *buttonspec)
1384{
1385 ui->button[i] = gtk_button_new_with_label(buttonspec->buttontext);
1386 g_signal_connect(ui->button[i], "clicked", G_CALLBACK (buttonspec->f), ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001387 gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], FALSE, FALSE, 3);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001388 gtk_widget_set_tooltip_text(ui->button[i], buttonspeclist[i].tooltiptext);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001389 gtk_widget_set_sensitive(ui->button[i], !buttonspec->start_insensitive);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001390}
1391
1392static void add_buttons(struct gui *ui,
1393 struct button_spec *buttonlist,
1394 int nbuttons)
1395{
1396 int i;
1397
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001398 for (i = 0; i < nbuttons; i++)
1399 add_button(ui, i, ui->buttonbox, &buttonlist[i]);
1400}
1401
Jens Axboe0420ba62012-02-29 11:16:52 +01001402static void on_info_bar_response(GtkWidget *widget, gint response,
1403 gpointer data)
1404{
1405 if (response == GTK_RESPONSE_OK) {
1406 gtk_widget_destroy(widget);
1407 ui.error_info_bar = NULL;
1408 }
1409}
1410
Jens Axboedf06f222012-03-02 13:32:04 +01001411void report_error(GError *error)
Jens Axboe0420ba62012-02-29 11:16:52 +01001412{
1413 if (ui.error_info_bar == NULL) {
1414 ui.error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
1415 GTK_RESPONSE_OK,
1416 NULL);
1417 g_signal_connect(ui.error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1418 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui.error_info_bar),
1419 GTK_MESSAGE_ERROR);
1420
1421 ui.error_label = gtk_label_new(error->message);
1422 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui.error_info_bar));
1423 gtk_container_add(GTK_CONTAINER(container), ui.error_label);
1424
1425 gtk_box_pack_start(GTK_BOX(ui.vbox), ui.error_info_bar, FALSE, FALSE, 0);
1426 gtk_widget_show_all(ui.vbox);
1427 } else {
1428 char buffer[256];
1429 snprintf(buffer, sizeof(buffer), "Failed to open file.");
1430 gtk_label_set(GTK_LABEL(ui.error_label), buffer);
1431 }
1432}
1433
Jens Axboe62bc9372012-03-07 11:45:07 +01001434struct connection_widgets
1435{
1436 GtkWidget *hentry;
1437 GtkWidget *combo;
1438 GtkWidget *button;
1439};
1440
1441static void hostname_cb(GtkEntry *entry, gpointer data)
1442{
1443 struct connection_widgets *cw = data;
1444 int uses_net = 0, is_localhost = 0;
1445 const gchar *text;
1446 gchar *ctext;
1447
1448 /*
1449 * Check whether to display the 'auto start backend' box
1450 * or not. Show it if we are a localhost and using network,
1451 * or using a socket.
1452 */
1453 ctext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->combo));
1454 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
1455 uses_net = 1;
1456 g_free(ctext);
1457
1458 if (uses_net) {
1459 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
1460 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
1461 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
1462 !strcmp(text, "ip6-loopback"))
1463 is_localhost = 1;
1464 }
1465
1466 if (!uses_net || is_localhost) {
1467 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
1468 gtk_widget_set_sensitive(cw->button, 1);
1469 } else {
1470 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
1471 gtk_widget_set_sensitive(cw->button, 0);
1472 }
1473}
1474
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001475static int get_connection_details(char **host, int *port, int *type,
1476 int *server_start)
Jens Axboea7a42ce2012-03-02 13:12:04 +01001477{
Jens Axboe62bc9372012-03-07 11:45:07 +01001478 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
1479 struct connection_widgets cw;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001480 char *typeentry;
1481
1482 dialog = gtk_dialog_new_with_buttons("Connection details",
1483 GTK_WINDOW(ui.window),
1484 GTK_DIALOG_DESTROY_WITH_PARENT,
1485 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1486 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1487
1488 frame = gtk_frame_new("Hostname / socket name");
Jens Axboef1299092012-03-07 20:00:02 +01001489 /* gtk_dialog_get_content_area() is 2.14 and newer */
1490 vbox = GTK_DIALOG(dialog)->vbox;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001491 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1492
1493 box = gtk_vbox_new(FALSE, 6);
1494 gtk_container_add(GTK_CONTAINER(frame), box);
1495
1496 hbox = gtk_hbox_new(TRUE, 10);
1497 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe62bc9372012-03-07 11:45:07 +01001498 cw.hentry = gtk_entry_new();
1499 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
1500 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001501
1502 frame = gtk_frame_new("Port");
1503 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1504 box = gtk_vbox_new(FALSE, 10);
1505 gtk_container_add(GTK_CONTAINER(frame), box);
1506
1507 hbox = gtk_hbox_new(TRUE, 4);
1508 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1509 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1510
1511 frame = gtk_frame_new("Type");
1512 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1513 box = gtk_vbox_new(FALSE, 10);
1514 gtk_container_add(GTK_CONTAINER(frame), box);
1515
1516 hbox = gtk_hbox_new(TRUE, 4);
1517 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1518
Jens Axboe62bc9372012-03-07 11:45:07 +01001519 cw.combo = gtk_combo_box_new_text();
1520 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv4");
1521 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv6");
1522 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "local socket");
1523 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001524
Jens Axboe62bc9372012-03-07 11:45:07 +01001525 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001526
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001527 frame = gtk_frame_new("Options");
1528 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1529 box = gtk_vbox_new(FALSE, 10);
1530 gtk_container_add(GTK_CONTAINER(frame), box);
1531
1532 hbox = gtk_hbox_new(TRUE, 4);
1533 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1534
Jens Axboe62bc9372012-03-07 11:45:07 +01001535 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1536 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
1537 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.");
1538 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
1539
1540 /*
1541 * Connect edit signal, so we can show/not-show the auto start button
1542 */
1543 g_signal_connect(GTK_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
1544 g_signal_connect(GTK_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001545
Jens Axboea7a42ce2012-03-02 13:12:04 +01001546 gtk_widget_show_all(dialog);
1547
1548 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1549 gtk_widget_destroy(dialog);
1550 return 1;
1551 }
1552
Jens Axboe62bc9372012-03-07 11:45:07 +01001553 *host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001554 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1555
Jens Axboe62bc9372012-03-07 11:45:07 +01001556 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw.combo));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001557 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1558 *type = Fio_client_ipv4;
1559 else if (!strncmp(typeentry, "IPv6", 4))
1560 *type = Fio_client_ipv6;
1561 else
1562 *type = Fio_client_socket;
1563 g_free(typeentry);
1564
Jens Axboe62bc9372012-03-07 11:45:07 +01001565 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001566
Jens Axboea7a42ce2012-03-02 13:12:04 +01001567 gtk_widget_destroy(dialog);
1568 return 0;
1569}
1570
Jens Axboee0681f32012-03-06 12:14:42 +01001571static void gfio_client_added(struct gui *ui, struct fio_client *client)
1572{
1573 struct gfio_client *gc;
1574
1575 gc = malloc(sizeof(*gc));
1576 memset(gc, 0, sizeof(*gc));
1577 gc->ui = ui;
1578
1579 client->client_data = gc;
1580}
1581
Jens Axboe0420ba62012-02-29 11:16:52 +01001582static void file_open(GtkWidget *w, gpointer data)
1583{
1584 GtkWidget *dialog;
Jens Axboe63a130b2012-03-06 20:08:59 +01001585 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01001586 GSList *filenames, *fn_glist;
1587 GtkFileFilter *filter;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001588 char *host;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001589 int port, type, server_start;
Jens Axboe0420ba62012-02-29 11:16:52 +01001590
1591 dialog = gtk_file_chooser_dialog_new("Open File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001592 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001593 GTK_FILE_CHOOSER_ACTION_OPEN,
1594 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1595 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1596 NULL);
1597 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1598
1599 filter = gtk_file_filter_new();
1600 gtk_file_filter_add_pattern(filter, "*.fio");
1601 gtk_file_filter_add_pattern(filter, "*.job");
Jens Axboe2d262992012-03-07 08:19:30 +01001602 gtk_file_filter_add_pattern(filter, "*.ini");
Jens Axboe0420ba62012-02-29 11:16:52 +01001603 gtk_file_filter_add_mime_type(filter, "text/fio");
1604 gtk_file_filter_set_name(filter, "Fio job file");
1605 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
1606
1607 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1608 gtk_widget_destroy(dialog);
1609 return;
1610 }
1611
1612 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001613
1614 gtk_widget_destroy(dialog);
1615
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001616 if (get_connection_details(&host, &port, &type, &server_start))
Jens Axboea7a42ce2012-03-02 13:12:04 +01001617 goto err;
1618
Jens Axboe0420ba62012-02-29 11:16:52 +01001619 filenames = fn_glist;
1620 while (filenames != NULL) {
Jens Axboee0681f32012-03-06 12:14:42 +01001621 struct fio_client *client;
1622
Jens Axboe63a130b2012-03-06 20:08:59 +01001623 ui->job_files = realloc(ui->job_files, (ui->nr_job_files + 1) * sizeof(char *));
1624 ui->job_files[ui->nr_job_files] = strdup(filenames->data);
1625 ui->nr_job_files++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001626
Jens Axboee0681f32012-03-06 12:14:42 +01001627 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
1628 if (!client) {
Jens Axboedf06f222012-03-02 13:32:04 +01001629 GError *error;
1630
1631 error = g_error_new(g_quark_from_string("fio"), 1,
1632 "Failed to add client %s", host);
Jens Axboe0420ba62012-02-29 11:16:52 +01001633 report_error(error);
1634 g_error_free(error);
Jens Axboe0420ba62012-02-29 11:16:52 +01001635 }
Jens Axboe63a130b2012-03-06 20:08:59 +01001636 gfio_client_added(ui, client);
Jens Axboe0420ba62012-02-29 11:16:52 +01001637
1638 g_free(filenames->data);
1639 filenames = g_slist_next(filenames);
1640 }
Jens Axboea7a42ce2012-03-02 13:12:04 +01001641 free(host);
Jens Axboe63a130b2012-03-06 20:08:59 +01001642
1643 if (server_start)
1644 gfio_start_server(ui);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001645err:
Jens Axboe0420ba62012-02-29 11:16:52 +01001646 g_slist_free(fn_glist);
Jens Axboe0420ba62012-02-29 11:16:52 +01001647}
1648
1649static void file_save(GtkWidget *w, gpointer data)
1650{
Jens Axboe63a130b2012-03-06 20:08:59 +01001651 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01001652 GtkWidget *dialog;
1653
1654 dialog = gtk_file_chooser_dialog_new("Save File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001655 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001656 GTK_FILE_CHOOSER_ACTION_SAVE,
1657 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1658 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1659 NULL);
1660
1661 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1662 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
1663
1664 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1665 char *filename;
1666
1667 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1668 // save_job_file(filename);
1669 g_free(filename);
1670 }
1671 gtk_widget_destroy(dialog);
1672}
1673
Jens Axboe9b260bd2012-03-06 11:02:52 +01001674static void view_log_destroy(GtkWidget *w, gpointer data)
1675{
1676 struct gui *ui = (struct gui *) data;
1677
1678 gtk_widget_ref(ui->log_tree);
1679 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
1680 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +01001681 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001682}
1683
1684static void view_log(GtkWidget *w, gpointer data)
1685{
Jens Axboe4cbe7212012-03-06 13:36:17 +01001686 GtkWidget *win, *scroll, *vbox, *box;
1687 struct gui *ui = (struct gui *) data;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001688
Jens Axboe4cbe7212012-03-06 13:36:17 +01001689 if (ui->log_view)
1690 return;
1691
1692 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001693 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001694 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001695
Jens Axboe4cbe7212012-03-06 13:36:17 +01001696 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001697
Jens Axboe4cbe7212012-03-06 13:36:17 +01001698 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
1699
1700 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1701
1702 box = gtk_hbox_new(TRUE, 0);
1703 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
1704 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
1705 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
1706
1707 vbox = gtk_vbox_new(TRUE, 5);
1708 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
1709
1710 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001711 gtk_widget_show_all(win);
1712}
1713
Jens Axboe46974a72012-03-02 19:34:13 +01001714static void preferences(GtkWidget *w, gpointer data)
1715{
Jens Axboef3e84402012-03-07 13:14:32 +01001716 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
Jens Axboe46974a72012-03-02 19:34:13 +01001717 int i;
1718
1719 dialog = gtk_dialog_new_with_buttons("Preferences",
1720 GTK_WINDOW(ui.window),
1721 GTK_DIALOG_DESTROY_WITH_PARENT,
1722 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1723 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1724 NULL);
1725
Jens Axboe0b8d11e2012-03-02 19:44:15 +01001726 frame = gtk_frame_new("Debug logging");
Jens Axboe46974a72012-03-02 19:34:13 +01001727 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
Jens Axboef3e84402012-03-07 13:14:32 +01001728
1729 vbox = gtk_vbox_new(FALSE, 6);
1730 gtk_container_add(GTK_CONTAINER(frame), vbox);
1731
Jens Axboe46974a72012-03-02 19:34:13 +01001732 box = gtk_hbox_new(FALSE, 6);
Jens Axboef3e84402012-03-07 13:14:32 +01001733 gtk_container_add(GTK_CONTAINER(vbox), box);
Jens Axboe46974a72012-03-02 19:34:13 +01001734
1735 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
1736
1737 for (i = 0; i < FD_DEBUG_MAX; i++) {
Jens Axboef3e84402012-03-07 13:14:32 +01001738 if (i == 7) {
1739 box = gtk_hbox_new(FALSE, 6);
1740 gtk_container_add(GTK_CONTAINER(vbox), box);
1741 }
1742
1743
Jens Axboe46974a72012-03-02 19:34:13 +01001744 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
Jens Axboe0b8d11e2012-03-02 19:44:15 +01001745 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
Jens Axboe46974a72012-03-02 19:34:13 +01001746 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
1747 }
1748
Jens Axboef3e84402012-03-07 13:14:32 +01001749 frame = gtk_frame_new("Graph font");
1750 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1751 vbox = gtk_vbox_new(FALSE, 6);
1752 gtk_container_add(GTK_CONTAINER(frame), vbox);
1753
1754 font = gtk_font_button_new();
1755 gtk_box_pack_start(GTK_BOX(vbox), font, FALSE, FALSE, 5);
1756
Jens Axboe46974a72012-03-02 19:34:13 +01001757 gtk_widget_show_all(dialog);
1758
1759 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1760 gtk_widget_destroy(dialog);
1761 return;
1762 }
1763
1764 for (i = 0; i < FD_DEBUG_MAX; i++) {
1765 int set;
1766
1767 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
1768 if (set)
1769 fio_debug |= (1UL << i);
1770 }
1771
Jens Axboef3e84402012-03-07 13:14:32 +01001772 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
Jens Axboe46974a72012-03-02 19:34:13 +01001773 gtk_widget_destroy(dialog);
1774}
1775
Jens Axboe0420ba62012-02-29 11:16:52 +01001776static void about_dialog(GtkWidget *w, gpointer data)
1777{
Jens Axboe81e4ea62012-03-07 14:18:28 +01001778 const char *authors[] = {
1779 "Jens Axboe <axboe@kernel.dk>",
1780 "Stephen Carmeron <stephenmcameron@gmail.com>",
1781 NULL
1782 };
Jens Axboe84a72ed2012-03-07 14:24:57 +01001783 const char *license[] = {
1784 "Fio is free software; you can redistribute it and/or modify "
1785 "it under the terms of the GNU General Public License as published by "
1786 "the Free Software Foundation; either version 2 of the License, or "
1787 "(at your option) any later version.\n",
1788 "Fio is distributed in the hope that it will be useful, "
1789 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
1790 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
1791 "GNU General Public License for more details.\n",
1792 "You should have received a copy of the GNU General Public License "
1793 "along with Fio; if not, write to the Free Software Foundation, Inc., "
1794 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
1795 };
1796 char *license_trans;
1797
1798 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
1799 license[2], "\n", NULL);
Jens Axboe81e4ea62012-03-07 14:18:28 +01001800
Jens Axboe0420ba62012-02-29 11:16:52 +01001801 gtk_show_about_dialog(NULL,
1802 "program-name", "gfio",
1803 "comments", "Gtk2 UI for fio",
Jens Axboe84a72ed2012-03-07 14:24:57 +01001804 "license", license_trans,
Jens Axboe81e4ea62012-03-07 14:18:28 +01001805 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
1806 "authors", authors,
Jens Axboe0420ba62012-02-29 11:16:52 +01001807 "version", fio_version_string,
Jens Axboe81e4ea62012-03-07 14:18:28 +01001808 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
Jens Axboe0420ba62012-02-29 11:16:52 +01001809 "logo-icon-name", "fio",
1810 /* Must be last: */
Jens Axboe81e4ea62012-03-07 14:18:28 +01001811 "wrap-license", TRUE,
Jens Axboe0420ba62012-02-29 11:16:52 +01001812 NULL);
Jens Axboe84a72ed2012-03-07 14:24:57 +01001813
1814 g_free (license_trans);
Jens Axboe0420ba62012-02-29 11:16:52 +01001815}
1816
1817static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01001818 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01001819 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01001820 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
1821 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
1822 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
1823 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01001824 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe46974a72012-03-02 19:34:13 +01001825 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
1826 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01001827};
Jens Axboe3e47bd22012-02-29 13:45:02 +01001828static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01001829
1830static const gchar *ui_string = " \
1831 <ui> \
1832 <menubar name=\"MainMenu\"> \
1833 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
1834 <menuitem name=\"Open\" action=\"OpenFile\" /> \
1835 <menuitem name=\"Save\" action=\"SaveFile\" /> \
1836 <separator name=\"Separator\"/> \
Jens Axboe46974a72012-03-02 19:34:13 +01001837 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
1838 <separator name=\"Separator2\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001839 <menuitem name=\"Quit\" action=\"Quit\" /> \
1840 </menu> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01001841 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
1842 <menuitem name=\"Log\" action=\"ViewLog\" /> \
1843 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01001844 <menu name=\"Help\" action=\"HelpMenuAction\"> \
1845 <menuitem name=\"About\" action=\"About\" /> \
1846 </menu> \
1847 </menubar> \
1848 </ui> \
1849";
1850
Jens Axboe4cbe7212012-03-06 13:36:17 +01001851static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
1852 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01001853{
1854 GtkActionGroup *action_group = gtk_action_group_new("Menu");
1855 GError *error = 0;
1856
1857 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001858 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001859
1860 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1861 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
1862
1863 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
1864 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
1865}
1866
1867void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
1868 GtkWidget *vbox, GtkUIManager *ui_manager)
1869{
1870 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
1871}
1872
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001873static void init_ui(int *argc, char **argv[], struct gui *ui)
1874{
Jens Axboe0420ba62012-02-29 11:16:52 +01001875 GtkSettings *settings;
1876 GtkUIManager *uimanager;
Jens Axboe843ad232012-02-29 11:44:53 +01001877 GtkWidget *menu, *probe, *probe_frame, *probe_box;
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01001878 GdkColor white;
Jens Axboe0420ba62012-02-29 11:16:52 +01001879
1880 memset(ui, 0, sizeof(*ui));
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001881
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001882 /* Magical g*thread incantation, you just need this thread stuff.
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001883 * Without it, the update that happens in gfio_update_thread_status
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001884 * doesn't really happen in a timely fashion, you need expose events
1885 */
Jens Axboeed727a42012-03-02 12:14:40 +01001886 if (!g_thread_supported())
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001887 g_thread_init(NULL);
1888 gdk_threads_init();
1889
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001890 gtk_init(argc, argv);
Jens Axboe0420ba62012-02-29 11:16:52 +01001891 settings = gtk_settings_get_default();
1892 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
1893 g_type_init();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001894
1895 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1896 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
Jens Axboef3e84402012-03-07 13:14:32 +01001897 gtk_window_set_default_size(GTK_WINDOW(ui->window), 700, 700);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001898
Jens Axboe0420ba62012-02-29 11:16:52 +01001899 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
1900 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001901
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001902 ui->vbox = gtk_vbox_new(FALSE, 0);
1903 gtk_container_add(GTK_CONTAINER (ui->window), ui->vbox);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001904
Jens Axboe0420ba62012-02-29 11:16:52 +01001905 uimanager = gtk_ui_manager_new();
Jens Axboe4cbe7212012-03-06 13:36:17 +01001906 menu = get_menubar_menu(ui->window, uimanager, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001907 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
1908
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001909 /*
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001910 * Set up alignments for widgets at the top of ui,
1911 * align top left, expand horizontally but not vertically
1912 */
1913 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001914 ui->topvbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001915 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001916 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->topalign, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001917
Jens Axboe3e47bd22012-02-29 13:45:02 +01001918 probe = gtk_frame_new("Job");
Jens Axboe843ad232012-02-29 11:44:53 +01001919 gtk_box_pack_start(GTK_BOX(ui->topvbox), probe, TRUE, FALSE, 3);
1920 probe_frame = gtk_vbox_new(FALSE, 3);
1921 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
1922
1923 probe_box = gtk_hbox_new(FALSE, 3);
1924 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01001925 ui->probe.hostname = new_info_label_in_frame(probe_box, "Host");
1926 ui->probe.os = new_info_label_in_frame(probe_box, "OS");
1927 ui->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
1928 ui->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
1929
Jens Axboe3e47bd22012-02-29 13:45:02 +01001930 probe_box = gtk_hbox_new(FALSE, 3);
1931 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01001932
Jens Axboeca850992012-03-05 20:04:43 +01001933 ui->eta.name = new_info_entry_in_frame(probe_box, "Name");
1934 ui->eta.iotype = new_info_entry_in_frame(probe_box, "IO");
1935 ui->eta.ioengine = new_info_entry_in_frame(probe_box, "IO Engine");
1936 ui->eta.iodepth = new_info_entry_in_frame(probe_box, "IO Depth");
1937 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
1938 ui->eta.files = new_info_entry_in_frame(probe_box, "Open files");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001939
1940 probe_box = gtk_hbox_new(FALSE, 3);
1941 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboeca850992012-03-05 20:04:43 +01001942 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1943 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1944 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1945 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001946
1947 /*
1948 * Only add this if we have a commit rate
1949 */
1950#if 0
1951 probe_box = gtk_hbox_new(FALSE, 3);
1952 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1953
Jens Axboe3e47bd22012-02-29 13:45:02 +01001954 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1955 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1956
Jens Axboe3e47bd22012-02-29 13:45:02 +01001957 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1958 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001959#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01001960
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001961 /*
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001962 * Set up a drawing area and IOPS and bandwidth graphs
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001963 */
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01001964 gdk_color_parse("white", &white);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001965 ui->drawing_area = gtk_drawing_area_new();
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001966 ui->drawing_area_xdim = DRAWING_AREA_XDIM;
1967 ui->drawing_area_ydim = DRAWING_AREA_YDIM;
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001968 gtk_widget_set_size_request(GTK_WIDGET(ui->drawing_area),
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001969 ui->drawing_area_xdim, ui->drawing_area_ydim);
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01001970 gtk_widget_modify_bg(ui->drawing_area, GTK_STATE_NORMAL, &white);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001971 g_signal_connect(G_OBJECT(ui->drawing_area), "expose_event",
1972 G_CALLBACK (on_expose_drawing_area), ui);
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001973 g_signal_connect(G_OBJECT(ui->drawing_area), "configure_event",
1974 G_CALLBACK (on_config_drawing_area), ui);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001975 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1976 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1977 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001978 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1979 ui->drawing_area);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001980 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->scrolled_window,
1981 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001982
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001983 setup_iops_graph(ui);
1984 setup_bandwidth_graph(ui);
1985
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001986 /*
1987 * Set up alignments for widgets at the bottom of ui,
1988 * align bottom left, expand horizontally but not vertically
1989 */
1990 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
1991 ui->buttonbox = gtk_hbox_new(FALSE, 0);
1992 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001993 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->bottomalign,
1994 FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001995
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001996 add_buttons(ui, buttonspeclist, ARRAYSIZE(buttonspeclist));
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001997
1998 /*
1999 * Set up thread status progress bar
2000 */
2001 ui->thread_status_pb = gtk_progress_bar_new();
2002 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01002003 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002004 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
2005
Jens Axboe9b260bd2012-03-06 11:02:52 +01002006 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002007
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002008 gtk_widget_show_all(ui->window);
2009}
2010
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002011int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002012{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002013 if (initialize_fio(envp))
2014 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01002015 if (fio_init_options())
2016 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01002017
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002018 init_ui(&argc, &argv, &ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01002019
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002020 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002021 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002022 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002023 return 0;
2024}