2 * gfio - gui front end for fio - the flexible io tester
4 * Copyright (C) 2012 Stephen M. Cameron <stephenmcameron@gmail.com>
5 * Copyright (C) 2012 Jens Axboe <axboe@kernel.dk>
7 * The license below covers all files distributed with fio unless otherwise
8 * noted in the file itself.
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.
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.
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
35 static int gfio_server_running;
36 static const char *gfio_graph_font;
38 static void gfio_update_thread_status(char *status_message, double perc);
39 static void view_log(GtkWidget *w, gpointer data);
41 #define ARRAYSIZE(x) (sizeof((x)) / (sizeof((x)[0])))
43 typedef void (*clickfunction)(GtkWidget *widget, gpointer data);
45 static void connect_clicked(GtkWidget *widget, gpointer data);
46 static void start_job_clicked(GtkWidget *widget, gpointer data);
48 static struct button_spec {
49 const char *buttontext;
51 const char *tooltiptext;
52 const int start_insensitive;
53 } buttonspeclist[] = {
54 #define CONNECT_BUTTON 0
55 #define START_JOB_BUTTON 1
56 { "Connect", connect_clicked, "Connect to host", 0 },
59 "Send current fio job to fio server to be executed", 1 },
81 GtkWidget *write_iops;
91 GtkWidget *bottomalign;
92 GtkWidget *thread_status_pb;
94 GtkWidget *button[ARRAYSIZE(buttonspeclist)];
95 GtkWidget *scrolled_window;
96 #define DRAWING_AREA_XDIM 1000
97 #define DRAWING_AREA_YDIM 400
98 GtkWidget *drawing_area;
99 int drawing_area_xdim;
100 int drawing_area_ydim;
101 GtkWidget *error_info_bar;
102 GtkWidget *error_label;
103 GtkWidget *results_notebook;
104 GtkWidget *results_window;
105 GtkListStore *log_model;
109 struct probe_widget probe;
110 struct eta_widget eta;
115 struct graph *iops_graph;
116 struct graph *bandwidth_graph;
117 struct fio_client *client;
124 GtkWidget *results_widget;
125 GtkWidget *disk_util_frame;
126 GtkWidget *err_entry;
129 static void setup_iops_graph(struct gui *ui)
132 graph_free(ui->iops_graph);
133 ui->iops_graph = graph_new(DRAWING_AREA_XDIM / 2.0,
134 DRAWING_AREA_YDIM, gfio_graph_font);
135 graph_title(ui->iops_graph, "IOPS");
136 graph_x_title(ui->iops_graph, "Time (secs)");
137 graph_add_label(ui->iops_graph, "Read IOPS");
138 graph_add_label(ui->iops_graph, "Write IOPS");
139 graph_set_color(ui->iops_graph, "Read IOPS", 0.13, 0.54, 0.13);
140 graph_set_color(ui->iops_graph, "Write IOPS", 1.0, 0.0, 0.0);
141 line_graph_set_data_count_limit(ui->iops_graph, 100);
144 static void setup_bandwidth_graph(struct gui *ui)
146 if (ui->bandwidth_graph)
147 graph_free(ui->bandwidth_graph);
148 ui->bandwidth_graph = graph_new(DRAWING_AREA_XDIM / 2.0,
149 DRAWING_AREA_YDIM, gfio_graph_font);
150 graph_title(ui->bandwidth_graph, "Bandwidth");
151 graph_x_title(ui->bandwidth_graph, "Time (secs)");
152 graph_add_label(ui->bandwidth_graph, "Read Bandwidth");
153 graph_add_label(ui->bandwidth_graph, "Write Bandwidth");
154 graph_set_color(ui->bandwidth_graph, "Read Bandwidth", 0.13, 0.54, 0.13);
155 graph_set_color(ui->bandwidth_graph, "Write Bandwidth", 1.0, 0.0, 0.0);
156 line_graph_set_data_count_limit(ui->bandwidth_graph, 100);
159 static void clear_ui_info(struct gui *ui)
161 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), "");
162 gtk_label_set_text(GTK_LABEL(ui->probe.os), "");
163 gtk_label_set_text(GTK_LABEL(ui->probe.arch), "");
164 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), "");
165 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), "");
166 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), "");
167 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), "");
168 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), "");
169 gtk_entry_set_text(GTK_ENTRY(ui->eta.jobs), "");
170 gtk_entry_set_text(GTK_ENTRY(ui->eta.files), "");
171 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), "");
172 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), "");
173 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), "");
174 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), "");
177 static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
179 GtkWidget *entry, *frame;
181 frame = gtk_frame_new(label);
182 entry = gtk_entry_new();
183 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
184 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
185 gtk_container_add(GTK_CONTAINER(frame), entry);
190 static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
192 GtkWidget *label_widget;
195 frame = gtk_frame_new(label);
196 label_widget = gtk_label_new(NULL);
197 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
198 gtk_container_add(GTK_CONTAINER(frame), label_widget);
203 static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
205 GtkWidget *button, *box;
207 box = gtk_hbox_new(FALSE, 3);
208 gtk_container_add(GTK_CONTAINER(hbox), box);
210 button = gtk_spin_button_new_with_range(min, max, 1.0);
211 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
213 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
214 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
219 static void gfio_set_connected(struct gui *ui, int connected)
222 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
224 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Disconnect");
225 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
228 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Connect");
229 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
230 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
234 static void label_set_int_value(GtkWidget *entry, unsigned int val)
238 sprintf(tmp, "%u", val);
239 gtk_label_set_text(GTK_LABEL(entry), tmp);
242 static void entry_set_int_value(GtkWidget *entry, unsigned int val)
246 sprintf(tmp, "%u", val);
247 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
251 #define ALIGN_RIGHT 2
255 GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
257 GtkCellRenderer *renderer;
258 GtkTreeViewColumn *col;
259 double xalign = 0.0; /* left as default */
260 PangoAlignment align;
263 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
264 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
266 visible = !(flags & INVISIBLE);
268 renderer = gtk_cell_renderer_text_new();
269 col = gtk_tree_view_column_new();
271 gtk_tree_view_column_set_title(col, title);
272 if (!(flags & UNSORTABLE))
273 gtk_tree_view_column_set_sort_column_id(col, index);
274 gtk_tree_view_column_set_resizable(col, TRUE);
275 gtk_tree_view_column_pack_start(col, renderer, TRUE);
276 gtk_tree_view_column_add_attribute(col, renderer, "text", index);
277 gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
279 case PANGO_ALIGN_LEFT:
282 case PANGO_ALIGN_CENTER:
285 case PANGO_ALIGN_RIGHT:
289 gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
290 gtk_tree_view_column_set_visible(col, visible);
291 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
295 static void gfio_ui_setup_log(struct gui *ui)
297 GtkTreeSelection *selection;
299 GtkWidget *tree_view;
301 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
303 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
304 gtk_widget_set_can_focus(tree_view, FALSE);
306 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
307 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
308 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
309 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
311 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
312 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
313 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
314 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
316 ui->log_model = model;
317 ui->log_tree = tree_view;
320 static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
326 GType types[FIO_IO_U_LIST_MAX_LEN];
327 GtkWidget *tree_view;
328 GtkTreeSelection *selection;
333 for (i = 0; i < len; i++)
334 types[i] = G_TYPE_INT;
336 model = gtk_list_store_newv(len, types);
338 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
339 gtk_widget_set_can_focus(tree_view, FALSE);
341 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
342 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
344 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
345 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
347 for (i = 0; i < len; i++) {
350 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
351 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
354 gtk_list_store_append(model, &iter);
356 for (i = 0; i < len; i++) {
358 ovals[i] = (ovals[i] + 999) / 1000;
359 gtk_list_store_set(model, &iter, i, ovals[i], -1);
365 static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
368 unsigned int *io_u_plat = ts->io_u_plat[ddir];
369 unsigned long nr = ts->clat_stat[ddir].samples;
370 fio_fp64_t *plist = ts->percentile_list;
371 unsigned int *ovals, len, minv, maxv, scale_down;
373 GtkWidget *tree_view, *frame, *hbox;
376 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
381 * We default to usecs, but if the value range is such that we
382 * should scale down to msecs, do that.
384 if (minv > 2000 && maxv > 99999) {
392 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
394 sprintf(tmp, "Completion percentiles (%s)", base);
395 frame = gtk_frame_new(tmp);
396 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
398 hbox = gtk_hbox_new(FALSE, 3);
399 gtk_container_add(GTK_CONTAINER(frame), hbox);
401 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
407 static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
408 unsigned long max, double mean, double dev)
410 const char *base = "(usec)";
411 GtkWidget *hbox, *label, *frame;
415 if (!usec_to_msec(&min, &max, &mean, &dev))
418 minp = num2str(min, 6, 1, 0);
419 maxp = num2str(max, 6, 1, 0);
421 sprintf(tmp, "%s %s", name, base);
422 frame = gtk_frame_new(tmp);
423 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
425 hbox = gtk_hbox_new(FALSE, 3);
426 gtk_container_add(GTK_CONTAINER(frame), hbox);
428 label = new_info_label_in_frame(hbox, "Minimum");
429 gtk_label_set_text(GTK_LABEL(label), minp);
430 label = new_info_label_in_frame(hbox, "Maximum");
431 gtk_label_set_text(GTK_LABEL(label), maxp);
432 label = new_info_label_in_frame(hbox, "Average");
433 sprintf(tmp, "%5.02f", mean);
434 gtk_label_set_text(GTK_LABEL(label), tmp);
435 label = new_info_label_in_frame(hbox, "Standard deviation");
436 sprintf(tmp, "%5.02f", dev);
437 gtk_label_set_text(GTK_LABEL(label), tmp);
448 static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
449 struct thread_stat *ts, int ddir)
451 const char *ddir_label[2] = { "Read", "Write" };
452 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
453 unsigned long min[3], max[3], runt;
454 unsigned long long bw, iops;
455 unsigned int flags = 0;
456 double mean[3], dev[3];
457 char *io_p, *bw_p, *iops_p;
460 if (!ts->runtime[ddir])
463 i2p = is_power_of_2(rs->kb_base);
464 runt = ts->runtime[ddir];
466 bw = (1000 * ts->io_bytes[ddir]) / runt;
467 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
468 bw_p = num2str(bw, 6, 1, i2p);
470 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
471 iops_p = num2str(iops, 6, 1, 0);
473 box = gtk_hbox_new(FALSE, 3);
474 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
476 frame = gtk_frame_new(ddir_label[ddir]);
477 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
479 main_vbox = gtk_vbox_new(FALSE, 3);
480 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
482 box = gtk_hbox_new(FALSE, 3);
483 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
485 label = new_info_label_in_frame(box, "IO");
486 gtk_label_set_text(GTK_LABEL(label), io_p);
487 label = new_info_label_in_frame(box, "Bandwidth");
488 gtk_label_set_text(GTK_LABEL(label), bw_p);
489 label = new_info_label_in_frame(box, "IOPS");
490 gtk_label_set_text(GTK_LABEL(label), iops_p);
491 label = new_info_label_in_frame(box, "Runtime (msec)");
492 label_set_int_value(label, ts->runtime[ddir]);
494 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
495 double p_of_agg = 100.0;
496 const char *bw_str = "KB";
500 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
501 if (p_of_agg > 100.0)
505 if (mean[0] > 999999.9) {
513 sprintf(tmp, "Bandwidth (%s)", bw_str);
514 frame = gtk_frame_new(tmp);
515 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
517 box = gtk_hbox_new(FALSE, 3);
518 gtk_container_add(GTK_CONTAINER(frame), box);
520 label = new_info_label_in_frame(box, "Minimum");
521 label_set_int_value(label, min[0]);
522 label = new_info_label_in_frame(box, "Maximum");
523 label_set_int_value(label, max[0]);
524 label = new_info_label_in_frame(box, "Percentage of jobs");
525 sprintf(tmp, "%3.2f%%", p_of_agg);
526 gtk_label_set_text(GTK_LABEL(label), tmp);
527 label = new_info_label_in_frame(box, "Average");
528 sprintf(tmp, "%5.02f", mean[0]);
529 gtk_label_set_text(GTK_LABEL(label), tmp);
530 label = new_info_label_in_frame(box, "Standard deviation");
531 sprintf(tmp, "%5.02f", dev[0]);
532 gtk_label_set_text(GTK_LABEL(label), tmp);
535 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
537 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
539 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
543 frame = gtk_frame_new("Latency");
544 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
546 vbox = gtk_vbox_new(FALSE, 3);
547 gtk_container_add(GTK_CONTAINER(frame), vbox);
549 if (flags & GFIO_SLAT)
550 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
551 if (flags & GFIO_CLAT)
552 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
553 if (flags & GFIO_LAT)
554 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
557 if (ts->clat_percentiles)
558 gfio_show_clat_percentiles(main_vbox, ts, ddir);
566 static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
569 GtkWidget *tree_view;
570 GtkTreeSelection *selection;
577 * Check if all are empty, in which case don't bother
579 for (i = 0, skipped = 0; i < num; i++)
586 types = malloc(num * sizeof(GType));
588 for (i = 0; i < num; i++)
589 types[i] = G_TYPE_STRING;
591 model = gtk_list_store_newv(num, types);
595 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
596 gtk_widget_set_can_focus(tree_view, FALSE);
598 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
599 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
601 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
602 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
604 for (i = 0; i < num; i++)
605 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
607 gtk_list_store_append(model, &iter);
609 for (i = 0; i < num; i++) {
613 sprintf(fbuf, "0.00");
615 sprintf(fbuf, "%3.2f%%", lat[i]);
617 gtk_list_store_set(model, &iter, i, fbuf, -1);
623 static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
625 GtkWidget *box, *frame, *tree_view;
626 double io_u_lat_u[FIO_IO_U_LAT_U_NR];
627 double io_u_lat_m[FIO_IO_U_LAT_M_NR];
628 const char *uranges[] = { "2", "4", "10", "20", "50", "100",
629 "250", "500", "750", "1000", };
630 const char *mranges[] = { "2", "4", "10", "20", "50", "100",
631 "250", "500", "750", "1000", "2000",
634 stat_calc_lat_u(ts, io_u_lat_u);
635 stat_calc_lat_m(ts, io_u_lat_m);
637 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
639 frame = gtk_frame_new("Latency buckets (usec)");
640 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
642 box = gtk_hbox_new(FALSE, 3);
643 gtk_container_add(GTK_CONTAINER(frame), box);
644 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
647 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
649 frame = gtk_frame_new("Latency buckets (msec)");
650 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
652 box = gtk_hbox_new(FALSE, 3);
653 gtk_container_add(GTK_CONTAINER(frame), box);
654 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
658 static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
660 GtkWidget *box, *frame, *entry;
661 double usr_cpu, sys_cpu;
662 unsigned long runtime;
665 runtime = ts->total_run_time;
667 double runt = (double) runtime;
669 usr_cpu = (double) ts->usr_time * 100 / runt;
670 sys_cpu = (double) ts->sys_time * 100 / runt;
676 frame = gtk_frame_new("OS resources");
677 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
679 box = gtk_hbox_new(FALSE, 3);
680 gtk_container_add(GTK_CONTAINER(frame), box);
682 entry = new_info_entry_in_frame(box, "User CPU");
683 sprintf(tmp, "%3.2f%%", usr_cpu);
684 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
685 entry = new_info_entry_in_frame(box, "System CPU");
686 sprintf(tmp, "%3.2f%%", sys_cpu);
687 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
688 entry = new_info_entry_in_frame(box, "Context switches");
689 entry_set_int_value(entry, ts->ctx);
690 entry = new_info_entry_in_frame(box, "Major faults");
691 entry_set_int_value(entry, ts->majf);
692 entry = new_info_entry_in_frame(box, "Minor faults");
693 entry_set_int_value(entry, ts->minf);
695 static void gfio_add_sc_depths_tree(GtkListStore *model,
696 struct thread_stat *ts, unsigned int len,
699 double io_u_dist[FIO_IO_U_MAP_NR];
701 /* Bits 0, and 3-8 */
702 const int add_mask = 0x1f9;
706 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
708 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
710 gtk_list_store_append(model, &iter);
712 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
714 for (i = 1, j = 0; i < len; i++) {
717 if (!(add_mask & (1UL << (i - 1))))
718 sprintf(fbuf, "0.0%%");
720 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
724 gtk_list_store_set(model, &iter, i, fbuf, -1);
729 static void gfio_add_total_depths_tree(GtkListStore *model,
730 struct thread_stat *ts, unsigned int len)
732 double io_u_dist[FIO_IO_U_MAP_NR];
734 /* Bits 1-6, and 8 */
735 const int add_mask = 0x17e;
738 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
740 gtk_list_store_append(model, &iter);
742 gtk_list_store_set(model, &iter, 0, "Total", -1);
744 for (i = 1, j = 0; i < len; i++) {
747 if (!(add_mask & (1UL << (i - 1))))
748 sprintf(fbuf, "0.0%%");
750 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
754 gtk_list_store_set(model, &iter, i, fbuf, -1);
759 static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
761 GtkWidget *frame, *box, *tree_view;
762 GtkTreeSelection *selection;
764 GType types[FIO_IO_U_MAP_NR + 1];
767 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
769 frame = gtk_frame_new("IO depths");
770 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
772 box = gtk_hbox_new(FALSE, 3);
773 gtk_container_add(GTK_CONTAINER(frame), box);
775 for (i = 0; i < NR_LABELS; i++)
776 types[i] = G_TYPE_STRING;
778 model = gtk_list_store_newv(NR_LABELS, types);
780 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
781 gtk_widget_set_can_focus(tree_view, FALSE);
783 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
784 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
786 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
787 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
789 for (i = 0; i < NR_LABELS; i++)
790 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
792 gfio_add_total_depths_tree(model, ts, NR_LABELS);
793 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 1);
794 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 0);
796 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
799 static gboolean results_window_delete(GtkWidget *w, gpointer data)
801 struct gui *ui = (struct gui *) data;
803 gtk_widget_destroy(w);
804 ui->results_window = NULL;
805 ui->results_notebook = NULL;
809 static GtkWidget *get_results_window(struct gui *ui)
811 GtkWidget *win, *notebook;
813 if (ui->results_window)
814 return ui->results_notebook;
816 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
817 gtk_window_set_title(GTK_WINDOW(win), "Results");
818 gtk_window_set_default_size(GTK_WINDOW(win), 1024, 768);
819 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ui);
820 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ui);
822 notebook = gtk_notebook_new();
823 gtk_container_add(GTK_CONTAINER(win), notebook);
825 ui->results_window = win;
826 ui->results_notebook = notebook;
827 return ui->results_notebook;
830 static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
831 struct group_run_stats *rs)
833 GtkWidget *res_win, *box, *vbox, *entry, *scroll;
834 struct gfio_client *gc = client->client_data;
838 res_win = get_results_window(gc->ui);
840 scroll = gtk_scrolled_window_new(NULL, NULL);
841 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
842 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
844 vbox = gtk_vbox_new(FALSE, 3);
846 box = gtk_hbox_new(FALSE, 0);
847 gtk_box_pack_start(GTK_BOX(vbox), box, TRUE, FALSE, 5);
849 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
851 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), scroll, gtk_label_new(ts->name));
853 gc->results_widget = vbox;
855 entry = new_info_entry_in_frame(box, "Name");
856 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
857 if (strlen(ts->description)) {
858 entry = new_info_entry_in_frame(box, "Description");
859 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
861 entry = new_info_entry_in_frame(box, "Group ID");
862 entry_set_int_value(entry, ts->groupid);
863 entry = new_info_entry_in_frame(box, "Jobs");
864 entry_set_int_value(entry, ts->members);
865 gc->err_entry = entry = new_info_entry_in_frame(box, "Error");
866 entry_set_int_value(entry, ts->error);
867 entry = new_info_entry_in_frame(box, "PID");
868 entry_set_int_value(entry, ts->pid);
870 if (ts->io_bytes[DDIR_READ])
871 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
872 if (ts->io_bytes[DDIR_WRITE])
873 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
875 gfio_show_latency_buckets(vbox, ts);
876 gfio_show_cpu_usage(vbox, ts);
877 gfio_show_io_depths(vbox, ts);
879 gtk_widget_show_all(gc->ui->results_window);
883 static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
885 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
886 struct gfio_client *gc = client->client_data;
890 char tmp[64], timebuf[80];
893 tm = localtime(&sec);
894 strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", tm);
895 sprintf(timebuf, "%s.%03ld", tmp, p->log_usec / 1000);
899 gtk_list_store_append(gc->ui->log_model, &iter);
900 gtk_list_store_set(gc->ui->log_model, &iter, 0, timebuf, -1);
901 gtk_list_store_set(gc->ui->log_model, &iter, 1, client->hostname, -1);
902 gtk_list_store_set(gc->ui->log_model, &iter, 2, p->level, -1);
903 gtk_list_store_set(gc->ui->log_model, &iter, 3, p->buf, -1);
905 if (p->level == FIO_LOG_ERR)
906 view_log(NULL, (gpointer) gc->ui);
911 static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
913 struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
914 struct gfio_client *gc = client->client_data;
915 GtkWidget *box, *frame, *entry, *vbox;
921 if (!gc->results_widget)
924 if (!gc->disk_util_frame) {
925 gc->disk_util_frame = gtk_frame_new("Disk utilization");
926 gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
929 vbox = gtk_vbox_new(FALSE, 3);
930 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
932 frame = gtk_frame_new((char *) p->dus.name);
933 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
935 box = gtk_vbox_new(FALSE, 3);
936 gtk_container_add(GTK_CONTAINER(frame), box);
938 frame = gtk_frame_new("Read");
939 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
940 vbox = gtk_hbox_new(TRUE, 3);
941 gtk_container_add(GTK_CONTAINER(frame), vbox);
942 entry = new_info_entry_in_frame(vbox, "IOs");
943 entry_set_int_value(entry, p->dus.ios[0]);
944 entry = new_info_entry_in_frame(vbox, "Merges");
945 entry_set_int_value(entry, p->dus.merges[0]);
946 entry = new_info_entry_in_frame(vbox, "Sectors");
947 entry_set_int_value(entry, p->dus.sectors[0]);
948 entry = new_info_entry_in_frame(vbox, "Ticks");
949 entry_set_int_value(entry, p->dus.ticks[0]);
951 frame = gtk_frame_new("Write");
952 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
953 vbox = gtk_hbox_new(TRUE, 3);
954 gtk_container_add(GTK_CONTAINER(frame), vbox);
955 entry = new_info_entry_in_frame(vbox, "IOs");
956 entry_set_int_value(entry, p->dus.ios[1]);
957 entry = new_info_entry_in_frame(vbox, "Merges");
958 entry_set_int_value(entry, p->dus.merges[1]);
959 entry = new_info_entry_in_frame(vbox, "Sectors");
960 entry_set_int_value(entry, p->dus.sectors[1]);
961 entry = new_info_entry_in_frame(vbox, "Ticks");
962 entry_set_int_value(entry, p->dus.ticks[1]);
964 frame = gtk_frame_new("Shared");
965 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
966 vbox = gtk_hbox_new(TRUE, 3);
967 gtk_container_add(GTK_CONTAINER(frame), vbox);
968 entry = new_info_entry_in_frame(vbox, "IO ticks");
969 entry_set_int_value(entry, p->dus.io_ticks);
970 entry = new_info_entry_in_frame(vbox, "Time in queue");
971 entry_set_int_value(entry, p->dus.time_in_queue);
975 util = (double) 100 * p->dus.io_ticks / (double) p->dus.msec;
979 sprintf(tmp, "%3.2f%%", util);
980 entry = new_info_entry_in_frame(vbox, "Disk utilization");
981 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
983 gtk_widget_show_all(gc->results_widget);
988 extern int sum_stat_clients;
989 extern struct thread_stat client_ts;
990 extern struct group_run_stats client_gs;
992 static int sum_stat_nr;
994 static void gfio_thread_status_op(struct fio_client *client,
995 struct fio_net_cmd *cmd)
997 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
999 gfio_display_ts(client, &p->ts, &p->rs);
1001 if (sum_stat_clients == 1)
1004 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
1005 sum_group_stats(&client_gs, &p->rs);
1007 client_ts.members++;
1008 client_ts.groupid = p->ts.groupid;
1010 if (++sum_stat_nr == sum_stat_clients) {
1011 strcpy(client_ts.name, "All clients");
1012 gfio_display_ts(client, &client_ts, &client_gs);
1016 static void gfio_group_stats_op(struct fio_client *client,
1017 struct fio_net_cmd *cmd)
1019 gdk_threads_enter();
1020 printf("gfio_group_stats_op called\n");
1021 fio_client_ops.group_stats(client, cmd);
1022 gdk_threads_leave();
1025 static gint on_config_drawing_area(GtkWidget *w, GdkEventConfigure *event)
1027 ui.drawing_area_xdim = w->allocation.width;
1028 ui.drawing_area_ydim = w->allocation.height;
1032 static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
1034 struct gui *ui = (struct gui *) p;
1037 graph_set_size(ui->iops_graph, ui->drawing_area_xdim / 2.0,
1038 ui->drawing_area_ydim);
1039 graph_set_size(ui->bandwidth_graph, ui->drawing_area_xdim / 2.0,
1040 ui->drawing_area_ydim);
1041 cr = gdk_cairo_create(w->window);
1043 cairo_set_source_rgb(cr, 0, 0, 0);
1046 cairo_translate(cr, 0, 0);
1047 line_graph_draw(ui->bandwidth_graph, cr);
1052 cairo_translate(cr, ui->drawing_area_xdim / 2.0, 0);
1053 line_graph_draw(ui->iops_graph, cr);
1061 static void gfio_update_eta(struct jobs_eta *je)
1063 static int eta_good;
1070 gdk_threads_enter();
1075 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1076 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1077 eta_to_str(eta_str, je->eta_sec);
1080 sprintf(tmp, "%u", je->nr_running);
1081 gtk_entry_set_text(GTK_ENTRY(ui.eta.jobs), tmp);
1082 sprintf(tmp, "%u", je->files_open);
1083 gtk_entry_set_text(GTK_ENTRY(ui.eta.files), tmp);
1086 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1087 if (je->m_rate || je->t_rate) {
1090 mr = num2str(je->m_rate, 4, 0, i2p);
1091 tr = num2str(je->t_rate, 4, 0, i2p);
1092 gtk_entry_set_text(GTK_ENTRY(ui.eta);
1093 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1096 } else if (je->m_iops || je->t_iops)
1097 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
1099 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_bw), "---");
1100 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_iops), "---");
1101 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_bw), "---");
1102 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_iops), "---");
1105 if (je->eta_sec != INT_MAX && je->nr_running) {
1109 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1110 strcpy(output, "-.-% done");
1114 sprintf(output, "%3.1f%% done", perc);
1117 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1118 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1120 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1121 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1123 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_bw), rate_str[0]);
1124 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_iops), iops_str[0]);
1125 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_bw), rate_str[1]);
1126 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_iops), iops_str[1]);
1128 graph_add_xy_data(ui.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1129 graph_add_xy_data(ui.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1130 graph_add_xy_data(ui.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1131 graph_add_xy_data(ui.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
1140 char *dst = output + strlen(output);
1142 sprintf(dst, " - %s", eta_str);
1145 gfio_update_thread_status(output, perc);
1146 gdk_threads_leave();
1149 static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1151 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
1152 struct gfio_client *gc = client->client_data;
1153 struct gui *ui = gc->ui;
1154 const char *os, *arch;
1157 os = fio_get_os_string(probe->os);
1161 arch = fio_get_arch_string(probe->arch);
1166 client->name = strdup((char *) probe->hostname);
1168 gdk_threads_enter();
1170 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), (char *) probe->hostname);
1171 gtk_label_set_text(GTK_LABEL(ui->probe.os), os);
1172 gtk_label_set_text(GTK_LABEL(ui->probe.arch), arch);
1173 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
1174 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), buf);
1176 gfio_set_connected(ui, 1);
1178 gdk_threads_leave();
1181 static void gfio_update_thread_status(char *status_message, double perc)
1183 static char message[100];
1184 const char *m = message;
1186 strncpy(message, status_message, sizeof(message) - 1);
1187 gtk_progress_bar_set_text(
1188 GTK_PROGRESS_BAR(ui.thread_status_pb), m);
1189 gtk_progress_bar_set_fraction(
1190 GTK_PROGRESS_BAR(ui.thread_status_pb), perc / 100.0);
1191 gtk_widget_queue_draw(ui.window);
1194 static void gfio_quit_op(struct fio_client *client)
1196 struct gfio_client *gc = client->client_data;
1198 gdk_threads_enter();
1199 gfio_set_connected(gc->ui, 0);
1200 gdk_threads_leave();
1203 static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1205 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
1206 struct gfio_client *gc = client->client_data;
1207 struct gui *ui = gc->ui;
1211 p->iodepth = le32_to_cpu(p->iodepth);
1212 p->rw = le32_to_cpu(p->rw);
1214 for (i = 0; i < 2; i++) {
1215 p->min_bs[i] = le32_to_cpu(p->min_bs[i]);
1216 p->max_bs[i] = le32_to_cpu(p->max_bs[i]);
1219 p->numjobs = le32_to_cpu(p->numjobs);
1220 p->group_reporting = le32_to_cpu(p->group_reporting);
1222 gdk_threads_enter();
1224 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), (gchar *) p->jobname);
1225 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), ddir_str(p->rw));
1226 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), (gchar *) p->ioengine);
1228 sprintf(tmp, "%u", p->iodepth);
1229 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), tmp);
1231 gdk_threads_leave();
1234 static void gfio_client_timed_out(struct fio_client *client)
1236 struct gfio_client *gc = client->client_data;
1237 GtkWidget *dialog, *label, *content;
1240 gdk_threads_enter();
1242 gfio_set_connected(gc->ui, 0);
1243 clear_ui_info(gc->ui);
1245 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
1247 dialog = gtk_dialog_new_with_buttons("Timed out!",
1248 GTK_WINDOW(gc->ui->window),
1249 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1250 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1252 /* gtk_dialog_get_content_area() is 2.14 and newer */
1253 content = GTK_DIALOG(dialog)->vbox;
1255 label = gtk_label_new((const gchar *) buf);
1256 gtk_container_add(GTK_CONTAINER(content), label);
1257 gtk_widget_show_all(dialog);
1258 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1260 gtk_dialog_run(GTK_DIALOG(dialog));
1261 gtk_widget_destroy(dialog);
1263 gdk_threads_leave();
1266 static void gfio_client_stop(struct fio_client *client, struct fio_net_cmd *cmd)
1268 struct gfio_client *gc = client->client_data;
1270 gdk_threads_enter();
1272 gfio_set_connected(gc->ui, 0);
1275 entry_set_int_value(gc->err_entry, client->error);
1277 gdk_threads_leave();
1280 struct client_ops gfio_client_ops = {
1281 .text_op = gfio_text_op,
1282 .disk_util = gfio_disk_util_op,
1283 .thread_status = gfio_thread_status_op,
1284 .group_stats = gfio_group_stats_op,
1285 .eta = gfio_update_eta,
1286 .probe = gfio_probe_op,
1287 .quit = gfio_quit_op,
1288 .add_job = gfio_add_job_op,
1289 .timed_out = gfio_client_timed_out,
1290 .stop = gfio_client_stop,
1291 .stay_connected = 1,
1294 static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1295 __attribute__((unused)) gpointer data)
1300 static void *job_thread(void *arg)
1302 fio_handle_clients(&gfio_client_ops);
1306 static int send_job_files(struct gui *ui)
1310 for (i = 0; i < ui->nr_job_files; i++) {
1311 ret = fio_clients_send_ini(ui->job_files[i]);
1315 free(ui->job_files[i]);
1316 ui->job_files[i] = NULL;
1318 while (i < ui->nr_job_files) {
1319 free(ui->job_files[i]);
1320 ui->job_files[i] = NULL;
1327 static void start_job_thread(struct gui *ui)
1329 if (send_job_files(ui)) {
1330 printf("Yeah, I didn't really like those options too much.\n");
1331 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
1336 static void *server_thread(void *arg)
1339 gfio_server_running = 1;
1340 fio_start_server(NULL);
1341 gfio_server_running = 0;
1345 static void gfio_start_server(struct gui *ui)
1347 if (!gfio_server_running) {
1348 gfio_server_running = 1;
1349 pthread_create(&ui->server_t, NULL, server_thread, NULL);
1350 pthread_detach(ui->server_t);
1354 static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1357 struct gui *ui = data;
1359 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
1360 start_job_thread(ui);
1363 static void file_open(GtkWidget *w, gpointer data);
1365 static void connect_clicked(GtkWidget *widget, gpointer data)
1367 struct gui *ui = data;
1369 if (!ui->connected) {
1370 if (!ui->nr_job_files)
1371 file_open(widget, data);
1372 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
1373 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
1374 if (!fio_clients_connect()) {
1375 pthread_create(&ui->t, NULL, job_thread, NULL);
1376 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 0);
1379 fio_clients_terminate();
1380 gfio_set_connected(ui, 0);
1385 static void add_button(struct gui *ui, int i, GtkWidget *buttonbox,
1386 struct button_spec *buttonspec)
1388 ui->button[i] = gtk_button_new_with_label(buttonspec->buttontext);
1389 g_signal_connect(ui->button[i], "clicked", G_CALLBACK (buttonspec->f), ui);
1390 gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], FALSE, FALSE, 3);
1391 gtk_widget_set_tooltip_text(ui->button[i], buttonspeclist[i].tooltiptext);
1392 gtk_widget_set_sensitive(ui->button[i], !buttonspec->start_insensitive);
1395 static void add_buttons(struct gui *ui,
1396 struct button_spec *buttonlist,
1401 for (i = 0; i < nbuttons; i++)
1402 add_button(ui, i, ui->buttonbox, &buttonlist[i]);
1405 static void on_info_bar_response(GtkWidget *widget, gint response,
1408 if (response == GTK_RESPONSE_OK) {
1409 gtk_widget_destroy(widget);
1410 ui.error_info_bar = NULL;
1414 void report_error(GError *error)
1416 if (ui.error_info_bar == NULL) {
1417 ui.error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
1420 g_signal_connect(ui.error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1421 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui.error_info_bar),
1424 ui.error_label = gtk_label_new(error->message);
1425 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui.error_info_bar));
1426 gtk_container_add(GTK_CONTAINER(container), ui.error_label);
1428 gtk_box_pack_start(GTK_BOX(ui.vbox), ui.error_info_bar, FALSE, FALSE, 0);
1429 gtk_widget_show_all(ui.vbox);
1432 snprintf(buffer, sizeof(buffer), "Failed to open file.");
1433 gtk_label_set(GTK_LABEL(ui.error_label), buffer);
1437 struct connection_widgets
1444 static void hostname_cb(GtkEntry *entry, gpointer data)
1446 struct connection_widgets *cw = data;
1447 int uses_net = 0, is_localhost = 0;
1452 * Check whether to display the 'auto start backend' box
1453 * or not. Show it if we are a localhost and using network,
1454 * or using a socket.
1456 ctext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->combo));
1457 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
1462 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
1463 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
1464 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
1465 !strcmp(text, "ip6-loopback"))
1469 if (!uses_net || is_localhost) {
1470 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
1471 gtk_widget_set_sensitive(cw->button, 1);
1473 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
1474 gtk_widget_set_sensitive(cw->button, 0);
1478 static int get_connection_details(char **host, int *port, int *type,
1481 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
1482 struct connection_widgets cw;
1485 dialog = gtk_dialog_new_with_buttons("Connection details",
1486 GTK_WINDOW(ui.window),
1487 GTK_DIALOG_DESTROY_WITH_PARENT,
1488 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1489 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1491 frame = gtk_frame_new("Hostname / socket name");
1492 /* gtk_dialog_get_content_area() is 2.14 and newer */
1493 vbox = GTK_DIALOG(dialog)->vbox;
1494 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1496 box = gtk_vbox_new(FALSE, 6);
1497 gtk_container_add(GTK_CONTAINER(frame), box);
1499 hbox = gtk_hbox_new(TRUE, 10);
1500 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1501 cw.hentry = gtk_entry_new();
1502 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
1503 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
1505 frame = gtk_frame_new("Port");
1506 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1507 box = gtk_vbox_new(FALSE, 10);
1508 gtk_container_add(GTK_CONTAINER(frame), box);
1510 hbox = gtk_hbox_new(TRUE, 4);
1511 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1512 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1514 frame = gtk_frame_new("Type");
1515 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1516 box = gtk_vbox_new(FALSE, 10);
1517 gtk_container_add(GTK_CONTAINER(frame), box);
1519 hbox = gtk_hbox_new(TRUE, 4);
1520 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1522 cw.combo = gtk_combo_box_new_text();
1523 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv4");
1524 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv6");
1525 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "local socket");
1526 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
1528 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
1530 frame = gtk_frame_new("Options");
1531 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1532 box = gtk_vbox_new(FALSE, 10);
1533 gtk_container_add(GTK_CONTAINER(frame), box);
1535 hbox = gtk_hbox_new(TRUE, 4);
1536 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1538 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1539 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
1540 gtk_widget_set_tooltip_text(cw.button, "When running fio locally, it is necessary to have the backend running on the same system. If this is checked, gfio will start the backend automatically for you if it isn't already running.");
1541 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
1544 * Connect edit signal, so we can show/not-show the auto start button
1546 g_signal_connect(GTK_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
1547 g_signal_connect(GTK_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
1549 gtk_widget_show_all(dialog);
1551 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1552 gtk_widget_destroy(dialog);
1556 *host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
1557 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1559 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw.combo));
1560 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1561 *type = Fio_client_ipv4;
1562 else if (!strncmp(typeentry, "IPv6", 4))
1563 *type = Fio_client_ipv6;
1565 *type = Fio_client_socket;
1568 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
1570 gtk_widget_destroy(dialog);
1574 static void gfio_client_added(struct gui *ui, struct fio_client *client)
1576 struct gfio_client *gc;
1578 gc = malloc(sizeof(*gc));
1579 memset(gc, 0, sizeof(*gc));
1582 client->client_data = gc;
1585 static void file_open(GtkWidget *w, gpointer data)
1588 struct gui *ui = data;
1589 GSList *filenames, *fn_glist;
1590 GtkFileFilter *filter;
1592 int port, type, server_start;
1594 dialog = gtk_file_chooser_dialog_new("Open File",
1595 GTK_WINDOW(ui->window),
1596 GTK_FILE_CHOOSER_ACTION_OPEN,
1597 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1598 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1600 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1602 filter = gtk_file_filter_new();
1603 gtk_file_filter_add_pattern(filter, "*.fio");
1604 gtk_file_filter_add_pattern(filter, "*.job");
1605 gtk_file_filter_add_pattern(filter, "*.ini");
1606 gtk_file_filter_add_mime_type(filter, "text/fio");
1607 gtk_file_filter_set_name(filter, "Fio job file");
1608 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
1610 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1611 gtk_widget_destroy(dialog);
1615 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
1617 gtk_widget_destroy(dialog);
1619 if (get_connection_details(&host, &port, &type, &server_start))
1622 filenames = fn_glist;
1623 while (filenames != NULL) {
1624 struct fio_client *client;
1626 ui->job_files = realloc(ui->job_files, (ui->nr_job_files + 1) * sizeof(char *));
1627 ui->job_files[ui->nr_job_files] = strdup(filenames->data);
1630 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
1634 error = g_error_new(g_quark_from_string("fio"), 1,
1635 "Failed to add client %s", host);
1636 report_error(error);
1637 g_error_free(error);
1639 gfio_client_added(ui, client);
1641 g_free(filenames->data);
1642 filenames = g_slist_next(filenames);
1647 gfio_start_server(ui);
1649 g_slist_free(fn_glist);
1652 static void file_save(GtkWidget *w, gpointer data)
1654 struct gui *ui = data;
1657 dialog = gtk_file_chooser_dialog_new("Save File",
1658 GTK_WINDOW(ui->window),
1659 GTK_FILE_CHOOSER_ACTION_SAVE,
1660 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1661 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1664 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1665 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
1667 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1670 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1671 // save_job_file(filename);
1674 gtk_widget_destroy(dialog);
1677 static void view_log_destroy(GtkWidget *w, gpointer data)
1679 struct gui *ui = (struct gui *) data;
1681 gtk_widget_ref(ui->log_tree);
1682 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
1683 gtk_widget_destroy(w);
1684 ui->log_view = NULL;
1687 static void view_log(GtkWidget *w, gpointer data)
1689 GtkWidget *win, *scroll, *vbox, *box;
1690 struct gui *ui = (struct gui *) data;
1695 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1696 gtk_window_set_title(GTK_WINDOW(win), "Log");
1697 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
1699 scroll = gtk_scrolled_window_new(NULL, NULL);
1701 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
1703 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1705 box = gtk_hbox_new(TRUE, 0);
1706 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
1707 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
1708 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
1710 vbox = gtk_vbox_new(TRUE, 5);
1711 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
1713 gtk_container_add(GTK_CONTAINER(win), vbox);
1714 gtk_widget_show_all(win);
1717 static void preferences(GtkWidget *w, gpointer data)
1719 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
1722 dialog = gtk_dialog_new_with_buttons("Preferences",
1723 GTK_WINDOW(ui.window),
1724 GTK_DIALOG_DESTROY_WITH_PARENT,
1725 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1726 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1729 frame = gtk_frame_new("Debug logging");
1730 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1732 vbox = gtk_vbox_new(FALSE, 6);
1733 gtk_container_add(GTK_CONTAINER(frame), vbox);
1735 box = gtk_hbox_new(FALSE, 6);
1736 gtk_container_add(GTK_CONTAINER(vbox), box);
1738 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
1740 for (i = 0; i < FD_DEBUG_MAX; i++) {
1742 box = gtk_hbox_new(FALSE, 6);
1743 gtk_container_add(GTK_CONTAINER(vbox), box);
1747 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
1748 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
1749 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
1752 frame = gtk_frame_new("Graph font");
1753 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1754 vbox = gtk_vbox_new(FALSE, 6);
1755 gtk_container_add(GTK_CONTAINER(frame), vbox);
1757 font = gtk_font_button_new();
1758 gtk_box_pack_start(GTK_BOX(vbox), font, FALSE, FALSE, 5);
1760 gtk_widget_show_all(dialog);
1762 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1763 gtk_widget_destroy(dialog);
1767 for (i = 0; i < FD_DEBUG_MAX; i++) {
1770 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
1772 fio_debug |= (1UL << i);
1775 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
1776 gtk_widget_destroy(dialog);
1779 static void about_dialog(GtkWidget *w, gpointer data)
1781 const char *authors[] = {
1782 "Jens Axboe <axboe@kernel.dk>",
1783 "Stephen Carmeron <stephenmcameron@gmail.com>",
1786 const char *license[] = {
1787 "Fio is free software; you can redistribute it and/or modify "
1788 "it under the terms of the GNU General Public License as published by "
1789 "the Free Software Foundation; either version 2 of the License, or "
1790 "(at your option) any later version.\n",
1791 "Fio is distributed in the hope that it will be useful, "
1792 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
1793 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
1794 "GNU General Public License for more details.\n",
1795 "You should have received a copy of the GNU General Public License "
1796 "along with Fio; if not, write to the Free Software Foundation, Inc., "
1797 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
1799 char *license_trans;
1801 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
1802 license[2], "\n", NULL);
1804 gtk_show_about_dialog(NULL,
1805 "program-name", "gfio",
1806 "comments", "Gtk2 UI for fio",
1807 "license", license_trans,
1808 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
1810 "version", fio_version_string,
1811 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
1812 "logo-icon-name", "fio",
1814 "wrap-license", TRUE,
1817 g_free (license_trans);
1820 static GtkActionEntry menu_items[] = {
1821 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
1822 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
1823 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
1824 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
1825 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
1826 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
1827 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
1828 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
1829 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
1831 static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
1833 static const gchar *ui_string = " \
1835 <menubar name=\"MainMenu\"> \
1836 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
1837 <menuitem name=\"Open\" action=\"OpenFile\" /> \
1838 <menuitem name=\"Save\" action=\"SaveFile\" /> \
1839 <separator name=\"Separator\"/> \
1840 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
1841 <separator name=\"Separator2\"/> \
1842 <menuitem name=\"Quit\" action=\"Quit\" /> \
1844 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
1845 <menuitem name=\"Log\" action=\"ViewLog\" /> \
1847 <menu name=\"Help\" action=\"HelpMenuAction\"> \
1848 <menuitem name=\"About\" action=\"About\" /> \
1854 static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
1857 GtkActionGroup *action_group = gtk_action_group_new("Menu");
1860 action_group = gtk_action_group_new("Menu");
1861 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
1863 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1864 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
1866 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
1867 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
1870 void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
1871 GtkWidget *vbox, GtkUIManager *ui_manager)
1873 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
1876 static void init_ui(int *argc, char **argv[], struct gui *ui)
1878 GtkSettings *settings;
1879 GtkUIManager *uimanager;
1880 GtkWidget *menu, *probe, *probe_frame, *probe_box;
1883 memset(ui, 0, sizeof(*ui));
1885 /* Magical g*thread incantation, you just need this thread stuff.
1886 * Without it, the update that happens in gfio_update_thread_status
1887 * doesn't really happen in a timely fashion, you need expose events
1889 if (!g_thread_supported())
1890 g_thread_init(NULL);
1893 gtk_init(argc, argv);
1894 settings = gtk_settings_get_default();
1895 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
1898 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1899 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
1900 gtk_window_set_default_size(GTK_WINDOW(ui->window), 700, 700);
1902 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
1903 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
1905 ui->vbox = gtk_vbox_new(FALSE, 0);
1906 gtk_container_add(GTK_CONTAINER (ui->window), ui->vbox);
1908 uimanager = gtk_ui_manager_new();
1909 menu = get_menubar_menu(ui->window, uimanager, ui);
1910 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
1913 * Set up alignments for widgets at the top of ui,
1914 * align top left, expand horizontally but not vertically
1916 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
1917 ui->topvbox = gtk_vbox_new(FALSE, 3);
1918 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
1919 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->topalign, FALSE, FALSE, 0);
1921 probe = gtk_frame_new("Job");
1922 gtk_box_pack_start(GTK_BOX(ui->topvbox), probe, TRUE, FALSE, 3);
1923 probe_frame = gtk_vbox_new(FALSE, 3);
1924 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
1926 probe_box = gtk_hbox_new(FALSE, 3);
1927 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1928 ui->probe.hostname = new_info_label_in_frame(probe_box, "Host");
1929 ui->probe.os = new_info_label_in_frame(probe_box, "OS");
1930 ui->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
1931 ui->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
1933 probe_box = gtk_hbox_new(FALSE, 3);
1934 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1936 ui->eta.name = new_info_entry_in_frame(probe_box, "Name");
1937 ui->eta.iotype = new_info_entry_in_frame(probe_box, "IO");
1938 ui->eta.ioengine = new_info_entry_in_frame(probe_box, "IO Engine");
1939 ui->eta.iodepth = new_info_entry_in_frame(probe_box, "IO Depth");
1940 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
1941 ui->eta.files = new_info_entry_in_frame(probe_box, "Open files");
1943 probe_box = gtk_hbox_new(FALSE, 3);
1944 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1945 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1946 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1947 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1948 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
1951 * Only add this if we have a commit rate
1954 probe_box = gtk_hbox_new(FALSE, 3);
1955 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1957 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1958 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1960 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1961 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1965 * Set up a drawing area and IOPS and bandwidth graphs
1967 gdk_color_parse("white", &white);
1968 ui->drawing_area = gtk_drawing_area_new();
1969 ui->drawing_area_xdim = DRAWING_AREA_XDIM;
1970 ui->drawing_area_ydim = DRAWING_AREA_YDIM;
1971 gtk_widget_set_size_request(GTK_WIDGET(ui->drawing_area),
1972 ui->drawing_area_xdim, ui->drawing_area_ydim);
1973 gtk_widget_modify_bg(ui->drawing_area, GTK_STATE_NORMAL, &white);
1974 g_signal_connect(G_OBJECT(ui->drawing_area), "expose_event",
1975 G_CALLBACK (on_expose_drawing_area), ui);
1976 g_signal_connect(G_OBJECT(ui->drawing_area), "configure_event",
1977 G_CALLBACK (on_config_drawing_area), ui);
1978 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1979 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1980 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1981 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1983 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->scrolled_window,
1986 setup_iops_graph(ui);
1987 setup_bandwidth_graph(ui);
1990 * Set up alignments for widgets at the bottom of ui,
1991 * align bottom left, expand horizontally but not vertically
1993 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
1994 ui->buttonbox = gtk_hbox_new(FALSE, 0);
1995 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
1996 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->bottomalign,
1999 add_buttons(ui, buttonspeclist, ARRAYSIZE(buttonspeclist));
2002 * Set up thread status progress bar
2004 ui->thread_status_pb = gtk_progress_bar_new();
2005 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
2006 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
2007 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
2009 gfio_ui_setup_log(ui);
2011 gtk_widget_show_all(ui->window);
2014 int main(int argc, char *argv[], char *envp[])
2016 if (initialize_fio(envp))
2018 if (fio_init_options())
2021 init_ui(&argc, &argv, &ui);
2023 gdk_threads_enter();
2025 gdk_threads_leave();