aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@fusionio.com>2012-08-21 15:19:35 -0400
committerChris Mason <chris.mason@fusionio.com>2012-08-22 21:42:17 -0400
commitabf08f96c0c90f2ef59c4ae5c1fe849803bf02de (patch)
tree3ab811627b5da742df94765196d74d8f90086176
parent7a147342d67ca55908d4d726ba36eb9ba2446c62 (diff)
downloadblktrace-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.c77
-rw-r--r--iowatcher/plot.c173
-rw-r--r--iowatcher/plot.h7
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