diff options
author | Chris Mason <chris.mason@fusionio.com> | 2012-08-21 15:19:35 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2012-08-22 21:42:17 -0400 |
commit | abf08f96c0c90f2ef59c4ae5c1fe849803bf02de (patch) | |
tree | 3ab811627b5da742df94765196d74d8f90086176 | |
parent | 7a147342d67ca55908d4d726ba36eb9ba2446c62 (diff) | |
download | blktrace-abf08f96c0c90f2ef59c4ae5c1fe849803bf02de.tar.gz |
iowatcher: Add a new movie mode that maps the IOs onto a platter.
The --movie option defaults to spindle mode now,
but you can choose --movie=rect or --movie=spindle
as well.
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
-rw-r--r-- | iowatcher/main.c | 77 | ||||
-rw-r--r-- | iowatcher/plot.c | 173 | ||||
-rw-r--r-- | iowatcher/plot.h | 7 |
3 files changed, 226 insertions, 31 deletions
diff --git a/iowatcher/main.c b/iowatcher/main.c index bc6132a..9eb7f3b 100644 --- a/iowatcher/main.c +++ b/iowatcher/main.c @@ -115,6 +115,31 @@ static char *graphs_by_name[] = { "iops", }; +enum { + MOVIE_SPINDLE, + MOVIE_RECT, + NUM_MOVIE_STYLES, +}; + +char *movie_styles[] = { + "spindle", + "rect", + NULL +}; + +static int movie_style = 0; + +static int lookup_movie_style(char *str) +{ + int i; + + for (i = 0; i < NUM_MOVIE_STYLES; i++) { + if (strcmp(str, movie_styles[i]) == 0) + return i; + } + return -1; +} + static int active_graphs[TOTAL_GRAPHS]; static int last_active_graph = IOPS_GRAPH_INDEX; @@ -423,7 +448,7 @@ static void set_all_max_tf(int seconds, u64 max_offset) static char *create_movie_temp_dir(void) { char *ret; - char *pattern = strdup("btrfs-movie-XXXXXX");; + char *pattern = strdup("io-movie-XXXXXX");; ret = mkdtemp(pattern); if (!ret) { @@ -473,16 +498,16 @@ static void add_history(struct plot_history *ph, struct list_head *list) static void plot_movie_history(struct plot *plot, struct list_head *list) { - float alpha = 0.1; struct plot_history *ph; + if (num_histories > 2) + rewind_spindle_steps(num_histories - 1); + list_for_each_entry(ph, list, list) { - if (ph->list.next == list) - alpha = 1; - svg_io_graph_movie_array(plot, ph, 1); - alpha += 0.2; - if (alpha > 1) - alpha = 0.8; + if (movie_style == MOVIE_SPINDLE) + svg_io_graph_movie_array_spindle(plot, ph); + else + svg_io_graph_movie_array(plot, ph); } } @@ -600,7 +625,7 @@ static void convert_movie_files(char *movie_dir) static void mencode_movie(char *movie_dir) { fprintf(stderr, "Creating movie %s\n", movie_dir); - snprintf(line, line_len, "ffmpeg -r 25 -y -i %s/%%10d-%s.svg.png -b:v 250k " + snprintf(line, line_len, "ffmpeg -r 20 -y -i %s/%%10d-%s.svg.png -b:v 250k " "-vcodec libx264 %s", movie_dir, output_filename, output_filename); system(line); } @@ -624,7 +649,7 @@ static void plot_io_movie(struct plot *plot) struct plot_history *write_history; int batch_i; int movie_len = 30; - int movie_frames_per_sec = 16; + int movie_frames_per_sec = 20; int total_frames = movie_len * movie_frames_per_sec; int rows, cols; int batch_count; @@ -646,7 +671,11 @@ static void plot_io_movie(struct plot *plot) set_plot_output(plot, line); set_plot_title(plot, graph_title); - setup_axis(plot); + if (movie_style == MOVIE_SPINDLE) + setup_axis_spindle(plot); + else + setup_axis(plot); + svg_alloc_legend(plot, num_traces * 2); read_history = alloc_plot_history(tf->read_color); @@ -661,9 +690,7 @@ static void plot_io_movie(struct plot *plot) batch_i = 0; while (i < cols && batch_i < batch_count) { - /* print just this column */ svg_io_graph_movie(tf->gdd_reads, read_history, i); - svg_io_graph_movie(tf->gdd_writes, write_history, i); i++; batch_i++; @@ -678,7 +705,7 @@ static void plot_io_movie(struct plot *plot) svg_write_legend(plot); close_plot(plot); - set_graph_size(cols, rows / 3); + set_graph_size(cols, rows / 7); plot->add_xlabel = 1; __plot_tput(plot, tf->gdd_reads->seconds); svg_write_time_line(plot, i); @@ -686,6 +713,7 @@ static void plot_io_movie(struct plot *plot) set_graph_size(cols, rows); close_plot(plot); + close_plot_file(plot); } free_all_plot_history(&movie_history_reads); free_all_plot_history(&movie_history_writes); @@ -907,7 +935,7 @@ enum { HELP_LONG_OPT = 1, }; -char *option_string = "T:t:o:l:r:O:N:d:p:mh:w:"; +char *option_string = "T:t:o:l:r:O:N:d:p:m::h:w:"; static struct option long_options[] = { {"title", required_argument, 0, 'T'}, {"trace", required_argument, 0, 't'}, @@ -918,7 +946,7 @@ static struct option long_options[] = { {"only-graph", required_argument, 0, 'O'}, {"device", required_argument, 0, 'd'}, {"prog", required_argument, 0, 'p'}, - {"movie", no_argument, 0, 'm'}, + {"movie", optional_argument, 0, 'm'}, {"width", required_argument, 0, 'w'}, {"height", required_argument, 0, 'h'}, {"help", no_argument, 0, HELP_LONG_OPT}, @@ -933,7 +961,7 @@ static void print_usage(void) "\t-l (--label): trace label in the graph\n" "\t-o (--output): output file name (SVG only)\n" "\t-p (--prog): program to run while blktrace is run\n" - "\t-p (--movie): create IO animations\n" + "\t-p (--movie [=spindle|rect]): create IO animations\n" "\t-r (--rolling): number of seconds in the rolling averge\n" "\t-T (--title): graph title\n" "\t-N (--no-graph): skip a single graph (io, tput, latency, queue_depth, iops)\n" @@ -993,6 +1021,15 @@ static int parse_options(int ac, char **av) break; case 'm': make_movie = 1; + if (optarg) { + movie_style = lookup_movie_style(optarg); + if (movie_style < 0) { + fprintf(stderr, "Unknown movie style %s\n", optarg); + print_usage(); + } + } + fprintf(stderr, "Using movie style: %s\n", + movie_styles[movie_style]); break; case 'h': opt_graph_height = atoi(optarg); @@ -1029,7 +1066,10 @@ int main(int ac, char **av) last_active_graph = last_graph(); if (make_movie) { set_io_graph_scale(256); - set_graph_size(700, 250); + if (movie_style == MOVIE_SPINDLE) + set_graph_size(550, 550); + else + set_graph_size(700, 400); } if (opt_graph_height) set_graph_height(opt_graph_height); @@ -1119,5 +1159,6 @@ int main(int ac, char **av) /* once for all */ close_plot(plot); + close_plot_file(plot); return 0; } diff --git a/iowatcher/plot.c b/iowatcher/plot.c index ce8fab8..7f30f77 100644 --- a/iowatcher/plot.c +++ b/iowatcher/plot.c @@ -34,8 +34,9 @@ #include "plot.h" static int io_graph_scale = 8; -static int graph_width = 600; -static int graph_height = 150; +static int graph_width = 700; +static int graph_height = 250; +static int graph_circle_extra = 30; static int graph_inner_x_margin = 2; static int graph_inner_y_margin = 2; static int graph_tick_len = 5; @@ -65,6 +66,9 @@ static int rolling_avg_secs = 0; static int line_len = 1024; static char line[1024]; +static int final_height = 0; +static int final_width = 0; + struct graph_line_data *alloc_line_data(int seconds, int stop_seconds) { int size = sizeof(struct graph_line_data) + (stop_seconds + 1) * sizeof(struct graph_line_pair); @@ -210,7 +214,8 @@ static double rolling_avg(struct graph_line_pair *data, int index, int distance) void write_svg_header(int fd) { - char *header = "<svg xmlns=\"http://www.w3.org/2000/svg\"\nxmlns:xlink=\"http://www.w3.org/1999/xlink\">\n"; + char *spaces = " \n"; + char *header = "<svg xmlns=\"http://www.w3.org/2000/svg\">\n"; char *filter1 ="<filter id=\"shadow\">\n " "<feOffset result=\"offOut\" in=\"SourceAlpha\" dx=\"4\" dy=\"4\" />\n " "<feGaussianBlur result=\"blurOut\" in=\"offOut\" stdDeviation=\"2\" />\n " @@ -230,8 +235,13 @@ void write_svg_header(int fd) "</filter>\n"; char *defs_start = "<defs>\n"; char *defs_close = "</defs>\n"; + final_width = 0; + final_height = 0; 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, defs_start, strlen(defs_start)); write(fd, filter1, strlen(filter1)); write(fd, filter2, strlen(filter2)); @@ -313,7 +323,6 @@ void setup_axis(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; plot->total_height = axis_y() + tick_label_pad + tick_font_size; @@ -327,6 +336,7 @@ void setup_axis(struct plot *plot) plot->total_height + 20); len = strlen(line); write(fd, line, len); + snprintf(line, line_len, "<rect x=\"15\" y=\"%d\" width=\"%d\" " "filter=\"url(#shadow)\" " "height=\"%d\" fill=\"white\" stroke=\"none\"/>", @@ -335,9 +345,13 @@ void setup_axis(struct plot *plot) 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; /* create an svg object for all our coords to be relative against */ - snprintf(line, line_len, "<svg x=\"%d\" y=\"%d\" style=\"enable-background:new\">\n", plot->start_x_offset, plot->start_y_offset); + snprintf(line, line_len, "<svg x=\"%d\" y=\"%d\">\n", plot->start_x_offset, plot->start_y_offset); write(fd, line, strlen(line)); snprintf(line, 1024, "<path d=\"M%d %d h %d V %d H %d Z\" stroke=\"black\" stroke-width=\"2\" fill=\"none\"/>\n", @@ -352,6 +366,50 @@ void setup_axis(struct plot *plot) } } +/* + * this draws a backing rectangle for the plot and it + * also creates a new svg element so our offsets can + * be relative to this one plot. + */ +void setup_axis_spindle(struct plot *plot) +{ + int len; + 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; + 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\" " + "height=\"%d\" fill=\"white\" stroke=\"none\"/>", + 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\" " + "filter=\"url(#shadow)\" " + "height=\"%d\" fill=\"white\" stroke=\"none\"/>", + plot->start_y_offset, plot->total_width, 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; + + /* 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); + write(fd, line, strlen(line)); + +} + /* draw a plot title. This should be done only once, * and it bumps the plot width/height numbers by * what it draws. @@ -541,12 +599,31 @@ struct plot *alloc_plot(void) return plot; } +int close_plot_file(struct plot *plot) +{ + int ret; + ret = lseek(plot->fd, 0, SEEK_SET); + if (ret == (off_t)-1) { + perror("seek"); + exit(1); + } + final_width = ((final_width + 1) / 2) * 2; + final_height = ((final_height + 1) / 2) * 2; + snprintf(line, line_len, "<svg xmlns=\"http://www.w3.org/2000/svg\" " + "width=\"%d\" height=\"%d\">\n", + final_width, final_height); + write(plot->fd, line, strlen(line)); + close(plot->fd); + plot->fd = 0; + return 0; +} + void set_plot_output(struct plot *plot, char *filename) { int fd; if (plot->fd) - close(plot->fd); + close_plot_file(plot); fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600); if (fd < 0) { fprintf(stderr, "Unable to open output file %s err %s\n", filename, strerror(errno)); @@ -644,17 +721,17 @@ void svg_write_time_line(struct plot *plot, int col) write(plot->fd, line, strlen(line)); } -static int svg_add_io(int fd, double row, double col, double width, double height, char *color, float alpha) +static int svg_add_io(int fd, double row, double col, double width, double height, char *color) { float rx = 0; snprintf(line, line_len, "<rect x=\"%.2f\" y=\"%.2f\" width=\"%.1f\" height=\"%.1f\" " - "rx=\"%.2f\" style=\"stroke:none;fill:%s;stroke-width:0;opacity:%.2f\"/>\n", - axis_x_off_double(col), axis_y_off_double(row), width, height, rx, color, alpha); + "rx=\"%.2f\" style=\"stroke:none;fill:%s;stroke-width:0\"/>\n", + axis_x_off_double(col), axis_y_off_double(row), width, height, rx, color); return write(fd, line, strlen(line)); } -int svg_io_graph_movie_array(struct plot *plot, struct plot_history *ph, float alpha) +int svg_io_graph_movie_array(struct plot *plot, struct plot_history *ph) { double cell_index; double movie_row; @@ -665,7 +742,78 @@ int svg_io_graph_movie_array(struct plot *plot, struct plot_history *ph, float a cell_index = ph->history[i]; movie_row = floor(cell_index / graph_width); movie_col = cell_index - movie_row * graph_width; - svg_add_io(plot->fd, movie_row, movie_col, 4, 4, ph->color, alpha); + svg_add_io(plot->fd, movie_row, movie_col, 4, 4, ph->color); + } + return 0; +} + +static float spindle_steps = 0; + +void rewind_spindle_steps(int num) +{ + spindle_steps -= num * 0.01; +} + +int svg_io_graph_movie_array_spindle(struct plot *plot, struct plot_history *ph) +{ + double cell_index; + int i; + int num_circles = 0; + double cells_per_circle; + double circle_num; + double degrees_per_cell; + double rot; + double center_x; + double center_y; + double graph_width_extra = graph_width + graph_circle_extra; + double graph_height_extra = graph_height + graph_circle_extra; + double radius;; + + if (graph_width_extra > graph_height_extra) + graph_width_extra = graph_height_extra; + + if (graph_width_extra < graph_height_extra) + graph_height_extra = graph_width_extra; + + radius = graph_width_extra; + + center_x = axis_x_off_double(graph_width_extra / 2); + center_y = axis_y_off_double(graph_height_extra / 2); + + snprintf(line, line_len, "<g transform=\"rotate(%.4f, %.2f, %.2f)\"> " + "<circle cx=\"%.2f\" cy=\"%.2f\" " + "stroke=\"black\" stroke-width=\"6\" " + "r=\"%.2f\" fill=\"none\"/>\n", + -spindle_steps * 1.2, center_x, center_y, center_x, center_y, graph_width_extra / 2); + write(plot->fd, line, strlen(line)); + snprintf(line, line_len, "<circle cx=\"%.2f\" cy=\"%.2f\" " + "stroke=\"none\" fill=\"red\" r=\"%.2f\"/>\n</g>\n", + axis_x_off_double(graph_width_extra), center_y, 4.5); + write(plot->fd, line, strlen(line)); + spindle_steps += 0.01; + + radius = floor(radius / 2); + num_circles = radius / 4 - 3; + cells_per_circle = ph->history_max / num_circles; + degrees_per_cell = 360 / cells_per_circle; + + for (i = 0; i < ph->num_used; i++) { + cell_index = ph->history[i]; + circle_num = floor(cell_index / cells_per_circle); + rot = cell_index - circle_num * cells_per_circle; + circle_num = num_circles - circle_num; + radius = circle_num * 4; + + rot = rot * degrees_per_cell; + rot -= spindle_steps; + snprintf(line, line_len, "<path transform=\"rotate(%.4f, %.2f, %.2f)\" " + "d=\"M %.2f %.2f a %.2f %.2f 0 0 1 0 5\" " + "stroke=\"%s\" stroke-width=\"4\"/>\n", + rot, center_x, center_y, + axis_x_off_double(graph_width_extra / 2 + radius) + 8, center_y, + radius, radius, ph->color); + + write(plot->fd, line, strlen(line)); } return 0; } @@ -698,6 +846,7 @@ int svg_io_graph_movie(struct graph_dot_data *gdd, struct plot_history *ph, int int margin_orig = graph_inner_y_margin; graph_inner_y_margin += 5; + ph->history_max = gdd->max_offset / movie_blocks_per_cell; for (row = gdd->rows - 1; row >= 0; row--) { bit_index = row * gdd->cols + col; @@ -741,7 +890,7 @@ int svg_io_graph(struct plot *plot, struct graph_dot_data *gdd, char *color) continue; val = gdd->data[arr_index]; if (val & (1 << bit_mod)) - svg_add_io(fd, floor(row / io_graph_scale), col, 1.5, 1.5, color, 1.0); + svg_add_io(fd, floor(row / io_graph_scale), col, 1.5, 1.5, color); } } return 0; diff --git a/iowatcher/plot.h b/iowatcher/plot.h index 938cc18..1d534dd 100644 --- a/iowatcher/plot.h +++ b/iowatcher/plot.h @@ -90,6 +90,7 @@ struct graph_dot_data { struct plot_history { struct list_head list; + double history_max; int history_len; int num_used; int col; @@ -130,8 +131,12 @@ void set_plot_output(struct plot *plot, char *filename); void set_graph_size(int width, int height); void get_graph_size(int *width, int *height); int svg_io_graph_movie(struct graph_dot_data *gdd, struct plot_history *ph, int col); -int svg_io_graph_movie_array(struct plot *plot, struct plot_history *ph, float alpha); +int svg_io_graph_movie_array(struct plot *plot, struct plot_history *ph); void svg_write_time_line(struct plot *plot, int col); void set_graph_height(int h); void set_graph_width(int w); +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); #endif |