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@xxxxxxx> --- iowatcher/blkparse.c | 136 +++++++++++++++++++++++++++++++++------------------ iowatcher/blkparse.h | 7 ++- iowatcher/main.c | 116 +++++++++++++------------------------------ iowatcher/plot.h | 3 +- 4 files changed, 125 insertions(+), 137 deletions(-) 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); -- 2.6.6 -- To unsubscribe from this list: send the line "unsubscribe linux-block" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html