gfio: add disk utilization output to end results

Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/gfio.c b/gfio.c
index 3f01682..457a13a 100644
--- a/gfio.c
+++ b/gfio.c
@@ -103,6 +103,12 @@
 	char **job_files;
 } ui;
 
+struct gfio_client {
+	struct gui *ui;
+	GtkWidget *results_widget;
+	GtkWidget *disk_util_frame;
+};
+
 static void clear_ui_info(struct gui *ui)
 {
 	gtk_label_set_text(GTK_LABEL(ui->probe.hostname), "");
@@ -293,8 +299,11 @@
 
 	gtk_list_store_append(model, &iter);
 
-	for (i = 0; i < len; i++)
+	for (i = 0; i < len; i++) {
+		if (scale)
+			ovals[i] = (ovals[i] + 999) / 1000;
 		gtk_list_store_set(model, &iter, i, ovals[i], -1);
+	}
 
 	return tree_view;
 }
@@ -387,10 +396,10 @@
 {
 	const char *ddir_label[2] = { "Read", "Write" };
 	GtkWidget *frame, *label, *box, *vbox, *main_vbox;
-	unsigned long min, max, runt;
+	unsigned long min[3], max[3], runt;
 	unsigned long long bw, iops;
 	unsigned int flags = 0;
-	double mean, dev;
+	double mean[3], dev[3];
 	char *io_p, *bw_p, *iops_p;
 	int i2p;
 
@@ -428,22 +437,22 @@
 	label = new_info_label_in_frame(box, "Runtime (msec)");
 	label_set_int_value(label, ts->runtime[ddir]);
 
-	if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
+	if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
 		double p_of_agg = 100.0;
 		const char *bw_str = "KB";
 		char tmp[32];
 
 		if (rs->agg[ddir]) {
-			p_of_agg = mean * 100 / (double) rs->agg[ddir];
+			p_of_agg = mean[0] * 100 / (double) rs->agg[ddir];
 			if (p_of_agg > 100.0)
 				p_of_agg = 100.0;
 		}
 
-		if (mean > 999999.9) {
-			min /= 1000.0;
-			max /= 1000.0;
-			mean /= 1000.0;
-			dev /= 1000.0;
+		if (mean[0] > 999999.9) {
+			min[0] /= 1000.0;
+			max[0] /= 1000.0;
+			mean[0] /= 1000.0;
+			dev[0] /= 1000.0;
 			bw_str = "MB";
 		}
 
@@ -455,25 +464,25 @@
 		gtk_container_add(GTK_CONTAINER(frame), box);
 
 		label = new_info_label_in_frame(box, "Minimum");
-		label_set_int_value(label, min);
+		label_set_int_value(label, min[0]);
 		label = new_info_label_in_frame(box, "Maximum");
-		label_set_int_value(label, max);
+		label_set_int_value(label, max[0]);
 		label = new_info_label_in_frame(box, "Percentage of jobs");
 		sprintf(tmp, "%3.2f%%", p_of_agg);
 		gtk_label_set_text(GTK_LABEL(label), tmp);
 		label = new_info_label_in_frame(box, "Average");
-		sprintf(tmp, "%5.02f", mean);
+		sprintf(tmp, "%5.02f", mean[0]);
 		gtk_label_set_text(GTK_LABEL(label), tmp);
 		label = new_info_label_in_frame(box, "Standard deviation");
-		sprintf(tmp, "%5.02f", dev);
+		sprintf(tmp, "%5.02f", dev[0]);
 		gtk_label_set_text(GTK_LABEL(label), tmp);
 	}
 
-	if (calc_lat(&ts->slat_stat[ddir], &min, &max, &mean, &dev))
+	if (calc_lat(&ts->slat_stat[ddir], &min[0], &max[0], &mean[0], &dev[0]))
 		flags |= GFIO_SLAT;
-	if (calc_lat(&ts->clat_stat[ddir], &min, &max, &mean, &dev))
+	if (calc_lat(&ts->clat_stat[ddir], &min[1], &max[1], &mean[1], &dev[1]))
 		flags |= GFIO_CLAT;
-	if (calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev))
+	if (calc_lat(&ts->lat_stat[ddir], &min[2], &max[2], &mean[2], &dev[2]))
 		flags |= GFIO_LAT;
 
 	if (flags) {
@@ -484,11 +493,11 @@
 		gtk_container_add(GTK_CONTAINER(frame), vbox);
 
 		if (flags & GFIO_SLAT)
-			gfio_show_lat(vbox, "Submission latency", min, max, mean, dev);
+			gfio_show_lat(vbox, "Submission latency", min[0], max[0], mean[0], dev[0]);
 		if (flags & GFIO_CLAT)
-			gfio_show_lat(vbox, "Completion latency", min, max, mean, dev);
+			gfio_show_lat(vbox, "Completion latency", min[1], max[1], mean[1], dev[1]);
 		if (flags & GFIO_LAT)
-			gfio_show_lat(vbox, "Total latency", min, max, mean, dev);
+			gfio_show_lat(vbox, "Total latency", min[2], max[2], mean[2], dev[2]);
 	}
 
 	if (ts->clat_percentiles)
@@ -761,11 +770,11 @@
 			    struct group_run_stats *rs)
 {
 	GtkWidget *res_win, *box, *vbox, *entry;
-	struct gui *ui = client->client_data;
+	struct gfio_client *gc = client->client_data;
 
 	gdk_threads_enter();
 
-	res_win = get_results_window(ui);
+	res_win = get_results_window(gc->ui);
 
 	vbox = gtk_vbox_new(FALSE, 3);
 
@@ -774,6 +783,8 @@
 
 	gtk_notebook_append_page(GTK_NOTEBOOK(res_win), vbox, gtk_label_new(ts->name));
 
+	gc->results_widget = vbox;
+
 	entry = new_info_entry_in_frame(box, "Name");
 	gtk_entry_set_text(GTK_ENTRY(entry), ts->name);
 	if (strlen(ts->description)) {
@@ -798,14 +809,14 @@
 	gfio_show_cpu_usage(vbox, ts);
 	gfio_show_io_depths(vbox, ts);
 
-	gtk_widget_show_all(ui->results_window);
+	gtk_widget_show_all(gc->ui->results_window);
 	gdk_threads_leave();
 }
 
 static void gfio_text_op(struct fio_client *client, struct fio_net_cmd *cmd)
 {
 	struct cmd_text_pdu *p = (struct cmd_text_pdu *) cmd->payload;
-	struct gui *ui = client->client_data;
+	struct gfio_client *gc = client->client_data;
 	GtkTreeIter iter;
 	struct tm *tm;
 	time_t sec;
@@ -818,20 +829,79 @@
 
 	gdk_threads_enter();
 
-	gtk_list_store_append(ui->log_model, &iter);
-	gtk_list_store_set(ui->log_model, &iter, 0, timebuf, -1);
-	gtk_list_store_set(ui->log_model, &iter, 1, client->hostname, -1);
-	gtk_list_store_set(ui->log_model, &iter, 2, p->level, -1);
-	gtk_list_store_set(ui->log_model, &iter, 3, p->buf, -1);
+	gtk_list_store_append(gc->ui->log_model, &iter);
+	gtk_list_store_set(gc->ui->log_model, &iter, 0, timebuf, -1);
+	gtk_list_store_set(gc->ui->log_model, &iter, 1, client->hostname, -1);
+	gtk_list_store_set(gc->ui->log_model, &iter, 2, p->level, -1);
+	gtk_list_store_set(gc->ui->log_model, &iter, 3, p->buf, -1);
 
 	gdk_threads_leave();
 }
 
 static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
 {
+	struct cmd_du_pdu *p = (struct cmd_du_pdu *) cmd->payload;
+	struct gfio_client *gc = client->client_data;
+	GtkWidget *box, *frame, *entry, *vbox;
+
 	gdk_threads_enter();
-	printf("gfio_disk_util_op called\n");
-	fio_client_ops.disk_util(client, cmd);
+
+	if (!gc->results_widget) {
+		printf("no results!\n");
+		goto out;
+	}
+
+	if (!gc->disk_util_frame) {
+		gc->disk_util_frame = gtk_frame_new("Disk utilization");
+		gtk_box_pack_start(GTK_BOX(gc->results_widget), gc->disk_util_frame, FALSE, FALSE, 5);
+	}
+
+	vbox = gtk_vbox_new(FALSE, 3);
+	gtk_container_add(GTK_CONTAINER(gc->disk_util_frame), vbox);
+
+	frame = gtk_frame_new((char *) p->dus.name);
+	gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
+
+	box = gtk_vbox_new(FALSE, 3);
+	gtk_container_add(GTK_CONTAINER(frame), box);
+
+	frame = gtk_frame_new("Read");
+	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
+	vbox = gtk_hbox_new(TRUE, 3);
+	gtk_container_add(GTK_CONTAINER(frame), vbox);
+	entry = new_info_entry_in_frame(vbox, "IOs");
+	entry_set_int_value(entry, p->dus.ios[0]);
+	entry = new_info_entry_in_frame(vbox, "Merges");
+	entry_set_int_value(entry, p->dus.merges[0]);
+	entry = new_info_entry_in_frame(vbox, "Sectors");
+	entry_set_int_value(entry, p->dus.sectors[0]);
+	entry = new_info_entry_in_frame(vbox, "Ticks");
+	entry_set_int_value(entry, p->dus.ticks[0]);
+
+	frame = gtk_frame_new("Write");
+	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
+	vbox = gtk_hbox_new(TRUE, 3);
+	gtk_container_add(GTK_CONTAINER(frame), vbox);
+	entry = new_info_entry_in_frame(vbox, "IOs");
+	entry_set_int_value(entry, p->dus.ios[1]);
+	entry = new_info_entry_in_frame(vbox, "Merges");
+	entry_set_int_value(entry, p->dus.merges[1]);
+	entry = new_info_entry_in_frame(vbox, "Sectors");
+	entry_set_int_value(entry, p->dus.sectors[1]);
+	entry = new_info_entry_in_frame(vbox, "Ticks");
+	entry_set_int_value(entry, p->dus.ticks[1]);
+
+	frame = gtk_frame_new("Shared");
+	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
+	vbox = gtk_hbox_new(TRUE, 3);
+	gtk_container_add(GTK_CONTAINER(frame), vbox);
+	entry = new_info_entry_in_frame(vbox, "IO ticks");
+	entry_set_int_value(entry, p->dus.io_ticks);
+	entry = new_info_entry_in_frame(vbox, "Time in queue");
+	entry_set_int_value(entry, p->dus.time_in_queue);
+
+	gtk_widget_show_all(gc->results_widget);
+out:
 	gdk_threads_leave();
 }
 
@@ -998,17 +1068,18 @@
 
 static void gfio_quit_op(struct fio_client *client)
 {
-	struct gui *ui = client->client_data;
+	struct gfio_client *gc = client->client_data;
 
 	gdk_threads_enter();
-	gfio_set_connected(ui, 0);
+	gfio_set_connected(gc->ui, 0);
 	gdk_threads_leave();
 }
 
 static void gfio_add_job_op(struct fio_client *client, struct fio_net_cmd *cmd)
 {
 	struct cmd_add_job_pdu *p = (struct cmd_add_job_pdu *) cmd->payload;
-	struct gui *ui = client->client_data;
+	struct gfio_client *gc = client->client_data;
+	struct gui *ui = gc->ui;
 	char tmp[8];
 	int i;
 
@@ -1037,19 +1108,19 @@
 
 static void gfio_client_timed_out(struct fio_client *client)
 {
-	struct gui *ui = client->client_data;
+	struct gfio_client *gc = client->client_data;
 	GtkWidget *dialog, *label, *content;
 	char buf[256];
 
 	gdk_threads_enter();
 
-	gfio_set_connected(ui, 0);
-	clear_ui_info(ui);
+	gfio_set_connected(gc->ui, 0);
+	clear_ui_info(gc->ui);
 
 	sprintf(buf, "Client %s: timeout talking to server.\n", client->hostname);
 
 	dialog = gtk_dialog_new_with_buttons("Timed out!",
-			GTK_WINDOW(ui->window),
+			GTK_WINDOW(gc->ui->window),
 			GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
 			GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
 
@@ -1290,6 +1361,17 @@
 	return 0;
 }
 
+static void gfio_client_added(struct gui *ui, struct fio_client *client)
+{
+	struct gfio_client *gc;
+
+	gc = malloc(sizeof(*gc));
+	memset(gc, 0, sizeof(*gc));
+	gc->ui = ui;
+
+	client->client_data = gc;
+}
+
 static void file_open(GtkWidget *w, gpointer data)
 {
 	GtkWidget *dialog;
@@ -1327,12 +1409,14 @@
 
 	filenames = fn_glist;
 	while (filenames != NULL) {
+		struct fio_client *client;
+
 		ui.job_files = realloc(ui.job_files, (ui.nr_job_files + 1) * sizeof(char *));
 		ui.job_files[ui.nr_job_files] = strdup(filenames->data);
 		ui.nr_job_files++;
 
-		ui.client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
-		if (!ui.client) {
+		client = fio_client_add_explicit(&gfio_client_ops, host, type, port);
+		if (!client) {
 			GError *error;
 
 			error = g_error_new(g_quark_from_string("fio"), 1,
@@ -1340,7 +1424,7 @@
 			report_error(error);
 			g_error_free(error);
 		}
-		ui.client->client_data = &ui;
+		gfio_client_added(&ui, client);
 			
 		g_free(filenames->data);
 		filenames = g_slist_next(filenames);