iowatcher: Add support for limitting IO graph offset from below
authorJan Kara <jack@suse.cz>
Sat, 1 Sep 2012 21:31:46 +0000 (23:31 +0200)
committerChris Mason <chris.mason@oracle.com>
Tue, 11 Sep 2012 00:53:05 +0000 (20:53 -0400)
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
iowatcher/blkparse.c
iowatcher/blkparse.h
iowatcher/main.c
iowatcher/plot.c
iowatcher/plot.h

index 3aa44a6f5aae46639627dbb394d4db6725fcf304..ddcf2044081aa9d4e4fce4b8b2acd6d7bf06d2d3 100644 (file)
@@ -413,11 +413,11 @@ out:
        return -1;
 }
 
-void find_highest_offset(struct trace *trace, u64 *max_ret, u64 *max_bank_ret,
-                        u64 *max_offset_ret)
+void find_extreme_offsets(struct trace *trace, u64 *min_ret, u64 *max_ret, u64 *max_bank_ret,
+                         u64 *max_offset_ret)
 {
        u64 found = 0;
-       u64 max = 0;
+       u64 max = 0, min = ~(u64)0;
        u64 max_bank = 0;
        u64 max_bank_offset = 0;
        u64 num_banks = 0;
@@ -425,11 +425,12 @@ void find_highest_offset(struct trace *trace, u64 *max_ret, u64 *max_bank_ret,
        while (1) {
                if (!(trace->io->action & BLK_TC_ACT(BLK_TC_NOTIFY))) {
                        found = trace->io->sector << 9;
-                       found += trace->io->bytes;
+                       if (found < min)
+                               min = found;
 
-                       if (max < found) {
+                       found += trace->io->bytes;
+                       if (max < found)
                                max = found;
-                       }
                } else {
                        u64 bank;
                        u64 offset;
@@ -445,31 +446,41 @@ void find_highest_offset(struct trace *trace, u64 *max_ret, u64 *max_bank_ret,
                        break;
        }
        first_record(trace);
+       *min_ret = min;
        *max_ret = max;
        *max_bank_ret = max_bank;
        *max_offset_ret = max_bank_offset;
 }
 
-int filter_outliers(struct trace *trace, u64 max_offset,
+int filter_outliers(struct trace *trace, u64 min_offset, u64 max_offset,
                    u64 *yzoom_min, u64 *yzoom_max)
 {
        int hits[11];
        u64 max_per_bucket[11];
-       u64 bytes_per_bucket = max_offset / 10;
+       u64 min_per_bucket[11];
+       u64 bytes_per_bucket = (max_offset - min_offset + 1) / 10;
        int slot;
        int fat_count = 0;
 
        memset(hits, 0, sizeof(int) * 11);
        memset(max_per_bucket, 0, sizeof(u64) * 11);
+       memset(min_per_bucket, 0xff, sizeof(u64) * 11);
        first_record(trace);
        while (1) {
                if (!(trace->io->action & BLK_TC_ACT(BLK_TC_NOTIFY)) &&
                    (trace->io->action & BLK_TA_MASK) == __BLK_TA_QUEUE) {
-                       u64 top = (trace->io->sector << 9) + trace->io->bytes;
-                       slot = (int)(top / bytes_per_bucket);
+                       u64 off = (trace->io->sector << 9) - min_offset;
+
+                       slot = (int)(off / bytes_per_bucket);
+                       hits[slot]++;
+                       if (off < min_per_bucket[slot])
+                               min_per_bucket[slot] = off;
+
+                       off += trace->io->bytes;
+                       slot = (int)(off / bytes_per_bucket);
                        hits[slot]++;
-                       if (top > max_per_bucket[slot])
-                               max_per_bucket[slot] = top;
+                       if (off > max_per_bucket[slot])
+                               max_per_bucket[slot] = off;
                }
                if (next_record(trace))
                        break;
@@ -486,17 +497,17 @@ int filter_outliers(struct trace *trace, u64 max_offset,
                double d = hits[slot];
 
                if (d >= (double)fat_count * .05) {
-                       *yzoom_max = max_per_bucket[slot];
+                       *yzoom_max = max_per_bucket[slot] + min_offset;
                        break;
                }
        }
 
-       *yzoom_min = 0;
+       *yzoom_min = min_offset;
        for (slot = 0; slot < 10; slot++) {
                double d = hits[slot];
 
                if (d >= (double)fat_count * .05) {
-                       *yzoom_min = slot * bytes_per_bucket;
+                       *yzoom_min = min_per_bucket[slot] + min_offset;
                        break;
                }
        }
index a78a8b746ce683474f722297bd595ea38c8269e3..2eff331c9f940e9fc9b0dcdde600a766e9c90ce6 100644 (file)
@@ -63,9 +63,9 @@ static inline unsigned int MINOR(unsigned int dev)
 void init_io_hash_table(void);
 struct trace *open_trace(char *filename);
 u64 find_last_time(struct trace *trace);
-void find_highest_offset(struct trace *trace, u64 *max_ret, u64 *max_bank_ret,
-                        u64 *max_offset_ret);
-int filter_outliers(struct trace *trace, u64 max_offset,
+void find_extreme_offsets(struct trace *trace, u64 *min_ret, u64 *max_ret,
+                         u64 *max_bank_ret, u64 *max_offset_ret);
+int filter_outliers(struct trace *trace, u64 min_offset, u64 max_offset,
                    u64 *yzoom_min, u64 *yzoom_max);
 void add_iop(struct trace *trace, struct graph_line_data *gld);
 void check_record(struct trace *trace);
index 8adeaccd172ab17a22df0c712019da73df64194c..8ff2b656b988e46e4f380dd514d515389bafafe7 100644 (file)
@@ -163,6 +163,7 @@ struct trace_file {
        struct trace *trace;
        int seconds;
        int stop_seconds;
+       u64 min_offset;
        u64 max_offset;
 
        char *read_color;
@@ -283,8 +284,8 @@ static void setup_trace_file_graphs(void)
                tf->latency_gld = alloc_line_data(tf->seconds, tf->stop_seconds);
                tf->queue_depth_gld = alloc_line_data(tf->seconds, tf->stop_seconds);
                tf->iop_gld = alloc_line_data(tf->seconds, tf->stop_seconds);
-               tf->gdd_writes = alloc_dot_data(tf->seconds, tf->max_offset, tf->stop_seconds);
-               tf->gdd_reads = alloc_dot_data(tf->seconds, tf->max_offset, tf->stop_seconds);
+               tf->gdd_writes = alloc_dot_data(tf->seconds, tf->min_offset, tf->max_offset, tf->stop_seconds);
+               tf->gdd_reads = alloc_dot_data(tf->seconds, tf->min_offset, tf->max_offset, tf->stop_seconds);
 
                if (tf->trace->mpstat_num_cpus == 0)
                        continue;
@@ -318,9 +319,10 @@ static void read_traces(void)
                tf->trace = trace;
                tf->seconds = SECONDS(last_time);
                tf->stop_seconds = SECONDS(last_time);
-               find_highest_offset(trace, &tf->max_offset, &max_bank,
-                                   &max_bank_offset);
-               filter_outliers(trace, tf->max_offset, &ymin, &ymax);
+               find_extreme_offsets(trace, &tf->min_offset, &tf->max_offset,
+                                   &max_bank, &max_bank_offset);
+               filter_outliers(trace, tf->min_offset, tf->max_offset, &ymin, &ymax);
+               tf->min_offset = ymin;
                tf->max_offset = ymax;
 
                read_mpstat(trace, tf->filename);
@@ -450,20 +452,23 @@ static void set_blktrace_outfile(char *arg)
 }
 
 
-static void compare_max_tf(struct trace_file *tf, int *seconds, u64 *max_offset)
+static void compare_minmax_tf(struct trace_file *tf, int *seconds, u64 *min_offset, u64 *max_offset)
 {
        if (tf->seconds > *seconds)
                *seconds = tf->seconds;
        if (tf->max_offset > *max_offset)
                *max_offset = tf->max_offset;
+       if (tf->min_offset < *min_offset)
+               *min_offset = tf->min_offset;
 }
 
-static void set_all_max_tf(int seconds, u64 max_offset)
+static void set_all_minmax_tf(int seconds, u64 min_offset, u64 max_offset)
 {
        struct trace_file *tf;
 
        list_for_each_entry(tf, &all_traces, list) {
                tf->seconds = seconds;
+               tf->min_offset = min_offset;
                tf->max_offset = max_offset;
        }
 }
@@ -545,7 +550,7 @@ static void free_all_plot_history(struct list_head *head)
        }
 }
 
-static void plot_io(struct plot *plot, int seconds, u64 max_offset)
+static void plot_io(struct plot *plot, int seconds, u64 min_offset, u64 max_offset)
 {
        struct trace_file *tf;
 
@@ -558,7 +563,8 @@ static void plot_io(struct plot *plot, int seconds, u64 max_offset)
 
        set_plot_label(plot, "Device IO");
        set_ylabel(plot, "Offset (MB)");
-       set_yticks(plot, 4, 0, max_offset / (1024 * 1024), "");
+       set_yticks(plot, 4, min_offset / (1024 * 1024),
+                  max_offset / (1024 * 1024), "");
        set_xticks(plot, num_xticks, 0, seconds);
 
        list_for_each_entry(tf, &all_traces, list) {
@@ -1120,6 +1126,7 @@ int main(int ac, char **av)
        struct plot *plot;
        int seconds = 0;
        u64 max_offset = 0;
+       u64 min_offset = ~(u64)0;
        struct trace_file *tf;
        int ret;
        int rows, cols;
@@ -1185,10 +1192,9 @@ int main(int ac, char **av)
 
        /* step two, find the maxes for time and offset */
        list_for_each_entry(tf, &all_traces, list)
-               compare_max_tf(tf, &seconds, &max_offset);
-
+               compare_minmax_tf(tf, &seconds, &min_offset, &max_offset);
        /* push the max we found into all the tfs */
-       set_all_max_tf(seconds, max_offset);
+       set_all_minmax_tf(seconds, min_offset, max_offset);
 
        /* alloc graphing structs for all the traces */
        setup_trace_file_graphs();
@@ -1217,7 +1223,7 @@ int main(int ac, char **av)
                plot->add_xlabel = 1;
        set_plot_title(plot, graph_title);
 
-       plot_io(plot, seconds, max_offset);
+       plot_io(plot, seconds, min_offset, max_offset);
        plot->add_xlabel = 0;
 
        if (columns > 1) {
index 74bcb59646605b4192494152cd359814fa0fb635..ec597ff438315568053981a65318f94d0a15936f 100644 (file)
@@ -90,7 +90,7 @@ void free_line_data(struct graph_line_data *gld)
        free(gld);
 }
 
-struct graph_dot_data *alloc_dot_data(int seconds, u64 max_offset, int stop_seconds)
+struct graph_dot_data *alloc_dot_data(int seconds, u64 min_offset, u64 max_offset, int stop_seconds)
 {
        int size;
        int arr_size;
@@ -115,6 +115,7 @@ struct graph_dot_data *alloc_dot_data(int seconds, u64 max_offset, int stop_seco
        gdd->stop_seconds = stop_seconds;
        gdd->rows = rows;
        gdd->cols = cols;
+       gdd->min_offset = min_offset;
        gdd->max_offset = max_offset;
        return gdd;
 }
@@ -126,8 +127,7 @@ void free_dot_data(struct graph_dot_data *gdd)
 
 void set_gdd_bit(struct graph_dot_data *gdd, u64 offset, double bytes, double time)
 {
-       double bytes_per_row = (double)gdd->max_offset / gdd->rows;
-
+       double bytes_per_row = (double)(gdd->max_offset - gdd->min_offset + 1) / gdd->rows;
        double secs_per_col = (double)gdd->seconds / gdd->cols;
        double col;
        double row;
@@ -138,13 +138,13 @@ void set_gdd_bit(struct graph_dot_data *gdd, u64 offset, double bytes, double ti
        int bit_mod;
        double mod = bytes_per_row;
 
-       if (offset > gdd->max_offset)
+       if (offset > gdd->max_offset || offset < gdd->min_offset)
                return;
 
        gdd->total_ios++;
        time = time / 1000000000.0;
        while (bytes > 0) {
-               row = (double)offset / bytes_per_row;
+               row = (double)(offset - gdd->min_offset) / bytes_per_row;
                col = time / secs_per_col;
 
                col_int = floor(col);
@@ -561,7 +561,7 @@ void set_yticks(struct plot *plot, int num_ticks, int first, int last, char *uni
                         "fill=\"black\" style=\"text-anchor: %s\">%d%s</text>\n",
                        text_x,
                        axis_y_off(tick_y - tick_font_size / 2),
-                       font_family, tick_font_size, anchor, step * i, units);
+                       font_family, tick_font_size, anchor, first + step * i, units);
                write(plot->fd, line, strlen(line));
                tick_y += pixels_per_tick;
        }
@@ -904,13 +904,13 @@ int svg_io_graph_movie(struct graph_dot_data *gdd, struct plot_history *ph, int
        unsigned char val;
        int bit_index;
        int bit_mod;
-       double blocks_per_row = gdd->max_offset / gdd->rows;
-       double movie_blocks_per_cell = gdd->max_offset / (graph_width * graph_height);
+       double blocks_per_row = (gdd->max_offset - gdd->min_offset + 1) / gdd->rows;
+       double movie_blocks_per_cell = (gdd->max_offset - gdd->min_offset + 1) / (graph_width * graph_height);
        double cell_index;
        int margin_orig = graph_inner_y_margin;
 
        graph_inner_y_margin += 5;
-       ph->history_max = gdd->max_offset / movie_blocks_per_cell;
+       ph->history_max = (gdd->max_offset - gdd->min_offset + 1) / movie_blocks_per_cell;
 
        for (row = gdd->rows - 1; row >= 0; row--) {
                bit_index = row * gdd->cols + col;
index 2d9d8916626021a57c5780d339c9603385327338..d70abcb4b83a7922adc830625667fadf9050bffd 100644 (file)
@@ -82,6 +82,7 @@ struct graph_line_data {
 };
 
 struct graph_dot_data {
+       u64 min_offset;
        u64 max_offset;
        u64 max_bank;
        u64 max_bank_offset;
@@ -120,7 +121,7 @@ int svg_io_graph(struct plot *plot, struct graph_dot_data *gdd, char *color);
 int svg_line_graph(struct plot *plot, struct graph_line_data *gld, char *color, int thresh1, int thresh2);
 struct graph_line_data *alloc_line_data(int seconds, int stop_seconds);
 void free_line_data(struct graph_line_data *gld);
-struct graph_dot_data *alloc_dot_data(int seconds, u64 max_offset, int stop_seconds);
+struct graph_dot_data *alloc_dot_data(int seconds, u64 min_offset, u64 max_offset, int stop_seconds);
 void free_dot_data(struct graph_dot_data *gdd);
 void set_gdd_bit(struct graph_dot_data *gdd, u64 offset, double bytes, double time);
 void print_gdd(struct graph_dot_data *gdd);