iowatcher: Fix io line graphs at the edge of the X axis
[blktrace.git] / iowatcher / main.c
index bc6132ad0e65da23fcd0820dde348ebad04fa5c2..22c0bb6086f7eeef351b67158b6e2bb05dcd2744 100644 (file)
@@ -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;
 
@@ -260,6 +285,8 @@ static void read_traces(void)
        u64 last_time;
        u64 ymin;
        u64 ymax;
+       u64 max_bank;
+       u64 max_bank_offset;
 
        list_for_each_entry(tf, &all_traces, list) {
                trace = open_trace(tf->filename);
@@ -270,8 +297,8 @@ static void read_traces(void)
                tf->trace = trace;
                tf->seconds = SECONDS(last_time);
                tf->stop_seconds = SECONDS(last_time);
-               tf->max_offset = find_highest_offset(trace);
-
+               find_highest_offset(trace, &tf->max_offset, &max_bank,
+                                   &max_bank_offset);
                filter_outliers(trace, tf->max_offset, &ymin, &ymax);
                tf->max_offset = ymax;
 
@@ -423,7 +450,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 +500,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);
         }
 }
 
@@ -501,9 +528,6 @@ static void __plot_io(struct plot *plot, int seconds, u64 max_offset)
 {
        struct trace_file *tf;
 
-       if (active_graphs[IO_GRAPH_INDEX] == 0)
-               return;
-
        setup_axis(plot);
 
        svg_alloc_legend(plot, num_traces * 2);
@@ -534,8 +558,10 @@ static void __plot_io(struct plot *plot, int seconds, u64 max_offset)
 
 static void plot_io(struct plot *plot, int seconds, u64 max_offset)
 {
-       plot->add_xlabel = last_active_graph == IO_GRAPH_INDEX;
+       if (active_graphs[IO_GRAPH_INDEX] == 0)
+               return;
 
+       plot->add_xlabel = last_active_graph == IO_GRAPH_INDEX;
        __plot_io(plot, seconds, max_offset);
        close_plot(plot);
 }
@@ -547,9 +573,6 @@ static void __plot_tput(struct plot *plot, int seconds)
        char line[128];
        u64 max = 0;
 
-       if (active_graphs[TPUT_GRAPH_INDEX] == 0)
-               return;
-
        if (num_traces > 1)
                svg_alloc_legend(plot, num_traces);
        list_for_each_entry(tf, &all_traces, list) {
@@ -571,7 +594,7 @@ static void __plot_tput(struct plot *plot, int seconds)
        set_xticks(plot, 9, 0, seconds);
 
        list_for_each_entry(tf, &all_traces, list) {
-               svg_line_graph(plot, tf->tput_gld, tf->read_color);
+               svg_line_graph(plot, tf->tput_gld, tf->read_color, 0, 0);
                if (num_traces > 1)
                        svg_add_legend(plot, tf->label, "", tf->read_color);
        }
@@ -584,6 +607,9 @@ static void __plot_tput(struct plot *plot, int seconds)
 
 static void plot_tput(struct plot *plot, int seconds)
 {
+       if (active_graphs[TPUT_GRAPH_INDEX] == 0)
+               return;
+
        plot->add_xlabel = last_active_graph == TPUT_GRAPH_INDEX;
        __plot_tput(plot, seconds);
        close_plot(plot);
@@ -600,7 +626,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 +650,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 +672,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 +691,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 +706,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 +714,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);
@@ -700,7 +729,6 @@ static void plot_cpu(struct plot *plot, int seconds, char *label,
                     int active_index, int gld_index)
 {
        struct trace_file *tf;
-       char line[128];
        int max = 0;
        int i;
        int gld_i;
@@ -740,11 +768,14 @@ static void plot_cpu(struct plot *plot, int seconds, char *label,
        cpu_color_index = 0;
        list_for_each_entry(tf, &all_traces, list) {
                for (i = 0; i < tf->mpstat_gld[0]->stop_seconds; i++) {
-                       avg += tf->mpstat_gld[gld_index]->data[i].sum;
+                       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);
+               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++) {
@@ -752,16 +783,23 @@ static void plot_cpu(struct plot *plot, int seconds, char *label,
                        double this_avg = 0;
 
                        for (gld_i = 0; gld_i < gld->stop_seconds; gld_i++)
-                               this_avg += gld->data[i].sum;
+                               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++) {
-                               if (this_avg > avg + 30 ||
-                                   gld->data[gld_i].sum > 95) {
+                               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);
-                                       snprintf(line, 128, " CPU %d\n", i - 1);
+                                       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;
@@ -774,10 +812,8 @@ static void plot_cpu(struct plot *plot, int seconds, char *label,
        if (plot->add_xlabel)
                set_xlabel(plot, "Time (seconds)");
 
-       if (plot->legend_index <= 8)
-               svg_write_legend(plot);
-       else
-               svg_free_legend(plot);
+       svg_write_legend(plot);
+       svg_free_legend(plot);
        close_plot(plot);
 }
 
@@ -813,7 +849,7 @@ static void plot_latency(struct plot *plot, int seconds)
        set_xticks(plot, 9, 0, seconds);
 
        list_for_each_entry(tf, &all_traces, list) {
-               svg_line_graph(plot, tf->latency_gld, tf->read_color);
+               svg_line_graph(plot, tf->latency_gld, tf->read_color, 0, 0);
                if (num_traces > 1)
                        svg_add_legend(plot, tf->label, "", tf->read_color);
        }
@@ -845,7 +881,7 @@ static void plot_queue_depth(struct plot *plot, int seconds)
        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);
+               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);
        }
@@ -890,7 +926,7 @@ static void plot_iops(struct plot *plot, int seconds)
        set_xticks(plot, 9, 0, seconds);
 
        list_for_each_entry(tf, &all_traces, list) {
-               svg_line_graph(plot, tf->iop_gld, tf->read_color);
+               svg_line_graph(plot, tf->iop_gld, tf->read_color, 0, 0);
                if (num_traces > 1)
                        svg_add_legend(plot, tf->label, "", tf->read_color);
        }
@@ -907,7 +943,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 +954,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 +969,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 +1029,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 +1074,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 +1167,6 @@ int main(int ac, char **av)
 
        /* once for all */
        close_plot(plot);
+       close_plot_file(plot);
        return 0;
 }