@@ -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)
@@ -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;
@@ -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);
}
}
@@ -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);
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(-)