diff mbox

[1/3] iowatcher: Do not distinguish between reads and writes in IO graphs

Message ID 1463745299-5951-2-git-send-email-jack@suse.cz (mailing list archive)
State New, archived
Headers show

Commit Message

Jan Kara May 20, 2016, 11:54 a.m. UTC
Currently names of struct members distinguish between IO graphs for
reads and writes. However with more involved IO graph coloring this
doesn't necessarily make sense and also it leads to a duplication where
we have to work with two arrays instead of one. There are only a few
places which care about read vs write distinction and those can be
implemented differently. So just replace two IO graph arrays with a
single one.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 iowatcher/blkparse.c | 136 +++++++++++++++++++++++++++++++++------------------
 iowatcher/blkparse.h |   7 ++-
 iowatcher/main.c     | 116 +++++++++++++------------------------------
 iowatcher/plot.h     |   3 +-
 4 files changed, 125 insertions(+), 137 deletions(-)
diff mbox

Patch

diff --git a/iowatcher/blkparse.c b/iowatcher/blkparse.c
index c7d1d652c78e..6f48079a2982 100644
--- a/iowatcher/blkparse.c
+++ b/iowatcher/blkparse.c
@@ -174,7 +174,7 @@  struct pending_io {
 struct pid_map {
 	struct list_head hash_list;
 	u32 pid;
-	int index;
+	int index[2];
 	char name[0];
 };
 
@@ -329,11 +329,25 @@  static struct pid_map *process_hash_search(u32 pid)
 	return NULL;
 }
 
-static struct pid_map *process_hash_insert(u32 pid, char *name)
+static struct pid_map *process_hash_new(u32 pid, char *name)
 {
+	struct pid_map *pm;
 	int slot = hash_pid(pid);
+
+	pm = malloc(sizeof(struct pid_map) + strlen(name) + 1);
+	pm->pid = pid;
+	pm->index[0] = 0;
+	pm->index[1] = 0;
+	strcpy(pm->name, name);
+	list_add_tail(&pm->hash_list, process_hash_table + slot);
+
+	return pm;
+}
+
+static struct pid_map *process_hash_insert(u32 pid, char *name)
+{
 	struct pid_map *pm;
-	int old_index = 0;
+	int old_index[2] = {};
 	char buf[16];
 
 	pm = process_hash_search(pid);
@@ -342,18 +356,17 @@  static struct pid_map *process_hash_insert(u32 pid, char *name)
 		if (!name || !strcmp(name, pm->name))
 			return pm;
 		list_del(&pm->hash_list);
-		old_index = pm->index;
+		old_index[0] = pm->index[0];
+		old_index[1] = pm->index[1];
 		free(pm);
 	}
 	if (!name) {
 		sprintf(buf, "[%u]", pid);
 		name = buf;
 	}
-	pm = malloc(sizeof(struct pid_map) + strlen(name) + 1);
-	pm->pid = pid;
-	pm->index = old_index;
-	strcpy(pm->name, name);
-	list_add_tail(&pm->hash_list, process_hash_table + slot);
+	pm = process_hash_new(pid, name);
+	pm->index[0] = old_index[0];
+	pm->index[1] = old_index[1];
 
 	return pm;
 }
@@ -1014,39 +1027,53 @@  void add_tput(struct trace *trace, struct graph_line_data *writes_gld,
 		gld->max = gld->data[seconds].sum;
 }
 
-#define GDD_PTR_ALLOC_STEP 16
+#define GDD_PTR_ALLOC_STEP 32
 
-static struct pid_map *get_pid_map(struct trace_file *tf, u32 pid)
+static int per_process_get_io_index(struct trace_file *tf,
+				    struct blk_io_trace *io,
+				    char **label, char **suffix)
 {
 	struct pid_map *pm;
+	int rw = !(BLK_DATADIR(io->action) & BLK_TC_READ);
 
-	if (!io_per_process) {
-		if (!tf->io_plots)
-			tf->io_plots = 1;
-		return NULL;
-	}
-
-	pm = process_hash_insert(pid, NULL);
+	pm = process_hash_insert(io->pid, NULL);
+	if (rw)
+		*suffix = " Writes";
+	else
+		*suffix = " Reads";
+	*label = pm->name;
 	/* New entry? */
-	if (!pm->index) {
+	if (!pm->index[rw]) {
 		if (tf->io_plots == tf->io_plots_allocated) {
 			tf->io_plots_allocated += GDD_PTR_ALLOC_STEP;
-			tf->gdd_reads = realloc(tf->gdd_reads, tf->io_plots_allocated * sizeof(struct graph_dot_data *));
-			if (!tf->gdd_reads)
-				abort();
-			tf->gdd_writes = realloc(tf->gdd_writes, tf->io_plots_allocated * sizeof(struct graph_dot_data *));
-			if (!tf->gdd_writes)
+			tf->gdd_io = realloc(tf->gdd_io, tf->io_plots_allocated * sizeof(struct graph_dot_data *));
+			if (!tf->gdd_io)
 				abort();
-			memset(tf->gdd_reads + tf->io_plots_allocated - GDD_PTR_ALLOC_STEP,
-			       0, GDD_PTR_ALLOC_STEP * sizeof(struct graph_dot_data *));
-			memset(tf->gdd_writes + tf->io_plots_allocated - GDD_PTR_ALLOC_STEP,
+			memset(tf->gdd_io + tf->io_plots_allocated - GDD_PTR_ALLOC_STEP,
 			       0, GDD_PTR_ALLOC_STEP * sizeof(struct graph_dot_data *));
 		}
-		pm->index = tf->io_plots++;
+		pm->index[rw] = tf->io_plots++;
 
-		return pm;
+		return pm->index[rw];
 	}
-	return pm;
+	return pm->index[rw];
+}
+
+static int default_get_io_index(struct trace_file *tf,
+				struct blk_io_trace *io,
+				char **label, char **suffix)
+{
+	int rw = !(BLK_DATADIR(io->action) & BLK_TC_READ);
+
+	*label = "";
+	if (rw)
+		*suffix = "Writes";
+	else
+		*suffix = "Reads";
+	/* We assume we have space for at least two plot pointers in gdd_io... */
+	if (tf->io_plots <= rw)
+		tf->io_plots = rw + 1;
+	return rw;
 }
 
 void add_io(struct trace *trace, struct trace_file *tf)
@@ -1055,8 +1082,7 @@  void add_io(struct trace *trace, struct trace_file *tf)
 	int action = io->action & BLK_TA_MASK;
 	u64 offset;
 	int index;
-	char *label;
-	struct pid_map *pm;
+	char *label, *suffix;
 
 	if (io->action & BLK_TC_ACT(BLK_TC_NOTIFY))
 		return;
@@ -1064,25 +1090,39 @@  void add_io(struct trace *trace, struct trace_file *tf)
 	if (action != io_event(trace))
 		return;
 
+	if (!(BLK_DATADIR(io->action) & BLK_TC_READ) &&
+	    !(BLK_DATADIR(io->action) & BLK_TC_WRITE))
+		return;
+
 	offset = map_io(trace, io);
 
-	pm = get_pid_map(tf, io->pid);
-	if (!pm) {
-		index = 0;
-		label = "";
-	} else {
-		index = pm->index;
-		label = pm->name;
-	}
-	if (BLK_DATADIR(io->action) & BLK_TC_READ) {
-		if (!tf->gdd_reads[index])
-			tf->gdd_reads[index] = alloc_dot_data(tf->min_seconds, tf->max_seconds, tf->min_offset, tf->max_offset, tf->stop_seconds, pick_color(), strdup(label));
-		set_gdd_bit(tf->gdd_reads[index], offset, io->bytes, io->time);
-	} else if (BLK_DATADIR(io->action) & BLK_TC_WRITE) {
-		if (!tf->gdd_writes[index])
-			tf->gdd_writes[index] = alloc_dot_data(tf->min_seconds, tf->max_seconds, tf->min_offset, tf->max_offset, tf->stop_seconds, pick_color(), strdup(label));
-		set_gdd_bit(tf->gdd_writes[index], offset, io->bytes, io->time);
+	if (!io_per_process)
+		index = default_get_io_index(tf, io, &label, &suffix);
+	else
+		index = per_process_get_io_index(tf, io, &label, &suffix);
+
+	if (!tf->gdd_io[index]) {
+		int len = strlen(label) + strlen(suffix) + 1;
+		char *concat = malloc(len);
+		char *color = pick_color();
+		int rw = !(BLK_DATADIR(io->action) & BLK_TC_READ);
+
+		if (!concat)
+			abort();
+		strcpy(concat, label);
+		strcat(concat, suffix);
+		tf->gdd_io[index] = alloc_dot_data(tf->min_seconds, tf->max_seconds, tf->min_offset, tf->max_offset, tf->stop_seconds, color, concat);
+		if (!io_per_process) {
+			/* Use the color also for corresponding line graphs. */
+			if (!tf->line_color)
+				tf->line_color = color;
+			if (!rw && !tf->reads_color)
+				tf->reads_color = color;
+			if (rw && !tf->writes_color)
+				tf->writes_color = color;
+		}
 	}
+	set_gdd_bit(tf->gdd_io[index], offset, io->bytes, io->time);
 }
 
 void add_pending_io(struct trace *trace, struct graph_line_data *gld)
diff --git a/iowatcher/blkparse.h b/iowatcher/blkparse.h
index fce9d01ed2c6..0448b70bbb09 100644
--- a/iowatcher/blkparse.h
+++ b/iowatcher/blkparse.h
@@ -91,13 +91,12 @@  struct trace_file {
 	int fio_trace;
 	struct graph_line_data *fio_gld;
 
-	/* Number of entries in gdd_writes / gdd_reads */
+	/* Number of entries in gdd_io */
 	int io_plots;
 
-	/* Allocated array size for gdd_writes / gdd_reads */
+	/* Allocated array size for gdd_io */
 	int io_plots_allocated;
-	struct graph_dot_data **gdd_writes;
-	struct graph_dot_data **gdd_reads;
+	struct graph_dot_data **gdd_io;
 
 	unsigned int mpstat_min_seconds;
 	unsigned int mpstat_max_seconds;
diff --git a/iowatcher/main.c b/iowatcher/main.c
index 54325fbfde52..f64c44d2ca5c 100644
--- a/iowatcher/main.c
+++ b/iowatcher/main.c
@@ -278,9 +278,9 @@  static void setup_trace_file_graphs(void)
 	int alloc_ptrs;
 
 	if (io_per_process)
-		alloc_ptrs = 16;
+		alloc_ptrs = 32;
 	else
-		alloc_ptrs = 1;
+		alloc_ptrs = 2;
 
 	list_for_each_entry(tf, &all_traces, list) {
 		tf->tput_reads_gld = alloc_line_data(tf->min_seconds, tf->max_seconds, tf->stop_seconds);
@@ -289,8 +289,7 @@  static void setup_trace_file_graphs(void)
 		tf->queue_depth_gld = alloc_line_data(tf->min_seconds, tf->max_seconds, tf->stop_seconds);
 
 		tf->iop_gld = alloc_line_data(tf->min_seconds, tf->max_seconds, tf->stop_seconds);
-		tf->gdd_writes = calloc(alloc_ptrs, sizeof(struct graph_dot_data *));
-		tf->gdd_reads = calloc(alloc_ptrs, sizeof(struct graph_dot_data *));
+		tf->gdd_io = calloc(alloc_ptrs, sizeof(struct graph_dot_data *));
 		tf->io_plots_allocated = alloc_ptrs;
 
 		if (tf->trace->mpstat_num_cpus == 0)
@@ -370,25 +369,19 @@  static void read_traces(void)
 static void pick_line_graph_color(void)
 {
 	struct trace_file *tf;
-	int i;
 
 	list_for_each_entry(tf, &all_traces, list) {
-		for (i = 0; i < tf->io_plots; i++) {
-			if (tf->gdd_reads[i]) {
-				tf->line_color = tf->gdd_reads[i]->color;
-				tf->reads_color = tf->gdd_reads[i]->color;
-			}
-			if (tf->gdd_writes[i]) {
-				tf->line_color = tf->gdd_writes[i]->color;
-				tf->writes_color = tf->gdd_writes[i]->color;
-			}
-			if (tf->writes_color && tf->reads_color)
-				break;
-		}
+		/*
+		 * For normal IO graph view colors will be already selected in
+		 * add_io().  However for more involved coloring of IO graph it
+		 * doesn't make sense to align colors so just pick some here.
+		 */
+		if (!tf->line_color)
+			tf->line_color = pick_color();
 		if (!tf->reads_color)
-			tf->reads_color = tf->line_color;
+			tf->reads_color = pick_color();
 		if (!tf->writes_color)
-			tf->writes_color = tf->line_color;
+			tf->writes_color = pick_color();
 	}
 }
 
@@ -603,22 +596,15 @@  static struct plot_history *alloc_plot_history(struct trace_file *tf)
 		perror("memory allocation failed");
 		exit(1);
 	}
-	ph->read_pid_history = calloc(tf->io_plots, sizeof(struct pid_plot_history *));
-	if (!ph->read_pid_history) {
-		perror("memory allocation failed");
-		exit(1);
-	}
-	ph->write_pid_history = calloc(tf->io_plots, sizeof(struct pid_plot_history *));
-	if (!ph->write_pid_history) {
+	ph->io_pid_history = calloc(tf->io_plots, sizeof(struct pid_plot_history *));
+	if (!ph->io_pid_history) {
 		perror("memory allocation failed");
 		exit(1);
 	}
 	ph->pid_history_count = tf->io_plots;
 	for (i = 0; i < tf->io_plots; i++) {
-		if (tf->gdd_reads[i])
-			ph->read_pid_history[i] = alloc_pid_plot_history(tf->gdd_reads[i]->color);
-		if (tf->gdd_writes[i])
-			ph->write_pid_history[i] = alloc_pid_plot_history(tf->gdd_writes[i]->color);
+		if (tf->gdd_io[i])
+			ph->io_pid_history[i] = alloc_pid_plot_history(tf->gdd_io[i]->color);
 	}
 	return ph;
 }
@@ -631,13 +617,10 @@  static void free_plot_history(struct plot_history *ph)
 	int pid;
 
 	for (pid = 0; pid < ph->pid_history_count; pid++) {
-		if (ph->read_pid_history[pid])
-			free(ph->read_pid_history[pid]);
-		if (ph->write_pid_history[pid])
-			free(ph->write_pid_history[pid]);
+		if (ph->io_pid_history[pid])
+			free(ph->io_pid_history[pid]);
 	}
-	free(ph->read_pid_history);
-	free(ph->write_pid_history);
+	free(ph->io_pid_history);
 	free(ph);
 }
 
@@ -666,22 +649,13 @@  static void plot_movie_history(struct plot *plot, struct list_head *list)
 
 	list_for_each_entry(ph, list, list) {
 		for (pid = 0; pid < ph->pid_history_count; pid++) {
-			if (ph->read_pid_history[pid]) {
+			if (ph->io_pid_history[pid]) {
 				if (movie_style == MOVIE_SPINDLE) {
 					svg_io_graph_movie_array_spindle(plot,
-						ph->read_pid_history[pid]);
+						ph->io_pid_history[pid]);
 				} else {
 					svg_io_graph_movie_array(plot,
-						ph->read_pid_history[pid]);
-				}
-			}
-			if (ph->write_pid_history[pid]) {
-				if (movie_style == MOVIE_SPINDLE) {
-					svg_io_graph_movie_array_spindle(plot,
-						ph->write_pid_history[pid]);
-				} else {
-					svg_io_graph_movie_array(plot,
-						ph->write_pid_history[pid]);
+						ph->io_pid_history[pid]);
 				}
 			}
 		}
@@ -707,29 +681,16 @@  static int count_io_plot_types(void)
 
 	list_for_each_entry(tf, &all_traces, list) {
 		for (i = 0; i < tf->io_plots; i++) {
-			if (tf->gdd_reads[i])
-				total_io_types++;
-			if (tf->gdd_writes[i])
+			if (tf->gdd_io[i])
 				total_io_types++;
 		}
 	}
 	return total_io_types;
 }
 
-static void plot_io_legend(struct plot *plot, struct graph_dot_data *gdd, char *prefix, char *rw)
+static void plot_io_legend(struct plot *plot, struct graph_dot_data *gdd, char *prefix)
 {
-	int ret = 0;
-	char *label = NULL;
-	if (io_per_process)
-		ret = asprintf(&label, "%s %s", prefix, gdd->label);
-	else
-		ret = asprintf(&label, "%s", prefix);
-	if (ret < 0) {
-		perror("Failed to process labels");
-		exit(1);
-	}
-	svg_add_legend(plot, label, rw, gdd->color);
-	free(label);
+	svg_add_legend(plot, prefix, gdd->label, gdd->color);
 }
 
 static void plot_io(struct plot *plot, unsigned int min_seconds,
@@ -755,13 +716,9 @@  static void plot_io(struct plot *plot, unsigned int min_seconds,
 		char *prefix = tf->label ? tf->label : "";
 
 		for (i = 0; i < tf->io_plots; i++) {
-			if (tf->gdd_writes[i]) {
-				svg_io_graph(plot, tf->gdd_writes[i]);
-				plot_io_legend(plot, tf->gdd_writes[i], prefix, " Writes");
-			}
-			if (tf->gdd_reads[i]) {
-				svg_io_graph(plot, tf->gdd_reads[i]);
-				plot_io_legend(plot, tf->gdd_reads[i], prefix, " Reads");
+			if (tf->gdd_io[i]) {
+				svg_io_graph(plot, tf->gdd_io[i]);
+				plot_io_legend(plot, tf->gdd_io[i], prefix);
 			}
 		}
 	}
@@ -1158,23 +1115,16 @@  static void plot_io_movie(struct plot *plot)
 			history->col = i;
 
 			for (pid = 0; pid < tf->io_plots; pid++) {
-				if (tf->gdd_reads[pid])
-					plot_io_legend(plot, tf->gdd_reads[pid], prefix, " Reads");
-				if (tf->gdd_writes[pid])
-					plot_io_legend(plot, tf->gdd_writes[pid], prefix, " Writes");
+				if (tf->gdd_io[pid])
+					plot_io_legend(plot, tf->gdd_io[pid], prefix);
 			}
 
 			batch_i = 0;
 			while (i < cols && batch_i < batch_count) {
 				for (pid = 0; pid < tf->io_plots; pid++) {
-					if (tf->gdd_reads[pid]) {
-						svg_io_graph_movie(tf->gdd_reads[pid],
-								   history->read_pid_history[pid],
-								   i);
-					}
-					if (tf->gdd_writes[pid]) {
-						svg_io_graph_movie(tf->gdd_writes[pid],
-								   history->write_pid_history[pid],
+					if (tf->gdd_io[pid]) {
+						svg_io_graph_movie(tf->gdd_io[pid],
+								   history->io_pid_history[pid],
 								   i);
 					}
 				}
diff --git a/iowatcher/plot.h b/iowatcher/plot.h
index d65bbcf3396e..48e17e8bd81b 100644
--- a/iowatcher/plot.h
+++ b/iowatcher/plot.h
@@ -128,8 +128,7 @@  struct plot_history {
 	struct list_head list;
 	int pid_history_count;
 	int col;
-	struct pid_plot_history **read_pid_history;
-	struct pid_plot_history **write_pid_history;
+	struct pid_plot_history **io_pid_history;
 };
 
 char *pick_color(void);