blob: 457a13af4f91bbb6087f00afd258d49a72229de4 [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>
5 *
6 * The license below covers all files distributed with fio unless otherwise
7 * noted in the file itself.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
Stephen M. Cameron8232e282012-02-24 08:17:31 +010023#include <locale.h>
Stephen M. Cameron60f6b332012-02-24 08:17:32 +010024#include <malloc.h>
Stephen M. Cameron8232e282012-02-24 08:17:31 +010025
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +010026#include <glib.h>
Stephen M. Cameronff1f3282012-02-24 08:17:30 +010027#include <gtk/gtk.h>
28
Stephen M. Cameron8232e282012-02-24 08:17:31 +010029#include "fio.h"
30
Jens Axboe3e47bd22012-02-29 13:45:02 +010031static void gfio_update_thread_status(char *status_message, double perc);
32
Stephen M. Cameronf3074002012-02-24 08:17:30 +010033#define ARRAYSIZE(x) (sizeof((x)) / (sizeof((x)[0])))
34
35typedef void (*clickfunction)(GtkWidget *widget, gpointer data);
36
Jens Axboe3e47bd22012-02-29 13:45:02 +010037static void connect_clicked(GtkWidget *widget, gpointer data);
Stephen M. Cameronf3074002012-02-24 08:17:30 +010038static void start_job_clicked(GtkWidget *widget, gpointer data);
39
40static struct button_spec {
41 const char *buttontext;
42 clickfunction f;
43 const char *tooltiptext;
Jens Axboe3e47bd22012-02-29 13:45:02 +010044 const int start_insensitive;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010045} buttonspeclist[] = {
Jens Axboe3e47bd22012-02-29 13:45:02 +010046#define CONNECT_BUTTON 0
47#define START_JOB_BUTTON 1
48 { "Connect", connect_clicked, "Connect to host", 0 },
Stephen M. Cameronf3074002012-02-24 08:17:30 +010049 { "Start Job",
50 start_job_clicked,
Jens Axboe3e47bd22012-02-29 13:45:02 +010051 "Send current fio job to fio server to be executed", 1 },
Stephen M. Cameronf3074002012-02-24 08:17:30 +010052};
53
Jens Axboe843ad232012-02-29 11:44:53 +010054struct probe_widget {
55 GtkWidget *hostname;
56 GtkWidget *os;
57 GtkWidget *arch;
58 GtkWidget *fio_ver;
59};
60
Jens Axboe3e47bd22012-02-29 13:45:02 +010061struct eta_widget {
Jens Axboe807f9972012-03-02 10:25:24 +010062 GtkWidget *name;
63 GtkWidget *iotype;
64 GtkWidget *ioengine;
65 GtkWidget *iodepth;
Jens Axboe3e47bd22012-02-29 13:45:02 +010066 GtkWidget *jobs;
67 GtkWidget *files;
68 GtkWidget *read_bw;
69 GtkWidget *read_iops;
70 GtkWidget *cr_bw;
71 GtkWidget *cr_iops;
72 GtkWidget *write_bw;
73 GtkWidget *write_iops;
74 GtkWidget *cw_bw;
75 GtkWidget *cw_iops;
76};
77
Stephen M. Cameronff1f3282012-02-24 08:17:30 +010078struct gui {
79 GtkWidget *window;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +010080 GtkWidget *vbox;
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +010081 GtkWidget *topvbox;
82 GtkWidget *topalign;
83 GtkWidget *bottomalign;
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +010084 GtkWidget *thread_status_pb;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010085 GtkWidget *buttonbox;
86 GtkWidget *button[ARRAYSIZE(buttonspeclist)];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +010087 GtkWidget *scrolled_window;
88 GtkWidget *textview;
Jens Axboe0420ba62012-02-29 11:16:52 +010089 GtkWidget *error_info_bar;
90 GtkWidget *error_label;
Jens Axboef9d40b42012-03-06 09:52:49 +010091 GtkWidget *results_notebook;
92 GtkWidget *results_window;
Jens Axboe9b260bd2012-03-06 11:02:52 +010093 GtkListStore *log_model;
94 GtkWidget *log_tree;
Stephen M. Cameron736f2df2012-02-24 08:17:32 +010095 GtkTextBuffer *text;
Jens Axboe843ad232012-02-29 11:44:53 +010096 struct probe_widget probe;
Jens Axboe3e47bd22012-02-29 13:45:02 +010097 struct eta_widget eta;
Jens Axboe3ec62ec2012-03-01 12:01:29 +010098 int connected;
Stephen M. Cameron25927252012-02-24 08:17:31 +010099 pthread_t t;
Jens Axboe0420ba62012-02-29 11:16:52 +0100100
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100101 struct fio_client *client;
Jens Axboe0420ba62012-02-29 11:16:52 +0100102 int nr_job_files;
103 char **job_files;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100104} ui;
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100105
Jens Axboee0681f32012-03-06 12:14:42 +0100106struct gfio_client {
107 struct gui *ui;
108 GtkWidget *results_widget;
109 GtkWidget *disk_util_frame;
110};
111
Jens Axboe8663ea62012-03-02 14:04:30 +0100112static void clear_ui_info(struct gui *ui)
113{
114 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), "");
115 gtk_label_set_text(GTK_LABEL(ui->probe.os), "");
116 gtk_label_set_text(GTK_LABEL(ui->probe.arch), "");
117 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), "");
Jens Axboeca850992012-03-05 20:04:43 +0100118 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), "");
119 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), "");
120 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), "");
121 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), "");
122 gtk_entry_set_text(GTK_ENTRY(ui->eta.jobs), "");
123 gtk_entry_set_text(GTK_ENTRY(ui->eta.files), "");
124 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), "");
125 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), "");
126 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), "");
127 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100128}
129
Jens Axboe3650a3c2012-03-05 14:09:03 +0100130static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
131{
132 GtkWidget *entry, *frame;
133
134 frame = gtk_frame_new(label);
135 entry = gtk_entry_new();
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100136 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100137 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
138 gtk_container_add(GTK_CONTAINER(frame), entry);
139
140 return entry;
141}
142
143static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
144{
145 GtkWidget *label_widget;
146 GtkWidget *frame;
147
148 frame = gtk_frame_new(label);
149 label_widget = gtk_label_new(NULL);
150 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
151 gtk_container_add(GTK_CONTAINER(frame), label_widget);
152
153 return label_widget;
154}
155
156static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
157{
158 GtkWidget *button, *box;
159
160 box = gtk_hbox_new(FALSE, 3);
161 gtk_container_add(GTK_CONTAINER(hbox), box);
162
163 button = gtk_spin_button_new_with_range(min, max, 1.0);
164 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
165
166 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
167 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
168
169 return button;
170}
171
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100172static void gfio_set_connected(struct gui *ui, int connected)
173{
174 if (connected) {
175 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
176 ui->connected = 1;
177 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Disconnect");
178 } else {
179 ui->connected = 0;
180 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Connect");
181 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
182 }
183}
184
Jens Axboe3650a3c2012-03-05 14:09:03 +0100185static void label_set_int_value(GtkWidget *entry, unsigned int val)
186{
187 char tmp[80];
188
189 sprintf(tmp, "%u", val);
190 gtk_label_set_text(GTK_LABEL(entry), tmp);
191}
192
193static void entry_set_int_value(GtkWidget *entry, unsigned int val)
194{
195 char tmp[80];
196
197 sprintf(tmp, "%u", val);
198 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
199}
200
Jens Axboea2697902012-03-05 16:43:49 +0100201#define ALIGN_LEFT 1
202#define ALIGN_RIGHT 2
203#define INVISIBLE 4
204#define UNSORTABLE 8
205
206GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
207{
208 GtkCellRenderer *renderer;
209 GtkTreeViewColumn *col;
210 double xalign = 0.0; /* left as default */
211 PangoAlignment align;
212 gboolean visible;
213
214 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
215 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
216 PANGO_ALIGN_CENTER;
217 visible = !(flags & INVISIBLE);
218
219 renderer = gtk_cell_renderer_text_new();
220 col = gtk_tree_view_column_new();
221
222 gtk_tree_view_column_set_title(col, title);
223 if (!(flags & UNSORTABLE))
224 gtk_tree_view_column_set_sort_column_id(col, index);
225 gtk_tree_view_column_set_resizable(col, TRUE);
226 gtk_tree_view_column_pack_start(col, renderer, TRUE);
227 gtk_tree_view_column_add_attribute(col, renderer, "text", index);
228 gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
229 switch (align) {
230 case PANGO_ALIGN_LEFT:
231 xalign = 0.0;
232 break;
233 case PANGO_ALIGN_CENTER:
234 xalign = 0.5;
235 break;
236 case PANGO_ALIGN_RIGHT:
237 xalign = 1.0;
238 break;
239 }
240 gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
241 gtk_tree_view_column_set_visible(col, visible);
242 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
243 return col;
244}
245
Jens Axboe9b260bd2012-03-06 11:02:52 +0100246static void gfio_ui_setup_log(struct gui *ui)
247{
248 GtkTreeSelection *selection;
249 GtkListStore *model;
250 GtkWidget *tree_view;
251
252 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
253
254 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
255 gtk_widget_set_can_focus(tree_view, FALSE);
256
257 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
258 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
259
260 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
261 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
262 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
263 tree_view_column(tree_view, 3, "Text", ALIGN_RIGHT | UNSORTABLE);
264
265 ui->log_model = model;
266 ui->log_tree = tree_view;
267}
268
Jens Axboea2697902012-03-05 16:43:49 +0100269static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
270 fio_fp64_t *plist,
271 unsigned int len,
272 const char *base,
273 unsigned int scale)
274{
275 GType types[FIO_IO_U_LIST_MAX_LEN];
276 GtkWidget *tree_view;
277 GtkTreeSelection *selection;
278 GtkListStore *model;
279 GtkTreeIter iter;
280 int i;
281
282 for (i = 0; i < len; i++)
283 types[i] = G_TYPE_INT;
284
285 model = gtk_list_store_newv(len, types);
286
287 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
288 gtk_widget_set_can_focus(tree_view, FALSE);
289
290 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
291 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
292
293 for (i = 0; i < len; i++) {
294 char fbuf[8];
295
296 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
297 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
298 }
299
300 gtk_list_store_append(model, &iter);
301
Jens Axboee0681f32012-03-06 12:14:42 +0100302 for (i = 0; i < len; i++) {
303 if (scale)
304 ovals[i] = (ovals[i] + 999) / 1000;
Jens Axboea2697902012-03-05 16:43:49 +0100305 gtk_list_store_set(model, &iter, i, ovals[i], -1);
Jens Axboee0681f32012-03-06 12:14:42 +0100306 }
Jens Axboea2697902012-03-05 16:43:49 +0100307
308 return tree_view;
309}
310
311static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
312 int ddir)
313{
314 unsigned int *io_u_plat = ts->io_u_plat[ddir];
315 unsigned long nr = ts->clat_stat[ddir].samples;
316 fio_fp64_t *plist = ts->percentile_list;
317 unsigned int *ovals, len, minv, maxv, scale_down;
318 const char *base;
319 GtkWidget *tree_view, *frame, *hbox;
320 char tmp[64];
321
322 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
323 if (!len)
324 goto out;
325
326 /*
327 * We default to usecs, but if the value range is such that we
328 * should scale down to msecs, do that.
329 */
330 if (minv > 2000 && maxv > 99999) {
331 scale_down = 1;
332 base = "msec";
333 } else {
334 scale_down = 0;
335 base = "usec";
336 }
337
338 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
339
340 sprintf(tmp, "Completion percentiles (%s)", base);
341 frame = gtk_frame_new(tmp);
342 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
343
344 hbox = gtk_hbox_new(FALSE, 3);
345 gtk_container_add(GTK_CONTAINER(frame), hbox);
346
347 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
348out:
349 if (ovals)
350 free(ovals);
351}
352
Jens Axboe3650a3c2012-03-05 14:09:03 +0100353static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
354 unsigned long max, double mean, double dev)
355{
356 const char *base = "(usec)";
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100357 GtkWidget *hbox, *label, *frame;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100358 char *minp, *maxp;
359 char tmp[64];
360
361 if (!usec_to_msec(&min, &max, &mean, &dev))
362 base = "(msec)";
363
364 minp = num2str(min, 6, 1, 0);
365 maxp = num2str(max, 6, 1, 0);
366
Jens Axboe3650a3c2012-03-05 14:09:03 +0100367 sprintf(tmp, "%s %s", name, base);
368 frame = gtk_frame_new(tmp);
369 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
370
Jens Axboe3650a3c2012-03-05 14:09:03 +0100371 hbox = gtk_hbox_new(FALSE, 3);
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100372 gtk_container_add(GTK_CONTAINER(frame), hbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100373
374 label = new_info_label_in_frame(hbox, "Minimum");
375 gtk_label_set_text(GTK_LABEL(label), minp);
376 label = new_info_label_in_frame(hbox, "Maximum");
377 gtk_label_set_text(GTK_LABEL(label), maxp);
378 label = new_info_label_in_frame(hbox, "Average");
379 sprintf(tmp, "%5.02f", mean);
380 gtk_label_set_text(GTK_LABEL(label), tmp);
381 label = new_info_label_in_frame(hbox, "Standard deviation");
382 sprintf(tmp, "%5.02f", dev);
383 gtk_label_set_text(GTK_LABEL(label), tmp);
384
385 free(minp);
386 free(maxp);
387
388}
389
Jens Axboeca850992012-03-05 20:04:43 +0100390#define GFIO_CLAT 1
391#define GFIO_SLAT 2
392#define GFIO_LAT 4
393
Jens Axboe3650a3c2012-03-05 14:09:03 +0100394static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
395 struct thread_stat *ts, int ddir)
396{
397 const char *ddir_label[2] = { "Read", "Write" };
Jens Axboe0b761302012-03-05 20:44:11 +0100398 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
Jens Axboee0681f32012-03-06 12:14:42 +0100399 unsigned long min[3], max[3], runt;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100400 unsigned long long bw, iops;
Jens Axboeca850992012-03-05 20:04:43 +0100401 unsigned int flags = 0;
Jens Axboee0681f32012-03-06 12:14:42 +0100402 double mean[3], dev[3];
Jens Axboe3650a3c2012-03-05 14:09:03 +0100403 char *io_p, *bw_p, *iops_p;
404 int i2p;
405
406 if (!ts->runtime[ddir])
407 return;
408
409 i2p = is_power_of_2(rs->kb_base);
410 runt = ts->runtime[ddir];
411
412 bw = (1000 * ts->io_bytes[ddir]) / runt;
413 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
414 bw_p = num2str(bw, 6, 1, i2p);
415
416 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
417 iops_p = num2str(iops, 6, 1, 0);
418
419 box = gtk_hbox_new(FALSE, 3);
420 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
421
422 frame = gtk_frame_new(ddir_label[ddir]);
423 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
424
Jens Axboe0b761302012-03-05 20:44:11 +0100425 main_vbox = gtk_vbox_new(FALSE, 3);
426 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100427
428 box = gtk_hbox_new(FALSE, 3);
Jens Axboe0b761302012-03-05 20:44:11 +0100429 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100430
431 label = new_info_label_in_frame(box, "IO");
432 gtk_label_set_text(GTK_LABEL(label), io_p);
433 label = new_info_label_in_frame(box, "Bandwidth");
434 gtk_label_set_text(GTK_LABEL(label), bw_p);
435 label = new_info_label_in_frame(box, "IOPS");
436 gtk_label_set_text(GTK_LABEL(label), iops_p);
437 label = new_info_label_in_frame(box, "Runtime (msec)");
438 label_set_int_value(label, ts->runtime[ddir]);
439
Jens Axboee0681f32012-03-06 12:14:42 +0100440 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
Jens Axboeca850992012-03-05 20:04:43 +0100441 double p_of_agg = 100.0;
442 const char *bw_str = "KB";
443 char tmp[32];
444
445 if (rs->agg[ddir]) {
Jens Axboee0681f32012-03-06 12:14:42 +0100446 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
Jens Axboeca850992012-03-05 20:04:43 +0100447 if (p_of_agg > 100.0)
448 p_of_agg = 100.0;
449 }
450
Jens Axboee0681f32012-03-06 12:14:42 +0100451 if (mean[0] > 999999.9) {
452 min[0] /= 1000.0;
453 max[0] /= 1000.0;
454 mean[0] /= 1000.0;
455 dev[0] /= 1000.0;
Jens Axboeca850992012-03-05 20:04:43 +0100456 bw_str = "MB";
457 }
458
Jens Axboe0b761302012-03-05 20:44:11 +0100459 sprintf(tmp, "Bandwidth (%s)", bw_str);
460 frame = gtk_frame_new(tmp);
461 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
Jens Axboeca850992012-03-05 20:04:43 +0100462
Jens Axboe0b761302012-03-05 20:44:11 +0100463 box = gtk_hbox_new(FALSE, 3);
464 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboeca850992012-03-05 20:04:43 +0100465
Jens Axboe0b761302012-03-05 20:44:11 +0100466 label = new_info_label_in_frame(box, "Minimum");
Jens Axboee0681f32012-03-06 12:14:42 +0100467 label_set_int_value(label, min[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100468 label = new_info_label_in_frame(box, "Maximum");
Jens Axboee0681f32012-03-06 12:14:42 +0100469 label_set_int_value(label, max[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100470 label = new_info_label_in_frame(box, "Percentage of jobs");
Jens Axboeca850992012-03-05 20:04:43 +0100471 sprintf(tmp, "%3.2f%%", p_of_agg);
472 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100473 label = new_info_label_in_frame(box, "Average");
Jens Axboee0681f32012-03-06 12:14:42 +0100474 sprintf(tmp, "%5.02f", mean[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100475 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100476 label = new_info_label_in_frame(box, "Standard deviation");
Jens Axboee0681f32012-03-06 12:14:42 +0100477 sprintf(tmp, "%5.02f", dev[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100478 gtk_label_set_text(GTK_LABEL(label), tmp);
479 }
480
Jens Axboee0681f32012-03-06 12:14:42 +0100481 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
Jens Axboe2b089892012-03-06 08:09:17 +0100482 flags |= GFIO_SLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100483 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
Jens Axboe2b089892012-03-06 08:09:17 +0100484 flags |= GFIO_CLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100485 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
Jens Axboe2b089892012-03-06 08:09:17 +0100486 flags |= GFIO_LAT;
487
488 if (flags) {
489 frame = gtk_frame_new("Latency");
490 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
491
492 vbox = gtk_vbox_new(FALSE, 3);
493 gtk_container_add(GTK_CONTAINER(frame), vbox);
494
495 if (flags & GFIO_SLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100496 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
Jens Axboe2b089892012-03-06 08:09:17 +0100497 if (flags & GFIO_CLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100498 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
Jens Axboe2b089892012-03-06 08:09:17 +0100499 if (flags & GFIO_LAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100500 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
Jens Axboe2b089892012-03-06 08:09:17 +0100501 }
502
503 if (ts->clat_percentiles)
504 gfio_show_clat_percentiles(main_vbox, ts, ddir);
505
506
Jens Axboe3650a3c2012-03-05 14:09:03 +0100507 free(io_p);
508 free(bw_p);
509 free(iops_p);
510}
511
Jens Axboee5bd1342012-03-05 21:38:12 +0100512static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
513 const char **labels)
514{
515 GtkWidget *tree_view;
516 GtkTreeSelection *selection;
517 GtkListStore *model;
518 GtkTreeIter iter;
519 GType *types;
520 int i, skipped;
521
522 /*
523 * Check if all are empty, in which case don't bother
524 */
525 for (i = 0, skipped = 0; i < num; i++)
526 if (lat[i] <= 0.0)
527 skipped++;
528
529 if (skipped == num)
530 return NULL;
531
532 types = malloc(num * sizeof(GType));
533
534 for (i = 0; i < num; i++)
535 types[i] = G_TYPE_STRING;
536
537 model = gtk_list_store_newv(num, types);
538 free(types);
539 types = NULL;
540
541 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
542 gtk_widget_set_can_focus(tree_view, FALSE);
543
544 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
545 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
546
547 for (i = 0; i < num; i++)
548 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
549
550 gtk_list_store_append(model, &iter);
551
552 for (i = 0; i < num; i++) {
553 char fbuf[32];
554
555 if (lat[i] <= 0.0)
556 sprintf(fbuf, "0.00");
557 else
558 sprintf(fbuf, "%3.2f%%", lat[i]);
559
560 gtk_list_store_set(model, &iter, i, fbuf, -1);
561 }
562
563 return tree_view;
564}
565
566static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
567{
568 GtkWidget *box, *frame, *tree_view;
569 double io_u_lat_u[FIO_IO_U_LAT_U_NR];
570 double io_u_lat_m[FIO_IO_U_LAT_M_NR];
571 const char *uranges[] = { "2", "4", "10", "20", "50", "100",
572 "250", "500", "750", "1000", };
573 const char *mranges[] = { "2", "4", "10", "20", "50", "100",
574 "250", "500", "750", "1000", "2000",
575 ">= 2000", };
576
577 stat_calc_lat_u(ts, io_u_lat_u);
578 stat_calc_lat_m(ts, io_u_lat_m);
579
580 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
581 if (tree_view) {
582 frame = gtk_frame_new("Latency buckets (usec)");
583 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
584
585 box = gtk_hbox_new(FALSE, 3);
586 gtk_container_add(GTK_CONTAINER(frame), box);
587 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
588 }
589
590 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
591 if (tree_view) {
592 frame = gtk_frame_new("Latency buckets (msec)");
593 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
594
595 box = gtk_hbox_new(FALSE, 3);
596 gtk_container_add(GTK_CONTAINER(frame), box);
597 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
598 }
599}
600
Jens Axboe2e331012012-03-05 22:07:54 +0100601static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
602{
603 GtkWidget *box, *frame, *entry;
604 double usr_cpu, sys_cpu;
605 unsigned long runtime;
606 char tmp[32];
607
608 runtime = ts->total_run_time;
609 if (runtime) {
610 double runt = (double) runtime;
611
612 usr_cpu = (double) ts->usr_time * 100 / runt;
613 sys_cpu = (double) ts->sys_time * 100 / runt;
614 } else {
615 usr_cpu = 0;
616 sys_cpu = 0;
617 }
618
619 frame = gtk_frame_new("OS resources");
620 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
621
622 box = gtk_hbox_new(FALSE, 3);
623 gtk_container_add(GTK_CONTAINER(frame), box);
624
625 entry = new_info_entry_in_frame(box, "User CPU");
626 sprintf(tmp, "%3.2f%%", usr_cpu);
627 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
628 entry = new_info_entry_in_frame(box, "System CPU");
629 sprintf(tmp, "%3.2f%%", sys_cpu);
630 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
631 entry = new_info_entry_in_frame(box, "Context switches");
632 entry_set_int_value(entry, ts->ctx);
633 entry = new_info_entry_in_frame(box, "Major faults");
634 entry_set_int_value(entry, ts->majf);
635 entry = new_info_entry_in_frame(box, "Minor faults");
636 entry_set_int_value(entry, ts->minf);
637}
Jens Axboe19998db2012-03-06 09:17:59 +0100638static void gfio_add_sc_depths_tree(GtkListStore *model,
639 struct thread_stat *ts, unsigned int len,
640 int submit)
641{
642 double io_u_dist[FIO_IO_U_MAP_NR];
643 GtkTreeIter iter;
644 /* Bits 0, and 3-8 */
645 const int add_mask = 0x1f9;
646 int i, j;
647
648 if (submit)
649 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
650 else
651 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
652
653 gtk_list_store_append(model, &iter);
654
655 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
656
657 for (i = 1, j = 0; i < len; i++) {
658 char fbuf[32];
659
660 if (!(add_mask & (1UL << (i - 1))))
661 sprintf(fbuf, "0.0%%");
662 else {
663 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
664 j++;
665 }
666
667 gtk_list_store_set(model, &iter, i, fbuf, -1);
668 }
669
670}
671
672static void gfio_add_total_depths_tree(GtkListStore *model,
673 struct thread_stat *ts, unsigned int len)
674{
675 double io_u_dist[FIO_IO_U_MAP_NR];
676 GtkTreeIter iter;
677 /* Bits 1-6, and 8 */
678 const int add_mask = 0x17e;
679 int i, j;
680
681 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
682
683 gtk_list_store_append(model, &iter);
684
685 gtk_list_store_set(model, &iter, 0, "Total", -1);
686
687 for (i = 1, j = 0; i < len; i++) {
688 char fbuf[32];
689
690 if (!(add_mask & (1UL << (i - 1))))
691 sprintf(fbuf, "0.0%%");
692 else {
693 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
694 j++;
695 }
696
697 gtk_list_store_set(model, &iter, i, fbuf, -1);
698 }
699
700}
Jens Axboe2e331012012-03-05 22:07:54 +0100701
702static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
703{
Jens Axboe2e331012012-03-05 22:07:54 +0100704 GtkWidget *frame, *box, *tree_view;
705 GtkTreeSelection *selection;
706 GtkListStore *model;
Jens Axboe2e331012012-03-05 22:07:54 +0100707 GType types[FIO_IO_U_MAP_NR + 1];
708 int i;
Jens Axboe19998db2012-03-06 09:17:59 +0100709#define NR_LABELS 10
710 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
Jens Axboe2e331012012-03-05 22:07:54 +0100711
712 frame = gtk_frame_new("IO depths");
713 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
714
715 box = gtk_hbox_new(FALSE, 3);
716 gtk_container_add(GTK_CONTAINER(frame), box);
717
Jens Axboe19998db2012-03-06 09:17:59 +0100718 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100719 types[i] = G_TYPE_STRING;
720
Jens Axboe19998db2012-03-06 09:17:59 +0100721 model = gtk_list_store_newv(NR_LABELS, types);
Jens Axboe2e331012012-03-05 22:07:54 +0100722
723 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
724 gtk_widget_set_can_focus(tree_view, FALSE);
725
726 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
727 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
728
Jens Axboe19998db2012-03-06 09:17:59 +0100729 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100730 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
731
Jens Axboe19998db2012-03-06 09:17:59 +0100732 gfio_add_total_depths_tree(model, ts, NR_LABELS);
733 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 1);
734 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 0);
Jens Axboe2e331012012-03-05 22:07:54 +0100735
736 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
737}
738
Jens Axboef9d40b42012-03-06 09:52:49 +0100739static gboolean results_window_delete(GtkWidget *w, gpointer data)
740{
741 struct gui *ui = (struct gui *) data;
742
743 gtk_widget_destroy(w);
744 ui->results_window = NULL;
745 ui->results_notebook = NULL;
746 return TRUE;
747}
748
749static GtkWidget *get_results_window(struct gui *ui)
750{
751 GtkWidget *win, *notebook;
752
753 if (ui->results_window)
754 return ui->results_notebook;
755
756 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
757 gtk_window_set_title(GTK_WINDOW(win), "Results");
758 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ui);
759 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ui);
760
761 notebook = gtk_notebook_new();
762 gtk_container_add(GTK_CONTAINER(win), notebook);
763
764 ui->results_window = win;
765 ui->results_notebook = notebook;
766 return ui->results_notebook;
767}
768
Jens Axboe3650a3c2012-03-05 14:09:03 +0100769static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
770 struct group_run_stats *rs)
771{
Jens Axboef9d40b42012-03-06 09:52:49 +0100772 GtkWidget *res_win, *box, *vbox, *entry;
Jens Axboee0681f32012-03-06 12:14:42 +0100773 struct gfio_client *gc = client->client_data;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100774
775 gdk_threads_enter();
776
Jens Axboee0681f32012-03-06 12:14:42 +0100777 res_win = get_results_window(gc->ui);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100778
779 vbox = gtk_vbox_new(FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100780
781 box = gtk_hbox_new(TRUE, 3);
782 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
783
Jens Axboef9d40b42012-03-06 09:52:49 +0100784 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), vbox, gtk_label_new(ts->name));
785
Jens Axboee0681f32012-03-06 12:14:42 +0100786 gc->results_widget = vbox;
787
Jens Axboe3650a3c2012-03-05 14:09:03 +0100788 entry = new_info_entry_in_frame(box, "Name");
789 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
790 if (strlen(ts->description)) {
791 entry = new_info_entry_in_frame(box, "Description");
792 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
793 }
794 entry = new_info_entry_in_frame(box, "Group ID");
795 entry_set_int_value(entry, ts->groupid);
796 entry = new_info_entry_in_frame(box, "Jobs");
797 entry_set_int_value(entry, ts->members);
798 entry = new_info_entry_in_frame(box, "Error");
799 entry_set_int_value(entry, ts->error);
800 entry = new_info_entry_in_frame(box, "PID");
801 entry_set_int_value(entry, ts->pid);
802
803 if (ts->io_bytes[DDIR_READ])
804 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
805 if (ts->io_bytes[DDIR_WRITE])
806 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
807
Jens Axboee5bd1342012-03-05 21:38:12 +0100808 gfio_show_latency_buckets(vbox, ts);
Jens Axboe2e331012012-03-05 22:07:54 +0100809 gfio_show_cpu_usage(vbox, ts);
810 gfio_show_io_depths(vbox, ts);
Jens Axboee5bd1342012-03-05 21:38:12 +0100811
Jens Axboee0681f32012-03-06 12:14:42 +0100812 gtk_widget_show_all(gc->ui->results_window);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100813 gdk_threads_leave();
814}
815
Jens Axboe084d1c62012-03-03 20:28:07 +0100816static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100817{
Jens Axboe9b260bd2012-03-06 11:02:52 +0100818 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +0100819 struct gfio_client *gc = client->client_data;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100820 GtkTreeIter iter;
821 struct tm *tm;
822 time_t sec;
823 char tmp[64], timebuf[80];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100824
Jens Axboe9b260bd2012-03-06 11:02:52 +0100825 sec = p->log_sec;
826 tm = localtime(&sec);
827 strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", tm);
828 sprintf(timebuf, "%s.%03ld", tmp, p->log_usec / 1000);
829
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100830 gdk_threads_enter();
Jens Axboe9b260bd2012-03-06 11:02:52 +0100831
Jens Axboee0681f32012-03-06 12:14:42 +0100832 gtk_list_store_append(gc->ui->log_model, &iter);
833 gtk_list_store_set(gc->ui->log_model, &iter, 0, timebuf, -1);
834 gtk_list_store_set(gc->ui->log_model, &iter, 1, client->hostname, -1);
835 gtk_list_store_set(gc->ui->log_model, &iter, 2, p->level, -1);
836 gtk_list_store_set(gc->ui->log_model, &iter, 3, p->buf, -1);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100837
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100838 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100839}
840
841static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
842{
Jens Axboee0681f32012-03-06 12:14:42 +0100843 struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
844 struct gfio_client *gc = client->client_data;
845 GtkWidget *box, *frame, *entry, *vbox;
846
Jens Axboe0050e5f2012-03-06 09:23:27 +0100847 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +0100848
849 if (!gc->results_widget) {
850 printf("no results!\n");
851 goto out;
852 }
853
854 if (!gc->disk_util_frame) {
855 gc->disk_util_frame = gtk_frame_new("Disk utilization");
856 gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
857 }
858
859 vbox = gtk_vbox_new(FALSE, 3);
860 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
861
862 frame = gtk_frame_new((char *) p->dus.name);
863 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
864
865 box = gtk_vbox_new(FALSE, 3);
866 gtk_container_add(GTK_CONTAINER(frame), box);
867
868 frame = gtk_frame_new("Read");
869 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
870 vbox = gtk_hbox_new(TRUE, 3);
871 gtk_container_add(GTK_CONTAINER(frame), vbox);
872 entry = new_info_entry_in_frame(vbox, "IOs");
873 entry_set_int_value(entry, p->dus.ios[0]);
874 entry = new_info_entry_in_frame(vbox, "Merges");
875 entry_set_int_value(entry, p->dus.merges[0]);
876 entry = new_info_entry_in_frame(vbox, "Sectors");
877 entry_set_int_value(entry, p->dus.sectors[0]);
878 entry = new_info_entry_in_frame(vbox, "Ticks");
879 entry_set_int_value(entry, p->dus.ticks[0]);
880
881 frame = gtk_frame_new("Write");
882 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
883 vbox = gtk_hbox_new(TRUE, 3);
884 gtk_container_add(GTK_CONTAINER(frame), vbox);
885 entry = new_info_entry_in_frame(vbox, "IOs");
886 entry_set_int_value(entry, p->dus.ios[1]);
887 entry = new_info_entry_in_frame(vbox, "Merges");
888 entry_set_int_value(entry, p->dus.merges[1]);
889 entry = new_info_entry_in_frame(vbox, "Sectors");
890 entry_set_int_value(entry, p->dus.sectors[1]);
891 entry = new_info_entry_in_frame(vbox, "Ticks");
892 entry_set_int_value(entry, p->dus.ticks[1]);
893
894 frame = gtk_frame_new("Shared");
895 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
896 vbox = gtk_hbox_new(TRUE, 3);
897 gtk_container_add(GTK_CONTAINER(frame), vbox);
898 entry = new_info_entry_in_frame(vbox, "IO ticks");
899 entry_set_int_value(entry, p->dus.io_ticks);
900 entry = new_info_entry_in_frame(vbox, "Time in queue");
901 entry_set_int_value(entry, p->dus.time_in_queue);
902
903 gtk_widget_show_all(gc->results_widget);
904out:
Jens Axboe0050e5f2012-03-06 09:23:27 +0100905 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100906}
907
Jens Axboe3650a3c2012-03-05 14:09:03 +0100908extern int sum_stat_clients;
909extern struct thread_stat client_ts;
910extern struct group_run_stats client_gs;
911
912static int sum_stat_nr;
913
Jens Axboe89e5fad2012-03-05 09:21:12 +0100914static void gfio_thread_status_op(struct fio_client *client,
915 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100916{
Jens Axboe3650a3c2012-03-05 14:09:03 +0100917 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
918
919 gfio_display_ts(client, &p->ts, &p->rs);
920
921 if (sum_stat_clients == 1)
922 return;
923
924 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
925 sum_group_stats(&client_gs, &p->rs);
926
927 client_ts.members++;
928 client_ts.groupid = p->ts.groupid;
929
930 if (++sum_stat_nr == sum_stat_clients) {
931 strcpy(client_ts.name, "All clients");
932 gfio_display_ts(client, &client_ts, &client_gs);
933 }
Stephen M. Camerona1820202012-02-24 08:17:31 +0100934}
935
Jens Axboe89e5fad2012-03-05 09:21:12 +0100936static void gfio_group_stats_op(struct fio_client *client,
937 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100938{
Jens Axboe0050e5f2012-03-06 09:23:27 +0100939 gdk_threads_enter();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100940 printf("gfio_group_stats_op called\n");
Jens Axboe89e5fad2012-03-05 09:21:12 +0100941 fio_client_ops.group_stats(client, cmd);
Jens Axboe0050e5f2012-03-06 09:23:27 +0100942 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100943}
944
Jens Axboe3e47bd22012-02-29 13:45:02 +0100945static void gfio_update_eta(struct jobs_eta *je)
946{
947 static int eta_good;
948 char eta_str[128];
949 char output[256];
950 char tmp[32];
951 double perc = 0.0;
952 int i2p = 0;
953
Jens Axboe0050e5f2012-03-06 09:23:27 +0100954 gdk_threads_enter();
955
Jens Axboe3e47bd22012-02-29 13:45:02 +0100956 eta_str[0] = '\0';
957 output[0] = '\0';
958
959 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
960 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
961 eta_to_str(eta_str, je->eta_sec);
962 }
963
964 sprintf(tmp, "%u", je->nr_running);
Jens Axboeca850992012-03-05 20:04:43 +0100965 gtk_entry_set_text(GTK_ENTRY(ui.eta.jobs), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +0100966 sprintf(tmp, "%u", je->files_open);
Jens Axboeca850992012-03-05 20:04:43 +0100967 gtk_entry_set_text(GTK_ENTRY(ui.eta.files), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +0100968
969#if 0
970 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
971 if (je->m_rate || je->t_rate) {
972 char *tr, *mr;
973
974 mr = num2str(je->m_rate, 4, 0, i2p);
975 tr = num2str(je->t_rate, 4, 0, i2p);
Jens Axboeca850992012-03-05 20:04:43 +0100976 gtk_entry_set_text(GTK_ENTRY(ui.eta);
Jens Axboe3e47bd22012-02-29 13:45:02 +0100977 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
978 free(tr);
979 free(mr);
980 } else if (je->m_iops || je->t_iops)
981 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
Jens Axboeebbd89c2012-03-02 11:21:13 +0100982
Jens Axboeca850992012-03-05 20:04:43 +0100983 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_bw), "---");
984 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_iops), "---");
985 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_bw), "---");
986 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_iops), "---");
Jens Axboe3e47bd22012-02-29 13:45:02 +0100987#endif
988
989 if (je->eta_sec != INT_MAX && je->nr_running) {
990 char *iops_str[2];
991 char *rate_str[2];
992
993 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
994 strcpy(output, "-.-% done");
995 else {
996 eta_good = 1;
997 perc *= 100.0;
998 sprintf(output, "%3.1f%% done", perc);
999 }
1000
1001 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1002 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1003
1004 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1005 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1006
Jens Axboeca850992012-03-05 20:04:43 +01001007 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_bw), rate_str[0]);
1008 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_iops), iops_str[0]);
1009 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_bw), rate_str[1]);
1010 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_iops), iops_str[1]);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001011
1012 free(rate_str[0]);
1013 free(rate_str[1]);
1014 free(iops_str[0]);
1015 free(iops_str[1]);
1016 }
1017
1018 if (eta_str[0]) {
1019 char *dst = output + strlen(output);
1020
1021 sprintf(dst, " - %s", eta_str);
1022 }
1023
1024 gfio_update_thread_status(output, perc);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001025 gdk_threads_leave();
Jens Axboe3e47bd22012-02-29 13:45:02 +01001026}
1027
Stephen M. Camerona1820202012-02-24 08:17:31 +01001028static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1029{
Jens Axboe843ad232012-02-29 11:44:53 +01001030 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
1031 const char *os, *arch;
1032 char buf[64];
1033
1034 os = fio_get_os_string(probe->os);
1035 if (!os)
1036 os = "unknown";
1037
1038 arch = fio_get_arch_string(probe->arch);
1039 if (!arch)
1040 os = "unknown";
1041
1042 if (!client->name)
1043 client->name = strdup((char *) probe->hostname);
1044
Jens Axboe0050e5f2012-03-06 09:23:27 +01001045 gdk_threads_enter();
1046
Jens Axboe843ad232012-02-29 11:44:53 +01001047 gtk_label_set_text(GTK_LABEL(ui.probe.hostname), (char *) probe->hostname);
1048 gtk_label_set_text(GTK_LABEL(ui.probe.os), os);
1049 gtk_label_set_text(GTK_LABEL(ui.probe.arch), arch);
1050 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
1051 gtk_label_set_text(GTK_LABEL(ui.probe.fio_ver), buf);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001052
1053 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001054}
1055
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001056static void gfio_update_thread_status(char *status_message, double perc)
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001057{
1058 static char message[100];
1059 const char *m = message;
1060
1061 strncpy(message, status_message, sizeof(message) - 1);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001062 gtk_progress_bar_set_text(
1063 GTK_PROGRESS_BAR(ui.thread_status_pb), m);
1064 gtk_progress_bar_set_fraction(
1065 GTK_PROGRESS_BAR(ui.thread_status_pb), perc / 100.0);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001066 gtk_widget_queue_draw(ui.window);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001067}
1068
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001069static void gfio_quit_op(struct fio_client *client)
1070{
Jens Axboee0681f32012-03-06 12:14:42 +01001071 struct gfio_client *gc = client->client_data;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001072
Jens Axboe0050e5f2012-03-06 09:23:27 +01001073 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +01001074 gfio_set_connected(gc->ui, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001075 gdk_threads_leave();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001076}
1077
Jens Axboe807f9972012-03-02 10:25:24 +01001078static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1079{
1080 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +01001081 struct gfio_client *gc = client->client_data;
1082 struct gui *ui = gc->ui;
Jens Axboe807f9972012-03-02 10:25:24 +01001083 char tmp[8];
1084 int i;
1085
1086 p->iodepth = le32_to_cpu(p->iodepth);
1087 p->rw = le32_to_cpu(p->rw);
1088
1089 for (i = 0; i < 2; i++) {
1090 p->min_bs[i] = le32_to_cpu(p->min_bs[i]);
1091 p->max_bs[i] = le32_to_cpu(p->max_bs[i]);
1092 }
1093
1094 p->numjobs = le32_to_cpu(p->numjobs);
1095 p->group_reporting = le32_to_cpu(p->group_reporting);
1096
Jens Axboe0050e5f2012-03-06 09:23:27 +01001097 gdk_threads_enter();
1098
Jens Axboeca850992012-03-05 20:04:43 +01001099 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), (gchar *) p->jobname);
1100 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), ddir_str(p->rw));
1101 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), (gchar *) p->ioengine);
Jens Axboe807f9972012-03-02 10:25:24 +01001102
1103 sprintf(tmp, "%u", p->iodepth);
Jens Axboeca850992012-03-05 20:04:43 +01001104 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), tmp);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001105
1106 gdk_threads_leave();
Jens Axboe807f9972012-03-02 10:25:24 +01001107}
1108
Jens Axboeed727a42012-03-02 12:14:40 +01001109static void gfio_client_timed_out(struct fio_client *client)
1110{
Jens Axboee0681f32012-03-06 12:14:42 +01001111 struct gfio_client *gc = client->client_data;
Jens Axboeed727a42012-03-02 12:14:40 +01001112 GtkWidget *dialog, *label, *content;
1113 char buf[256];
1114
1115 gdk_threads_enter();
1116
Jens Axboee0681f32012-03-06 12:14:42 +01001117 gfio_set_connected(gc->ui, 0);
1118 clear_ui_info(gc->ui);
Jens Axboeed727a42012-03-02 12:14:40 +01001119
1120 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
1121
1122 dialog = gtk_dialog_new_with_buttons("Timed out!",
Jens Axboee0681f32012-03-06 12:14:42 +01001123 GTK_WINDOW(gc->ui->window),
Jens Axboeed727a42012-03-02 12:14:40 +01001124 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1125 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1126
1127 content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1128 label = gtk_label_new((const gchar *) buf);
1129 gtk_container_add(GTK_CONTAINER(content), label);
1130 gtk_widget_show_all(dialog);
1131 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1132
1133 gtk_dialog_run(GTK_DIALOG(dialog));
1134 gtk_widget_destroy(dialog);
1135
1136 gdk_threads_leave();
1137}
1138
Stephen M. Camerona1820202012-02-24 08:17:31 +01001139struct client_ops gfio_client_ops = {
Jens Axboe0420ba62012-02-29 11:16:52 +01001140 .text_op = gfio_text_op,
1141 .disk_util = gfio_disk_util_op,
1142 .thread_status = gfio_thread_status_op,
1143 .group_stats = gfio_group_stats_op,
Jens Axboea5276612012-03-04 15:15:08 +01001144 .eta = gfio_update_eta,
Jens Axboe0420ba62012-02-29 11:16:52 +01001145 .probe = gfio_probe_op,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001146 .quit = gfio_quit_op,
Jens Axboe807f9972012-03-02 10:25:24 +01001147 .add_job = gfio_add_job_op,
Jens Axboeed727a42012-03-02 12:14:40 +01001148 .timed_out = gfio_client_timed_out,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001149 .stay_connected = 1,
Stephen M. Camerona1820202012-02-24 08:17:31 +01001150};
1151
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001152static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1153 __attribute__((unused)) gpointer data)
1154{
1155 gtk_main_quit();
1156}
1157
Stephen M. Cameron25927252012-02-24 08:17:31 +01001158static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001159{
Stephen M. Cameron25927252012-02-24 08:17:31 +01001160 fio_handle_clients(&gfio_client_ops);
Stephen M. Cameron25927252012-02-24 08:17:31 +01001161 return NULL;
1162}
1163
Jens Axboe0420ba62012-02-29 11:16:52 +01001164static int send_job_files(struct gui *ui)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001165{
Jens Axboe441013b2012-03-01 08:01:52 +01001166 int i, ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001167
Jens Axboe0420ba62012-02-29 11:16:52 +01001168 for (i = 0; i < ui->nr_job_files; i++) {
1169 ret = fio_clients_send_ini(ui->job_files[i]);
Jens Axboe441013b2012-03-01 08:01:52 +01001170 if (ret)
1171 break;
1172
Jens Axboe0420ba62012-02-29 11:16:52 +01001173 free(ui->job_files[i]);
1174 ui->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001175 }
1176 while (i < ui->nr_job_files) {
1177 free(ui->job_files[i]);
1178 ui->job_files[i] = NULL;
1179 i++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001180 }
1181
Jens Axboe441013b2012-03-01 08:01:52 +01001182 return ret;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001183}
1184
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001185static void start_job_thread(struct gui *ui)
Stephen M. Cameron25927252012-02-24 08:17:31 +01001186{
Jens Axboe0420ba62012-02-29 11:16:52 +01001187 if (send_job_files(ui)) {
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001188 printf("Yeah, I didn't really like those options too much.\n");
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001189 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
1190 return;
1191 }
Stephen M. Cameron25927252012-02-24 08:17:31 +01001192}
1193
1194static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1195 gpointer data)
1196{
1197 struct gui *ui = data;
1198
Stephen M. Cameron25927252012-02-24 08:17:31 +01001199 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001200 start_job_thread(ui);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001201}
1202
Jens Axboedf06f222012-03-02 13:32:04 +01001203static void file_open(GtkWidget *w, gpointer data);
1204
1205static void connect_clicked(GtkWidget *widget, gpointer data)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001206{
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001207 struct gui *ui = data;
1208
1209 if (!ui->connected) {
Jens Axboedf06f222012-03-02 13:32:04 +01001210 if (!ui->nr_job_files)
1211 file_open(widget, data);
Jens Axboe8663ea62012-03-02 14:04:30 +01001212 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001213 fio_clients_connect();
1214 pthread_create(&ui->t, NULL, job_thread, NULL);
1215 gfio_set_connected(ui, 1);
Jens Axboedf06f222012-03-02 13:32:04 +01001216 } else {
1217 fio_clients_terminate();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001218 gfio_set_connected(ui, 0);
Jens Axboe88432652012-03-02 19:09:31 +01001219 clear_ui_info(ui);
Jens Axboedf06f222012-03-02 13:32:04 +01001220 }
Jens Axboe3e47bd22012-02-29 13:45:02 +01001221}
1222
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001223static void add_button(struct gui *ui, int i, GtkWidget *buttonbox,
1224 struct button_spec *buttonspec)
1225{
1226 ui->button[i] = gtk_button_new_with_label(buttonspec->buttontext);
1227 g_signal_connect(ui->button[i], "clicked", G_CALLBACK (buttonspec->f), ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001228 gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], FALSE, FALSE, 3);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001229 gtk_widget_set_tooltip_text(ui->button[i], buttonspeclist[i].tooltiptext);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001230 gtk_widget_set_sensitive(ui->button[i], !buttonspec->start_insensitive);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001231}
1232
1233static void add_buttons(struct gui *ui,
1234 struct button_spec *buttonlist,
1235 int nbuttons)
1236{
1237 int i;
1238
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001239 for (i = 0; i < nbuttons; i++)
1240 add_button(ui, i, ui->buttonbox, &buttonlist[i]);
1241}
1242
Jens Axboe0420ba62012-02-29 11:16:52 +01001243static void on_info_bar_response(GtkWidget *widget, gint response,
1244 gpointer data)
1245{
1246 if (response == GTK_RESPONSE_OK) {
1247 gtk_widget_destroy(widget);
1248 ui.error_info_bar = NULL;
1249 }
1250}
1251
Jens Axboedf06f222012-03-02 13:32:04 +01001252void report_error(GError *error)
Jens Axboe0420ba62012-02-29 11:16:52 +01001253{
1254 if (ui.error_info_bar == NULL) {
1255 ui.error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
1256 GTK_RESPONSE_OK,
1257 NULL);
1258 g_signal_connect(ui.error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1259 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui.error_info_bar),
1260 GTK_MESSAGE_ERROR);
1261
1262 ui.error_label = gtk_label_new(error->message);
1263 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui.error_info_bar));
1264 gtk_container_add(GTK_CONTAINER(container), ui.error_label);
1265
1266 gtk_box_pack_start(GTK_BOX(ui.vbox), ui.error_info_bar, FALSE, FALSE, 0);
1267 gtk_widget_show_all(ui.vbox);
1268 } else {
1269 char buffer[256];
1270 snprintf(buffer, sizeof(buffer), "Failed to open file.");
1271 gtk_label_set(GTK_LABEL(ui.error_label), buffer);
1272 }
1273}
1274
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001275static int get_connection_details(char **host, int *port, int *type,
1276 int *server_start)
Jens Axboea7a42ce2012-03-02 13:12:04 +01001277{
1278 GtkWidget *dialog, *box, *vbox, *hentry, *hbox, *frame, *pentry, *combo;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001279 GtkWidget *button;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001280 char *typeentry;
1281
1282 dialog = gtk_dialog_new_with_buttons("Connection details",
1283 GTK_WINDOW(ui.window),
1284 GTK_DIALOG_DESTROY_WITH_PARENT,
1285 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1286 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1287
1288 frame = gtk_frame_new("Hostname / socket name");
1289 vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1290 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1291
1292 box = gtk_vbox_new(FALSE, 6);
1293 gtk_container_add(GTK_CONTAINER(frame), box);
1294
1295 hbox = gtk_hbox_new(TRUE, 10);
1296 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1297 hentry = gtk_entry_new();
1298 gtk_entry_set_text(GTK_ENTRY(hentry), "localhost");
1299 gtk_box_pack_start(GTK_BOX(hbox), hentry, TRUE, TRUE, 0);
1300
1301 frame = gtk_frame_new("Port");
1302 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1303 box = gtk_vbox_new(FALSE, 10);
1304 gtk_container_add(GTK_CONTAINER(frame), box);
1305
1306 hbox = gtk_hbox_new(TRUE, 4);
1307 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1308 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1309
1310 frame = gtk_frame_new("Type");
1311 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1312 box = gtk_vbox_new(FALSE, 10);
1313 gtk_container_add(GTK_CONTAINER(frame), box);
1314
1315 hbox = gtk_hbox_new(TRUE, 4);
1316 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1317
1318 combo = gtk_combo_box_text_new();
1319 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "IPv4");
1320 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "IPv6");
1321 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "local socket");
1322 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
1323
1324 gtk_container_add(GTK_CONTAINER(hbox), combo);
1325
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001326 frame = gtk_frame_new("Options");
1327 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1328 box = gtk_vbox_new(FALSE, 10);
1329 gtk_container_add(GTK_CONTAINER(frame), box);
1330
1331 hbox = gtk_hbox_new(TRUE, 4);
1332 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1333
1334 button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1335 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), 1);
1336 gtk_widget_set_tooltip_text(button, "When running fio locally, it is necessary to have the backend running on the same system. If this is checked, gfio will start the backend automatically for you if it isn't already running.");
1337 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 6);
1338
Jens Axboea7a42ce2012-03-02 13:12:04 +01001339 gtk_widget_show_all(dialog);
1340
1341 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1342 gtk_widget_destroy(dialog);
1343 return 1;
1344 }
1345
1346 *host = strdup(gtk_entry_get_text(GTK_ENTRY(hentry)));
1347 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1348
1349 typeentry = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
1350 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1351 *type = Fio_client_ipv4;
1352 else if (!strncmp(typeentry, "IPv6", 4))
1353 *type = Fio_client_ipv6;
1354 else
1355 *type = Fio_client_socket;
1356 g_free(typeentry);
1357
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001358 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
1359
Jens Axboea7a42ce2012-03-02 13:12:04 +01001360 gtk_widget_destroy(dialog);
1361 return 0;
1362}
1363
Jens Axboee0681f32012-03-06 12:14:42 +01001364static void gfio_client_added(struct gui *ui, struct fio_client *client)
1365{
1366 struct gfio_client *gc;
1367
1368 gc = malloc(sizeof(*gc));
1369 memset(gc, 0, sizeof(*gc));
1370 gc->ui = ui;
1371
1372 client->client_data = gc;
1373}
1374
Jens Axboe0420ba62012-02-29 11:16:52 +01001375static void file_open(GtkWidget *w, gpointer data)
1376{
1377 GtkWidget *dialog;
1378 GSList *filenames, *fn_glist;
1379 GtkFileFilter *filter;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001380 char *host;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001381 int port, type, server_start;
Jens Axboe0420ba62012-02-29 11:16:52 +01001382
1383 dialog = gtk_file_chooser_dialog_new("Open File",
1384 GTK_WINDOW(ui.window),
1385 GTK_FILE_CHOOSER_ACTION_OPEN,
1386 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1387 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1388 NULL);
1389 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1390
1391 filter = gtk_file_filter_new();
1392 gtk_file_filter_add_pattern(filter, "*.fio");
1393 gtk_file_filter_add_pattern(filter, "*.job");
1394 gtk_file_filter_add_mime_type(filter, "text/fio");
1395 gtk_file_filter_set_name(filter, "Fio job file");
1396 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
1397
1398 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1399 gtk_widget_destroy(dialog);
1400 return;
1401 }
1402
1403 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001404
1405 gtk_widget_destroy(dialog);
1406
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001407 if (get_connection_details(&host, &port, &type, &server_start))
Jens Axboea7a42ce2012-03-02 13:12:04 +01001408 goto err;
1409
Jens Axboe0420ba62012-02-29 11:16:52 +01001410 filenames = fn_glist;
1411 while (filenames != NULL) {
Jens Axboee0681f32012-03-06 12:14:42 +01001412 struct fio_client *client;
1413
Jens Axboe0420ba62012-02-29 11:16:52 +01001414 ui.job_files = realloc(ui.job_files, (ui.nr_job_files + 1) * sizeof(char *));
1415 ui.job_files[ui.nr_job_files] = strdup(filenames->data);
1416 ui.nr_job_files++;
1417
Jens Axboee0681f32012-03-06 12:14:42 +01001418 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
1419 if (!client) {
Jens Axboedf06f222012-03-02 13:32:04 +01001420 GError *error;
1421
1422 error = g_error_new(g_quark_from_string("fio"), 1,
1423 "Failed to add client %s", host);
Jens Axboe0420ba62012-02-29 11:16:52 +01001424 report_error(error);
1425 g_error_free(error);
Jens Axboe0420ba62012-02-29 11:16:52 +01001426 }
Jens Axboee0681f32012-03-06 12:14:42 +01001427 gfio_client_added(&ui, client);
Jens Axboe0420ba62012-02-29 11:16:52 +01001428
1429 g_free(filenames->data);
1430 filenames = g_slist_next(filenames);
1431 }
Jens Axboea7a42ce2012-03-02 13:12:04 +01001432 free(host);
1433err:
Jens Axboe0420ba62012-02-29 11:16:52 +01001434 g_slist_free(fn_glist);
Jens Axboe0420ba62012-02-29 11:16:52 +01001435}
1436
1437static void file_save(GtkWidget *w, gpointer data)
1438{
1439 GtkWidget *dialog;
1440
1441 dialog = gtk_file_chooser_dialog_new("Save File",
1442 GTK_WINDOW(ui.window),
1443 GTK_FILE_CHOOSER_ACTION_SAVE,
1444 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1445 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1446 NULL);
1447
1448 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1449 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
1450
1451 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1452 char *filename;
1453
1454 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1455 // save_job_file(filename);
1456 g_free(filename);
1457 }
1458 gtk_widget_destroy(dialog);
1459}
1460
Jens Axboe9b260bd2012-03-06 11:02:52 +01001461static void view_log_destroy(GtkWidget *w, gpointer data)
1462{
1463 struct gui *ui = (struct gui *) data;
1464
1465 gtk_widget_ref(ui->log_tree);
1466 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
1467 gtk_widget_destroy(w);
1468}
1469
1470static void view_log(GtkWidget *w, gpointer data)
1471{
1472 GtkWidget *win, *box;
1473
1474 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1475 gtk_window_set_title(GTK_WINDOW(win), "Log");
1476
1477 box = gtk_hbox_new(FALSE, 3);
1478 gtk_container_add(GTK_CONTAINER(win), box);
1479
1480 g_signal_connect(box, "delete-event", G_CALLBACK(view_log_destroy), (gpointer) &ui);
1481 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), (gpointer) &ui);
1482 gtk_container_add(GTK_CONTAINER(box), ui.log_tree);
1483 gtk_widget_show_all(win);
1484}
1485
Jens Axboe46974a72012-03-02 19:34:13 +01001486static void preferences(GtkWidget *w, gpointer data)
1487{
1488 GtkWidget *dialog, *frame, *box, **buttons;
1489 int i;
1490
1491 dialog = gtk_dialog_new_with_buttons("Preferences",
1492 GTK_WINDOW(ui.window),
1493 GTK_DIALOG_DESTROY_WITH_PARENT,
1494 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1495 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1496 NULL);
1497
Jens Axboe0b8d11e2012-03-02 19:44:15 +01001498 frame = gtk_frame_new("Debug logging");
Jens Axboe46974a72012-03-02 19:34:13 +01001499 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1500 box = gtk_hbox_new(FALSE, 6);
1501 gtk_container_add(GTK_CONTAINER(frame), box);
1502
1503 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
1504
1505 for (i = 0; i < FD_DEBUG_MAX; i++) {
1506 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
Jens Axboe0b8d11e2012-03-02 19:44:15 +01001507 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
Jens Axboe46974a72012-03-02 19:34:13 +01001508 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
1509 }
1510
1511 gtk_widget_show_all(dialog);
1512
1513 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1514 gtk_widget_destroy(dialog);
1515 return;
1516 }
1517
1518 for (i = 0; i < FD_DEBUG_MAX; i++) {
1519 int set;
1520
1521 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
1522 if (set)
1523 fio_debug |= (1UL << i);
1524 }
1525
1526 gtk_widget_destroy(dialog);
1527}
1528
Jens Axboe0420ba62012-02-29 11:16:52 +01001529static void about_dialog(GtkWidget *w, gpointer data)
1530{
1531 gtk_show_about_dialog(NULL,
1532 "program-name", "gfio",
1533 "comments", "Gtk2 UI for fio",
1534 "license", "GPLv2",
1535 "version", fio_version_string,
1536 "copyright", "Jens Axboe <axboe@kernel.dk> 2012",
1537 "logo-icon-name", "fio",
1538 /* Must be last: */
1539 NULL, NULL,
1540 NULL);
1541}
1542
1543static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01001544 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01001545 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01001546 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
1547 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
1548 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
1549 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01001550 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe46974a72012-03-02 19:34:13 +01001551 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
1552 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01001553};
Jens Axboe3e47bd22012-02-29 13:45:02 +01001554static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01001555
1556static const gchar *ui_string = " \
1557 <ui> \
1558 <menubar name=\"MainMenu\"> \
1559 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
1560 <menuitem name=\"Open\" action=\"OpenFile\" /> \
1561 <menuitem name=\"Save\" action=\"SaveFile\" /> \
1562 <separator name=\"Separator\"/> \
Jens Axboe46974a72012-03-02 19:34:13 +01001563 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
1564 <separator name=\"Separator2\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001565 <menuitem name=\"Quit\" action=\"Quit\" /> \
1566 </menu> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01001567 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
1568 <menuitem name=\"Log\" action=\"ViewLog\" /> \
1569 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01001570 <menu name=\"Help\" action=\"HelpMenuAction\"> \
1571 <menuitem name=\"About\" action=\"About\" /> \
1572 </menu> \
1573 </menubar> \
1574 </ui> \
1575";
1576
1577static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager)
1578{
1579 GtkActionGroup *action_group = gtk_action_group_new("Menu");
1580 GError *error = 0;
1581
1582 action_group = gtk_action_group_new("Menu");
1583 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, 0);
1584
1585 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1586 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
1587
1588 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
1589 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
1590}
1591
1592void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
1593 GtkWidget *vbox, GtkUIManager *ui_manager)
1594{
1595 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
1596}
1597
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001598static void init_ui(int *argc, char **argv[], struct gui *ui)
1599{
Jens Axboe0420ba62012-02-29 11:16:52 +01001600 GtkSettings *settings;
1601 GtkUIManager *uimanager;
Jens Axboe843ad232012-02-29 11:44:53 +01001602 GtkWidget *menu, *probe, *probe_frame, *probe_box;
Jens Axboe0420ba62012-02-29 11:16:52 +01001603
1604 memset(ui, 0, sizeof(*ui));
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001605
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001606 /* Magical g*thread incantation, you just need this thread stuff.
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001607 * Without it, the update that happens in gfio_update_thread_status
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001608 * doesn't really happen in a timely fashion, you need expose events
1609 */
Jens Axboeed727a42012-03-02 12:14:40 +01001610 if (!g_thread_supported())
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001611 g_thread_init(NULL);
1612 gdk_threads_init();
1613
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001614 gtk_init(argc, argv);
Jens Axboe0420ba62012-02-29 11:16:52 +01001615 settings = gtk_settings_get_default();
1616 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
1617 g_type_init();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001618
1619 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1620 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
1621 gtk_window_set_default_size(GTK_WINDOW(ui->window), 700, 500);
1622
Jens Axboe0420ba62012-02-29 11:16:52 +01001623 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
1624 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001625
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001626 ui->vbox = gtk_vbox_new(FALSE, 0);
1627 gtk_container_add(GTK_CONTAINER (ui->window), ui->vbox);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001628
Jens Axboe0420ba62012-02-29 11:16:52 +01001629 uimanager = gtk_ui_manager_new();
1630 menu = get_menubar_menu(ui->window, uimanager);
1631 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
1632
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001633 /*
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001634 * Set up alignments for widgets at the top of ui,
1635 * align top left, expand horizontally but not vertically
1636 */
1637 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001638 ui->topvbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001639 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001640 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->topalign, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001641
Jens Axboe3e47bd22012-02-29 13:45:02 +01001642 probe = gtk_frame_new("Job");
Jens Axboe843ad232012-02-29 11:44:53 +01001643 gtk_box_pack_start(GTK_BOX(ui->topvbox), probe, TRUE, FALSE, 3);
1644 probe_frame = gtk_vbox_new(FALSE, 3);
1645 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
1646
1647 probe_box = gtk_hbox_new(FALSE, 3);
1648 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01001649 ui->probe.hostname = new_info_label_in_frame(probe_box, "Host");
1650 ui->probe.os = new_info_label_in_frame(probe_box, "OS");
1651 ui->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
1652 ui->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
1653
Jens Axboe3e47bd22012-02-29 13:45:02 +01001654 probe_box = gtk_hbox_new(FALSE, 3);
1655 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01001656
Jens Axboeca850992012-03-05 20:04:43 +01001657 ui->eta.name = new_info_entry_in_frame(probe_box, "Name");
1658 ui->eta.iotype = new_info_entry_in_frame(probe_box, "IO");
1659 ui->eta.ioengine = new_info_entry_in_frame(probe_box, "IO Engine");
1660 ui->eta.iodepth = new_info_entry_in_frame(probe_box, "IO Depth");
1661 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
1662 ui->eta.files = new_info_entry_in_frame(probe_box, "Open files");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001663
1664 probe_box = gtk_hbox_new(FALSE, 3);
1665 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboeca850992012-03-05 20:04:43 +01001666 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1667 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1668 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1669 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001670
1671 /*
1672 * Only add this if we have a commit rate
1673 */
1674#if 0
1675 probe_box = gtk_hbox_new(FALSE, 3);
1676 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1677
Jens Axboe3e47bd22012-02-29 13:45:02 +01001678 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1679 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1680
Jens Axboe3e47bd22012-02-29 13:45:02 +01001681 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1682 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001683#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01001684
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001685 /*
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001686 * Add a text box for text op messages
1687 */
1688 ui->textview = gtk_text_view_new();
1689 ui->text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ui->textview));
1690 gtk_text_buffer_set_text(ui->text, "", -1);
1691 gtk_text_view_set_editable(GTK_TEXT_VIEW(ui->textview), FALSE);
1692 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ui->textview), FALSE);
1693 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1694 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1695 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1696 gtk_container_add(GTK_CONTAINER(ui->scrolled_window), ui->textview);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001697 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->scrolled_window,
1698 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001699
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001700 /*
1701 * Set up alignments for widgets at the bottom of ui,
1702 * align bottom left, expand horizontally but not vertically
1703 */
1704 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
1705 ui->buttonbox = gtk_hbox_new(FALSE, 0);
1706 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001707 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->bottomalign,
1708 FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001709
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001710 add_buttons(ui, buttonspeclist, ARRAYSIZE(buttonspeclist));
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001711
1712 /*
1713 * Set up thread status progress bar
1714 */
1715 ui->thread_status_pb = gtk_progress_bar_new();
1716 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01001717 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001718 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
1719
Jens Axboe9b260bd2012-03-06 11:02:52 +01001720 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001721
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001722 gtk_widget_show_all(ui->window);
1723}
1724
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001725int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001726{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001727 if (initialize_fio(envp))
1728 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01001729 if (fio_init_options())
1730 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01001731
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001732 init_ui(&argc, &argv, &ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001733
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001734 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001735 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001736 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001737 return 0;
1738}