blob: 4bc3a3e663f3cead732b5b25bd601d5667c50e49 [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 Axboe8577f4f2012-03-09 19:28:27 +010037static unsigned int gfio_graph_limit = 100;
Jens Axboe63a130b2012-03-06 20:08:59 +010038
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 Axboe2f99deb2012-03-09 14:37:29 +010061 "Start the current job on the server", 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 Axboec80b74b2012-03-12 10:23:28 +010071struct multitext_widget {
72 GtkWidget *entry;
73 char **text;
74 unsigned int cur_text;
75 unsigned int max_text;
76};
77
Jens Axboe3e47bd22012-02-29 13:45:02 +010078struct eta_widget {
Jens Axboe3863d1a2012-03-09 17:39:05 +010079 GtkWidget *names;
Jens Axboec80b74b2012-03-12 10:23:28 +010080 struct multitext_widget iotype;
81 struct multitext_widget ioengine;
82 struct multitext_widget iodepth;
Jens Axboe3e47bd22012-02-29 13:45:02 +010083 GtkWidget *jobs;
84 GtkWidget *files;
85 GtkWidget *read_bw;
86 GtkWidget *read_iops;
87 GtkWidget *cr_bw;
88 GtkWidget *cr_iops;
89 GtkWidget *write_bw;
90 GtkWidget *write_iops;
91 GtkWidget *cw_bw;
92 GtkWidget *cw_iops;
93};
94
Jens Axboe2f99deb2012-03-09 14:37:29 +010095struct gfio_graphs {
96#define DRAWING_AREA_XDIM 1000
97#define DRAWING_AREA_YDIM 400
98 GtkWidget *drawing_area;
Jens Axboe2f99deb2012-03-09 14:37:29 +010099 struct graph *iops_graph;
100 struct graph *bandwidth_graph;
101};
102
103/*
104 * Main window widgets and data
105 */
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100106struct gui {
107 GtkWidget *window;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100108 GtkWidget *vbox;
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +0100109 GtkWidget *topvbox;
110 GtkWidget *topalign;
111 GtkWidget *bottomalign;
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +0100112 GtkWidget *thread_status_pb;
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100113 GtkWidget *buttonbox;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100114 GtkWidget *scrolled_window;
115 GtkWidget *notebook;
116 GtkWidget *error_info_bar;
117 GtkWidget *error_label;
118 GtkListStore *log_model;
119 GtkWidget *log_tree;
120 GtkWidget *log_view;
121 struct gfio_graphs graphs;
122 struct probe_widget probe;
123 struct eta_widget eta;
124 pthread_t server_t;
125
Jens Axboea9eccde2012-03-09 14:59:42 +0100126 pthread_t t;
127 int handler_running;
128
Jens Axboe2f99deb2012-03-09 14:37:29 +0100129 struct flist_head list;
130} main_ui;
131
132/*
133 * Notebook entry
134 */
135struct gui_entry {
136 struct flist_head list;
137 struct gui *ui;
138
139 GtkWidget *vbox;
140 GtkWidget *topvbox;
141 GtkWidget *topalign;
142 GtkWidget *bottomalign;
Jens Axboec80b74b2012-03-12 10:23:28 +0100143 GtkWidget *job_notebook;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100144 GtkWidget *thread_status_pb;
145 GtkWidget *buttonbox;
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100146 GtkWidget *button[ARRAYSIZE(buttonspeclist)];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100147 GtkWidget *scrolled_window;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100148 GtkWidget *notebook;
Jens Axboe0420ba62012-02-29 11:16:52 +0100149 GtkWidget *error_info_bar;
150 GtkWidget *error_label;
Jens Axboef9d40b42012-03-06 09:52:49 +0100151 GtkWidget *results_notebook;
152 GtkWidget *results_window;
Jens Axboe9b260bd2012-03-06 11:02:52 +0100153 GtkListStore *log_model;
154 GtkWidget *log_tree;
Jens Axboe4cbe7212012-03-06 13:36:17 +0100155 GtkWidget *log_view;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100156 struct gfio_graphs graphs;
Jens Axboe843ad232012-02-29 11:44:53 +0100157 struct probe_widget probe;
Jens Axboe3e47bd22012-02-29 13:45:02 +0100158 struct eta_widget eta;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100159 GtkWidget *page_label;
160 gint page_num;
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100161 int connected;
Jens Axboe0420ba62012-02-29 11:16:52 +0100162
Jens Axboeb9d2f302012-03-08 20:36:28 +0100163 struct gfio_client *client;
Jens Axboe0420ba62012-02-29 11:16:52 +0100164 int nr_job_files;
165 char **job_files;
Jens Axboe2f99deb2012-03-09 14:37:29 +0100166};
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100167
Jens Axboee0681f32012-03-06 12:14:42 +0100168struct gfio_client {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100169 struct gui_entry *ge;
Jens Axboeb9d2f302012-03-08 20:36:28 +0100170 struct fio_client *client;
Jens Axboee0681f32012-03-06 12:14:42 +0100171 GtkWidget *results_widget;
172 GtkWidget *disk_util_frame;
Jens Axboe6b79c802012-03-08 10:51:36 +0100173 GtkWidget *err_entry;
Jens Axboedcaeb602012-03-08 19:45:37 +0100174 unsigned int job_added;
175 struct thread_options o;
Jens Axboee0681f32012-03-06 12:14:42 +0100176};
177
Jens Axboe9988ca72012-03-09 15:14:06 +0100178static void gfio_update_thread_status(struct gui_entry *ge, char *status_message, double perc);
179static void gfio_update_thread_status_all(char *status_message, double perc);
Jens Axboec7249262012-03-09 17:11:04 +0100180void report_error(GError *error);
Jens Axboe9988ca72012-03-09 15:14:06 +0100181
Stephen M. Cameronf0af9f82012-03-11 11:35:50 +0100182static void iops_graph_y_axis_unit_change(struct graph *g, int power_of_ten)
183{
184 switch (power_of_ten) {
185 case 9: graph_y_title(g, "Billions of IOs / sec");
186 break;
187 case 6: graph_y_title(g, "Millions of IOs / sec");
188 break;
189 case 3: graph_y_title(g, "Thousands of IOs / sec");
190 break;
191 case 0:
192 default: graph_y_title(g, "IOs / sec");
193 break;
194 }
195}
196
Jens Axboe2f99deb2012-03-09 14:37:29 +0100197static struct graph *setup_iops_graph(void)
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100198{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100199 struct graph *g;
200
201 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
202 graph_title(g, "IOPS");
203 graph_x_title(g, "Time (secs)");
204 graph_y_title(g, "IOs / sec");
205 graph_add_label(g, "Read IOPS");
206 graph_add_label(g, "Write IOPS");
207 graph_set_color(g, "Read IOPS", 0.13, 0.54, 0.13);
208 graph_set_color(g, "Write IOPS", 1.0, 0.0, 0.0);
Jens Axboe8577f4f2012-03-09 19:28:27 +0100209 line_graph_set_data_count_limit(g, gfio_graph_limit);
Stephen M. Cameronf0af9f82012-03-11 11:35:50 +0100210 graph_y_axis_unit_change_notify(g, iops_graph_y_axis_unit_change);
Stephen M. Camerondef0ac22012-03-12 07:32:57 +0100211 graph_add_extra_space(g, 0.005, 0.005, 0.03, 0.03);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100212 return g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100213}
214
Stephen M. Cameronf0af9f82012-03-11 11:35:50 +0100215static void bandwidth_graph_y_axis_unit_change(struct graph *g, int power_of_ten)
216{
217 switch (power_of_ten) {
218 case 9: graph_y_title(g, "Petabytes / sec");
219 break;
220 case 6: graph_y_title(g, "Gigabytes / sec");
221 break;
222 case 3: graph_y_title(g, "Megabytes / sec");
223 break;
224 case 0:
225 default: graph_y_title(g, "Kilobytes / sec");
226 break;
227 }
228}
229
Jens Axboe2f99deb2012-03-09 14:37:29 +0100230static struct graph *setup_bandwidth_graph(void)
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100231{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100232 struct graph *g;
233
234 g = graph_new(DRAWING_AREA_XDIM / 2.0, DRAWING_AREA_YDIM, gfio_graph_font);
235 graph_title(g, "Bandwidth");
236 graph_x_title(g, "Time (secs)");
237 graph_y_title(g, "Kbytes / sec");
238 graph_add_label(g, "Read Bandwidth");
239 graph_add_label(g, "Write Bandwidth");
240 graph_set_color(g, "Read Bandwidth", 0.13, 0.54, 0.13);
241 graph_set_color(g, "Write Bandwidth", 1.0, 0.0, 0.0);
242 line_graph_set_data_count_limit(g, 100);
Stephen M. Cameronf0af9f82012-03-11 11:35:50 +0100243 graph_y_axis_unit_change_notify(g, bandwidth_graph_y_axis_unit_change);
Stephen M. Camerondef0ac22012-03-12 07:32:57 +0100244 graph_add_extra_space(g, 0.005, 0.005, 0.03, 0.03);
245
Jens Axboe2f99deb2012-03-09 14:37:29 +0100246 return g;
Jens Axboe2fd3bb02012-03-07 08:07:39 +0100247}
248
Jens Axboe2f99deb2012-03-09 14:37:29 +0100249static void setup_graphs(struct gfio_graphs *g)
Jens Axboe8663ea62012-03-02 14:04:30 +0100250{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100251 g->iops_graph = setup_iops_graph();
252 g->bandwidth_graph = setup_bandwidth_graph();
253}
254
Jens Axboec80b74b2012-03-12 10:23:28 +0100255static void multitext_add_entry(struct multitext_widget *mt, const char *text)
256{
257 mt->text = realloc(mt->text, (mt->max_text + 1) * sizeof(char *));
258 mt->text[mt->max_text] = strdup(text);
259 mt->max_text++;
260}
261
262static void multitext_set_entry(struct multitext_widget *mt, unsigned int index)
263{
264 if (index >= mt->max_text)
265 return;
Jens Axboeda185432012-03-12 11:05:46 +0100266 if (!mt->text || !mt->text[index])
Jens Axboec80b74b2012-03-12 10:23:28 +0100267 return;
268
269 mt->cur_text = index;
270 gtk_entry_set_text(GTK_ENTRY(mt->entry), mt->text[index]);
271}
272
273static void multitext_update_entry(struct multitext_widget *mt,
274 unsigned int index, const char *text)
275{
Jens Axboeda185432012-03-12 11:05:46 +0100276 if (!mt->text)
277 return;
278
Jens Axboec80b74b2012-03-12 10:23:28 +0100279 if (mt->text[index])
280 free(mt->text[index]);
281
282 mt->text[index] = strdup(text);
283 if (mt->cur_text == index)
284 gtk_entry_set_text(GTK_ENTRY(mt->entry), mt->text[index]);
285}
286
287static void multitext_free(struct multitext_widget *mt)
288{
289 int i;
290
291 gtk_entry_set_text(GTK_ENTRY(mt->entry), "");
292
293 for (i = 0; i < mt->max_text; i++) {
294 if (mt->text[i])
295 free(mt->text[i]);
296 }
297
298 free(mt->text);
299 mt->cur_text = -1;
300 mt->max_text = 0;
301}
302
Jens Axboe2f99deb2012-03-09 14:37:29 +0100303static void clear_ge_ui_info(struct gui_entry *ge)
304{
305 gtk_label_set_text(GTK_LABEL(ge->probe.hostname), "");
306 gtk_label_set_text(GTK_LABEL(ge->probe.os), "");
307 gtk_label_set_text(GTK_LABEL(ge->probe.arch), "");
308 gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100309#if 0
310 /* should we empty it... */
Jens Axboe2f99deb2012-03-09 14:37:29 +0100311 gtk_entry_set_text(GTK_ENTRY(ge->eta.name), "");
Jens Axboe3863d1a2012-03-09 17:39:05 +0100312#endif
Jens Axboec80b74b2012-03-12 10:23:28 +0100313 multitext_update_entry(&ge->eta.iotype, 0, "");
314 multitext_update_entry(&ge->eta.ioengine, 0, "");
315 multitext_update_entry(&ge->eta.iodepth, 0, "");
Jens Axboe2f99deb2012-03-09 14:37:29 +0100316 gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), "");
317 gtk_entry_set_text(GTK_ENTRY(ge->eta.files), "");
318 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), "");
319 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), "");
320 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), "");
321 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), "");
Jens Axboe8663ea62012-03-02 14:04:30 +0100322}
323
Jens Axboe3863d1a2012-03-09 17:39:05 +0100324static GtkWidget *new_combo_entry_in_frame(GtkWidget *box, const char *label)
325{
326 GtkWidget *entry, *frame;
327
328 frame = gtk_frame_new(label);
329 entry = gtk_combo_box_new_text();
330 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
331 gtk_container_add(GTK_CONTAINER(frame), entry);
332
333 return entry;
334}
335
Jens Axboe3650a3c2012-03-05 14:09:03 +0100336static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
337{
338 GtkWidget *entry, *frame;
339
340 frame = gtk_frame_new(label);
341 entry = gtk_entry_new();
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100342 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100343 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
344 gtk_container_add(GTK_CONTAINER(frame), entry);
345
346 return entry;
347}
348
349static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
350{
351 GtkWidget *label_widget;
352 GtkWidget *frame;
353
354 frame = gtk_frame_new(label);
355 label_widget = gtk_label_new(NULL);
356 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
357 gtk_container_add(GTK_CONTAINER(frame), label_widget);
358
359 return label_widget;
360}
361
362static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
363{
364 GtkWidget *button, *box;
365
366 box = gtk_hbox_new(FALSE, 3);
367 gtk_container_add(GTK_CONTAINER(hbox), box);
368
369 button = gtk_spin_button_new_with_range(min, max, 1.0);
370 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
371
372 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
373 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
374
375 return button;
376}
377
Jens Axboe2f99deb2012-03-09 14:37:29 +0100378static void gfio_set_connected(struct gui_entry *ge, int connected)
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100379{
380 if (connected) {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100381 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 1);
382 ge->connected = 1;
383 gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), "Disconnect");
384 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100385 } else {
Jens Axboe2f99deb2012-03-09 14:37:29 +0100386 ge->connected = 0;
387 gtk_button_set_label(GTK_BUTTON(ge->button[CONNECT_BUTTON]), "Connect");
388 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 0);
389 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 0);
390 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 1);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100391 }
392}
393
Jens Axboe3650a3c2012-03-05 14:09:03 +0100394static void label_set_int_value(GtkWidget *entry, unsigned int val)
395{
396 char tmp[80];
397
398 sprintf(tmp, "%u", val);
399 gtk_label_set_text(GTK_LABEL(entry), tmp);
400}
401
402static void entry_set_int_value(GtkWidget *entry, unsigned int val)
403{
404 char tmp[80];
405
406 sprintf(tmp, "%u", val);
407 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
408}
409
Jens Axboe16ce5ad2012-03-12 11:56:09 +0100410static void show_info_dialog(struct gui *ui, const char *title,
411 const char *message)
412{
413 GtkWidget *dialog, *content, *label;
414
415 dialog = gtk_dialog_new_with_buttons(title, GTK_WINDOW(ui->window),
416 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
417 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
418
419 content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
420 label = gtk_label_new(message);
421 gtk_container_add(GTK_CONTAINER(content), label);
422 gtk_widget_show_all(dialog);
423 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
424 gtk_dialog_run(GTK_DIALOG(dialog));
425 gtk_widget_destroy(dialog);
426}
427
Jens Axboea2697902012-03-05 16:43:49 +0100428#define ALIGN_LEFT 1
429#define ALIGN_RIGHT 2
430#define INVISIBLE 4
431#define UNSORTABLE 8
432
433GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title, unsigned int flags)
434{
435 GtkCellRenderer *renderer;
436 GtkTreeViewColumn *col;
437 double xalign = 0.0; /* left as default */
438 PangoAlignment align;
439 gboolean visible;
440
441 align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
442 (flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
443 PANGO_ALIGN_CENTER;
444 visible = !(flags & INVISIBLE);
445
446 renderer = gtk_cell_renderer_text_new();
447 col = gtk_tree_view_column_new();
448
449 gtk_tree_view_column_set_title(col, title);
450 if (!(flags & UNSORTABLE))
451 gtk_tree_view_column_set_sort_column_id(col, index);
452 gtk_tree_view_column_set_resizable(col, TRUE);
453 gtk_tree_view_column_pack_start(col, renderer, TRUE);
454 gtk_tree_view_column_add_attribute(col, renderer, "text", index);
455 gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
456 switch (align) {
457 case PANGO_ALIGN_LEFT:
458 xalign = 0.0;
459 break;
460 case PANGO_ALIGN_CENTER:
461 xalign = 0.5;
462 break;
463 case PANGO_ALIGN_RIGHT:
464 xalign = 1.0;
465 break;
466 }
467 gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
468 gtk_tree_view_column_set_visible(col, visible);
469 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
470 return col;
471}
472
Jens Axboe9b260bd2012-03-06 11:02:52 +0100473static void gfio_ui_setup_log(struct gui *ui)
474{
475 GtkTreeSelection *selection;
476 GtkListStore *model;
477 GtkWidget *tree_view;
478
479 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
480
481 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
482 gtk_widget_set_can_focus(tree_view, FALSE);
483
484 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
485 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
Jens Axboe661f7412012-03-06 13:55:45 +0100486 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
487 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100488
489 tree_view_column(tree_view, 0, "Time", ALIGN_RIGHT | UNSORTABLE);
490 tree_view_column(tree_view, 1, "Host", ALIGN_RIGHT | UNSORTABLE);
491 tree_view_column(tree_view, 2, "Level", ALIGN_RIGHT | UNSORTABLE);
Jens Axboef095d562012-03-06 13:49:12 +0100492 tree_view_column(tree_view, 3, "Text", ALIGN_LEFT | UNSORTABLE);
Jens Axboe9b260bd2012-03-06 11:02:52 +0100493
494 ui->log_model = model;
495 ui->log_tree = tree_view;
496}
497
Jens Axboea2697902012-03-05 16:43:49 +0100498static GtkWidget *gfio_output_clat_percentiles(unsigned int *ovals,
499 fio_fp64_t *plist,
500 unsigned int len,
501 const char *base,
502 unsigned int scale)
503{
504 GType types[FIO_IO_U_LIST_MAX_LEN];
505 GtkWidget *tree_view;
506 GtkTreeSelection *selection;
507 GtkListStore *model;
508 GtkTreeIter iter;
509 int i;
510
511 for (i = 0; i < len; i++)
512 types[i] = G_TYPE_INT;
513
514 model = gtk_list_store_newv(len, types);
515
516 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
517 gtk_widget_set_can_focus(tree_view, FALSE);
518
Jens Axboe661f7412012-03-06 13:55:45 +0100519 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
520 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
521
Jens Axboea2697902012-03-05 16:43:49 +0100522 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
523 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
524
525 for (i = 0; i < len; i++) {
526 char fbuf[8];
527
528 sprintf(fbuf, "%2.2f%%", plist[i].u.f);
529 tree_view_column(tree_view, i, fbuf, ALIGN_RIGHT | UNSORTABLE);
530 }
531
532 gtk_list_store_append(model, &iter);
533
Jens Axboee0681f32012-03-06 12:14:42 +0100534 for (i = 0; i < len; i++) {
535 if (scale)
536 ovals[i] = (ovals[i] + 999) / 1000;
Jens Axboea2697902012-03-05 16:43:49 +0100537 gtk_list_store_set(model, &iter, i, ovals[i], -1);
Jens Axboee0681f32012-03-06 12:14:42 +0100538 }
Jens Axboea2697902012-03-05 16:43:49 +0100539
540 return tree_view;
541}
542
543static void gfio_show_clat_percentiles(GtkWidget *vbox, struct thread_stat *ts,
544 int ddir)
545{
546 unsigned int *io_u_plat = ts->io_u_plat[ddir];
547 unsigned long nr = ts->clat_stat[ddir].samples;
548 fio_fp64_t *plist = ts->percentile_list;
549 unsigned int *ovals, len, minv, maxv, scale_down;
550 const char *base;
551 GtkWidget *tree_view, *frame, *hbox;
552 char tmp[64];
553
554 len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
555 if (!len)
556 goto out;
557
558 /*
559 * We default to usecs, but if the value range is such that we
560 * should scale down to msecs, do that.
561 */
562 if (minv > 2000 && maxv > 99999) {
563 scale_down = 1;
564 base = "msec";
565 } else {
566 scale_down = 0;
567 base = "usec";
568 }
569
570 tree_view = gfio_output_clat_percentiles(ovals, plist, len, base, scale_down);
571
572 sprintf(tmp, "Completion percentiles (%s)", base);
573 frame = gtk_frame_new(tmp);
574 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
575
576 hbox = gtk_hbox_new(FALSE, 3);
577 gtk_container_add(GTK_CONTAINER(frame), hbox);
578
579 gtk_box_pack_start(GTK_BOX(hbox), tree_view, TRUE, FALSE, 3);
580out:
581 if (ovals)
582 free(ovals);
583}
584
Jens Axboe3650a3c2012-03-05 14:09:03 +0100585static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
586 unsigned long max, double mean, double dev)
587{
588 const char *base = "(usec)";
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100589 GtkWidget *hbox, *label, *frame;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100590 char *minp, *maxp;
591 char tmp[64];
592
593 if (!usec_to_msec(&min, &max, &mean, &dev))
594 base = "(msec)";
595
596 minp = num2str(min, 6, 1, 0);
597 maxp = num2str(max, 6, 1, 0);
598
Jens Axboe3650a3c2012-03-05 14:09:03 +0100599 sprintf(tmp, "%s %s", name, base);
600 frame = gtk_frame_new(tmp);
601 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
602
Jens Axboe3650a3c2012-03-05 14:09:03 +0100603 hbox = gtk_hbox_new(FALSE, 3);
Jens Axboe1c1e4a52012-03-05 14:37:38 +0100604 gtk_container_add(GTK_CONTAINER(frame), hbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100605
606 label = new_info_label_in_frame(hbox, "Minimum");
607 gtk_label_set_text(GTK_LABEL(label), minp);
608 label = new_info_label_in_frame(hbox, "Maximum");
609 gtk_label_set_text(GTK_LABEL(label), maxp);
610 label = new_info_label_in_frame(hbox, "Average");
611 sprintf(tmp, "%5.02f", mean);
612 gtk_label_set_text(GTK_LABEL(label), tmp);
613 label = new_info_label_in_frame(hbox, "Standard deviation");
614 sprintf(tmp, "%5.02f", dev);
615 gtk_label_set_text(GTK_LABEL(label), tmp);
616
617 free(minp);
618 free(maxp);
619
620}
621
Jens Axboeca850992012-03-05 20:04:43 +0100622#define GFIO_CLAT 1
623#define GFIO_SLAT 2
624#define GFIO_LAT 4
625
Jens Axboe3650a3c2012-03-05 14:09:03 +0100626static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
627 struct thread_stat *ts, int ddir)
628{
629 const char *ddir_label[2] = { "Read", "Write" };
Jens Axboe0b761302012-03-05 20:44:11 +0100630 GtkWidget *frame, *label, *box, *vbox, *main_vbox;
Jens Axboee0681f32012-03-06 12:14:42 +0100631 unsigned long min[3], max[3], runt;
Jens Axboe3650a3c2012-03-05 14:09:03 +0100632 unsigned long long bw, iops;
Jens Axboeca850992012-03-05 20:04:43 +0100633 unsigned int flags = 0;
Jens Axboee0681f32012-03-06 12:14:42 +0100634 double mean[3], dev[3];
Jens Axboe3650a3c2012-03-05 14:09:03 +0100635 char *io_p, *bw_p, *iops_p;
636 int i2p;
637
638 if (!ts->runtime[ddir])
639 return;
640
641 i2p = is_power_of_2(rs->kb_base);
642 runt = ts->runtime[ddir];
643
644 bw = (1000 * ts->io_bytes[ddir]) / runt;
645 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
646 bw_p = num2str(bw, 6, 1, i2p);
647
648 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
649 iops_p = num2str(iops, 6, 1, 0);
650
651 box = gtk_hbox_new(FALSE, 3);
652 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
653
654 frame = gtk_frame_new(ddir_label[ddir]);
655 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
656
Jens Axboe0b761302012-03-05 20:44:11 +0100657 main_vbox = gtk_vbox_new(FALSE, 3);
658 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100659
660 box = gtk_hbox_new(FALSE, 3);
Jens Axboe0b761302012-03-05 20:44:11 +0100661 gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +0100662
663 label = new_info_label_in_frame(box, "IO");
664 gtk_label_set_text(GTK_LABEL(label), io_p);
665 label = new_info_label_in_frame(box, "Bandwidth");
666 gtk_label_set_text(GTK_LABEL(label), bw_p);
667 label = new_info_label_in_frame(box, "IOPS");
668 gtk_label_set_text(GTK_LABEL(label), iops_p);
669 label = new_info_label_in_frame(box, "Runtime (msec)");
670 label_set_int_value(label, ts->runtime[ddir]);
671
Jens Axboee0681f32012-03-06 12:14:42 +0100672 if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
Jens Axboeca850992012-03-05 20:04:43 +0100673 double p_of_agg = 100.0;
674 const char *bw_str = "KB";
675 char tmp[32];
676
677 if (rs->agg[ddir]) {
Jens Axboee0681f32012-03-06 12:14:42 +0100678 p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
Jens Axboeca850992012-03-05 20:04:43 +0100679 if (p_of_agg > 100.0)
680 p_of_agg = 100.0;
681 }
682
Jens Axboee0681f32012-03-06 12:14:42 +0100683 if (mean[0] > 999999.9) {
684 min[0] /= 1000.0;
685 max[0] /= 1000.0;
686 mean[0] /= 1000.0;
687 dev[0] /= 1000.0;
Jens Axboeca850992012-03-05 20:04:43 +0100688 bw_str = "MB";
689 }
690
Jens Axboe0b761302012-03-05 20:44:11 +0100691 sprintf(tmp, "Bandwidth (%s)", bw_str);
692 frame = gtk_frame_new(tmp);
693 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
Jens Axboeca850992012-03-05 20:04:43 +0100694
Jens Axboe0b761302012-03-05 20:44:11 +0100695 box = gtk_hbox_new(FALSE, 3);
696 gtk_container_add(GTK_CONTAINER(frame), box);
Jens Axboeca850992012-03-05 20:04:43 +0100697
Jens Axboe0b761302012-03-05 20:44:11 +0100698 label = new_info_label_in_frame(box, "Minimum");
Jens Axboee0681f32012-03-06 12:14:42 +0100699 label_set_int_value(label, min[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100700 label = new_info_label_in_frame(box, "Maximum");
Jens Axboee0681f32012-03-06 12:14:42 +0100701 label_set_int_value(label, max[0]);
Jens Axboe0b761302012-03-05 20:44:11 +0100702 label = new_info_label_in_frame(box, "Percentage of jobs");
Jens Axboeca850992012-03-05 20:04:43 +0100703 sprintf(tmp, "%3.2f%%", p_of_agg);
704 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100705 label = new_info_label_in_frame(box, "Average");
Jens Axboee0681f32012-03-06 12:14:42 +0100706 sprintf(tmp, "%5.02f", mean[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100707 gtk_label_set_text(GTK_LABEL(label), tmp);
Jens Axboe0b761302012-03-05 20:44:11 +0100708 label = new_info_label_in_frame(box, "Standard deviation");
Jens Axboee0681f32012-03-06 12:14:42 +0100709 sprintf(tmp, "%5.02f", dev[0]);
Jens Axboeca850992012-03-05 20:04:43 +0100710 gtk_label_set_text(GTK_LABEL(label), tmp);
711 }
712
Jens Axboee0681f32012-03-06 12:14:42 +0100713 if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
Jens Axboe2b089892012-03-06 08:09:17 +0100714 flags |= GFIO_SLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100715 if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
Jens Axboe2b089892012-03-06 08:09:17 +0100716 flags |= GFIO_CLAT;
Jens Axboee0681f32012-03-06 12:14:42 +0100717 if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
Jens Axboe2b089892012-03-06 08:09:17 +0100718 flags |= GFIO_LAT;
719
720 if (flags) {
721 frame = gtk_frame_new("Latency");
722 gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
723
724 vbox = gtk_vbox_new(FALSE, 3);
725 gtk_container_add(GTK_CONTAINER(frame), vbox);
726
727 if (flags & GFIO_SLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100728 gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
Jens Axboe2b089892012-03-06 08:09:17 +0100729 if (flags & GFIO_CLAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100730 gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
Jens Axboe2b089892012-03-06 08:09:17 +0100731 if (flags & GFIO_LAT)
Jens Axboee0681f32012-03-06 12:14:42 +0100732 gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
Jens Axboe2b089892012-03-06 08:09:17 +0100733 }
734
735 if (ts->clat_percentiles)
736 gfio_show_clat_percentiles(main_vbox, ts, ddir);
737
738
Jens Axboe3650a3c2012-03-05 14:09:03 +0100739 free(io_p);
740 free(bw_p);
741 free(iops_p);
742}
743
Jens Axboee5bd1342012-03-05 21:38:12 +0100744static GtkWidget *gfio_output_lat_buckets(double *lat, unsigned int num,
745 const char **labels)
746{
747 GtkWidget *tree_view;
748 GtkTreeSelection *selection;
749 GtkListStore *model;
750 GtkTreeIter iter;
751 GType *types;
752 int i, skipped;
753
754 /*
755 * Check if all are empty, in which case don't bother
756 */
757 for (i = 0, skipped = 0; i < num; i++)
758 if (lat[i] <= 0.0)
759 skipped++;
760
761 if (skipped == num)
762 return NULL;
763
764 types = malloc(num * sizeof(GType));
765
766 for (i = 0; i < num; i++)
767 types[i] = G_TYPE_STRING;
768
769 model = gtk_list_store_newv(num, types);
770 free(types);
771 types = NULL;
772
773 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
774 gtk_widget_set_can_focus(tree_view, FALSE);
775
Jens Axboe661f7412012-03-06 13:55:45 +0100776 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
777 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
778
Jens Axboee5bd1342012-03-05 21:38:12 +0100779 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
780 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
781
782 for (i = 0; i < num; i++)
783 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
784
785 gtk_list_store_append(model, &iter);
786
787 for (i = 0; i < num; i++) {
788 char fbuf[32];
789
790 if (lat[i] <= 0.0)
791 sprintf(fbuf, "0.00");
792 else
793 sprintf(fbuf, "%3.2f%%", lat[i]);
794
795 gtk_list_store_set(model, &iter, i, fbuf, -1);
796 }
797
798 return tree_view;
799}
800
801static void gfio_show_latency_buckets(GtkWidget *vbox, struct thread_stat *ts)
802{
803 GtkWidget *box, *frame, *tree_view;
804 double io_u_lat_u[FIO_IO_U_LAT_U_NR];
805 double io_u_lat_m[FIO_IO_U_LAT_M_NR];
806 const char *uranges[] = { "2", "4", "10", "20", "50", "100",
807 "250", "500", "750", "1000", };
808 const char *mranges[] = { "2", "4", "10", "20", "50", "100",
809 "250", "500", "750", "1000", "2000",
810 ">= 2000", };
811
812 stat_calc_lat_u(ts, io_u_lat_u);
813 stat_calc_lat_m(ts, io_u_lat_m);
814
815 tree_view = gfio_output_lat_buckets(io_u_lat_u, FIO_IO_U_LAT_U_NR, uranges);
816 if (tree_view) {
817 frame = gtk_frame_new("Latency buckets (usec)");
818 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
819
820 box = gtk_hbox_new(FALSE, 3);
821 gtk_container_add(GTK_CONTAINER(frame), box);
822 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
823 }
824
825 tree_view = gfio_output_lat_buckets(io_u_lat_m, FIO_IO_U_LAT_M_NR, mranges);
826 if (tree_view) {
827 frame = gtk_frame_new("Latency buckets (msec)");
828 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
829
830 box = gtk_hbox_new(FALSE, 3);
831 gtk_container_add(GTK_CONTAINER(frame), box);
832 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
833 }
834}
835
Jens Axboe2e331012012-03-05 22:07:54 +0100836static void gfio_show_cpu_usage(GtkWidget *vbox, struct thread_stat *ts)
837{
838 GtkWidget *box, *frame, *entry;
839 double usr_cpu, sys_cpu;
840 unsigned long runtime;
841 char tmp[32];
842
843 runtime = ts->total_run_time;
844 if (runtime) {
845 double runt = (double) runtime;
846
847 usr_cpu = (double) ts->usr_time * 100 / runt;
848 sys_cpu = (double) ts->sys_time * 100 / runt;
849 } else {
850 usr_cpu = 0;
851 sys_cpu = 0;
852 }
853
854 frame = gtk_frame_new("OS resources");
855 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
856
857 box = gtk_hbox_new(FALSE, 3);
858 gtk_container_add(GTK_CONTAINER(frame), box);
859
860 entry = new_info_entry_in_frame(box, "User CPU");
861 sprintf(tmp, "%3.2f%%", usr_cpu);
862 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
863 entry = new_info_entry_in_frame(box, "System CPU");
864 sprintf(tmp, "%3.2f%%", sys_cpu);
865 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
866 entry = new_info_entry_in_frame(box, "Context switches");
867 entry_set_int_value(entry, ts->ctx);
868 entry = new_info_entry_in_frame(box, "Major faults");
869 entry_set_int_value(entry, ts->majf);
870 entry = new_info_entry_in_frame(box, "Minor faults");
871 entry_set_int_value(entry, ts->minf);
872}
Jens Axboe19998db2012-03-06 09:17:59 +0100873static void gfio_add_sc_depths_tree(GtkListStore *model,
874 struct thread_stat *ts, unsigned int len,
875 int submit)
876{
877 double io_u_dist[FIO_IO_U_MAP_NR];
878 GtkTreeIter iter;
879 /* Bits 0, and 3-8 */
880 const int add_mask = 0x1f9;
881 int i, j;
882
883 if (submit)
884 stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
885 else
886 stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
887
888 gtk_list_store_append(model, &iter);
889
890 gtk_list_store_set(model, &iter, 0, submit ? "Submit" : "Complete", -1);
891
892 for (i = 1, j = 0; i < len; i++) {
893 char fbuf[32];
894
895 if (!(add_mask & (1UL << (i - 1))))
896 sprintf(fbuf, "0.0%%");
897 else {
898 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
899 j++;
900 }
901
902 gtk_list_store_set(model, &iter, i, fbuf, -1);
903 }
904
905}
906
907static void gfio_add_total_depths_tree(GtkListStore *model,
908 struct thread_stat *ts, unsigned int len)
909{
910 double io_u_dist[FIO_IO_U_MAP_NR];
911 GtkTreeIter iter;
912 /* Bits 1-6, and 8 */
913 const int add_mask = 0x17e;
914 int i, j;
915
916 stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
917
918 gtk_list_store_append(model, &iter);
919
920 gtk_list_store_set(model, &iter, 0, "Total", -1);
921
922 for (i = 1, j = 0; i < len; i++) {
923 char fbuf[32];
924
925 if (!(add_mask & (1UL << (i - 1))))
926 sprintf(fbuf, "0.0%%");
927 else {
928 sprintf(fbuf, "%3.1f%%", io_u_dist[j]);
929 j++;
930 }
931
932 gtk_list_store_set(model, &iter, i, fbuf, -1);
933 }
934
935}
Jens Axboe2e331012012-03-05 22:07:54 +0100936
937static void gfio_show_io_depths(GtkWidget *vbox, struct thread_stat *ts)
938{
Jens Axboe2e331012012-03-05 22:07:54 +0100939 GtkWidget *frame, *box, *tree_view;
940 GtkTreeSelection *selection;
941 GtkListStore *model;
Jens Axboe2e331012012-03-05 22:07:54 +0100942 GType types[FIO_IO_U_MAP_NR + 1];
943 int i;
Jens Axboe19998db2012-03-06 09:17:59 +0100944#define NR_LABELS 10
945 const char *labels[NR_LABELS] = { "Depth", "0", "1", "2", "4", "8", "16", "32", "64", ">= 64" };
Jens Axboe2e331012012-03-05 22:07:54 +0100946
947 frame = gtk_frame_new("IO depths");
948 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
949
950 box = gtk_hbox_new(FALSE, 3);
951 gtk_container_add(GTK_CONTAINER(frame), box);
952
Jens Axboe19998db2012-03-06 09:17:59 +0100953 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100954 types[i] = G_TYPE_STRING;
955
Jens Axboe19998db2012-03-06 09:17:59 +0100956 model = gtk_list_store_newv(NR_LABELS, types);
Jens Axboe2e331012012-03-05 22:07:54 +0100957
958 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
959 gtk_widget_set_can_focus(tree_view, FALSE);
960
Jens Axboe661f7412012-03-06 13:55:45 +0100961 g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
962 "enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH, NULL);
963
Jens Axboe2e331012012-03-05 22:07:54 +0100964 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
965 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
966
Jens Axboe19998db2012-03-06 09:17:59 +0100967 for (i = 0; i < NR_LABELS; i++)
Jens Axboe2e331012012-03-05 22:07:54 +0100968 tree_view_column(tree_view, i, labels[i], ALIGN_RIGHT | UNSORTABLE);
969
Jens Axboe19998db2012-03-06 09:17:59 +0100970 gfio_add_total_depths_tree(model, ts, NR_LABELS);
971 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 1);
972 gfio_add_sc_depths_tree(model, ts, NR_LABELS, 0);
Jens Axboe2e331012012-03-05 22:07:54 +0100973
974 gtk_box_pack_start(GTK_BOX(box), tree_view, TRUE, FALSE, 3);
975}
976
Jens Axboef9d40b42012-03-06 09:52:49 +0100977static gboolean results_window_delete(GtkWidget *w, gpointer data)
978{
Jens Axboe2f99deb2012-03-09 14:37:29 +0100979 struct gui_entry *ge = (struct gui_entry *) data;
Jens Axboef9d40b42012-03-06 09:52:49 +0100980
981 gtk_widget_destroy(w);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100982 ge->results_window = NULL;
983 ge->results_notebook = NULL;
Jens Axboef9d40b42012-03-06 09:52:49 +0100984 return TRUE;
985}
986
Jens Axboe2f99deb2012-03-09 14:37:29 +0100987static GtkWidget *get_results_window(struct gui_entry *ge)
Jens Axboef9d40b42012-03-06 09:52:49 +0100988{
989 GtkWidget *win, *notebook;
990
Jens Axboe2f99deb2012-03-09 14:37:29 +0100991 if (ge->results_window)
992 return ge->results_notebook;
Jens Axboef9d40b42012-03-06 09:52:49 +0100993
994 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
995 gtk_window_set_title(GTK_WINDOW(win), "Results");
Jens Axboeb01329d2012-03-07 20:31:28 +0100996 gtk_window_set_default_size(GTK_WINDOW(win), 1024, 768);
Jens Axboe2f99deb2012-03-09 14:37:29 +0100997 g_signal_connect(win, "delete-event", G_CALLBACK(results_window_delete), ge);
998 g_signal_connect(win, "destroy", G_CALLBACK(results_window_delete), ge);
Jens Axboef9d40b42012-03-06 09:52:49 +0100999
1000 notebook = gtk_notebook_new();
Jens Axboe0aa928c2012-03-09 17:24:07 +01001001 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), 1);
1002 gtk_notebook_popup_enable(GTK_NOTEBOOK(notebook));
Jens Axboef9d40b42012-03-06 09:52:49 +01001003 gtk_container_add(GTK_CONTAINER(win), notebook);
1004
Jens Axboe2f99deb2012-03-09 14:37:29 +01001005 ge->results_window = win;
1006 ge->results_notebook = notebook;
1007 return ge->results_notebook;
Jens Axboef9d40b42012-03-06 09:52:49 +01001008}
1009
Jens Axboe3650a3c2012-03-05 14:09:03 +01001010static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
1011 struct group_run_stats *rs)
1012{
Jens Axboeb01329d2012-03-07 20:31:28 +01001013 GtkWidget *res_win, *box, *vbox, *entry, *scroll;
Jens Axboee0681f32012-03-06 12:14:42 +01001014 struct gfio_client *gc = client->client_data;
Jens Axboe3650a3c2012-03-05 14:09:03 +01001015
1016 gdk_threads_enter();
1017
Jens Axboe2f99deb2012-03-09 14:37:29 +01001018 res_win = get_results_window(gc->ge);
Jens Axboe3650a3c2012-03-05 14:09:03 +01001019
Jens Axboeb01329d2012-03-07 20:31:28 +01001020 scroll = gtk_scrolled_window_new(NULL, NULL);
1021 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
1022 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1023
Jens Axboe3650a3c2012-03-05 14:09:03 +01001024 vbox = gtk_vbox_new(FALSE, 3);
Jens Axboe3650a3c2012-03-05 14:09:03 +01001025
Jens Axboeb01329d2012-03-07 20:31:28 +01001026 box = gtk_hbox_new(FALSE, 0);
1027 gtk_box_pack_start(GTK_BOX(vbox), box, TRUE, FALSE, 5);
Jens Axboe3650a3c2012-03-05 14:09:03 +01001028
Jens Axboeb01329d2012-03-07 20:31:28 +01001029 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
1030
1031 gtk_notebook_append_page(GTK_NOTEBOOK(res_win), scroll, gtk_label_new(ts->name));
Jens Axboef9d40b42012-03-06 09:52:49 +01001032
Jens Axboee0681f32012-03-06 12:14:42 +01001033 gc->results_widget = vbox;
1034
Jens Axboe3650a3c2012-03-05 14:09:03 +01001035 entry = new_info_entry_in_frame(box, "Name");
1036 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
1037 if (strlen(ts->description)) {
1038 entry = new_info_entry_in_frame(box, "Description");
1039 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
1040 }
1041 entry = new_info_entry_in_frame(box, "Group ID");
1042 entry_set_int_value(entry, ts->groupid);
1043 entry = new_info_entry_in_frame(box, "Jobs");
1044 entry_set_int_value(entry, ts->members);
Jens Axboe6b79c802012-03-08 10:51:36 +01001045 gc->err_entry = entry = new_info_entry_in_frame(box, "Error");
Jens Axboe3650a3c2012-03-05 14:09:03 +01001046 entry_set_int_value(entry, ts->error);
1047 entry = new_info_entry_in_frame(box, "PID");
1048 entry_set_int_value(entry, ts->pid);
1049
1050 if (ts->io_bytes[DDIR_READ])
1051 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
1052 if (ts->io_bytes[DDIR_WRITE])
1053 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
1054
Jens Axboee5bd1342012-03-05 21:38:12 +01001055 gfio_show_latency_buckets(vbox, ts);
Jens Axboe2e331012012-03-05 22:07:54 +01001056 gfio_show_cpu_usage(vbox, ts);
1057 gfio_show_io_depths(vbox, ts);
Jens Axboee5bd1342012-03-05 21:38:12 +01001058
Jens Axboe2f99deb2012-03-09 14:37:29 +01001059 gtk_widget_show_all(gc->ge->results_window);
Jens Axboe3650a3c2012-03-05 14:09:03 +01001060 gdk_threads_leave();
1061}
1062
Jens Axboe084d1c62012-03-03 20:28:07 +01001063static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001064{
Jens Axboe9b260bd2012-03-06 11:02:52 +01001065 struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001066 struct gui *ui = &main_ui;
Jens Axboe9b260bd2012-03-06 11:02:52 +01001067 GtkTreeIter iter;
1068 struct tm *tm;
1069 time_t sec;
1070 char tmp[64], timebuf[80];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001071
Jens Axboe9b260bd2012-03-06 11:02:52 +01001072 sec = p->log_sec;
1073 tm = localtime(&sec);
1074 strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", tm);
1075 sprintf(timebuf, "%s.%03ld", tmp, p->log_usec / 1000);
1076
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001077 gdk_threads_enter();
Jens Axboe9b260bd2012-03-06 11:02:52 +01001078
Jens Axboe2f99deb2012-03-09 14:37:29 +01001079 gtk_list_store_append(ui->log_model, &iter);
1080 gtk_list_store_set(ui->log_model, &iter, 0, timebuf, -1);
1081 gtk_list_store_set(ui->log_model, &iter, 1, client->hostname, -1);
1082 gtk_list_store_set(ui->log_model, &iter, 2, p->level, -1);
1083 gtk_list_store_set(ui->log_model, &iter, 3, p->buf, -1);
Jens Axboe9b260bd2012-03-06 11:02:52 +01001084
Jens Axboe6b79c802012-03-08 10:51:36 +01001085 if (p->level == FIO_LOG_ERR)
Jens Axboe2f99deb2012-03-09 14:37:29 +01001086 view_log(NULL, (gpointer) ui);
Jens Axboe6b79c802012-03-08 10:51:36 +01001087
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01001088 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001089}
1090
1091static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
1092{
Jens Axboee0681f32012-03-06 12:14:42 +01001093 struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
1094 struct gfio_client *gc = client->client_data;
1095 GtkWidget *box, *frame, *entry, *vbox;
Jens Axboe604cfe32012-03-07 19:51:36 +01001096 double util;
1097 char tmp[16];
Jens Axboee0681f32012-03-06 12:14:42 +01001098
Jens Axboe0050e5f2012-03-06 09:23:27 +01001099 gdk_threads_enter();
Jens Axboee0681f32012-03-06 12:14:42 +01001100
Jens Axboe45dcb2e2012-03-07 16:16:50 +01001101 if (!gc->results_widget)
Jens Axboee0681f32012-03-06 12:14:42 +01001102 goto out;
Jens Axboee0681f32012-03-06 12:14:42 +01001103
1104 if (!gc->disk_util_frame) {
1105 gc->disk_util_frame = gtk_frame_new("Disk utilization");
1106 gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
1107 }
1108
1109 vbox = gtk_vbox_new(FALSE, 3);
1110 gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
1111
1112 frame = gtk_frame_new((char *) p->dus.name);
1113 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
1114
1115 box = gtk_vbox_new(FALSE, 3);
1116 gtk_container_add(GTK_CONTAINER(frame), box);
1117
1118 frame = gtk_frame_new("Read");
1119 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1120 vbox = gtk_hbox_new(TRUE, 3);
1121 gtk_container_add(GTK_CONTAINER(frame), vbox);
1122 entry = new_info_entry_in_frame(vbox, "IOs");
1123 entry_set_int_value(entry, p->dus.ios[0]);
1124 entry = new_info_entry_in_frame(vbox, "Merges");
1125 entry_set_int_value(entry, p->dus.merges[0]);
1126 entry = new_info_entry_in_frame(vbox, "Sectors");
1127 entry_set_int_value(entry, p->dus.sectors[0]);
1128 entry = new_info_entry_in_frame(vbox, "Ticks");
1129 entry_set_int_value(entry, p->dus.ticks[0]);
1130
1131 frame = gtk_frame_new("Write");
1132 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1133 vbox = gtk_hbox_new(TRUE, 3);
1134 gtk_container_add(GTK_CONTAINER(frame), vbox);
1135 entry = new_info_entry_in_frame(vbox, "IOs");
1136 entry_set_int_value(entry, p->dus.ios[1]);
1137 entry = new_info_entry_in_frame(vbox, "Merges");
1138 entry_set_int_value(entry, p->dus.merges[1]);
1139 entry = new_info_entry_in_frame(vbox, "Sectors");
1140 entry_set_int_value(entry, p->dus.sectors[1]);
1141 entry = new_info_entry_in_frame(vbox, "Ticks");
1142 entry_set_int_value(entry, p->dus.ticks[1]);
1143
1144 frame = gtk_frame_new("Shared");
1145 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
1146 vbox = gtk_hbox_new(TRUE, 3);
1147 gtk_container_add(GTK_CONTAINER(frame), vbox);
1148 entry = new_info_entry_in_frame(vbox, "IO ticks");
1149 entry_set_int_value(entry, p->dus.io_ticks);
1150 entry = new_info_entry_in_frame(vbox, "Time in queue");
1151 entry_set_int_value(entry, p->dus.time_in_queue);
1152
Jens Axboe604cfe32012-03-07 19:51:36 +01001153 util = 0.0;
1154 if (p->dus.msec)
1155 util = (double) 100 * p->dus.io_ticks / (double) p->dus.msec;
1156 if (util > 100.0)
1157 util = 100.0;
1158
1159 sprintf(tmp, "%3.2f%%", util);
1160 entry = new_info_entry_in_frame(vbox, "Disk utilization");
1161 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
1162
Jens Axboee0681f32012-03-06 12:14:42 +01001163 gtk_widget_show_all(gc->results_widget);
1164out:
Jens Axboe0050e5f2012-03-06 09:23:27 +01001165 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001166}
1167
Jens Axboe3650a3c2012-03-05 14:09:03 +01001168extern int sum_stat_clients;
1169extern struct thread_stat client_ts;
1170extern struct group_run_stats client_gs;
1171
1172static int sum_stat_nr;
1173
Jens Axboe89e5fad2012-03-05 09:21:12 +01001174static void gfio_thread_status_op(struct fio_client *client,
1175 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001176{
Jens Axboe3650a3c2012-03-05 14:09:03 +01001177 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
1178
1179 gfio_display_ts(client, &p->ts, &p->rs);
1180
1181 if (sum_stat_clients == 1)
1182 return;
1183
1184 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
1185 sum_group_stats(&client_gs, &p->rs);
1186
1187 client_ts.members++;
1188 client_ts.groupid = p->ts.groupid;
1189
1190 if (++sum_stat_nr == sum_stat_clients) {
1191 strcpy(client_ts.name, "All clients");
1192 gfio_display_ts(client, &client_ts, &client_gs);
1193 }
Stephen M. Camerona1820202012-02-24 08:17:31 +01001194}
1195
Jens Axboe89e5fad2012-03-05 09:21:12 +01001196static void gfio_group_stats_op(struct fio_client *client,
1197 struct fio_net_cmd *cmd)
Stephen M. Camerona1820202012-02-24 08:17:31 +01001198{
Jens Axboe98ceabd2012-03-09 08:53:28 +01001199 /* We're ignoring group stats for now */
Stephen M. Camerona1820202012-02-24 08:17:31 +01001200}
1201
Jens Axboe2f99deb2012-03-09 14:37:29 +01001202static gint on_config_drawing_area(GtkWidget *w, GdkEventConfigure *event,
1203 gpointer data)
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001204{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001205 struct gfio_graphs *g = data;
1206
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001207 graph_set_size(g->iops_graph, w->allocation.width / 2.0, w->allocation.height);
1208 graph_set_position(g->iops_graph, w->allocation.width / 2.0, 0.0);
1209 graph_set_size(g->bandwidth_graph, w->allocation.width / 2.0, w->allocation.height);
1210 graph_set_position(g->bandwidth_graph, 0, 0);
Stephen M. Cameron3ea48b82012-03-07 19:40:58 +01001211 return TRUE;
1212}
1213
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001214static void draw_graph(struct graph *g, cairo_t *cr)
1215{
1216 line_graph_draw(g, cr);
1217 cairo_stroke(cr);
1218}
1219
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001220static int on_expose_drawing_area(GtkWidget *w, GdkEvent *event, gpointer p)
1221{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001222 struct gfio_graphs *g = p;
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001223 cairo_t *cr;
1224
1225 cr = gdk_cairo_create(w->window);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001226 cairo_set_source_rgb(cr, 0, 0, 0);
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01001227 draw_graph(g->iops_graph, cr);
1228 draw_graph(g->bandwidth_graph, cr);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001229 cairo_destroy(cr);
1230
1231 return FALSE;
1232}
1233
Jens Axboe2f99deb2012-03-09 14:37:29 +01001234/*
1235 * Client specific ETA
1236 */
1237static void gfio_update_client_eta(struct fio_client *client, struct jobs_eta *je)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001238{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001239 struct gfio_client *gc = client->client_data;
1240 struct gui_entry *ge = gc->ge;
Jens Axboe3e47bd22012-02-29 13:45:02 +01001241 static int eta_good;
1242 char eta_str[128];
1243 char output[256];
1244 char tmp[32];
1245 double perc = 0.0;
1246 int i2p = 0;
1247
Jens Axboe0050e5f2012-03-06 09:23:27 +01001248 gdk_threads_enter();
1249
Jens Axboe3e47bd22012-02-29 13:45:02 +01001250 eta_str[0] = '\0';
1251 output[0] = '\0';
1252
1253 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1254 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1255 eta_to_str(eta_str, je->eta_sec);
1256 }
1257
1258 sprintf(tmp, "%u", je->nr_running);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001259 gtk_entry_set_text(GTK_ENTRY(ge->eta.jobs), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001260 sprintf(tmp, "%u", je->files_open);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001261 gtk_entry_set_text(GTK_ENTRY(ge->eta.files), tmp);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001262
1263#if 0
1264 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1265 if (je->m_rate || je->t_rate) {
1266 char *tr, *mr;
1267
1268 mr = num2str(je->m_rate, 4, 0, i2p);
1269 tr = num2str(je->t_rate, 4, 0, i2p);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001270 gtk_entry_set_text(GTK_ENTRY(ge->eta);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001271 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1272 free(tr);
1273 free(mr);
1274 } else if (je->m_iops || je->t_iops)
1275 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
Jens Axboeebbd89c2012-03-02 11:21:13 +01001276
Jens Axboe2f99deb2012-03-09 14:37:29 +01001277 gtk_entry_set_text(GTK_ENTRY(ge->eta.cr_bw), "---");
1278 gtk_entry_set_text(GTK_ENTRY(ge->eta.cr_iops), "---");
1279 gtk_entry_set_text(GTK_ENTRY(ge->eta.cw_bw), "---");
1280 gtk_entry_set_text(GTK_ENTRY(ge->eta.cw_iops), "---");
Jens Axboe3e47bd22012-02-29 13:45:02 +01001281#endif
1282
1283 if (je->eta_sec != INT_MAX && je->nr_running) {
1284 char *iops_str[2];
1285 char *rate_str[2];
1286
1287 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1288 strcpy(output, "-.-% done");
1289 else {
1290 eta_good = 1;
1291 perc *= 100.0;
1292 sprintf(output, "%3.1f%% done", perc);
1293 }
1294
1295 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1296 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1297
1298 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1299 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1300
Jens Axboe2f99deb2012-03-09 14:37:29 +01001301 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), rate_str[0]);
1302 gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), iops_str[0]);
1303 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), rate_str[1]);
1304 gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), iops_str[1]);
Jens Axboe3e47bd22012-02-29 13:45:02 +01001305
Jens Axboe2f99deb2012-03-09 14:37:29 +01001306 graph_add_xy_data(ge->graphs.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1307 graph_add_xy_data(ge->graphs.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1308 graph_add_xy_data(ge->graphs.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1309 graph_add_xy_data(ge->graphs.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
1310
1311 free(rate_str[0]);
1312 free(rate_str[1]);
1313 free(iops_str[0]);
1314 free(iops_str[1]);
1315 }
1316
1317 if (eta_str[0]) {
1318 char *dst = output + strlen(output);
1319
1320 sprintf(dst, " - %s", eta_str);
1321 }
1322
Jens Axboe9988ca72012-03-09 15:14:06 +01001323 gfio_update_thread_status(ge, output, perc);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001324 gdk_threads_leave();
1325}
1326
1327/*
1328 * Update ETA in main window for all clients
1329 */
1330static void gfio_update_all_eta(struct jobs_eta *je)
1331{
1332 struct gui *ui = &main_ui;
1333 static int eta_good;
1334 char eta_str[128];
1335 char output[256];
1336 double perc = 0.0;
1337 int i2p = 0;
1338
1339 gdk_threads_enter();
1340
1341 eta_str[0] = '\0';
1342 output[0] = '\0';
1343
1344 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
1345 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
1346 eta_to_str(eta_str, je->eta_sec);
1347 }
1348
1349#if 0
1350 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
1351 if (je->m_rate || je->t_rate) {
1352 char *tr, *mr;
1353
1354 mr = num2str(je->m_rate, 4, 0, i2p);
1355 tr = num2str(je->t_rate, 4, 0, i2p);
1356 gtk_entry_set_text(GTK_ENTRY(ui->eta);
1357 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
1358 free(tr);
1359 free(mr);
1360 } else if (je->m_iops || je->t_iops)
1361 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
1362
1363 gtk_entry_set_text(GTK_ENTRY(ui->eta.cr_bw), "---");
1364 gtk_entry_set_text(GTK_ENTRY(ui->eta.cr_iops), "---");
1365 gtk_entry_set_text(GTK_ENTRY(ui->eta.cw_bw), "---");
1366 gtk_entry_set_text(GTK_ENTRY(ui->eta.cw_iops), "---");
1367#endif
1368
Jens Axboe3863d1a2012-03-09 17:39:05 +01001369 entry_set_int_value(ui->eta.jobs, je->nr_running);
1370
Jens Axboe2f99deb2012-03-09 14:37:29 +01001371 if (je->eta_sec != INT_MAX && je->nr_running) {
1372 char *iops_str[2];
1373 char *rate_str[2];
1374
1375 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
1376 strcpy(output, "-.-% done");
1377 else {
1378 eta_good = 1;
1379 perc *= 100.0;
1380 sprintf(output, "%3.1f%% done", perc);
1381 }
1382
1383 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
1384 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
1385
1386 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
1387 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
1388
1389 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), rate_str[0]);
1390 gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), iops_str[0]);
1391 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), rate_str[1]);
1392 gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), iops_str[1]);
1393
1394 graph_add_xy_data(ui->graphs.iops_graph, "Read IOPS", je->elapsed_sec, je->iops[0]);
1395 graph_add_xy_data(ui->graphs.iops_graph, "Write IOPS", je->elapsed_sec, je->iops[1]);
1396 graph_add_xy_data(ui->graphs.bandwidth_graph, "Read Bandwidth", je->elapsed_sec, je->rate[0]);
1397 graph_add_xy_data(ui->graphs.bandwidth_graph, "Write Bandwidth", je->elapsed_sec, je->rate[1]);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01001398
Jens Axboe3e47bd22012-02-29 13:45:02 +01001399 free(rate_str[0]);
1400 free(rate_str[1]);
1401 free(iops_str[0]);
1402 free(iops_str[1]);
1403 }
1404
1405 if (eta_str[0]) {
1406 char *dst = output + strlen(output);
1407
1408 sprintf(dst, " - %s", eta_str);
1409 }
1410
Jens Axboe9988ca72012-03-09 15:14:06 +01001411 gfio_update_thread_status_all(output, perc);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001412 gdk_threads_leave();
Jens Axboe3e47bd22012-02-29 13:45:02 +01001413}
1414
Stephen M. Camerona1820202012-02-24 08:17:31 +01001415static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
1416{
Jens Axboe843ad232012-02-29 11:44:53 +01001417 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001418 struct gfio_client *gc = client->client_data;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001419 struct gui_entry *ge = gc->ge;
Jens Axboe843ad232012-02-29 11:44:53 +01001420 const char *os, *arch;
1421 char buf[64];
1422
1423 os = fio_get_os_string(probe->os);
1424 if (!os)
1425 os = "unknown";
1426
1427 arch = fio_get_arch_string(probe->arch);
1428 if (!arch)
1429 os = "unknown";
1430
1431 if (!client->name)
1432 client->name = strdup((char *) probe->hostname);
1433
Jens Axboe0050e5f2012-03-06 09:23:27 +01001434 gdk_threads_enter();
1435
Jens Axboe2f99deb2012-03-09 14:37:29 +01001436 gtk_label_set_text(GTK_LABEL(ge->probe.hostname), (char *) probe->hostname);
1437 gtk_label_set_text(GTK_LABEL(ge->probe.os), os);
1438 gtk_label_set_text(GTK_LABEL(ge->probe.arch), arch);
Jens Axboe843ad232012-02-29 11:44:53 +01001439 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001440 gtk_label_set_text(GTK_LABEL(ge->probe.fio_ver), buf);
Jens Axboe88f6e7a2012-03-06 12:55:29 +01001441
Jens Axboe2f99deb2012-03-09 14:37:29 +01001442 gfio_set_connected(ge, 1);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001443
1444 gdk_threads_leave();
Stephen M. Camerona1820202012-02-24 08:17:31 +01001445}
1446
Jens Axboe9988ca72012-03-09 15:14:06 +01001447static void gfio_update_thread_status(struct gui_entry *ge,
1448 char *status_message, double perc)
1449{
1450 static char message[100];
1451 const char *m = message;
1452
1453 strncpy(message, status_message, sizeof(message) - 1);
1454 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), m);
1455 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), perc / 100.0);
1456 gtk_widget_queue_draw(main_ui.window);
1457}
1458
1459static void gfio_update_thread_status_all(char *status_message, double perc)
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001460{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001461 struct gui *ui = &main_ui;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001462 static char message[100];
1463 const char *m = message;
1464
1465 strncpy(message, status_message, sizeof(message) - 1);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001466 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), m);
1467 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), perc / 100.0);
1468 gtk_widget_queue_draw(ui->window);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01001469}
1470
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001471static void gfio_quit_op(struct fio_client *client)
1472{
Jens Axboee0681f32012-03-06 12:14:42 +01001473 struct gfio_client *gc = client->client_data;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001474
Jens Axboe0050e5f2012-03-06 09:23:27 +01001475 gdk_threads_enter();
Jens Axboe2f99deb2012-03-09 14:37:29 +01001476 gfio_set_connected(gc->ge, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001477 gdk_threads_leave();
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001478}
1479
Jens Axboe807f9972012-03-02 10:25:24 +01001480static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
1481{
1482 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
Jens Axboee0681f32012-03-06 12:14:42 +01001483 struct gfio_client *gc = client->client_data;
Jens Axboedcaeb602012-03-08 19:45:37 +01001484 struct thread_options *o = &gc->o;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001485 struct gui_entry *ge = gc->ge;
Jens Axboe807f9972012-03-02 10:25:24 +01001486 char tmp[8];
Jens Axboe807f9972012-03-02 10:25:24 +01001487
Jens Axboedcaeb602012-03-08 19:45:37 +01001488 convert_thread_options_to_cpu(o, &p->top);
Jens Axboe807f9972012-03-02 10:25:24 +01001489
Jens Axboe0050e5f2012-03-06 09:23:27 +01001490 gdk_threads_enter();
1491
Jens Axboe2f99deb2012-03-09 14:37:29 +01001492 gtk_label_set_text(GTK_LABEL(ge->page_label), (gchar *) o->name);
1493
Jens Axboe3863d1a2012-03-09 17:39:05 +01001494 gtk_combo_box_append_text(GTK_COMBO_BOX(ge->eta.names), (gchar *) o->name);
1495 gtk_combo_box_set_active(GTK_COMBO_BOX(ge->eta.names), 0);
1496
Jens Axboec80b74b2012-03-12 10:23:28 +01001497 multitext_add_entry(&ge->eta.iotype, ddir_str(o->td_ddir));
1498 multitext_add_entry(&ge->eta.ioengine, (const char *) o->ioengine);
Jens Axboe807f9972012-03-02 10:25:24 +01001499
Jens Axboedcaeb602012-03-08 19:45:37 +01001500 sprintf(tmp, "%u", o->iodepth);
Jens Axboec80b74b2012-03-12 10:23:28 +01001501 multitext_add_entry(&ge->eta.iodepth, tmp);
1502
1503 multitext_set_entry(&ge->eta.iotype, 0);
1504 multitext_set_entry(&ge->eta.ioengine, 0);
1505 multitext_set_entry(&ge->eta.iodepth, 0);
Jens Axboe0050e5f2012-03-06 09:23:27 +01001506
Jens Axboedcaeb602012-03-08 19:45:37 +01001507 gc->job_added++;
1508
Jens Axboe0050e5f2012-03-06 09:23:27 +01001509 gdk_threads_leave();
Jens Axboe807f9972012-03-02 10:25:24 +01001510}
1511
Jens Axboeed727a42012-03-02 12:14:40 +01001512static void gfio_client_timed_out(struct fio_client *client)
1513{
Jens Axboee0681f32012-03-06 12:14:42 +01001514 struct gfio_client *gc = client->client_data;
Jens Axboeed727a42012-03-02 12:14:40 +01001515 char buf[256];
1516
1517 gdk_threads_enter();
1518
Jens Axboe2f99deb2012-03-09 14:37:29 +01001519 gfio_set_connected(gc->ge, 0);
1520 clear_ge_ui_info(gc->ge);
Jens Axboeed727a42012-03-02 12:14:40 +01001521
1522 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001523 show_info_dialog(gc->ge->ui, "Network timeout", buf);
Jens Axboeed727a42012-03-02 12:14:40 +01001524
1525 gdk_threads_leave();
1526}
1527
Jens Axboe6b79c802012-03-08 10:51:36 +01001528static void gfio_client_stop(struct fio_client *client, struct fio_net_cmd *cmd)
1529{
1530 struct gfio_client *gc = client->client_data;
1531
1532 gdk_threads_enter();
1533
Jens Axboe2f99deb2012-03-09 14:37:29 +01001534 gfio_set_connected(gc->ge, 0);
Jens Axboe6b79c802012-03-08 10:51:36 +01001535
1536 if (gc->err_entry)
1537 entry_set_int_value(gc->err_entry, client->error);
1538
1539 gdk_threads_leave();
1540}
1541
Stephen M. Camerona1820202012-02-24 08:17:31 +01001542struct client_ops gfio_client_ops = {
Jens Axboe0420ba62012-02-29 11:16:52 +01001543 .text_op = gfio_text_op,
1544 .disk_util = gfio_disk_util_op,
1545 .thread_status = gfio_thread_status_op,
1546 .group_stats = gfio_group_stats_op,
Jens Axboe2f99deb2012-03-09 14:37:29 +01001547 .jobs_eta = gfio_update_client_eta,
1548 .eta = gfio_update_all_eta,
Jens Axboe0420ba62012-02-29 11:16:52 +01001549 .probe = gfio_probe_op,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001550 .quit = gfio_quit_op,
Jens Axboe807f9972012-03-02 10:25:24 +01001551 .add_job = gfio_add_job_op,
Jens Axboeed727a42012-03-02 12:14:40 +01001552 .timed_out = gfio_client_timed_out,
Jens Axboe6b79c802012-03-08 10:51:36 +01001553 .stop = gfio_client_stop,
Jens Axboe6433ee02012-03-09 20:10:51 +01001554 .eta_msec = FIO_CLIENT_DEF_ETA_MSEC,
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001555 .stay_connected = 1,
Stephen M. Camerona1820202012-02-24 08:17:31 +01001556};
1557
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01001558static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
1559 __attribute__((unused)) gpointer data)
1560{
1561 gtk_main_quit();
1562}
1563
Stephen M. Cameron25927252012-02-24 08:17:31 +01001564static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001565{
Jens Axboea9eccde2012-03-09 14:59:42 +01001566 struct gui *ui = arg;
1567
1568 ui->handler_running = 1;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001569 fio_handle_clients(&gfio_client_ops);
Jens Axboea9eccde2012-03-09 14:59:42 +01001570 ui->handler_running = 0;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001571 return NULL;
1572}
1573
Jens Axboe2f99deb2012-03-09 14:37:29 +01001574static int send_job_files(struct gui_entry *ge)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001575{
Jens Axboe9988ca72012-03-09 15:14:06 +01001576 struct gfio_client *gc = ge->client;
Jens Axboe441013b2012-03-01 08:01:52 +01001577 int i, ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001578
Jens Axboe2f99deb2012-03-09 14:37:29 +01001579 for (i = 0; i < ge->nr_job_files; i++) {
Jens Axboe9988ca72012-03-09 15:14:06 +01001580 ret = fio_client_send_ini(gc->client, ge->job_files[i]);
Jens Axboec7249262012-03-09 17:11:04 +01001581 if (ret < 0) {
1582 GError *error;
1583
1584 error = g_error_new(g_quark_from_string("fio"), 1, "Failed to send file %s: %s\n", ge->job_files[i], strerror(-ret));
1585 report_error(error);
1586 g_error_free(error);
1587 break;
1588 } else if (ret)
Jens Axboe441013b2012-03-01 08:01:52 +01001589 break;
1590
Jens Axboe2f99deb2012-03-09 14:37:29 +01001591 free(ge->job_files[i]);
1592 ge->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001593 }
Jens Axboe2f99deb2012-03-09 14:37:29 +01001594 while (i < ge->nr_job_files) {
1595 free(ge->job_files[i]);
1596 ge->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +01001597 i++;
Jens Axboe0420ba62012-02-29 11:16:52 +01001598 }
1599
Jens Axboe441013b2012-03-01 08:01:52 +01001600 return ret;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +01001601}
1602
Jens Axboe63a130b2012-03-06 20:08:59 +01001603static void *server_thread(void *arg)
1604{
1605 is_backend = 1;
1606 gfio_server_running = 1;
1607 fio_start_server(NULL);
1608 gfio_server_running = 0;
1609 return NULL;
1610}
1611
Jens Axboe2f99deb2012-03-09 14:37:29 +01001612static void gfio_start_server(void)
Jens Axboe63a130b2012-03-06 20:08:59 +01001613{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001614 struct gui *ui = &main_ui;
1615
Jens Axboe63a130b2012-03-06 20:08:59 +01001616 if (!gfio_server_running) {
1617 gfio_server_running = 1;
1618 pthread_create(&ui->server_t, NULL, server_thread, NULL);
Jens Axboee34f6ad2012-03-06 20:47:15 +01001619 pthread_detach(ui->server_t);
Jens Axboe63a130b2012-03-06 20:08:59 +01001620 }
1621}
1622
Stephen M. Cameron25927252012-02-24 08:17:31 +01001623static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
1624 gpointer data)
1625{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001626 struct gui_entry *ge = data;
1627 struct gfio_client *gc = ge->client;
Stephen M. Cameron25927252012-02-24 08:17:31 +01001628
Jens Axboe2f99deb2012-03-09 14:37:29 +01001629 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 0);
1630 fio_start_client(gc->client);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001631}
1632
Jens Axboedf06f222012-03-02 13:32:04 +01001633static void file_open(GtkWidget *w, gpointer data);
1634
1635static void connect_clicked(GtkWidget *widget, gpointer data)
Jens Axboe3e47bd22012-02-29 13:45:02 +01001636{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001637 struct gui_entry *ge = data;
1638 struct gfio_client *gc = ge->client;
Jens Axboe3ec62ec2012-03-01 12:01:29 +01001639
Jens Axboe2f99deb2012-03-09 14:37:29 +01001640 if (!ge->connected) {
Jens Axboec7249262012-03-09 17:11:04 +01001641 int ret;
1642
Jens Axboe2f99deb2012-03-09 14:37:29 +01001643 if (!ge->nr_job_files)
Jens Axboedf06f222012-03-02 13:32:04 +01001644 file_open(widget, data);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001645 if (!ge->nr_job_files)
1646 return;
1647
1648 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No jobs running");
1649 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
Jens Axboec7249262012-03-09 17:11:04 +01001650 ret = fio_client_connect(gc->client);
1651 if (!ret) {
Jens Axboea9eccde2012-03-09 14:59:42 +01001652 if (!ge->ui->handler_running)
1653 pthread_create(&ge->ui->t, NULL, job_thread, ge->ui);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001654 gtk_widget_set_sensitive(ge->button[CONNECT_BUTTON], 0);
1655 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 1);
Jens Axboec7249262012-03-09 17:11:04 +01001656 } else {
1657 GError *error;
1658
1659 error = g_error_new(g_quark_from_string("fio"), 1, "Failed to connect to %s: %s\n", ge->client->client->hostname, strerror(-ret));
1660 report_error(error);
1661 g_error_free(error);
Jens Axboe69406b92012-03-06 14:00:42 +01001662 }
Jens Axboedf06f222012-03-02 13:32:04 +01001663 } else {
Jens Axboe2f99deb2012-03-09 14:37:29 +01001664 fio_client_terminate(gc->client);
1665 gfio_set_connected(ge, 0);
1666 clear_ge_ui_info(ge);
Jens Axboedf06f222012-03-02 13:32:04 +01001667 }
Jens Axboe3e47bd22012-02-29 13:45:02 +01001668}
1669
Jens Axboeb9d2f302012-03-08 20:36:28 +01001670static void send_clicked(GtkWidget *widget, gpointer data)
1671{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001672 struct gui_entry *ge = data;
Jens Axboeb9d2f302012-03-08 20:36:28 +01001673
Jens Axboe2f99deb2012-03-09 14:37:29 +01001674 if (send_job_files(ge)) {
Jens Axboec7249262012-03-09 17:11:04 +01001675 GError *error;
1676
1677 error = g_error_new(g_quark_from_string("fio"), 1, "Failed to send one or more job files for client %s", ge->client->client->hostname);
1678 report_error(error);
1679 g_error_free(error);
1680
Jens Axboe2f99deb2012-03-09 14:37:29 +01001681 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 1);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001682 }
1683
Jens Axboe2f99deb2012-03-09 14:37:29 +01001684 gtk_widget_set_sensitive(ge->button[SEND_BUTTON], 0);
1685 gtk_widget_set_sensitive(ge->button[START_JOB_BUTTON], 1);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001686}
1687
Jens Axboe2f99deb2012-03-09 14:37:29 +01001688static GtkWidget *add_button(GtkWidget *buttonbox,
1689 struct button_spec *buttonspec, gpointer data)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001690{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001691 GtkWidget *button = gtk_button_new_with_label(buttonspec->buttontext);
1692
1693 g_signal_connect(button, "clicked", G_CALLBACK(buttonspec->f), data);
1694 gtk_box_pack_start(GTK_BOX(buttonbox), button, FALSE, FALSE, 3);
1695 gtk_widget_set_tooltip_text(button, buttonspec->tooltiptext);
1696 gtk_widget_set_sensitive(button, !buttonspec->start_insensitive);
1697
1698 return button;
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001699}
1700
Jens Axboe2f99deb2012-03-09 14:37:29 +01001701static void add_buttons(struct gui_entry *ge, struct button_spec *buttonlist,
1702 int nbuttons)
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001703{
1704 int i;
1705
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001706 for (i = 0; i < nbuttons; i++)
Jens Axboe2f99deb2012-03-09 14:37:29 +01001707 ge->button[i] = add_button(ge->buttonbox, &buttonlist[i], ge);
Stephen M. Cameronf3074002012-02-24 08:17:30 +01001708}
1709
Jens Axboe0420ba62012-02-29 11:16:52 +01001710static void on_info_bar_response(GtkWidget *widget, gint response,
1711 gpointer data)
1712{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001713 struct gui *ui = &main_ui;
1714
Jens Axboe0420ba62012-02-29 11:16:52 +01001715 if (response == GTK_RESPONSE_OK) {
1716 gtk_widget_destroy(widget);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001717 ui->error_info_bar = NULL;
Jens Axboe0420ba62012-02-29 11:16:52 +01001718 }
1719}
1720
Jens Axboedf06f222012-03-02 13:32:04 +01001721void report_error(GError *error)
Jens Axboe0420ba62012-02-29 11:16:52 +01001722{
Jens Axboe2f99deb2012-03-09 14:37:29 +01001723 struct gui *ui = &main_ui;
1724
1725 if (ui->error_info_bar == NULL) {
1726 ui->error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
Jens Axboe0420ba62012-02-29 11:16:52 +01001727 GTK_RESPONSE_OK,
1728 NULL);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001729 g_signal_connect(ui->error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
1730 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui->error_info_bar),
Jens Axboe0420ba62012-02-29 11:16:52 +01001731 GTK_MESSAGE_ERROR);
1732
Jens Axboe2f99deb2012-03-09 14:37:29 +01001733 ui->error_label = gtk_label_new(error->message);
1734 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui->error_info_bar));
1735 gtk_container_add(GTK_CONTAINER(container), ui->error_label);
Jens Axboe0420ba62012-02-29 11:16:52 +01001736
Jens Axboe2f99deb2012-03-09 14:37:29 +01001737 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->error_info_bar, FALSE, FALSE, 0);
1738 gtk_widget_show_all(ui->vbox);
Jens Axboe0420ba62012-02-29 11:16:52 +01001739 } else {
1740 char buffer[256];
1741 snprintf(buffer, sizeof(buffer), "Failed to open file.");
Jens Axboe2f99deb2012-03-09 14:37:29 +01001742 gtk_label_set(GTK_LABEL(ui->error_label), buffer);
Jens Axboe0420ba62012-02-29 11:16:52 +01001743 }
1744}
1745
Jens Axboe62bc9372012-03-07 11:45:07 +01001746struct connection_widgets
1747{
1748 GtkWidget *hentry;
1749 GtkWidget *combo;
1750 GtkWidget *button;
1751};
1752
1753static void hostname_cb(GtkEntry *entry, gpointer data)
1754{
1755 struct connection_widgets *cw = data;
1756 int uses_net = 0, is_localhost = 0;
1757 const gchar *text;
1758 gchar *ctext;
1759
1760 /*
1761 * Check whether to display the 'auto start backend' box
1762 * or not. Show it if we are a localhost and using network,
1763 * or using a socket.
1764 */
1765 ctext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->combo));
1766 if (!ctext || !strncmp(ctext, "IPv4", 4) || !strncmp(ctext, "IPv6", 4))
1767 uses_net = 1;
1768 g_free(ctext);
1769
1770 if (uses_net) {
1771 text = gtk_entry_get_text(GTK_ENTRY(cw->hentry));
1772 if (!strcmp(text, "127.0.0.1") || !strcmp(text, "localhost") ||
1773 !strcmp(text, "::1") || !strcmp(text, "ip6-localhost") ||
1774 !strcmp(text, "ip6-loopback"))
1775 is_localhost = 1;
1776 }
1777
1778 if (!uses_net || is_localhost) {
1779 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 1);
1780 gtk_widget_set_sensitive(cw->button, 1);
1781 } else {
1782 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw->button), 0);
1783 gtk_widget_set_sensitive(cw->button, 0);
1784 }
1785}
1786
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001787static int get_connection_details(char **host, int *port, int *type,
1788 int *server_start)
Jens Axboea7a42ce2012-03-02 13:12:04 +01001789{
Jens Axboe62bc9372012-03-07 11:45:07 +01001790 GtkWidget *dialog, *box, *vbox, *hbox, *frame, *pentry;
1791 struct connection_widgets cw;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001792 char *typeentry;
1793
1794 dialog = gtk_dialog_new_with_buttons("Connection details",
Jens Axboe2f99deb2012-03-09 14:37:29 +01001795 GTK_WINDOW(main_ui.window),
Jens Axboea7a42ce2012-03-02 13:12:04 +01001796 GTK_DIALOG_DESTROY_WITH_PARENT,
1797 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1798 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1799
1800 frame = gtk_frame_new("Hostname / socket name");
Jens Axboef1299092012-03-07 20:00:02 +01001801 /* gtk_dialog_get_content_area() is 2.14 and newer */
1802 vbox = GTK_DIALOG(dialog)->vbox;
Jens Axboea7a42ce2012-03-02 13:12:04 +01001803 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1804
1805 box = gtk_vbox_new(FALSE, 6);
1806 gtk_container_add(GTK_CONTAINER(frame), box);
1807
1808 hbox = gtk_hbox_new(TRUE, 10);
1809 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
Jens Axboe62bc9372012-03-07 11:45:07 +01001810 cw.hentry = gtk_entry_new();
1811 gtk_entry_set_text(GTK_ENTRY(cw.hentry), "localhost");
1812 gtk_box_pack_start(GTK_BOX(hbox), cw.hentry, TRUE, TRUE, 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001813
1814 frame = gtk_frame_new("Port");
1815 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1816 box = gtk_vbox_new(FALSE, 10);
1817 gtk_container_add(GTK_CONTAINER(frame), box);
1818
1819 hbox = gtk_hbox_new(TRUE, 4);
1820 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1821 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
1822
1823 frame = gtk_frame_new("Type");
1824 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1825 box = gtk_vbox_new(FALSE, 10);
1826 gtk_container_add(GTK_CONTAINER(frame), box);
1827
1828 hbox = gtk_hbox_new(TRUE, 4);
1829 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1830
Jens Axboe62bc9372012-03-07 11:45:07 +01001831 cw.combo = gtk_combo_box_new_text();
1832 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv4");
1833 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "IPv6");
1834 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.combo), "local socket");
1835 gtk_combo_box_set_active(GTK_COMBO_BOX(cw.combo), 0);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001836
Jens Axboe62bc9372012-03-07 11:45:07 +01001837 gtk_container_add(GTK_CONTAINER(hbox), cw.combo);
Jens Axboea7a42ce2012-03-02 13:12:04 +01001838
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001839 frame = gtk_frame_new("Options");
1840 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
1841 box = gtk_vbox_new(FALSE, 10);
1842 gtk_container_add(GTK_CONTAINER(frame), box);
1843
1844 hbox = gtk_hbox_new(TRUE, 4);
1845 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1846
Jens Axboe62bc9372012-03-07 11:45:07 +01001847 cw.button = gtk_check_button_new_with_label("Auto-spawn fio backend");
1848 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.button), 1);
1849 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.");
1850 gtk_box_pack_start(GTK_BOX(hbox), cw.button, FALSE, FALSE, 6);
1851
1852 /*
1853 * Connect edit signal, so we can show/not-show the auto start button
1854 */
1855 g_signal_connect(GTK_OBJECT(cw.hentry), "changed", G_CALLBACK(hostname_cb), &cw);
1856 g_signal_connect(GTK_OBJECT(cw.combo), "changed", G_CALLBACK(hostname_cb), &cw);
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001857
Jens Axboea7a42ce2012-03-02 13:12:04 +01001858 gtk_widget_show_all(dialog);
1859
1860 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
1861 gtk_widget_destroy(dialog);
1862 return 1;
1863 }
1864
Jens Axboe62bc9372012-03-07 11:45:07 +01001865 *host = strdup(gtk_entry_get_text(GTK_ENTRY(cw.hentry)));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001866 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
1867
Jens Axboe62bc9372012-03-07 11:45:07 +01001868 typeentry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw.combo));
Jens Axboea7a42ce2012-03-02 13:12:04 +01001869 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
1870 *type = Fio_client_ipv4;
1871 else if (!strncmp(typeentry, "IPv6", 4))
1872 *type = Fio_client_ipv6;
1873 else
1874 *type = Fio_client_socket;
1875 g_free(typeentry);
1876
Jens Axboe62bc9372012-03-07 11:45:07 +01001877 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.button));
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01001878
Jens Axboea7a42ce2012-03-02 13:12:04 +01001879 gtk_widget_destroy(dialog);
1880 return 0;
1881}
1882
Jens Axboe2f99deb2012-03-09 14:37:29 +01001883static void gfio_client_added(struct gui_entry *ge, struct fio_client *client)
Jens Axboee0681f32012-03-06 12:14:42 +01001884{
1885 struct gfio_client *gc;
1886
1887 gc = malloc(sizeof(*gc));
1888 memset(gc, 0, sizeof(*gc));
Jens Axboe2f99deb2012-03-09 14:37:29 +01001889 gc->ge = ge;
Jens Axboe343cb4a2012-03-09 17:16:51 +01001890 gc->client = fio_get_client(client);
Jens Axboeb9d2f302012-03-08 20:36:28 +01001891
Jens Axboe2f99deb2012-03-09 14:37:29 +01001892 ge->client = gc;
Jens Axboee0681f32012-03-06 12:14:42 +01001893
1894 client->client_data = gc;
1895}
1896
Jens Axboe2f99deb2012-03-09 14:37:29 +01001897static GtkWidget *new_client_page(struct gui_entry *ge);
1898
1899static struct gui_entry *alloc_new_gui_entry(struct gui *ui)
1900{
1901 struct gui_entry *ge;
1902
1903 ge = malloc(sizeof(*ge));
1904 memset(ge, 0, sizeof(*ge));
1905 INIT_FLIST_HEAD(&ge->list);
1906 flist_add_tail(&ge->list, &ui->list);
1907 ge->ui = ui;
1908 return ge;
1909}
1910
1911/*
1912 * FIXME: need more handling here
1913 */
1914static void ge_destroy(GtkWidget *w, gpointer data)
1915{
1916 struct gui_entry *ge = data;
Jens Axboe343cb4a2012-03-09 17:16:51 +01001917 struct gfio_client *gc = ge->client;
1918
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001919 if (gc && gc->client) {
1920 if (ge->connected)
1921 fio_client_terminate(gc->client);
1922
Jens Axboe343cb4a2012-03-09 17:16:51 +01001923 fio_put_client(gc->client);
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001924 }
Jens Axboe2f99deb2012-03-09 14:37:29 +01001925
1926 flist_del(&ge->list);
1927 free(ge);
1928}
1929
1930static struct gui_entry *get_new_ge_with_tab(const char *name)
1931{
1932 struct gui_entry *ge;
1933
1934 ge = alloc_new_gui_entry(&main_ui);
1935
1936 ge->vbox = new_client_page(ge);
1937 g_signal_connect(ge->vbox, "destroy", G_CALLBACK(ge_destroy), ge);
1938
1939 ge->page_label = gtk_label_new(name);
1940 ge->page_num = gtk_notebook_append_page(GTK_NOTEBOOK(main_ui.notebook), ge->vbox, ge->page_label);
1941
1942 gtk_widget_show_all(main_ui.window);
1943 return ge;
1944}
1945
1946static void file_new(GtkWidget *w, gpointer data)
1947{
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001948 struct gui *ui = (struct gui *) data;
1949 struct gui_entry *ge;
1950
1951 ge = get_new_ge_with_tab("Untitled");
1952 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
Jens Axboe2f99deb2012-03-09 14:37:29 +01001953}
1954
1955/*
1956 * Return the 'ge' corresponding to the tab. If the active tab is the
1957 * main tab, open a new tab.
1958 */
1959static struct gui_entry *get_ge_from_page(unsigned int cur_page)
1960{
1961 struct flist_head *entry;
1962 struct gui_entry *ge;
1963
1964 if (!cur_page)
1965 return get_new_ge_with_tab("Untitled");
1966
1967 flist_for_each(entry, &main_ui.list) {
1968 ge = flist_entry(entry, struct gui_entry, list);
1969 if (ge->page_num == cur_page)
1970 return ge;
1971 }
1972
1973 return NULL;
1974}
1975
Jens Axboe16ce5ad2012-03-12 11:56:09 +01001976static void file_close(GtkWidget *w, gpointer data)
1977{
1978 struct gui *ui = (struct gui *) data;
1979 gint cur_page;
1980
1981 /*
1982 * Can't close the main tab
1983 */
1984 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
1985 if (cur_page) {
1986 struct gui_entry *ge = get_ge_from_page(cur_page);
1987
1988 gtk_widget_destroy(ge->vbox);
1989 return;
1990 }
1991
1992 show_info_dialog(ui, "Error", "The main page view cannot be closed\n");
1993}
1994
Jens Axboe0420ba62012-02-29 11:16:52 +01001995static void file_open(GtkWidget *w, gpointer data)
1996{
Jens Axboe63a130b2012-03-06 20:08:59 +01001997 struct gui *ui = data;
Jens Axboe2f99deb2012-03-09 14:37:29 +01001998 GtkWidget *dialog;
Jens Axboe0420ba62012-02-29 11:16:52 +01001999 GSList *filenames, *fn_glist;
2000 GtkFileFilter *filter;
Jens Axboea7a42ce2012-03-02 13:12:04 +01002001 char *host;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01002002 int port, type, server_start;
Jens Axboe2f99deb2012-03-09 14:37:29 +01002003 struct gui_entry *ge;
2004 gint cur_page;
2005
2006 /*
2007 * Creates new tab if current tab is the main window, or the
2008 * current tab already has a client.
2009 */
2010 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(ui->notebook));
2011 ge = get_ge_from_page(cur_page);
2012 if (ge->client)
2013 ge = get_new_ge_with_tab("Untitled");
2014
2015 gtk_notebook_set_current_page(GTK_NOTEBOOK(ui->notebook), ge->page_num);
Jens Axboe0420ba62012-02-29 11:16:52 +01002016
2017 dialog = gtk_file_chooser_dialog_new("Open File",
Jens Axboe63a130b2012-03-06 20:08:59 +01002018 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01002019 GTK_FILE_CHOOSER_ACTION_OPEN,
2020 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2021 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
2022 NULL);
2023 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
2024
2025 filter = gtk_file_filter_new();
2026 gtk_file_filter_add_pattern(filter, "*.fio");
2027 gtk_file_filter_add_pattern(filter, "*.job");
Jens Axboe2d262992012-03-07 08:19:30 +01002028 gtk_file_filter_add_pattern(filter, "*.ini");
Jens Axboe0420ba62012-02-29 11:16:52 +01002029 gtk_file_filter_add_mime_type(filter, "text/fio");
2030 gtk_file_filter_set_name(filter, "Fio job file");
2031 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
2032
2033 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
2034 gtk_widget_destroy(dialog);
2035 return;
2036 }
2037
2038 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Jens Axboea7a42ce2012-03-02 13:12:04 +01002039
2040 gtk_widget_destroy(dialog);
2041
Jens Axboeb9f3c7e2012-03-02 14:27:17 +01002042 if (get_connection_details(&host, &port, &type, &server_start))
Jens Axboea7a42ce2012-03-02 13:12:04 +01002043 goto err;
2044
Jens Axboe0420ba62012-02-29 11:16:52 +01002045 filenames = fn_glist;
2046 while (filenames != NULL) {
Jens Axboee0681f32012-03-06 12:14:42 +01002047 struct fio_client *client;
2048
Jens Axboe2f99deb2012-03-09 14:37:29 +01002049 ge->job_files = realloc(ge->job_files, (ge->nr_job_files + 1) * sizeof(char *));
2050 ge->job_files[ge->nr_job_files] = strdup(filenames->data);
2051 ge->nr_job_files++;
Jens Axboe0420ba62012-02-29 11:16:52 +01002052
Jens Axboee0681f32012-03-06 12:14:42 +01002053 client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
2054 if (!client) {
Jens Axboedf06f222012-03-02 13:32:04 +01002055 GError *error;
2056
2057 error = g_error_new(g_quark_from_string("fio"), 1,
2058 "Failed to add client %s", host);
Jens Axboe0420ba62012-02-29 11:16:52 +01002059 report_error(error);
2060 g_error_free(error);
Jens Axboe0420ba62012-02-29 11:16:52 +01002061 }
Jens Axboe2f99deb2012-03-09 14:37:29 +01002062 gfio_client_added(ge, client);
Jens Axboe0420ba62012-02-29 11:16:52 +01002063
2064 g_free(filenames->data);
2065 filenames = g_slist_next(filenames);
2066 }
Jens Axboea7a42ce2012-03-02 13:12:04 +01002067 free(host);
Jens Axboe63a130b2012-03-06 20:08:59 +01002068
2069 if (server_start)
Jens Axboe2f99deb2012-03-09 14:37:29 +01002070 gfio_start_server();
Jens Axboea7a42ce2012-03-02 13:12:04 +01002071err:
Jens Axboe0420ba62012-02-29 11:16:52 +01002072 g_slist_free(fn_glist);
Jens Axboe0420ba62012-02-29 11:16:52 +01002073}
2074
2075static void file_save(GtkWidget *w, gpointer data)
2076{
Jens Axboe63a130b2012-03-06 20:08:59 +01002077 struct gui *ui = data;
Jens Axboe0420ba62012-02-29 11:16:52 +01002078 GtkWidget *dialog;
2079
2080 dialog = gtk_file_chooser_dialog_new("Save File",
Jens Axboe63a130b2012-03-06 20:08:59 +01002081 GTK_WINDOW(ui->window),
Jens Axboe0420ba62012-02-29 11:16:52 +01002082 GTK_FILE_CHOOSER_ACTION_SAVE,
2083 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2084 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
2085 NULL);
2086
2087 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
2088 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
2089
2090 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
2091 char *filename;
2092
2093 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
2094 // save_job_file(filename);
2095 g_free(filename);
2096 }
2097 gtk_widget_destroy(dialog);
2098}
2099
Jens Axboe9b260bd2012-03-06 11:02:52 +01002100static void view_log_destroy(GtkWidget *w, gpointer data)
2101{
2102 struct gui *ui = (struct gui *) data;
2103
2104 gtk_widget_ref(ui->log_tree);
2105 gtk_container_remove(GTK_CONTAINER(w), ui->log_tree);
2106 gtk_widget_destroy(w);
Jens Axboe4cbe7212012-03-06 13:36:17 +01002107 ui->log_view = NULL;
Jens Axboe9b260bd2012-03-06 11:02:52 +01002108}
2109
2110static void view_log(GtkWidget *w, gpointer data)
2111{
Jens Axboe4cbe7212012-03-06 13:36:17 +01002112 GtkWidget *win, *scroll, *vbox, *box;
2113 struct gui *ui = (struct gui *) data;
Jens Axboe9b260bd2012-03-06 11:02:52 +01002114
Jens Axboe4cbe7212012-03-06 13:36:17 +01002115 if (ui->log_view)
2116 return;
2117
2118 ui->log_view = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002119 gtk_window_set_title(GTK_WINDOW(win), "Log");
Jens Axboe4cbe7212012-03-06 13:36:17 +01002120 gtk_window_set_default_size(GTK_WINDOW(win), 700, 500);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002121
Jens Axboe4cbe7212012-03-06 13:36:17 +01002122 scroll = gtk_scrolled_window_new(NULL, NULL);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002123
Jens Axboe4cbe7212012-03-06 13:36:17 +01002124 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
2125
2126 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2127
2128 box = gtk_hbox_new(TRUE, 0);
2129 gtk_box_pack_start_defaults(GTK_BOX(box), ui->log_tree);
2130 g_signal_connect(box, "destroy", G_CALLBACK(view_log_destroy), ui);
2131 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), box);
2132
2133 vbox = gtk_vbox_new(TRUE, 5);
2134 gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
2135
2136 gtk_container_add(GTK_CONTAINER(win), vbox);
Jens Axboe9b260bd2012-03-06 11:02:52 +01002137 gtk_widget_show_all(win);
2138}
2139
Jens Axboe16ce5ad2012-03-12 11:56:09 +01002140static void edit_options(GtkWidget *w, gpointer data)
2141{
2142}
2143
Jens Axboe8577f4f2012-03-09 19:28:27 +01002144static void __update_graph_limits(struct gfio_graphs *g)
2145{
2146 line_graph_set_data_count_limit(g->iops_graph, gfio_graph_limit);
2147 line_graph_set_data_count_limit(g->bandwidth_graph, gfio_graph_limit);
2148}
2149
2150static void update_graph_limits(void)
2151{
2152 struct flist_head *entry;
2153 struct gui_entry *ge;
2154
2155 __update_graph_limits(&main_ui.graphs);
2156
2157 flist_for_each(entry, &main_ui.list) {
2158 ge = flist_entry(entry, struct gui_entry, list);
2159 __update_graph_limits(&ge->graphs);
2160 }
2161}
2162
Jens Axboe46974a72012-03-02 19:34:13 +01002163static void preferences(GtkWidget *w, gpointer data)
2164{
Jens Axboef3e84402012-03-07 13:14:32 +01002165 GtkWidget *dialog, *frame, *box, **buttons, *vbox, *font;
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002166 GtkWidget *hbox, *spin, *entry, *spin_int;
Jens Axboe46974a72012-03-02 19:34:13 +01002167 int i;
2168
2169 dialog = gtk_dialog_new_with_buttons("Preferences",
Jens Axboe2f99deb2012-03-09 14:37:29 +01002170 GTK_WINDOW(main_ui.window),
Jens Axboe46974a72012-03-02 19:34:13 +01002171 GTK_DIALOG_DESTROY_WITH_PARENT,
2172 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2173 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2174 NULL);
2175
Jens Axboe8577f4f2012-03-09 19:28:27 +01002176 frame = gtk_frame_new("Graphing");
Jens Axboef3e84402012-03-07 13:14:32 +01002177 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
2178 vbox = gtk_vbox_new(FALSE, 6);
2179 gtk_container_add(GTK_CONTAINER(frame), vbox);
2180
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002181 hbox = gtk_hbox_new(FALSE, 5);
2182 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
2183 entry = gtk_label_new("Font face to use for graph labels");
2184 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 5);
2185
Jens Axboef3e84402012-03-07 13:14:32 +01002186 font = gtk_font_button_new();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002187 gtk_box_pack_start(GTK_BOX(hbox), font, FALSE, FALSE, 5);
Jens Axboef3e84402012-03-07 13:14:32 +01002188
Jens Axboe8577f4f2012-03-09 19:28:27 +01002189 box = gtk_vbox_new(FALSE, 6);
2190 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
2191
2192 hbox = gtk_hbox_new(FALSE, 5);
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002193 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
Jens Axboe8577f4f2012-03-09 19:28:27 +01002194 entry = gtk_label_new("Maximum number of data points in graph (seconds)");
2195 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
2196
Jens Axboec05d9052012-03-11 13:05:35 +01002197 spin = create_spinbutton(hbox, 10, 1000000, gfio_graph_limit);
Jens Axboe8577f4f2012-03-09 19:28:27 +01002198
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002199 box = gtk_vbox_new(FALSE, 6);
2200 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
2201
2202 hbox = gtk_hbox_new(FALSE, 5);
2203 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 5);
2204 entry = gtk_label_new("Client ETA request interval (msec)");
2205 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
2206
2207 spin_int = create_spinbutton(hbox, 100, 100000, gfio_client_ops.eta_msec);
Jens Axboea31d9fa2012-03-09 20:23:05 +01002208 frame = gtk_frame_new("Debug logging");
2209 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
2210 vbox = gtk_vbox_new(FALSE, 6);
2211 gtk_container_add(GTK_CONTAINER(frame), vbox);
2212
2213 box = gtk_hbox_new(FALSE, 6);
2214 gtk_container_add(GTK_CONTAINER(vbox), box);
2215
2216 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
2217
2218 for (i = 0; i < FD_DEBUG_MAX; i++) {
2219 if (i == 7) {
2220 box = gtk_hbox_new(FALSE, 6);
2221 gtk_container_add(GTK_CONTAINER(vbox), box);
2222 }
2223
2224
2225 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
2226 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
2227 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
2228 }
2229
Jens Axboe46974a72012-03-02 19:34:13 +01002230 gtk_widget_show_all(dialog);
2231
2232 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
2233 gtk_widget_destroy(dialog);
2234 return;
2235 }
2236
2237 for (i = 0; i < FD_DEBUG_MAX; i++) {
2238 int set;
2239
2240 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
2241 if (set)
2242 fio_debug |= (1UL << i);
2243 }
2244
Jens Axboef3e84402012-03-07 13:14:32 +01002245 gfio_graph_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
Jens Axboe8577f4f2012-03-09 19:28:27 +01002246 gfio_graph_limit = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
2247 update_graph_limits();
Jens Axboe1cf6bca2012-03-09 20:20:17 +01002248 gfio_client_ops.eta_msec = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_int));
Jens Axboe8577f4f2012-03-09 19:28:27 +01002249
Jens Axboe46974a72012-03-02 19:34:13 +01002250 gtk_widget_destroy(dialog);
2251}
2252
Jens Axboe0420ba62012-02-29 11:16:52 +01002253static void about_dialog(GtkWidget *w, gpointer data)
2254{
Jens Axboe81e4ea62012-03-07 14:18:28 +01002255 const char *authors[] = {
2256 "Jens Axboe <axboe@kernel.dk>",
2257 "Stephen Carmeron <stephenmcameron@gmail.com>",
2258 NULL
2259 };
Jens Axboe84a72ed2012-03-07 14:24:57 +01002260 const char *license[] = {
2261 "Fio is free software; you can redistribute it and/or modify "
2262 "it under the terms of the GNU General Public License as published by "
2263 "the Free Software Foundation; either version 2 of the License, or "
2264 "(at your option) any later version.\n",
2265 "Fio is distributed in the hope that it will be useful, "
2266 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
2267 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
2268 "GNU General Public License for more details.\n",
2269 "You should have received a copy of the GNU General Public License "
2270 "along with Fio; if not, write to the Free Software Foundation, Inc., "
2271 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
2272 };
2273 char *license_trans;
2274
2275 license_trans = g_strconcat(license[0], "\n", license[1], "\n",
2276 license[2], "\n", NULL);
Jens Axboe81e4ea62012-03-07 14:18:28 +01002277
Jens Axboe0420ba62012-02-29 11:16:52 +01002278 gtk_show_about_dialog(NULL,
2279 "program-name", "gfio",
2280 "comments", "Gtk2 UI for fio",
Jens Axboe84a72ed2012-03-07 14:24:57 +01002281 "license", license_trans,
Jens Axboe81e4ea62012-03-07 14:18:28 +01002282 "website", "http://git.kernel.dk/?p=fio.git;a=summary",
2283 "authors", authors,
Jens Axboe0420ba62012-02-29 11:16:52 +01002284 "version", fio_version_string,
Jens Axboe81e4ea62012-03-07 14:18:28 +01002285 "copyright", "© 2012 Jens Axboe <axboe@kernel.dk>",
Jens Axboe0420ba62012-02-29 11:16:52 +01002286 "logo-icon-name", "fio",
2287 /* Must be last: */
Jens Axboe81e4ea62012-03-07 14:18:28 +01002288 "wrap-license", TRUE,
Jens Axboe0420ba62012-02-29 11:16:52 +01002289 NULL);
Jens Axboe84a72ed2012-03-07 14:24:57 +01002290
Jens Axboe2f99deb2012-03-09 14:37:29 +01002291 g_free(license_trans);
Jens Axboe0420ba62012-02-29 11:16:52 +01002292}
2293
2294static GtkActionEntry menu_items[] = {
Jens Axboe46974a72012-03-02 19:34:13 +01002295 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
Jens Axboe9b260bd2012-03-06 11:02:52 +01002296 { "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
Jens Axboe16ce5ad2012-03-12 11:56:09 +01002297 { "JobMenuAction", GTK_STOCK_FILE, "Job", NULL, NULL, NULL},
Jens Axboe46974a72012-03-02 19:34:13 +01002298 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
Jens Axboe2f99deb2012-03-09 14:37:29 +01002299 { "NewFile", GTK_STOCK_NEW, "New", "<Control>N", NULL, G_CALLBACK(file_new) },
Jens Axboe16ce5ad2012-03-12 11:56:09 +01002300 { "CloseFile", GTK_STOCK_CLOSE, "Close", "<Control>W", NULL, G_CALLBACK(file_close) },
Jens Axboe46974a72012-03-02 19:34:13 +01002301 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
2302 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
2303 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
Jens Axboe9b260bd2012-03-06 11:02:52 +01002304 { "ViewLog", NULL, "Log", "<Control>l", NULL, G_CALLBACK(view_log) },
Jens Axboe16ce5ad2012-03-12 11:56:09 +01002305 { "EditOptions", NULL, "Edit Options", "<Control>E", NULL, G_CALLBACK(edit_options) },
Jens Axboe46974a72012-03-02 19:34:13 +01002306 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
2307 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
Jens Axboe0420ba62012-02-29 11:16:52 +01002308};
Jens Axboe3e47bd22012-02-29 13:45:02 +01002309static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +01002310
2311static const gchar *ui_string = " \
2312 <ui> \
2313 <menubar name=\"MainMenu\"> \
2314 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01002315 <menuitem name=\"New\" action=\"NewFile\" /> \
Jens Axboe16ce5ad2012-03-12 11:56:09 +01002316 <menuitem name=\"Close\" action=\"CloseFile\" /> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01002317 <separator name=\"Separator1\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01002318 <menuitem name=\"Open\" action=\"OpenFile\" /> \
2319 <menuitem name=\"Save\" action=\"SaveFile\" /> \
Jens Axboe46974a72012-03-02 19:34:13 +01002320 <separator name=\"Separator2\"/> \
Jens Axboe2f99deb2012-03-09 14:37:29 +01002321 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
2322 <separator name=\"Separator3\"/> \
Jens Axboe0420ba62012-02-29 11:16:52 +01002323 <menuitem name=\"Quit\" action=\"Quit\" /> \
2324 </menu> \
Jens Axboe16ce5ad2012-03-12 11:56:09 +01002325 <menu name=\"JobMenu\" action=\"JobMenuAction\"> \
2326 <menuitem name=\"Edit Options\" action=\"EditOptions\" /> \
2327 </menu>\
Jens Axboe9b260bd2012-03-06 11:02:52 +01002328 <menu name=\"ViewMenu\" action=\"ViewMenuAction\"> \
2329 <menuitem name=\"Log\" action=\"ViewLog\" /> \
2330 </menu>\
Jens Axboe0420ba62012-02-29 11:16:52 +01002331 <menu name=\"Help\" action=\"HelpMenuAction\"> \
2332 <menuitem name=\"About\" action=\"About\" /> \
2333 </menu> \
2334 </menubar> \
2335 </ui> \
2336";
2337
Jens Axboe4cbe7212012-03-06 13:36:17 +01002338static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager,
2339 struct gui *ui)
Jens Axboe0420ba62012-02-29 11:16:52 +01002340{
2341 GtkActionGroup *action_group = gtk_action_group_new("Menu");
2342 GError *error = 0;
2343
2344 action_group = gtk_action_group_new("Menu");
Jens Axboe4cbe7212012-03-06 13:36:17 +01002345 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, ui);
Jens Axboe0420ba62012-02-29 11:16:52 +01002346
2347 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
2348 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
2349
2350 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
2351 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
2352}
2353
2354void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
2355 GtkWidget *vbox, GtkUIManager *ui_manager)
2356{
2357 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
2358}
2359
Jens Axboec80b74b2012-03-12 10:23:28 +01002360static void combo_entry_changed(GtkComboBox *box, gpointer data)
2361{
2362 struct gui_entry *ge = (struct gui_entry *) data;
2363 gint index;
2364
2365 index = gtk_combo_box_get_active(box);
2366
2367 multitext_set_entry(&ge->eta.iotype, index);
2368 multitext_set_entry(&ge->eta.ioengine, index);
2369 multitext_set_entry(&ge->eta.iodepth, index);
2370}
2371
2372static void combo_entry_destroy(GtkWidget *widget, gpointer data)
2373{
2374 struct gui_entry *ge = (struct gui_entry *) data;
2375
2376 multitext_free(&ge->eta.iotype);
2377 multitext_free(&ge->eta.ioengine);
2378 multitext_free(&ge->eta.iodepth);
2379}
2380
Jens Axboe2f99deb2012-03-09 14:37:29 +01002381static GtkWidget *new_client_page(struct gui_entry *ge)
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002382{
Jens Axboe2f99deb2012-03-09 14:37:29 +01002383 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01002384 GdkColor white;
Jens Axboe0420ba62012-02-29 11:16:52 +01002385
Jens Axboe2f99deb2012-03-09 14:37:29 +01002386 main_vbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01002387
Jens Axboe2f99deb2012-03-09 14:37:29 +01002388 ge->topalign = gtk_alignment_new(0, 0, 1, 0);
2389 ge->topvbox = gtk_vbox_new(FALSE, 3);
2390 gtk_container_add(GTK_CONTAINER(ge->topalign), ge->topvbox);
2391 gtk_box_pack_start(GTK_BOX(main_vbox), ge->topalign, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002392
Jens Axboe3e47bd22012-02-29 13:45:02 +01002393 probe = gtk_frame_new("Job");
Jens Axboe2f99deb2012-03-09 14:37:29 +01002394 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +01002395 probe_frame = gtk_vbox_new(FALSE, 3);
2396 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
2397
2398 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002399 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2400 ge->probe.hostname = new_info_label_in_frame(probe_box, "Host");
2401 ge->probe.os = new_info_label_in_frame(probe_box, "OS");
2402 ge->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
2403 ge->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
Jens Axboe843ad232012-02-29 11:44:53 +01002404
Jens Axboe3e47bd22012-02-29 13:45:02 +01002405 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002406 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2407
Jens Axboe3863d1a2012-03-09 17:39:05 +01002408 ge->eta.names = new_combo_entry_in_frame(probe_box, "Jobs");
Jens Axboec80b74b2012-03-12 10:23:28 +01002409 g_signal_connect(ge->eta.names, "changed", G_CALLBACK(combo_entry_changed), ge);
2410 g_signal_connect(ge->eta.names, "destroy", G_CALLBACK(combo_entry_destroy), ge);
2411 ge->eta.iotype.entry = new_info_entry_in_frame(probe_box, "IO");
2412 ge->eta.ioengine.entry = new_info_entry_in_frame(probe_box, "IO Engine");
2413 ge->eta.iodepth.entry = new_info_entry_in_frame(probe_box, "IO Depth");
Jens Axboe2f99deb2012-03-09 14:37:29 +01002414 ge->eta.jobs = new_info_entry_in_frame(probe_box, "Jobs");
2415 ge->eta.files = new_info_entry_in_frame(probe_box, "Open files");
2416
2417 probe_box = gtk_hbox_new(FALSE, 3);
2418 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
2419 ge->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
2420 ge->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
2421 ge->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
2422 ge->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
2423
2424 /*
2425 * Only add this if we have a commit rate
2426 */
2427#if 0
2428 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe3e47bd22012-02-29 13:45:02 +01002429 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +01002430
Jens Axboe2f99deb2012-03-09 14:37:29 +01002431 ge->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
2432 ge->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2433
2434 ge->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
2435 ge->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2436#endif
2437
2438 /*
2439 * Set up a drawing area and IOPS and bandwidth graphs
2440 */
2441 gdk_color_parse("white", &white);
2442 ge->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01002443 gtk_widget_set_size_request(GTK_WIDGET(ge->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01002444 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002445 gtk_widget_modify_bg(ge->graphs.drawing_area, GTK_STATE_NORMAL, &white);
2446 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "expose_event",
2447 G_CALLBACK(on_expose_drawing_area), &ge->graphs);
2448 g_signal_connect(G_OBJECT(ge->graphs.drawing_area), "configure_event",
2449 G_CALLBACK(on_config_drawing_area), &ge->graphs);
2450 ge->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2451 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ge->scrolled_window),
2452 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2453 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ge->scrolled_window),
2454 ge->graphs.drawing_area);
2455 gtk_box_pack_start(GTK_BOX(main_vbox), ge->scrolled_window,
2456 TRUE, TRUE, 0);
2457
2458 setup_graphs(&ge->graphs);
2459
2460 /*
2461 * Set up alignments for widgets at the bottom of ui,
2462 * align bottom left, expand horizontally but not vertically
2463 */
2464 ge->bottomalign = gtk_alignment_new(0, 1, 1, 0);
2465 ge->buttonbox = gtk_hbox_new(FALSE, 0);
2466 gtk_container_add(GTK_CONTAINER(ge->bottomalign), ge->buttonbox);
2467 gtk_box_pack_start(GTK_BOX(main_vbox), ge->bottomalign,
2468 FALSE, FALSE, 0);
2469
2470 add_buttons(ge, buttonspeclist, ARRAYSIZE(buttonspeclist));
2471
2472 /*
2473 * Set up thread status progress bar
2474 */
2475 ge->thread_status_pb = gtk_progress_bar_new();
2476 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ge->thread_status_pb), 0.0);
2477 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ge->thread_status_pb), "No connections");
2478 gtk_container_add(GTK_CONTAINER(ge->buttonbox), ge->thread_status_pb);
2479
2480
2481 return main_vbox;
2482}
2483
2484static GtkWidget *new_main_page(struct gui *ui)
2485{
2486 GtkWidget *main_vbox, *probe, *probe_frame, *probe_box;
2487 GdkColor white;
2488
2489 main_vbox = gtk_vbox_new(FALSE, 3);
2490
2491 /*
2492 * Set up alignments for widgets at the top of ui,
2493 * align top left, expand horizontally but not vertically
2494 */
2495 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
2496 ui->topvbox = gtk_vbox_new(FALSE, 0);
2497 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
2498 gtk_box_pack_start(GTK_BOX(main_vbox), ui->topalign, FALSE, FALSE, 0);
2499
2500 probe = gtk_frame_new("Run statistics");
2501 gtk_box_pack_start(GTK_BOX(main_vbox), probe, FALSE, FALSE, 3);
2502 probe_frame = gtk_vbox_new(FALSE, 3);
2503 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
Jens Axboe3e47bd22012-02-29 13:45:02 +01002504
2505 probe_box = gtk_hbox_new(FALSE, 3);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002506 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, FALSE, FALSE, 3);
Jens Axboe3863d1a2012-03-09 17:39:05 +01002507 ui->eta.jobs = new_info_entry_in_frame(probe_box, "Running");
Jens Axboeca850992012-03-05 20:04:43 +01002508 ui->eta.read_bw = new_info_entry_in_frame(probe_box, "Read BW");
2509 ui->eta.read_iops = new_info_entry_in_frame(probe_box, "IOPS");
2510 ui->eta.write_bw = new_info_entry_in_frame(probe_box, "Write BW");
2511 ui->eta.write_iops = new_info_entry_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01002512
2513 /*
2514 * Only add this if we have a commit rate
2515 */
2516#if 0
2517 probe_box = gtk_hbox_new(FALSE, 3);
2518 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
2519
Jens Axboe3e47bd22012-02-29 13:45:02 +01002520 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
2521 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
2522
Jens Axboe3e47bd22012-02-29 13:45:02 +01002523 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
2524 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +01002525#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +01002526
Stephen M. Cameron45032dd2012-02-24 08:17:31 +01002527 /*
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002528 * Set up a drawing area and IOPS and bandwidth graphs
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002529 */
Stephen M. Cameronaaa71f62012-03-07 14:47:03 +01002530 gdk_color_parse("white", &white);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002531 ui->graphs.drawing_area = gtk_drawing_area_new();
Jens Axboe2f99deb2012-03-09 14:37:29 +01002532 gtk_widget_set_size_request(GTK_WIDGET(ui->graphs.drawing_area),
Stephen M. Cameron57f9d282012-03-11 11:36:51 +01002533 DRAWING_AREA_XDIM, DRAWING_AREA_YDIM);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002534 gtk_widget_modify_bg(ui->graphs.drawing_area, GTK_STATE_NORMAL, &white);
2535 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "expose_event",
2536 G_CALLBACK(on_expose_drawing_area), &ui->graphs);
2537 g_signal_connect(G_OBJECT(ui->graphs.drawing_area), "configure_event",
2538 G_CALLBACK(on_config_drawing_area), &ui->graphs);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002539 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2540 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
2541 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002542 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ui->scrolled_window),
Jens Axboe2f99deb2012-03-09 14:37:29 +01002543 ui->graphs.drawing_area);
2544 gtk_box_pack_start(GTK_BOX(main_vbox), ui->scrolled_window,
Stephen M. Camerone1645342012-02-24 08:17:32 +01002545 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +01002546
Jens Axboe2f99deb2012-03-09 14:37:29 +01002547 setup_graphs(&ui->graphs);
Jens Axboe2fd3bb02012-03-07 08:07:39 +01002548
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002549 /*
2550 * Set up alignments for widgets at the bottom of ui,
2551 * align bottom left, expand horizontally but not vertically
2552 */
2553 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
2554 ui->buttonbox = gtk_hbox_new(FALSE, 0);
2555 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
Jens Axboe2f99deb2012-03-09 14:37:29 +01002556 gtk_box_pack_start(GTK_BOX(main_vbox), ui->bottomalign,
Stephen M. Camerone1645342012-02-24 08:17:32 +01002557 FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +01002558
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002559 /*
2560 * Set up thread status progress bar
2561 */
2562 ui->thread_status_pb = gtk_progress_bar_new();
2563 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +01002564 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002565 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
2566
Jens Axboe2f99deb2012-03-09 14:37:29 +01002567 return main_vbox;
2568}
2569
2570static gboolean notebook_switch_page(GtkNotebook *notebook, GtkWidget *widget,
2571 guint page, gpointer data)
2572
2573{
2574 return TRUE;
2575}
2576
2577static void init_ui(int *argc, char **argv[], struct gui *ui)
2578{
2579 GtkSettings *settings;
2580 GtkUIManager *uimanager;
2581 GtkWidget *menu, *vbox;
2582
2583 /* Magical g*thread incantation, you just need this thread stuff.
2584 * Without it, the update that happens in gfio_update_thread_status
2585 * doesn't really happen in a timely fashion, you need expose events
2586 */
2587 if (!g_thread_supported())
2588 g_thread_init(NULL);
2589 gdk_threads_init();
2590
2591 gtk_init(argc, argv);
2592 settings = gtk_settings_get_default();
2593 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
2594 g_type_init();
2595
2596 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2597 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
2598 gtk_window_set_default_size(GTK_WINDOW(ui->window), 1024, 768);
2599
2600 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
2601 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
2602
2603 ui->vbox = gtk_vbox_new(FALSE, 0);
2604 gtk_container_add(GTK_CONTAINER(ui->window), ui->vbox);
2605
2606 uimanager = gtk_ui_manager_new();
2607 menu = get_menubar_menu(ui->window, uimanager, ui);
2608 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
2609
2610 ui->notebook = gtk_notebook_new();
2611 g_signal_connect(ui->notebook, "switch-page", G_CALLBACK(notebook_switch_page), ui);
Jens Axboeb870c312012-03-09 17:22:01 +01002612 gtk_notebook_set_scrollable(GTK_NOTEBOOK(ui->notebook), 1);
Jens Axboe0aa928c2012-03-09 17:24:07 +01002613 gtk_notebook_popup_enable(GTK_NOTEBOOK(ui->notebook));
Jens Axboe2f99deb2012-03-09 14:37:29 +01002614 gtk_container_add(GTK_CONTAINER(ui->vbox), ui->notebook);
2615
2616 vbox = new_main_page(ui);
2617
2618 gtk_notebook_append_page(GTK_NOTEBOOK(ui->notebook), vbox, gtk_label_new("Main"));
2619
Jens Axboe9b260bd2012-03-06 11:02:52 +01002620 gfio_ui_setup_log(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +01002621
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002622 gtk_widget_show_all(ui->window);
2623}
2624
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002625int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002626{
Stephen M. Cameron8232e282012-02-24 08:17:31 +01002627 if (initialize_fio(envp))
2628 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +01002629 if (fio_init_options())
2630 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +01002631
Jens Axboe2f99deb2012-03-09 14:37:29 +01002632 memset(&main_ui, 0, sizeof(main_ui));
2633 INIT_FLIST_HEAD(&main_ui.list);
2634
2635 init_ui(&argc, &argv, &main_ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +01002636
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002637 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002638 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +01002639 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +01002640 return 0;
2641}