iowatcher: Start support for multiple colums of plots
authorChris Mason <chris.mason@fusionio.com>
Mon, 27 Aug 2012 21:39:58 +0000 (17:39 -0400)
committerChris Mason <chris.mason@oracle.com>
Mon, 27 Aug 2012 21:39:58 +0000 (17:39 -0400)
The movie mode is updated to put extra plots on
the side.

Signed-off-by: Chris Mason <chris.mason@fusionio.com>
iowatcher/main.c
iowatcher/plot.c
iowatcher/plot.h

index 22c0bb6086f7eeef351b67158b6e2bb05dcd2744..90eef0faf5a36b39ca64db6537fda11b98466fa4 100644 (file)
@@ -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);
        }
index d59c5c75c8795621c1f238bf5f180f1c0a828e30..f1ebc61dabf63de65a0e4152573a7e0f4fc15207 100644 (file)
@@ -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;
index 11434c46983c9a56f8a6b1edfec76820821ecf84..fd0fa2a6587931ad9bc8a925e376f8421c1ba957 100644 (file)
@@ -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