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