blob: e92ab03146277e3de7e04aa1365a586d471dff53 [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>
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 */
Stephen M. Cameron8232e282012-02-24 08:17:31 +010023#include <locale.h>
Stephen M. Cameron60f6b332012-02-24 08:17:32 +010024#include <malloc.h>
Stephen M. Cameron8232e282012-02-24 08:17:31 +010025
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +010026#include <glib.h>
Stephen M. Cameronff1f3282012-02-24 08:17:30 +010027#include <gtk/gtk.h>
28
Stephen M. Cameron8232e282012-02-24 08:17:31 +010029#include "fio.h"
30
Jens Axboe3e47bd22012-02-29 13:45:02 +010031static void gfio_update_thread_status(char *status_message, double perc);
32
Stephen M. Cameronf3074002012-02-24 08:17:30 +010033#define ARRAYSIZE(x) (sizeof((x)) / (sizeof((x)[0])))
34
35typedef void (*clickfunction)(GtkWidget *widget, gpointer data);
36
Jens Axboe3e47bd22012-02-29 13:45:02 +010037static void connect_clicked(GtkWidget *widget, gpointer data);
Stephen M. Cameronf3074002012-02-24 08:17:30 +010038static void start_job_clicked(GtkWidget *widget, gpointer data);
39
40static struct button_spec {
41 const char *buttontext;
42 clickfunction f;
43 const char *tooltiptext;
Jens Axboe3e47bd22012-02-29 13:45:02 +010044 const int start_insensitive;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010045} buttonspeclist[] = {
Jens Axboe3e47bd22012-02-29 13:45:02 +010046#define CONNECT_BUTTON 0
47#define START_JOB_BUTTON 1
48 { "Connect", connect_clicked, "Connect to host", 0 },
Stephen M. Cameronf3074002012-02-24 08:17:30 +010049 { "Start Job",
50 start_job_clicked,
Jens Axboe3e47bd22012-02-29 13:45:02 +010051 "Send current fio job to fio server to be executed", 1 },
Stephen M. Cameronf3074002012-02-24 08:17:30 +010052};
53
Jens Axboe843ad232012-02-29 11:44:53 +010054struct probe_widget {
55 GtkWidget *hostname;
56 GtkWidget *os;
57 GtkWidget *arch;
58 GtkWidget *fio_ver;
59};
60
Jens Axboe3e47bd22012-02-29 13:45:02 +010061struct eta_widget {
Jens Axboe807f9972012-03-02 10:25:24 +010062 GtkWidget *name;
63 GtkWidget *iotype;
64 GtkWidget *ioengine;
65 GtkWidget *iodepth;
Jens Axboe3e47bd22012-02-29 13:45:02 +010066 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
Stephen M. Cameronff1f3282012-02-24 08:17:30 +010078struct gui {
79 GtkWidget *window;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +010080 GtkWidget *vbox;
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +010081 GtkWidget *topvbox;
82 GtkWidget *topalign;
83 GtkWidget *bottomalign;
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +010084 GtkWidget *thread_status_pb;
Stephen M. Cameronf3074002012-02-24 08:17:30 +010085 GtkWidget *buttonbox;
86 GtkWidget *button[ARRAYSIZE(buttonspeclist)];
Stephen M. Cameron736f2df2012-02-24 08:17:32 +010087 GtkWidget *scrolled_window;
88 GtkWidget *textview;
Jens Axboe0420ba62012-02-29 11:16:52 +010089 GtkWidget *error_info_bar;
90 GtkWidget *error_label;
Stephen M. Cameron736f2df2012-02-24 08:17:32 +010091 GtkTextBuffer *text;
Jens Axboe843ad232012-02-29 11:44:53 +010092 struct probe_widget probe;
Jens Axboe3e47bd22012-02-29 13:45:02 +010093 struct eta_widget eta;
Jens Axboe3ec62ec2012-03-01 12:01:29 +010094 int connected;
Stephen M. Cameron25927252012-02-24 08:17:31 +010095 pthread_t t;
Jens Axboe0420ba62012-02-29 11:16:52 +010096
Jens Axboe3ec62ec2012-03-01 12:01:29 +010097 struct fio_client *client;
Jens Axboe0420ba62012-02-29 11:16:52 +010098 int nr_job_files;
99 char **job_files;
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100100} ui;
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100101
Jens Axboe8663ea62012-03-02 14:04:30 +0100102static 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
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100120static void gfio_set_connected(struct gui *ui, int connected)
121{
122 if (connected) {
123 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
124 ui->connected = 1;
125 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Disconnect");
126 } else {
127 ui->connected = 0;
128 gtk_button_set_label(GTK_BUTTON(ui->button[CONNECT_BUTTON]), "Connect");
129 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
Jens Axboe8663ea62012-03-02 14:04:30 +0100130 clear_ui_info(ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100131 }
132}
133
Stephen M. Camerona1820202012-02-24 08:17:31 +0100134static void gfio_text_op(struct fio_client *client,
135 FILE *f, __u16 pdu_len, const char *buf)
136{
Jens Axboe807f9972012-03-02 10:25:24 +0100137#if 0
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100138 GtkTextBuffer *buffer;
139 GtkTextIter end;
140
141 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ui.textview));
142 gdk_threads_enter();
143 gtk_text_buffer_get_end_iter(buffer, &end);
144 gtk_text_buffer_insert(buffer, &end, buf, -1);
145 gdk_threads_leave();
146 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ui.textview),
147 &end, 0.0, FALSE, 0.0,0.0);
Jens Axboe807f9972012-03-02 10:25:24 +0100148#else
149 fio_client_ops.text_op(client, f, pdu_len, buf);
150#endif
Stephen M. Camerona1820202012-02-24 08:17:31 +0100151}
152
153static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
154{
155 printf("gfio_disk_util_op called\n");
156 fio_client_ops.disk_util(client, cmd);
157}
158
159static void gfio_thread_status_op(struct fio_net_cmd *cmd)
160{
161 printf("gfio_thread_status_op called\n");
162 fio_client_ops.thread_status(cmd);
163}
164
165static void gfio_group_stats_op(struct fio_net_cmd *cmd)
166{
167 printf("gfio_group_stats_op called\n");
168 fio_client_ops.group_stats(cmd);
169}
170
Jens Axboe3e47bd22012-02-29 13:45:02 +0100171static void gfio_update_eta(struct jobs_eta *je)
172{
173 static int eta_good;
174 char eta_str[128];
175 char output[256];
176 char tmp[32];
177 double perc = 0.0;
178 int i2p = 0;
179
180 eta_str[0] = '\0';
181 output[0] = '\0';
182
183 if (je->eta_sec != INT_MAX && je->elapsed_sec) {
184 perc = (double) je->elapsed_sec / (double) (je->elapsed_sec + je->eta_sec);
185 eta_to_str(eta_str, je->eta_sec);
186 }
187
188 sprintf(tmp, "%u", je->nr_running);
189 gtk_label_set_text(GTK_LABEL(ui.eta.jobs), tmp);
190 sprintf(tmp, "%u", je->files_open);
191 gtk_label_set_text(GTK_LABEL(ui.eta.files), tmp);
192
193#if 0
194 if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
195 if (je->m_rate || je->t_rate) {
196 char *tr, *mr;
197
198 mr = num2str(je->m_rate, 4, 0, i2p);
199 tr = num2str(je->t_rate, 4, 0, i2p);
200 gtk_label_set_text(GTK_LABEL(ui.eta.
201 p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
202 free(tr);
203 free(mr);
204 } else if (je->m_iops || je->t_iops)
205 p += sprintf(p, ", CR=%d/%d IOPS", je->t_iops, je->m_iops);
Jens Axboeebbd89c2012-03-02 11:21:13 +0100206
Jens Axboe3e47bd22012-02-29 13:45:02 +0100207 gtk_label_set_text(GTK_LABEL(ui.eta.cr_bw), "---");
208 gtk_label_set_text(GTK_LABEL(ui.eta.cr_iops), "---");
209 gtk_label_set_text(GTK_LABEL(ui.eta.cw_bw), "---");
210 gtk_label_set_text(GTK_LABEL(ui.eta.cw_iops), "---");
211#endif
212
213 if (je->eta_sec != INT_MAX && je->nr_running) {
214 char *iops_str[2];
215 char *rate_str[2];
216
217 if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
218 strcpy(output, "-.-% done");
219 else {
220 eta_good = 1;
221 perc *= 100.0;
222 sprintf(output, "%3.1f%% done", perc);
223 }
224
225 rate_str[0] = num2str(je->rate[0], 5, 10, i2p);
226 rate_str[1] = num2str(je->rate[1], 5, 10, i2p);
227
228 iops_str[0] = num2str(je->iops[0], 4, 1, 0);
229 iops_str[1] = num2str(je->iops[1], 4, 1, 0);
230
231 gtk_label_set_text(GTK_LABEL(ui.eta.read_bw), rate_str[0]);
232 gtk_label_set_text(GTK_LABEL(ui.eta.read_iops), iops_str[0]);
233 gtk_label_set_text(GTK_LABEL(ui.eta.write_bw), rate_str[1]);
234 gtk_label_set_text(GTK_LABEL(ui.eta.write_iops), iops_str[1]);
235
236 free(rate_str[0]);
237 free(rate_str[1]);
238 free(iops_str[0]);
239 free(iops_str[1]);
240 }
241
242 if (eta_str[0]) {
243 char *dst = output + strlen(output);
244
245 sprintf(dst, " - %s", eta_str);
246 }
247
248 gfio_update_thread_status(output, perc);
249}
250
Stephen M. Camerona1820202012-02-24 08:17:31 +0100251static void gfio_eta_op(struct fio_client *client, struct fio_net_cmd *cmd)
252{
Jens Axboe3e47bd22012-02-29 13:45:02 +0100253 struct jobs_eta *je = (struct jobs_eta *) cmd->payload;
254 struct client_eta *eta = (struct client_eta *) (uintptr_t) cmd->tag;
255
256 client->eta_in_flight = NULL;
257 flist_del_init(&client->eta_list);
258
259 fio_client_convert_jobs_eta(je);
260 fio_client_sum_jobs_eta(&eta->eta, je);
261 fio_client_dec_jobs_eta(eta, gfio_update_eta);
Stephen M. Camerona1820202012-02-24 08:17:31 +0100262}
263
264static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
265{
Jens Axboe843ad232012-02-29 11:44:53 +0100266 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
267 const char *os, *arch;
268 char buf[64];
269
270 os = fio_get_os_string(probe->os);
271 if (!os)
272 os = "unknown";
273
274 arch = fio_get_arch_string(probe->arch);
275 if (!arch)
276 os = "unknown";
277
278 if (!client->name)
279 client->name = strdup((char *) probe->hostname);
280
281 gtk_label_set_text(GTK_LABEL(ui.probe.hostname), (char *) probe->hostname);
282 gtk_label_set_text(GTK_LABEL(ui.probe.os), os);
283 gtk_label_set_text(GTK_LABEL(ui.probe.arch), arch);
284 sprintf(buf, "%u.%u.%u", probe->fio_major, probe->fio_minor, probe->fio_patch);
285 gtk_label_set_text(GTK_LABEL(ui.probe.fio_ver), buf);
Stephen M. Camerona1820202012-02-24 08:17:31 +0100286}
287
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +0100288static void gfio_update_thread_status(char *status_message, double perc)
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100289{
290 static char message[100];
291 const char *m = message;
292
293 strncpy(message, status_message, sizeof(message) - 1);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +0100294 gtk_progress_bar_set_text(
295 GTK_PROGRESS_BAR(ui.thread_status_pb), m);
296 gtk_progress_bar_set_fraction(
297 GTK_PROGRESS_BAR(ui.thread_status_pb), perc / 100.0);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100298 gdk_threads_enter();
299 gtk_widget_queue_draw(ui.window);
300 gdk_threads_leave();
301}
302
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100303static void gfio_quit_op(struct fio_client *client)
304{
305 struct gui *ui = client->client_data;
306
307 gfio_set_connected(ui, 0);
308}
309
Jens Axboe807f9972012-03-02 10:25:24 +0100310static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
311{
312 struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
313 struct gui *ui = client->client_data;
314 char tmp[8];
315 int i;
316
317 p->iodepth = le32_to_cpu(p->iodepth);
318 p->rw = le32_to_cpu(p->rw);
319
320 for (i = 0; i < 2; i++) {
321 p->min_bs[i] = le32_to_cpu(p->min_bs[i]);
322 p->max_bs[i] = le32_to_cpu(p->max_bs[i]);
323 }
324
325 p->numjobs = le32_to_cpu(p->numjobs);
326 p->group_reporting = le32_to_cpu(p->group_reporting);
327
328 gtk_label_set_text(GTK_LABEL(ui->eta.name), (gchar *) p->jobname);
329 gtk_label_set_text(GTK_LABEL(ui->eta.iotype), ddir_str(p->rw));
330 gtk_label_set_text(GTK_LABEL(ui->eta.ioengine), (gchar *) p->ioengine);
331
332 sprintf(tmp, "%u", p->iodepth);
333 gtk_label_set_text(GTK_LABEL(ui->eta.iodepth), tmp);
334}
335
Jens Axboeed727a42012-03-02 12:14:40 +0100336static void gfio_client_timed_out(struct fio_client *client)
337{
338 struct gui *ui = client->client_data;
339 GtkWidget *dialog, *label, *content;
340 char buf[256];
341
342 gdk_threads_enter();
343
344 gfio_set_connected(ui, 0);
345
346 sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
347
348 dialog = gtk_dialog_new_with_buttons("Timed out!",
349 GTK_WINDOW(ui->window),
350 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
351 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
352
353 content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
354 label = gtk_label_new((const gchar *) buf);
355 gtk_container_add(GTK_CONTAINER(content), label);
356 gtk_widget_show_all(dialog);
357 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
358
359 gtk_dialog_run(GTK_DIALOG(dialog));
360 gtk_widget_destroy(dialog);
361
362 gdk_threads_leave();
363}
364
Stephen M. Camerona1820202012-02-24 08:17:31 +0100365struct client_ops gfio_client_ops = {
Jens Axboe0420ba62012-02-29 11:16:52 +0100366 .text_op = gfio_text_op,
367 .disk_util = gfio_disk_util_op,
368 .thread_status = gfio_thread_status_op,
369 .group_stats = gfio_group_stats_op,
370 .eta = gfio_eta_op,
371 .probe = gfio_probe_op,
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100372 .quit = gfio_quit_op,
Jens Axboe807f9972012-03-02 10:25:24 +0100373 .add_job = gfio_add_job_op,
Jens Axboeed727a42012-03-02 12:14:40 +0100374 .timed_out = gfio_client_timed_out,
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100375 .stay_connected = 1,
Stephen M. Camerona1820202012-02-24 08:17:31 +0100376};
377
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100378static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
379 __attribute__((unused)) gpointer data)
380{
381 gtk_main_quit();
382}
383
Stephen M. Cameron25927252012-02-24 08:17:31 +0100384static void *job_thread(void *arg)
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100385{
Stephen M. Cameron25927252012-02-24 08:17:31 +0100386 fio_handle_clients(&gfio_client_ops);
Stephen M. Cameron25927252012-02-24 08:17:31 +0100387 return NULL;
388}
389
Jens Axboe0420ba62012-02-29 11:16:52 +0100390static int send_job_files(struct gui *ui)
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100391{
Jens Axboe441013b2012-03-01 08:01:52 +0100392 int i, ret = 0;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100393
Jens Axboe0420ba62012-02-29 11:16:52 +0100394 for (i = 0; i < ui->nr_job_files; i++) {
395 ret = fio_clients_send_ini(ui->job_files[i]);
Jens Axboe441013b2012-03-01 08:01:52 +0100396 if (ret)
397 break;
398
Jens Axboe0420ba62012-02-29 11:16:52 +0100399 free(ui->job_files[i]);
400 ui->job_files[i] = NULL;
Jens Axboe441013b2012-03-01 08:01:52 +0100401 }
402 while (i < ui->nr_job_files) {
403 free(ui->job_files[i]);
404 ui->job_files[i] = NULL;
405 i++;
Jens Axboe0420ba62012-02-29 11:16:52 +0100406 }
407
Jens Axboe441013b2012-03-01 08:01:52 +0100408 return ret;
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100409}
410
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100411static void start_job_thread(struct gui *ui)
Stephen M. Cameron25927252012-02-24 08:17:31 +0100412{
Jens Axboe0420ba62012-02-29 11:16:52 +0100413 if (send_job_files(ui)) {
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100414 printf("Yeah, I didn't really like those options too much.\n");
Stephen M. Cameron60f6b332012-02-24 08:17:32 +0100415 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
416 return;
417 }
Stephen M. Cameron25927252012-02-24 08:17:31 +0100418}
419
Jens Axboea7a42ce2012-03-02 13:12:04 +0100420static GtkWidget *new_info_label_in_frame(GtkWidget *box, const char *label)
421{
422 GtkWidget *label_widget;
423 GtkWidget *frame;
424
425 frame = gtk_frame_new(label);
426 label_widget = gtk_label_new(NULL);
427 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 3);
428 gtk_container_add(GTK_CONTAINER(frame), label_widget);
429
430 return label_widget;
431}
432
Jens Axboea7a42ce2012-03-02 13:12:04 +0100433static GtkWidget *create_spinbutton(GtkWidget *hbox, double min, double max, double defval)
434{
435 GtkWidget *button, *box;
436
437 box = gtk_hbox_new(FALSE, 3);
438 gtk_container_add(GTK_CONTAINER(hbox), box);
439
440 button = gtk_spin_button_new_with_range(min, max, 1.0);
441 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
442
443 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(button), GTK_UPDATE_IF_VALID);
444 gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), defval);
445
446 return button;
447}
448
Stephen M. Cameron25927252012-02-24 08:17:31 +0100449static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
450 gpointer data)
451{
452 struct gui *ui = data;
453
Stephen M. Cameron25927252012-02-24 08:17:31 +0100454 gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100455 start_job_thread(ui);
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100456}
457
Jens Axboedf06f222012-03-02 13:32:04 +0100458static void file_open(GtkWidget *w, gpointer data);
459
460static void connect_clicked(GtkWidget *widget, gpointer data)
Jens Axboe3e47bd22012-02-29 13:45:02 +0100461{
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100462 struct gui *ui = data;
463
464 if (!ui->connected) {
Jens Axboedf06f222012-03-02 13:32:04 +0100465 if (!ui->nr_job_files)
466 file_open(widget, data);
Jens Axboe8663ea62012-03-02 14:04:30 +0100467 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100468 fio_clients_connect();
469 pthread_create(&ui->t, NULL, job_thread, NULL);
470 gfio_set_connected(ui, 1);
Jens Axboedf06f222012-03-02 13:32:04 +0100471 } else {
472 fio_clients_terminate();
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100473 gfio_set_connected(ui, 0);
Jens Axboedf06f222012-03-02 13:32:04 +0100474 }
Jens Axboe3e47bd22012-02-29 13:45:02 +0100475}
476
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100477static void add_button(struct gui *ui, int i, GtkWidget *buttonbox,
478 struct button_spec *buttonspec)
479{
480 ui->button[i] = gtk_button_new_with_label(buttonspec->buttontext);
481 g_signal_connect(ui->button[i], "clicked", G_CALLBACK (buttonspec->f), ui);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100482 gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], FALSE, FALSE, 3);
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100483 gtk_widget_set_tooltip_text(ui->button[i], buttonspeclist[i].tooltiptext);
Jens Axboe3e47bd22012-02-29 13:45:02 +0100484 gtk_widget_set_sensitive(ui->button[i], !buttonspec->start_insensitive);
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100485}
486
487static void add_buttons(struct gui *ui,
488 struct button_spec *buttonlist,
489 int nbuttons)
490{
491 int i;
492
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100493 for (i = 0; i < nbuttons; i++)
494 add_button(ui, i, ui->buttonbox, &buttonlist[i]);
495}
496
Jens Axboe0420ba62012-02-29 11:16:52 +0100497static void on_info_bar_response(GtkWidget *widget, gint response,
498 gpointer data)
499{
500 if (response == GTK_RESPONSE_OK) {
501 gtk_widget_destroy(widget);
502 ui.error_info_bar = NULL;
503 }
504}
505
Jens Axboedf06f222012-03-02 13:32:04 +0100506void report_error(GError *error)
Jens Axboe0420ba62012-02-29 11:16:52 +0100507{
508 if (ui.error_info_bar == NULL) {
509 ui.error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
510 GTK_RESPONSE_OK,
511 NULL);
512 g_signal_connect(ui.error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
513 gtk_info_bar_set_message_type(GTK_INFO_BAR(ui.error_info_bar),
514 GTK_MESSAGE_ERROR);
515
516 ui.error_label = gtk_label_new(error->message);
517 GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(ui.error_info_bar));
518 gtk_container_add(GTK_CONTAINER(container), ui.error_label);
519
520 gtk_box_pack_start(GTK_BOX(ui.vbox), ui.error_info_bar, FALSE, FALSE, 0);
521 gtk_widget_show_all(ui.vbox);
522 } else {
523 char buffer[256];
524 snprintf(buffer, sizeof(buffer), "Failed to open file.");
525 gtk_label_set(GTK_LABEL(ui.error_label), buffer);
526 }
527}
528
Jens Axboeb9f3c7e2012-03-02 14:27:17 +0100529static int get_connection_details(char **host, int *port, int *type,
530 int *server_start)
Jens Axboea7a42ce2012-03-02 13:12:04 +0100531{
532 GtkWidget *dialog, *box, *vbox, *hentry, *hbox, *frame, *pentry, *combo;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +0100533 GtkWidget *button;
Jens Axboea7a42ce2012-03-02 13:12:04 +0100534 char *typeentry;
535
536 dialog = gtk_dialog_new_with_buttons("Connection details",
537 GTK_WINDOW(ui.window),
538 GTK_DIALOG_DESTROY_WITH_PARENT,
539 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
540 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
541
542 frame = gtk_frame_new("Hostname / socket name");
543 vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
544 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
545
546 box = gtk_vbox_new(FALSE, 6);
547 gtk_container_add(GTK_CONTAINER(frame), box);
548
549 hbox = gtk_hbox_new(TRUE, 10);
550 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
551 hentry = gtk_entry_new();
552 gtk_entry_set_text(GTK_ENTRY(hentry), "localhost");
553 gtk_box_pack_start(GTK_BOX(hbox), hentry, TRUE, TRUE, 0);
554
555 frame = gtk_frame_new("Port");
556 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
557 box = gtk_vbox_new(FALSE, 10);
558 gtk_container_add(GTK_CONTAINER(frame), box);
559
560 hbox = gtk_hbox_new(TRUE, 4);
561 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
562 pentry = create_spinbutton(hbox, 1, 65535, FIO_NET_PORT);
563
564 frame = gtk_frame_new("Type");
565 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
566 box = gtk_vbox_new(FALSE, 10);
567 gtk_container_add(GTK_CONTAINER(frame), box);
568
569 hbox = gtk_hbox_new(TRUE, 4);
570 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
571
572 combo = gtk_combo_box_text_new();
573 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "IPv4");
574 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "IPv6");
575 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "local socket");
576 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
577
578 gtk_container_add(GTK_CONTAINER(hbox), combo);
579
Jens Axboeb9f3c7e2012-03-02 14:27:17 +0100580 frame = gtk_frame_new("Options");
581 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
582 box = gtk_vbox_new(FALSE, 10);
583 gtk_container_add(GTK_CONTAINER(frame), box);
584
585 hbox = gtk_hbox_new(TRUE, 4);
586 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
587
588 button = gtk_check_button_new_with_label("Auto-spawn fio backend");
589 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), 1);
590 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.");
591 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 6);
592
Jens Axboea7a42ce2012-03-02 13:12:04 +0100593 gtk_widget_show_all(dialog);
594
595 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
596 gtk_widget_destroy(dialog);
597 return 1;
598 }
599
600 *host = strdup(gtk_entry_get_text(GTK_ENTRY(hentry)));
601 *port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pentry));
602
603 typeentry = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
604 if (!typeentry || !strncmp(typeentry, "IPv4", 4))
605 *type = Fio_client_ipv4;
606 else if (!strncmp(typeentry, "IPv6", 4))
607 *type = Fio_client_ipv6;
608 else
609 *type = Fio_client_socket;
610 g_free(typeentry);
611
Jens Axboeb9f3c7e2012-03-02 14:27:17 +0100612 *server_start = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
613
Jens Axboea7a42ce2012-03-02 13:12:04 +0100614 gtk_widget_destroy(dialog);
615 return 0;
616}
617
Jens Axboe0420ba62012-02-29 11:16:52 +0100618static void file_open(GtkWidget *w, gpointer data)
619{
620 GtkWidget *dialog;
621 GSList *filenames, *fn_glist;
622 GtkFileFilter *filter;
Jens Axboea7a42ce2012-03-02 13:12:04 +0100623 char *host;
Jens Axboeb9f3c7e2012-03-02 14:27:17 +0100624 int port, type, server_start;
Jens Axboe0420ba62012-02-29 11:16:52 +0100625
626 dialog = gtk_file_chooser_dialog_new("Open File",
627 GTK_WINDOW(ui.window),
628 GTK_FILE_CHOOSER_ACTION_OPEN,
629 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
630 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
631 NULL);
632 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
633
634 filter = gtk_file_filter_new();
635 gtk_file_filter_add_pattern(filter, "*.fio");
636 gtk_file_filter_add_pattern(filter, "*.job");
637 gtk_file_filter_add_mime_type(filter, "text/fio");
638 gtk_file_filter_set_name(filter, "Fio job file");
639 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
640
641 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
642 gtk_widget_destroy(dialog);
643 return;
644 }
645
646 fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Jens Axboea7a42ce2012-03-02 13:12:04 +0100647
648 gtk_widget_destroy(dialog);
649
Jens Axboeb9f3c7e2012-03-02 14:27:17 +0100650 if (get_connection_details(&host, &port, &type, &server_start))
Jens Axboea7a42ce2012-03-02 13:12:04 +0100651 goto err;
652
Jens Axboe0420ba62012-02-29 11:16:52 +0100653 filenames = fn_glist;
654 while (filenames != NULL) {
Jens Axboe0420ba62012-02-29 11:16:52 +0100655 ui.job_files = realloc(ui.job_files, (ui.nr_job_files + 1) * sizeof(char *));
656 ui.job_files[ui.nr_job_files] = strdup(filenames->data);
657 ui.nr_job_files++;
658
Jens Axboea7a42ce2012-03-02 13:12:04 +0100659 ui.client = fio_client_add_explicit(host, type, port);
Jens Axboedf06f222012-03-02 13:32:04 +0100660 if (!ui.client) {
661 GError *error;
662
663 error = g_error_new(g_quark_from_string("fio"), 1,
664 "Failed to add client %s", host);
Jens Axboe0420ba62012-02-29 11:16:52 +0100665 report_error(error);
666 g_error_free(error);
Jens Axboe0420ba62012-02-29 11:16:52 +0100667 }
Jens Axboedf06f222012-03-02 13:32:04 +0100668 ui.client->client_data = &ui;
Jens Axboe0420ba62012-02-29 11:16:52 +0100669
670 g_free(filenames->data);
671 filenames = g_slist_next(filenames);
672 }
Jens Axboea7a42ce2012-03-02 13:12:04 +0100673 free(host);
674err:
Jens Axboe0420ba62012-02-29 11:16:52 +0100675 g_slist_free(fn_glist);
Jens Axboe0420ba62012-02-29 11:16:52 +0100676}
677
678static void file_save(GtkWidget *w, gpointer data)
679{
680 GtkWidget *dialog;
681
682 dialog = gtk_file_chooser_dialog_new("Save File",
683 GTK_WINDOW(ui.window),
684 GTK_FILE_CHOOSER_ACTION_SAVE,
685 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
686 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
687 NULL);
688
689 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
690 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
691
692 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
693 char *filename;
694
695 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
696 // save_job_file(filename);
697 g_free(filename);
698 }
699 gtk_widget_destroy(dialog);
700}
701
702static void about_dialog(GtkWidget *w, gpointer data)
703{
704 gtk_show_about_dialog(NULL,
705 "program-name", "gfio",
706 "comments", "Gtk2 UI for fio",
707 "license", "GPLv2",
708 "version", fio_version_string,
709 "copyright", "Jens Axboe <axboe@kernel.dk> 2012",
710 "logo-icon-name", "fio",
711 /* Must be last: */
712 NULL, NULL,
713 NULL);
714}
715
716static GtkActionEntry menu_items[] = {
717 { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
718 { "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
719 { "OpenFile", GTK_STOCK_OPEN, NULL, "<Control>O", NULL, G_CALLBACK(file_open) },
720 { "SaveFile", GTK_STOCK_SAVE, NULL, "<Control>S", NULL, G_CALLBACK(file_save) },
721 { "Quit", GTK_STOCK_QUIT, NULL, "<Control>Q", NULL, G_CALLBACK(quit_clicked) },
722 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
723};
Jens Axboe3e47bd22012-02-29 13:45:02 +0100724static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
Jens Axboe0420ba62012-02-29 11:16:52 +0100725
726static const gchar *ui_string = " \
727 <ui> \
728 <menubar name=\"MainMenu\"> \
729 <menu name=\"FileMenu\" action=\"FileMenuAction\"> \
730 <menuitem name=\"Open\" action=\"OpenFile\" /> \
731 <menuitem name=\"Save\" action=\"SaveFile\" /> \
732 <separator name=\"Separator\"/> \
733 <menuitem name=\"Quit\" action=\"Quit\" /> \
734 </menu> \
735 <menu name=\"Help\" action=\"HelpMenuAction\"> \
736 <menuitem name=\"About\" action=\"About\" /> \
737 </menu> \
738 </menubar> \
739 </ui> \
740";
741
742static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager)
743{
744 GtkActionGroup *action_group = gtk_action_group_new("Menu");
745 GError *error = 0;
746
747 action_group = gtk_action_group_new("Menu");
748 gtk_action_group_add_actions(action_group, menu_items, nmenu_items, 0);
749
750 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
751 gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
752
753 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
754 return gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
755}
756
757void gfio_ui_setup(GtkSettings *settings, GtkWidget *menubar,
758 GtkWidget *vbox, GtkUIManager *ui_manager)
759{
760 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
761}
762
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100763static void init_ui(int *argc, char **argv[], struct gui *ui)
764{
Jens Axboe0420ba62012-02-29 11:16:52 +0100765 GtkSettings *settings;
766 GtkUIManager *uimanager;
Jens Axboe843ad232012-02-29 11:44:53 +0100767 GtkWidget *menu, *probe, *probe_frame, *probe_box;
Jens Axboe0420ba62012-02-29 11:16:52 +0100768
769 memset(ui, 0, sizeof(*ui));
Stephen M. Cameron45032dd2012-02-24 08:17:31 +0100770
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +0100771 /* Magical g*thread incantation, you just need this thread stuff.
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +0100772 * Without it, the update that happens in gfio_update_thread_status
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +0100773 * doesn't really happen in a timely fashion, you need expose events
774 */
Jens Axboeed727a42012-03-02 12:14:40 +0100775 if (!g_thread_supported())
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +0100776 g_thread_init(NULL);
777 gdk_threads_init();
778
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100779 gtk_init(argc, argv);
Jens Axboe0420ba62012-02-29 11:16:52 +0100780 settings = gtk_settings_get_default();
781 gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "gfio setting");
782 g_type_init();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100783
784 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
785 gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
786 gtk_window_set_default_size(GTK_WINDOW(ui->window), 700, 500);
787
Jens Axboe0420ba62012-02-29 11:16:52 +0100788 g_signal_connect(ui->window, "delete-event", G_CALLBACK(quit_clicked), NULL);
789 g_signal_connect(ui->window, "destroy", G_CALLBACK(quit_clicked), NULL);
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100790
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100791 ui->vbox = gtk_vbox_new(FALSE, 0);
792 gtk_container_add(GTK_CONTAINER (ui->window), ui->vbox);
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +0100793
Jens Axboe0420ba62012-02-29 11:16:52 +0100794 uimanager = gtk_ui_manager_new();
795 menu = get_menubar_menu(ui->window, uimanager);
796 gfio_ui_setup(settings, menu, ui->vbox, uimanager);
797
Stephen M. Cameron04cc6b72012-02-24 08:17:31 +0100798 /*
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +0100799 * Set up alignments for widgets at the top of ui,
800 * align top left, expand horizontally but not vertically
801 */
802 ui->topalign = gtk_alignment_new(0, 0, 1, 0);
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100803 ui->topvbox = gtk_vbox_new(FALSE, 3);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +0100804 gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +0100805 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->topalign, FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +0100806
Jens Axboe3e47bd22012-02-29 13:45:02 +0100807 probe = gtk_frame_new("Job");
Jens Axboe843ad232012-02-29 11:44:53 +0100808 gtk_box_pack_start(GTK_BOX(ui->topvbox), probe, TRUE, FALSE, 3);
809 probe_frame = gtk_vbox_new(FALSE, 3);
810 gtk_container_add(GTK_CONTAINER(probe), probe_frame);
811
812 probe_box = gtk_hbox_new(FALSE, 3);
813 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe843ad232012-02-29 11:44:53 +0100814 ui->probe.hostname = new_info_label_in_frame(probe_box, "Host");
815 ui->probe.os = new_info_label_in_frame(probe_box, "OS");
816 ui->probe.arch = new_info_label_in_frame(probe_box, "Architecture");
817 ui->probe.fio_ver = new_info_label_in_frame(probe_box, "Fio version");
818
Jens Axboe3e47bd22012-02-29 13:45:02 +0100819 probe_box = gtk_hbox_new(FALSE, 3);
820 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
Jens Axboe807f9972012-03-02 10:25:24 +0100821
822 ui->eta.name = new_info_label_in_frame(probe_box, "Name");
823 ui->eta.iotype = new_info_label_in_frame(probe_box, "IO");
824 ui->eta.ioengine = new_info_label_in_frame(probe_box, "IO Engine");
825 ui->eta.iodepth = new_info_label_in_frame(probe_box, "IO Depth");
Jens Axboe3e47bd22012-02-29 13:45:02 +0100826 ui->eta.jobs = new_info_label_in_frame(probe_box, "Jobs");
827 ui->eta.files = new_info_label_in_frame(probe_box, "Open files");
828
829 probe_box = gtk_hbox_new(FALSE, 3);
830 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
831 ui->eta.read_bw = new_info_label_in_frame(probe_box, "Read BW");
832 ui->eta.read_iops = new_info_label_in_frame(probe_box, "IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +0100833 ui->eta.write_bw = new_info_label_in_frame(probe_box, "Write BW");
834 ui->eta.write_iops = new_info_label_in_frame(probe_box, "IOPS");
835
836 /*
837 * Only add this if we have a commit rate
838 */
839#if 0
840 probe_box = gtk_hbox_new(FALSE, 3);
841 gtk_box_pack_start(GTK_BOX(probe_frame), probe_box, TRUE, FALSE, 3);
842
Jens Axboe3e47bd22012-02-29 13:45:02 +0100843 ui->eta.cr_bw = new_info_label_in_frame(probe_box, "Commit BW");
844 ui->eta.cr_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
845
Jens Axboe3e47bd22012-02-29 13:45:02 +0100846 ui->eta.cw_bw = new_info_label_in_frame(probe_box, "Commit BW");
847 ui->eta.cw_iops = new_info_label_in_frame(probe_box, "Commit IOPS");
Jens Axboe807f9972012-03-02 10:25:24 +0100848#endif
Jens Axboe3e47bd22012-02-29 13:45:02 +0100849
Stephen M. Cameron45032dd2012-02-24 08:17:31 +0100850 /*
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100851 * Add a text box for text op messages
852 */
853 ui->textview = gtk_text_view_new();
854 ui->text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ui->textview));
855 gtk_text_buffer_set_text(ui->text, "", -1);
856 gtk_text_view_set_editable(GTK_TEXT_VIEW(ui->textview), FALSE);
857 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ui->textview), FALSE);
858 ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
859 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
860 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
861 gtk_container_add(GTK_CONTAINER(ui->scrolled_window), ui->textview);
Stephen M. Camerone1645342012-02-24 08:17:32 +0100862 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->scrolled_window,
863 TRUE, TRUE, 0);
Stephen M. Cameron736f2df2012-02-24 08:17:32 +0100864
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +0100865 /*
866 * Set up alignments for widgets at the bottom of ui,
867 * align bottom left, expand horizontally but not vertically
868 */
869 ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
870 ui->buttonbox = gtk_hbox_new(FALSE, 0);
871 gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
Stephen M. Camerone1645342012-02-24 08:17:32 +0100872 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->bottomalign,
873 FALSE, FALSE, 0);
Stephen M. Cameronc36f98d2012-02-24 08:17:32 +0100874
Stephen M. Cameronf3074002012-02-24 08:17:30 +0100875 add_buttons(ui, buttonspeclist, ARRAYSIZE(buttonspeclist));
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100876
877 /*
878 * Set up thread status progress bar
879 */
880 ui->thread_status_pb = gtk_progress_bar_new();
881 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
Jens Axboe8663ea62012-03-02 14:04:30 +0100882 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ui->thread_status_pb), "No connections");
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100883 gtk_container_add(GTK_CONTAINER(ui->buttonbox), ui->thread_status_pb);
884
885
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100886 gtk_widget_show_all(ui->window);
887}
888
Stephen M. Cameron8232e282012-02-24 08:17:31 +0100889int main(int argc, char *argv[], char *envp[])
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100890{
Stephen M. Cameron8232e282012-02-24 08:17:31 +0100891 if (initialize_fio(envp))
892 return 1;
Jens Axboe0420ba62012-02-29 11:16:52 +0100893 if (fio_init_options())
894 return 1;
Stephen M. Camerona1820202012-02-24 08:17:31 +0100895
Jens Axboe3ec62ec2012-03-01 12:01:29 +0100896 fio_debug = ~0UL;
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100897 init_ui(&argc, &argv, &ui);
Stephen M. Cameron5b7573a2012-02-24 08:17:31 +0100898
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +0100899 gdk_threads_enter();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100900 gtk_main();
Stephen M. Cameron2839f0c2012-02-24 08:17:31 +0100901 gdk_threads_leave();
Stephen M. Cameronff1f3282012-02-24 08:17:30 +0100902 return 0;
903}