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);
47 static void send_clicked(GtkWidget *widget, gpointer data);
49 static struct button_spec {
50 const char *buttontext;
52 const char *tooltiptext;
53 const int start_insensitive;
54 } buttonspeclist[] = {
55 #define CONNECT_BUTTON 0
57 #define START_JOB_BUTTON 2
58 { "Connect", connect_clicked, "Connect to host", 0 },
59 { "Send", send_clicked, "Send job description to host", 1 },
60 { "Start Job", start_job_clicked,
61 "Send current fio job to fio server to be executed", 1 },
83 GtkWidget *write_iops;
93 GtkWidget *bottomalign;
94 GtkWidget *thread_status_pb;
96 GtkWidget *button[ARRAYSIZE(buttonspeclist)];
97 GtkWidget *scrolled_window;
98 #define DRAWING_AREA_XDIM 1000
99 #define DRAWING_AREA_YDIM 400
100 GtkWidget *drawing_area;
101 int drawing_area_xdim;
102 int drawing_area_ydim;
103 GtkWidget *error_info_bar;
104 GtkWidget *error_label;
105 GtkWidget *results_notebook;
106 GtkWidget *results_window;
107 GtkListStore *log_model;
111 struct probe_widget probe;
112 struct eta_widget eta;
117 struct graph *iops_graph;
118 struct graph *bandwidth_graph;
119 struct gfio_client *client;
126 struct fio_client *client;
127 GtkWidget *results_widget;
128 GtkWidget *disk_util_frame;
129 GtkWidget *err_entry;
130 unsigned int job_added;
131 struct thread_options o;
134 static void setup_iops_graph(struct gui *ui)
137 graph_free(ui->iops_graph);
138 ui->iops_graph = graph_new(DRAWING_AREA_XDIM / 2.0,
139 DRAWING_AREA_YDIM, gfio_graph_font);
140 graph_title(ui->iops_graph, "IOPS");
141 graph_x_title(ui->iops_graph, "Time (secs)");
142 graph_y_title(ui->iops_graph, "IOs / sec");
143 graph_add_label(ui->iops_graph, "Read IOPS");
144 graph_add_label(ui->iops_graph, "Write IOPS");
145 graph_set_color(ui->iops_graph, "Read IOPS", 0.13, 0.54, 0.13);
146 graph_set_color(ui->iops_graph, "Write IOPS", 1.0, 0.0, 0.0);
147 line_graph_set_data_count_limit(ui->iops_graph, 100);
150 static void setup_bandwidth_graph(struct gui *ui)
152 if (ui->bandwidth_graph)
153 graph_free(ui->bandwidth_graph);
154 ui->bandwidth_graph = graph_new(DRAWING_AREA_XDIM / 2.0,
155 DRAWING_AREA_YDIM, gfio_graph_font);
156 graph_title(ui->bandwidth_graph, "Bandwidth");
157 graph_x_title(ui->bandwidth_graph, "Time (secs)");
158 graph_y_title(ui->bandwidth_graph, "Kbytes / sec");
159 graph_add_label(ui->bandwidth_graph, "Read Bandwidth");
160 graph_add_label(ui->bandwidth_graph, "Write Bandwidth");
161 graph_set_color(ui->bandwidth_graph, "Read Bandwidth", 0.13, 0.54, 0.13);
162 graph_set_color(ui->bandwidth_graph, "Write Bandwidth", 1.0, 0.0, 0.0);
163 line_graph_set_data_count_limit(ui->bandwidth_graph, 100);
166 static void clear_ui_info(struct gui *ui)
168 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), "");
169 gtk_label_set_text(GTK_LABEL(ui->probe.os), "");
170 gtk_label_set_text(GTK_LABEL(ui->probe.arch), "");
171 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), "");
172 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), "");
173 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), "");
174 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), "");
175 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), "");
176 gtk_entry_set_text(GTK_ENTRY(ui->eta.jobs), "");
177 gtk_entry_set_text(GTK_ENTRY(ui->eta.files), "");
178 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), "");
179 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), "");
180 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), "");
181 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), "");
184 static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
186 GtkWidget *entry, *frame;
188 frame = gtk_frame_new(label);
189 entry = gtk_entry_new();
190 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
191 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
192 gtk_container_add(GTK_CONTAINER(frame), entry);
197 static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
199 GtkWidget *label_widget;
202 frame = gtk_frame_new(label);
203 label_widget = gtk_label_new(NULL);
204 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
205 gtk_container_add(GTK_CONTAINER(frame), label_widget);
210 static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
212 GtkWidget *button, *box;
214 box = gtk_hbox_new(FALSE, 3);
215 gtk_container_add(GTK_CONTAINER(hbox), box);
217 button = gtk_spin_button_new_with_range(min, max, 1.0);
218 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
220 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
221 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
226 static void gfio_set_connected(struct gui *ui, int connected)
229 gtk_widget_set_sensitive(ui->button[SEND_BUTTON], 1);
231 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Disconnect");
232 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
235 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Connect");
236 gtk_widget_set_sensitive(ui->button[SEND_BUTTON], 0);
237 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
238 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
242 static void label_set_int_value(GtkWidget *entry, unsigned int val)
246 sprintf(tmp, "%u", val);
247 gtk_label_set_text(GTK_LABEL(entry), tmp);
250 static void entry_set_int_value(GtkWidget *entry, unsigned int val)
254 sprintf(tmp, "%u", val);
255 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
259 #define ALIGN_RIGHT 2
263 GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
265 GtkCellRenderer *renderer;
266 GtkTreeViewColumn *col;
267 double xalign = 0.0; /* left as default */
268 PangoAlignment align;
271 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
272 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
274 visible = !(flags & INVISIBLE);
276 renderer = gtk_cell_renderer_text_new();
277 col = gtk_tree_view_column_new();
279 gtk_tree_view_column_set_title(col, title);
280 if (!(flags & UNSORTABLE))
281 gtk_tree_view_column_set_sort_column_id(col, index);
282 gtk_tree_view_column_set_resizable(col, TRUE);
283 gtk_tree_view_column_pack_start(col, renderer, TRUE);
284 gtk_tree_view_column_add_attribute(col, renderer, "text", index);
285 gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
287 case PANGO_ALIGN_LEFT:
290 case PANGO_ALIGN_CENTER:
293 case PANGO_ALIGN_RIGHT:
297 gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
298 gtk_tree_view_column_set_visible(col, visible);
299 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
303 static void gfio_ui_setup_log(struct gui *ui)
305 GtkTreeSelection *selection;
307 GtkWidget *tree_view;
309 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
311 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
312 gtk_widget_set_can_focus(tree_view, FALSE);
314 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
315 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
316 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
317 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
319 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
320 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
321 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
322 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
324 ui->log_model = model;
325 ui->log_tree = tree_view;
328 static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
334 GType types[FIO_IO_U_LIST_MAX_LEN];
335 GtkWidget *tree_view;
336 GtkTreeSelection *selection;
341 for (i = 0; i < len; i++)
342 types[i] = G_TYPE_INT;
344 model = gtk_list_store_newv(len, types);
346 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
347 gtk_widget_set_can_focus(tree_view, FALSE);
349 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
350 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
352 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
353 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
355 for (i = 0; i < len; i++) {
358 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
359 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
362 gtk_list_store_append(model, &iter);
364 for (i = 0; i < len; i++) {
366 ovals[i] = (ovals[i] + 999) / 1000;
367 gtk_list_store_set(model, &iter, i, ovals[i], -1);
373 static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
376 unsigned int *io_u_plat = ts->io_u_plat[ddir];
377 unsigned long nr = ts->clat_stat[ddir].samples;
378 fio_fp64_t *plist = ts->percentile_list;
379 unsigned int *ovals, len, minv, maxv, scale_down;
381 GtkWidget *tree_view, *frame, *hbox;
384 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
389 * We default to usecs, but if the value range is such that we
390 * should scale down to msecs, do that.
392 if (minv > 2000 && maxv > 99999) {
400 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
402 sprintf(tmp, "Completion percentiles (%s)", base);
403 frame = gtk_frame_new(tmp);
404 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
406 hbox = gtk_hbox_new(FALSE, 3);
407 gtk_container_add(GTK_CONTAINER(frame), hbox);
409 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
415 static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
416 unsigned long max, double mean, double dev)
418 const char *base = "(usec)";
419 GtkWidget *hbox, *label, *frame;
423 if (!usec_to_msec(&min, &max, &mean, &dev))
426 minp = num2str(min, 6, 1, 0);
427 maxp = num2str(max, 6, 1, 0);
429 sprintf(tmp, "%s %s", name, base);
430 frame = gtk_frame_new(tmp);
431 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
433 hbox = gtk_hbox_new(FALSE, 3);
434 gtk_container_add(GTK_CONTAINER(frame), hbox);
436 label = new_info_label_in_frame(hbox, "Minimum");
437 gtk_label_set_text(GTK_LABEL(label), minp);
438 label = new_info_label_in_frame(hbox, "Maximum");
439 gtk_label_set_text(GTK_LABEL(label), maxp);
440 label = new_info_label_in_frame(hbox, "Average");
441 sprintf(tmp, "%5.02f", mean);
442 gtk_label_set_text(GTK_LABEL(label), tmp);
443 label = new_info_label_in_frame(hbox, "Standard deviation");
444 sprintf(tmp, "%5.02f", dev);
445 gtk_label_set_text(GTK_LABEL(label), tmp);
456 static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
457 struct thread_stat *ts, int ddir)
459 const char *ddir_label[2] = { "Read", "Write" };
460 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
461 unsigned long min[3], max[3], runt;
462 unsigned long long bw, iops;
463 unsigned int flags = 0;
464 double mean[3], dev[3];
465 char *io_p, *bw_p, *iops_p;
468 if (!ts->runtime[ddir])
471 i2p = is_power_of_2(rs->kb_base);
472 runt = ts->runtime[ddir];
474 bw = (1000 * ts->io_bytes[ddir]) / runt;
475 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
476 bw_p = num2str(bw, 6, 1, i2p);
478 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
479 iops_p = num2str(iops, 6, 1, 0);
481 box = gtk_hbox_new(FALSE, 3);
482 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
484 frame = gtk_frame_new(ddir_label[ddir]);
485 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
487 main_vbox = gtk_vbox_new(FALSE, 3);
488 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
490 box = gtk_hbox_new(FALSE, 3);
491 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
493 label = new_info_label_in_frame(box, "IO");
494 gtk_label_set_text(GTK_LABEL(label), io_p);
495 label = new_info_label_in_frame(box, "Bandwidth");
496 gtk_label_set_text(GTK_LABEL(label), bw_p);
497 label = new_info_label_in_frame(box, "IOPS");
498 gtk_label_set_text(GTK_LABEL(label), iops_p);
499 label = new_info_label_in_frame(box, "Runtime (msec)");
500 label_set_int_value(label, ts->runtime[ddir]);
502 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
503 double p_of_agg = 100.0;
504 const char *bw_str = "KB";
508 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
509 if (p_of_agg > 100.0)
513 if (mean[0] > 999999.9) {
521 sprintf(tmp, "Bandwidth (%s)", bw_str);
522 frame = gtk_frame_new(tmp);
523 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
525 box = gtk_hbox_new(FALSE, 3);
526 gtk_container_add(GTK_CONTAINER(frame), box);
528 label = new_info_label_in_frame(box, "Minimum");
529 label_set_int_value(label, min[0]);
530 label = new_info_label_in_frame(box, "Maximum");
531 label_set_int_value(label, max[0]);
532 label = new_info_label_in_frame(box, "Percentage of jobs");
533 sprintf(tmp, "%3.2f%%", p_of_agg);
534 gtk_label_set_text(GTK_LABEL(label), tmp);
535 label = new_info_label_in_frame(box, "Average");
536 sprintf(tmp, "%5.02f", mean[0]);
537 gtk_label_set_text(GTK_LABEL(label), tmp);
538 label = new_info_label_in_frame(box, "Standard deviation");
539 sprintf(tmp, "%5.02f", dev[0]);
540 gtk_label_set_text(GTK_LABEL(label), tmp);
543 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
545 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
547 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
551 frame = gtk_frame_new("Latency");
552 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
554 vbox = gtk_vbox_new(FALSE, 3);
555 gtk_container_add(GTK_CONTAINER(frame), vbox);
557 if (flags & GFIO_SLAT)
558 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
559 if (flags & GFIO_CLAT)
560 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
561 if (flags & GFIO_LAT)
562 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
565 if (ts->clat_percentiles)
566 gfio_show_clat_percentiles(main_vbox, ts, ddir);
574 static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
577 GtkWidget *tree_view;
578 GtkTreeSelection *selection;
585 * Check if all are empty, in which case don't bother
587 for (i = 0, skipped = 0; i < num; i++)
594 types = malloc(num * sizeof(GType));
596 for (i = 0; i < num; i++)
597 types[i] = G_TYPE_STRING;
599 model = gtk_list_store_newv(num, types);
603 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
604 gtk_widget_set_can_focus(tree_view, FALSE);
606 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
607 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
609 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
610 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
612 for (i = 0; i < num; i++)
613 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
615 gtk_list_store_append(model, &iter);
617 for (i = 0; i < num; i++) {
621 sprintf(fbuf, "0.00");
623 sprintf(fbuf, "%3.2f%%", lat[i]);
625 gtk_list_store_set(model, &iter, i, fbuf, -1);
631 static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
633 GtkWidget *box, *frame, *tree_view;
634 double io_u_lat_u[FIO_IO_U_LAT_U_NR];
635 double io_u_lat_m[FIO_IO_U_LAT_M_NR];
636 const char *uranges[] = { "2", "4", "10", "20", "50", "100",
637 "250", "500", "750", "1000", };
638 const char *mranges[] = { "2", "4", "10", "20", "50", "100",
639 "250", "500", "750", "1000", "2000",
642 stat_calc_lat_u(ts, io_u_lat_u);
643 stat_calc_lat_m(ts, io_u_lat_m);
645 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
647 frame = gtk_frame_new("Latency buckets (usec)");
648 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
650 box = gtk_hbox_new(FALSE, 3);
651 gtk_container_add(GTK_CONTAINER(frame), box);
652 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
655 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
657 frame = gtk_frame_new("Latency buckets (msec)");
658 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
660 box = gtk_hbox_new(FALSE, 3);
661 gtk_container_add(GTK_CONTAINER(frame), box);
662 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
666 static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
668 GtkWidget *box, *frame, *entry;
669 double usr_cpu, sys_cpu;
670 unsigned long runtime;
673 runtime = ts->total_run_time;
675 double runt = (double) runtime;
677 usr_cpu = (double) ts->usr_time * 100 / runt;
678 sys_cpu = (double) ts->sys_time * 100 / runt;
684 frame = gtk_frame_new("OS resources");
685 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
687 box = gtk_hbox_new(FALSE, 3);
688 gtk_container_add(GTK_CONTAINER(frame), box);
690 entry = new_info_entry_in_frame(box, "User CPU");
691 sprintf(tmp, "%3.2f%%", usr_cpu);
692 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
693 entry = new_info_entry_in_frame(box, "System CPU");
694 sprintf(tmp, "%3.2f%%", sys_cpu);
695 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
696 entry = new_info_entry_in_frame(box, "Context switches");
697 entry_set_int_value(entry, ts->ctx);
698 entry = new_info_entry_in_frame(box, "Major faults");
699 entry_set_int_value(entry, ts->majf);
700 entry = new_info_entry_in_frame(box, "Minor faults");
701 entry_set_int_value(entry, ts->minf);
703 static void gfio_add_sc_depths_tree(GtkListStore *model,
704 struct thread_stat *ts, unsigned int len,
707 double io_u_dist[FIO_IO_U_MAP_NR];
709 /* Bits 0, and 3-8 */
710 const int add_mask = 0x1f9;
714 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
716 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
718 gtk_list_store_append(model, &iter);
720 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
722 for (i = 1, j = 0; i < len; i++) {
725 if (!(add_mask & (1UL << (i - 1))))
726 sprintf(fbuf, "0.0%%");
728 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
732 gtk_list_store_set(model, &iter, i, fbuf, -1);
737 static void gfio_add_total_depths_tree(GtkListStore *model,
738 struct thread_stat *ts, unsigned int len)
740 double io_u_dist[FIO_IO_U_MAP_NR];
742 /* Bits 1-6, and 8 */
743 const int add_mask = 0x17e;
746 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
748 gtk_list_store_append(model, &iter);
750 gtk_list_store_set(model, &iter, 0, "Total", -1);
752 for (i = 1, j = 0; i < len; i++) {
755 if (!(add_mask & (1UL << (i - 1))))
756 sprintf(fbuf, "0.0%%");
758 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
762 gtk_list_store_set(model, &iter, i, fbuf, -1);
767 static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
769 GtkWidget *frame, *box, *tree_view;
770 GtkTreeSelection *selection;
772 GType types[FIO_IO_U_MAP_NR + 1];
775 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
777 frame = gtk_frame_new("IO depths");
778 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
780 box = gtk_hbox_new(FALSE, 3);
781 gtk_container_add(GTK_CONTAINER(frame), box);
783 for (i = 0; i < NR_LABELS; i++)
784 types[i] = G_TYPE_STRING;
786 model = gtk_list_store_newv(NR_LABELS, types);
788 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
789 gtk_widget_set_can_focus(tree_view, FALSE);
791 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
792 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
794 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
795 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
797 for (i = 0; i < NR_LABELS; i++)
798 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
800 gfio_add_total_depths_tree(model, ts, NR_LABELS);
801 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 1);
802 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 0);
804 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
807 static gboolean results_window_delete(GtkWidget *w, gpointer data)
809 struct gui *ui = (struct gui *) data;
811 gtk_widget_destroy(w);
812 ui->results_window = NULL;
813 ui->results_notebook = NULL;
817 static GtkWidget *get_results_window(struct gui *ui)
819 GtkWidget *win, *notebook;
821 if (ui->results_window)
822 return ui->results_notebook;
824 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
825 gtk_window_set_title(GTK_WINDOW(win), "Results");
826 gtk_window_set_default_size(GTK_WINDOW(win), 1024, 768);
827 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ui);
828 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ui);
830 notebook = gtk_notebook_new();
831 gtk_container_add(GTK_CONTAINER(win), notebook);
833 ui->results_window = win;
834 ui->results_notebook = notebook;
835 return ui->results_notebook;
838 static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
839 struct group_run_stats *rs)
841 GtkWidget *res_win, *box, *vbox, *entry, *scroll;
842 struct gfio_client *gc = client->client_data;
846 res_win = get_results_window(gc->ui);
848 scroll = gtk_scrolled_window_new(NULL, NULL);
849 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
850 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
852 vbox = gtk_vbox_new(FALSE, 3);
854 box = gtk_hbox_new(FALSE, 0);
855 gtk_box_pack_start(GTK_BOX(vbox), box, TRUE, FALSE, 5);
857 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
859 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), scroll, gtk_label_new(ts->name));
861 gc->results_widget = vbox;
863 entry = new_info_entry_in_frame(box, "Name");
864 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
865 if (strlen(ts->description)) {
866 entry = new_info_entry_in_frame(box, "Description");
867 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
869 entry = new_info_entry_in_frame(box, "Group ID");
870 entry_set_int_value(entry, ts->groupid);
871 entry = new_info_entry_in_frame(box, "Jobs");
872 entry_set_int_value(entry, ts->members);
873 gc->err_entry = entry = new_info_entry_in_frame(box, "Error");
874 entry_set_int_value(entry, ts->error);
875 entry = new_info_entry_in_frame(box, "PID");
876 entry_set_int_value(entry, ts->pid);
878 if (ts->io_bytes[DDIR_READ])
879 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
880 if (ts->io_bytes[DDIR_WRITE])
881 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
883 gfio_show_latency_buckets(vbox, ts);
884 gfio_show_cpu_usage(vbox, ts);
885 gfio_show_io_depths(vbox, ts);
887 gtk_widget_show_all(gc->ui->results_window);
891 static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
893 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
894 struct gfio_client *gc = client->client_data;
898 char tmp[64], timebuf[80];
901 tm = localtime(&sec);
902 strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", tm);
903 sprintf(timebuf, "%s.%03ld", tmp, p->log_usec / 1000);
907 gtk_list_store_append(gc->ui->log_model, &iter);
908 gtk_list_store_set(gc->ui->log_model, &iter, 0, timebuf, -1);
909 gtk_list_store_set(gc->ui->log_model, &iter, 1, client->hostname, -1);
910 gtk_list_store_set(gc->ui->log_model, &iter, 2, p->level, -1);
911 gtk_list_store_set(gc->ui->log_model, &iter, 3, p->buf, -1);
913 if (p->level == FIO_LOG_ERR)
914 view_log(NULL, (gpointer) gc->ui);
919 static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
921 struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
922 struct gfio_client *gc = client->client_data;
923 GtkWidget *box, *frame, *entry, *vbox;
929 if (!gc->results_widget)
932 if (!gc->disk_util_frame) {
933 gc->disk_util_frame = gtk_frame_new("Disk utilization");
934 gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
937 vbox = gtk_vbox_new(FALSE, 3);
938 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
940 frame = gtk_frame_new((char *) p->dus.name);
941 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
943 box = gtk_vbox_new(FALSE, 3);
944 gtk_container_add(GTK_CONTAINER(frame), box);
946 frame = gtk_frame_new("Read");
947 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
948 vbox = gtk_hbox_new(TRUE, 3);
949 gtk_container_add(GTK_CONTAINER(frame), vbox);
950 entry = new_info_entry_in_frame(vbox, "IOs");
951 entry_set_int_value(entry, p->dus.ios[0]);
952 entry = new_info_entry_in_frame(vbox, "Merges");
953 entry_set_int_value(entry, p->dus.merges[0]);
954 entry = new_info_entry_in_frame(vbox, "Sectors");
955 entry_set_int_value(entry, p->dus.sectors[0]);
956 entry = new_info_entry_in_frame(vbox, "Ticks");
957 entry_set_int_value(entry, p->dus.ticks[0]);
959 frame = gtk_frame_new("Write");
960 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
961 vbox = gtk_hbox_new(TRUE, 3);
962 gtk_container_add(GTK_CONTAINER(frame), vbox);
963 entry = new_info_entry_in_frame(vbox, "IOs");
964 entry_set_int_value(entry, p->dus.ios[1]);
965 entry = new_info_entry_in_frame(vbox, "Merges");
966 entry_set_int_value(entry, p->dus.merges[1]);
967 entry = new_info_entry_in_frame(vbox, "Sectors");
968 entry_set_int_value(entry, p->dus.sectors[1]);
969 entry = new_info_entry_in_frame(vbox, "Ticks");
970 entry_set_int_value(entry, p->dus.ticks[1]);
972 frame = gtk_frame_new("Shared");
973 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
974 vbox = gtk_hbox_new(TRUE, 3);
975 gtk_container_add(GTK_CONTAINER(frame), vbox);
976 entry = new_info_entry_in_frame(vbox, "IO ticks");
977 entry_set_int_value(entry, p->dus.io_ticks);
978 entry = new_info_entry_in_frame(vbox, "Time in queue");
979 entry_set_int_value(entry, p->dus.time_in_queue);
983 util = (double) 100 * p->dus.io_ticks / (double) p->dus.msec;
987 sprintf(tmp, "%3.2f%%", util);
988 entry = new_info_entry_in_frame(vbox, "Disk utilization");
989 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
991 gtk_widget_show_all(gc->results_widget);
996 extern int sum_stat_clients;
997 extern struct thread_stat client_ts;
998 extern struct group_run_stats client_gs;
1000 static int sum_stat_nr;
1002 static void gfio_thread_status_op(struct fio_client *client,
1003 struct fio_net_cmd *cmd)
1005 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
1007 gfio_display_ts(client, &p->ts, &p->rs);
1009 if (sum_stat_clients == 1)
1012 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
1013 sum_group_stats(&client_gs, &p->rs);
1015 client_ts.members++;
1016 client_ts.groupid = p->ts.groupid;
1018 if (++sum_stat_nr == sum_stat_clients) {
1019 strcpy(client_ts.name, "All clients");
1020 gfio_display_ts(client, &client_ts, &client_gs);
1024 static void gfio_group_stats_op(struct fio_client *client,
1025 struct fio_net_cmd *cmd)
1027 gdk_threads_enter();
1028 printf("gfio_group_stats_op called\n");
1029 fio_client_ops.group_stats(client, cmd);
1030 gdk_threads_leave();
1033 static gint on_config_drawing_area(GtkWidget *w, GdkEventConfigure *event)
1035 ui.drawing_area_xdim = w->allocation.width;
1036 ui.drawing_area_ydim = w->allocation.height;
1040 static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
1042 struct gui *ui = (struct gui *) p;
1045 graph_set_size(ui->iops_graph, ui->drawing_area_xdim / 2.0,
1046 ui->drawing_area_ydim);
1047 graph_set_size(ui->bandwidth_graph, ui->drawing_area_xdim / 2.0,
1048 ui->drawing_area_ydim);
1049 cr = gdk_cairo_create(w->window);
1051 cairo_set_source_rgb(cr, 0, 0, 0);
1054 cairo_translate(cr, 0, 0);
1055 line_graph_draw(ui->bandwidth_graph, cr);
1060 cairo_translate(cr, ui->drawing_area_xdim / 2.0, 0);
1061 line_graph_draw(ui->iops_graph, cr);
1069 static void gfio_update_eta(struct jobs_eta *je)
1071 static int eta_good;
1078 gdk_threads_enter();
1083 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1084 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1085 eta_to_str(eta_str, je->eta_sec);
1088 sprintf(tmp, "%u", je->nr_running);
1089 gtk_entry_set_text(GTK_ENTRY(ui.eta.jobs), tmp);
1090 sprintf(tmp, "%u", je->files_open);
1091 gtk_entry_set_text(GTK_ENTRY(ui.eta.files), tmp);
1094 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1095 if (je->m_rate || je->t_rate) {
1098 mr = num2str(je->m_rate, 4, 0, i2p);
1099 tr = num2str(je->t_rate, 4, 0, i2p);
1100 gtk_entry_set_text(GTK_ENTRY(ui.eta);
1101 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1104 } else if (je->m_iops || je->t_iops)
1105 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
1107 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_bw), "---");
1108 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_iops), "---");
1109 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_bw), "---");
1110 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_iops), "---");
1113 if (je->eta_sec != INT_MAX && je->nr_running) {
1117 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1118 strcpy(output, "-.-% done");
1122 sprintf(output, "%3.1f%% done", perc);
1125 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1126 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1128 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1129 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1131 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_bw), rate_str[0]);
1132 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_iops), iops_str[0]);
1133 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_bw), rate_str[1]);
1134 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_iops), iops_str[1]);
1136 graph_add_xy_data(ui.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1137 graph_add_xy_data(ui.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1138 graph_add_xy_data(ui.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1139 graph_add_xy_data(ui.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
1148 char *dst = output + strlen(output);
1150 sprintf(dst, " - %s", eta_str);
1153 gfio_update_thread_status(output, perc);
1154 gdk_threads_leave();
1157 static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1159 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
1160 struct gfio_client *gc = client->client_data;
1161 struct gui *ui = gc->ui;
1162 const char *os, *arch;
1165 os = fio_get_os_string(probe->os);
1169 arch = fio_get_arch_string(probe->arch);
1174 client->name = strdup((char *) probe->hostname);
1176 gdk_threads_enter();
1178 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), (char *) probe->hostname);
1179 gtk_label_set_text(GTK_LABEL(ui->probe.os), os);
1180 gtk_label_set_text(GTK_LABEL(ui->probe.arch), arch);
1181 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
1182 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), buf);
1184 gfio_set_connected(ui, 1);
1186 gdk_threads_leave();
1189 static void gfio_update_thread_status(char *status_message, double perc)
1191 static char message[100];
1192 const char *m = message;
1194 strncpy(message, status_message, sizeof(message) - 1);
1195 gtk_progress_bar_set_text(
1196 GTK_PROGRESS_BAR(ui.thread_status_pb), m);
1197 gtk_progress_bar_set_fraction(
1198 GTK_PROGRESS_BAR(ui.thread_status_pb), perc / 100.0);
1199 gtk_widget_queue_draw(ui.window);
1202 static void gfio_quit_op(struct fio_client *client)
1204 struct gfio_client *gc = client->client_data;
1206 gdk_threads_enter();
1207 gfio_set_connected(gc->ui, 0);
1208 gdk_threads_leave();
1211 static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1213 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
1214 struct gfio_client *gc = client->client_data;
1215 struct thread_options *o = &gc->o;
1216 struct gui *ui = gc->ui;
1219 convert_thread_options_to_cpu(o, &p->top);
1221 gdk_threads_enter();
1223 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), (gchar *) o->name);
1224 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), ddir_str(o->td_ddir));
1225 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), (gchar *) o->ioengine);
1227 sprintf(tmp, "%u", o->iodepth);
1228 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), tmp);
1232 gdk_threads_leave();
1235 static void gfio_client_timed_out(struct fio_client *client)
1237 struct gfio_client *gc = client->client_data;
1238 GtkWidget *dialog, *label, *content;
1241 gdk_threads_enter();
1243 gfio_set_connected(gc->ui, 0);
1244 clear_ui_info(gc->ui);
1246 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
1248 dialog = gtk_dialog_new_with_buttons("Timed out!",
1249 GTK_WINDOW(gc->ui->window),
1250 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1251 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1253 /* gtk_dialog_get_content_area() is 2.14 and newer */
1254 content = GTK_DIALOG(dialog)->vbox;
1256 label = gtk_label_new((const gchar *) buf);
1257 gtk_container_add(GTK_CONTAINER(content), label);
1258 gtk_widget_show_all(dialog);
1259 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1261 gtk_dialog_run(GTK_DIALOG(dialog));
1262 gtk_widget_destroy(dialog);
1264 gdk_threads_leave();
1267 static void gfio_client_stop(struct fio_client *client, struct fio_net_cmd *cmd)
1269 struct gfio_client *gc = client->client_data;
1271 gdk_threads_enter();
1273 gfio_set_connected(gc->ui, 0);
1276 entry_set_int_value(gc->err_entry, client->error);
1278 gdk_threads_leave();
1281 struct client_ops gfio_client_ops = {
1282 .text_op = gfio_text_op,
1283 .disk_util = gfio_disk_util_op,
1284 .thread_status = gfio_thread_status_op,
1285 .group_stats = gfio_group_stats_op,
1286 .eta = gfio_update_eta,
1287 .probe = gfio_probe_op,
1288 .quit = gfio_quit_op,
1289 .add_job = gfio_add_job_op,
1290 .timed_out = gfio_client_timed_out,
1291 .stop = gfio_client_stop,
1292 .stay_connected = 1,
1295 static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1296 __attribute__((unused)) gpointer data)
1301 static void *job_thread(void *arg)
1303 fio_handle_clients(&gfio_client_ops);
1307 static int send_job_files(struct gui *ui)
1311 for (i = 0; i < ui->nr_job_files; i++) {
1312 ret = fio_clients_send_ini(ui->job_files[i]);
1316 free(ui->job_files[i]);
1317 ui->job_files[i] = NULL;
1319 while (i < ui->nr_job_files) {
1320 free(ui->job_files[i]);
1321 ui->job_files[i] = NULL;
1328 static void *server_thread(void *arg)
1331 gfio_server_running = 1;
1332 fio_start_server(NULL);
1333 gfio_server_running = 0;
1337 static void gfio_start_server(struct gui *ui)
1339 if (!gfio_server_running) {
1340 gfio_server_running = 1;
1341 pthread_create(&ui->server_t, NULL, server_thread, NULL);
1342 pthread_detach(ui->server_t);
1346 static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1349 struct gui *ui = data;
1350 struct gfio_client *gc = ui->client;
1352 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
1353 fio_net_send_simple_cmd(gc->client->fd, FIO_NET_CMD_RUN, 0, NULL);
1356 static void file_open(GtkWidget *w, gpointer data);
1358 static void connect_clicked(GtkWidget *widget, gpointer data)
1360 struct gui *ui = data;
1362 if (!ui->connected) {
1363 if (!ui->nr_job_files)
1364 file_open(widget, data);
1365 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
1366 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
1367 if (!fio_clients_connect()) {
1368 pthread_create(&ui->t, NULL, job_thread, NULL);
1369 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 0);
1370 gtk_widget_set_sensitive(ui->button[SEND_BUTTON], 1);
1373 fio_clients_terminate();
1374 gfio_set_connected(ui, 0);
1379 static void send_clicked(GtkWidget *widget, gpointer data)
1381 struct gui *ui = data;
1383 if (send_job_files(ui)) {
1384 printf("Yeah, I didn't really like those options too much.\n");
1385 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
1388 gtk_widget_set_sensitive(ui->button[SEND_BUTTON], 0);
1389 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
1392 static void add_button(struct gui *ui, int i, GtkWidget *buttonbox,
1393 struct button_spec *buttonspec)
1395 ui->button[i] = gtk_button_new_with_label(buttonspec->buttontext);
1396 g_signal_connect(ui->button[i], "clicked", G_CALLBACK (buttonspec->f), ui);
1397 gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], FALSE, FALSE, 3);
1398 gtk_widget_set_tooltip_text(ui->button[i], buttonspeclist[i].tooltiptext);
1399 gtk_widget_set_sensitive(ui->button[i], !buttonspec->start_insensitive);
1402 static void add_buttons(struct gui *ui,
1403 struct button_spec *buttonlist,
1408 for (i = 0; i < nbuttons; i++)
1409 add_button(ui, i, ui->buttonbox, &buttonlist[i]);
1412 static void on_info_bar_response(GtkWidget *widget, gint response,
1415 if (response == GTK_RESPONSE_OK) {
1416 gtk_widget_destroy(widget);
1417 ui.error_info_bar = NULL;
1421 void report_error(GError *error)
1423 if (ui.error_info_bar == NULL) {
1424 ui.error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
1427 g_signal_connect(ui.error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1428 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui.error_info_bar),
1431 ui.error_label = gtk_label_new(error->message);
1432 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui.error_info_bar));
1433 gtk_container_add(GTK_CONTAINER(container), ui.error_label);
1435 gtk_box_pack_start(GTK_BOX(ui.vbox), ui.error_info_bar, FALSE, FALSE, 0);
1436 gtk_widget_show_all(ui.vbox);
1439 snprintf(buffer, sizeof(buffer), "Failed to open file.");
1440 gtk_label_set(GTK_LABEL(ui.error_label), buffer);
1444 struct connection_widgets
1451 static void hostname_cb(GtkEntry *entry, gpointer data)
1453 struct connection_widgets *cw = data;
1454 int uses_net = 0, is_localhost = 0;
1459 * Check whether to display the 'auto start backend' box
1460 * or not. Show it if we are a localhost and using network,
1461 * or using a socket.
1463 ctext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->combo));
1464 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
1469 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
1470 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
1471 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
1472 !strcmp(text, "ip6-loopback"))
1476 if (!uses_net || is_localhost) {
1477 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
1478 gtk_widget_set_sensitive(cw->button, 1);
1480 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
1481 gtk_widget_set_sensitive(cw->button, 0);
1485 static int get_connection_details(char **host, int *port, int *type,
1488 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
1489 struct connection_widgets cw;
1492 dialog = gtk_dialog_new_with_buttons("Connection details",
1493 GTK_WINDOW(ui.window),
1494 GTK_DIALOG_DESTROY_WITH_PARENT,
1495 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1496 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1498 frame = gtk_frame_new("Hostname / socket name");
1499 /* gtk_dialog_get_content_area() is 2.14 and newer */
1500 vbox = GTK_DIALOG(dialog)->vbox;
1501 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1503 box = gtk_vbox_new(FALSE, 6);
1504 gtk_container_add(GTK_CONTAINER(frame), box);
1506 hbox = gtk_hbox_new(TRUE, 10);
1507 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1508 cw.hentry = gtk_entry_new();
1509 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
1510 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
1512 frame = gtk_frame_new("Port");
1513 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1514 box = gtk_vbox_new(FALSE, 10);
1515 gtk_container_add(GTK_CONTAINER(frame), box);
1517 hbox = gtk_hbox_new(TRUE, 4);
1518 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1519 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1521 frame = gtk_frame_new("Type");
1522 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1523 box = gtk_vbox_new(FALSE, 10);
1524 gtk_container_add(GTK_CONTAINER(frame), box);
1526 hbox = gtk_hbox_new(TRUE, 4);
1527 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1529 cw.combo = gtk_combo_box_new_text();
1530 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv4");
1531 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv6");
1532 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "local socket");
1533 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
1535 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
1537 frame = gtk_frame_new("Options");
1538 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1539 box = gtk_vbox_new(FALSE, 10);
1540 gtk_container_add(GTK_CONTAINER(frame), box);
1542 hbox = gtk_hbox_new(TRUE, 4);
1543 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1545 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1546 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
1547 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.");
1548 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
1551 * Connect edit signal, so we can show/not-show the auto start button
1553 g_signal_connect(GTK_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
1554 g_signal_connect(GTK_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
1556 gtk_widget_show_all(dialog);
1558 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1559 gtk_widget_destroy(dialog);
1563 *host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
1564 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1566 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw.combo));
1567 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1568 *type = Fio_client_ipv4;
1569 else if (!strncmp(typeentry, "IPv6", 4))
1570 *type = Fio_client_ipv6;
1572 *type = Fio_client_socket;
1575 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
1577 gtk_widget_destroy(dialog);
1581 static void gfio_client_added(struct gui *ui, struct fio_client *client)
1583 struct gfio_client *gc;
1585 gc = malloc(sizeof(*gc));
1586 memset(gc, 0, sizeof(*gc));
1588 gc->client = client;
1592 client->client_data = gc;
1595 static void file_open(GtkWidget *w, gpointer data)
1598 struct gui *ui = data;
1599 GSList *filenames, *fn_glist;
1600 GtkFileFilter *filter;
1602 int port, type, server_start;
1604 dialog = gtk_file_chooser_dialog_new("Open File",
1605 GTK_WINDOW(ui->window),
1606 GTK_FILE_CHOOSER_ACTION_OPEN,
1607 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1608 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1610 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1612 filter = gtk_file_filter_new();
1613 gtk_file_filter_add_pattern(filter, "*.fio");
1614 gtk_file_filter_add_pattern(filter, "*.job");
1615 gtk_file_filter_add_pattern(filter, "*.ini");
1616 gtk_file_filter_add_mime_type(filter, "text/fio");
1617 gtk_file_filter_set_name(filter, "Fio job file");
1618 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
1620 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1621 gtk_widget_destroy(dialog);
1625 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
1627 gtk_widget_destroy(dialog);
1629 if (get_connection_details(&host, &port, &type, &server_start))
1632 filenames = fn_glist;
1633 while (filenames != NULL) {
1634 struct fio_client *client;
1636 ui->job_files = realloc(ui->job_files, (ui->nr_job_files + 1) * sizeof(char *));
1637 ui->job_files[ui->nr_job_files] = strdup(filenames->data);
1640 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
1644 error = g_error_new(g_quark_from_string("fio"), 1,
1645 "Failed to add client %s", host);
1646 report_error(error);
1647 g_error_free(error);
1649 gfio_client_added(ui, client);
1651 g_free(filenames->data);
1652 filenames = g_slist_next(filenames);
1657 gfio_start_server(ui);
1659 g_slist_free(fn_glist);
1662 static void file_save(GtkWidget *w, gpointer data)
1664 struct gui *ui = data;
1667 dialog = gtk_file_chooser_dialog_new("Save File",
1668 GTK_WINDOW(ui->window),
1669 GTK_FILE_CHOOSER_ACTION_SAVE,
1670 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1671 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1674 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1675 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
1677 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1680 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1681 // save_job_file(filename);
1684 gtk_widget_destroy(dialog);
1687 static void view_log_destroy(GtkWidget *w, gpointer data)
1689 struct gui *ui = (struct gui *) data;
1691 gtk_widget_ref(ui->log_tree);
1692 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
1693 gtk_widget_destroy(w);
1694 ui->log_view = NULL;
1697 static void view_log(GtkWidget *w, gpointer data)
1699 GtkWidget *win, *scroll, *vbox, *box;
1700 struct gui *ui = (struct gui *) data;
1705 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1706 gtk_window_set_title(GTK_WINDOW(win), "Log");
1707 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
1709 scroll = gtk_scrolled_window_new(NULL, NULL);
1711 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
1713 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1715 box = gtk_hbox_new(TRUE, 0);
1716 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
1717 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
1718 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
1720 vbox = gtk_vbox_new(TRUE, 5);
1721 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
1723 gtk_container_add(GTK_CONTAINER(win), vbox);
1724 gtk_widget_show_all(win);
1727 static void preferences(GtkWidget *w, gpointer data)
1729 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
1732 dialog = gtk_dialog_new_with_buttons("Preferences",
1733 GTK_WINDOW(ui.window),
1734 GTK_DIALOG_DESTROY_WITH_PARENT,
1735 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1736 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1739 frame = gtk_frame_new("Debug logging");
1740 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1742 vbox = gtk_vbox_new(FALSE, 6);
1743 gtk_container_add(GTK_CONTAINER(frame), vbox);
1745 box = gtk_hbox_new(FALSE, 6);
1746 gtk_container_add(GTK_CONTAINER(vbox), box);
1748 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
1750 for (i = 0; i < FD_DEBUG_MAX; i++) {
1752 box = gtk_hbox_new(FALSE, 6);
1753 gtk_container_add(GTK_CONTAINER(vbox), box);
1757 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
1758 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
1759 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
1762 frame = gtk_frame_new("Graph font");
1763 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1764 vbox = gtk_vbox_new(FALSE, 6);
1765 gtk_container_add(GTK_CONTAINER(frame), vbox);
1767 font = gtk_font_button_new();
1768 gtk_box_pack_start(GTK_BOX(vbox), font, FALSE, FALSE, 5);
1770 gtk_widget_show_all(dialog);
1772 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1773 gtk_widget_destroy(dialog);
1777 for (i = 0; i < FD_DEBUG_MAX; i++) {
1780 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
1782 fio_debug |= (1UL << i);
1785 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
1786 gtk_widget_destroy(dialog);
1789 static void about_dialog(GtkWidget *w, gpointer data)
1791 const char *authors[] = {
1792 "Jens Axboe <axboe@kernel.dk>",
1793 "Stephen Carmeron <stephenmcameron@gmail.com>",
1796 const char *license[] = {
1797 "Fio is free software; you can redistribute it and/or modify "
1798 "it under the terms of the GNU General Public License as published by "
1799 "the Free Software Foundation; either version 2 of the License, or "
1800 "(at your option) any later version.\n",
1801 "Fio is distributed in the hope that it will be useful, "
1802 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
1803 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
1804 "GNU General Public License for more details.\n",
1805 "You should have received a copy of the GNU General Public License "
1806 "along with Fio; if not, write to the Free Software Foundation, Inc., "
1807 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
1809 char *license_trans;
1811 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
1812 license[2], "\n", NULL);
1814 gtk_show_about_dialog(NULL,
1815 "program-name", "gfio",
1816 "comments", "Gtk2 UI for fio",
1817 "license", license_trans,
1818 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
1820 "version", fio_version_string,
1821 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
1822 "logo-icon-name", "fio",
1824 "wrap-license", TRUE,
1827 g_free (license_trans);
1830 static GtkActionEntry menu_items[] = {
1831 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
1832 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
1833 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
1834 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
1835 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
1836 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
1837 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
1838 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
1839 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
1841 static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
1843 static const gchar *ui_string = " \
1845 <menubar name=\"MainMenu\"> \
1846 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
1847 <menuitem name=\"Open\" action=\"OpenFile\" /> \
1848 <menuitem name=\"Save\" action=\"SaveFile\" /> \
1849 <separator name=\"Separator\"/> \
1850 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
1851 <separator name=\"Separator2\"/> \
1852 <menuitem name=\"Quit\" action=\"Quit\" /> \
1854 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
1855 <menuitem name=\"Log\" action=\"ViewLog\" /> \
1857 <menu name=\"Help\" action=\"HelpMenuAction\"> \
1858 <menuitem name=\"About\" action=\"About\" /> \
1864 static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
1867 GtkActionGroup *action_group = gtk_action_group_new("Menu");
1870 action_group = gtk_action_group_new("Menu");
1871 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
1873 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1874 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
1876 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
1877 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
1880 void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
1881 GtkWidget *vbox, GtkUIManager *ui_manager)
1883 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
1886 static void init_ui(int *argc, char **argv[], struct gui *ui)
1888 GtkSettings *settings;
1889 GtkUIManager *uimanager;
1890 GtkWidget *menu, *probe, *probe_frame, *probe_box;
1893 memset(ui, 0, sizeof(*ui));
1895 /* Magical g*thread incantation, you just need this thread stuff.
1896 * Without it, the update that happens in gfio_update_thread_status
1897 * doesn't really happen in a timely fashion, you need expose events
1899 if (!g_thread_supported())
1900 g_thread_init(NULL);
1903 gtk_init(argc, argv);
1904 settings = gtk_settings_get_default();
1905 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
1908 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1909 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
1910 gtk_window_set_default_size(GTK_WINDOW(ui->window), 700, 700);
1912 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
1913 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
1915 ui->vbox = gtk_vbox_new(FALSE, 0);
1916 gtk_container_add(GTK_CONTAINER (ui->window), ui->vbox);
1918 uimanager = gtk_ui_manager_new();
1919 menu = get_menubar_menu(ui->window, uimanager, ui);
1920 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
1923 * Set up alignments for widgets at the top of ui,
1924 * align top left, expand horizontally but not vertically
1926 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
1927 ui->topvbox = gtk_vbox_new(FALSE, 3);
1928 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
1929 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->topalign, FALSE, FALSE, 0);
1931 probe = gtk_frame_new("Job");
1932 gtk_box_pack_start(GTK_BOX(ui->topvbox), probe, TRUE, FALSE, 3);
1933 probe_frame = gtk_vbox_new(FALSE, 3);
1934 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
1936 probe_box = gtk_hbox_new(FALSE, 3);
1937 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1938 ui->probe.hostname = new_info_label_in_frame(probe_box, "Host");
1939 ui->probe.os = new_info_label_in_frame(probe_box, "OS");
1940 ui->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
1941 ui->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
1943 probe_box = gtk_hbox_new(FALSE, 3);
1944 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1946 ui->eta.name = new_info_entry_in_frame(probe_box, "Name");
1947 ui->eta.iotype = new_info_entry_in_frame(probe_box, "IO");
1948 ui->eta.ioengine = new_info_entry_in_frame(probe_box, "IO Engine");
1949 ui->eta.iodepth = new_info_entry_in_frame(probe_box, "IO Depth");
1950 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
1951 ui->eta.files = new_info_entry_in_frame(probe_box, "Open files");
1953 probe_box = gtk_hbox_new(FALSE, 3);
1954 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1955 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1956 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1957 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1958 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
1961 * Only add this if we have a commit rate
1964 probe_box = gtk_hbox_new(FALSE, 3);
1965 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1967 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1968 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1970 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1971 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1975 * Set up a drawing area and IOPS and bandwidth graphs
1977 gdk_color_parse("white", &white);
1978 ui->drawing_area = gtk_drawing_area_new();
1979 ui->drawing_area_xdim = DRAWING_AREA_XDIM;
1980 ui->drawing_area_ydim = DRAWING_AREA_YDIM;
1981 gtk_widget_set_size_request(GTK_WIDGET(ui->drawing_area),
1982 ui->drawing_area_xdim, ui->drawing_area_ydim);
1983 gtk_widget_modify_bg(ui->drawing_area, GTK_STATE_NORMAL, &white);
1984 g_signal_connect(G_OBJECT(ui->drawing_area), "expose_event",
1985 G_CALLBACK (on_expose_drawing_area), ui);
1986 g_signal_connect(G_OBJECT(ui->drawing_area), "configure_event",
1987 G_CALLBACK (on_config_drawing_area), ui);
1988 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1989 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1990 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1991 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1993 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->scrolled_window,
1996 setup_iops_graph(ui);
1997 setup_bandwidth_graph(ui);
2000 * Set up alignments for widgets at the bottom of ui,
2001 * align bottom left, expand horizontally but not vertically
2003 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
2004 ui->buttonbox = gtk_hbox_new(FALSE, 0);
2005 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
2006 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->bottomalign,
2009 add_buttons(ui, buttonspeclist, ARRAYSIZE(buttonspeclist));
2012 * Set up thread status progress bar
2014 ui->thread_status_pb = gtk_progress_bar_new();
2015 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
2016 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
2017 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
2019 gfio_ui_setup_log(ui);
2021 gtk_widget_show_all(ui->window);
2024 int main(int argc, char *argv[], char *envp[])
2026 if (initialize_fio(envp))
2028 if (fio_init_options())
2031 init_ui(&argc, &argv, &ui);
2033 gdk_threads_enter();
2035 gdk_threads_leave();