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