blob: 4c9cce15892beb9ade81677d2ffee4bad958c3e5 [file] [log] [blame]
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001/*
2 * gfio - gui front end for fio - the flexible io tester
3 *
4 * Copyright (C) 2012 Stephen M. Cameron <stephenmcameron@gmail.com>
Jens Axboec0187f32012-03-06 15:39:15 +01005 * Copyright (C) 2012 Jens Axboe <axboe@kernel.dk>
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01006 *
7 * The license below covers all files distributed with fio unless otherwise
8 * noted in the file itself.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
Stephen M. Cameron8232e282012-02-24 08:17:31 +010024#include <locale.h>
Stephen M. Cameron60f6b332012-02-24 08:17:32 +010025#include <malloc.h>
Stephen M. Cameron8232e282012-02-24 08:17:31 +010026
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +010027#include <glib.h>
Stephen M. Cameronff1f3282012-02-24 08:17:30 +010028#include <gtk/gtk.h>
29
Stephen M. Cameron8232e282012-02-24 08:17:31 +010030#include "fio.h"
31
Jens Axboe63a130b2012-03-06 20:08:59 +010032static int gfio_server_running;
33
Jens Axboe3e47bd22012-02-29 13:45:02 +010034static void gfio_update_thread_status(char *status_message, double perc);
35
Stephen M. Cameronf3074002012-02-24 08:17:30 +010036#define ARRAYSIZE(x) (sizeof((x)) / (sizeof((x)[0])))
37
38typedef void (*clickfunction)(GtkWidget *widget, gpointer data);
39
Jens Axboe3e47bd22012-02-29 13:45:02 +010040static void connect_clicked(GtkWidget *widget, gpointer data);
Stephen M. Cameronf3074002012-02-24 08:17:30 +010041static void start_job_clicked(GtkWidget *widget, gpointer data);
42
43static struct button_spec {
44 const char *buttontext;
45 clickfunction f;
46 const char *tooltiptext;
Jens Axboe3e47bd22012-02-29 13:45:02 +010047 const int start_insensitive;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010048} buttonspeclist[] = {
Jens Axboe3e47bd22012-02-29 13:45:02 +010049#define CONNECT_BUTTON 0
50#define START_JOB_BUTTON 1
51 { "Connect", connect_clicked, "Connect to host", 0 },
Stephen M. Cameronf3074002012-02-24 08:17:30 +010052 { "Start Job",
53 start_job_clicked,
Jens Axboe3e47bd22012-02-29 13:45:02 +010054 "Send current fio job to fio server to be executed", 1 },
Stephen M. Cameronf3074002012-02-24 08:17:30 +010055};
56
Jens Axboe843ad232012-02-29 11:44:53 +010057struct probe_widget {
58 GtkWidget *hostname;
59 GtkWidget *os;
60 GtkWidget *arch;
61 GtkWidget *fio_ver;
62};
63
Jens Axboe3e47bd22012-02-29 13:45:02 +010064struct eta_widget {
Jens Axboe807f9972012-03-02 10:25:24 +010065 GtkWidget *name;
66 GtkWidget *iotype;
67 GtkWidget *ioengine;
68 GtkWidget *iodepth;
Jens Axboe3e47bd22012-02-29 13:45:02 +010069 GtkWidget *jobs;
70 GtkWidget *files;
71 GtkWidget *read_bw;
72 GtkWidget *read_iops;
73 GtkWidget *cr_bw;
74 GtkWidget *cr_iops;
75 GtkWidget *write_bw;
76 GtkWidget *write_iops;
77 GtkWidget *cw_bw;
78 GtkWidget *cw_iops;
79};
80
Stephen M. Cameronff1f3282012-02-24 08:17:30 +010081struct gui {
82 GtkWidget *window;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +010083 GtkWidget *vbox;
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +010084 GtkWidget *topvbox;
85 GtkWidget *topalign;
86 GtkWidget *bottomalign;
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +010087 GtkWidget *thread_status_pb;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010088 GtkWidget *buttonbox;
89 GtkWidget *button[ARRAYSIZE(buttonspeclist)];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +010090 GtkWidget *scrolled_window;
91 GtkWidget *textview;
Jens Axboe0420ba62012-02-29 11:16:52 +010092 GtkWidget *error_info_bar;
93 GtkWidget *error_label;
Jens Axboef9d40b42012-03-06 09:52:49 +010094 GtkWidget *results_notebook;
95 GtkWidget *results_window;
Jens Axboe9b260bd2012-03-06 11:02:52 +010096 GtkListStore *log_model;
97 GtkWidget *log_tree;
Jens Axboe4cbe7212012-03-06 13:36:17 +010098 GtkWidget *log_view;
Stephen M. Cameron736f2df2012-02-24 08:17:32 +010099 GtkTextBuffer *text;
Jens Axboe843ad232012-02-29 11:44:53 +0100100 struct probe_widget probe;
Jens Axboe3e47bd22012-02-29 13:45:02 +0100101 struct eta_widget eta;
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100102 int connected;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100103 pthread_t t;
Jens Axboe63a130b2012-03-06 20:08:59 +0100104 pthread_t server_t;
Jens Axboe0420ba62012-02-29 11:16:52 +0100105
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100106 struct fio_client *client;
Jens Axboe0420ba62012-02-29 11:16:52 +0100107 int nr_job_files;
108 char **job_files;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100109} ui;
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100110
Jens Axboee0681f32012-03-06 12:14:42 +0100111struct gfio_client {
112 struct gui *ui;
113 GtkWidget *results_widget;
114 GtkWidget *disk_util_frame;
115};
116
Jens Axboe8663ea62012-03-02 14:04:30 +0100117static void clear_ui_info(struct gui *ui)
118{
119 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), "");
120 gtk_label_set_text(GTK_LABEL(ui->probe.os), "");
121 gtk_label_set_text(GTK_LABEL(ui->probe.arch), "");
122 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), "");
Jens Axboeca850992012-03-05 20:04:43 +0100123 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), "");
124 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), "");
125 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), "");
126 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), "");
127 gtk_entry_set_text(GTK_ENTRY(ui->eta.jobs), "");
128 gtk_entry_set_text(GTK_ENTRY(ui->eta.files), "");
129 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), "");
130 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), "");
131 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), "");
132 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100133}
134
Jens Axboe3650a3c2012-03-05 14:09:03 +0100135static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
136{
137 GtkWidget *entry, *frame;
138
139 frame = gtk_frame_new(label);
140 entry = gtk_entry_new();
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100141 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100142 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
143 gtk_container_add(GTK_CONTAINER(frame), entry);
144
145 return entry;
146}
147
148static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
149{
150 GtkWidget *label_widget;
151 GtkWidget *frame;
152
153 frame = gtk_frame_new(label);
154 label_widget = gtk_label_new(NULL);
155 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
156 gtk_container_add(GTK_CONTAINER(frame), label_widget);
157
158 return label_widget;
159}
160
161static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
162{
163 GtkWidget *button, *box;
164
165 box = gtk_hbox_new(FALSE, 3);
166 gtk_container_add(GTK_CONTAINER(hbox), box);
167
168 button = gtk_spin_button_new_with_range(min, max, 1.0);
169 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
170
171 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
172 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
173
174 return button;
175}
176
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100177static void gfio_set_connected(struct gui *ui, int connected)
178{
179 if (connected) {
180 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
181 ui->connected = 1;
182 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Disconnect");
Jens Axboe88f6e7a2012-03-06 12:55:29 +0100183 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100184 } else {
185 ui->connected = 0;
186 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Connect");
187 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
Jens Axboe63a130b2012-03-06 20:08:59 +0100188 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100189 }
190}
191
Jens Axboe3650a3c2012-03-05 14:09:03 +0100192static void label_set_int_value(GtkWidget *entry, unsigned int val)
193{
194 char tmp[80];
195
196 sprintf(tmp, "%u", val);
197 gtk_label_set_text(GTK_LABEL(entry), tmp);
198}
199
200static void entry_set_int_value(GtkWidget *entry, unsigned int val)
201{
202 char tmp[80];
203
204 sprintf(tmp, "%u", val);
205 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
206}
207
Jens Axboea2697902012-03-05 16:43:49 +0100208#define ALIGN_LEFT 1
209#define ALIGN_RIGHT 2
210#define INVISIBLE 4
211#define UNSORTABLE 8
212
213GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
214{
215 GtkCellRenderer *renderer;
216 GtkTreeViewColumn *col;
217 double xalign = 0.0; /* left as default */
218 PangoAlignment align;
219 gboolean visible;
220
221 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
222 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
223 PANGO_ALIGN_CENTER;
224 visible = !(flags & INVISIBLE);
225
226 renderer = gtk_cell_renderer_text_new();
227 col = gtk_tree_view_column_new();
228
229 gtk_tree_view_column_set_title(col, title);
230 if (!(flags & UNSORTABLE))
231 gtk_tree_view_column_set_sort_column_id(col, index);
232 gtk_tree_view_column_set_resizable(col, TRUE);
233 gtk_tree_view_column_pack_start(col, renderer, TRUE);
234 gtk_tree_view_column_add_attribute(col, renderer, "text", index);
235 gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
236 switch (align) {
237 case PANGO_ALIGN_LEFT:
238 xalign = 0.0;
239 break;
240 case PANGO_ALIGN_CENTER:
241 xalign = 0.5;
242 break;
243 case PANGO_ALIGN_RIGHT:
244 xalign = 1.0;
245 break;
246 }
247 gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
248 gtk_tree_view_column_set_visible(col, visible);
249 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
250 return col;
251}
252
Jens Axboe9b260bd2012-03-06 11:02:52 +0100253static void gfio_ui_setup_log(struct gui *ui)
254{
255 GtkTreeSelection *selection;
256 GtkListStore *model;
257 GtkWidget *tree_view;
258
259 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
260
261 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
262 gtk_widget_set_can_focus(tree_view, FALSE);
263
264 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
265 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
Jens Axboe661f7412012-03-06 13:55:45 +0100266 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
267 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100268
269 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
270 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
271 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
Jens Axboef095d562012-03-06 13:49:12 +0100272 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100273
274 ui->log_model = model;
275 ui->log_tree = tree_view;
276}
277
Jens Axboea2697902012-03-05 16:43:49 +0100278static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
279 fio_fp64_t *plist,
280 unsigned int len,
281 const char *base,
282 unsigned int scale)
283{
284 GType types[FIO_IO_U_LIST_MAX_LEN];
285 GtkWidget *tree_view;
286 GtkTreeSelection *selection;
287 GtkListStore *model;
288 GtkTreeIter iter;
289 int i;
290
291 for (i = 0; i < len; i++)
292 types[i] = G_TYPE_INT;
293
294 model = gtk_list_store_newv(len, types);
295
296 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
297 gtk_widget_set_can_focus(tree_view, FALSE);
298
Jens Axboe661f7412012-03-06 13:55:45 +0100299 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
300 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
301
Jens Axboea2697902012-03-05 16:43:49 +0100302 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
303 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
304
305 for (i = 0; i < len; i++) {
306 char fbuf[8];
307
308 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
309 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
310 }
311
312 gtk_list_store_append(model, &iter);
313
Jens Axboee0681f32012-03-06 12:14:42 +0100314 for (i = 0; i < len; i++) {
315 if (scale)
316 ovals[i] = (ovals[i] + 999) / 1000;
Jens Axboea2697902012-03-05 16:43:49 +0100317 gtk_list_store_set(model, &iter, i, ovals[i], -1);
Jens Axboee0681f32012-03-06 12:14:42 +0100318 }
Jens Axboea2697902012-03-05 16:43:49 +0100319
320 return tree_view;
321}
322
323static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
324 int ddir)
325{
326 unsigned int *io_u_plat = ts->io_u_plat[ddir];
327 unsigned long nr = ts->clat_stat[ddir].samples;
328 fio_fp64_t *plist = ts->percentile_list;
329 unsigned int *ovals, len, minv, maxv, scale_down;
330 const char *base;
331 GtkWidget *tree_view, *frame, *hbox;
332 char tmp[64];
333
334 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
335 if (!len)
336 goto out;
337
338 /*
339 * We default to usecs, but if the value range is such that we
340 * should scale down to msecs, do that.
341 */
342 if (minv > 2000 && maxv > 99999) {
343 scale_down = 1;
344 base = "msec";
345 } else {
346 scale_down = 0;
347 base = "usec";
348 }
349
350 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
351
352 sprintf(tmp, "Completion percentiles (%s)", base);
353 frame = gtk_frame_new(tmp);
354 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
355
356 hbox = gtk_hbox_new(FALSE, 3);
357 gtk_container_add(GTK_CONTAINER(frame), hbox);
358
359 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
360out:
361 if (ovals)
362 free(ovals);
363}
364
Jens Axboe3650a3c2012-03-05 14:09:03 +0100365static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
366 unsigned long max, double mean, double dev)
367{
368 const char *base = "(usec)";
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100369 GtkWidget *hbox, *label, *frame;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100370 char *minp, *maxp;
371 char tmp[64];
372
373 if (!usec_to_msec(&min, &max, &mean, &dev))
374 base = "(msec)";
375
376 minp = num2str(min, 6, 1, 0);
377 maxp = num2str(max, 6, 1, 0);
378
Jens Axboe3650a3c2012-03-05 14:09:03 +0100379 sprintf(tmp, "%s %s", name, base);
380 frame = gtk_frame_new(tmp);
381 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
382
Jens Axboe3650a3c2012-03-05 14:09:03 +0100383 hbox = gtk_hbox_new(FALSE, 3);
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100384 gtk_container_add(GTK_CONTAINER(frame), hbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100385
386 label = new_info_label_in_frame(hbox, "Minimum");
387 gtk_label_set_text(GTK_LABEL(label), minp);
388 label = new_info_label_in_frame(hbox, "Maximum");
389 gtk_label_set_text(GTK_LABEL(label), maxp);
390 label = new_info_label_in_frame(hbox, "Average");
391 sprintf(tmp, "%5.02f", mean);
392 gtk_label_set_text(GTK_LABEL(label), tmp);
393 label = new_info_label_in_frame(hbox, "Standard deviation");
394 sprintf(tmp, "%5.02f", dev);
395 gtk_label_set_text(GTK_LABEL(label), tmp);
396
397 free(minp);
398 free(maxp);
399
400}
401
Jens Axboeca850992012-03-05 20:04:43 +0100402#define GFIO_CLAT 1
403#define GFIO_SLAT 2
404#define GFIO_LAT 4
405
Jens Axboe3650a3c2012-03-05 14:09:03 +0100406static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
407 struct thread_stat *ts, int ddir)
408{
409 const char *ddir_label[2] = { "Read", "Write" };
Jens Axboe0b761302012-03-05 20:44:11 +0100410 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
Jens Axboee0681f32012-03-06 12:14:42 +0100411 unsigned long min[3], max[3], runt;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100412 unsigned long long bw, iops;
Jens Axboeca850992012-03-05 20:04:43 +0100413 unsigned int flags = 0;
Jens Axboee0681f32012-03-06 12:14:42 +0100414 double mean[3], dev[3];
Jens Axboe3650a3c2012-03-05 14:09:03 +0100415 char *io_p, *bw_p, *iops_p;
416 int i2p;
417
418 if (!ts->runtime[ddir])
419 return;
420
421 i2p = is_power_of_2(rs->kb_base);
422 runt = ts->runtime[ddir];
423
424 bw = (1000 * ts->io_bytes[ddir]) / runt;
425 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
426 bw_p = num2str(bw, 6, 1, i2p);
427
428 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
429 iops_p = num2str(iops, 6, 1, 0);
430
431 box = gtk_hbox_new(FALSE, 3);
432 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
433
434 frame = gtk_frame_new(ddir_label[ddir]);
435 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
436
Jens Axboe0b761302012-03-05 20:44:11 +0100437 main_vbox = gtk_vbox_new(FALSE, 3);
438 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100439
440 box = gtk_hbox_new(FALSE, 3);
Jens Axboe0b761302012-03-05 20:44:11 +0100441 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100442
443 label = new_info_label_in_frame(box, "IO");
444 gtk_label_set_text(GTK_LABEL(label), io_p);
445 label = new_info_label_in_frame(box, "Bandwidth");
446 gtk_label_set_text(GTK_LABEL(label), bw_p);
447 label = new_info_label_in_frame(box, "IOPS");
448 gtk_label_set_text(GTK_LABEL(label), iops_p);
449 label = new_info_label_in_frame(box, "Runtime (msec)");
450 label_set_int_value(label, ts->runtime[ddir]);
451
Jens Axboee0681f32012-03-06 12:14:42 +0100452 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
Jens Axboeca850992012-03-05 20:04:43 +0100453 double p_of_agg = 100.0;
454 const char *bw_str = "KB";
455 char tmp[32];
456
457 if (rs->agg[ddir]) {
Jens Axboee0681f32012-03-06 12:14:42 +0100458 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
Jens Axboeca850992012-03-05 20:04:43 +0100459 if (p_of_agg > 100.0)
460 p_of_agg = 100.0;
461 }
462
Jens Axboee0681f32012-03-06 12:14:42 +0100463 if (mean[0] > 999999.9) {
464 min[0] /= 1000.0;
465 max[0] /= 1000.0;
466 mean[0] /= 1000.0;
467 dev[0] /= 1000.0;
Jens Axboeca850992012-03-05 20:04:43 +0100468 bw_str = "MB";
469 }
470
Jens Axboe0b761302012-03-05 20:44:11 +0100471 sprintf(tmp, "Bandwidth (%s)", bw_str);
472 frame = gtk_frame_new(tmp);
473 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
Jens Axboeca850992012-03-05 20:04:43 +0100474
Jens Axboe0b761302012-03-05 20:44:11 +0100475 box = gtk_hbox_new(FALSE, 3);
476 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboeca850992012-03-05 20:04:43 +0100477
Jens Axboe0b761302012-03-05 20:44:11 +0100478 label = new_info_label_in_frame(box, "Minimum");
Jens Axboee0681f32012-03-06 12:14:42 +0100479 label_set_int_value(label, min[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100480 label = new_info_label_in_frame(box, "Maximum");
Jens Axboee0681f32012-03-06 12:14:42 +0100481 label_set_int_value(label, max[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100482 label = new_info_label_in_frame(box, "Percentage of jobs");
Jens Axboeca850992012-03-05 20:04:43 +0100483 sprintf(tmp, "%3.2f%%", p_of_agg);
484 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100485 label = new_info_label_in_frame(box, "Average");
Jens Axboee0681f32012-03-06 12:14:42 +0100486 sprintf(tmp, "%5.02f", mean[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100487 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100488 label = new_info_label_in_frame(box, "Standard deviation");
Jens Axboee0681f32012-03-06 12:14:42 +0100489 sprintf(tmp, "%5.02f", dev[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100490 gtk_label_set_text(GTK_LABEL(label), tmp);
491 }
492
Jens Axboee0681f32012-03-06 12:14:42 +0100493 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
Jens Axboe2b089892012-03-06 08:09:17 +0100494 flags |= GFIO_SLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100495 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
Jens Axboe2b089892012-03-06 08:09:17 +0100496 flags |= GFIO_CLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100497 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
Jens Axboe2b089892012-03-06 08:09:17 +0100498 flags |= GFIO_LAT;
499
500 if (flags) {
501 frame = gtk_frame_new("Latency");
502 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
503
504 vbox = gtk_vbox_new(FALSE, 3);
505 gtk_container_add(GTK_CONTAINER(frame), vbox);
506
507 if (flags & GFIO_SLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100508 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
Jens Axboe2b089892012-03-06 08:09:17 +0100509 if (flags & GFIO_CLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100510 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
Jens Axboe2b089892012-03-06 08:09:17 +0100511 if (flags & GFIO_LAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100512 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
Jens Axboe2b089892012-03-06 08:09:17 +0100513 }
514
515 if (ts->clat_percentiles)
516 gfio_show_clat_percentiles(main_vbox, ts, ddir);
517
518
Jens Axboe3650a3c2012-03-05 14:09:03 +0100519 free(io_p);
520 free(bw_p);
521 free(iops_p);
522}
523
Jens Axboee5bd1342012-03-05 21:38:12 +0100524static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
525 const char **labels)
526{
527 GtkWidget *tree_view;
528 GtkTreeSelection *selection;
529 GtkListStore *model;
530 GtkTreeIter iter;
531 GType *types;
532 int i, skipped;
533
534 /*
535 * Check if all are empty, in which case don't bother
536 */
537 for (i = 0, skipped = 0; i < num; i++)
538 if (lat[i] <= 0.0)
539 skipped++;
540
541 if (skipped == num)
542 return NULL;
543
544 types = malloc(num * sizeof(GType));
545
546 for (i = 0; i < num; i++)
547 types[i] = G_TYPE_STRING;
548
549 model = gtk_list_store_newv(num, types);
550 free(types);
551 types = NULL;
552
553 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
554 gtk_widget_set_can_focus(tree_view, FALSE);
555
Jens Axboe661f7412012-03-06 13:55:45 +0100556 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
557 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
558
Jens Axboee5bd1342012-03-05 21:38:12 +0100559 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
560 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
561
562 for (i = 0; i < num; i++)
563 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
564
565 gtk_list_store_append(model, &iter);
566
567 for (i = 0; i < num; i++) {
568 char fbuf[32];
569
570 if (lat[i] <= 0.0)
571 sprintf(fbuf, "0.00");
572 else
573 sprintf(fbuf, "%3.2f%%", lat[i]);
574
575 gtk_list_store_set(model, &iter, i, fbuf, -1);
576 }
577
578 return tree_view;
579}
580
581static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
582{
583 GtkWidget *box, *frame, *tree_view;
584 double io_u_lat_u[FIO_IO_U_LAT_U_NR];
585 double io_u_lat_m[FIO_IO_U_LAT_M_NR];
586 const char *uranges[] = { "2", "4", "10", "20", "50", "100",
587 "250", "500", "750", "1000", };
588 const char *mranges[] = { "2", "4", "10", "20", "50", "100",
589 "250", "500", "750", "1000", "2000",
590 ">= 2000", };
591
592 stat_calc_lat_u(ts, io_u_lat_u);
593 stat_calc_lat_m(ts, io_u_lat_m);
594
595 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
596 if (tree_view) {
597 frame = gtk_frame_new("Latency buckets (usec)");
598 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
599
600 box = gtk_hbox_new(FALSE, 3);
601 gtk_container_add(GTK_CONTAINER(frame), box);
602 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
603 }
604
605 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
606 if (tree_view) {
607 frame = gtk_frame_new("Latency buckets (msec)");
608 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
609
610 box = gtk_hbox_new(FALSE, 3);
611 gtk_container_add(GTK_CONTAINER(frame), box);
612 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
613 }
614}
615
Jens Axboe2e331012012-03-05 22:07:54 +0100616static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
617{
618 GtkWidget *box, *frame, *entry;
619 double usr_cpu, sys_cpu;
620 unsigned long runtime;
621 char tmp[32];
622
623 runtime = ts->total_run_time;
624 if (runtime) {
625 double runt = (double) runtime;
626
627 usr_cpu = (double) ts->usr_time * 100 / runt;
628 sys_cpu = (double) ts->sys_time * 100 / runt;
629 } else {
630 usr_cpu = 0;
631 sys_cpu = 0;
632 }
633
634 frame = gtk_frame_new("OS resources");
635 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
636
637 box = gtk_hbox_new(FALSE, 3);
638 gtk_container_add(GTK_CONTAINER(frame), box);
639
640 entry = new_info_entry_in_frame(box, "User CPU");
641 sprintf(tmp, "%3.2f%%", usr_cpu);
642 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
643 entry = new_info_entry_in_frame(box, "System CPU");
644 sprintf(tmp, "%3.2f%%", sys_cpu);
645 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
646 entry = new_info_entry_in_frame(box, "Context switches");
647 entry_set_int_value(entry, ts->ctx);
648 entry = new_info_entry_in_frame(box, "Major faults");
649 entry_set_int_value(entry, ts->majf);
650 entry = new_info_entry_in_frame(box, "Minor faults");
651 entry_set_int_value(entry, ts->minf);
652}
Jens Axboe19998db2012-03-06 09:17:59 +0100653static void gfio_add_sc_depths_tree(GtkListStore *model,
654 struct thread_stat *ts, unsigned int len,
655 int submit)
656{
657 double io_u_dist[FIO_IO_U_MAP_NR];
658 GtkTreeIter iter;
659 /* Bits 0, and 3-8 */
660 const int add_mask = 0x1f9;
661 int i, j;
662
663 if (submit)
664 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
665 else
666 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
667
668 gtk_list_store_append(model, &iter);
669
670 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
671
672 for (i = 1, j = 0; i < len; i++) {
673 char fbuf[32];
674
675 if (!(add_mask & (1UL << (i - 1))))
676 sprintf(fbuf, "0.0%%");
677 else {
678 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
679 j++;
680 }
681
682 gtk_list_store_set(model, &iter, i, fbuf, -1);
683 }
684
685}
686
687static void gfio_add_total_depths_tree(GtkListStore *model,
688 struct thread_stat *ts, unsigned int len)
689{
690 double io_u_dist[FIO_IO_U_MAP_NR];
691 GtkTreeIter iter;
692 /* Bits 1-6, and 8 */
693 const int add_mask = 0x17e;
694 int i, j;
695
696 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
697
698 gtk_list_store_append(model, &iter);
699
700 gtk_list_store_set(model, &iter, 0, "Total", -1);
701
702 for (i = 1, j = 0; i < len; i++) {
703 char fbuf[32];
704
705 if (!(add_mask & (1UL << (i - 1))))
706 sprintf(fbuf, "0.0%%");
707 else {
708 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
709 j++;
710 }
711
712 gtk_list_store_set(model, &iter, i, fbuf, -1);
713 }
714
715}
Jens Axboe2e331012012-03-05 22:07:54 +0100716
717static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
718{
Jens Axboe2e331012012-03-05 22:07:54 +0100719 GtkWidget *frame, *box, *tree_view;
720 GtkTreeSelection *selection;
721 GtkListStore *model;
Jens Axboe2e331012012-03-05 22:07:54 +0100722 GType types[FIO_IO_U_MAP_NR + 1];
723 int i;
Jens Axboe19998db2012-03-06 09:17:59 +0100724#define NR_LABELS 10
725 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
Jens Axboe2e331012012-03-05 22:07:54 +0100726
727 frame = gtk_frame_new("IO depths");
728 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
729
730 box = gtk_hbox_new(FALSE, 3);
731 gtk_container_add(GTK_CONTAINER(frame), box);
732
Jens Axboe19998db2012-03-06 09:17:59 +0100733 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100734 types[i] = G_TYPE_STRING;
735
Jens Axboe19998db2012-03-06 09:17:59 +0100736 model = gtk_list_store_newv(NR_LABELS, types);
Jens Axboe2e331012012-03-05 22:07:54 +0100737
738 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
739 gtk_widget_set_can_focus(tree_view, FALSE);
740
Jens Axboe661f7412012-03-06 13:55:45 +0100741 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
742 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
743
Jens Axboe2e331012012-03-05 22:07:54 +0100744 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
745 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
746
Jens Axboe19998db2012-03-06 09:17:59 +0100747 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100748 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
749
Jens Axboe19998db2012-03-06 09:17:59 +0100750 gfio_add_total_depths_tree(model, ts, NR_LABELS);
751 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 1);
752 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 0);
Jens Axboe2e331012012-03-05 22:07:54 +0100753
754 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
755}
756
Jens Axboef9d40b42012-03-06 09:52:49 +0100757static gboolean results_window_delete(GtkWidget *w, gpointer data)
758{
759 struct gui *ui = (struct gui *) data;
760
761 gtk_widget_destroy(w);
762 ui->results_window = NULL;
763 ui->results_notebook = NULL;
764 return TRUE;
765}
766
767static GtkWidget *get_results_window(struct gui *ui)
768{
769 GtkWidget *win, *notebook;
770
771 if (ui->results_window)
772 return ui->results_notebook;
773
774 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
775 gtk_window_set_title(GTK_WINDOW(win), "Results");
776 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ui);
777 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ui);
778
779 notebook = gtk_notebook_new();
780 gtk_container_add(GTK_CONTAINER(win), notebook);
781
782 ui->results_window = win;
783 ui->results_notebook = notebook;
784 return ui->results_notebook;
785}
786
Jens Axboe3650a3c2012-03-05 14:09:03 +0100787static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
788 struct group_run_stats *rs)
789{
Jens Axboef9d40b42012-03-06 09:52:49 +0100790 GtkWidget *res_win, *box, *vbox, *entry;
Jens Axboee0681f32012-03-06 12:14:42 +0100791 struct gfio_client *gc = client->client_data;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100792
793 gdk_threads_enter();
794
Jens Axboee0681f32012-03-06 12:14:42 +0100795 res_win = get_results_window(gc->ui);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100796
797 vbox = gtk_vbox_new(FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100798
799 box = gtk_hbox_new(TRUE, 3);
800 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
801
Jens Axboef9d40b42012-03-06 09:52:49 +0100802 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), vbox, gtk_label_new(ts->name));
803
Jens Axboee0681f32012-03-06 12:14:42 +0100804 gc->results_widget = vbox;
805
Jens Axboe3650a3c2012-03-05 14:09:03 +0100806 entry = new_info_entry_in_frame(box, "Name");
807 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
808 if (strlen(ts->description)) {
809 entry = new_info_entry_in_frame(box, "Description");
810 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
811 }
812 entry = new_info_entry_in_frame(box, "Group ID");
813 entry_set_int_value(entry, ts->groupid);
814 entry = new_info_entry_in_frame(box, "Jobs");
815 entry_set_int_value(entry, ts->members);
816 entry = new_info_entry_in_frame(box, "Error");
817 entry_set_int_value(entry, ts->error);
818 entry = new_info_entry_in_frame(box, "PID");
819 entry_set_int_value(entry, ts->pid);
820
821 if (ts->io_bytes[DDIR_READ])
822 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
823 if (ts->io_bytes[DDIR_WRITE])
824 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
825
Jens Axboee5bd1342012-03-05 21:38:12 +0100826 gfio_show_latency_buckets(vbox, ts);
Jens Axboe2e331012012-03-05 22:07:54 +0100827 gfio_show_cpu_usage(vbox, ts);
828 gfio_show_io_depths(vbox, ts);
Jens Axboee5bd1342012-03-05 21:38:12 +0100829
Jens Axboee0681f32012-03-06 12:14:42 +0100830 gtk_widget_show_all(gc->ui->results_window);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100831 gdk_threads_leave();
832}
833
Jens Axboe084d1c62012-03-03 20:28:07 +0100834static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100835{
Jens Axboe9b260bd2012-03-06 11:02:52 +0100836 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +0100837 struct gfio_client *gc = client->client_data;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100838 GtkTreeIter iter;
839 struct tm *tm;
840 time_t sec;
841 char tmp[64], timebuf[80];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100842
Jens Axboe9b260bd2012-03-06 11:02:52 +0100843 sec = p->log_sec;
844 tm = localtime(&sec);
845 strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", tm);
846 sprintf(timebuf, "%s.%03ld", tmp, p->log_usec / 1000);
847
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100848 gdk_threads_enter();
Jens Axboe9b260bd2012-03-06 11:02:52 +0100849
Jens Axboee0681f32012-03-06 12:14:42 +0100850 gtk_list_store_append(gc->ui->log_model, &iter);
851 gtk_list_store_set(gc->ui->log_model, &iter, 0, timebuf, -1);
852 gtk_list_store_set(gc->ui->log_model, &iter, 1, client->hostname, -1);
853 gtk_list_store_set(gc->ui->log_model, &iter, 2, p->level, -1);
854 gtk_list_store_set(gc->ui->log_model, &iter, 3, p->buf, -1);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100855
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100856 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100857}
858
859static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
860{
Jens Axboee0681f32012-03-06 12:14:42 +0100861 struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
862 struct gfio_client *gc = client->client_data;
863 GtkWidget *box, *frame, *entry, *vbox;
864
Jens Axboe0050e5f2012-03-06 09:23:27 +0100865 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +0100866
867 if (!gc->results_widget) {
868 printf("no results!\n");
869 goto out;
870 }
871
872 if (!gc->disk_util_frame) {
873 gc->disk_util_frame = gtk_frame_new("Disk utilization");
874 gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
875 }
876
877 vbox = gtk_vbox_new(FALSE, 3);
878 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
879
880 frame = gtk_frame_new((char *) p->dus.name);
881 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
882
883 box = gtk_vbox_new(FALSE, 3);
884 gtk_container_add(GTK_CONTAINER(frame), box);
885
886 frame = gtk_frame_new("Read");
887 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
888 vbox = gtk_hbox_new(TRUE, 3);
889 gtk_container_add(GTK_CONTAINER(frame), vbox);
890 entry = new_info_entry_in_frame(vbox, "IOs");
891 entry_set_int_value(entry, p->dus.ios[0]);
892 entry = new_info_entry_in_frame(vbox, "Merges");
893 entry_set_int_value(entry, p->dus.merges[0]);
894 entry = new_info_entry_in_frame(vbox, "Sectors");
895 entry_set_int_value(entry, p->dus.sectors[0]);
896 entry = new_info_entry_in_frame(vbox, "Ticks");
897 entry_set_int_value(entry, p->dus.ticks[0]);
898
899 frame = gtk_frame_new("Write");
900 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
901 vbox = gtk_hbox_new(TRUE, 3);
902 gtk_container_add(GTK_CONTAINER(frame), vbox);
903 entry = new_info_entry_in_frame(vbox, "IOs");
904 entry_set_int_value(entry, p->dus.ios[1]);
905 entry = new_info_entry_in_frame(vbox, "Merges");
906 entry_set_int_value(entry, p->dus.merges[1]);
907 entry = new_info_entry_in_frame(vbox, "Sectors");
908 entry_set_int_value(entry, p->dus.sectors[1]);
909 entry = new_info_entry_in_frame(vbox, "Ticks");
910 entry_set_int_value(entry, p->dus.ticks[1]);
911
912 frame = gtk_frame_new("Shared");
913 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
914 vbox = gtk_hbox_new(TRUE, 3);
915 gtk_container_add(GTK_CONTAINER(frame), vbox);
916 entry = new_info_entry_in_frame(vbox, "IO ticks");
917 entry_set_int_value(entry, p->dus.io_ticks);
918 entry = new_info_entry_in_frame(vbox, "Time in queue");
919 entry_set_int_value(entry, p->dus.time_in_queue);
920
921 gtk_widget_show_all(gc->results_widget);
922out:
Jens Axboe0050e5f2012-03-06 09:23:27 +0100923 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100924}
925
Jens Axboe3650a3c2012-03-05 14:09:03 +0100926extern int sum_stat_clients;
927extern struct thread_stat client_ts;
928extern struct group_run_stats client_gs;
929
930static int sum_stat_nr;
931
Jens Axboe89e5fad2012-03-05 09:21:12 +0100932static void gfio_thread_status_op(struct fio_client *client,
933 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100934{
Jens Axboe3650a3c2012-03-05 14:09:03 +0100935 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
936
937 gfio_display_ts(client, &p->ts, &p->rs);
938
939 if (sum_stat_clients == 1)
940 return;
941
942 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
943 sum_group_stats(&client_gs, &p->rs);
944
945 client_ts.members++;
946 client_ts.groupid = p->ts.groupid;
947
948 if (++sum_stat_nr == sum_stat_clients) {
949 strcpy(client_ts.name, "All clients");
950 gfio_display_ts(client, &client_ts, &client_gs);
951 }
Stephen M. Camerona1820202012-02-24 08:17:31 +0100952}
953
Jens Axboe89e5fad2012-03-05 09:21:12 +0100954static void gfio_group_stats_op(struct fio_client *client,
955 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100956{
Jens Axboe0050e5f2012-03-06 09:23:27 +0100957 gdk_threads_enter();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100958 printf("gfio_group_stats_op called\n");
Jens Axboe89e5fad2012-03-05 09:21:12 +0100959 fio_client_ops.group_stats(client, cmd);
Jens Axboe0050e5f2012-03-06 09:23:27 +0100960 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100961}
962
Jens Axboe3e47bd22012-02-29 13:45:02 +0100963static void gfio_update_eta(struct jobs_eta *je)
964{
965 static int eta_good;
966 char eta_str[128];
967 char output[256];
968 char tmp[32];
969 double perc = 0.0;
970 int i2p = 0;
971
Jens Axboe0050e5f2012-03-06 09:23:27 +0100972 gdk_threads_enter();
973
Jens Axboe3e47bd22012-02-29 13:45:02 +0100974 eta_str[0] = '\0';
975 output[0] = '\0';
976
977 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
978 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
979 eta_to_str(eta_str, je->eta_sec);
980 }
981
982 sprintf(tmp, "%u", je->nr_running);
Jens Axboeca850992012-03-05 20:04:43 +0100983 gtk_entry_set_text(GTK_ENTRY(ui.eta.jobs), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +0100984 sprintf(tmp, "%u", je->files_open);
Jens Axboeca850992012-03-05 20:04:43 +0100985 gtk_entry_set_text(GTK_ENTRY(ui.eta.files), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +0100986
987#if 0
988 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
989 if (je->m_rate || je->t_rate) {
990 char *tr, *mr;
991
992 mr = num2str(je->m_rate, 4, 0, i2p);
993 tr = num2str(je->t_rate, 4, 0, i2p);
Jens Axboeca850992012-03-05 20:04:43 +0100994 gtk_entry_set_text(GTK_ENTRY(ui.eta);
Jens Axboe3e47bd22012-02-29 13:45:02 +0100995 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
996 free(tr);
997 free(mr);
998 } else if (je->m_iops || je->t_iops)
999 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
Jens Axboeebbd89c2012-03-02 11:21:13 +01001000
Jens Axboeca850992012-03-05 20:04:43 +01001001 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_bw), "---");
1002 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_iops), "---");
1003 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_bw), "---");
1004 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_iops), "---");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001005#endif
1006
1007 if (je->eta_sec != INT_MAX && je->nr_running) {
1008 char *iops_str[2];
1009 char *rate_str[2];
1010
1011 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1012 strcpy(output, "-.-% done");
1013 else {
1014 eta_good = 1;
1015 perc *= 100.0;
1016 sprintf(output, "%3.1f%% done", perc);
1017 }
1018
1019 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1020 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1021
1022 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1023 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1024
Jens Axboeca850992012-03-05 20:04:43 +01001025 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_bw), rate_str[0]);
1026 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_iops), iops_str[0]);
1027 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_bw), rate_str[1]);
1028 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_iops), iops_str[1]);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001029
1030 free(rate_str[0]);
1031 free(rate_str[1]);
1032 free(iops_str[0]);
1033 free(iops_str[1]);
1034 }
1035
1036 if (eta_str[0]) {
1037 char *dst = output + strlen(output);
1038
1039 sprintf(dst, " - %s", eta_str);
1040 }
1041
1042 gfio_update_thread_status(output, perc);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001043 gdk_threads_leave();
Jens Axboe3e47bd22012-02-29 13:45:02 +01001044}
1045
Stephen M. Camerona1820202012-02-24 08:17:31 +01001046static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1047{
Jens Axboe843ad232012-02-29 11:44:53 +01001048 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001049 struct gfio_client *gc = client->client_data;
1050 struct gui *ui = gc->ui;
Jens Axboe843ad232012-02-29 11:44:53 +01001051 const char *os, *arch;
1052 char buf[64];
1053
1054 os = fio_get_os_string(probe->os);
1055 if (!os)
1056 os = "unknown";
1057
1058 arch = fio_get_arch_string(probe->arch);
1059 if (!arch)
1060 os = "unknown";
1061
1062 if (!client->name)
1063 client->name = strdup((char *) probe->hostname);
1064
Jens Axboe0050e5f2012-03-06 09:23:27 +01001065 gdk_threads_enter();
1066
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001067 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), (char *) probe->hostname);
1068 gtk_label_set_text(GTK_LABEL(ui->probe.os), os);
1069 gtk_label_set_text(GTK_LABEL(ui->probe.arch), arch);
Jens Axboe843ad232012-02-29 11:44:53 +01001070 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001071 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), buf);
1072
1073 gfio_set_connected(ui, 1);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001074
1075 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001076}
1077
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001078static void gfio_update_thread_status(char *status_message, double perc)
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001079{
1080 static char message[100];
1081 const char *m = message;
1082
1083 strncpy(message, status_message, sizeof(message) - 1);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001084 gtk_progress_bar_set_text(
1085 GTK_PROGRESS_BAR(ui.thread_status_pb), m);
1086 gtk_progress_bar_set_fraction(
1087 GTK_PROGRESS_BAR(ui.thread_status_pb), perc / 100.0);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001088 gtk_widget_queue_draw(ui.window);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001089}
1090
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001091static void gfio_quit_op(struct fio_client *client)
1092{
Jens Axboee0681f32012-03-06 12:14:42 +01001093 struct gfio_client *gc = client->client_data;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001094
Jens Axboe0050e5f2012-03-06 09:23:27 +01001095 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +01001096 gfio_set_connected(gc->ui, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001097 gdk_threads_leave();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001098}
1099
Jens Axboe807f9972012-03-02 10:25:24 +01001100static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1101{
1102 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +01001103 struct gfio_client *gc = client->client_data;
1104 struct gui *ui = gc->ui;
Jens Axboe807f9972012-03-02 10:25:24 +01001105 char tmp[8];
1106 int i;
1107
1108 p->iodepth = le32_to_cpu(p->iodepth);
1109 p->rw = le32_to_cpu(p->rw);
1110
1111 for (i = 0; i < 2; i++) {
1112 p->min_bs[i] = le32_to_cpu(p->min_bs[i]);
1113 p->max_bs[i] = le32_to_cpu(p->max_bs[i]);
1114 }
1115
1116 p->numjobs = le32_to_cpu(p->numjobs);
1117 p->group_reporting = le32_to_cpu(p->group_reporting);
1118
Jens Axboe0050e5f2012-03-06 09:23:27 +01001119 gdk_threads_enter();
1120
Jens Axboeca850992012-03-05 20:04:43 +01001121 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), (gchar *) p->jobname);
1122 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), ddir_str(p->rw));
1123 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), (gchar *) p->ioengine);
Jens Axboe807f9972012-03-02 10:25:24 +01001124
1125 sprintf(tmp, "%u", p->iodepth);
Jens Axboeca850992012-03-05 20:04:43 +01001126 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), tmp);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001127
1128 gdk_threads_leave();
Jens Axboe807f9972012-03-02 10:25:24 +01001129}
1130
Jens Axboeed727a42012-03-02 12:14:40 +01001131static void gfio_client_timed_out(struct fio_client *client)
1132{
Jens Axboee0681f32012-03-06 12:14:42 +01001133 struct gfio_client *gc = client->client_data;
Jens Axboeed727a42012-03-02 12:14:40 +01001134 GtkWidget *dialog, *label, *content;
1135 char buf[256];
1136
1137 gdk_threads_enter();
1138
Jens Axboee0681f32012-03-06 12:14:42 +01001139 gfio_set_connected(gc->ui, 0);
1140 clear_ui_info(gc->ui);
Jens Axboeed727a42012-03-02 12:14:40 +01001141
1142 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
1143
1144 dialog = gtk_dialog_new_with_buttons("Timed out!",
Jens Axboee0681f32012-03-06 12:14:42 +01001145 GTK_WINDOW(gc->ui->window),
Jens Axboeed727a42012-03-02 12:14:40 +01001146 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1147 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1148
1149 content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1150 label = gtk_label_new((const gchar *) buf);
1151 gtk_container_add(GTK_CONTAINER(content), label);
1152 gtk_widget_show_all(dialog);
1153 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1154
1155 gtk_dialog_run(GTK_DIALOG(dialog));
1156 gtk_widget_destroy(dialog);
1157
1158 gdk_threads_leave();
1159}
1160
Stephen M. Camerona1820202012-02-24 08:17:31 +01001161struct client_ops gfio_client_ops = {
Jens Axboe0420ba62012-02-29 11:16:52 +01001162 .text_op = gfio_text_op,
1163 .disk_util = gfio_disk_util_op,
1164 .thread_status = gfio_thread_status_op,
1165 .group_stats = gfio_group_stats_op,
Jens Axboea5276612012-03-04 15:15:08 +01001166 .eta = gfio_update_eta,
Jens Axboe0420ba62012-02-29 11:16:52 +01001167 .probe = gfio_probe_op,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001168 .quit = gfio_quit_op,
Jens Axboe807f9972012-03-02 10:25:24 +01001169 .add_job = gfio_add_job_op,
Jens Axboeed727a42012-03-02 12:14:40 +01001170 .timed_out = gfio_client_timed_out,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001171 .stay_connected = 1,
Stephen M. Camerona1820202012-02-24 08:17:31 +01001172};
1173
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001174static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1175 __attribute__((unused)) gpointer data)
1176{
1177 gtk_main_quit();
1178}
1179
Stephen M. Cameron25927252012-02-24 08:17:31 +01001180static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001181{
Stephen M. Cameron25927252012-02-24 08:17:31 +01001182 fio_handle_clients(&gfio_client_ops);
Stephen M. Cameron25927252012-02-24 08:17:31 +01001183 return NULL;
1184}
1185
Jens Axboe0420ba62012-02-29 11:16:52 +01001186static int send_job_files(struct gui *ui)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001187{
Jens Axboe441013b2012-03-01 08:01:52 +01001188 int i, ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001189
Jens Axboe0420ba62012-02-29 11:16:52 +01001190 for (i = 0; i < ui->nr_job_files; i++) {
1191 ret = fio_clients_send_ini(ui->job_files[i]);
Jens Axboe441013b2012-03-01 08:01:52 +01001192 if (ret)
1193 break;
1194
Jens Axboe0420ba62012-02-29 11:16:52 +01001195 free(ui->job_files[i]);
1196 ui->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001197 }
1198 while (i < ui->nr_job_files) {
1199 free(ui->job_files[i]);
1200 ui->job_files[i] = NULL;
1201 i++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001202 }
1203
Jens Axboe441013b2012-03-01 08:01:52 +01001204 return ret;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001205}
1206
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001207static void start_job_thread(struct gui *ui)
Stephen M. Cameron25927252012-02-24 08:17:31 +01001208{
Jens Axboe0420ba62012-02-29 11:16:52 +01001209 if (send_job_files(ui)) {
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001210 printf("Yeah, I didn't really like those options too much.\n");
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001211 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
1212 return;
1213 }
Stephen M. Cameron25927252012-02-24 08:17:31 +01001214}
1215
Jens Axboe63a130b2012-03-06 20:08:59 +01001216static void *server_thread(void *arg)
1217{
1218 is_backend = 1;
1219 gfio_server_running = 1;
1220 fio_start_server(NULL);
1221 gfio_server_running = 0;
1222 return NULL;
1223}
1224
1225static void gfio_start_server(struct gui *ui)
1226{
1227 if (!gfio_server_running) {
1228 gfio_server_running = 1;
1229 pthread_create(&ui->server_t, NULL, server_thread, NULL);
1230 }
1231}
1232
Stephen M. Cameron25927252012-02-24 08:17:31 +01001233static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1234 gpointer data)
1235{
1236 struct gui *ui = data;
1237
Stephen M. Cameron25927252012-02-24 08:17:31 +01001238 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001239 start_job_thread(ui);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001240}
1241
Jens Axboedf06f222012-03-02 13:32:04 +01001242static void file_open(GtkWidget *w, gpointer data);
1243
1244static void connect_clicked(GtkWidget *widget, gpointer data)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001245{
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001246 struct gui *ui = data;
1247
1248 if (!ui->connected) {
Jens Axboedf06f222012-03-02 13:32:04 +01001249 if (!ui->nr_job_files)
1250 file_open(widget, data);
Jens Axboe8663ea62012-03-02 14:04:30 +01001251 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
Jens Axboe69406b92012-03-06 14:00:42 +01001252 if (!fio_clients_connect()) {
1253 pthread_create(&ui->t, NULL, job_thread, NULL);
1254 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 0);
1255 }
Jens Axboedf06f222012-03-02 13:32:04 +01001256 } else {
1257 fio_clients_terminate();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001258 gfio_set_connected(ui, 0);
Jens Axboe88432652012-03-02 19:09:31 +01001259 clear_ui_info(ui);
Jens Axboedf06f222012-03-02 13:32:04 +01001260 }
Jens Axboe3e47bd22012-02-29 13:45:02 +01001261}
1262
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001263static void add_button(struct gui *ui, int i, GtkWidget *buttonbox,
1264 struct button_spec *buttonspec)
1265{
1266 ui->button[i] = gtk_button_new_with_label(buttonspec->buttontext);
1267 g_signal_connect(ui->button[i], "clicked", G_CALLBACK (buttonspec->f), ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001268 gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], FALSE, FALSE, 3);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001269 gtk_widget_set_tooltip_text(ui->button[i], buttonspeclist[i].tooltiptext);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001270 gtk_widget_set_sensitive(ui->button[i], !buttonspec->start_insensitive);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001271}
1272
1273static void add_buttons(struct gui *ui,
1274 struct button_spec *buttonlist,
1275 int nbuttons)
1276{
1277 int i;
1278
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001279 for (i = 0; i < nbuttons; i++)
1280 add_button(ui, i, ui->buttonbox, &buttonlist[i]);
1281}
1282
Jens Axboe0420ba62012-02-29 11:16:52 +01001283static void on_info_bar_response(GtkWidget *widget, gint response,
1284 gpointer data)
1285{
1286 if (response == GTK_RESPONSE_OK) {
1287 gtk_widget_destroy(widget);
1288 ui.error_info_bar = NULL;
1289 }
1290}
1291
Jens Axboedf06f222012-03-02 13:32:04 +01001292void report_error(GError *error)
Jens Axboe0420ba62012-02-29 11:16:52 +01001293{
1294 if (ui.error_info_bar == NULL) {
1295 ui.error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
1296 GTK_RESPONSE_OK,
1297 NULL);
1298 g_signal_connect(ui.error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1299 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui.error_info_bar),
1300 GTK_MESSAGE_ERROR);
1301
1302 ui.error_label = gtk_label_new(error->message);
1303 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui.error_info_bar));
1304 gtk_container_add(GTK_CONTAINER(container), ui.error_label);
1305
1306 gtk_box_pack_start(GTK_BOX(ui.vbox), ui.error_info_bar, FALSE, FALSE, 0);
1307 gtk_widget_show_all(ui.vbox);
1308 } else {
1309 char buffer[256];
1310 snprintf(buffer, sizeof(buffer), "Failed to open file.");
1311 gtk_label_set(GTK_LABEL(ui.error_label), buffer);
1312 }
1313}
1314
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001315static int get_connection_details(char **host, int *port, int *type,
1316 int *server_start)
Jens Axboea7a42ce2012-03-02 13:12:04 +01001317{
1318 GtkWidget *dialog, *box, *vbox, *hentry, *hbox, *frame, *pentry, *combo;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001319 GtkWidget *button;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001320 char *typeentry;
1321
1322 dialog = gtk_dialog_new_with_buttons("Connection details",
1323 GTK_WINDOW(ui.window),
1324 GTK_DIALOG_DESTROY_WITH_PARENT,
1325 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1326 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1327
1328 frame = gtk_frame_new("Hostname / socket name");
1329 vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1330 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1331
1332 box = gtk_vbox_new(FALSE, 6);
1333 gtk_container_add(GTK_CONTAINER(frame), box);
1334
1335 hbox = gtk_hbox_new(TRUE, 10);
1336 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1337 hentry = gtk_entry_new();
1338 gtk_entry_set_text(GTK_ENTRY(hentry), "localhost");
1339 gtk_box_pack_start(GTK_BOX(hbox), hentry, TRUE, TRUE, 0);
1340
1341 frame = gtk_frame_new("Port");
1342 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1343 box = gtk_vbox_new(FALSE, 10);
1344 gtk_container_add(GTK_CONTAINER(frame), box);
1345
1346 hbox = gtk_hbox_new(TRUE, 4);
1347 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1348 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1349
1350 frame = gtk_frame_new("Type");
1351 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1352 box = gtk_vbox_new(FALSE, 10);
1353 gtk_container_add(GTK_CONTAINER(frame), box);
1354
1355 hbox = gtk_hbox_new(TRUE, 4);
1356 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1357
Jens Axboeb4655622012-03-06 13:46:21 +01001358 combo = gtk_combo_box_new_text();
1359 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "IPv4");
1360 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "IPv6");
1361 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "local socket");
Jens Axboea7a42ce2012-03-02 13:12:04 +01001362 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
1363
1364 gtk_container_add(GTK_CONTAINER(hbox), combo);
1365
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001366 frame = gtk_frame_new("Options");
1367 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1368 box = gtk_vbox_new(FALSE, 10);
1369 gtk_container_add(GTK_CONTAINER(frame), box);
1370
1371 hbox = gtk_hbox_new(TRUE, 4);
1372 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1373
1374 button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1375 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), 1);
1376 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.");
1377 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 6);
1378
Jens Axboea7a42ce2012-03-02 13:12:04 +01001379 gtk_widget_show_all(dialog);
1380
1381 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1382 gtk_widget_destroy(dialog);
1383 return 1;
1384 }
1385
1386 *host = strdup(gtk_entry_get_text(GTK_ENTRY(hentry)));
1387 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1388
Jens Axboeb4655622012-03-06 13:46:21 +01001389 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001390 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1391 *type = Fio_client_ipv4;
1392 else if (!strncmp(typeentry, "IPv6", 4))
1393 *type = Fio_client_ipv6;
1394 else
1395 *type = Fio_client_socket;
1396 g_free(typeentry);
1397
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001398 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
1399
Jens Axboea7a42ce2012-03-02 13:12:04 +01001400 gtk_widget_destroy(dialog);
1401 return 0;
1402}
1403
Jens Axboee0681f32012-03-06 12:14:42 +01001404static void gfio_client_added(struct gui *ui, struct fio_client *client)
1405{
1406 struct gfio_client *gc;
1407
1408 gc = malloc(sizeof(*gc));
1409 memset(gc, 0, sizeof(*gc));
1410 gc->ui = ui;
1411
1412 client->client_data = gc;
1413}
1414
Jens Axboe0420ba62012-02-29 11:16:52 +01001415static void file_open(GtkWidget *w, gpointer data)
1416{
1417 GtkWidget *dialog;
Jens Axboe63a130b2012-03-06 20:08:59 +01001418 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01001419 GSList *filenames, *fn_glist;
1420 GtkFileFilter *filter;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001421 char *host;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001422 int port, type, server_start;
Jens Axboe0420ba62012-02-29 11:16:52 +01001423
1424 dialog = gtk_file_chooser_dialog_new("Open File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001425 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001426 GTK_FILE_CHOOSER_ACTION_OPEN,
1427 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1428 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1429 NULL);
1430 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1431
1432 filter = gtk_file_filter_new();
1433 gtk_file_filter_add_pattern(filter, "*.fio");
1434 gtk_file_filter_add_pattern(filter, "*.job");
1435 gtk_file_filter_add_mime_type(filter, "text/fio");
1436 gtk_file_filter_set_name(filter, "Fio job file");
1437 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
1438
1439 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1440 gtk_widget_destroy(dialog);
1441 return;
1442 }
1443
1444 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001445
1446 gtk_widget_destroy(dialog);
1447
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001448 if (get_connection_details(&host, &port, &type, &server_start))
Jens Axboea7a42ce2012-03-02 13:12:04 +01001449 goto err;
1450
Jens Axboe0420ba62012-02-29 11:16:52 +01001451 filenames = fn_glist;
1452 while (filenames != NULL) {
Jens Axboee0681f32012-03-06 12:14:42 +01001453 struct fio_client *client;
1454
Jens Axboe63a130b2012-03-06 20:08:59 +01001455 ui->job_files = realloc(ui->job_files, (ui->nr_job_files + 1) * sizeof(char *));
1456 ui->job_files[ui->nr_job_files] = strdup(filenames->data);
1457 ui->nr_job_files++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001458
Jens Axboee0681f32012-03-06 12:14:42 +01001459 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
1460 if (!client) {
Jens Axboedf06f222012-03-02 13:32:04 +01001461 GError *error;
1462
1463 error = g_error_new(g_quark_from_string("fio"), 1,
1464 "Failed to add client %s", host);
Jens Axboe0420ba62012-02-29 11:16:52 +01001465 report_error(error);
1466 g_error_free(error);
Jens Axboe0420ba62012-02-29 11:16:52 +01001467 }
Jens Axboe63a130b2012-03-06 20:08:59 +01001468 gfio_client_added(ui, client);
Jens Axboe0420ba62012-02-29 11:16:52 +01001469
1470 g_free(filenames->data);
1471 filenames = g_slist_next(filenames);
1472 }
Jens Axboea7a42ce2012-03-02 13:12:04 +01001473 free(host);
Jens Axboe63a130b2012-03-06 20:08:59 +01001474
1475 if (server_start)
1476 gfio_start_server(ui);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001477err:
Jens Axboe0420ba62012-02-29 11:16:52 +01001478 g_slist_free(fn_glist);
Jens Axboe0420ba62012-02-29 11:16:52 +01001479}
1480
1481static void file_save(GtkWidget *w, gpointer data)
1482{
Jens Axboe63a130b2012-03-06 20:08:59 +01001483 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01001484 GtkWidget *dialog;
1485
1486 dialog = gtk_file_chooser_dialog_new("Save File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001487 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001488 GTK_FILE_CHOOSER_ACTION_SAVE,
1489 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1490 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1491 NULL);
1492
1493 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1494 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
1495
1496 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1497 char *filename;
1498
1499 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1500 // save_job_file(filename);
1501 g_free(filename);
1502 }
1503 gtk_widget_destroy(dialog);
1504}
1505
Jens Axboe9b260bd2012-03-06 11:02:52 +01001506static void view_log_destroy(GtkWidget *w, gpointer data)
1507{
1508 struct gui *ui = (struct gui *) data;
1509
1510 gtk_widget_ref(ui->log_tree);
1511 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
1512 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +01001513 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001514}
1515
1516static void view_log(GtkWidget *w, gpointer data)
1517{
Jens Axboe4cbe7212012-03-06 13:36:17 +01001518 GtkWidget *win, *scroll, *vbox, *box;
1519 struct gui *ui = (struct gui *) data;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001520
Jens Axboe4cbe7212012-03-06 13:36:17 +01001521 if (ui->log_view)
1522 return;
1523
1524 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001525 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001526 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001527
Jens Axboe4cbe7212012-03-06 13:36:17 +01001528 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001529
Jens Axboe4cbe7212012-03-06 13:36:17 +01001530 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
1531
1532 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1533
1534 box = gtk_hbox_new(TRUE, 0);
1535 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
1536 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
1537 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
1538
1539 vbox = gtk_vbox_new(TRUE, 5);
1540 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
1541
1542 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001543 gtk_widget_show_all(win);
1544}
1545
Jens Axboe46974a72012-03-02 19:34:13 +01001546static void preferences(GtkWidget *w, gpointer data)
1547{
1548 GtkWidget *dialog, *frame, *box, **buttons;
1549 int i;
1550
1551 dialog = gtk_dialog_new_with_buttons("Preferences",
1552 GTK_WINDOW(ui.window),
1553 GTK_DIALOG_DESTROY_WITH_PARENT,
1554 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1555 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1556 NULL);
1557
Jens Axboe0b8d11e2012-03-02 19:44:15 +01001558 frame = gtk_frame_new("Debug logging");
Jens Axboe46974a72012-03-02 19:34:13 +01001559 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1560 box = gtk_hbox_new(FALSE, 6);
1561 gtk_container_add(GTK_CONTAINER(frame), box);
1562
1563 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
1564
1565 for (i = 0; i < FD_DEBUG_MAX; i++) {
1566 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
Jens Axboe0b8d11e2012-03-02 19:44:15 +01001567 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
Jens Axboe46974a72012-03-02 19:34:13 +01001568 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
1569 }
1570
1571 gtk_widget_show_all(dialog);
1572
1573 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1574 gtk_widget_destroy(dialog);
1575 return;
1576 }
1577
1578 for (i = 0; i < FD_DEBUG_MAX; i++) {
1579 int set;
1580
1581 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
1582 if (set)
1583 fio_debug |= (1UL << i);
1584 }
1585
1586 gtk_widget_destroy(dialog);
1587}
1588
Jens Axboe0420ba62012-02-29 11:16:52 +01001589static void about_dialog(GtkWidget *w, gpointer data)
1590{
1591 gtk_show_about_dialog(NULL,
1592 "program-name", "gfio",
1593 "comments", "Gtk2 UI for fio",
1594 "license", "GPLv2",
1595 "version", fio_version_string,
1596 "copyright", "Jens Axboe <axboe@kernel.dk> 2012",
1597 "logo-icon-name", "fio",
1598 /* Must be last: */
1599 NULL, NULL,
1600 NULL);
1601}
1602
1603static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01001604 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01001605 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01001606 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
1607 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
1608 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
1609 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01001610 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe46974a72012-03-02 19:34:13 +01001611 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
1612 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01001613};
Jens Axboe3e47bd22012-02-29 13:45:02 +01001614static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01001615
1616static const gchar *ui_string = " \
1617 <ui> \
1618 <menubar name=\"MainMenu\"> \
1619 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
1620 <menuitem name=\"Open\" action=\"OpenFile\" /> \
1621 <menuitem name=\"Save\" action=\"SaveFile\" /> \
1622 <separator name=\"Separator\"/> \
Jens Axboe46974a72012-03-02 19:34:13 +01001623 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
1624 <separator name=\"Separator2\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001625 <menuitem name=\"Quit\" action=\"Quit\" /> \
1626 </menu> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01001627 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
1628 <menuitem name=\"Log\" action=\"ViewLog\" /> \
1629 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01001630 <menu name=\"Help\" action=\"HelpMenuAction\"> \
1631 <menuitem name=\"About\" action=\"About\" /> \
1632 </menu> \
1633 </menubar> \
1634 </ui> \
1635";
1636
Jens Axboe4cbe7212012-03-06 13:36:17 +01001637static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
1638 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01001639{
1640 GtkActionGroup *action_group = gtk_action_group_new("Menu");
1641 GError *error = 0;
1642
1643 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001644 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001645
1646 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1647 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
1648
1649 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
1650 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
1651}
1652
1653void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
1654 GtkWidget *vbox, GtkUIManager *ui_manager)
1655{
1656 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
1657}
1658
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001659static void init_ui(int *argc, char **argv[], struct gui *ui)
1660{
Jens Axboe0420ba62012-02-29 11:16:52 +01001661 GtkSettings *settings;
1662 GtkUIManager *uimanager;
Jens Axboe843ad232012-02-29 11:44:53 +01001663 GtkWidget *menu, *probe, *probe_frame, *probe_box;
Jens Axboe0420ba62012-02-29 11:16:52 +01001664
1665 memset(ui, 0, sizeof(*ui));
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001666
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001667 /* Magical g*thread incantation, you just need this thread stuff.
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001668 * Without it, the update that happens in gfio_update_thread_status
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001669 * doesn't really happen in a timely fashion, you need expose events
1670 */
Jens Axboeed727a42012-03-02 12:14:40 +01001671 if (!g_thread_supported())
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001672 g_thread_init(NULL);
1673 gdk_threads_init();
1674
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001675 gtk_init(argc, argv);
Jens Axboe0420ba62012-02-29 11:16:52 +01001676 settings = gtk_settings_get_default();
1677 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
1678 g_type_init();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001679
1680 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1681 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
1682 gtk_window_set_default_size(GTK_WINDOW(ui->window), 700, 500);
1683
Jens Axboe0420ba62012-02-29 11:16:52 +01001684 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
1685 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001686
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001687 ui->vbox = gtk_vbox_new(FALSE, 0);
1688 gtk_container_add(GTK_CONTAINER (ui->window), ui->vbox);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001689
Jens Axboe0420ba62012-02-29 11:16:52 +01001690 uimanager = gtk_ui_manager_new();
Jens Axboe4cbe7212012-03-06 13:36:17 +01001691 menu = get_menubar_menu(ui->window, uimanager, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001692 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
1693
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001694 /*
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001695 * Set up alignments for widgets at the top of ui,
1696 * align top left, expand horizontally but not vertically
1697 */
1698 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001699 ui->topvbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001700 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001701 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->topalign, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001702
Jens Axboe3e47bd22012-02-29 13:45:02 +01001703 probe = gtk_frame_new("Job");
Jens Axboe843ad232012-02-29 11:44:53 +01001704 gtk_box_pack_start(GTK_BOX(ui->topvbox), probe, TRUE, FALSE, 3);
1705 probe_frame = gtk_vbox_new(FALSE, 3);
1706 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
1707
1708 probe_box = gtk_hbox_new(FALSE, 3);
1709 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01001710 ui->probe.hostname = new_info_label_in_frame(probe_box, "Host");
1711 ui->probe.os = new_info_label_in_frame(probe_box, "OS");
1712 ui->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
1713 ui->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
1714
Jens Axboe3e47bd22012-02-29 13:45:02 +01001715 probe_box = gtk_hbox_new(FALSE, 3);
1716 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01001717
Jens Axboeca850992012-03-05 20:04:43 +01001718 ui->eta.name = new_info_entry_in_frame(probe_box, "Name");
1719 ui->eta.iotype = new_info_entry_in_frame(probe_box, "IO");
1720 ui->eta.ioengine = new_info_entry_in_frame(probe_box, "IO Engine");
1721 ui->eta.iodepth = new_info_entry_in_frame(probe_box, "IO Depth");
1722 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
1723 ui->eta.files = new_info_entry_in_frame(probe_box, "Open files");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001724
1725 probe_box = gtk_hbox_new(FALSE, 3);
1726 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboeca850992012-03-05 20:04:43 +01001727 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1728 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1729 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1730 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001731
1732 /*
1733 * Only add this if we have a commit rate
1734 */
1735#if 0
1736 probe_box = gtk_hbox_new(FALSE, 3);
1737 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1738
Jens Axboe3e47bd22012-02-29 13:45:02 +01001739 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1740 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1741
Jens Axboe3e47bd22012-02-29 13:45:02 +01001742 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1743 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001744#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01001745
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001746 /*
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001747 * Add a text box for text op messages
1748 */
1749 ui->textview = gtk_text_view_new();
1750 ui->text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ui->textview));
1751 gtk_text_buffer_set_text(ui->text, "", -1);
1752 gtk_text_view_set_editable(GTK_TEXT_VIEW(ui->textview), FALSE);
1753 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ui->textview), FALSE);
1754 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1755 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1756 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1757 gtk_container_add(GTK_CONTAINER(ui->scrolled_window), ui->textview);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001758 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->scrolled_window,
1759 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001760
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001761 /*
1762 * Set up alignments for widgets at the bottom of ui,
1763 * align bottom left, expand horizontally but not vertically
1764 */
1765 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
1766 ui->buttonbox = gtk_hbox_new(FALSE, 0);
1767 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001768 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->bottomalign,
1769 FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001770
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001771 add_buttons(ui, buttonspeclist, ARRAYSIZE(buttonspeclist));
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001772
1773 /*
1774 * Set up thread status progress bar
1775 */
1776 ui->thread_status_pb = gtk_progress_bar_new();
1777 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01001778 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001779 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
1780
Jens Axboe9b260bd2012-03-06 11:02:52 +01001781 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001782
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001783 gtk_widget_show_all(ui->window);
1784}
1785
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001786int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001787{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001788 if (initialize_fio(envp))
1789 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01001790 if (fio_init_options())
1791 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01001792
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001793 init_ui(&argc, &argv, &ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001794
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001795 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001796 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001797 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001798 return 0;
1799}