End results fixes
[fio.git] / gfio.c
CommitLineData
ff1f3280
SC
1/*
2 * gfio - gui front end for fio - the flexible io tester
3 *
4 * Copyright (C) 2012 Stephen M. Cameron <stephenmcameron@gmail.com>
5 *
6 * The license below covers all files distributed with fio unless otherwise
7 * noted in the file itself.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
8232e285 23#include <locale.h>
60f6b330 24#include <malloc.h>
8232e285 25
5b7573ab 26#include <glib.h>
ff1f3280
SC
27#include <gtk/gtk.h>
28
8232e285
SC
29#include "fio.h"
30
3e47bd25
JA
31static void gfio_update_thread_status(char *status_message, double perc);
32
f3074008
SC
33#define ARRAYSIZE(x) (sizeof((x)) / (sizeof((x)[0])))
34
35typedef void (*clickfunction)(GtkWidget *widget, gpointer data);
36
3e47bd25 37static void connect_clicked(GtkWidget *widget, gpointer data);
f3074008
SC
38static void start_job_clicked(GtkWidget *widget, gpointer data);
39
40static struct button_spec {
41 const char *buttontext;
42 clickfunction f;
43 const char *tooltiptext;
3e47bd25 44 const int start_insensitive;
f3074008 45} buttonspeclist[] = {
3e47bd25
JA
46#define CONNECT_BUTTON 0
47#define START_JOB_BUTTON 1
48 { "Connect", connect_clicked, "Connect to host", 0 },
f3074008
SC
49 { "Start Job",
50 start_job_clicked,
3e47bd25 51 "Send current fio job to fio server to be executed", 1 },
f3074008
SC
52};
53
843ad237
JA
54struct probe_widget {
55 GtkWidget *hostname;
56 GtkWidget *os;
57 GtkWidget *arch;
58 GtkWidget *fio_ver;
59};
60
3e47bd25 61struct eta_widget {
807f9971
JA
62 GtkWidget *name;
63 GtkWidget *iotype;
64 GtkWidget *ioengine;
65 GtkWidget *iodepth;
3e47bd25
JA
66 GtkWidget *jobs;
67 GtkWidget *files;
68 GtkWidget *read_bw;
69 GtkWidget *read_iops;
70 GtkWidget *cr_bw;
71 GtkWidget *cr_iops;
72 GtkWidget *write_bw;
73 GtkWidget *write_iops;
74 GtkWidget *cw_bw;
75 GtkWidget *cw_iops;
76};
77
ff1f3280
SC
78struct gui {
79 GtkWidget *window;
5b7573ab 80 GtkWidget *vbox;
c36f98d9
SC
81 GtkWidget *topvbox;
82 GtkWidget *topalign;
83 GtkWidget *bottomalign;
04cc6b77 84 GtkWidget *thread_status_pb;
f3074008
SC
85 GtkWidget *buttonbox;
86 GtkWidget *button[ARRAYSIZE(buttonspeclist)];
736f2dff
SC
87 GtkWidget *scrolled_window;
88 GtkWidget *textview;
0420ba6a
JA
89 GtkWidget *error_info_bar;
90 GtkWidget *error_label;
736f2dff 91 GtkTextBuffer *text;
843ad237 92 struct probe_widget probe;
3e47bd25 93 struct eta_widget eta;
3ec62ec4 94 int connected;
25927259 95 pthread_t t;
0420ba6a 96
3ec62ec4 97 struct fio_client *client;
0420ba6a
JA
98 int nr_job_files;
99 char **job_files;
5b7573ab 100} ui;
ff1f3280 101
8663ea65
JA
102static void clear_ui_info(struct gui *ui)
103{
104 gtk_label_set_text(GTK_LABEL(ui->probe.hostname), "");
105 gtk_label_set_text(GTK_LABEL(ui->probe.os), "");
106 gtk_label_set_text(GTK_LABEL(ui->probe.arch), "");
107 gtk_label_set_text(GTK_LABEL(ui->probe.fio_ver), "");
108 gtk_label_set_text(GTK_LABEL(ui->eta.name), "");
109 gtk_label_set_text(GTK_LABEL(ui->eta.iotype), "");
110 gtk_label_set_text(GTK_LABEL(ui->eta.ioengine), "");
111 gtk_label_set_text(GTK_LABEL(ui->eta.iodepth), "");
112 gtk_label_set_text(GTK_LABEL(ui->eta.jobs), "");
113 gtk_label_set_text(GTK_LABEL(ui->eta.files), "");
114 gtk_label_set_text(GTK_LABEL(ui->eta.read_bw), "");
115 gtk_label_set_text(GTK_LABEL(ui->eta.read_iops), "");
116 gtk_label_set_text(GTK_LABEL(ui->eta.write_bw), "");
117 gtk_label_set_text(GTK_LABEL(ui->eta.write_iops), "");
118}
119
3650a3ca
JA
120static GtkWidget *new_info_entry_in_frame(GtkWidget *box, const char *label)
121{
122 GtkWidget *entry, *frame;
123
124 frame = gtk_frame_new(label);
125 entry = gtk_entry_new();
1c1e4a5b 126 gtk_entry_set_editable(GTK_ENTRY(entry), 0);
3650a3ca
JA
127 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
128 gtk_container_add(GTK_CONTAINER(frame), entry);
129
130 return entry;
131}
132
133static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
134{
135 GtkWidget *label_widget;
136 GtkWidget *frame;
137
138 frame = gtk_frame_new(label);
139 label_widget = gtk_label_new(NULL);
140 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
141 gtk_container_add(GTK_CONTAINER(frame), label_widget);
142
143 return label_widget;
144}
145
146static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
147{
148 GtkWidget *button, *box;
149
150 box = gtk_hbox_new(FALSE, 3);
151 gtk_container_add(GTK_CONTAINER(hbox), box);
152
153 button = gtk_spin_button_new_with_range(min, max, 1.0);
154 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
155
156 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
157 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
158
159 return button;
160}
161
3ec62ec4
JA
162static void gfio_set_connected(struct gui *ui, int connected)
163{
164 if (connected) {
165 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
166 ui->connected = 1;
167 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Disconnect");
168 } else {
169 ui->connected = 0;
170 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Connect");
171 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
172 }
173}
174
3650a3ca
JA
175static void label_set_int_value(GtkWidget *entry, unsigned int val)
176{
177 char tmp[80];
178
179 sprintf(tmp, "%u", val);
180 gtk_label_set_text(GTK_LABEL(entry), tmp);
181}
182
183static void entry_set_int_value(GtkWidget *entry, unsigned int val)
184{
185 char tmp[80];
186
187 sprintf(tmp, "%u", val);
188 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
189}
190
191static void gfio_show_lat(GtkWidget *vbox, const char *name, unsigned long min,
192 unsigned long max, double mean, double dev)
193{
194 const char *base = "(usec)";
1c1e4a5b 195 GtkWidget *hbox, *label, *frame;
3650a3ca
JA
196 char *minp, *maxp;
197 char tmp[64];
198
199 if (!usec_to_msec(&min, &max, &mean, &dev))
200 base = "(msec)";
201
202 minp = num2str(min, 6, 1, 0);
203 maxp = num2str(max, 6, 1, 0);
204
3650a3ca
JA
205 sprintf(tmp, "%s %s", name, base);
206 frame = gtk_frame_new(tmp);
207 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
208
3650a3ca 209 hbox = gtk_hbox_new(FALSE, 3);
1c1e4a5b 210 gtk_container_add(GTK_CONTAINER(frame), hbox);
3650a3ca
JA
211
212 label = new_info_label_in_frame(hbox, "Minimum");
213 gtk_label_set_text(GTK_LABEL(label), minp);
214 label = new_info_label_in_frame(hbox, "Maximum");
215 gtk_label_set_text(GTK_LABEL(label), maxp);
216 label = new_info_label_in_frame(hbox, "Average");
217 sprintf(tmp, "%5.02f", mean);
218 gtk_label_set_text(GTK_LABEL(label), tmp);
219 label = new_info_label_in_frame(hbox, "Standard deviation");
220 sprintf(tmp, "%5.02f", dev);
221 gtk_label_set_text(GTK_LABEL(label), tmp);
222
223 free(minp);
224 free(maxp);
225
226}
227
228static void gfio_show_ddir_status(GtkWidget *mbox, struct group_run_stats *rs,
229 struct thread_stat *ts, int ddir)
230{
231 const char *ddir_label[2] = { "Read", "Write" };
232 GtkWidget *frame, *label, *box, *vbox;
233 unsigned long min, max, runt;
234 unsigned long long bw, iops;
235 double mean, dev;
236 char *io_p, *bw_p, *iops_p;
237 int i2p;
238
239 if (!ts->runtime[ddir])
240 return;
241
242 i2p = is_power_of_2(rs->kb_base);
243 runt = ts->runtime[ddir];
244
245 bw = (1000 * ts->io_bytes[ddir]) / runt;
246 io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p);
247 bw_p = num2str(bw, 6, 1, i2p);
248
249 iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
250 iops_p = num2str(iops, 6, 1, 0);
251
252 box = gtk_hbox_new(FALSE, 3);
253 gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
254
255 frame = gtk_frame_new(ddir_label[ddir]);
256 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
257
258 vbox = gtk_vbox_new(FALSE, 3);
259 gtk_container_add(GTK_CONTAINER(frame), vbox);
260
261 box = gtk_hbox_new(FALSE, 3);
262 gtk_box_pack_start(GTK_BOX(vbox), box, TRUE, FALSE, 3);
263
264 label = new_info_label_in_frame(box, "IO");
265 gtk_label_set_text(GTK_LABEL(label), io_p);
266 label = new_info_label_in_frame(box, "Bandwidth");
267 gtk_label_set_text(GTK_LABEL(label), bw_p);
268 label = new_info_label_in_frame(box, "IOPS");
269 gtk_label_set_text(GTK_LABEL(label), iops_p);
270 label = new_info_label_in_frame(box, "Runtime (msec)");
271 label_set_int_value(label, ts->runtime[ddir]);
272
273 frame = gtk_frame_new("Latency");
274 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
275
276 vbox = gtk_vbox_new(FALSE, 3);
277 gtk_container_add(GTK_CONTAINER(frame), vbox);
278
279 if (calc_lat(&ts->slat_stat[ddir], &min, &max, &mean, &dev))
280 gfio_show_lat(vbox, "Submission latency", min, max, mean, dev);
281 if (calc_lat(&ts->clat_stat[ddir], &min, &max, &mean, &dev))
282 gfio_show_lat(vbox, "Completion latency", min, max, mean, dev);
283 if (calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev))
284 gfio_show_lat(vbox, "Total latency", min, max, mean, dev);
285
286 free(io_p);
287 free(bw_p);
288 free(iops_p);
289}
290
291static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
292 struct group_run_stats *rs)
293{
294 GtkWidget *dialog, *box, *vbox, *entry, *content;
295 struct gui *ui = client->client_data;
296
297 gdk_threads_enter();
298
299 dialog = gtk_dialog_new_with_buttons("Results", GTK_WINDOW(ui->window),
300 GTK_DIALOG_DESTROY_WITH_PARENT,
301 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
302
303 g_signal_connect_swapped(dialog, "response",
304 G_CALLBACK(gtk_widget_destroy),
305 dialog);
306
307 content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
308
309 vbox = gtk_vbox_new(FALSE, 3);
310 gtk_container_add(GTK_CONTAINER(content), vbox);
311
312 box = gtk_hbox_new(TRUE, 3);
313 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
314
315 entry = new_info_entry_in_frame(box, "Name");
316 gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
317 if (strlen(ts->description)) {
318 entry = new_info_entry_in_frame(box, "Description");
319 gtk_entry_set_text(GTK_ENTRY(entry), ts->description);
320 }
321 entry = new_info_entry_in_frame(box, "Group ID");
322 entry_set_int_value(entry, ts->groupid);
323 entry = new_info_entry_in_frame(box, "Jobs");
324 entry_set_int_value(entry, ts->members);
325 entry = new_info_entry_in_frame(box, "Error");
326 entry_set_int_value(entry, ts->error);
327 entry = new_info_entry_in_frame(box, "PID");
328 entry_set_int_value(entry, ts->pid);
329
330 if (ts->io_bytes[DDIR_READ])
331 gfio_show_ddir_status(vbox, rs, ts, DDIR_READ);
332 if (ts->io_bytes[DDIR_WRITE])
333 gfio_show_ddir_status(vbox, rs, ts, DDIR_WRITE);
334
335 gtk_widget_show_all(dialog);
336
337 gdk_threads_leave();
338}
339
084d1c6f 340static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
a1820207 341{
807f9971 342#if 0
736f2dff
SC
343 GtkTextBuffer *buffer;
344 GtkTextIter end;
345
346 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ui.textview));
347 gdk_threads_enter();
348 gtk_text_buffer_get_end_iter(buffer, &end);
349 gtk_text_buffer_insert(buffer, &end, buf, -1);
350 gdk_threads_leave();
351 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ui.textview),
352 &end, 0.0, FALSE, 0.0,0.0);
807f9971 353#else
084d1c6f 354 fio_client_ops.text_op(client, cmd);
807f9971 355#endif
a1820207
SC
356}
357
358static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
359{
360 printf("gfio_disk_util_op called\n");
361 fio_client_ops.disk_util(client, cmd);
362}
363
3650a3ca
JA
364extern int sum_stat_clients;
365extern struct thread_stat client_ts;
366extern struct group_run_stats client_gs;
367
368static int sum_stat_nr;
369
89e5fad9
JA
370static void gfio_thread_status_op(struct fio_client *client,
371 struct fio_net_cmd *cmd)
a1820207 372{
3650a3ca
JA
373 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
374
375 gfio_display_ts(client, &p->ts, &p->rs);
376
377 if (sum_stat_clients == 1)
378 return;
379
380 sum_thread_stats(&client_ts, &p->ts, sum_stat_nr);
381 sum_group_stats(&client_gs, &p->rs);
382
383 client_ts.members++;
384 client_ts.groupid = p->ts.groupid;
385
386 if (++sum_stat_nr == sum_stat_clients) {
387 strcpy(client_ts.name, "All clients");
388 gfio_display_ts(client, &client_ts, &client_gs);
389 }
a1820207
SC
390}
391
89e5fad9
JA
392static void gfio_group_stats_op(struct fio_client *client,
393 struct fio_net_cmd *cmd)
a1820207
SC
394{
395 printf("gfio_group_stats_op called\n");
89e5fad9 396 fio_client_ops.group_stats(client, cmd);
a1820207
SC
397}
398
3e47bd25
JA
399static void gfio_update_eta(struct jobs_eta *je)
400{
401 static int eta_good;
402 char eta_str[128];
403 char output[256];
404 char tmp[32];
405 double perc = 0.0;
406 int i2p = 0;
407
408 eta_str[0] = '\0';
409 output[0] = '\0';
410
411 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
412 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
413 eta_to_str(eta_str, je->eta_sec);
414 }
415
416 sprintf(tmp, "%u", je->nr_running);
417 gtk_label_set_text(GTK_LABEL(ui.eta.jobs), tmp);
418 sprintf(tmp, "%u", je->files_open);
419 gtk_label_set_text(GTK_LABEL(ui.eta.files), tmp);
420
421#if 0
422 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
423 if (je->m_rate || je->t_rate) {
424 char *tr, *mr;
425
426 mr = num2str(je->m_rate, 4, 0, i2p);
427 tr = num2str(je->t_rate, 4, 0, i2p);
428 gtk_label_set_text(GTK_LABEL(ui.eta.
429 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
430 free(tr);
431 free(mr);
432 } else if (je->m_iops || je->t_iops)
433 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
ebbd89cc 434
3e47bd25
JA
435 gtk_label_set_text(GTK_LABEL(ui.eta.cr_bw), "---");
436 gtk_label_set_text(GTK_LABEL(ui.eta.cr_iops), "---");
437 gtk_label_set_text(GTK_LABEL(ui.eta.cw_bw), "---");
438 gtk_label_set_text(GTK_LABEL(ui.eta.cw_iops), "---");
439#endif
440
441 if (je->eta_sec != INT_MAX && je->nr_running) {
442 char *iops_str[2];
443 char *rate_str[2];
444
445 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
446 strcpy(output, "-.-% done");
447 else {
448 eta_good = 1;
449 perc *= 100.0;
450 sprintf(output, "%3.1f%% done", perc);
451 }
452
453 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
454 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
455
456 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
457 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
458
459 gtk_label_set_text(GTK_LABEL(ui.eta.read_bw), rate_str[0]);
460 gtk_label_set_text(GTK_LABEL(ui.eta.read_iops), iops_str[0]);
461 gtk_label_set_text(GTK_LABEL(ui.eta.write_bw), rate_str[1]);
462 gtk_label_set_text(GTK_LABEL(ui.eta.write_iops), iops_str[1]);
463
464 free(rate_str[0]);
465 free(rate_str[1]);
466 free(iops_str[0]);
467 free(iops_str[1]);
468 }
469
470 if (eta_str[0]) {
471 char *dst = output + strlen(output);
472
473 sprintf(dst, " - %s", eta_str);
474 }
475
476 gfio_update_thread_status(output, perc);
477}
478
a1820207
SC
479static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
480{
843ad237
JA
481 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
482 const char *os, *arch;
483 char buf[64];
484
485 os = fio_get_os_string(probe->os);
486 if (!os)
487 os = "unknown";
488
489 arch = fio_get_arch_string(probe->arch);
490 if (!arch)
491 os = "unknown";
492
493 if (!client->name)
494 client->name = strdup((char *) probe->hostname);
495
496 gtk_label_set_text(GTK_LABEL(ui.probe.hostname), (char *) probe->hostname);
497 gtk_label_set_text(GTK_LABEL(ui.probe.os), os);
498 gtk_label_set_text(GTK_LABEL(ui.probe.arch), arch);
499 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
500 gtk_label_set_text(GTK_LABEL(ui.probe.fio_ver), buf);
a1820207
SC
501}
502
04cc6b77 503static void gfio_update_thread_status(char *status_message, double perc)
5b7573ab
SC
504{
505 static char message[100];
506 const char *m = message;
507
508 strncpy(message, status_message, sizeof(message) - 1);
04cc6b77
SC
509 gtk_progress_bar_set_text(
510 GTK_PROGRESS_BAR(ui.thread_status_pb), m);
511 gtk_progress_bar_set_fraction(
512 GTK_PROGRESS_BAR(ui.thread_status_pb), perc / 100.0);
5b7573ab
SC
513 gdk_threads_enter();
514 gtk_widget_queue_draw(ui.window);
515 gdk_threads_leave();
516}
517
3ec62ec4
JA
518static void gfio_quit_op(struct fio_client *client)
519{
520 struct gui *ui = client->client_data;
521
522 gfio_set_connected(ui, 0);
523}
524
807f9971
JA
525static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
526{
527 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
528 struct gui *ui = client->client_data;
529 char tmp[8];
530 int i;
531
532 p->iodepth = le32_to_cpu(p->iodepth);
533 p->rw = le32_to_cpu(p->rw);
534
535 for (i = 0; i < 2; i++) {
536 p->min_bs[i] = le32_to_cpu(p->min_bs[i]);
537 p->max_bs[i] = le32_to_cpu(p->max_bs[i]);
538 }
539
540 p->numjobs = le32_to_cpu(p->numjobs);
541 p->group_reporting = le32_to_cpu(p->group_reporting);
542
543 gtk_label_set_text(GTK_LABEL(ui->eta.name), (gchar *) p->jobname);
544 gtk_label_set_text(GTK_LABEL(ui->eta.iotype), ddir_str(p->rw));
545 gtk_label_set_text(GTK_LABEL(ui->eta.ioengine), (gchar *) p->ioengine);
546
547 sprintf(tmp, "%u", p->iodepth);
548 gtk_label_set_text(GTK_LABEL(ui->eta.iodepth), tmp);
549}
550
ed727a46
JA
551static void gfio_client_timed_out(struct fio_client *client)
552{
553 struct gui *ui = client->client_data;
554 GtkWidget *dialog, *label, *content;
555 char buf[256];
556
557 gdk_threads_enter();
558
559 gfio_set_connected(ui, 0);
88432651 560 clear_ui_info(ui);
ed727a46
JA
561
562 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
563
564 dialog = gtk_dialog_new_with_buttons("Timed out!",
565 GTK_WINDOW(ui->window),
566 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
567 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
568
569 content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
570 label = gtk_label_new((const gchar *) buf);
571 gtk_container_add(GTK_CONTAINER(content), label);
572 gtk_widget_show_all(dialog);
573 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
574
575 gtk_dialog_run(GTK_DIALOG(dialog));
576 gtk_widget_destroy(dialog);
577
578 gdk_threads_leave();
579}
580
a1820207 581struct client_ops gfio_client_ops = {
0420ba6a
JA
582 .text_op = gfio_text_op,
583 .disk_util = gfio_disk_util_op,
584 .thread_status = gfio_thread_status_op,
585 .group_stats = gfio_group_stats_op,
a5276616 586 .eta = gfio_update_eta,
0420ba6a 587 .probe = gfio_probe_op,
3ec62ec4 588 .quit = gfio_quit_op,
807f9971 589 .add_job = gfio_add_job_op,
ed727a46 590 .timed_out = gfio_client_timed_out,
3ec62ec4 591 .stay_connected = 1,
a1820207
SC
592};
593
ff1f3280
SC
594static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
595 __attribute__((unused)) gpointer data)
596{
597 gtk_main_quit();
598}
599
25927259
SC
600static void *job_thread(void *arg)
601{
25927259 602 fio_handle_clients(&gfio_client_ops);
25927259
SC
603 return NULL;
604}
605
0420ba6a 606static int send_job_files(struct gui *ui)
60f6b330 607{
441013b4 608 int i, ret = 0;
0420ba6a
JA
609
610 for (i = 0; i < ui->nr_job_files; i++) {
611 ret = fio_clients_send_ini(ui->job_files[i]);
441013b4
JA
612 if (ret)
613 break;
614
0420ba6a
JA
615 free(ui->job_files[i]);
616 ui->job_files[i] = NULL;
441013b4
JA
617 }
618 while (i < ui->nr_job_files) {
619 free(ui->job_files[i]);
620 ui->job_files[i] = NULL;
621 i++;
0420ba6a
JA
622 }
623
441013b4 624 return ret;
60f6b330
SC
625}
626
3ec62ec4 627static void start_job_thread(struct gui *ui)
25927259 628{
0420ba6a 629 if (send_job_files(ui)) {
60f6b330 630 printf("Yeah, I didn't really like those options too much.\n");
60f6b330
SC
631 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
632 return;
633 }
25927259
SC
634}
635
f3074008 636static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
25927259 637 gpointer data)
f3074008 638{
25927259
SC
639 struct gui *ui = data;
640
25927259 641 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
3ec62ec4 642 start_job_thread(ui);
f3074008
SC
643}
644
df06f220
JA
645static void file_open(GtkWidget *w, gpointer data);
646
647static void connect_clicked(GtkWidget *widget, gpointer data)
3e47bd25 648{
3ec62ec4
JA
649 struct gui *ui = data;
650
651 if (!ui->connected) {
df06f220
JA
652 if (!ui->nr_job_files)
653 file_open(widget, data);
8663ea65 654 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
3ec62ec4
JA
655 fio_clients_connect();
656 pthread_create(&ui->t, NULL, job_thread, NULL);
657 gfio_set_connected(ui, 1);
df06f220
JA
658 } else {
659 fio_clients_terminate();
3ec62ec4 660 gfio_set_connected(ui, 0);
88432651 661 clear_ui_info(ui);
df06f220 662 }
3e47bd25
JA
663}
664
f3074008
SC
665static void add_button(struct gui *ui, int i, GtkWidget *buttonbox,
666 struct button_spec *buttonspec)
667{
668 ui->button[i] = gtk_button_new_with_label(buttonspec->buttontext);
669 g_signal_connect(ui->button[i], "clicked", G_CALLBACK (buttonspec->f), ui);
3ec62ec4 670 gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], FALSE, FALSE, 3);
f3074008 671 gtk_widget_set_tooltip_text(ui->button[i], buttonspeclist[i].tooltiptext);
3e47bd25 672 gtk_widget_set_sensitive(ui->button[i], !buttonspec->start_insensitive);
f3074008
SC
673}
674
675static void add_buttons(struct gui *ui,
676 struct button_spec *buttonlist,
677 int nbuttons)
678{
679 int i;
680
f3074008
SC
681 for (i = 0; i < nbuttons; i++)
682 add_button(ui, i, ui->buttonbox, &buttonlist[i]);
683}
684
0420ba6a
JA
685static void on_info_bar_response(GtkWidget *widget, gint response,
686 gpointer data)
687{
688 if (response == GTK_RESPONSE_OK) {
689 gtk_widget_destroy(widget);
690 ui.error_info_bar = NULL;
691 }
692}
693
df06f220 694void report_error(GError *error)
0420ba6a
JA
695{
696 if (ui.error_info_bar == NULL) {
697 ui.error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
698 GTK_RESPONSE_OK,
699 NULL);
700 g_signal_connect(ui.error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
701 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui.error_info_bar),
702 GTK_MESSAGE_ERROR);
703
704 ui.error_label = gtk_label_new(error->message);
705 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui.error_info_bar));
706 gtk_container_add(GTK_CONTAINER(container), ui.error_label);
707
708 gtk_box_pack_start(GTK_BOX(ui.vbox), ui.error_info_bar, FALSE, FALSE, 0);
709 gtk_widget_show_all(ui.vbox);
710 } else {
711 char buffer[256];
712 snprintf(buffer, sizeof(buffer), "Failed to open file.");
713 gtk_label_set(GTK_LABEL(ui.error_label), buffer);
714 }
715}
716
b9f3c7ed
JA
717static int get_connection_details(char **host, int *port, int *type,
718 int *server_start)
a7a42ce1
JA
719{
720 GtkWidget *dialog, *box, *vbox, *hentry, *hbox, *frame, *pentry, *combo;
b9f3c7ed 721 GtkWidget *button;
a7a42ce1
JA
722 char *typeentry;
723
724 dialog = gtk_dialog_new_with_buttons("Connection details",
725 GTK_WINDOW(ui.window),
726 GTK_DIALOG_DESTROY_WITH_PARENT,
727 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
728 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
729
730 frame = gtk_frame_new("Hostname / socket name");
731 vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
732 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
733
734 box = gtk_vbox_new(FALSE, 6);
735 gtk_container_add(GTK_CONTAINER(frame), box);
736
737 hbox = gtk_hbox_new(TRUE, 10);
738 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
739 hentry = gtk_entry_new();
740 gtk_entry_set_text(GTK_ENTRY(hentry), "localhost");
741 gtk_box_pack_start(GTK_BOX(hbox), hentry, TRUE, TRUE, 0);
742
743 frame = gtk_frame_new("Port");
744 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
745 box = gtk_vbox_new(FALSE, 10);
746 gtk_container_add(GTK_CONTAINER(frame), box);
747
748 hbox = gtk_hbox_new(TRUE, 4);
749 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
750 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
751
752 frame = gtk_frame_new("Type");
753 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
754 box = gtk_vbox_new(FALSE, 10);
755 gtk_container_add(GTK_CONTAINER(frame), box);
756
757 hbox = gtk_hbox_new(TRUE, 4);
758 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
759
760 combo = gtk_combo_box_text_new();
761 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "IPv4");
762 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "IPv6");
763 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "local socket");
764 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
765
766 gtk_container_add(GTK_CONTAINER(hbox), combo);
767
b9f3c7ed
JA
768 frame = gtk_frame_new("Options");
769 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
770 box = gtk_vbox_new(FALSE, 10);
771 gtk_container_add(GTK_CONTAINER(frame), box);
772
773 hbox = gtk_hbox_new(TRUE, 4);
774 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
775
776 button = gtk_check_button_new_with_label("Auto-spawn fio backend");
777 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), 1);
778 gtk_widget_set_tooltip_text(button, "When running fio locally, it is necessary to have the backend running on the same system. If this is checked, gfio will start the backend automatically for you if it isn't already running.");
779 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 6);
780
a7a42ce1
JA
781 gtk_widget_show_all(dialog);
782
783 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
784 gtk_widget_destroy(dialog);
785 return 1;
786 }
787
788 *host = strdup(gtk_entry_get_text(GTK_ENTRY(hentry)));
789 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
790
791 typeentry = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
792 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
793 *type = Fio_client_ipv4;
794 else if (!strncmp(typeentry, "IPv6", 4))
795 *type = Fio_client_ipv6;
796 else
797 *type = Fio_client_socket;
798 g_free(typeentry);
799
b9f3c7ed
JA
800 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
801
a7a42ce1
JA
802 gtk_widget_destroy(dialog);
803 return 0;
804}
805
0420ba6a
JA
806static void file_open(GtkWidget *w, gpointer data)
807{
808 GtkWidget *dialog;
809 GSList *filenames, *fn_glist;
810 GtkFileFilter *filter;
a7a42ce1 811 char *host;
b9f3c7ed 812 int port, type, server_start;
0420ba6a
JA
813
814 dialog = gtk_file_chooser_dialog_new("Open File",
815 GTK_WINDOW(ui.window),
816 GTK_FILE_CHOOSER_ACTION_OPEN,
817 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
818 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
819 NULL);
820 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
821
822 filter = gtk_file_filter_new();
823 gtk_file_filter_add_pattern(filter, "*.fio");
824 gtk_file_filter_add_pattern(filter, "*.job");
825 gtk_file_filter_add_mime_type(filter, "text/fio");
826 gtk_file_filter_set_name(filter, "Fio job file");
827 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
828
829 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
830 gtk_widget_destroy(dialog);
831 return;
832 }
833
834 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
a7a42ce1
JA
835
836 gtk_widget_destroy(dialog);
837
b9f3c7ed 838 if (get_connection_details(&host, &port, &type, &server_start))
a7a42ce1
JA
839 goto err;
840
0420ba6a
JA
841 filenames = fn_glist;
842 while (filenames != NULL) {
0420ba6a
JA
843 ui.job_files = realloc(ui.job_files, (ui.nr_job_files + 1) * sizeof(char *));
844 ui.job_files[ui.nr_job_files] = strdup(filenames->data);
845 ui.nr_job_files++;
846
a5276616 847 ui.client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
df06f220
JA
848 if (!ui.client) {
849 GError *error;
850
851 error = g_error_new(g_quark_from_string("fio"), 1,
852 "Failed to add client %s", host);
0420ba6a
JA
853 report_error(error);
854 g_error_free(error);
0420ba6a 855 }
df06f220 856 ui.client->client_data = &ui;
0420ba6a
JA
857
858 g_free(filenames->data);
859 filenames = g_slist_next(filenames);
860 }
a7a42ce1
JA
861 free(host);
862err:
0420ba6a 863 g_slist_free(fn_glist);
0420ba6a
JA
864}
865
866static void file_save(GtkWidget *w, gpointer data)
867{
868 GtkWidget *dialog;
869
870 dialog = gtk_file_chooser_dialog_new("Save File",
871 GTK_WINDOW(ui.window),
872 GTK_FILE_CHOOSER_ACTION_SAVE,
873 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
874 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
875 NULL);
876
877 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
878 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
879
880 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
881 char *filename;
882
883 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
884 // save_job_file(filename);
885 g_free(filename);
886 }
887 gtk_widget_destroy(dialog);
888}
889
46974a7d
JA
890static void preferences(GtkWidget *w, gpointer data)
891{
892 GtkWidget *dialog, *frame, *box, **buttons;
893 int i;
894
895 dialog = gtk_dialog_new_with_buttons("Preferences",
896 GTK_WINDOW(ui.window),
897 GTK_DIALOG_DESTROY_WITH_PARENT,
898 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
899 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
900 NULL);
901
0b8d11ed 902 frame = gtk_frame_new("Debug logging");
46974a7d
JA
903 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
904 box = gtk_hbox_new(FALSE, 6);
905 gtk_container_add(GTK_CONTAINER(frame), box);
906
907 buttons = malloc(sizeof(GtkWidget *) * FD_DEBUG_MAX);
908
909 for (i = 0; i < FD_DEBUG_MAX; i++) {
910 buttons[i] = gtk_check_button_new_with_label(debug_levels[i].name);
0b8d11ed 911 gtk_widget_set_tooltip_text(buttons[i], debug_levels[i].help);
46974a7d
JA
912 gtk_box_pack_start(GTK_BOX(box), buttons[i], FALSE, FALSE, 6);
913 }
914
915 gtk_widget_show_all(dialog);
916
917 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
918 gtk_widget_destroy(dialog);
919 return;
920 }
921
922 for (i = 0; i < FD_DEBUG_MAX; i++) {
923 int set;
924
925 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttons[i]));
926 if (set)
927 fio_debug |= (1UL << i);
928 }
929
930 gtk_widget_destroy(dialog);
931}
932
0420ba6a
JA
933static void about_dialog(GtkWidget *w, gpointer data)
934{
935 gtk_show_about_dialog(NULL,
936 "program-name", "gfio",
937 "comments", "Gtk2 UI for fio",
938 "license", "GPLv2",
939 "version", fio_version_string,
940 "copyright", "Jens Axboe <axboe@kernel.dk> 2012",
941 "logo-icon-name", "fio",
942 /* Must be last: */
943 NULL, NULL,
944 NULL);
945}
946
947static GtkActionEntry menu_items[] = {
46974a7d
JA
948 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
949 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
950 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
951 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
952 { "Preferences", GTK_STOCK_PREFERENCES, NULL, "<Control>p", NULL, G_CALLBACK(preferences) },
953 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
954 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
0420ba6a 955};
3e47bd25 956static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
0420ba6a
JA
957
958static const gchar *ui_string = " \
959 <ui> \
960 <menubar name=\"MainMenu\"> \
961 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
962 <menuitem name=\"Open\" action=\"OpenFile\" /> \
963 <menuitem name=\"Save\" action=\"SaveFile\" /> \
964 <separator name=\"Separator\"/> \
46974a7d
JA
965 <menuitem name=\"Preferences\" action=\"Preferences\" /> \
966 <separator name=\"Separator2\"/> \
0420ba6a
JA
967 <menuitem name=\"Quit\" action=\"Quit\" /> \
968 </menu> \
969 <menu name=\"Help\" action=\"HelpMenuAction\"> \
970 <menuitem name=\"About\" action=\"About\" /> \
971 </menu> \
972 </menubar> \
973 </ui> \
974";
975
976static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager)
977{
978 GtkActionGroup *action_group = gtk_action_group_new("Menu");
979 GError *error = 0;
980
981 action_group = gtk_action_group_new("Menu");
982 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, 0);
983
984 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
985 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
986
987 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
988 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
989}
990
991void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
992 GtkWidget *vbox, GtkUIManager *ui_manager)
993{
994 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
995}
996
ff1f3280
SC
997static void init_ui(int *argc, char **argv[], struct gui *ui)
998{
0420ba6a
JA
999 GtkSettings *settings;
1000 GtkUIManager *uimanager;
843ad237 1001 GtkWidget *menu, *probe, *probe_frame, *probe_box;
0420ba6a
JA
1002
1003 memset(ui, 0, sizeof(*ui));
45032dd8 1004
2839f0c6 1005 /* Magical g*thread incantation, you just need this thread stuff.
04cc6b77 1006 * Without it, the update that happens in gfio_update_thread_status
2839f0c6
SC
1007 * doesn't really happen in a timely fashion, you need expose events
1008 */
ed727a46 1009 if (!g_thread_supported())
2839f0c6
SC
1010 g_thread_init(NULL);
1011 gdk_threads_init();
1012
ff1f3280 1013 gtk_init(argc, argv);
0420ba6a
JA
1014 settings = gtk_settings_get_default();
1015 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
1016 g_type_init();
ff1f3280
SC
1017
1018 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1019 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
1020 gtk_window_set_default_size(GTK_WINDOW(ui->window), 700, 500);
1021
0420ba6a
JA
1022 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
1023 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
ff1f3280 1024
5b7573ab
SC
1025 ui->vbox = gtk_vbox_new(FALSE, 0);
1026 gtk_container_add(GTK_CONTAINER (ui->window), ui->vbox);
04cc6b77 1027
0420ba6a
JA
1028 uimanager = gtk_ui_manager_new();
1029 menu = get_menubar_menu(ui->window, uimanager);
1030 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
1031
c36f98d9
SC
1032 /*
1033 * Set up alignments for widgets at the top of ui,
1034 * align top left, expand horizontally but not vertically
1035 */
1036 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
3ec62ec4 1037 ui->topvbox = gtk_vbox_new(FALSE, 3);
c36f98d9 1038 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
e164534f 1039 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->topalign, FALSE, FALSE, 0);
c36f98d9 1040
3e47bd25 1041 probe = gtk_frame_new("Job");
843ad237
JA
1042 gtk_box_pack_start(GTK_BOX(ui->topvbox), probe, TRUE, FALSE, 3);
1043 probe_frame = gtk_vbox_new(FALSE, 3);
1044 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
1045
1046 probe_box = gtk_hbox_new(FALSE, 3);
1047 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
843ad237
JA
1048 ui->probe.hostname = new_info_label_in_frame(probe_box, "Host");
1049 ui->probe.os = new_info_label_in_frame(probe_box, "OS");
1050 ui->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
1051 ui->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
1052
3e47bd25
JA
1053 probe_box = gtk_hbox_new(FALSE, 3);
1054 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
807f9971
JA
1055
1056 ui->eta.name = new_info_label_in_frame(probe_box, "Name");
1057 ui->eta.iotype = new_info_label_in_frame(probe_box, "IO");
1058 ui->eta.ioengine = new_info_label_in_frame(probe_box, "IO Engine");
1059 ui->eta.iodepth = new_info_label_in_frame(probe_box, "IO Depth");
3e47bd25
JA
1060 ui->eta.jobs = new_info_label_in_frame(probe_box, "Jobs");
1061 ui->eta.files = new_info_label_in_frame(probe_box, "Open files");
1062
1063 probe_box = gtk_hbox_new(FALSE, 3);
1064 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
1065 ui->eta.read_bw = new_info_label_in_frame(probe_box, "Read BW");
1066 ui->eta.read_iops = new_info_label_in_frame(probe_box, "IOPS");
807f9971
JA
1067 ui->eta.write_bw = new_info_label_in_frame(probe_box, "Write BW");
1068 ui->eta.write_iops = new_info_label_in_frame(probe_box, "IOPS");
3e47bd25 1069
807f9971
JA
1070 /*
1071 * Only add this if we have a commit rate
1072 */
1073#if 0
3e47bd25
JA
1074 probe_box = gtk_hbox_new(FALSE, 3);
1075 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
807f9971
JA
1076
1077 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
1078 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
1079
3e47bd25
JA
1080 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
1081 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
807f9971 1082#endif
3e47bd25 1083
736f2dff
SC
1084 /*
1085 * Add a text box for text op messages
1086 */
1087 ui->textview = gtk_text_view_new();
1088 ui->text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ui->textview));
1089 gtk_text_buffer_set_text(ui->text, "", -1);
1090 gtk_text_view_set_editable(GTK_TEXT_VIEW(ui->textview), FALSE);
1091 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ui->textview), FALSE);
1092 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1093 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
1094 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1095 gtk_container_add(GTK_CONTAINER(ui->scrolled_window), ui->textview);
e164534f
SC
1096 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->scrolled_window,
1097 TRUE, TRUE, 0);
736f2dff 1098
c36f98d9
SC
1099 /*
1100 * Set up alignments for widgets at the bottom of ui,
1101 * align bottom left, expand horizontally but not vertically
1102 */
1103 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
1104 ui->buttonbox = gtk_hbox_new(FALSE, 0);
1105 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
e164534f
SC
1106 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->bottomalign,
1107 FALSE, FALSE, 0);
c36f98d9 1108
f3074008 1109 add_buttons(ui, buttonspeclist, ARRAYSIZE(buttonspeclist));
3ec62ec4
JA
1110
1111 /*
1112 * Set up thread status progress bar
1113 */
1114 ui->thread_status_pb = gtk_progress_bar_new();
1115 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
8663ea65 1116 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
3ec62ec4
JA
1117 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
1118
1119
ff1f3280
SC
1120 gtk_widget_show_all(ui->window);
1121}
1122
8232e285 1123int main(int argc, char *argv[], char *envp[])
ff1f3280 1124{
8232e285
SC
1125 if (initialize_fio(envp))
1126 return 1;
0420ba6a
JA
1127 if (fio_init_options())
1128 return 1;
a1820207 1129
ff1f3280 1130 init_ui(&argc, &argv, &ui);
5b7573ab 1131
2839f0c6 1132 gdk_threads_enter();
ff1f3280 1133 gtk_main();
2839f0c6 1134 gdk_threads_leave();
ff1f3280
SC
1135 return 0;
1136}