blob: ead2c3d3a3f3f031dd4aaf9a5a1ce1d8fccdb83d [file] [log] [blame]
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001/*
2 * gfio - gui front end for fio - the flexible io tester
3 *
4 * Copyright (C) 2012 Stephen M. Cameron <stephenmcameron@gmail.com>
Jens Axboec0187f32012-03-06 15:39:15 +01005 * Copyright (C) 2012 Jens Axboe <axboe@kernel.dk>
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01006 *
7 * The license below covers all files distributed with fio unless otherwise
8 * noted in the file itself.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
Stephen M. Cameron8232e282012-02-24 08:17:31 +010024#include <locale.h>
Stephen M. Cameron60f6b332012-02-24 08:17:32 +010025#include <malloc.h>
Jens Axboe6b79c802012-03-08 10:51:36 +010026#include <string.h>
Stephen M. Cameron8232e282012-02-24 08:17:31 +010027
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +010028#include <glib.h>
Jens Axboe2fd3bb02012-03-07 08:07:39 +010029#include <cairo.h>
Stephen M. Cameronff1f3282012-02-24 08:17:30 +010030#include <gtk/gtk.h>
31
Stephen M. Cameron8232e282012-02-24 08:17:31 +010032#include "fio.h"
Jens Axboe2fd3bb02012-03-07 08:07:39 +010033#include "graph.h"
Stephen M. Cameron8232e282012-02-24 08:17:31 +010034
Jens Axboe63a130b2012-03-06 20:08:59 +010035static int gfio_server_running;
Jens Axboef3e84402012-03-07 13:14:32 +010036static const char *gfio_graph_font;
Jens Axboe63a130b2012-03-06 20:08:59 +010037
Jens Axboe3e47bd22012-02-29 13:45:02 +010038static void gfio_update_thread_status(char *status_message, double perc);
Jens Axboe6b79c802012-03-08 10:51:36 +010039static void view_log(GtkWidget *w, gpointer data);
Jens Axboe3e47bd22012-02-29 13:45:02 +010040
Stephen M. Cameronf3074002012-02-24 08:17:30 +010041#define ARRAYSIZE(x) (sizeof((x)) / (sizeof((x)[0])))
42
43typedef void (*clickfunction)(GtkWidget *widget, gpointer data);
44
Jens Axboe3e47bd22012-02-29 13:45:02 +010045static void connect_clicked(GtkWidget *widget, gpointer data);
Stephen M. Cameronf3074002012-02-24 08:17:30 +010046static void start_job_clicked(GtkWidget *widget, gpointer data);
Jens Axboeb9d2f302012-03-08 20:36:28 +010047static void send_clicked(GtkWidget *widget, gpointer data);
Stephen M. Cameronf3074002012-02-24 08:17:30 +010048
49static struct button_spec {
50 const char *buttontext;
51 clickfunction f;
52 const char *tooltiptext;
Jens Axboe3e47bd22012-02-29 13:45:02 +010053 const int start_insensitive;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010054} buttonspeclist[] = {
Jens Axboe3e47bd22012-02-29 13:45:02 +010055#define CONNECT_BUTTON 0
Jens Axboeb9d2f302012-03-08 20:36:28 +010056#define SEND_BUTTON 1
57#define START_JOB_BUTTON 2
Jens Axboe3e47bd22012-02-29 13:45:02 +010058 { "Connect", connect_clicked, "Connect to host", 0 },
Jens Axboeb9d2f302012-03-08 20:36:28 +010059 { "Send", send_clicked, "Send job description to host", 1 },
60 { "Start Job", start_job_clicked,
Jens Axboe3e47bd22012-02-29 13:45:02 +010061 "Send current fio job to fio server to be executed", 1 },
Stephen M. Cameronf3074002012-02-24 08:17:30 +010062};
63
Jens Axboe843ad232012-02-29 11:44:53 +010064struct probe_widget {
65 GtkWidget *hostname;
66 GtkWidget *os;
67 GtkWidget *arch;
68 GtkWidget *fio_ver;
69};
70
Jens Axboe3e47bd22012-02-29 13:45:02 +010071struct eta_widget {
Jens Axboe807f9972012-03-02 10:25:24 +010072 GtkWidget *name;
73 GtkWidget *iotype;
74 GtkWidget *ioengine;
75 GtkWidget *iodepth;
Jens Axboe3e47bd22012-02-29 13:45:02 +010076 GtkWidget *jobs;
77 GtkWidget *files;
78 GtkWidget *read_bw;
79 GtkWidget *read_iops;
80 GtkWidget *cr_bw;
81 GtkWidget *cr_iops;
82 GtkWidget *write_bw;
83 GtkWidget *write_iops;
84 GtkWidget *cw_bw;
85 GtkWidget *cw_iops;
86};
87
Stephen M. Cameronff1f3282012-02-24 08:17:30 +010088struct gui {
89 GtkWidget *window;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +010090 GtkWidget *vbox;
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +010091 GtkWidget *topvbox;
92 GtkWidget *topalign;
93 GtkWidget *bottomalign;
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +010094 GtkWidget *thread_status_pb;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010095 GtkWidget *buttonbox;
96 GtkWidget *button[ARRAYSIZE(buttonspeclist)];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +010097 GtkWidget *scrolled_window;
Jens Axboe2fd3bb02012-03-07 08:07:39 +010098#define DRAWING_AREA_XDIM 1000
99#define DRAWING_AREA_YDIM 400
100 GtkWidget *drawing_area;
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +0100101 int drawing_area_xdim;
102 int drawing_area_ydim;
Jens Axboe0420ba62012-02-29 11:16:52 +0100103 GtkWidget *error_info_bar;
104 GtkWidget *error_label;
Jens Axboef9d40b42012-03-06 09:52:49 +0100105 GtkWidget *results_notebook;
106 GtkWidget *results_window;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100107 GtkListStore *log_model;
108 GtkWidget *log_tree;
Jens Axboe4cbe7212012-03-06 13:36:17 +0100109 GtkWidget *log_view;
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100110 GtkTextBuffer *text;
Jens Axboe843ad232012-02-29 11:44:53 +0100111 struct probe_widget probe;
Jens Axboe3e47bd22012-02-29 13:45:02 +0100112 struct eta_widget eta;
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100113 int connected;
Stephen M. Cameron25927252012-02-24 08:17:31 +0100114 pthread_t t;
Jens Axboe63a130b2012-03-06 20:08:59 +0100115 pthread_t server_t;
Jens Axboe0420ba62012-02-29 11:16:52 +0100116
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100117 struct graph *iops_graph;
118 struct graph *bandwidth_graph;
Jens Axboeb9d2f302012-03-08 20:36:28 +0100119 struct gfio_client *client;
Jens Axboe0420ba62012-02-29 11:16:52 +0100120 int nr_job_files;
121 char **job_files;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100122} ui;
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100123
Jens Axboee0681f32012-03-06 12:14:42 +0100124struct gfio_client {
125 struct gui *ui;
Jens Axboeb9d2f302012-03-08 20:36:28 +0100126 struct fio_client *client;
Jens Axboee0681f32012-03-06 12:14:42 +0100127 GtkWidget *results_widget;
128 GtkWidget *disk_util_frame;
Jens Axboe6b79c802012-03-08 10:51:36 +0100129 GtkWidget *err_entry;
Jens Axboedcaeb602012-03-08 19:45:37 +0100130 unsigned int job_added;
131 struct thread_options o;
Jens Axboee0681f32012-03-06 12:14:42 +0100132};
133
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100134static void setup_iops_graph(struct gui *ui)
135{
136 if (ui->iops_graph)
137 graph_free(ui->iops_graph);
Jens Axboe87d5f272012-03-07 12:31:40 +0100138 ui->iops_graph = graph_new(DRAWING_AREA_XDIM / 2.0,
Jens Axboef3e84402012-03-07 13:14:32 +0100139 DRAWING_AREA_YDIM, gfio_graph_font);
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100140 graph_title(ui->iops_graph, "IOPS");
Stephen M. Cameronb04ad8d2012-03-07 14:49:37 +0100141 graph_x_title(ui->iops_graph, "Time (secs)");
Stephen M. Cameron019dd472012-03-08 17:00:10 +0100142 graph_y_title(ui->iops_graph, "IOs / sec");
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100143 graph_add_label(ui->iops_graph, "Read IOPS");
144 graph_add_label(ui->iops_graph, "Write IOPS");
Jens Axboe9f4883a2012-03-07 16:22:50 +0100145 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);
Stephen M. Cameronfe8afdd2012-03-07 19:34:19 +0100147 line_graph_set_data_count_limit(ui->iops_graph, 100);
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100148}
149
150static void setup_bandwidth_graph(struct gui *ui)
151{
152 if (ui->bandwidth_graph)
153 graph_free(ui->bandwidth_graph);
Jens Axboe87d5f272012-03-07 12:31:40 +0100154 ui->bandwidth_graph = graph_new(DRAWING_AREA_XDIM / 2.0,
Jens Axboef3e84402012-03-07 13:14:32 +0100155 DRAWING_AREA_YDIM, gfio_graph_font);
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100156 graph_title(ui->bandwidth_graph, "Bandwidth");
Stephen M. Cameronb04ad8d2012-03-07 14:49:37 +0100157 graph_x_title(ui->bandwidth_graph, "Time (secs)");
Stephen M. Cameron019dd472012-03-08 17:00:10 +0100158 graph_y_title(ui->bandwidth_graph, "Kbytes / sec");
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100159 graph_add_label(ui->bandwidth_graph, "Read Bandwidth");
160 graph_add_label(ui->bandwidth_graph, "Write Bandwidth");
Jens Axboe9f4883a2012-03-07 16:22:50 +0100161 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);
Stephen M. Cameronfe8afdd2012-03-07 19:34:19 +0100163 line_graph_set_data_count_limit(ui->bandwidth_graph, 100);
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100164}
165
Jens Axboe8663ea62012-03-02 14:04:30 +0100166static void clear_ui_info(struct gui *ui)
167{
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), "");
Jens Axboeca850992012-03-05 20:04:43 +0100172 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), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100182}
183
Jens Axboe3650a3c2012-03-05 14:09:03 +0100184static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
185{
186 GtkWidget *entry, *frame;
187
188 frame = gtk_frame_new(label);
189 entry = gtk_entry_new();
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100190 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100191 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
192 gtk_container_add(GTK_CONTAINER(frame), entry);
193
194 return entry;
195}
196
197static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
198{
199 GtkWidget *label_widget;
200 GtkWidget *frame;
201
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);
206
207 return label_widget;
208}
209
210static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
211{
212 GtkWidget *button, *box;
213
214 box = gtk_hbox_new(FALSE, 3);
215 gtk_container_add(GTK_CONTAINER(hbox), box);
216
217 button = gtk_spin_button_new_with_range(min, max, 1.0);
218 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
219
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);
222
223 return button;
224}
225
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100226static void gfio_set_connected(struct gui *ui, int connected)
227{
228 if (connected) {
Jens Axboeb9d2f302012-03-08 20:36:28 +0100229 gtk_widget_set_sensitive(ui->button[SEND_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100230 ui->connected = 1;
231 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Disconnect");
Jens Axboe88f6e7a2012-03-06 12:55:29 +0100232 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100233 } else {
234 ui->connected = 0;
235 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Connect");
Jens Axboeb9d2f302012-03-08 20:36:28 +0100236 gtk_widget_set_sensitive(ui->button[SEND_BUTTON], 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100237 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
Jens Axboe63a130b2012-03-06 20:08:59 +0100238 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100239 }
240}
241
Jens Axboe3650a3c2012-03-05 14:09:03 +0100242static void label_set_int_value(GtkWidget *entry, unsigned int val)
243{
244 char tmp[80];
245
246 sprintf(tmp, "%u", val);
247 gtk_label_set_text(GTK_LABEL(entry), tmp);
248}
249
250static void entry_set_int_value(GtkWidget *entry, unsigned int val)
251{
252 char tmp[80];
253
254 sprintf(tmp, "%u", val);
255 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
256}
257
Jens Axboea2697902012-03-05 16:43:49 +0100258#define ALIGN_LEFT 1
259#define ALIGN_RIGHT 2
260#define INVISIBLE 4
261#define UNSORTABLE 8
262
263GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
264{
265 GtkCellRenderer *renderer;
266 GtkTreeViewColumn *col;
267 double xalign = 0.0; /* left as default */
268 PangoAlignment align;
269 gboolean visible;
270
271 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
272 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
273 PANGO_ALIGN_CENTER;
274 visible = !(flags & INVISIBLE);
275
276 renderer = gtk_cell_renderer_text_new();
277 col = gtk_tree_view_column_new();
278
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);
286 switch (align) {
287 case PANGO_ALIGN_LEFT:
288 xalign = 0.0;
289 break;
290 case PANGO_ALIGN_CENTER:
291 xalign = 0.5;
292 break;
293 case PANGO_ALIGN_RIGHT:
294 xalign = 1.0;
295 break;
296 }
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);
300 return col;
301}
302
Jens Axboe9b260bd2012-03-06 11:02:52 +0100303static void gfio_ui_setup_log(struct gui *ui)
304{
305 GtkTreeSelection *selection;
306 GtkListStore *model;
307 GtkWidget *tree_view;
308
309 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
310
311 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
312 gtk_widget_set_can_focus(tree_view, FALSE);
313
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);
Jens Axboe661f7412012-03-06 13:55:45 +0100316 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
317 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100318
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);
Jens Axboef095d562012-03-06 13:49:12 +0100322 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100323
324 ui->log_model = model;
325 ui->log_tree = tree_view;
326}
327
Jens Axboea2697902012-03-05 16:43:49 +0100328static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
329 fio_fp64_t *plist,
330 unsigned int len,
331 const char *base,
332 unsigned int scale)
333{
334 GType types[FIO_IO_U_LIST_MAX_LEN];
335 GtkWidget *tree_view;
336 GtkTreeSelection *selection;
337 GtkListStore *model;
338 GtkTreeIter iter;
339 int i;
340
341 for (i = 0; i < len; i++)
342 types[i] = G_TYPE_INT;
343
344 model = gtk_list_store_newv(len, types);
345
346 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
347 gtk_widget_set_can_focus(tree_view, FALSE);
348
Jens Axboe661f7412012-03-06 13:55:45 +0100349 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
350 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
351
Jens Axboea2697902012-03-05 16:43:49 +0100352 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
353 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
354
355 for (i = 0; i < len; i++) {
356 char fbuf[8];
357
358 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
359 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
360 }
361
362 gtk_list_store_append(model, &iter);
363
Jens Axboee0681f32012-03-06 12:14:42 +0100364 for (i = 0; i < len; i++) {
365 if (scale)
366 ovals[i] = (ovals[i] + 999) / 1000;
Jens Axboea2697902012-03-05 16:43:49 +0100367 gtk_list_store_set(model, &iter, i, ovals[i], -1);
Jens Axboee0681f32012-03-06 12:14:42 +0100368 }
Jens Axboea2697902012-03-05 16:43:49 +0100369
370 return tree_view;
371}
372
373static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
374 int ddir)
375{
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;
380 const char *base;
381 GtkWidget *tree_view, *frame, *hbox;
382 char tmp[64];
383
384 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
385 if (!len)
386 goto out;
387
388 /*
389 * We default to usecs, but if the value range is such that we
390 * should scale down to msecs, do that.
391 */
392 if (minv > 2000 && maxv > 99999) {
393 scale_down = 1;
394 base = "msec";
395 } else {
396 scale_down = 0;
397 base = "usec";
398 }
399
400 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
401
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);
405
406 hbox = gtk_hbox_new(FALSE, 3);
407 gtk_container_add(GTK_CONTAINER(frame), hbox);
408
409 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
410out:
411 if (ovals)
412 free(ovals);
413}
414
Jens Axboe3650a3c2012-03-05 14:09:03 +0100415static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
416 unsigned long max, double mean, double dev)
417{
418 const char *base = "(usec)";
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100419 GtkWidget *hbox, *label, *frame;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100420 char *minp, *maxp;
421 char tmp[64];
422
423 if (!usec_to_msec(&min, &max, &mean, &dev))
424 base = "(msec)";
425
426 minp = num2str(min, 6, 1, 0);
427 maxp = num2str(max, 6, 1, 0);
428
Jens Axboe3650a3c2012-03-05 14:09:03 +0100429 sprintf(tmp, "%s %s", name, base);
430 frame = gtk_frame_new(tmp);
431 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
432
Jens Axboe3650a3c2012-03-05 14:09:03 +0100433 hbox = gtk_hbox_new(FALSE, 3);
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100434 gtk_container_add(GTK_CONTAINER(frame), hbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100435
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);
446
447 free(minp);
448 free(maxp);
449
450}
451
Jens Axboeca850992012-03-05 20:04:43 +0100452#define GFIO_CLAT 1
453#define GFIO_SLAT 2
454#define GFIO_LAT 4
455
Jens Axboe3650a3c2012-03-05 14:09:03 +0100456static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
457 struct thread_stat *ts, int ddir)
458{
459 const char *ddir_label[2] = { "Read", "Write" };
Jens Axboe0b761302012-03-05 20:44:11 +0100460 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
Jens Axboee0681f32012-03-06 12:14:42 +0100461 unsigned long min[3], max[3], runt;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100462 unsigned long long bw, iops;
Jens Axboeca850992012-03-05 20:04:43 +0100463 unsigned int flags = 0;
Jens Axboee0681f32012-03-06 12:14:42 +0100464 double mean[3], dev[3];
Jens Axboe3650a3c2012-03-05 14:09:03 +0100465 char *io_p, *bw_p, *iops_p;
466 int i2p;
467
468 if (!ts->runtime[ddir])
469 return;
470
471 i2p = is_power_of_2(rs->kb_base);
472 runt = ts->runtime[ddir];
473
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);
477
478 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
479 iops_p = num2str(iops, 6, 1, 0);
480
481 box = gtk_hbox_new(FALSE, 3);
482 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
483
484 frame = gtk_frame_new(ddir_label[ddir]);
485 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
486
Jens Axboe0b761302012-03-05 20:44:11 +0100487 main_vbox = gtk_vbox_new(FALSE, 3);
488 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100489
490 box = gtk_hbox_new(FALSE, 3);
Jens Axboe0b761302012-03-05 20:44:11 +0100491 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100492
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]);
501
Jens Axboee0681f32012-03-06 12:14:42 +0100502 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
Jens Axboeca850992012-03-05 20:04:43 +0100503 double p_of_agg = 100.0;
504 const char *bw_str = "KB";
505 char tmp[32];
506
507 if (rs->agg[ddir]) {
Jens Axboee0681f32012-03-06 12:14:42 +0100508 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
Jens Axboeca850992012-03-05 20:04:43 +0100509 if (p_of_agg > 100.0)
510 p_of_agg = 100.0;
511 }
512
Jens Axboee0681f32012-03-06 12:14:42 +0100513 if (mean[0] > 999999.9) {
514 min[0] /= 1000.0;
515 max[0] /= 1000.0;
516 mean[0] /= 1000.0;
517 dev[0] /= 1000.0;
Jens Axboeca850992012-03-05 20:04:43 +0100518 bw_str = "MB";
519 }
520
Jens Axboe0b761302012-03-05 20:44:11 +0100521 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);
Jens Axboeca850992012-03-05 20:04:43 +0100524
Jens Axboe0b761302012-03-05 20:44:11 +0100525 box = gtk_hbox_new(FALSE, 3);
526 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboeca850992012-03-05 20:04:43 +0100527
Jens Axboe0b761302012-03-05 20:44:11 +0100528 label = new_info_label_in_frame(box, "Minimum");
Jens Axboee0681f32012-03-06 12:14:42 +0100529 label_set_int_value(label, min[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100530 label = new_info_label_in_frame(box, "Maximum");
Jens Axboee0681f32012-03-06 12:14:42 +0100531 label_set_int_value(label, max[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100532 label = new_info_label_in_frame(box, "Percentage of jobs");
Jens Axboeca850992012-03-05 20:04:43 +0100533 sprintf(tmp, "%3.2f%%", p_of_agg);
534 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100535 label = new_info_label_in_frame(box, "Average");
Jens Axboee0681f32012-03-06 12:14:42 +0100536 sprintf(tmp, "%5.02f", mean[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100537 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100538 label = new_info_label_in_frame(box, "Standard deviation");
Jens Axboee0681f32012-03-06 12:14:42 +0100539 sprintf(tmp, "%5.02f", dev[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100540 gtk_label_set_text(GTK_LABEL(label), tmp);
541 }
542
Jens Axboee0681f32012-03-06 12:14:42 +0100543 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
Jens Axboe2b089892012-03-06 08:09:17 +0100544 flags |= GFIO_SLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100545 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
Jens Axboe2b089892012-03-06 08:09:17 +0100546 flags |= GFIO_CLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100547 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
Jens Axboe2b089892012-03-06 08:09:17 +0100548 flags |= GFIO_LAT;
549
550 if (flags) {
551 frame = gtk_frame_new("Latency");
552 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
553
554 vbox = gtk_vbox_new(FALSE, 3);
555 gtk_container_add(GTK_CONTAINER(frame), vbox);
556
557 if (flags & GFIO_SLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100558 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
Jens Axboe2b089892012-03-06 08:09:17 +0100559 if (flags & GFIO_CLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100560 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
Jens Axboe2b089892012-03-06 08:09:17 +0100561 if (flags & GFIO_LAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100562 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
Jens Axboe2b089892012-03-06 08:09:17 +0100563 }
564
565 if (ts->clat_percentiles)
566 gfio_show_clat_percentiles(main_vbox, ts, ddir);
567
568
Jens Axboe3650a3c2012-03-05 14:09:03 +0100569 free(io_p);
570 free(bw_p);
571 free(iops_p);
572}
573
Jens Axboee5bd1342012-03-05 21:38:12 +0100574static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
575 const char **labels)
576{
577 GtkWidget *tree_view;
578 GtkTreeSelection *selection;
579 GtkListStore *model;
580 GtkTreeIter iter;
581 GType *types;
582 int i, skipped;
583
584 /*
585 * Check if all are empty, in which case don't bother
586 */
587 for (i = 0, skipped = 0; i < num; i++)
588 if (lat[i] <= 0.0)
589 skipped++;
590
591 if (skipped == num)
592 return NULL;
593
594 types = malloc(num * sizeof(GType));
595
596 for (i = 0; i < num; i++)
597 types[i] = G_TYPE_STRING;
598
599 model = gtk_list_store_newv(num, types);
600 free(types);
601 types = NULL;
602
603 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
604 gtk_widget_set_can_focus(tree_view, FALSE);
605
Jens Axboe661f7412012-03-06 13:55:45 +0100606 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
607 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
608
Jens Axboee5bd1342012-03-05 21:38:12 +0100609 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
610 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
611
612 for (i = 0; i < num; i++)
613 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
614
615 gtk_list_store_append(model, &iter);
616
617 for (i = 0; i < num; i++) {
618 char fbuf[32];
619
620 if (lat[i] <= 0.0)
621 sprintf(fbuf, "0.00");
622 else
623 sprintf(fbuf, "%3.2f%%", lat[i]);
624
625 gtk_list_store_set(model, &iter, i, fbuf, -1);
626 }
627
628 return tree_view;
629}
630
631static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
632{
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",
640 ">= 2000", };
641
642 stat_calc_lat_u(ts, io_u_lat_u);
643 stat_calc_lat_m(ts, io_u_lat_m);
644
645 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
646 if (tree_view) {
647 frame = gtk_frame_new("Latency buckets (usec)");
648 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
649
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);
653 }
654
655 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
656 if (tree_view) {
657 frame = gtk_frame_new("Latency buckets (msec)");
658 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
659
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);
663 }
664}
665
Jens Axboe2e331012012-03-05 22:07:54 +0100666static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
667{
668 GtkWidget *box, *frame, *entry;
669 double usr_cpu, sys_cpu;
670 unsigned long runtime;
671 char tmp[32];
672
673 runtime = ts->total_run_time;
674 if (runtime) {
675 double runt = (double) runtime;
676
677 usr_cpu = (double) ts->usr_time * 100 / runt;
678 sys_cpu = (double) ts->sys_time * 100 / runt;
679 } else {
680 usr_cpu = 0;
681 sys_cpu = 0;
682 }
683
684 frame = gtk_frame_new("OS resources");
685 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
686
687 box = gtk_hbox_new(FALSE, 3);
688 gtk_container_add(GTK_CONTAINER(frame), box);
689
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);
702}
Jens Axboe19998db2012-03-06 09:17:59 +0100703static void gfio_add_sc_depths_tree(GtkListStore *model,
704 struct thread_stat *ts, unsigned int len,
705 int submit)
706{
707 double io_u_dist[FIO_IO_U_MAP_NR];
708 GtkTreeIter iter;
709 /* Bits 0, and 3-8 */
710 const int add_mask = 0x1f9;
711 int i, j;
712
713 if (submit)
714 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
715 else
716 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
717
718 gtk_list_store_append(model, &iter);
719
720 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
721
722 for (i = 1, j = 0; i < len; i++) {
723 char fbuf[32];
724
725 if (!(add_mask & (1UL << (i - 1))))
726 sprintf(fbuf, "0.0%%");
727 else {
728 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
729 j++;
730 }
731
732 gtk_list_store_set(model, &iter, i, fbuf, -1);
733 }
734
735}
736
737static void gfio_add_total_depths_tree(GtkListStore *model,
738 struct thread_stat *ts, unsigned int len)
739{
740 double io_u_dist[FIO_IO_U_MAP_NR];
741 GtkTreeIter iter;
742 /* Bits 1-6, and 8 */
743 const int add_mask = 0x17e;
744 int i, j;
745
746 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
747
748 gtk_list_store_append(model, &iter);
749
750 gtk_list_store_set(model, &iter, 0, "Total", -1);
751
752 for (i = 1, j = 0; i < len; i++) {
753 char fbuf[32];
754
755 if (!(add_mask & (1UL << (i - 1))))
756 sprintf(fbuf, "0.0%%");
757 else {
758 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
759 j++;
760 }
761
762 gtk_list_store_set(model, &iter, i, fbuf, -1);
763 }
764
765}
Jens Axboe2e331012012-03-05 22:07:54 +0100766
767static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
768{
Jens Axboe2e331012012-03-05 22:07:54 +0100769 GtkWidget *frame, *box, *tree_view;
770 GtkTreeSelection *selection;
771 GtkListStore *model;
Jens Axboe2e331012012-03-05 22:07:54 +0100772 GType types[FIO_IO_U_MAP_NR + 1];
773 int i;
Jens Axboe19998db2012-03-06 09:17:59 +0100774#define NR_LABELS 10
775 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
Jens Axboe2e331012012-03-05 22:07:54 +0100776
777 frame = gtk_frame_new("IO depths");
778 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
779
780 box = gtk_hbox_new(FALSE, 3);
781 gtk_container_add(GTK_CONTAINER(frame), box);
782
Jens Axboe19998db2012-03-06 09:17:59 +0100783 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100784 types[i] = G_TYPE_STRING;
785
Jens Axboe19998db2012-03-06 09:17:59 +0100786 model = gtk_list_store_newv(NR_LABELS, types);
Jens Axboe2e331012012-03-05 22:07:54 +0100787
788 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
789 gtk_widget_set_can_focus(tree_view, FALSE);
790
Jens Axboe661f7412012-03-06 13:55:45 +0100791 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
792 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
793
Jens Axboe2e331012012-03-05 22:07:54 +0100794 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
795 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
796
Jens Axboe19998db2012-03-06 09:17:59 +0100797 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100798 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
799
Jens Axboe19998db2012-03-06 09:17:59 +0100800 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);
Jens Axboe2e331012012-03-05 22:07:54 +0100803
804 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
805}
806
Jens Axboef9d40b42012-03-06 09:52:49 +0100807static gboolean results_window_delete(GtkWidget *w, gpointer data)
808{
809 struct gui *ui = (struct gui *) data;
810
811 gtk_widget_destroy(w);
812 ui->results_window = NULL;
813 ui->results_notebook = NULL;
814 return TRUE;
815}
816
817static GtkWidget *get_results_window(struct gui *ui)
818{
819 GtkWidget *win, *notebook;
820
821 if (ui->results_window)
822 return ui->results_notebook;
823
824 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
825 gtk_window_set_title(GTK_WINDOW(win), "Results");
Jens Axboeb01329d2012-03-07 20:31:28 +0100826 gtk_window_set_default_size(GTK_WINDOW(win), 1024, 768);
Jens Axboef9d40b42012-03-06 09:52:49 +0100827 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ui);
828 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ui);
829
830 notebook = gtk_notebook_new();
831 gtk_container_add(GTK_CONTAINER(win), notebook);
832
833 ui->results_window = win;
834 ui->results_notebook = notebook;
835 return ui->results_notebook;
836}
837
Jens Axboe3650a3c2012-03-05 14:09:03 +0100838static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
839 struct group_run_stats *rs)
840{
Jens Axboeb01329d2012-03-07 20:31:28 +0100841 GtkWidget *res_win, *box, *vbox, *entry, *scroll;
Jens Axboee0681f32012-03-06 12:14:42 +0100842 struct gfio_client *gc = client->client_data;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100843
844 gdk_threads_enter();
845
Jens Axboee0681f32012-03-06 12:14:42 +0100846 res_win = get_results_window(gc->ui);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100847
Jens Axboeb01329d2012-03-07 20:31:28 +0100848 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);
851
Jens Axboe3650a3c2012-03-05 14:09:03 +0100852 vbox = gtk_vbox_new(FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100853
Jens Axboeb01329d2012-03-07 20:31:28 +0100854 box = gtk_hbox_new(FALSE, 0);
855 gtk_box_pack_start(GTK_BOX(vbox), box, TRUE, FALSE, 5);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100856
Jens Axboeb01329d2012-03-07 20:31:28 +0100857 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
858
859 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), scroll, gtk_label_new(ts->name));
Jens Axboef9d40b42012-03-06 09:52:49 +0100860
Jens Axboee0681f32012-03-06 12:14:42 +0100861 gc->results_widget = vbox;
862
Jens Axboe3650a3c2012-03-05 14:09:03 +0100863 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);
868 }
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);
Jens Axboe6b79c802012-03-08 10:51:36 +0100873 gc->err_entry = entry = new_info_entry_in_frame(box, "Error");
Jens Axboe3650a3c2012-03-05 14:09:03 +0100874 entry_set_int_value(entry, ts->error);
875 entry = new_info_entry_in_frame(box, "PID");
876 entry_set_int_value(entry, ts->pid);
877
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);
882
Jens Axboee5bd1342012-03-05 21:38:12 +0100883 gfio_show_latency_buckets(vbox, ts);
Jens Axboe2e331012012-03-05 22:07:54 +0100884 gfio_show_cpu_usage(vbox, ts);
885 gfio_show_io_depths(vbox, ts);
Jens Axboee5bd1342012-03-05 21:38:12 +0100886
Jens Axboee0681f32012-03-06 12:14:42 +0100887 gtk_widget_show_all(gc->ui->results_window);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100888 gdk_threads_leave();
889}
890
Jens Axboe084d1c62012-03-03 20:28:07 +0100891static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +0100892{
Jens Axboe9b260bd2012-03-06 11:02:52 +0100893 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +0100894 struct gfio_client *gc = client->client_data;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100895 GtkTreeIter iter;
896 struct tm *tm;
897 time_t sec;
898 char tmp[64], timebuf[80];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100899
Jens Axboe9b260bd2012-03-06 11:02:52 +0100900 sec = p->log_sec;
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);
904
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100905 gdk_threads_enter();
Jens Axboe9b260bd2012-03-06 11:02:52 +0100906
Jens Axboee0681f32012-03-06 12:14:42 +0100907 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);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100912
Jens Axboe6b79c802012-03-08 10:51:36 +0100913 if (p->level == FIO_LOG_ERR)
914 view_log(NULL, (gpointer) gc->ui);
915
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100916 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100917}
918
919static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
920{
Jens Axboee0681f32012-03-06 12:14:42 +0100921 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;
Jens Axboe604cfe32012-03-07 19:51:36 +0100924 double util;
925 char tmp[16];
Jens Axboee0681f32012-03-06 12:14:42 +0100926
Jens Axboe0050e5f2012-03-06 09:23:27 +0100927 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +0100928
Jens Axboe45dcb2e2012-03-07 16:16:50 +0100929 if (!gc->results_widget)
Jens Axboee0681f32012-03-06 12:14:42 +0100930 goto out;
Jens Axboee0681f32012-03-06 12:14:42 +0100931
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);
935 }
936
937 vbox = gtk_vbox_new(FALSE, 3);
938 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
939
940 frame = gtk_frame_new((char *) p->dus.name);
941 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
942
943 box = gtk_vbox_new(FALSE, 3);
944 gtk_container_add(GTK_CONTAINER(frame), box);
945
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]);
958
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]);
971
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);
980
Jens Axboe604cfe32012-03-07 19:51:36 +0100981 util = 0.0;
982 if (p->dus.msec)
983 util = (double) 100 * p->dus.io_ticks / (double) p->dus.msec;
984 if (util > 100.0)
985 util = 100.0;
986
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);
990
Jens Axboee0681f32012-03-06 12:14:42 +0100991 gtk_widget_show_all(gc->results_widget);
992out:
Jens Axboe0050e5f2012-03-06 09:23:27 +0100993 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +0100994}
995
Jens Axboe3650a3c2012-03-05 14:09:03 +0100996extern int sum_stat_clients;
997extern struct thread_stat client_ts;
998extern struct group_run_stats client_gs;
999
1000static int sum_stat_nr;
1001
Jens Axboe89e5fad2012-03-05 09:21:12 +01001002static void gfio_thread_status_op(struct fio_client *client,
1003 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001004{
Jens Axboe3650a3c2012-03-05 14:09:03 +01001005 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
1006
1007 gfio_display_ts(client, &p->ts, &p->rs);
1008
1009 if (sum_stat_clients == 1)
1010 return;
1011
1012 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
1013 sum_group_stats(&client_gs, &p->rs);
1014
1015 client_ts.members++;
1016 client_ts.groupid = p->ts.groupid;
1017
1018 if (++sum_stat_nr == sum_stat_clients) {
1019 strcpy(client_ts.name, "All clients");
1020 gfio_display_ts(client, &client_ts, &client_gs);
1021 }
Stephen M. Camerona1820202012-02-24 08:17:31 +01001022}
1023
Jens Axboe89e5fad2012-03-05 09:21:12 +01001024static void gfio_group_stats_op(struct fio_client *client,
1025 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001026{
Jens Axboe98ceabd2012-03-09 08:53:28 +01001027 /* We're ignoring group stats for now */
Stephen M. Camerona1820202012-02-24 08:17:31 +01001028}
1029
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001030static gint on_config_drawing_area(GtkWidget *w, GdkEventConfigure *event)
1031{
1032 ui.drawing_area_xdim = w->allocation.width;
1033 ui.drawing_area_ydim = w->allocation.height;
1034 return TRUE;
1035}
1036
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001037static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
1038{
1039 struct gui *ui = (struct gui *) p;
1040 cairo_t *cr;
1041
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001042 graph_set_size(ui->iops_graph, ui->drawing_area_xdim / 2.0,
1043 ui->drawing_area_ydim);
1044 graph_set_size(ui->bandwidth_graph, ui->drawing_area_xdim / 2.0,
1045 ui->drawing_area_ydim);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001046 cr = gdk_cairo_create(w->window);
1047
1048 cairo_set_source_rgb(cr, 0, 0, 0);
1049
1050 cairo_save(cr);
1051 cairo_translate(cr, 0, 0);
1052 line_graph_draw(ui->bandwidth_graph, cr);
1053 cairo_stroke(cr);
1054 cairo_restore(cr);
1055
1056 cairo_save(cr);
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001057 cairo_translate(cr, ui->drawing_area_xdim / 2.0, 0);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001058 line_graph_draw(ui->iops_graph, cr);
1059 cairo_stroke(cr);
1060 cairo_restore(cr);
1061 cairo_destroy(cr);
1062
1063 return FALSE;
1064}
1065
Jens Axboe3e47bd22012-02-29 13:45:02 +01001066static void gfio_update_eta(struct jobs_eta *je)
1067{
1068 static int eta_good;
1069 char eta_str[128];
1070 char output[256];
1071 char tmp[32];
1072 double perc = 0.0;
1073 int i2p = 0;
1074
Jens Axboe0050e5f2012-03-06 09:23:27 +01001075 gdk_threads_enter();
1076
Jens Axboe3e47bd22012-02-29 13:45:02 +01001077 eta_str[0] = '\0';
1078 output[0] = '\0';
1079
1080 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1081 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1082 eta_to_str(eta_str, je->eta_sec);
1083 }
1084
1085 sprintf(tmp, "%u", je->nr_running);
Jens Axboeca850992012-03-05 20:04:43 +01001086 gtk_entry_set_text(GTK_ENTRY(ui.eta.jobs), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001087 sprintf(tmp, "%u", je->files_open);
Jens Axboeca850992012-03-05 20:04:43 +01001088 gtk_entry_set_text(GTK_ENTRY(ui.eta.files), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001089
1090#if 0
1091 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1092 if (je->m_rate || je->t_rate) {
1093 char *tr, *mr;
1094
1095 mr = num2str(je->m_rate, 4, 0, i2p);
1096 tr = num2str(je->t_rate, 4, 0, i2p);
Jens Axboeca850992012-03-05 20:04:43 +01001097 gtk_entry_set_text(GTK_ENTRY(ui.eta);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001098 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1099 free(tr);
1100 free(mr);
1101 } else if (je->m_iops || je->t_iops)
1102 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
Jens Axboeebbd89c2012-03-02 11:21:13 +01001103
Jens Axboeca850992012-03-05 20:04:43 +01001104 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_bw), "---");
1105 gtk_entry_set_text(GTK_ENTRY(ui.eta.cr_iops), "---");
1106 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_bw), "---");
1107 gtk_entry_set_text(GTK_ENTRY(ui.eta.cw_iops), "---");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001108#endif
1109
1110 if (je->eta_sec != INT_MAX && je->nr_running) {
1111 char *iops_str[2];
1112 char *rate_str[2];
1113
1114 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1115 strcpy(output, "-.-% done");
1116 else {
1117 eta_good = 1;
1118 perc *= 100.0;
1119 sprintf(output, "%3.1f%% done", perc);
1120 }
1121
1122 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1123 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1124
1125 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1126 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1127
Jens Axboeca850992012-03-05 20:04:43 +01001128 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_bw), rate_str[0]);
1129 gtk_entry_set_text(GTK_ENTRY(ui.eta.read_iops), iops_str[0]);
1130 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_bw), rate_str[1]);
1131 gtk_entry_set_text(GTK_ENTRY(ui.eta.write_iops), iops_str[1]);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001132
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001133 graph_add_xy_data(ui.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1134 graph_add_xy_data(ui.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1135 graph_add_xy_data(ui.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1136 graph_add_xy_data(ui.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
1137
Jens Axboe3e47bd22012-02-29 13:45:02 +01001138 free(rate_str[0]);
1139 free(rate_str[1]);
1140 free(iops_str[0]);
1141 free(iops_str[1]);
1142 }
1143
1144 if (eta_str[0]) {
1145 char *dst = output + strlen(output);
1146
1147 sprintf(dst, " - %s", eta_str);
1148 }
1149
1150 gfio_update_thread_status(output, perc);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001151 gdk_threads_leave();
Jens Axboe3e47bd22012-02-29 13:45:02 +01001152}
1153
Stephen M. Camerona1820202012-02-24 08:17:31 +01001154static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1155{
Jens Axboe843ad232012-02-29 11:44:53 +01001156 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001157 struct gfio_client *gc = client->client_data;
1158 struct gui *ui = gc->ui;
Jens Axboe843ad232012-02-29 11:44:53 +01001159 const char *os, *arch;
1160 char buf[64];
1161
1162 os = fio_get_os_string(probe->os);
1163 if (!os)
1164 os = "unknown";
1165
1166 arch = fio_get_arch_string(probe->arch);
1167 if (!arch)
1168 os = "unknown";
1169
1170 if (!client->name)
1171 client->name = strdup((char *) probe->hostname);
1172
Jens Axboe0050e5f2012-03-06 09:23:27 +01001173 gdk_threads_enter();
1174
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001175 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), (char *) probe->hostname);
1176 gtk_label_set_text(GTK_LABEL(ui->probe.os), os);
1177 gtk_label_set_text(GTK_LABEL(ui->probe.arch), arch);
Jens Axboe843ad232012-02-29 11:44:53 +01001178 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001179 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), buf);
1180
1181 gfio_set_connected(ui, 1);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001182
1183 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001184}
1185
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001186static void gfio_update_thread_status(char *status_message, double perc)
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001187{
1188 static char message[100];
1189 const char *m = message;
1190
1191 strncpy(message, status_message, sizeof(message) - 1);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001192 gtk_progress_bar_set_text(
1193 GTK_PROGRESS_BAR(ui.thread_status_pb), m);
1194 gtk_progress_bar_set_fraction(
1195 GTK_PROGRESS_BAR(ui.thread_status_pb), perc / 100.0);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001196 gtk_widget_queue_draw(ui.window);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001197}
1198
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001199static void gfio_quit_op(struct fio_client *client)
1200{
Jens Axboee0681f32012-03-06 12:14:42 +01001201 struct gfio_client *gc = client->client_data;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001202
Jens Axboe0050e5f2012-03-06 09:23:27 +01001203 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +01001204 gfio_set_connected(gc->ui, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001205 gdk_threads_leave();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001206}
1207
Jens Axboe807f9972012-03-02 10:25:24 +01001208static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1209{
1210 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +01001211 struct gfio_client *gc = client->client_data;
Jens Axboedcaeb602012-03-08 19:45:37 +01001212 struct thread_options *o = &gc->o;
Jens Axboee0681f32012-03-06 12:14:42 +01001213 struct gui *ui = gc->ui;
Jens Axboe807f9972012-03-02 10:25:24 +01001214 char tmp[8];
Jens Axboe807f9972012-03-02 10:25:24 +01001215
Jens Axboedcaeb602012-03-08 19:45:37 +01001216 convert_thread_options_to_cpu(o, &p->top);
Jens Axboe807f9972012-03-02 10:25:24 +01001217
Jens Axboe0050e5f2012-03-06 09:23:27 +01001218 gdk_threads_enter();
1219
Jens Axboedcaeb602012-03-08 19:45:37 +01001220 gtk_entry_set_text(GTK_ENTRY(ui->eta.name), (gchar *) o->name);
1221 gtk_entry_set_text(GTK_ENTRY(ui->eta.iotype), ddir_str(o->td_ddir));
1222 gtk_entry_set_text(GTK_ENTRY(ui->eta.ioengine), (gchar *) o->ioengine);
Jens Axboe807f9972012-03-02 10:25:24 +01001223
Jens Axboedcaeb602012-03-08 19:45:37 +01001224 sprintf(tmp, "%u", o->iodepth);
Jens Axboeca850992012-03-05 20:04:43 +01001225 gtk_entry_set_text(GTK_ENTRY(ui->eta.iodepth), tmp);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001226
Jens Axboedcaeb602012-03-08 19:45:37 +01001227 gc->job_added++;
1228
Jens Axboe0050e5f2012-03-06 09:23:27 +01001229 gdk_threads_leave();
Jens Axboe807f9972012-03-02 10:25:24 +01001230}
1231
Jens Axboeed727a42012-03-02 12:14:40 +01001232static void gfio_client_timed_out(struct fio_client *client)
1233{
Jens Axboee0681f32012-03-06 12:14:42 +01001234 struct gfio_client *gc = client->client_data;
Jens Axboeed727a42012-03-02 12:14:40 +01001235 GtkWidget *dialog, *label, *content;
1236 char buf[256];
1237
1238 gdk_threads_enter();
1239
Jens Axboee0681f32012-03-06 12:14:42 +01001240 gfio_set_connected(gc->ui, 0);
1241 clear_ui_info(gc->ui);
Jens Axboeed727a42012-03-02 12:14:40 +01001242
1243 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
1244
1245 dialog = gtk_dialog_new_with_buttons("Timed out!",
Jens Axboee0681f32012-03-06 12:14:42 +01001246 GTK_WINDOW(gc->ui->window),
Jens Axboeed727a42012-03-02 12:14:40 +01001247 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1248 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1249
Jens Axboef1299092012-03-07 20:00:02 +01001250 /* gtk_dialog_get_content_area() is 2.14 and newer */
1251 content = GTK_DIALOG(dialog)->vbox;
1252
Jens Axboeed727a42012-03-02 12:14:40 +01001253 label = gtk_label_new((const gchar *) buf);
1254 gtk_container_add(GTK_CONTAINER(content), label);
1255 gtk_widget_show_all(dialog);
1256 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1257
1258 gtk_dialog_run(GTK_DIALOG(dialog));
1259 gtk_widget_destroy(dialog);
1260
1261 gdk_threads_leave();
1262}
1263
Jens Axboe6b79c802012-03-08 10:51:36 +01001264static void gfio_client_stop(struct fio_client *client, struct fio_net_cmd *cmd)
1265{
1266 struct gfio_client *gc = client->client_data;
1267
1268 gdk_threads_enter();
1269
1270 gfio_set_connected(gc->ui, 0);
1271
1272 if (gc->err_entry)
1273 entry_set_int_value(gc->err_entry, client->error);
1274
1275 gdk_threads_leave();
1276}
1277
Stephen M. Camerona1820202012-02-24 08:17:31 +01001278struct client_ops gfio_client_ops = {
Jens Axboe0420ba62012-02-29 11:16:52 +01001279 .text_op = gfio_text_op,
1280 .disk_util = gfio_disk_util_op,
1281 .thread_status = gfio_thread_status_op,
1282 .group_stats = gfio_group_stats_op,
Jens Axboea5276612012-03-04 15:15:08 +01001283 .eta = gfio_update_eta,
Jens Axboe0420ba62012-02-29 11:16:52 +01001284 .probe = gfio_probe_op,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001285 .quit = gfio_quit_op,
Jens Axboe807f9972012-03-02 10:25:24 +01001286 .add_job = gfio_add_job_op,
Jens Axboeed727a42012-03-02 12:14:40 +01001287 .timed_out = gfio_client_timed_out,
Jens Axboe6b79c802012-03-08 10:51:36 +01001288 .stop = gfio_client_stop,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001289 .stay_connected = 1,
Stephen M. Camerona1820202012-02-24 08:17:31 +01001290};
1291
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001292static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1293 __attribute__((unused)) gpointer data)
1294{
1295 gtk_main_quit();
1296}
1297
Stephen M. Cameron25927252012-02-24 08:17:31 +01001298static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001299{
Stephen M. Cameron25927252012-02-24 08:17:31 +01001300 fio_handle_clients(&gfio_client_ops);
Stephen M. Cameron25927252012-02-24 08:17:31 +01001301 return NULL;
1302}
1303
Jens Axboe0420ba62012-02-29 11:16:52 +01001304static int send_job_files(struct gui *ui)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001305{
Jens Axboe441013b2012-03-01 08:01:52 +01001306 int i, ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001307
Jens Axboe0420ba62012-02-29 11:16:52 +01001308 for (i = 0; i < ui->nr_job_files; i++) {
1309 ret = fio_clients_send_ini(ui->job_files[i]);
Jens Axboe441013b2012-03-01 08:01:52 +01001310 if (ret)
1311 break;
1312
Jens Axboe0420ba62012-02-29 11:16:52 +01001313 free(ui->job_files[i]);
1314 ui->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001315 }
1316 while (i < ui->nr_job_files) {
1317 free(ui->job_files[i]);
1318 ui->job_files[i] = NULL;
1319 i++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001320 }
1321
Jens Axboe441013b2012-03-01 08:01:52 +01001322 return ret;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001323}
1324
Jens Axboe63a130b2012-03-06 20:08:59 +01001325static void *server_thread(void *arg)
1326{
1327 is_backend = 1;
1328 gfio_server_running = 1;
1329 fio_start_server(NULL);
1330 gfio_server_running = 0;
1331 return NULL;
1332}
1333
1334static void gfio_start_server(struct gui *ui)
1335{
1336 if (!gfio_server_running) {
1337 gfio_server_running = 1;
1338 pthread_create(&ui->server_t, NULL, server_thread, NULL);
Jens Axboee34f6ad2012-03-06 20:47:15 +01001339 pthread_detach(ui->server_t);
Jens Axboe63a130b2012-03-06 20:08:59 +01001340 }
1341}
1342
Stephen M. Cameron25927252012-02-24 08:17:31 +01001343static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1344 gpointer data)
1345{
1346 struct gui *ui = data;
Jens Axboeb9d2f302012-03-08 20:36:28 +01001347 struct gfio_client *gc = ui->client;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001348
Stephen M. Cameron25927252012-02-24 08:17:31 +01001349 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001350 fio_net_send_simple_cmd(gc->client->fd, FIO_NET_CMD_RUN, 0, NULL);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001351}
1352
Jens Axboedf06f222012-03-02 13:32:04 +01001353static void file_open(GtkWidget *w, gpointer data);
1354
1355static void connect_clicked(GtkWidget *widget, gpointer data)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001356{
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001357 struct gui *ui = data;
1358
1359 if (!ui->connected) {
Jens Axboedf06f222012-03-02 13:32:04 +01001360 if (!ui->nr_job_files)
1361 file_open(widget, data);
Jens Axboe8663ea62012-03-02 14:04:30 +01001362 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
Jens Axboee34f6ad2012-03-06 20:47:15 +01001363 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe69406b92012-03-06 14:00:42 +01001364 if (!fio_clients_connect()) {
1365 pthread_create(&ui->t, NULL, job_thread, NULL);
1366 gtk_widget_set_sensitive(ui->button[CONNECT_BUTTON], 0);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001367 gtk_widget_set_sensitive(ui->button[SEND_BUTTON], 1);
Jens Axboe69406b92012-03-06 14:00:42 +01001368 }
Jens Axboedf06f222012-03-02 13:32:04 +01001369 } else {
1370 fio_clients_terminate();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001371 gfio_set_connected(ui, 0);
Jens Axboe88432652012-03-02 19:09:31 +01001372 clear_ui_info(ui);
Jens Axboedf06f222012-03-02 13:32:04 +01001373 }
Jens Axboe3e47bd22012-02-29 13:45:02 +01001374}
1375
Jens Axboeb9d2f302012-03-08 20:36:28 +01001376static void send_clicked(GtkWidget *widget, gpointer data)
1377{
1378 struct gui *ui = data;
1379
1380 if (send_job_files(ui)) {
1381 printf("Yeah, I didn't really like those options too much.\n");
1382 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
1383 }
1384
1385 gtk_widget_set_sensitive(ui->button[SEND_BUTTON], 0);
1386 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
1387}
1388
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001389static void add_button(struct gui *ui, int i, GtkWidget *buttonbox,
1390 struct button_spec *buttonspec)
1391{
1392 ui->button[i] = gtk_button_new_with_label(buttonspec->buttontext);
1393 g_signal_connect(ui->button[i], "clicked", G_CALLBACK (buttonspec->f), ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001394 gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], FALSE, FALSE, 3);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001395 gtk_widget_set_tooltip_text(ui->button[i], buttonspeclist[i].tooltiptext);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001396 gtk_widget_set_sensitive(ui->button[i], !buttonspec->start_insensitive);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001397}
1398
1399static void add_buttons(struct gui *ui,
1400 struct button_spec *buttonlist,
1401 int nbuttons)
1402{
1403 int i;
1404
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001405 for (i = 0; i < nbuttons; i++)
1406 add_button(ui, i, ui->buttonbox, &buttonlist[i]);
1407}
1408
Jens Axboe0420ba62012-02-29 11:16:52 +01001409static void on_info_bar_response(GtkWidget *widget, gint response,
1410 gpointer data)
1411{
1412 if (response == GTK_RESPONSE_OK) {
1413 gtk_widget_destroy(widget);
1414 ui.error_info_bar = NULL;
1415 }
1416}
1417
Jens Axboedf06f222012-03-02 13:32:04 +01001418void report_error(GError *error)
Jens Axboe0420ba62012-02-29 11:16:52 +01001419{
1420 if (ui.error_info_bar == NULL) {
1421 ui.error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
1422 GTK_RESPONSE_OK,
1423 NULL);
1424 g_signal_connect(ui.error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1425 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui.error_info_bar),
1426 GTK_MESSAGE_ERROR);
1427
1428 ui.error_label = gtk_label_new(error->message);
1429 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui.error_info_bar));
1430 gtk_container_add(GTK_CONTAINER(container), ui.error_label);
1431
1432 gtk_box_pack_start(GTK_BOX(ui.vbox), ui.error_info_bar, FALSE, FALSE, 0);
1433 gtk_widget_show_all(ui.vbox);
1434 } else {
1435 char buffer[256];
1436 snprintf(buffer, sizeof(buffer), "Failed to open file.");
1437 gtk_label_set(GTK_LABEL(ui.error_label), buffer);
1438 }
1439}
1440
Jens Axboe62bc9372012-03-07 11:45:07 +01001441struct connection_widgets
1442{
1443 GtkWidget *hentry;
1444 GtkWidget *combo;
1445 GtkWidget *button;
1446};
1447
1448static void hostname_cb(GtkEntry *entry, gpointer data)
1449{
1450 struct connection_widgets *cw = data;
1451 int uses_net = 0, is_localhost = 0;
1452 const gchar *text;
1453 gchar *ctext;
1454
1455 /*
1456 * Check whether to display the 'auto start backend' box
1457 * or not. Show it if we are a localhost and using network,
1458 * or using a socket.
1459 */
1460 ctext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->combo));
1461 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
1462 uses_net = 1;
1463 g_free(ctext);
1464
1465 if (uses_net) {
1466 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
1467 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
1468 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
1469 !strcmp(text, "ip6-loopback"))
1470 is_localhost = 1;
1471 }
1472
1473 if (!uses_net || is_localhost) {
1474 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
1475 gtk_widget_set_sensitive(cw->button, 1);
1476 } else {
1477 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
1478 gtk_widget_set_sensitive(cw->button, 0);
1479 }
1480}
1481
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001482static int get_connection_details(char **host, int *port, int *type,
1483 int *server_start)
Jens Axboea7a42ce2012-03-02 13:12:04 +01001484{
Jens Axboe62bc9372012-03-07 11:45:07 +01001485 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
1486 struct connection_widgets cw;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001487 char *typeentry;
1488
1489 dialog = gtk_dialog_new_with_buttons("Connection details",
1490 GTK_WINDOW(ui.window),
1491 GTK_DIALOG_DESTROY_WITH_PARENT,
1492 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1493 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1494
1495 frame = gtk_frame_new("Hostname / socket name");
Jens Axboef1299092012-03-07 20:00:02 +01001496 /* gtk_dialog_get_content_area() is 2.14 and newer */
1497 vbox = GTK_DIALOG(dialog)->vbox;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001498 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1499
1500 box = gtk_vbox_new(FALSE, 6);
1501 gtk_container_add(GTK_CONTAINER(frame), box);
1502
1503 hbox = gtk_hbox_new(TRUE, 10);
1504 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe62bc9372012-03-07 11:45:07 +01001505 cw.hentry = gtk_entry_new();
1506 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
1507 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001508
1509 frame = gtk_frame_new("Port");
1510 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1511 box = gtk_vbox_new(FALSE, 10);
1512 gtk_container_add(GTK_CONTAINER(frame), box);
1513
1514 hbox = gtk_hbox_new(TRUE, 4);
1515 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1516 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1517
1518 frame = gtk_frame_new("Type");
1519 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1520 box = gtk_vbox_new(FALSE, 10);
1521 gtk_container_add(GTK_CONTAINER(frame), box);
1522
1523 hbox = gtk_hbox_new(TRUE, 4);
1524 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1525
Jens Axboe62bc9372012-03-07 11:45:07 +01001526 cw.combo = gtk_combo_box_new_text();
1527 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv4");
1528 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv6");
1529 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "local socket");
1530 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001531
Jens Axboe62bc9372012-03-07 11:45:07 +01001532 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001533
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001534 frame = gtk_frame_new("Options");
1535 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1536 box = gtk_vbox_new(FALSE, 10);
1537 gtk_container_add(GTK_CONTAINER(frame), box);
1538
1539 hbox = gtk_hbox_new(TRUE, 4);
1540 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1541
Jens Axboe62bc9372012-03-07 11:45:07 +01001542 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1543 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
1544 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.");
1545 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
1546
1547 /*
1548 * Connect edit signal, so we can show/not-show the auto start button
1549 */
1550 g_signal_connect(GTK_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
1551 g_signal_connect(GTK_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001552
Jens Axboea7a42ce2012-03-02 13:12:04 +01001553 gtk_widget_show_all(dialog);
1554
1555 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1556 gtk_widget_destroy(dialog);
1557 return 1;
1558 }
1559
Jens Axboe62bc9372012-03-07 11:45:07 +01001560 *host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001561 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1562
Jens Axboe62bc9372012-03-07 11:45:07 +01001563 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw.combo));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001564 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1565 *type = Fio_client_ipv4;
1566 else if (!strncmp(typeentry, "IPv6", 4))
1567 *type = Fio_client_ipv6;
1568 else
1569 *type = Fio_client_socket;
1570 g_free(typeentry);
1571
Jens Axboe62bc9372012-03-07 11:45:07 +01001572 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001573
Jens Axboea7a42ce2012-03-02 13:12:04 +01001574 gtk_widget_destroy(dialog);
1575 return 0;
1576}
1577
Jens Axboee0681f32012-03-06 12:14:42 +01001578static void gfio_client_added(struct gui *ui, struct fio_client *client)
1579{
1580 struct gfio_client *gc;
1581
1582 gc = malloc(sizeof(*gc));
1583 memset(gc, 0, sizeof(*gc));
1584 gc->ui = ui;
Jens Axboeb9d2f302012-03-08 20:36:28 +01001585 gc->client = client;
1586
1587 ui->client = gc;
Jens Axboee0681f32012-03-06 12:14:42 +01001588
1589 client->client_data = gc;
1590}
1591
Jens Axboe0420ba62012-02-29 11:16:52 +01001592static void file_open(GtkWidget *w, gpointer data)
1593{
1594 GtkWidget *dialog;
Jens Axboe63a130b2012-03-06 20:08:59 +01001595 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01001596 GSList *filenames, *fn_glist;
1597 GtkFileFilter *filter;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001598 char *host;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001599 int port, type, server_start;
Jens Axboe0420ba62012-02-29 11:16:52 +01001600
1601 dialog = gtk_file_chooser_dialog_new("Open File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001602 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001603 GTK_FILE_CHOOSER_ACTION_OPEN,
1604 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1605 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1606 NULL);
1607 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1608
1609 filter = gtk_file_filter_new();
1610 gtk_file_filter_add_pattern(filter, "*.fio");
1611 gtk_file_filter_add_pattern(filter, "*.job");
Jens Axboe2d262992012-03-07 08:19:30 +01001612 gtk_file_filter_add_pattern(filter, "*.ini");
Jens Axboe0420ba62012-02-29 11:16:52 +01001613 gtk_file_filter_add_mime_type(filter, "text/fio");
1614 gtk_file_filter_set_name(filter, "Fio job file");
1615 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
1616
1617 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1618 gtk_widget_destroy(dialog);
1619 return;
1620 }
1621
1622 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001623
1624 gtk_widget_destroy(dialog);
1625
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001626 if (get_connection_details(&host, &port, &type, &server_start))
Jens Axboea7a42ce2012-03-02 13:12:04 +01001627 goto err;
1628
Jens Axboe0420ba62012-02-29 11:16:52 +01001629 filenames = fn_glist;
1630 while (filenames != NULL) {
Jens Axboee0681f32012-03-06 12:14:42 +01001631 struct fio_client *client;
1632
Jens Axboe63a130b2012-03-06 20:08:59 +01001633 ui->job_files = realloc(ui->job_files, (ui->nr_job_files + 1) * sizeof(char *));
1634 ui->job_files[ui->nr_job_files] = strdup(filenames->data);
1635 ui->nr_job_files++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001636
Jens Axboee0681f32012-03-06 12:14:42 +01001637 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
1638 if (!client) {
Jens Axboedf06f222012-03-02 13:32:04 +01001639 GError *error;
1640
1641 error = g_error_new(g_quark_from_string("fio"), 1,
1642 "Failed to add client %s", host);
Jens Axboe0420ba62012-02-29 11:16:52 +01001643 report_error(error);
1644 g_error_free(error);
Jens Axboe0420ba62012-02-29 11:16:52 +01001645 }
Jens Axboe63a130b2012-03-06 20:08:59 +01001646 gfio_client_added(ui, client);
Jens Axboe0420ba62012-02-29 11:16:52 +01001647
1648 g_free(filenames->data);
1649 filenames = g_slist_next(filenames);
1650 }
Jens Axboea7a42ce2012-03-02 13:12:04 +01001651 free(host);
Jens Axboe63a130b2012-03-06 20:08:59 +01001652
1653 if (server_start)
1654 gfio_start_server(ui);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001655err:
Jens Axboe0420ba62012-02-29 11:16:52 +01001656 g_slist_free(fn_glist);
Jens Axboe0420ba62012-02-29 11:16:52 +01001657}
1658
1659static void file_save(GtkWidget *w, gpointer data)
1660{
Jens Axboe63a130b2012-03-06 20:08:59 +01001661 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01001662 GtkWidget *dialog;
1663
1664 dialog = gtk_file_chooser_dialog_new("Save File",
Jens Axboe63a130b2012-03-06 20:08:59 +01001665 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01001666 GTK_FILE_CHOOSER_ACTION_SAVE,
1667 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1668 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1669 NULL);
1670
1671 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1672 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
1673
1674 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1675 char *filename;
1676
1677 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1678 // save_job_file(filename);
1679 g_free(filename);
1680 }
1681 gtk_widget_destroy(dialog);
1682}
1683
Jens Axboe9b260bd2012-03-06 11:02:52 +01001684static void view_log_destroy(GtkWidget *w, gpointer data)
1685{
1686 struct gui *ui = (struct gui *) data;
1687
1688 gtk_widget_ref(ui->log_tree);
1689 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
1690 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +01001691 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001692}
1693
1694static void view_log(GtkWidget *w, gpointer data)
1695{
Jens Axboe4cbe7212012-03-06 13:36:17 +01001696 GtkWidget *win, *scroll, *vbox, *box;
1697 struct gui *ui = (struct gui *) data;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001698
Jens Axboe4cbe7212012-03-06 13:36:17 +01001699 if (ui->log_view)
1700 return;
1701
1702 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001703 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001704 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001705
Jens Axboe4cbe7212012-03-06 13:36:17 +01001706 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001707
Jens Axboe4cbe7212012-03-06 13:36:17 +01001708 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
1709
1710 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1711
1712 box = gtk_hbox_new(TRUE, 0);
1713 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
1714 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
1715 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
1716
1717 vbox = gtk_vbox_new(TRUE, 5);
1718 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
1719
1720 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001721 gtk_widget_show_all(win);
1722}
1723
Jens Axboe46974a72012-03-02 19:34:13 +01001724static void preferences(GtkWidget *w, gpointer data)
1725{
Jens Axboef3e84402012-03-07 13:14:32 +01001726 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
Jens Axboe46974a72012-03-02 19:34:13 +01001727 int i;
1728
1729 dialog = gtk_dialog_new_with_buttons("Preferences",
1730 GTK_WINDOW(ui.window),
1731 GTK_DIALOG_DESTROY_WITH_PARENT,
1732 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1733 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1734 NULL);
1735
Jens Axboe0b8d11e2012-03-02 19:44:15 +01001736 frame = gtk_frame_new("Debug logging");
Jens Axboe46974a72012-03-02 19:34:13 +01001737 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
Jens Axboef3e84402012-03-07 13:14:32 +01001738
1739 vbox = gtk_vbox_new(FALSE, 6);
1740 gtk_container_add(GTK_CONTAINER(frame), vbox);
1741
Jens Axboe46974a72012-03-02 19:34:13 +01001742 box = gtk_hbox_new(FALSE, 6);
Jens Axboef3e84402012-03-07 13:14:32 +01001743 gtk_container_add(GTK_CONTAINER(vbox), box);
Jens Axboe46974a72012-03-02 19:34:13 +01001744
1745 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
1746
1747 for (i = 0; i < FD_DEBUG_MAX; i++) {
Jens Axboef3e84402012-03-07 13:14:32 +01001748 if (i == 7) {
1749 box = gtk_hbox_new(FALSE, 6);
1750 gtk_container_add(GTK_CONTAINER(vbox), box);
1751 }
1752
1753
Jens Axboe46974a72012-03-02 19:34:13 +01001754 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
Jens Axboe0b8d11e2012-03-02 19:44:15 +01001755 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
Jens Axboe46974a72012-03-02 19:34:13 +01001756 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
1757 }
1758
Jens Axboef3e84402012-03-07 13:14:32 +01001759 frame = gtk_frame_new("Graph font");
1760 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
1761 vbox = gtk_vbox_new(FALSE, 6);
1762 gtk_container_add(GTK_CONTAINER(frame), vbox);
1763
1764 font = gtk_font_button_new();
1765 gtk_box_pack_start(GTK_BOX(vbox), font, FALSE, FALSE, 5);
1766
Jens Axboe46974a72012-03-02 19:34:13 +01001767 gtk_widget_show_all(dialog);
1768
1769 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1770 gtk_widget_destroy(dialog);
1771 return;
1772 }
1773
1774 for (i = 0; i < FD_DEBUG_MAX; i++) {
1775 int set;
1776
1777 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
1778 if (set)
1779 fio_debug |= (1UL << i);
1780 }
1781
Jens Axboef3e84402012-03-07 13:14:32 +01001782 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
Jens Axboe46974a72012-03-02 19:34:13 +01001783 gtk_widget_destroy(dialog);
1784}
1785
Jens Axboe0420ba62012-02-29 11:16:52 +01001786static void about_dialog(GtkWidget *w, gpointer data)
1787{
Jens Axboe81e4ea62012-03-07 14:18:28 +01001788 const char *authors[] = {
1789 "Jens Axboe <axboe@kernel.dk>",
1790 "Stephen Carmeron <stephenmcameron@gmail.com>",
1791 NULL
1792 };
Jens Axboe84a72ed2012-03-07 14:24:57 +01001793 const char *license[] = {
1794 "Fio is free software; you can redistribute it and/or modify "
1795 "it under the terms of the GNU General Public License as published by "
1796 "the Free Software Foundation; either version 2 of the License, or "
1797 "(at your option) any later version.\n",
1798 "Fio is distributed in the hope that it will be useful, "
1799 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
1800 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
1801 "GNU General Public License for more details.\n",
1802 "You should have received a copy of the GNU General Public License "
1803 "along with Fio; if not, write to the Free Software Foundation, Inc., "
1804 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
1805 };
1806 char *license_trans;
1807
1808 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
1809 license[2], "\n", NULL);
Jens Axboe81e4ea62012-03-07 14:18:28 +01001810
Jens Axboe0420ba62012-02-29 11:16:52 +01001811 gtk_show_about_dialog(NULL,
1812 "program-name", "gfio",
1813 "comments", "Gtk2 UI for fio",
Jens Axboe84a72ed2012-03-07 14:24:57 +01001814 "license", license_trans,
Jens Axboe81e4ea62012-03-07 14:18:28 +01001815 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
1816 "authors", authors,
Jens Axboe0420ba62012-02-29 11:16:52 +01001817 "version", fio_version_string,
Jens Axboe81e4ea62012-03-07 14:18:28 +01001818 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
Jens Axboe0420ba62012-02-29 11:16:52 +01001819 "logo-icon-name", "fio",
1820 /* Must be last: */
Jens Axboe81e4ea62012-03-07 14:18:28 +01001821 "wrap-license", TRUE,
Jens Axboe0420ba62012-02-29 11:16:52 +01001822 NULL);
Jens Axboe84a72ed2012-03-07 14:24:57 +01001823
1824 g_free (license_trans);
Jens Axboe0420ba62012-02-29 11:16:52 +01001825}
1826
1827static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01001828 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01001829 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01001830 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
1831 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
1832 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
1833 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01001834 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe46974a72012-03-02 19:34:13 +01001835 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
1836 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01001837};
Jens Axboe3e47bd22012-02-29 13:45:02 +01001838static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01001839
1840static const gchar *ui_string = " \
1841 <ui> \
1842 <menubar name=\"MainMenu\"> \
1843 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
1844 <menuitem name=\"Open\" action=\"OpenFile\" /> \
1845 <menuitem name=\"Save\" action=\"SaveFile\" /> \
1846 <separator name=\"Separator\"/> \
Jens Axboe46974a72012-03-02 19:34:13 +01001847 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
1848 <separator name=\"Separator2\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01001849 <menuitem name=\"Quit\" action=\"Quit\" /> \
1850 </menu> \
Jens Axboe9b260bd2012-03-06 11:02:52 +01001851 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
1852 <menuitem name=\"Log\" action=\"ViewLog\" /> \
1853 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01001854 <menu name=\"Help\" action=\"HelpMenuAction\"> \
1855 <menuitem name=\"About\" action=\"About\" /> \
1856 </menu> \
1857 </menubar> \
1858 </ui> \
1859";
1860
Jens Axboe4cbe7212012-03-06 13:36:17 +01001861static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
1862 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01001863{
1864 GtkActionGroup *action_group = gtk_action_group_new("Menu");
1865 GError *error = 0;
1866
1867 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01001868 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001869
1870 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1871 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
1872
1873 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
1874 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
1875}
1876
1877void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
1878 GtkWidget *vbox, GtkUIManager *ui_manager)
1879{
1880 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
1881}
1882
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001883static void init_ui(int *argc, char **argv[], struct gui *ui)
1884{
Jens Axboe0420ba62012-02-29 11:16:52 +01001885 GtkSettings *settings;
1886 GtkUIManager *uimanager;
Jens Axboe843ad232012-02-29 11:44:53 +01001887 GtkWidget *menu, *probe, *probe_frame, *probe_box;
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01001888 GdkColor white;
Jens Axboe0420ba62012-02-29 11:16:52 +01001889
1890 memset(ui, 0, sizeof(*ui));
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001891
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001892 /* Magical g*thread incantation, you just need this thread stuff.
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001893 * Without it, the update that happens in gfio_update_thread_status
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001894 * doesn't really happen in a timely fashion, you need expose events
1895 */
Jens Axboeed727a42012-03-02 12:14:40 +01001896 if (!g_thread_supported())
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01001897 g_thread_init(NULL);
1898 gdk_threads_init();
1899
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001900 gtk_init(argc, argv);
Jens Axboe0420ba62012-02-29 11:16:52 +01001901 settings = gtk_settings_get_default();
1902 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
1903 g_type_init();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001904
1905 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1906 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
Jens Axboef3e84402012-03-07 13:14:32 +01001907 gtk_window_set_default_size(GTK_WINDOW(ui->window), 700, 700);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001908
Jens Axboe0420ba62012-02-29 11:16:52 +01001909 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
1910 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001911
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001912 ui->vbox = gtk_vbox_new(FALSE, 0);
1913 gtk_container_add(GTK_CONTAINER (ui->window), ui->vbox);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001914
Jens Axboe0420ba62012-02-29 11:16:52 +01001915 uimanager = gtk_ui_manager_new();
Jens Axboe4cbe7212012-03-06 13:36:17 +01001916 menu = get_menubar_menu(ui->window, uimanager, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01001917 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
1918
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +01001919 /*
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001920 * Set up alignments for widgets at the top of ui,
1921 * align top left, expand horizontally but not vertically
1922 */
1923 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001924 ui->topvbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001925 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001926 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->topalign, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001927
Jens Axboe3e47bd22012-02-29 13:45:02 +01001928 probe = gtk_frame_new("Job");
Jens Axboe843ad232012-02-29 11:44:53 +01001929 gtk_box_pack_start(GTK_BOX(ui->topvbox), probe, TRUE, FALSE, 3);
1930 probe_frame = gtk_vbox_new(FALSE, 3);
1931 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
1932
1933 probe_box = gtk_hbox_new(FALSE, 3);
1934 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01001935 ui->probe.hostname = new_info_label_in_frame(probe_box, "Host");
1936 ui->probe.os = new_info_label_in_frame(probe_box, "OS");
1937 ui->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
1938 ui->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
1939
Jens Axboe3e47bd22012-02-29 13:45:02 +01001940 probe_box = gtk_hbox_new(FALSE, 3);
1941 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01001942
Jens Axboeca850992012-03-05 20:04:43 +01001943 ui->eta.name = new_info_entry_in_frame(probe_box, "Name");
1944 ui->eta.iotype = new_info_entry_in_frame(probe_box, "IO");
1945 ui->eta.ioengine = new_info_entry_in_frame(probe_box, "IO Engine");
1946 ui->eta.iodepth = new_info_entry_in_frame(probe_box, "IO Depth");
1947 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
1948 ui->eta.files = new_info_entry_in_frame(probe_box, "Open files");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001949
1950 probe_box = gtk_hbox_new(FALSE, 3);
1951 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboeca850992012-03-05 20:04:43 +01001952 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
1953 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
1954 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
1955 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001956
1957 /*
1958 * Only add this if we have a commit rate
1959 */
1960#if 0
1961 probe_box = gtk_hbox_new(FALSE, 3);
1962 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1963
Jens Axboe3e47bd22012-02-29 13:45:02 +01001964 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1965 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1966
Jens Axboe3e47bd22012-02-29 13:45:02 +01001967 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1968 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01001969#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01001970
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01001971 /*
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001972 * Set up a drawing area and IOPS and bandwidth graphs
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001973 */
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01001974 gdk_color_parse("white", &white);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001975 ui->drawing_area = gtk_drawing_area_new();
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001976 ui->drawing_area_xdim = DRAWING_AREA_XDIM;
1977 ui->drawing_area_ydim = DRAWING_AREA_YDIM;
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001978 gtk_widget_set_size_request(GTK_WIDGET(ui->drawing_area),
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001979 ui->drawing_area_xdim, ui->drawing_area_ydim);
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01001980 gtk_widget_modify_bg(ui->drawing_area, GTK_STATE_NORMAL, &white);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001981 g_signal_connect(G_OBJECT(ui->drawing_area), "expose_event",
1982 G_CALLBACK (on_expose_drawing_area), ui);
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001983 g_signal_connect(G_OBJECT(ui->drawing_area), "configure_event",
1984 G_CALLBACK (on_config_drawing_area), ui);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001985 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1986 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1987 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001988 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1989 ui->drawing_area);
Stephen M. Camerone1645342012-02-24 08:17:32 +01001990 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->scrolled_window,
1991 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001992
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001993 setup_iops_graph(ui);
1994 setup_bandwidth_graph(ui);
1995
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01001996 /*
1997 * Set up alignments for widgets at the bottom of ui,
1998 * align bottom left, expand horizontally but not vertically
1999 */
2000 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
2001 ui->buttonbox = gtk_hbox_new(FALSE, 0);
2002 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +01002003 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->bottomalign,
2004 FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002005
Stephen M. Cameronf3074002012-02-24 08:17:30 +01002006 add_buttons(ui, buttonspeclist, ARRAYSIZE(buttonspeclist));
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002007
2008 /*
2009 * Set up thread status progress bar
2010 */
2011 ui->thread_status_pb = gtk_progress_bar_new();
2012 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01002013 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002014 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
2015
Jens Axboe9b260bd2012-03-06 11:02:52 +01002016 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002017
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002018 gtk_widget_show_all(ui->window);
2019}
2020
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002021int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002022{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002023 if (initialize_fio(envp))
2024 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01002025 if (fio_init_options())
2026 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01002027
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002028 init_ui(&argc, &argv, &ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01002029
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002030 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002031 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002032 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002033 return 0;
2034}