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;
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;
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;
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;
}
}
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);
struct trace *trace;
int seconds;
int stop_seconds;
+ u64 min_offset;
u64 max_offset;
char *read_color;
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;
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);
}
-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;
}
}
}
}
-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;
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) {
struct plot *plot;
int seconds = 0;
u64 max_offset = 0;
+ u64 min_offset = ~(u64)0;
struct trace_file *tf;
int ret;
int rows, cols;
/* 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();
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) {
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;
gdd->stop_seconds = stop_seconds;
gdd->rows = rows;
gdd->cols = cols;
+ gdd->min_offset = min_offset;
gdd->max_offset = max_offset;
return 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;
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);
"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;
}
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;
};
struct graph_dot_data {
+ u64 min_offset;
u64 max_offset;
u64 max_bank;
u64 max_bank_offset;
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);