blob: 09a2484224f090d4a39ab3083a32b5a076e7b32f [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;
Jens Axboe4cbe7212012-03-06 13:36:17 +010095 GtkWidget *log_view;
Stephen M. Cameron736f2df2012-02-24 08:17:32 +010096 GtkTextBuffer *text;
Jens Axboe843ad232012-02-29 11:44:53 +010097 struct probe_widget probe;
Jens Axboe3e47bd22012-02-29 13:45:02 +010098 struct eta_widget eta;
Jens Axboe3ec62ec2012-03-01 12:01:29 +010099 int connected;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100100 pthread_t t;
Jens Axboe0420ba62012-02-29 11:16:52 +0100101
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100102 struct fio_client *client;
Jens Axboe0420ba62012-02-29 11:16:52 +0100103 int nr_job_files;
104 char **job_files;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100105} ui;
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100106
Jens Axboee0681f32012-03-06 12:14:42 +0100107struct gfio_client {
108 struct gui *ui;
109 GtkWidget *results_widget;
110 GtkWidget *disk_util_frame;
111};
112
Jens Axboe8663ea62012-03-02 14:04:30 +0100113static void clear_ui_info(struct gui *ui)
114{
115 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), "");
116 gtk_label_set_text(GTK_LABEL(ui->probe.os), "");
117 gtk_label_set_text(GTK_LABEL(ui->probe.arch), "");
118 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), "");
Jens Axboeca850992012-03-05 20:04:43 +0100119 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), "");
120 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), "");
121 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), "");
122 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), "");
123 gtk_entry_set_text(GTK_ENTRY(ui->eta.jobs), "");
124 gtk_entry_set_text(GTK_ENTRY(ui->eta.files), "");
125 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), "");
126 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), "");
127 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), "");
128 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100129}
130
Jens Axboe3650a3c2012-03-05 14:09:03 +0100131static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
132{
133 GtkWidget *entry, *frame;
134
135 frame = gtk_frame_new(label);
136 entry = gtk_entry_new();
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100137 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100138 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
139 gtk_container_add(GTK_CONTAINER(frame), entry);
140
141 return entry;
142}
143
144static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
145{
146 GtkWidget *label_widget;
147 GtkWidget *frame;
148
149 frame = gtk_frame_new(label);
150 label_widget = gtk_label_new(NULL);
151 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
152 gtk_container_add(GTK_CONTAINER(frame), label_widget);
153
154 return label_widget;
155}
156
157static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
158{
159 GtkWidget *button, *box;
160
161 box = gtk_hbox_new(FALSE, 3);
162 gtk_container_add(GTK_CONTAINER(hbox), box);
163
164 button = gtk_spin_button_new_with_range(min, max, 1.0);
165 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
166
167 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
168 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
169
170 return button;
171}
172
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100173static void gfio_set_connected(struct gui *ui, int connected)
174{
175 if (connected) {
176 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
177 ui->connected = 1;
178 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Disconnect");
Jens Axboe88f6e7a2012-03-06 12:55:29 +0100179 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100180 } else {
181 ui->connected = 0;
182 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Connect");
183 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
184 }
185}
186
Jens Axboe3650a3c2012-03-05 14:09:03 +0100187static void label_set_int_value(GtkWidget *entry, unsigned int val)
188{
189 char tmp[80];
190
191 sprintf(tmp, "%u", val);
192 gtk_label_set_text(GTK_LABEL(entry), tmp);
193}
194
195static void entry_set_int_value(GtkWidget *entry, unsigned int val)
196{
197 char tmp[80];
198
199 sprintf(tmp, "%u", val);
200 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
201}
202
Jens Axboea2697902012-03-05 16:43:49 +0100203#define ALIGN_LEFT 1
204#define ALIGN_RIGHT 2
205#define INVISIBLE 4
206#define UNSORTABLE 8
207
208GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
209{
210 GtkCellRenderer *renderer;
211 GtkTreeViewColumn *col;
212 double xalign = 0.0; /* left as default */
213 PangoAlignment align;
214 gboolean visible;
215
216 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
217 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
218 PANGO_ALIGN_CENTER;
219 visible = !(flags & INVISIBLE);
220
221 renderer = gtk_cell_renderer_text_new();
222 col = gtk_tree_view_column_new();
223
224 gtk_tree_view_column_set_title(col, title);
225 if (!(flags & UNSORTABLE))
226 gtk_tree_view_column_set_sort_column_id(col, index);
227 gtk_tree_view_column_set_resizable(col, TRUE);
228 gtk_tree_view_column_pack_start(col, renderer, TRUE);
229 gtk_tree_view_column_add_attribute(col, renderer, "text", index);
230 gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
231 switch (align) {
232 case PANGO_ALIGN_LEFT:
233 xalign = 0.0;
234 break;
235 case PANGO_ALIGN_CENTER:
236 xalign = 0.5;
237 break;
238 case PANGO_ALIGN_RIGHT:
239 xalign = 1.0;
240 break;
241 }
242 gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
243 gtk_tree_view_column_set_visible(col, visible);
244 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
245 return col;
246}
247
Jens Axboe9b260bd2012-03-06 11:02:52 +0100248static void gfio_ui_setup_log(struct gui *ui)
249{
250 GtkTreeSelection *selection;
251 GtkListStore *model;
252 GtkWidget *tree_view;
253
254 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
255
256 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
257 gtk_widget_set_can_focus(tree_view, FALSE);
258
259 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
260 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
261
262 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
263 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
264 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
265 tree_view_column(tree_view, 3, "Text", ALIGN_RIGHT | UNSORTABLE);
266
267 ui->log_model = model;
268 ui->log_tree = tree_view;
269}
270
Jens Axboea2697902012-03-05 16:43:49 +0100271static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
272 fio_fp64_t *plist,
273 unsigned int len,
274 const char *base,
275 unsigned int scale)
276{
277 GType types[FIO_IO_U_LIST_MAX_LEN];
278 GtkWidget *tree_view;
279 GtkTreeSelection *selection;
280 GtkListStore *model;
281 GtkTreeIter iter;
282 int i;
283
284 for (i = 0; i < len; i++)
285 types[i] = G_TYPE_INT;
286
287 model = gtk_list_store_newv(len, types);
288
289 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
290 gtk_widget_set_can_focus(tree_view, FALSE);
291
292 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
293 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
294
295 for (i = 0; i < len; i++) {
296 char fbuf[8];
297
298 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
299 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
300 }
301
302 gtk_list_store_append(model, &iter);
303
Jens Axboee0681f32012-03-06 12:14:42 +0100304 for (i = 0; i < len; i++) {
305 if (scale)
306 ovals[i] = (ovals[i] + 999) / 1000;
Jens Axboea2697902012-03-05 16:43:49 +0100307 gtk_list_store_set(model, &iter, i, ovals[i], -1);
Jens Axboee0681f32012-03-06 12:14:42 +0100308 }
Jens Axboea2697902012-03-05 16:43:49 +0100309
310 return tree_view;
311}
312
313static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
314 int ddir)
315{
316 unsigned int *io_u_plat = ts->io_u_plat[ddir];
317 unsigned long nr = ts->clat_stat[ddir].samples;
318 fio_fp64_t *plist = ts->percentile_list;
319 unsigned int *ovals, len, minv, maxv, scale_down;
320 const char *base;
321 GtkWidget *tree_view, *frame, *hbox;
322 char tmp[64];
323
324 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
325 if (!len)
326 goto out;
327
328 /*
329 * We default to usecs, but if the value range is such that we
330 * should scale down to msecs, do that.
331 */
332 if (minv > 2000 && maxv > 99999) {
333 scale_down = 1;
334 base = "msec";
335 } else {
336 scale_down = 0;
337 base = "usec";
338 }
339
340 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
341
342 sprintf(tmp, "Completion percentiles (%s)", base);
343 frame = gtk_frame_new(tmp);
344 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
345
346 hbox = gtk_hbox_new(FALSE, 3);
347 gtk_container_add(GTK_CONTAINER(frame), hbox);
348
349 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
350out:
351 if (ovals)
352 free(ovals);
353}
354
Jens Axboe3650a3c2012-03-05 14:09:03 +0100355static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
356 unsigned long max, double mean, double dev)
357{
358 const char *base = "(usec)";
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100359 GtkWidget *hbox, *label, *frame;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100360 char *minp, *maxp;
361 char tmp[64];
362
363 if (!usec_to_msec(&min, &max, &mean, &dev))
364 base = "(msec)";
365
366 minp = num2str(min, 6, 1, 0);
367 maxp = num2str(max, 6, 1, 0);
368
Jens Axboe3650a3c2012-03-05 14:09:03 +0100369 sprintf(tmp, "%s %s", name, base);
370 frame = gtk_frame_new(tmp);
371 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
372
Jens Axboe3650a3c2012-03-05 14:09:03 +0100373 hbox = gtk_hbox_new(FALSE, 3);
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100374 gtk_container_add(GTK_CONTAINER(frame), hbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100375
376 label = new_info_label_in_frame(hbox, "Minimum");
377 gtk_label_set_text(GTK_LABEL(label), minp);
378 label = new_info_label_in_frame(hbox, "Maximum");
379 gtk_label_set_text(GTK_LABEL(label), maxp);
380 label = new_info_label_in_frame(hbox, "Average");
381 sprintf(tmp, "%5.02f", mean);
382 gtk_label_set_text(GTK_LABEL(label), tmp);
383 label = new_info_label_in_frame(hbox, "Standard deviation");
384 sprintf(tmp, "%5.02f", dev);
385 gtk_label_set_text(GTK_LABEL(label), tmp);
386
387 free(minp);
388 free(maxp);
389
390}
391
Jens Axboeca850992012-03-05 20:04:43 +0100392#define GFIO_CLAT 1
393#define GFIO_SLAT 2
394#define GFIO_LAT 4
395
Jens Axboe3650a3c2012-03-05 14:09:03 +0100396static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
397 struct thread_stat *ts, int ddir)
398{
399 const char *ddir_label[2] = { "Read", "Write" };
Jens Axboe0b761302012-03-05 20:44:11 +0100400 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
Jens Axboee0681f32012-03-06 12:14:42 +0100401 unsigned long min[3], max[3], runt;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100402 unsigned long long bw, iops;
Jens Axboeca850992012-03-05 20:04:43 +0100403 unsigned int flags = 0;
Jens Axboee0681f32012-03-06 12:14:42 +0100404 double mean[3], dev[3];
Jens Axboe3650a3c2012-03-05 14:09:03 +0100405 char *io_p, *bw_p, *iops_p;
406 int i2p;
407
408 if (!ts->runtime[ddir])
409 return;
410
411 i2p = is_power_of_2(rs->kb_base);
412 runt = ts->runtime[ddir];
413
414 bw = (1000 * ts->io_bytes[ddir]) / runt;
415 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
416 bw_p = num2str(bw, 6, 1, i2p);
417
418 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
419 iops_p = num2str(iops, 6, 1, 0);
420
421 box = gtk_hbox_new(FALSE, 3);
422 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
423
424 frame = gtk_frame_new(ddir_label[ddir]);
425 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
426
Jens Axboe0b761302012-03-05 20:44:11 +0100427 main_vbox = gtk_vbox_new(FALSE, 3);
428 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100429
430 box = gtk_hbox_new(FALSE, 3);
Jens Axboe0b761302012-03-05 20:44:11 +0100431 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100432
433 label = new_info_label_in_frame(box, "IO");
434 gtk_label_set_text(GTK_LABEL(label), io_p);
435 label = new_info_label_in_frame(box, "Bandwidth");
436 gtk_label_set_text(GTK_LABEL(label), bw_p);
437 label = new_info_label_in_frame(box, "IOPS");
438 gtk_label_set_text(GTK_LABEL(label), iops_p);
439 label = new_info_label_in_frame(box, "Runtime (msec)");
440 label_set_int_value(label, ts->runtime[ddir]);
441
Jens Axboee0681f32012-03-06 12:14:42 +0100442 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
Jens Axboeca850992012-03-05 20:04:43 +0100443 double p_of_agg = 100.0;
444 const char *bw_str = "KB";
445 char tmp[32];
446
447 if (rs->agg[ddir]) {
Jens Axboee0681f32012-03-06 12:14:42 +0100448 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
Jens Axboeca850992012-03-05 20:04:43 +0100449 if (p_of_agg > 100.0)
450 p_of_agg = 100.0;
451 }
452
Jens Axboee0681f32012-03-06 12:14:42 +0100453 if (mean[0] > 999999.9) {
454 min[0] /= 1000.0;
455 max[0] /= 1000.0;
456 mean[0] /= 1000.0;
457 dev[0] /= 1000.0;
Jens Axboeca850992012-03-05 20:04:43 +0100458 bw_str = "MB";
459 }
460
Jens Axboe0b761302012-03-05 20:44:11 +0100461 sprintf(tmp, "Bandwidth (%s)", bw_str);
462 frame = gtk_frame_new(tmp);
463 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
Jens Axboeca850992012-03-05 20:04:43 +0100464
Jens Axboe0b761302012-03-05 20:44:11 +0100465 box = gtk_hbox_new(FALSE, 3);
466 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboeca850992012-03-05 20:04:43 +0100467
Jens Axboe0b761302012-03-05 20:44:11 +0100468 label = new_info_label_in_frame(box, "Minimum");
Jens Axboee0681f32012-03-06 12:14:42 +0100469 label_set_int_value(label, min[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100470 label = new_info_label_in_frame(box, "Maximum");
Jens Axboee0681f32012-03-06 12:14:42 +0100471 label_set_int_value(label, max[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100472 label = new_info_label_in_frame(box, "Percentage of jobs");
Jens Axboeca850992012-03-05 20:04:43 +0100473 sprintf(tmp, "%3.2f%%", p_of_agg);
474 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100475 label = new_info_label_in_frame(box, "Average");
Jens Axboee0681f32012-03-06 12:14:42 +0100476 sprintf(tmp, "%5.02f", mean[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100477 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100478 label = new_info_label_in_frame(box, "Standard deviation");
Jens Axboee0681f32012-03-06 12:14:42 +0100479 sprintf(tmp, "%5.02f", dev[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100480 gtk_label_set_text(GTK_LABEL(label), tmp);
481 }
482
Jens Axboee0681f32012-03-06 12:14:42 +0100483 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
Jens Axboe2b089892012-03-06 08:09:17 +0100484 flags |= GFIO_SLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100485 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
Jens Axboe2b089892012-03-06 08:09:17 +0100486 flags |= GFIO_CLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100487 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
Jens Axboe2b089892012-03-06 08:09:17 +0100488 flags |= GFIO_LAT;
489
490 if (flags) {
491 frame = gtk_frame_new("Latency");
492 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
493
494 vbox = gtk_vbox_new(FALSE, 3);
495 gtk_container_add(GTK_CONTAINER(frame), vbox);
496
497 if (flags & GFIO_SLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100498 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
Jens Axboe2b089892012-03-06 08:09:17 +0100499 if (flags & GFIO_CLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100500 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
Jens Axboe2b089892012-03-06 08:09:17 +0100501 if (flags & GFIO_LAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100502 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
Jens Axboe2b089892012-03-06 08:09:17 +0100503 }
504
505 if (ts->clat_percentiles)
506 gfio_show_clat_percentiles(main_vbox, ts, ddir);
507
508
Jens Axboe3650a3c2012-03-05 14:09:03 +0100509 free(io_p);
510 free(bw_p);
511 free(iops_p);
512}
513
Jens Axboee5bd1342012-03-05 21:38:12 +0100514static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
515 const char **labels)
516{
517 GtkWidget *tree_view;
518 GtkTreeSelection *selection;
519 GtkListStore *model;
520 GtkTreeIter iter;
521 GType *types;
522 int i, skipped;
523
524 /*
525 * Check if all are empty, in which case don't bother
526 */
527 for (i = 0, skipped = 0; i < num; i++)
528 if (lat[i] <= 0.0)
529 skipped++;
530
531 if (skipped == num)
532 return NULL;
533
534 types = malloc(num * sizeof(GType));
535
536 for (i = 0; i < num; i++)
537 types[i] = G_TYPE_STRING;
538
539 model = gtk_list_store_newv(num, types);
540 free(types);
541 types = NULL;
542
543 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
544 gtk_widget_set_can_focus(tree_view, FALSE);
545
546 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
547 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
548
549 for (i = 0; i < num; i++)
550 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
551
552 gtk_list_store_append(model, &iter);
553
554 for (i = 0; i < num; i++) {
555 char fbuf[32];
556
557 if (lat[i] <= 0.0)
558 sprintf(fbuf, "0.00");
559 else
560 sprintf(fbuf, "%3.2f%%", lat[i]);
561
562 gtk_list_store_set(model, &iter, i, fbuf, -1);
563 }
564
565 return tree_view;
566}
567
568static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
569{
570 GtkWidget *box, *frame, *tree_view;
571 double io_u_lat_u[FIO_IO_U_LAT_U_NR];
572 double io_u_lat_m[FIO_IO_U_LAT_M_NR];
573 const char *uranges[] = { "2", "4", "10", "20", "50", "100",
574 "250", "500", "750", "1000", };
575 const char *mranges[] = { "2", "4", "10", "20", "50", "100",
576 "250", "500", "750", "1000", "2000",
577 ">= 2000", };
578
579 stat_calc_lat_u(ts, io_u_lat_u);
580 stat_calc_lat_m(ts, io_u_lat_m);
581
582 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
583 if (tree_view) {
584 frame = gtk_frame_new("Latency buckets (usec)");
585 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
586
587 box = gtk_hbox_new(FALSE, 3);
588 gtk_container_add(GTK_CONTAINER(frame), box);
589 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
590 }
591
592 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
593 if (tree_view) {
594 frame = gtk_frame_new("Latency buckets (msec)");
595 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
596
597 box = gtk_hbox_new(FALSE, 3);
598 gtk_container_add(GTK_CONTAINER(frame), box);
599 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
600 }
601}
602
Jens Axboe2e331012012-03-05 22:07:54 +0100603static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
604{
605 GtkWidget *box, *frame, *entry;
606 double usr_cpu, sys_cpu;
607 unsigned long runtime;
608 char tmp[32];
609
610 runtime = ts->total_run_time;
611 if (runtime) {
612 double runt = (double) runtime;
613
614 usr_cpu = (double) ts->usr_time * 100 / runt;
615 sys_cpu = (double) ts->sys_time * 100 / runt;
616 } else {
617 usr_cpu = 0;
618 sys_cpu = 0;
619 }
620
621 frame = gtk_frame_new("OS resources");
622 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
623
624 box = gtk_hbox_new(FALSE, 3);
625 gtk_container_add(GTK_CONTAINER(frame), box);
626
627 entry = new_info_entry_in_frame(box, "User CPU");
628 sprintf(tmp, "%3.2f%%", usr_cpu);
629 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
630 entry = new_info_entry_in_frame(box, "System CPU");
631 sprintf(tmp, "%3.2f%%", sys_cpu);
632 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
633 entry = new_info_entry_in_frame(box, "Context switches");
634 entry_set_int_value(entry, ts->ctx);
635 entry = new_info_entry_in_frame(box, "Major faults");
636 entry_set_int_value(entry, ts->majf);
637 entry = new_info_entry_in_frame(box, "Minor faults");
638 entry_set_int_value(entry, ts->minf);
639}
Jens Axboe19998db2012-03-06 09:17:59 +0100640static void gfio_add_sc_depths_tree(GtkListStore *model,
641 struct thread_stat *ts, unsigned int len,
642 int submit)
643{
644 double io_u_dist[FIO_IO_U_MAP_NR];
645 GtkTreeIter iter;
646 /* Bits 0, and 3-8 */
647 const int add_mask = 0x1f9;
648 int i, j;
649
650 if (submit)
651 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
652 else
653 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
654
655 gtk_list_store_append(model, &iter);
656
657 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
658
659 for (i = 1, j = 0; i < len; i++) {
660 char fbuf[32];
661
662 if (!(add_mask & (1UL << (i - 1))))
663 sprintf(fbuf, "0.0%%");
664 else {
665 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
666 j++;
667 }
668
669 gtk_list_store_set(model, &iter, i, fbuf, -1);
670 }
671
672}
673
674static void gfio_add_total_depths_tree(GtkListStore *model,
675 struct thread_stat *ts, unsigned int len)
676{
677 double io_u_dist[FIO_IO_U_MAP_NR];
678 GtkTreeIter iter;
679 /* Bits 1-6, and 8 */
680 const int add_mask = 0x17e;
681 int i, j;
682
683 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
684
685 gtk_list_store_append(model, &iter);
686
687 gtk_list_store_set(model, &iter, 0, "Total", -1);
688
689 for (i = 1, j = 0; i < len; i++) {
690 char fbuf[32];
691
692 if (!(add_mask & (1UL << (i - 1))))
693 sprintf(fbuf, "0.0%%");
694 else {
695 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
696 j++;
697 }
698
699 gtk_list_store_set(model, &iter, i, fbuf, -1);
700 }
701
702}
Jens Axboe2e331012012-03-05 22:07:54 +0100703
704static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
705{
Jens Axboe2e331012012-03-05 22:07:54 +0100706 GtkWidget *frame, *box, *tree_view;
707 GtkTreeSelection *selection;
708 GtkListStore *model;
Jens Axboe2e331012012-03-05 22:07:54 +0100709 GType types[FIO_IO_U_MAP_NR + 1];
710 int i;
Jens Axboe19998db2012-03-06 09:17:59 +0100711#define NR_LABELS 10
712 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
Jens Axboe2e331012012-03-05 22:07:54 +0100713
714 frame = gtk_frame_new("IO depths");
715 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
716
717 box = gtk_hbox_new(FALSE, 3);
718 gtk_container_add(GTK_CONTAINER(frame), box);
719
Jens Axboe19998db2012-03-06 09:17:59 +0100720 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100721 types[i] = G_TYPE_STRING;
722
Jens Axboe19998db2012-03-06 09:17:59 +0100723 model = gtk_list_store_newv(NR_LABELS, types);
Jens Axboe2e331012012-03-05 22:07:54 +0100724
725 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
726 gtk_widget_set_can_focus(tree_view, FALSE);
727
728 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
729 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
730
Jens Axboe19998db2012-03-06 09:17:59 +0100731 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100732 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
733
Jens Axboe19998db2012-03-06 09:17:59 +0100734 gfio_add_total_depths_tree(model, ts, NR_LABELS);
735 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 1);
736 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 0);
Jens Axboe2e331012012-03-05 22:07:54 +0100737
738 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
739}
740
Jens Axboef9d40b42012-03-06 09:52:49 +0100741static gboolean results_window_delete(GtkWidget *w, gpointer data)
742{
743 struct gui *ui = (struct gui *) data;
744
745 gtk_widget_destroy(w);
746 ui->results_window = NULL;
747 ui->results_notebook = NULL;
748 return TRUE;
749}
750
751static GtkWidget *get_results_window(struct gui *ui)
752{
753 GtkWidget *win, *notebook;
754
755 if (ui->results_window)
756 return ui->results_notebook;
757
758 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
759 gtk_window_set_title(GTK_WINDOW(win), "Results");
760 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ui);
761 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ui);
762
763 notebook = gtk_notebook_new();
764 gtk_container_add(GTK_CONTAINER(win), notebook);
765
766 ui->results_window = win;
767 ui->results_notebook = notebook;
768 return ui->results_notebook;
769}
770
Jens Axboe3650a3c2012-03-05 14:09:03 +0100771static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
772 struct group_run_stats *rs)
773{
Jens Axboef9d40b42012-03-06 09:52:49 +0100774 GtkWidget *res_win, *box, *vbox, *entry;
Jens Axboee0681f32012-03-06 12:14:42 +0100775 struct gfio_client *gc = client->client_data;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100776
777 gdk_threads_enter();
778
Jens Axboee0681f32012-03-06 12:14:42 +0100779 res_win = get_results_window(gc->ui);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100780
781 vbox = gtk_vbox_new(FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100782
783 box = gtk_hbox_new(TRUE, 3);
784 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
785
Jens Axboef9d40b42012-03-06 09:52:49 +0100786 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), vbox, gtk_label_new(ts->name));
787
Jens Axboee0681f32012-03-06 12:14:42 +0100788 gc->results_widget = vbox;
789
Jens Axboe3650a3c2012-03-05 14:09:03 +0100790 entry = new_info_entry_in_frame(box, "Name");
791 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
792 if (strlen(ts->description)) {
793 entry = new_info_entry_in_frame(box, "Description");
794 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
795 }
796 entry = new_info_entry_in_frame(box, "Group ID");
797 entry_set_int_value(entry, ts->groupid);
798 entry = new_info_entry_in_frame(box, "Jobs");
799 entry_set_int_value(entry, ts->members);
800 entry = new_info_entry_in_frame(box, "Error");
801 entry_set_int_value(entry, ts->error);
802 entry = new_info_entry_in_frame(box, "PID");
803 entry_set_int_value(entry, ts->pid);
804
805 if (ts->io_bytes[DDIR_READ])
806 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
807 if (ts->io_bytes[DDIR_WRITE])
808 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
809
Jens Axboee5bd1342012-03-05 21:38:12 +0100810 gfio_show_latency_buckets(vbox, ts);
Jens Axboe2e331012012-03-05 22:07:54 +0100811 gfio_show_cpu_usage(vbox, ts);
812 gfio_show_io_depths(vbox, ts);
Jens Axboee5bd1342012-03-05 21:38:12 +0100813
Jens Axboee0681f32012-03-06 12:14:42 +0100814 gtk_widget_show_all(gc->ui->results_window);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100815 gdk_threads_leave();
816}
817
Jens Axboe084d1c62012-03-03 20:28:07 +0100818static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100819{
Jens Axboe9b260bd2012-03-06 11:02:52 +0100820 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +0100821 struct gfio_client *gc = client->client_data;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100822 GtkTreeIter iter;
823 struct tm *tm;
824 time_t sec;
825 char tmp[64], timebuf[80];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100826
Jens Axboe9b260bd2012-03-06 11:02:52 +0100827 sec = p->log_sec;
828 tm = localtime(&sec);
829 strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", tm);
830 sprintf(timebuf, "%s.%03ld", tmp, p->log_usec / 1000);
831
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100832 gdk_threads_enter();
Jens Axboe9b260bd2012-03-06 11:02:52 +0100833
Jens Axboee0681f32012-03-06 12:14:42 +0100834 gtk_list_store_append(gc->ui->log_model, &iter);
835 gtk_list_store_set(gc->ui->log_model, &iter, 0, timebuf, -1);
836 gtk_list_store_set(gc->ui->log_model, &iter, 1, client->hostname, -1);
837 gtk_list_store_set(gc->ui->log_model, &iter, 2, p->level, -1);
838 gtk_list_store_set(gc->ui->log_model, &iter, 3, p->buf, -1);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100839
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100840 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100841}
842
843static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
844{
Jens Axboee0681f32012-03-06 12:14:42 +0100845 struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
846 struct gfio_client *gc = client->client_data;
847 GtkWidget *box, *frame, *entry, *vbox;
848
Jens Axboe0050e5f2012-03-06 09:23:27 +0100849 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +0100850
851 if (!gc->results_widget) {
852 printf("no results!\n");
853 goto out;
854 }
855
856 if (!gc->disk_util_frame) {
857 gc->disk_util_frame = gtk_frame_new("Disk utilization");
858 gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
859 }
860
861 vbox = gtk_vbox_new(FALSE, 3);
862 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
863
864 frame = gtk_frame_new((char *) p->dus.name);
865 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
866
867 box = gtk_vbox_new(FALSE, 3);
868 gtk_container_add(GTK_CONTAINER(frame), box);
869
870 frame = gtk_frame_new("Read");
871 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
872 vbox = gtk_hbox_new(TRUE, 3);
873 gtk_container_add(GTK_CONTAINER(frame), vbox);
874 entry = new_info_entry_in_frame(vbox, "IOs");
875 entry_set_int_value(entry, p->dus.ios[0]);
876 entry = new_info_entry_in_frame(vbox, "Merges");
877 entry_set_int_value(entry, p->dus.merges[0]);
878 entry = new_info_entry_in_frame(vbox, "Sectors");
879 entry_set_int_value(entry, p->dus.sectors[0]);
880 entry = new_info_entry_in_frame(vbox, "Ticks");
881 entry_set_int_value(entry, p->dus.ticks[0]);
882
883 frame = gtk_frame_new("Write");
884 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
885 vbox = gtk_hbox_new(TRUE, 3);
886 gtk_container_add(GTK_CONTAINER(frame), vbox);
887 entry = new_info_entry_in_frame(vbox, "IOs");
888 entry_set_int_value(entry, p->dus.ios[1]);
889 entry = new_info_entry_in_frame(vbox, "Merges");
890 entry_set_int_value(entry, p->dus.merges[1]);
891 entry = new_info_entry_in_frame(vbox, "Sectors");
892 entry_set_int_value(entry, p->dus.sectors[1]);
893 entry = new_info_entry_in_frame(vbox, "Ticks");
894 entry_set_int_value(entry, p->dus.ticks[1]);
895
896 frame = gtk_frame_new("Shared");
897 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
898 vbox = gtk_hbox_new(TRUE, 3);
899 gtk_container_add(GTK_CONTAINER(frame), vbox);
900 entry = new_info_entry_in_frame(vbox, "IO ticks");
901 entry_set_int_value(entry, p->dus.io_ticks);
902 entry = new_info_entry_in_frame(vbox, "Time in queue");
903 entry_set_int_value(entry, p->dus.time_in_queue);
904
905 gtk_widget_show_all(gc->results_widget);
906out:
Jens Axboe0050e5f2012-03-06 09:23:27 +0100907 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100908}
909
Jens Axboe3650a3c2012-03-05 14:09:03 +0100910extern int sum_stat_clients;
911extern struct thread_stat client_ts;
912extern struct group_run_stats client_gs;
913
914static int sum_stat_nr;
915
Jens Axboe89e5fad2012-03-05 09:21:12 +0100916static void gfio_thread_status_op(struct fio_client *client,
917 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100918{
Jens Axboe3650a3c2012-03-05 14:09:03 +0100919 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
920
921 gfio_display_ts(client, &p->ts, &p->rs);
922
923 if (sum_stat_clients == 1)
924 return;
925
926 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
927 sum_group_stats(&client_gs, &p->rs);
928
929 client_ts.members++;
930 client_ts.groupid = p->ts.groupid;
931
932 if (++sum_stat_nr == sum_stat_clients) {
933 strcpy(client_ts.name, "All clients");
934 gfio_display_ts(client, &client_ts, &client_gs);
935 }
Stephen M. Camerona1820202012-02-24 08:17:31 +0100936}
937
Jens Axboe89e5fad2012-03-05 09:21:12 +0100938static void gfio_group_stats_op(struct fio_client *client,
939 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100940{
Jens Axboe0050e5f2012-03-06 09:23:27 +0100941 gdk_threads_enter();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100942 printf("gfio_group_stats_op called\n");
Jens Axboe89e5fad2012-03-05 09:21:12 +0100943 fio_client_ops.group_stats(client, cmd);
Jens Axboe0050e5f2012-03-06 09:23:27 +0100944 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100945}
946
Jens Axboe3e47bd22012-02-29 13:45:02 +0100947static void gfio_update_eta(struct jobs_eta *je)
948{
949 static int eta_good;
950 char eta_str[128];
951 char output[256];
952 char tmp[32];
953 double perc = 0.0;
954 int i2p = 0;
955
Jens Axboe0050e5f2012-03-06 09:23:27 +0100956 gdk_threads_enter();
957
Jens Axboe3e47bd22012-02-29 13:45:02 +0100958 eta_str[0] = '\0';
959 output[0] = '\0';
960
961 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
962 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
963 eta_to_str(eta_str, je->eta_sec);
964 }
965
966 sprintf(tmp, "%u", je->nr_running);
Jens Axboeca850992012-03-05 20:04:43 +0100967 gtk_entry_set_text(GTK_ENTRY(ui.eta.jobs), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +0100968 sprintf(tmp, "%u", je->files_open);
Jens Axboeca850992012-03-05 20:04:43 +0100969 gtk_entry_set_text(GTK_ENTRY(ui.eta.files), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +0100970
971#if 0
972 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
973 if (je->m_rate || je->t_rate) {
974 char *tr, *mr;
975
976 mr = num2str(je->m_rate, 4, 0, i2p);
977 tr = num2str(je->t_rate, 4, 0, i2p);
Jens Axboeca850992012-03-05 20:04:43 +0100978 gtk_entry_set_text(GTK_ENTRY(ui.eta);
Jens Axboe3e47bd22012-02-29 13:45:02 +0100979 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
980 free(tr);
981 free(mr);
982 } else if (je->m_iops || je->t_iops)
983 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
Jens Axboeebbd89c2012-03-02 11:21:13 +0100984
Jens Axboeca850992012-03-05 20:04:43 +0100985 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_bw), "---");
986 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_iops), "---");
987 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_bw), "---");
988 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_iops), "---");
Jens Axboe3e47bd22012-02-29 13:45:02 +0100989#endif
990
991 if (je->eta_sec != INT_MAX && je->nr_running) {
992 char *iops_str[2];
993 char *rate_str[2];
994
995 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
996 strcpy(output, "-.-% done");
997 else {
998 eta_good = 1;
999 perc *= 100.0;
1000 sprintf(output, "%3.1f%% done", perc);
1001 }
1002
1003 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1004 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1005
1006 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1007 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1008
Jens Axboeca850992012-03-05 20:04:43 +01001009 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_bw), rate_str[0]);
1010 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_iops), iops_str[0]);
1011 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_bw), rate_str[1]);
1012 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_iops), iops_str[1]);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001013
1014 free(rate_str[0]);
1015 free(rate_str[1]);
1016 free(iops_str[0]);
1017 free(iops_str[1]);
1018 }
1019
1020 if (eta_str[0]) {
1021 char *dst = output + strlen(output);
1022
1023 sprintf(dst, " - %s", eta_str);
1024 }
1025
1026 gfio_update_thread_status(output, perc);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001027 gdk_threads_leave();
Jens Axboe3e47bd22012-02-29 13:45:02 +01001028}
1029
Stephen M. Camerona1820202012-02-24 08:17:31 +01001030static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1031{
Jens Axboe843ad232012-02-29 11:44:53 +01001032 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001033 struct gfio_client *gc = client->client_data;
1034 struct gui *ui = gc->ui;
Jens Axboe843ad232012-02-29 11:44:53 +01001035 const char *os, *arch;
1036 char buf[64];
1037
1038 os = fio_get_os_string(probe->os);
1039 if (!os)
1040 os = "unknown";
1041
1042 arch = fio_get_arch_string(probe->arch);
1043 if (!arch)
1044 os = "unknown";
1045
1046 if (!client->name)
1047 client->name = strdup((char *) probe->hostname);
1048
Jens Axboe0050e5f2012-03-06 09:23:27 +01001049 gdk_threads_enter();
1050
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001051 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), (char *) probe->hostname);
1052 gtk_label_set_text(GTK_LABEL(ui->probe.os), os);
1053 gtk_label_set_text(GTK_LABEL(ui->probe.arch), arch);
Jens Axboe843ad232012-02-29 11:44:53 +01001054 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001055 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), buf);
1056
1057 gfio_set_connected(ui, 1);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001058
1059 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001060}
1061
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001062static void gfio_update_thread_status(char *status_message, double perc)
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001063{
1064 static char message[100];
1065 const char *m = message;
1066
1067 strncpy(message, status_message, sizeof(message) - 1);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001068 gtk_progress_bar_set_text(
1069 GTK_PROGRESS_BAR(ui.thread_status_pb), m);
1070 gtk_progress_bar_set_fraction(
1071 GTK_PROGRESS_BAR(ui.thread_status_pb), perc / 100.0);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001072 gtk_widget_queue_draw(ui.window);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001073}
1074
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001075static void gfio_quit_op(struct fio_client *client)
1076{
Jens Axboee0681f32012-03-06 12:14:42 +01001077 struct gfio_client *gc = client->client_data;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001078
Jens Axboe0050e5f2012-03-06 09:23:27 +01001079 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +01001080 gfio_set_connected(gc->ui, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001081 gdk_threads_leave();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001082}
1083
Jens Axboe807f9972012-03-02 10:25:24 +01001084static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1085{
1086 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +01001087 struct gfio_client *gc = client->client_data;
1088 struct gui *ui = gc->ui;
Jens Axboe807f9972012-03-02 10:25:24 +01001089 char tmp[8];
1090 int i;
1091
1092 p->iodepth = le32_to_cpu(p->iodepth);
1093 p->rw = le32_to_cpu(p->rw);
1094
1095 for (i = 0; i < 2; i++) {
1096 p->min_bs[i] = le32_to_cpu(p->min_bs[i]);
1097 p->max_bs[i] = le32_to_cpu(p->max_bs[i]);
1098 }
1099
1100 p->numjobs = le32_to_cpu(p->numjobs);
1101 p->group_reporting = le32_to_cpu(p->group_reporting);
1102
Jens Axboe0050e5f2012-03-06 09:23:27 +01001103 gdk_threads_enter();
1104
Jens Axboeca850992012-03-05 20:04:43 +01001105 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), (gchar *) p->jobname);
1106 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), ddir_str(p->rw));
1107 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), (gchar *) p->ioengine);
Jens Axboe807f9972012-03-02 10:25:24 +01001108
1109 sprintf(tmp, "%u", p->iodepth);
Jens Axboeca850992012-03-05 20:04:43 +01001110 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), tmp);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001111
1112 gdk_threads_leave();
Jens Axboe807f9972012-03-02 10:25:24 +01001113}
1114
Jens Axboeed727a42012-03-02 12:14:40 +01001115static void gfio_client_timed_out(struct fio_client *client)
1116{
Jens Axboee0681f32012-03-06 12:14:42 +01001117 struct gfio_client *gc = client->client_data;
Jens Axboeed727a42012-03-02 12:14:40 +01001118 GtkWidget *dialog, *label, *content;
1119 char buf[256];
1120
1121 gdk_threads_enter();
1122
Jens Axboee0681f32012-03-06 12:14:42 +01001123 gfio_set_connected(gc->ui, 0);
1124 clear_ui_info(gc->ui);
Jens Axboeed727a42012-03-02 12:14:40 +01001125
1126 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
1127
1128 dialog = gtk_dialog_new_with_buttons("Timed out!",
Jens Axboee0681f32012-03-06 12:14:42 +01001129 GTK_WINDOW(gc->ui->window),
Jens Axboeed727a42012-03-02 12:14:40 +01001130 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1131 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1132
1133 content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1134 label = gtk_label_new((const gchar *) buf);
1135 gtk_container_add(GTK_CONTAINER(content), label);
1136 gtk_widget_show_all(dialog);
1137 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1138
1139 gtk_dialog_run(GTK_DIALOG(dialog));
1140 gtk_widget_destroy(dialog);
1141
1142 gdk_threads_leave();
1143}
1144
Stephen M. Camerona1820202012-02-24 08:17:31 +01001145struct client_ops gfio_client_ops = {
Jens Axboe0420ba62012-02-29 11:16:52 +01001146 .text_op = gfio_text_op,
1147 .disk_util = gfio_disk_util_op,
1148 .thread_status = gfio_thread_status_op,
1149 .group_stats = gfio_group_stats_op,
Jens Axboea5276612012-03-04 15:15:08 +01001150 .eta = gfio_update_eta,
Jens Axboe0420ba62012-02-29 11:16:52 +01001151 .probe = gfio_probe_op,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001152 .quit = gfio_quit_op,
Jens Axboe807f9972012-03-02 10:25:24 +01001153 .add_job = gfio_add_job_op,
Jens Axboeed727a42012-03-02 12:14:40 +01001154 .timed_out = gfio_client_timed_out,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001155 .stay_connected = 1,
Stephen M. Camerona1820202012-02-24 08:17:31 +01001156};
1157
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001158static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1159 __attribute__((unused)) gpointer data)
1160{
1161 gtk_main_quit();
1162}
1163
Stephen M. Cameron25927252012-02-24 08:17:31 +01001164static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001165{
Stephen M. Cameron25927252012-02-24 08:17:31 +01001166 fio_handle_clients(&gfio_client_ops);
Stephen M. Cameron25927252012-02-24 08:17:31 +01001167 return NULL;
1168}
1169
Jens Axboe0420ba62012-02-29 11:16:52 +01001170static int send_job_files(struct gui *ui)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001171{
Jens Axboe441013b2012-03-01 08:01:52 +01001172 int i, ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001173
Jens Axboe0420ba62012-02-29 11:16:52 +01001174 for (i = 0; i < ui->nr_job_files; i++) {
1175 ret = fio_clients_send_ini(ui->job_files[i]);
Jens Axboe441013b2012-03-01 08:01:52 +01001176 if (ret)
1177 break;
1178
Jens Axboe0420ba62012-02-29 11:16:52 +01001179 free(ui->job_files[i]);
1180 ui->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001181 }
1182 while (i < ui->nr_job_files) {
1183 free(ui->job_files[i]);
1184 ui->job_files[i] = NULL;
1185 i++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001186 }
1187
Jens Axboe441013b2012-03-01 08:01:52 +01001188 return ret;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001189}
1190
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001191static void start_job_thread(struct gui *ui)
Stephen M. Cameron25927252012-02-24 08:17:31 +01001192{
Jens Axboe0420ba62012-02-29 11:16:52 +01001193 if (send_job_files(ui)) {
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001194 printf("Yeah, I didn't really like those options too much.\n");
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001195 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
1196 return;
1197 }
Stephen M. Cameron25927252012-02-24 08:17:31 +01001198}
1199
1200static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1201 gpointer data)
1202{
1203 struct gui *ui = data;
1204
Stephen M. Cameron25927252012-02-24 08:17:31 +01001205 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001206 start_job_thread(ui);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001207}
1208
Jens Axboedf06f222012-03-02 13:32:04 +01001209static void file_open(GtkWidget *w, gpointer data);
1210
1211static void connect_clicked(GtkWidget *widget, gpointer data)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001212{
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001213 struct gui *ui = data;
1214
1215 if (!ui->connected) {
Jens Axboedf06f222012-03-02 13:32:04 +01001216 if (!ui->nr_job_files)
1217 file_open(widget, data);
Jens Axboe8663ea62012-03-02 14:04:30 +01001218 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001219 fio_clients_connect();
1220 pthread_create(&ui->t, NULL, job_thread, NULL);
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001221 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 0);
Jens Axboedf06f222012-03-02 13:32:04 +01001222 } else {
1223 fio_clients_terminate();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001224 gfio_set_connected(ui, 0);
Jens Axboe88432652012-03-02 19:09:31 +01001225 clear_ui_info(ui);
Jens Axboedf06f222012-03-02 13:32:04 +01001226 }
Jens Axboe3e47bd22012-02-29 13:45:02 +01001227}
1228
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001229static void add_button(struct gui *ui, int i, GtkWidget *buttonbox,
1230 struct button_spec *buttonspec)
1231{
1232 ui->button[i] = gtk_button_new_with_label(buttonspec->buttontext);
1233 g_signal_connect(ui->button[i], "clicked", G_CALLBACK (buttonspec->f), ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001234 gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], FALSE, FALSE, 3);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001235 gtk_widget_set_tooltip_text(ui->button[i], buttonspeclist[i].tooltiptext);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001236 gtk_widget_set_sensitive(ui->button[i], !buttonspec->start_insensitive);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001237}
1238
1239static void add_buttons(struct gui *ui,
1240 struct button_spec *buttonlist,
1241 int nbuttons)
1242{
1243 int i;
1244
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001245 for (i = 0; i < nbuttons; i++)
1246 add_button(ui, i, ui->buttonbox, &buttonlist[i]);
1247}
1248
Jens Axboe0420ba62012-02-29 11:16:52 +01001249static void on_info_bar_response(GtkWidget *widget, gint response,
1250 gpointer data)
1251{
1252 if (response == GTK_RESPONSE_OK) {
1253 gtk_widget_destroy(widget);
1254 ui.error_info_bar = NULL;
1255 }
1256}
1257
Jens Axboedf06f222012-03-02 13:32:04 +01001258void report_error(GError *error)
Jens Axboe0420ba62012-02-29 11:16:52 +01001259{
1260 if (ui.error_info_bar == NULL) {
1261 ui.error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
1262 GTK_RESPONSE_OK,
1263 NULL);
1264 g_signal_connect(ui.error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1265 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui.error_info_bar),
1266 GTK_MESSAGE_ERROR);
1267
1268 ui.error_label = gtk_label_new(error->message);
1269 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui.error_info_bar));
1270 gtk_container_add(GTK_CONTAINER(container), ui.error_label);
1271
1272 gtk_box_pack_start(GTK_BOX(ui.vbox), ui.error_info_bar, FALSE, FALSE, 0);
1273 gtk_widget_show_all(ui.vbox);
1274 } else {
1275 char buffer[256];
1276 snprintf(buffer, sizeof(buffer), "Failed to open file.");
1277 gtk_label_set(GTK_LABEL(ui.error_label), buffer);
1278 }
1279}
1280
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001281static int get_connection_details(char **host, int *port, int *type,
1282 int *server_start)
Jens Axboea7a42ce2012-03-02 13:12:04 +01001283{
1284 GtkWidget *dialog, *box, *vbox, *hentry, *hbox, *frame, *pentry, *combo;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001285 GtkWidget *button;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001286 char *typeentry;
1287
1288 dialog = gtk_dialog_new_with_buttons("Connection details",
1289 GTK_WINDOW(ui.window),
1290 GTK_DIALOG_DESTROY_WITH_PARENT,
1291 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1292 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1293
1294 frame = gtk_frame_new("Hostname / socket name");
1295 vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1296 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1297
1298 box = gtk_vbox_new(FALSE, 6);
1299 gtk_container_add(GTK_CONTAINER(frame), box);
1300
1301 hbox = gtk_hbox_new(TRUE, 10);
1302 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1303 hentry = gtk_entry_new();
1304 gtk_entry_set_text(GTK_ENTRY(hentry), "localhost");
1305 gtk_box_pack_start(GTK_BOX(hbox), hentry, TRUE, TRUE, 0);
1306
1307 frame = gtk_frame_new("Port");
1308 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1309 box = gtk_vbox_new(FALSE, 10);
1310 gtk_container_add(GTK_CONTAINER(frame), box);
1311
1312 hbox = gtk_hbox_new(TRUE, 4);
1313 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1314 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1315
1316 frame = gtk_frame_new("Type");
1317 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1318 box = gtk_vbox_new(FALSE, 10);
1319 gtk_container_add(GTK_CONTAINER(frame), box);
1320
1321 hbox = gtk_hbox_new(TRUE, 4);
1322 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1323
1324 combo = gtk_combo_box_text_new();
1325 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "IPv4");
1326 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "IPv6");
1327 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "local socket");
1328 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
1329
1330 gtk_container_add(GTK_CONTAINER(hbox), combo);
1331
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001332 frame = gtk_frame_new("Options");
1333 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1334 box = gtk_vbox_new(FALSE, 10);
1335 gtk_container_add(GTK_CONTAINER(frame), box);
1336
1337 hbox = gtk_hbox_new(TRUE, 4);
1338 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1339
1340 button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1341 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), 1);
1342 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.");
1343 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 6);
1344
Jens Axboea7a42ce2012-03-02 13:12:04 +01001345 gtk_widget_show_all(dialog);
1346
1347 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1348 gtk_widget_destroy(dialog);
1349 return 1;
1350 }
1351
1352 *host = strdup(gtk_entry_get_text(GTK_ENTRY(hentry)));
1353 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1354
1355 typeentry = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
1356 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1357 *type = Fio_client_ipv4;
1358 else if (!strncmp(typeentry, "IPv6", 4))
1359 *type = Fio_client_ipv6;
1360 else
1361 *type = Fio_client_socket;
1362 g_free(typeentry);
1363
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001364 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
1365
Jens Axboea7a42ce2012-03-02 13:12:04 +01001366 gtk_widget_destroy(dialog);
1367 return 0;
1368}
1369
Jens Axboee0681f32012-03-06 12:14:42 +01001370static void gfio_client_added(struct gui *ui, struct fio_client *client)
1371{
1372 struct gfio_client *gc;
1373
1374 gc = malloc(sizeof(*gc));
1375 memset(gc, 0, sizeof(*gc));
1376 gc->ui = ui;
1377
1378 client->client_data = gc;
1379}
1380
Jens Axboe0420ba62012-02-29 11:16:52 +01001381static void file_open(GtkWidget *w, gpointer data)
1382{
1383 GtkWidget *dialog;
1384 GSList *filenames, *fn_glist;
1385 GtkFileFilter *filter;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001386 char *host;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001387 int port, type, server_start;
Jens Axboe0420ba62012-02-29 11:16:52 +01001388
1389 dialog = gtk_file_chooser_dialog_new("Open File",
1390 GTK_WINDOW(ui.window),
1391 GTK_FILE_CHOOSER_ACTION_OPEN,
1392 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1393 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1394 NULL);
1395 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1396
1397 filter = gtk_file_filter_new();
1398 gtk_file_filter_add_pattern(filter, "*.fio");
1399 gtk_file_filter_add_pattern(filter, "*.job");
1400 gtk_file_filter_add_mime_type(filter, "text/fio");
1401 gtk_file_filter_set_name(filter, "Fio job file");
1402 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
1403
1404 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1405 gtk_widget_destroy(dialog);
1406 return;
1407 }
1408
1409 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001410
1411 gtk_widget_destroy(dialog);
1412
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001413 if (get_connection_details(&host, &port, &type, &server_start))
Jens Axboea7a42ce2012-03-02 13:12:04 +01001414 goto err;
1415
Jens Axboe0420ba62012-02-29 11:16:52 +01001416 filenames = fn_glist;
1417 while (filenames != NULL) {
Jens Axboee0681f32012-03-06 12:14:42 +01001418 struct fio_client *client;
1419
Jens Axboe0420ba62012-02-29 11:16:52 +01001420 ui.job_files = realloc(ui.job_files, (ui.nr_job_files + 1) * sizeof(char *));
1421 ui.job_files[ui.nr_job_files] = strdup(filenames->data);
1422 ui.nr_job_files++;
1423
Jens Axboee0681f32012-03-06 12:14:42 +01001424 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
1425 if (!client) {
Jens Axboedf06f222012-03-02 13:32:04 +01001426 GError *error;
1427
1428 error = g_error_new(g_quark_from_string("fio"), 1,
1429 "Failed to add client %s", host);
Jens Axboe0420ba62012-02-29 11:16:52 +01001430 report_error(error);
1431 g_error_free(error);
Jens Axboe0420ba62012-02-29 11:16:52 +01001432 }
Jens Axboee0681f32012-03-06 12:14:42 +01001433 gfio_client_added(&ui, client);
Jens Axboe0420ba62012-02-29 11:16:52 +01001434
1435 g_free(filenames->data);
1436 filenames = g_slist_next(filenames);
1437 }
Jens Axboea7a42ce2012-03-02 13:12:04 +01001438 free(host);
1439err:
Jens Axboe0420ba62012-02-29 11:16:52 +01001440 g_slist_free(fn_glist);
Jens Axboe0420ba62012-02-29 11:16:52 +01001441}
1442
1443static void file_save(GtkWidget *w, gpointer data)
1444{
1445 GtkWidget *dialog;
1446
1447 dialog = gtk_file_chooser_dialog_new("Save File",
1448 GTK_WINDOW(ui.window),
1449 GTK_FILE_CHOOSER_ACTION_SAVE,
1450 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1451 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1452 NULL);
1453
1454 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1455 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
1456
1457 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1458 char *filename;
1459
1460 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1461 // save_job_file(filename);
1462 g_free(filename);
1463 }
1464 gtk_widget_destroy(dialog);
1465}
1466
Jens Axboe9b260bd2012-03-06 11:02:52 +01001467static void view_log_destroy(GtkWidget *w, gpointer data)
1468{
1469 struct gui *ui = (struct gui *) data;
1470
1471 gtk_widget_ref(ui->log_tree);
1472 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
1473 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +01001474 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001475}
1476
1477static void view_log(GtkWidget *w, gpointer data)
1478{
Jens Axboe4cbe7212012-03-06 13:36:17 +01001479 GtkWidget *win, *scroll, *vbox, *box;
1480 struct gui *ui = (struct gui *) data;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001481
Jens Axboe4cbe7212012-03-06 13:36:17 +01001482 if (ui->log_view)
1483 return;
1484
1485 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001486 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001487 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001488
Jens Axboe4cbe7212012-03-06 13:36:17 +01001489 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001490
Jens Axboe4cbe7212012-03-06 13:36:17 +01001491 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
1492
1493 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1494
1495 box = gtk_hbox_new(TRUE, 0);
1496 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
1497 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
1498 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
1499
1500 vbox = gtk_vbox_new(TRUE, 5);
1501 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
1502
1503 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001504 gtk_widget_show_all(win);
1505}
1506
Jens Axboe46974a72012-03-02 19:34:13 +01001507static void preferences(GtkWidget *w, gpointer data)
1508{
1509 GtkWidget *dialog, *frame, *box, **buttons;
1510 int i;
1511
1512 dialog = gtk_dialog_new_with_buttons("Preferences",
1513 GTK_WINDOW(ui.window),
1514 GTK_DIALOG_DESTROY_WITH_PARENT,
1515 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1516 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1517 NULL);
1518
Jens Axboe0b8d11e2012-03-02 19:44:15 +01001519 frame = gtk_frame_new("Debug logging");
Jens Axboe46974a72012-03-02 19:34:13 +01001520 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1521 box = gtk_hbox_new(FALSE, 6);
1522 gtk_container_add(GTK_CONTAINER(frame), box);
1523
1524 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
1525
1526 for (i = 0; i < FD_DEBUG_MAX; i++) {
1527 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
Jens Axboe0b8d11e2012-03-02 19:44:15 +01001528 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
Jens Axboe46974a72012-03-02 19:34:13 +01001529 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
1530 }
1531
1532 gtk_widget_show_all(dialog);
1533
1534 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1535 gtk_widget_destroy(dialog);
1536 return;
1537 }
1538
1539 for (i = 0; i < FD_DEBUG_MAX; i++) {
1540 int set;
1541
1542 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
1543 if (set)
1544 fio_debug |= (1UL << i);
1545 }
1546
1547 gtk_widget_destroy(dialog);
1548}
1549
Jens Axboe0420ba62012-02-29 11:16:52 +01001550static void about_dialog(GtkWidget *w, gpointer data)
1551{
1552 gtk_show_about_dialog(NULL,
1553 "program-name", "gfio",
1554 "comments", "Gtk2 UI for fio",
1555 "license", "GPLv2",
1556 "version", fio_version_string,
1557 "copyright", "Jens Axboe <axboe@kernel.dk> 2012",
1558 "logo-icon-name", "fio",
1559 /* Must be last: */
1560 NULL, NULL,
1561 NULL);
1562}
1563
1564static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01001565 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01001566 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01001567 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
1568 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
1569 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
1570 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01001571 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe46974a72012-03-02 19:34:13 +01001572 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
1573 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01001574};
Jens Axboe3e47bd22012-02-29 13:45:02 +01001575static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01001576
1577static const gchar *ui_string = " \
1578 <ui> \
1579 <menubar name=\"MainMenu\"> \
1580 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
1581 <menuitem name=\"Open\" action=\"OpenFile\" /> \
1582 <menuitem name=\"Save\" action=\"SaveFile\" /> \
1583 <separator name=\"Separator\"/> \
Jens Axboe46974a72012-03-02 19:34:13 +01001584 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
1585 <separator name=\"Separator2\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001586 <menuitem name=\"Quit\" action=\"Quit\" /> \
1587 </menu> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01001588 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
1589 <menuitem name=\"Log\" action=\"ViewLog\" /> \
1590 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01001591 <menu name=\"Help\" action=\"HelpMenuAction\"> \
1592 <menuitem name=\"About\" action=\"About\" /> \
1593 </menu> \
1594 </menubar> \
1595 </ui> \
1596";
1597
Jens Axboe4cbe7212012-03-06 13:36:17 +01001598static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
1599 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01001600{
1601 GtkActionGroup *action_group = gtk_action_group_new("Menu");
1602 GError *error = 0;
1603
1604 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001605 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001606
1607 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1608 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
1609
1610 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
1611 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
1612}
1613
1614void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
1615 GtkWidget *vbox, GtkUIManager *ui_manager)
1616{
1617 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
1618}
1619
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001620static void init_ui(int *argc, char **argv[], struct gui *ui)
1621{
Jens Axboe0420ba62012-02-29 11:16:52 +01001622 GtkSettings *settings;
1623 GtkUIManager *uimanager;
Jens Axboe843ad232012-02-29 11:44:53 +01001624 GtkWidget *menu, *probe, *probe_frame, *probe_box;
Jens Axboe0420ba62012-02-29 11:16:52 +01001625
1626 memset(ui, 0, sizeof(*ui));
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001627
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001628 /* Magical g*thread incantation, you just need this thread stuff.
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001629 * Without it, the update that happens in gfio_update_thread_status
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001630 * doesn't really happen in a timely fashion, you need expose events
1631 */
Jens Axboeed727a42012-03-02 12:14:40 +01001632 if (!g_thread_supported())
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001633 g_thread_init(NULL);
1634 gdk_threads_init();
1635
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001636 gtk_init(argc, argv);
Jens Axboe0420ba62012-02-29 11:16:52 +01001637 settings = gtk_settings_get_default();
1638 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
1639 g_type_init();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001640
1641 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1642 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
1643 gtk_window_set_default_size(GTK_WINDOW(ui->window), 700, 500);
1644
Jens Axboe0420ba62012-02-29 11:16:52 +01001645 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
1646 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001647
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001648 ui->vbox = gtk_vbox_new(FALSE, 0);
1649 gtk_container_add(GTK_CONTAINER (ui->window), ui->vbox);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001650
Jens Axboe0420ba62012-02-29 11:16:52 +01001651 uimanager = gtk_ui_manager_new();
Jens Axboe4cbe7212012-03-06 13:36:17 +01001652 menu = get_menubar_menu(ui->window, uimanager, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001653 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
1654
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001655 /*
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001656 * Set up alignments for widgets at the top of ui,
1657 * align top left, expand horizontally but not vertically
1658 */
1659 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001660 ui->topvbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001661 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001662 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->topalign, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001663
Jens Axboe3e47bd22012-02-29 13:45:02 +01001664 probe = gtk_frame_new("Job");
Jens Axboe843ad232012-02-29 11:44:53 +01001665 gtk_box_pack_start(GTK_BOX(ui->topvbox), probe, TRUE, FALSE, 3);
1666 probe_frame = gtk_vbox_new(FALSE, 3);
1667 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
1668
1669 probe_box = gtk_hbox_new(FALSE, 3);
1670 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01001671 ui->probe.hostname = new_info_label_in_frame(probe_box, "Host");
1672 ui->probe.os = new_info_label_in_frame(probe_box, "OS");
1673 ui->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
1674 ui->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
1675
Jens Axboe3e47bd22012-02-29 13:45:02 +01001676 probe_box = gtk_hbox_new(FALSE, 3);
1677 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01001678
Jens Axboeca850992012-03-05 20:04:43 +01001679 ui->eta.name = new_info_entry_in_frame(probe_box, "Name");
1680 ui->eta.iotype = new_info_entry_in_frame(probe_box, "IO");
1681 ui->eta.ioengine = new_info_entry_in_frame(probe_box, "IO Engine");
1682 ui->eta.iodepth = new_info_entry_in_frame(probe_box, "IO Depth");
1683 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
1684 ui->eta.files = new_info_entry_in_frame(probe_box, "Open files");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001685
1686 probe_box = gtk_hbox_new(FALSE, 3);
1687 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboeca850992012-03-05 20:04:43 +01001688 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1689 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1690 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1691 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001692
1693 /*
1694 * Only add this if we have a commit rate
1695 */
1696#if 0
1697 probe_box = gtk_hbox_new(FALSE, 3);
1698 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1699
Jens Axboe3e47bd22012-02-29 13:45:02 +01001700 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1701 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1702
Jens Axboe3e47bd22012-02-29 13:45:02 +01001703 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1704 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001705#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01001706
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001707 /*
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001708 * Add a text box for text op messages
1709 */
1710 ui->textview = gtk_text_view_new();
1711 ui->text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ui->textview));
1712 gtk_text_buffer_set_text(ui->text, "", -1);
1713 gtk_text_view_set_editable(GTK_TEXT_VIEW(ui->textview), FALSE);
1714 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ui->textview), FALSE);
1715 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1716 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1717 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1718 gtk_container_add(GTK_CONTAINER(ui->scrolled_window), ui->textview);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001719 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->scrolled_window,
1720 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001721
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001722 /*
1723 * Set up alignments for widgets at the bottom of ui,
1724 * align bottom left, expand horizontally but not vertically
1725 */
1726 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
1727 ui->buttonbox = gtk_hbox_new(FALSE, 0);
1728 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001729 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->bottomalign,
1730 FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001731
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001732 add_buttons(ui, buttonspeclist, ARRAYSIZE(buttonspeclist));
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001733
1734 /*
1735 * Set up thread status progress bar
1736 */
1737 ui->thread_status_pb = gtk_progress_bar_new();
1738 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01001739 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001740 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
1741
Jens Axboe9b260bd2012-03-06 11:02:52 +01001742 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001743
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001744 gtk_widget_show_all(ui->window);
1745}
1746
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001747int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001748{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01001749 if (initialize_fio(envp))
1750 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01001751 if (fio_init_options())
1752 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01001753
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001754 init_ui(&argc, &argv, &ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001755
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001756 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001757 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001758 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001759 return 0;
1760}