aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@fusionio.com>2012-08-27 17:39:58 -0400
committerChris Mason <chris.mason@oracle.com>2012-08-27 17:39:58 -0400
commit8ed9516f791ead08ade69c952b14d3b4f85c38ef (patch)
tree3d21a3a56edd66d91f9f2b822ef584eb12875f19
parentf106953d41597722efd068e67eaae5664ef5034d (diff)
downloadblktrace-8ed9516f791ead08ade69c952b14d3b4f85c38ef.tar.gz
iowatcher: Start support for multiple colums of plots
The movie mode is updated to put extra plots on the side. Signed-off-by: Chris Mason <chris.mason@fusionio.com>
-rw-r--r--iowatcher/main.c300
-rw-r--r--iowatcher/plot.c57
-rw-r--r--iowatcher/plot.h3
3 files changed, 215 insertions, 145 deletions
diff --git a/iowatcher/main.c b/iowatcher/main.c
index 22c0bb6..90eef0f 100644
--- a/iowatcher/main.c
+++ b/iowatcher/main.c
@@ -615,6 +615,144 @@ static void plot_tput(struct plot *plot, int seconds)
close_plot(plot);
}
+static int __plot_cpu(struct plot *plot, int seconds, char *label,
+ int active_index, int gld_index)
+{
+ struct trace_file *tf;
+ int max = 0;
+ int i;
+ int gld_i;
+ char *color;
+ double avg = 0;
+ int ymax;
+ int plotted = 0;
+
+ list_for_each_entry(tf, &all_traces, list) {
+ if (tf->trace->mpstat_num_cpus > max)
+ max = tf->trace->mpstat_num_cpus;
+ }
+ if (max == 0)
+ return 1;
+
+ tf = list_entry(all_traces.next, struct trace_file, list);
+
+ ymax = tf->mpstat_gld[gld_index]->max;
+ if (ymax == 0)
+ return 1;
+
+ svg_alloc_legend(plot, num_traces * max);
+
+ plot->add_xlabel = last_active_graph == active_index;
+ setup_axis(plot);
+ set_plot_label(plot, label);
+
+ seconds = tf->mpstat_seconds;
+
+ set_yticks(plot, 4, 0, tf->mpstat_gld[gld_index]->max, "");
+ set_ylabel(plot, "Percent");
+ set_xticks(plot, 9, 0, seconds);
+
+ cpu_color_index = 0;
+ list_for_each_entry(tf, &all_traces, list) {
+ for (i = 0; i < tf->mpstat_gld[0]->stop_seconds; i++) {
+ if (tf->mpstat_gld[gld_index]->data[i].count) {
+ avg += (tf->mpstat_gld[gld_index]->data[i].sum /
+ tf->mpstat_gld[gld_index]->data[i].count);
+ }
+ }
+ avg /= tf->mpstat_gld[gld_index]->stop_seconds;
+ color = pick_cpu_color();
+ svg_line_graph(plot, tf->mpstat_gld[0], color, 0, 0);
+ svg_add_legend(plot, tf->label, " avg", color);
+
+ for (i = 1; i < tf->trace->mpstat_num_cpus + 1; i++) {
+ struct graph_line_data *gld = tf->mpstat_gld[i * MPSTAT_GRAPHS + gld_index];
+ double this_avg = 0;
+
+ for (gld_i = 0; gld_i < gld->stop_seconds; gld_i++)
+ this_avg += gld->data[i].sum /
+ gld->data[i].count;;
+
+ this_avg /= gld->stop_seconds;
+
+ for (gld_i = 0; gld_i < gld->stop_seconds; gld_i++) {
+ double val;
+
+ if (gld->data[gld_i].count == 0)
+ continue;
+ val = (double)gld->data[gld_i].sum /
+ gld->data[gld_i].count;
+
+ if (this_avg > avg + 30 || val > 95) {
+ color = pick_cpu_color();
+ svg_line_graph(plot, gld, color, avg + 30, 95);
+ snprintf(line, line_len, " CPU %d\n", i - 1);
+ svg_add_legend(plot, tf->label, line, color);
+ plotted++;
+ break;
+ }
+
+ }
+ }
+ }
+
+ if (plot->add_xlabel)
+ set_xlabel(plot, "Time (seconds)");
+
+ if (!plot->no_legend) {
+ svg_write_legend(plot);
+ svg_free_legend(plot);
+ }
+ return 0;
+}
+
+static void plot_cpu(struct plot *plot, int seconds, char *label,
+ int active_index, int gld_index)
+{
+ if (active_graphs[active_index] == 0)
+ return;
+
+ plot->add_xlabel = last_active_graph == active_index;
+ if (!__plot_cpu(plot, seconds, label, active_index, gld_index))
+ close_plot(plot);
+}
+
+static void __plot_queue_depth(struct plot *plot, int seconds)
+{
+ struct trace_file *tf;
+
+ plot->add_xlabel = last_active_graph == QUEUE_DEPTH_GRAPH_INDEX;
+
+ setup_axis(plot);
+ set_plot_label(plot, "Queue Depth");
+ if (num_traces > 1)
+ svg_alloc_legend(plot, num_traces);
+
+ tf = list_entry(all_traces.next, struct trace_file, list);
+ set_ylabel(plot, "Pending IO");
+ set_yticks(plot, 4, 0, tf->queue_depth_gld->max, "");
+ set_xticks(plot, 9, 0, seconds);
+
+ list_for_each_entry(tf, &all_traces, list) {
+ svg_line_graph(plot, tf->queue_depth_gld, tf->read_color, 0, 0);
+ if (num_traces > 1)
+ svg_add_legend(plot, tf->label, "", tf->read_color);
+ }
+
+ if (plot->add_xlabel)
+ set_xlabel(plot, "Time (seconds)");
+ if (num_traces > 1)
+ svg_write_legend(plot);
+}
+
+static void plot_queue_depth(struct plot *plot, int seconds)
+{
+ if (active_graphs[QUEUE_DEPTH_GRAPH_INDEX] == 0)
+ return;
+ __plot_queue_depth(plot, seconds);
+ close_plot(plot);
+}
+
static void convert_movie_files(char *movie_dir)
{
fprintf(stderr, "Converting svg files in %s\n", movie_dir);
@@ -654,6 +792,8 @@ static void plot_io_movie(struct plot *plot)
int total_frames = movie_len * movie_frames_per_sec;
int rows, cols;
int batch_count;
+ int graph_width_factor = 5;
+ int orig_y_offset;
get_graph_size(&cols, &rows);
batch_count = cols / total_frames;
@@ -670,8 +810,33 @@ static void plot_io_movie(struct plot *plot)
while (i < cols) {
snprintf(line, line_len, "%s/%010d-%s.svg", movie_dir, i, output_filename);
set_plot_output(plot, line);
-
set_plot_title(plot, graph_title);
+ orig_y_offset = plot->start_y_offset;
+
+ plot->no_legend = 1;
+
+ set_graph_size(cols / graph_width_factor, rows / 8);
+
+ __plot_tput(plot, tf->gdd_reads->seconds);
+ svg_write_time_line(plot, i / graph_width_factor);
+ close_plot(plot);
+
+ if (!__plot_cpu(plot, tf->gdd_reads->seconds,
+ "CPU System Time", CPU_SYS_GRAPH_INDEX, MPSTAT_SYS)) {
+ svg_write_time_line(plot, i / graph_width_factor);
+ close_plot(plot);
+ }
+
+ __plot_queue_depth(plot, tf->gdd_reads->seconds);
+ svg_write_time_line(plot, i / graph_width_factor);
+
+ close_plot_col(plot);
+
+ /* movie graph starts here */
+ plot->start_y_offset = orig_y_offset;
+ set_graph_size(cols - cols / graph_width_factor, rows);
+ plot->no_legend = 0;
+
if (movie_style == MOVIE_SPINDLE)
setup_axis_spindle(plot);
else
@@ -705,15 +870,8 @@ static void plot_io_movie(struct plot *plot)
svg_write_legend(plot);
close_plot(plot);
-
- set_graph_size(cols, rows / 7);
- plot->add_xlabel = 1;
- __plot_tput(plot, tf->gdd_reads->seconds);
- svg_write_time_line(plot, i);
close_plot(plot);
- set_graph_size(cols, rows);
- close_plot(plot);
close_plot_file(plot);
}
free_all_plot_history(&movie_history_reads);
@@ -725,98 +883,6 @@ static void plot_io_movie(struct plot *plot)
free(movie_dir);
}
-static void plot_cpu(struct plot *plot, int seconds, char *label,
- int active_index, int gld_index)
-{
- struct trace_file *tf;
- int max = 0;
- int i;
- int gld_i;
- char *color;
- double avg = 0;
- int ymax;
- int plotted = 0;
-
- if (active_graphs[active_index] == 0)
- return;
-
- list_for_each_entry(tf, &all_traces, list) {
- if (tf->trace->mpstat_num_cpus > max)
- max = tf->trace->mpstat_num_cpus;
- }
- if (max == 0)
- return;
-
- tf = list_entry(all_traces.next, struct trace_file, list);
-
- ymax = tf->mpstat_gld[gld_index]->max;
- if (ymax == 0)
- return;
-
- svg_alloc_legend(plot, num_traces * max);
-
- plot->add_xlabel = last_active_graph == active_index;
- setup_axis(plot);
- set_plot_label(plot, label);
-
- seconds = tf->mpstat_seconds;
-
- set_yticks(plot, 4, 0, tf->mpstat_gld[gld_index]->max, "");
- set_ylabel(plot, "Percent");
- set_xticks(plot, 9, 0, seconds);
-
- cpu_color_index = 0;
- list_for_each_entry(tf, &all_traces, list) {
- for (i = 0; i < tf->mpstat_gld[0]->stop_seconds; i++) {
- if (tf->mpstat_gld[gld_index]->data[i].count) {
- avg += (tf->mpstat_gld[gld_index]->data[i].sum /
- tf->mpstat_gld[gld_index]->data[i].count);
- }
- }
- avg /= tf->mpstat_gld[gld_index]->stop_seconds;
- color = pick_cpu_color();
- svg_line_graph(plot, tf->mpstat_gld[0], color, 0, 0);
- svg_add_legend(plot, tf->label, " avg", color);
-
- for (i = 1; i < tf->trace->mpstat_num_cpus + 1; i++) {
- struct graph_line_data *gld = tf->mpstat_gld[i * MPSTAT_GRAPHS + gld_index];
- double this_avg = 0;
-
- for (gld_i = 0; gld_i < gld->stop_seconds; gld_i++)
- this_avg += gld->data[i].sum /
- gld->data[i].count;;
-
- this_avg /= gld->stop_seconds;
-
- for (gld_i = 0; gld_i < gld->stop_seconds; gld_i++) {
- double val;
-
- if (gld->data[gld_i].count == 0)
- continue;
- val = (double)gld->data[gld_i].sum /
- gld->data[gld_i].count;
-
- if (this_avg > avg + 30 || val > 95) {
- color = pick_cpu_color();
- svg_line_graph(plot, gld, color, avg + 30, 95);
- snprintf(line, line_len, " CPU %d\n", i - 1);
- svg_add_legend(plot, tf->label, line, color);
- plotted++;
- break;
- }
-
- }
- }
- }
-
- if (plot->add_xlabel)
- set_xlabel(plot, "Time (seconds)");
-
- svg_write_legend(plot);
- svg_free_legend(plot);
- close_plot(plot);
-}
-
static void plot_latency(struct plot *plot, int seconds)
{
struct trace_file *tf;
@@ -861,38 +927,6 @@ static void plot_latency(struct plot *plot, int seconds)
close_plot(plot);
}
-static void plot_queue_depth(struct plot *plot, int seconds)
-{
- struct trace_file *tf;
-
- if (active_graphs[QUEUE_DEPTH_GRAPH_INDEX] == 0)
- return;
-
- plot->add_xlabel = last_active_graph == QUEUE_DEPTH_GRAPH_INDEX;
-
- setup_axis(plot);
- set_plot_label(plot, "Queue Depth");
- if (num_traces > 1)
- svg_alloc_legend(plot, num_traces);
-
- tf = list_entry(all_traces.next, struct trace_file, list);
- set_ylabel(plot, "Pending IO");
- set_yticks(plot, 4, 0, tf->queue_depth_gld->max, "");
- set_xticks(plot, 9, 0, seconds);
-
- list_for_each_entry(tf, &all_traces, list) {
- svg_line_graph(plot, tf->queue_depth_gld, tf->read_color, 0, 0);
- if (num_traces > 1)
- svg_add_legend(plot, tf->label, "", tf->read_color);
- }
-
- if (plot->add_xlabel)
- set_xlabel(plot, "Time (seconds)");
- if (num_traces > 1)
- svg_write_legend(plot);
- close_plot(plot);
-}
-
static void plot_iops(struct plot *plot, int seconds)
{
struct trace_file *tf;
@@ -1075,7 +1109,7 @@ int main(int ac, char **av)
if (make_movie) {
set_io_graph_scale(256);
if (movie_style == MOVIE_SPINDLE)
- set_graph_size(550, 550);
+ set_graph_size(750, 550);
else
set_graph_size(700, 400);
}
diff --git a/iowatcher/plot.c b/iowatcher/plot.c
index d59c5c7..f1ebc61 100644
--- a/iowatcher/plot.c
+++ b/iowatcher/plot.c
@@ -241,6 +241,8 @@ void write_svg_header(int fd)
write(fd, header, strlen(header));
/* write a bunch of spaces so we can stuff in the width and height later */
write(fd, spaces, strlen(spaces));
+ write(fd, spaces, strlen(spaces));
+ write(fd, spaces, strlen(spaces));
write(fd, defs_start, strlen(defs_start));
write(fd, filter1, strlen(filter1));
@@ -322,33 +324,40 @@ void setup_axis(struct plot *plot)
int len;
int fd = plot->fd;
int bump_height = tick_font_size * 3 + axis_label_font_size;
+ int local_legend_width = legend_width;
- plot->total_width = axis_x_off(graph_width) + graph_left_pad / 2 + legend_width;
+ if (plot->no_legend)
+ local_legend_width = 0;
+
+ plot->total_width = axis_x_off(graph_width) + graph_left_pad / 2 + local_legend_width;;
plot->total_height = axis_y() + tick_label_pad + tick_font_size;
if (plot->add_xlabel)
plot->total_height += bump_height;
/* backing rect */
- snprintf(line, line_len, "<rect x=\"0\" y=\"%d\" width=\"%d\" "
+ snprintf(line, line_len, "<rect x=\"%d\" y=\"%d\" width=\"%d\" "
"height=\"%d\" fill=\"white\" stroke=\"none\"/>",
+ plot->start_x_offset,
plot->start_y_offset, plot->total_width + 40,
plot->total_height + 20);
len = strlen(line);
write(fd, line, len);
- snprintf(line, line_len, "<rect x=\"15\" y=\"%d\" width=\"%d\" "
+ snprintf(line, line_len, "<rect x=\"%d\" y=\"%d\" width=\"%d\" "
"filter=\"url(#shadow)\" "
"height=\"%d\" fill=\"white\" stroke=\"none\"/>",
+ plot->start_x_offset + 15,
plot->start_y_offset, plot->total_width, plot->total_height);
len = strlen(line);
write(fd, line, len);
plot->total_height += 20;
+ plot->total_width += 20;
if (plot->total_height + plot->start_y_offset > final_height)
final_height = plot->total_height + plot->start_y_offset;
- if (plot->total_width + 40 > final_width)
- final_width = plot->total_width + 40;
+ if (plot->start_x_offset + plot->total_width + 40 > final_width)
+ final_width = plot->start_x_offset + plot->total_width + 40;
/* create an svg object for all our coords to be relative against */
snprintf(line, line_len, "<svg x=\"%d\" y=\"%d\">\n", plot->start_x_offset, plot->start_y_offset);
@@ -377,32 +386,37 @@ void setup_axis_spindle(struct plot *plot)
int fd = plot->fd;
int bump_height = tick_font_size * 3 + axis_label_font_size;
- plot->total_width = axis_x_off(graph_width) + graph_left_pad / 2 + legend_width;
+ legend_x_off = -60;
+
+ plot->total_width = axis_x_off(graph_width) + legend_width;
plot->total_height = axis_y() + tick_label_pad + tick_font_size;
if (plot->add_xlabel)
plot->total_height += bump_height;
/* backing rect */
- snprintf(line, line_len, "<rect x=\"0\" y=\"%d\" width=\"%d\" "
+ snprintf(line, line_len, "<rect x=\"%d\" y=\"%d\" width=\"%d\" "
"height=\"%d\" fill=\"white\" stroke=\"none\"/>",
- plot->start_y_offset, plot->total_width + 40,
+ plot->start_x_offset,
+ plot->start_y_offset, plot->total_width + 10,
plot->total_height + 20);
len = strlen(line);
write(fd, line, len);
- snprintf(line, line_len, "<rect x=\"15\" y=\"%d\" width=\"%d\" "
+ snprintf(line, line_len, "<rect x=\"%d\" y=\"%d\" width=\"%d\" "
"filter=\"url(#shadow)\" "
"height=\"%d\" fill=\"white\" stroke=\"none\"/>",
- plot->start_y_offset, plot->total_width, plot->total_height);
+ plot->start_x_offset + 15,
+ plot->start_y_offset, plot->total_width - 30,
+ plot->total_height);
len = strlen(line);
write(fd, line, len);
plot->total_height += 20;
if (plot->total_height + plot->start_y_offset > final_height)
final_height = plot->total_height + plot->start_y_offset;
- if (plot->total_width + 40 > final_width)
- final_width = plot->total_width + 40;
+ if (plot->start_x_offset + plot->total_width + 40 > final_width)
+ final_width = plot->start_x_offset + plot->total_width + 40;
/* create an svg object for all our coords to be relative against */
snprintf(line, line_len, "<svg x=\"%d\" y=\"%d\">\n", plot->start_x_offset, plot->start_y_offset);
@@ -587,6 +601,22 @@ int close_plot(struct plot *plot)
return 0;
}
+int close_plot_no_height(struct plot *plot)
+{
+ close_svg(plot->fd);
+ plot->add_xlabel = 0;
+ return 0;
+}
+
+int close_plot_col(struct plot *plot)
+{
+ close_svg(plot->fd);
+ plot->start_x_offset += plot->total_width;
+ plot->add_xlabel = 0;
+ return 0;
+}
+
+
struct plot *alloc_plot(void)
{
struct plot *plot;
@@ -613,6 +643,9 @@ int close_plot_file(struct plot *plot)
"width=\"%d\" height=\"%d\">\n",
final_width, final_height);
write(plot->fd, line, strlen(line));
+ snprintf(line, line_len, "<rect x=\"0\" y=\"0\" width=\"%d\" "
+ "height=\"%d\" fill=\"white\"/>\n", final_width, final_height);
+ write(plot->fd, line, strlen(line));
close(plot->fd);
plot->fd = 0;
return 0;
diff --git a/iowatcher/plot.h b/iowatcher/plot.h
index 11434c4..fd0fa2a 100644
--- a/iowatcher/plot.h
+++ b/iowatcher/plot.h
@@ -36,6 +36,7 @@ struct plot {
int start_x_offset;
int add_xlabel;
+ int no_legend;
/*
* these two are for anyone that wants
@@ -114,6 +115,7 @@ void print_gdd(struct graph_dot_data *gdd);
void write_svg_header(int fd);
struct plot *alloc_plot(void);
int close_plot(struct plot *plot);
+int close_plot_no_height(struct plot *plot);
void setup_axis(struct plot *plot);
void set_xticks(struct plot *plot, int num_ticks, int first, int last);
void set_yticks(struct plot *plot, int num_ticks, int first, int last, char *units);
@@ -144,4 +146,5 @@ int close_plot_file(struct plot *plot);
int svg_io_graph_movie_array_spindle(struct plot *plot, struct plot_history *ph);
void rewind_spindle_steps(int num);
void setup_axis_spindle(struct plot *plot);
+int close_plot_col(struct plot *plot);
#endif