diff options
author | Chris Mason <chris.mason@fusionio.com> | 2012-08-27 17:39:58 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2012-08-27 17:39:58 -0400 |
commit | 8ed9516f791ead08ade69c952b14d3b4f85c38ef (patch) | |
tree | 3d21a3a56edd66d91f9f2b822ef584eb12875f19 | |
parent | f106953d41597722efd068e67eaae5664ef5034d (diff) | |
download | blktrace-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.c | 300 | ||||
-rw-r--r-- | iowatcher/plot.c | 57 | ||||
-rw-r--r-- | iowatcher/plot.h | 3 |
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 |