From 29ed6e76b4ca81103f31c8316f9e4cfcf134572f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 15 Apr 2012 15:24:39 -0300 Subject: [PATCH 01/25] perf annotate: Rename objdump_line to disasm_line We want to move away from using 'objdump -dS' as the only disassembler supported. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-lsn9pjuxxm5ezsubyhkmprw7@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 179 +++++++++++++++--------------- tools/perf/util/annotate.c | 72 ++++++------ tools/perf/util/annotate.h | 11 +- 3 files changed, 128 insertions(+), 134 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 4db5186472b5..bc540b1576c3 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -15,7 +15,7 @@ struct annotate_browser { struct ui_browser b; struct rb_root entries; struct rb_node *curr_hot; - struct objdump_line *selection; + struct disasm_line *selection; u64 start; int nr_asm_entries; int nr_entries; @@ -25,26 +25,25 @@ struct annotate_browser { char search_bf[128]; }; -struct objdump_line_rb_node { +struct disasm_line_rb_node { struct rb_node rb_node; double percent; u32 idx; int idx_asm; }; -static inline -struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self) +static inline struct disasm_line_rb_node *disasm_line__rb(struct disasm_line *dl) { - return (struct objdump_line_rb_node *)(self + 1); + return (struct disasm_line_rb_node *)(dl + 1); } -static bool objdump_line__filter(struct ui_browser *browser, void *entry) +static bool disasm_line__filter(struct ui_browser *browser, void *entry) { struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); if (ab->hide_src_code) { - struct objdump_line *ol = list_entry(entry, struct objdump_line, node); - return ol->offset == -1; + struct disasm_line *dl = list_entry(entry, struct disasm_line, node); + return dl->offset == -1; } return false; @@ -53,17 +52,17 @@ static bool objdump_line__filter(struct ui_browser *browser, void *entry) static void annotate_browser__write(struct ui_browser *self, void *entry, int row) { struct annotate_browser *ab = container_of(self, struct annotate_browser, b); - struct objdump_line *ol = list_entry(entry, struct objdump_line, node); + struct disasm_line *dl = list_entry(entry, struct disasm_line, node); bool current_entry = ui_browser__is_current_entry(self, row); bool change_color = (!ab->hide_src_code && (!current_entry || (self->use_navkeypressed && !self->navkeypressed))); int width = self->width; - if (ol->offset != -1) { - struct objdump_line_rb_node *olrb = objdump_line__rb(ol); - ui_browser__set_percent_color(self, olrb->percent, current_entry); - slsmg_printf(" %7.2f ", olrb->percent); + if (dl->offset != -1) { + struct disasm_line_rb_node *dlrb = disasm_line__rb(dl); + ui_browser__set_percent_color(self, dlrb->percent, current_entry); + slsmg_printf(" %7.2f ", dlrb->percent); } else { ui_browser__set_percent_color(self, 0, current_entry); slsmg_write_nstring(" ", 9); @@ -76,16 +75,16 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro if (!self->navkeypressed) width += 1; - if (ol->offset != -1 && change_color) + if (dl->offset != -1 && change_color) ui_browser__set_color(self, HE_COLORSET_CODE); - if (!*ol->line) + if (!*dl->line) slsmg_write_nstring(" ", width - 18); - else if (ol->offset == -1) - slsmg_write_nstring(ol->line, width - 18); + else if (dl->offset == -1) + slsmg_write_nstring(dl->line, width - 18); else { char bf[64]; - u64 addr = ol->offset; + u64 addr = dl->offset; int printed, color = -1; if (!ab->use_offset) @@ -97,28 +96,27 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro slsmg_write_nstring(bf, printed); if (change_color) ui_browser__set_color(self, color); - slsmg_write_nstring(ol->line, width - 18 - printed); + slsmg_write_nstring(dl->line, width - 18 - printed); } if (current_entry) - ab->selection = ol; + ab->selection = dl; } -static double objdump_line__calc_percent(struct objdump_line *self, - struct symbol *sym, int evidx) +static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx) { double percent = 0.0; - if (self->offset != -1) { + if (dl->offset != -1) { int len = sym->end - sym->start; unsigned int hits = 0; struct annotation *notes = symbol__annotation(sym); struct source_line *src_line = notes->src->lines; struct sym_hist *h = annotation__histogram(notes, evidx); - s64 offset = self->offset; - struct objdump_line *next; + s64 offset = dl->offset; + struct disasm_line *next; - next = objdump__get_next_ip_line(¬es->src->source, self); + next = disasm__get_next_ip_line(¬es->src->source, dl); while (offset < (s64)len && (next == NULL || offset < next->offset)) { if (src_line) { @@ -139,27 +137,26 @@ static double objdump_line__calc_percent(struct objdump_line *self, return percent; } -static void objdump__insert_line(struct rb_root *self, - struct objdump_line_rb_node *line) +static void disasm_rb_tree__insert(struct rb_root *root, struct disasm_line_rb_node *dlrb) { - struct rb_node **p = &self->rb_node; + struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; - struct objdump_line_rb_node *l; + struct disasm_line_rb_node *l; while (*p != NULL) { parent = *p; - l = rb_entry(parent, struct objdump_line_rb_node, rb_node); - if (line->percent < l->percent) + l = rb_entry(parent, struct disasm_line_rb_node, rb_node); + if (dlrb->percent < l->percent) p = &(*p)->rb_left; else p = &(*p)->rb_right; } - rb_link_node(&line->rb_node, parent, p); - rb_insert_color(&line->rb_node, self); + rb_link_node(&dlrb->rb_node, parent, p); + rb_insert_color(&dlrb->rb_node, root); } static void annotate_browser__set_top(struct annotate_browser *self, - struct objdump_line *pos, u32 idx) + struct disasm_line *pos, u32 idx) { unsigned back; @@ -168,9 +165,9 @@ static void annotate_browser__set_top(struct annotate_browser *self, self->b.top_idx = self->b.index = idx; while (self->b.top_idx != 0 && back != 0) { - pos = list_entry(pos->node.prev, struct objdump_line, node); + pos = list_entry(pos->node.prev, struct disasm_line, node); - if (objdump_line__filter(&self->b, &pos->node)) + if (disasm_line__filter(&self->b, &pos->node)) continue; --self->b.top_idx; @@ -184,11 +181,11 @@ static void annotate_browser__set_top(struct annotate_browser *self, static void annotate_browser__set_rb_top(struct annotate_browser *browser, struct rb_node *nd) { - struct objdump_line_rb_node *rbpos; - struct objdump_line *pos; + struct disasm_line_rb_node *rbpos; + struct disasm_line *pos; - rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node); - pos = ((struct objdump_line *)rbpos) - 1; + rbpos = rb_entry(nd, struct disasm_line_rb_node, rb_node); + pos = ((struct disasm_line *)rbpos) - 1; annotate_browser__set_top(browser, pos, rbpos->idx); browser->curr_hot = nd; } @@ -199,20 +196,20 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, struct map_symbol *ms = browser->b.priv; struct symbol *sym = ms->sym; struct annotation *notes = symbol__annotation(sym); - struct objdump_line *pos; + struct disasm_line *pos; browser->entries = RB_ROOT; pthread_mutex_lock(¬es->lock); list_for_each_entry(pos, ¬es->src->source, node) { - struct objdump_line_rb_node *rbpos = objdump_line__rb(pos); - rbpos->percent = objdump_line__calc_percent(pos, sym, evidx); + struct disasm_line_rb_node *rbpos = disasm_line__rb(pos); + rbpos->percent = disasm_line__calc_percent(pos, sym, evidx); if (rbpos->percent < 0.01) { RB_CLEAR_NODE(&rbpos->rb_node); continue; } - objdump__insert_line(&browser->entries, rbpos); + disasm_rb_tree__insert(&browser->entries, rbpos); } pthread_mutex_unlock(¬es->lock); @@ -221,38 +218,38 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, static bool annotate_browser__toggle_source(struct annotate_browser *browser) { - struct objdump_line *ol; - struct objdump_line_rb_node *olrb; + struct disasm_line *dl; + struct disasm_line_rb_node *dlrb; off_t offset = browser->b.index - browser->b.top_idx; browser->b.seek(&browser->b, offset, SEEK_CUR); - ol = list_entry(browser->b.top, struct objdump_line, node); - olrb = objdump_line__rb(ol); + dl = list_entry(browser->b.top, struct disasm_line, node); + dlrb = disasm_line__rb(dl); if (browser->hide_src_code) { - if (olrb->idx_asm < offset) - offset = olrb->idx; + if (dlrb->idx_asm < offset) + offset = dlrb->idx; browser->b.nr_entries = browser->nr_entries; browser->hide_src_code = false; browser->b.seek(&browser->b, -offset, SEEK_CUR); - browser->b.top_idx = olrb->idx - offset; - browser->b.index = olrb->idx; + browser->b.top_idx = dlrb->idx - offset; + browser->b.index = dlrb->idx; } else { - if (olrb->idx_asm < 0) { + if (dlrb->idx_asm < 0) { ui_helpline__puts("Only available for assembly lines."); browser->b.seek(&browser->b, -offset, SEEK_CUR); return false; } - if (olrb->idx_asm < offset) - offset = olrb->idx_asm; + if (dlrb->idx_asm < offset) + offset = dlrb->idx_asm; browser->b.nr_entries = browser->nr_asm_entries; browser->hide_src_code = true; browser->b.seek(&browser->b, -offset, SEEK_CUR); - browser->b.top_idx = olrb->idx_asm - offset; - browser->b.index = olrb->idx_asm; + browser->b.top_idx = dlrb->idx_asm - offset; + browser->b.index = dlrb->idx_asm; } return true; @@ -302,20 +299,20 @@ static bool annotate_browser__callq(struct annotate_browser *browser, return true; } -static struct objdump_line * - annotate_browser__find_offset(struct annotate_browser *browser, - s64 offset, s64 *idx) +static +struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser, + s64 offset, s64 *idx) { struct map_symbol *ms = browser->b.priv; struct symbol *sym = ms->sym; struct annotation *notes = symbol__annotation(sym); - struct objdump_line *pos; + struct disasm_line *pos; *idx = 0; list_for_each_entry(pos, ¬es->src->source, node) { if (pos->offset == offset) return pos; - if (!objdump_line__filter(&browser->b, &pos->node)) + if (!disasm_line__filter(&browser->b, &pos->node)) ++*idx; } @@ -325,7 +322,7 @@ static struct objdump_line * static bool annotate_browser__jump(struct annotate_browser *browser) { const char *jumps[] = { "je ", "jne ", "ja ", "jmpq ", "js ", "jmp ", NULL }; - struct objdump_line *line; + struct disasm_line *dl; s64 idx, offset; char *s = NULL; int i = 0; @@ -346,29 +343,29 @@ static bool annotate_browser__jump(struct annotate_browser *browser) } offset = strtoll(s, NULL, 16); - line = annotate_browser__find_offset(browser, offset, &idx); - if (line == NULL) { + dl = annotate_browser__find_offset(browser, offset, &idx); + if (dl == NULL) { ui_helpline__puts("Invallid jump offset"); return true; } - annotate_browser__set_top(browser, line, idx); + annotate_browser__set_top(browser, dl, idx); return true; } -static struct objdump_line * - annotate_browser__find_string(struct annotate_browser *browser, - char *s, s64 *idx) +static +struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser, + char *s, s64 *idx) { struct map_symbol *ms = browser->b.priv; struct symbol *sym = ms->sym; struct annotation *notes = symbol__annotation(sym); - struct objdump_line *pos = browser->selection; + struct disasm_line *pos = browser->selection; *idx = browser->b.index; list_for_each_entry_continue(pos, ¬es->src->source, node) { - if (objdump_line__filter(&browser->b, &pos->node)) + if (disasm_line__filter(&browser->b, &pos->node)) continue; ++*idx; @@ -382,32 +379,32 @@ static struct objdump_line * static bool __annotate_browser__search(struct annotate_browser *browser) { - struct objdump_line *line; + struct disasm_line *dl; s64 idx; - line = annotate_browser__find_string(browser, browser->search_bf, &idx); - if (line == NULL) { + dl = annotate_browser__find_string(browser, browser->search_bf, &idx); + if (dl == NULL) { ui_helpline__puts("String not found!"); return false; } - annotate_browser__set_top(browser, line, idx); + annotate_browser__set_top(browser, dl, idx); browser->searching_backwards = false; return true; } -static struct objdump_line * - annotate_browser__find_string_reverse(struct annotate_browser *browser, - char *s, s64 *idx) +static +struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser, + char *s, s64 *idx) { struct map_symbol *ms = browser->b.priv; struct symbol *sym = ms->sym; struct annotation *notes = symbol__annotation(sym); - struct objdump_line *pos = browser->selection; + struct disasm_line *pos = browser->selection; *idx = browser->b.index; list_for_each_entry_continue_reverse(pos, ¬es->src->source, node) { - if (objdump_line__filter(&browser->b, &pos->node)) + if (disasm_line__filter(&browser->b, &pos->node)) continue; --*idx; @@ -421,16 +418,16 @@ static struct objdump_line * static bool __annotate_browser__search_reverse(struct annotate_browser *browser) { - struct objdump_line *line; + struct disasm_line *dl; s64 idx; - line = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx); - if (line == NULL) { + dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx); + if (dl == NULL) { ui_helpline__puts("String not found!"); return false; } - annotate_browser__set_top(browser, line, idx); + annotate_browser__set_top(browser, dl, idx); browser->searching_backwards = true; return true; } @@ -613,7 +610,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, void(*timer)(void *arg), void *arg, int delay_secs) { - struct objdump_line *pos, *n; + struct disasm_line *pos, *n; struct annotation *notes; struct map_symbol ms = { .map = map, @@ -624,7 +621,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, .refresh = ui_browser__list_head_refresh, .seek = ui_browser__list_head_seek, .write = annotate_browser__write, - .filter = objdump_line__filter, + .filter = disasm_line__filter, .priv = &ms, .use_navkeypressed = true, }, @@ -637,7 +634,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, if (map->dso->annotate_warned) return -1; - if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { + if (symbol__annotate(sym, map, sizeof(struct disasm_line_rb_node)) < 0) { ui__error("%s", ui_helpline__last_msg); return -1; } @@ -648,12 +645,12 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, browser.start = map__rip_2objdump(map, sym->start); list_for_each_entry(pos, ¬es->src->source, node) { - struct objdump_line_rb_node *rbpos; + struct disasm_line_rb_node *rbpos; size_t line_len = strlen(pos->line); if (browser.b.width < line_len) browser.b.width = line_len; - rbpos = objdump_line__rb(pos); + rbpos = disasm_line__rb(pos); rbpos->idx = browser.nr_entries++; if (pos->offset != -1) rbpos->idx_asm = browser.nr_asm_entries++; @@ -667,7 +664,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs); list_for_each_entry_safe(pos, n, ¬es->src->source, node) { list_del(&pos->node); - objdump_line__free(pos); + disasm_line__free(pos); } return ret; } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 1e7fd52bd29d..ef1d57def76d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -78,36 +78,35 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, return 0; } -static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize) +static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) { - struct objdump_line *self = malloc(sizeof(*self) + privsize); + struct disasm_line *dl = malloc(sizeof(*dl) + privsize); - if (self != NULL) { - self->offset = offset; - self->line = strdup(line); - if (self->line == NULL) + if (dl != NULL) { + dl->offset = offset; + dl->line = strdup(line); + if (dl->line == NULL) goto out_delete; } - return self; + return dl; out_delete: - free(self); + free(dl); return NULL; } -void objdump_line__free(struct objdump_line *self) +void disasm_line__free(struct disasm_line *dl) { - free(self->line); - free(self); + free(dl->line); + free(dl); } -static void objdump__add_line(struct list_head *head, struct objdump_line *line) +static void disasm__add(struct list_head *head, struct disasm_line *line) { list_add_tail(&line->node, head); } -struct objdump_line *objdump__get_next_ip_line(struct list_head *head, - struct objdump_line *pos) +struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos) { list_for_each_entry_continue(pos, head, node) if (pos->offset >= 0) @@ -116,15 +115,14 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head, return NULL; } -static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, - u64 start, int evidx, u64 len, int min_pcnt, - int printed, int max_lines, - struct objdump_line *queue) +static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, + int evidx, u64 len, int min_pcnt, int printed, + int max_lines, struct disasm_line *queue) { static const char *prev_line; static const char *prev_color; - if (oline->offset != -1) { + if (dl->offset != -1) { const char *path = NULL; unsigned int hits = 0; double percent = 0.0; @@ -132,11 +130,11 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, struct annotation *notes = symbol__annotation(sym); struct source_line *src_line = notes->src->lines; struct sym_hist *h = annotation__histogram(notes, evidx); - s64 offset = oline->offset; + s64 offset = dl->offset; const u64 addr = start + offset; - struct objdump_line *next; + struct disasm_line *next; - next = objdump__get_next_ip_line(¬es->src->source, oline); + next = disasm__get_next_ip_line(¬es->src->source, dl); while (offset < (s64)len && (next == NULL || offset < next->offset)) { @@ -161,9 +159,9 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, if (queue != NULL) { list_for_each_entry_from(queue, ¬es->src->source, node) { - if (queue == oline) + if (queue == dl) break; - objdump_line__print(queue, sym, start, evidx, len, + disasm_line__print(queue, sym, start, evidx, len, 0, 0, 1, NULL); } } @@ -187,17 +185,17 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, color_fprintf(stdout, color, " %7.2f", percent); printf(" : "); color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); - color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line); + color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); } else if (max_lines && printed >= max_lines) return 1; else { if (queue) return -1; - if (!*oline->line) + if (!*dl->line) printf(" :\n"); else - printf(" : %s\n", oline->line); + printf(" : %s\n", dl->line); } return 0; @@ -207,7 +205,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, FILE *file, size_t privsize) { struct annotation *notes = symbol__annotation(sym); - struct objdump_line *objdump_line; + struct disasm_line *dl; char *line = NULL, *parsed_line, *tmp, *tmp2, *c; size_t line_len; s64 line_ip, offset = -1; @@ -258,13 +256,13 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, parsed_line = tmp2 + 1; } - objdump_line = objdump_line__new(offset, parsed_line, privsize); + dl = disasm_line__new(offset, parsed_line, privsize); free(line); - if (objdump_line == NULL) + if (dl == NULL) return -1; - objdump__add_line(¬es->src->source, objdump_line); + disasm__add(¬es->src->source, dl); return 0; } @@ -503,7 +501,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, struct dso *dso = map->dso; const char *filename = dso->long_name, *d_filename; struct annotation *notes = symbol__annotation(sym); - struct objdump_line *pos, *queue = NULL; + struct disasm_line *pos, *queue = NULL; u64 start = map__rip_2objdump(map, sym->start); int printed = 2, queue_len = 0; int more = 0; @@ -528,7 +526,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, queue_len = 0; } - switch (objdump_line__print(pos, sym, start, evidx, len, + switch (disasm_line__print(pos, sym, start, evidx, len, min_pcnt, printed, max_lines, queue)) { case 0: @@ -583,13 +581,13 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) } } -void objdump_line_list__purge(struct list_head *head) +void disasm__purge(struct list_head *head) { - struct objdump_line *pos, *n; + struct disasm_line *pos, *n; list_for_each_entry_safe(pos, n, head, node) { list_del(&pos->node); - objdump_line__free(pos); + disasm_line__free(pos); } } @@ -618,7 +616,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, if (print_lines) symbol__free_source_line(sym, len); - objdump_line_list__purge(&symbol__annotation(sym)->src->source); + disasm__purge(&symbol__annotation(sym)->src->source); return 0; } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index efa5dc82bfae..8bb68bb2a04a 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -7,15 +7,14 @@ #include #include -struct objdump_line { +struct disasm_line { struct list_head node; s64 offset; char *line; }; -void objdump_line__free(struct objdump_line *self); -struct objdump_line *objdump__get_next_ip_line(struct list_head *head, - struct objdump_line *pos); +void disasm_line__free(struct disasm_line *dl); +struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); struct sym_hist { u64 sum; @@ -32,7 +31,7 @@ struct source_line { * * @histogram: Array of addr hit histograms per event being monitored * @lines: If 'print_lines' is specified, per source code line percentages - * @source: source parsed from objdump -dS + * @source: source parsed from a disassembler like objdump -dS * * lines is allocated, percentages calculated and all sorted by percentage * when the annotation is about to be presented, so the percentages are for @@ -82,7 +81,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, int context); void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); -void objdump_line_list__purge(struct list_head *head); +void disasm__purge(struct list_head *head); int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, bool print_lines, bool full_paths, int min_pcnt, From 5145418b06fa907883ff1f62301d534a0d26ba18 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 15 Apr 2012 15:52:18 -0300 Subject: [PATCH 02/25] perf annotate: Parse instruction For lines with instructions find the name and operands, breaking those tokens for consumption by the browser. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-6aazb9f5o3d9zi28e6rruv12@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 65 +++++++++++++++++++++++++++++++++++++- tools/perf/util/annotate.h | 3 ++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ef1d57def76d..a72585ab52e8 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -80,16 +80,50 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) { - struct disasm_line *dl = malloc(sizeof(*dl) + privsize); + struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); if (dl != NULL) { dl->offset = offset; dl->line = strdup(line); if (dl->line == NULL) goto out_delete; + + if (offset != -1) { + char *name = dl->line, tmp; + + while (isspace(name[0])) + ++name; + + if (name[0] == '\0') + goto out_delete; + + dl->operands = name + 1; + + while (dl->operands[0] != '\0' && + !isspace(dl->operands[0])) + ++dl->operands; + + tmp = dl->operands[0]; + dl->operands[0] = '\0'; + dl->name = strdup(name); + + if (dl->name == NULL) + goto out_free_line; + + dl->operands[0] = tmp; + + if (dl->operands[0] != '\0') { + dl->operands++; + while (isspace(dl->operands[0])) + ++dl->operands; + } + } } return dl; + +out_free_line: + free(dl->line); out_delete: free(dl); return NULL; @@ -98,6 +132,7 @@ out_delete: void disasm_line__free(struct disasm_line *dl) { free(dl->line); + free(dl->name); free(dl); } @@ -591,6 +626,34 @@ void disasm__purge(struct list_head *head) } } +static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp) +{ + size_t printed; + + if (dl->offset == -1) + return fprintf(fp, "%s\n", dl->line); + + printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name); + + if (dl->operands[0] != '\0') { + printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", + dl->operands); + } + + return printed + fprintf(fp, "\n"); +} + +size_t disasm__fprintf(struct list_head *head, FILE *fp) +{ + struct disasm_line *pos; + size_t printed = 0; + + list_for_each_entry(pos, head, node) + printed += disasm_line__fprintf(pos, fp); + + return printed; +} + int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, bool print_lines, bool full_paths, int min_pcnt, int max_lines) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 8bb68bb2a04a..dd7636d24133 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -11,10 +11,13 @@ struct disasm_line { struct list_head node; s64 offset; char *line; + char *name; + char *operands; }; void disasm_line__free(struct disasm_line *dl); struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); +size_t disasm__fprintf(struct list_head *head, FILE *fp); struct sym_hist { u64 sum; From 657bcaf5097e1aff53d724358deb24ce803f43a4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 15 Apr 2012 20:12:07 -0300 Subject: [PATCH 03/25] perf annotate browser: Use the disasm_line instruction name and operand fields No need to reparse it everytime. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-90ncot487p4h5rzkn8h2whou@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index bc540b1576c3..0bc3e652b541 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -260,22 +260,16 @@ static bool annotate_browser__callq(struct annotate_browser *browser, void *arg, int delay_secs) { struct map_symbol *ms = browser->b.priv; + struct disasm_line *dl = browser->selection; struct symbol *sym = ms->sym; struct annotation *notes; struct symbol *target; - char *s = strstr(browser->selection->line, "callq "); u64 ip; - if (s == NULL) + if (strcmp(dl->name, "callq")) return false; - s = strchr(s, ' '); - if (s++ == NULL) { - ui_helpline__puts("Invallid callq instruction."); - return true; - } - - ip = strtoull(s, NULL, 16); + ip = strtoull(dl->operands, NULL, 16); ip = ms->map->map_ip(ms->map, ip); target = map__find_symbol(ms->map, ip, NULL); if (target == NULL) { @@ -321,22 +315,19 @@ struct disasm_line *annotate_browser__find_offset(struct annotate_browser *brows static bool annotate_browser__jump(struct annotate_browser *browser) { - const char *jumps[] = { "je ", "jne ", "ja ", "jmpq ", "js ", "jmp ", NULL }; - struct disasm_line *dl; + const char *jumps[] = { "je", "jne", "ja", "jmpq", "js", "jmp", NULL }; + struct disasm_line *dl = browser->selection; s64 idx, offset; - char *s = NULL; + char *s; int i = 0; - while (jumps[i]) { - s = strstr(browser->selection->line, jumps[i++]); - if (s) - break; - } + while (jumps[i] && strcmp(dl->name, jumps[i])) + ++i; - if (s == NULL) + if (jumps[i] == NULL) return false; - s = strchr(s, '+'); + s = strchr(dl->operands, '+'); if (s++ == NULL) { ui_helpline__puts("Invallid jump instruction."); return true; From 4f9d03251b9d202ebce805757360ef0fac5eb74e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 18 Apr 2012 13:58:34 -0300 Subject: [PATCH 04/25] perf annotate: Disassembler instruction parsing So that at disassembly time we parse targets, etc. Supporting jump instructions initially, call functions are next. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-7vzlh66n5or46n27ji658cnl@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 19 ++-------- tools/perf/util/annotate.c | 63 +++++++++++++++++++++++++++++++ tools/perf/util/annotate.h | 13 +++++++ 3 files changed, 79 insertions(+), 16 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 0bc3e652b541..bdbb54fd05ae 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -315,26 +315,13 @@ struct disasm_line *annotate_browser__find_offset(struct annotate_browser *brows static bool annotate_browser__jump(struct annotate_browser *browser) { - const char *jumps[] = { "je", "jne", "ja", "jmpq", "js", "jmp", NULL }; struct disasm_line *dl = browser->selection; - s64 idx, offset; - char *s; - int i = 0; + s64 idx; - while (jumps[i] && strcmp(dl->name, jumps[i])) - ++i; - - if (jumps[i] == NULL) + if (!dl->ins || !ins__is_jump(dl->ins)) return false; - s = strchr(dl->operands, '+'); - if (s++ == NULL) { - ui_helpline__puts("Invallid jump instruction."); - return true; - } - - offset = strtoll(s, NULL, 16); - dl = annotate_browser__find_offset(browser, offset, &idx); + dl = annotate_browser__find_offset(browser, dl->target, &idx); if (dl == NULL) { ui_helpline__puts("Invallid jump offset"); return true; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a72585ab52e8..4ee2c07924bc 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -18,6 +18,53 @@ const char *disassembler_style; +static int jump_ops__parse_target(const char *operands, u64 *target) +{ + const char *s = strchr(operands, '+'); + + if (s++ == NULL) + return -1; + + *target = strtoll(s, NULL, 16); + return 0; +} + +static struct ins_ops jump_ops = { + .parse_target = jump_ops__parse_target, +}; + +bool ins__is_jump(const struct ins *ins) +{ + return ins->ops == &jump_ops; +} + + +/* + * Must be sorted by name! + */ +static struct ins instructions[] = { + { .name = "ja", .ops = &jump_ops, }, + { .name = "je", .ops = &jump_ops, }, + { .name = "jmp", .ops = &jump_ops, }, + { .name = "jmpq", .ops = &jump_ops, }, + { .name = "jne", .ops = &jump_ops, }, + { .name = "js", .ops = &jump_ops, }, +}; + +static int ins__cmp(const void *name, const void *insp) +{ + const struct ins *ins = insp; + + return strcmp(name, ins->name); +} + +static struct ins *ins__find(const char *name) +{ + const int nmemb = ARRAY_SIZE(instructions); + + return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp); +} + int symbol__annotate_init(struct map *map __used, struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); @@ -78,6 +125,20 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, return 0; } +static void disasm_line__init_ins(struct disasm_line *dl) +{ + dl->ins = ins__find(dl->name); + + if (dl->ins == NULL) + return; + + if (!dl->ins->ops) + return; + + if (dl->ins->ops->parse_target) + dl->ins->ops->parse_target(dl->operands, &dl->target); +} + static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) { struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); @@ -117,6 +178,8 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privs while (isspace(dl->operands[0])) ++dl->operands; } + + disasm_line__init_ins(dl); } } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index dd7636d24133..934c6fe3a91b 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -7,11 +7,24 @@ #include #include +struct ins_ops { + int (*parse_target)(const char *operands, u64 *target); +}; + +struct ins { + const char *name; + struct ins_ops *ops; +}; + +bool ins__is_jump(const struct ins *ins); + struct disasm_line { struct list_head node; s64 offset; + u64 target; char *line; char *name; + struct ins *ins; char *operands; }; From d86b0597c4bd41ea3edc6446a855306eed34f93b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 18 Apr 2012 16:07:38 -0300 Subject: [PATCH 05/25] perf annotate: Parse call targets earlier No need to do it everytime the user presses enter/-> on a call instruction. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-ybgss44m5ycry8mk7b1qdbre@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 10 +++++----- tools/perf/util/annotate.c | 18 +++++++++++++++++- tools/perf/util/annotate.h | 1 + 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index bdbb54fd05ae..46ef966ccc5b 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -266,11 +266,10 @@ static bool annotate_browser__callq(struct annotate_browser *browser, struct symbol *target; u64 ip; - if (strcmp(dl->name, "callq")) + if (!ins__is_call(dl->ins)) return false; - ip = strtoull(dl->operands, NULL, 16); - ip = ms->map->map_ip(ms->map, ip); + ip = ms->map->map_ip(ms->map, dl->target); target = map__find_symbol(ms->map, ip, NULL); if (target == NULL) { ui_helpline__puts("The called function was not found."); @@ -318,7 +317,7 @@ static bool annotate_browser__jump(struct annotate_browser *browser) struct disasm_line *dl = browser->selection; s64 idx; - if (!dl->ins || !ins__is_jump(dl->ins)) + if (!ins__is_jump(dl->ins)) return false; dl = annotate_browser__find_offset(browser, dl->target, &idx); @@ -556,7 +555,8 @@ show_help: ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); else if (self->selection->offset == -1) ui_helpline__puts("Actions are only available for assembly lines."); - else if (!(annotate_browser__jump(self) || + else if (!self->selection->ins || + !(annotate_browser__jump(self) || annotate_browser__callq(self, evidx, timer, arg, delay_secs))) ui_helpline__puts("Actions are only available for the 'callq' and jump instructions."); continue; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 4ee2c07924bc..a4296fdd9a68 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -18,6 +18,21 @@ const char *disassembler_style; +static int call_ops__parse_target(const char *operands, u64 *target) +{ + *target = strtoull(operands, NULL, 16); + return 0; +} + +static struct ins_ops call_ops = { + .parse_target = call_ops__parse_target, +}; + +bool ins__is_call(const struct ins *ins) +{ + return ins->ops == &call_ops; +} + static int jump_ops__parse_target(const char *operands, u64 *target) { const char *s = strchr(operands, '+'); @@ -38,11 +53,12 @@ bool ins__is_jump(const struct ins *ins) return ins->ops == &jump_ops; } - /* * Must be sorted by name! */ static struct ins instructions[] = { + { .name = "call", .ops = &call_ops, }, + { .name = "callq", .ops = &call_ops, }, { .name = "ja", .ops = &jump_ops, }, { .name = "je", .ops = &jump_ops, }, { .name = "jmp", .ops = &jump_ops, }, diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 934c6fe3a91b..a2105f204a42 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -17,6 +17,7 @@ struct ins { }; bool ins__is_jump(const struct ins *ins); +bool ins__is_call(const struct ins *ins); struct disasm_line { struct list_head node; From 28548d78ad521310f0ae58f791aa796d3d685151 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Apr 2012 10:16:27 -0300 Subject: [PATCH 06/25] perf annotate: Introduce scnprintf ins_ops method And implement the jump one, where if the operands string is not passed, a compact form that uses just the target address is used. Right now this is toggled via the 'o' option in the annotate browser, switching from: 0.00 : ffffffff811661e8: je ffffffff81166204 0.00 : ffffffff811661ea: cmp $0xb,%esi 0.00 : ffffffff811661ed: je ffffffff811661f8 To: 0.00 : 28: je 44 0.00 : 2a: cmp $0xb,%esi 0.00 : 2d: je 38 Suggested-by: Linus Torvalds Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-o88q46yh4kxgpd1chk5gvjl5@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 13 +++++++++++-- tools/perf/util/annotate.c | 10 ++++++++++ tools/perf/util/annotate.h | 4 ++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 46ef966ccc5b..f7d2db3e8464 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -83,7 +83,7 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro else if (dl->offset == -1) slsmg_write_nstring(dl->line, width - 18); else { - char bf[64]; + char bf[256], *line = dl->line; u64 addr = dl->offset; int printed, color = -1; @@ -96,7 +96,16 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro slsmg_write_nstring(bf, printed); if (change_color) ui_browser__set_color(self, color); - slsmg_write_nstring(dl->line, width - 18 - printed); + if (dl->ins && dl->ins->ops->scnprintf) { + dl->ins->ops->scnprintf(dl->ins, bf, sizeof(bf), + !ab->use_offset ? dl->operands : NULL, + dl->target); + line = bf; + slsmg_write_nstring(" ", 7); + printed += 7; + } + + slsmg_write_nstring(line, width - 18 - printed); } if (current_entry) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a4296fdd9a68..ed1f89d7044e 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -44,8 +44,18 @@ static int jump_ops__parse_target(const char *operands, u64 *target) return 0; } +static int jump_ops__scnprintf(struct ins *ins, char *bf, size_t size, + const char *operands, u64 target) +{ + if (operands) + return scnprintf(bf, size, "%-6.6s %s", ins->name, operands); + + return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, target); +} + static struct ins_ops jump_ops = { .parse_target = jump_ops__parse_target, + .scnprintf = jump_ops__scnprintf, }; bool ins__is_jump(const struct ins *ins) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index a2105f204a42..6314335007f0 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -7,8 +7,12 @@ #include #include +struct ins; + struct ins_ops { int (*parse_target)(const char *operands, u64 *target); + int (*scnprintf)(struct ins *ins, char *bf, size_t size, + const char *operands, u64 target); }; struct ins { From 887c0066a810234cfae9927b3781b6a1c617fb39 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Apr 2012 10:29:53 -0300 Subject: [PATCH 07/25] perf annotate browser: Rename disasm_line_rb_node Its not just an rb_node, it carries extra state that is private to the browser. And will carry some more in the next patches. Better name it browser_disasm_line, i.e. something derived from disasm_line, that specializes it. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-nev4b97vdvv35we1qmooym52@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 76 +++++++++++++++---------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index f7d2db3e8464..58ebfd0ac1e8 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -25,16 +25,16 @@ struct annotate_browser { char search_bf[128]; }; -struct disasm_line_rb_node { +struct browser_disasm_line { struct rb_node rb_node; double percent; u32 idx; int idx_asm; }; -static inline struct disasm_line_rb_node *disasm_line__rb(struct disasm_line *dl) +static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl) { - return (struct disasm_line_rb_node *)(dl + 1); + return (struct browser_disasm_line *)(dl + 1); } static bool disasm_line__filter(struct ui_browser *browser, void *entry) @@ -60,9 +60,9 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro int width = self->width; if (dl->offset != -1) { - struct disasm_line_rb_node *dlrb = disasm_line__rb(dl); - ui_browser__set_percent_color(self, dlrb->percent, current_entry); - slsmg_printf(" %7.2f ", dlrb->percent); + struct browser_disasm_line *bdl = disasm_line__browser(dl); + ui_browser__set_percent_color(self, bdl->percent, current_entry); + slsmg_printf(" %7.2f ", bdl->percent); } else { ui_browser__set_percent_color(self, 0, current_entry); slsmg_write_nstring(" ", 9); @@ -146,22 +146,22 @@ static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *s return percent; } -static void disasm_rb_tree__insert(struct rb_root *root, struct disasm_line_rb_node *dlrb) +static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl) { struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; - struct disasm_line_rb_node *l; + struct browser_disasm_line *l; while (*p != NULL) { parent = *p; - l = rb_entry(parent, struct disasm_line_rb_node, rb_node); - if (dlrb->percent < l->percent) + l = rb_entry(parent, struct browser_disasm_line, rb_node); + if (bdl->percent < l->percent) p = &(*p)->rb_left; else p = &(*p)->rb_right; } - rb_link_node(&dlrb->rb_node, parent, p); - rb_insert_color(&dlrb->rb_node, root); + rb_link_node(&bdl->rb_node, parent, p); + rb_insert_color(&bdl->rb_node, root); } static void annotate_browser__set_top(struct annotate_browser *self, @@ -190,12 +190,12 @@ static void annotate_browser__set_top(struct annotate_browser *self, static void annotate_browser__set_rb_top(struct annotate_browser *browser, struct rb_node *nd) { - struct disasm_line_rb_node *rbpos; + struct browser_disasm_line *bpos; struct disasm_line *pos; - rbpos = rb_entry(nd, struct disasm_line_rb_node, rb_node); - pos = ((struct disasm_line *)rbpos) - 1; - annotate_browser__set_top(browser, pos, rbpos->idx); + bpos = rb_entry(nd, struct browser_disasm_line, rb_node); + pos = ((struct disasm_line *)bpos) - 1; + annotate_browser__set_top(browser, pos, bpos->idx); browser->curr_hot = nd; } @@ -212,13 +212,13 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, pthread_mutex_lock(¬es->lock); list_for_each_entry(pos, ¬es->src->source, node) { - struct disasm_line_rb_node *rbpos = disasm_line__rb(pos); - rbpos->percent = disasm_line__calc_percent(pos, sym, evidx); - if (rbpos->percent < 0.01) { - RB_CLEAR_NODE(&rbpos->rb_node); + struct browser_disasm_line *bpos = disasm_line__browser(pos); + bpos->percent = disasm_line__calc_percent(pos, sym, evidx); + if (bpos->percent < 0.01) { + RB_CLEAR_NODE(&bpos->rb_node); continue; } - disasm_rb_tree__insert(&browser->entries, rbpos); + disasm_rb_tree__insert(&browser->entries, bpos); } pthread_mutex_unlock(¬es->lock); @@ -228,37 +228,37 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, static bool annotate_browser__toggle_source(struct annotate_browser *browser) { struct disasm_line *dl; - struct disasm_line_rb_node *dlrb; + struct browser_disasm_line *bdl; off_t offset = browser->b.index - browser->b.top_idx; browser->b.seek(&browser->b, offset, SEEK_CUR); dl = list_entry(browser->b.top, struct disasm_line, node); - dlrb = disasm_line__rb(dl); + bdl = disasm_line__browser(dl); if (browser->hide_src_code) { - if (dlrb->idx_asm < offset) - offset = dlrb->idx; + if (bdl->idx_asm < offset) + offset = bdl->idx; browser->b.nr_entries = browser->nr_entries; browser->hide_src_code = false; browser->b.seek(&browser->b, -offset, SEEK_CUR); - browser->b.top_idx = dlrb->idx - offset; - browser->b.index = dlrb->idx; + browser->b.top_idx = bdl->idx - offset; + browser->b.index = bdl->idx; } else { - if (dlrb->idx_asm < 0) { + if (bdl->idx_asm < 0) { ui_helpline__puts("Only available for assembly lines."); browser->b.seek(&browser->b, -offset, SEEK_CUR); return false; } - if (dlrb->idx_asm < offset) - offset = dlrb->idx_asm; + if (bdl->idx_asm < offset) + offset = bdl->idx_asm; browser->b.nr_entries = browser->nr_asm_entries; browser->hide_src_code = true; browser->b.seek(&browser->b, -offset, SEEK_CUR); - browser->b.top_idx = dlrb->idx_asm - offset; - browser->b.index = dlrb->idx_asm; + browser->b.top_idx = bdl->idx_asm - offset; + browser->b.index = bdl->idx_asm; } return true; @@ -621,7 +621,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, if (map->dso->annotate_warned) return -1; - if (symbol__annotate(sym, map, sizeof(struct disasm_line_rb_node)) < 0) { + if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) { ui__error("%s", ui_helpline__last_msg); return -1; } @@ -632,17 +632,17 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, browser.start = map__rip_2objdump(map, sym->start); list_for_each_entry(pos, ¬es->src->source, node) { - struct disasm_line_rb_node *rbpos; + struct browser_disasm_line *bpos; size_t line_len = strlen(pos->line); if (browser.b.width < line_len) browser.b.width = line_len; - rbpos = disasm_line__rb(pos); - rbpos->idx = browser.nr_entries++; + bpos = disasm_line__browser(pos); + bpos->idx = browser.nr_entries++; if (pos->offset != -1) - rbpos->idx_asm = browser.nr_asm_entries++; + bpos->idx_asm = browser.nr_asm_entries++; else - rbpos->idx_asm = -1; + bpos->idx_asm = -1; } browser.b.nr_entries = browser.nr_entries; From 1b2e2df4e395293e65dbda49e58cb4c7abeb7507 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Apr 2012 10:57:06 -0300 Subject: [PATCH 08/25] perf symbols: Introduce symbol__size method Fixing some off by one cases in the process. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-fxumzufhk829z0q9anmvemea@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 10 +++++----- tools/perf/util/symbol.h | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ed1f89d7044e..d8e2f414e610 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -101,7 +101,7 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym) int symbol__alloc_hist(struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); - const size_t size = sym->end - sym->start + 1; + const size_t size = symbol__size(sym); size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); @@ -609,7 +609,7 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx) { struct annotation *notes = symbol__annotation(sym); struct sym_hist *h = annotation__histogram(notes, evidx); - u64 len = sym->end - sym->start, offset; + u64 len = symbol__size(sym), offset; for (offset = 0; offset < len; ++offset) if (h->addr[offset] != 0) @@ -636,7 +636,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, else d_filename = basename(filename); - len = sym->end - sym->start; + len = symbol__size(sym); printf(" Percent | Source code & Disassembly of %s\n", d_filename); printf("------------------------------------------------\n"); @@ -696,7 +696,7 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) { struct annotation *notes = symbol__annotation(sym); struct sym_hist *h = annotation__histogram(notes, evidx); - int len = sym->end - sym->start, offset; + int len = symbol__size(sym), offset; h->sum = 0; for (offset = 0; offset < len; ++offset) { @@ -755,7 +755,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, if (symbol__annotate(sym, map, 0) < 0) return -1; - len = sym->end - sym->start; + len = symbol__size(sym); if (print_lines) { symbol__get_source_line(sym, map, evidx, &source_line, diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index ac49ef208a5f..1f003884f1ab 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -65,6 +65,11 @@ struct symbol { void symbol__delete(struct symbol *sym); +static inline size_t symbol__size(const struct symbol *sym) +{ + return sym->end - sym->start + 1; +} + struct strlist; struct symbol_conf { From b793a40185b246c2690e06c6d86d12c35f24ab4c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Apr 2012 12:19:22 -0300 Subject: [PATCH 09/25] perf annotate browser: Hide non jump target addresses in offset mode This: 0.00 : ffffffff8116bd00: lock btsl $0x0,(%r12) 100.00 : ffffffff8116bd07: sbb %eax,%eax 0.00 : ffffffff8116bd09: test %eax,%eax 0.00 : ffffffff8116bd0b: jne ffffffff8116bf5f <__mem_cgroup_commit_charge+0x28f> 0.00 : ffffffff8116bd11: mov (%r12),%rax 0.00 : ffffffff8116bd15: test $0x2,%al 0.00 : ffffffff8116bd17: jne ffffffff8116bf6e <__mem_cgroup_commit_charge+0x29e> 0.00 : ffffffff8116bd1d: test %r9b,%r9b 0.00 : ffffffff8116bd20: jne ffffffff8116be30 <__mem_cgroup_commit_charge+0x160> 0.00 : ffffffff8116bd26: xor %eax,%eax 0.00 : ffffffff8116bd28: mov %r13,0x8(%r12) 0.00 : ffffffff8116bd2d: lock orb $0x2,(%r12) 0.00 : ffffffff8116bd33: test %r9b,%r9b 0.00 : ffffffff8116bd36: je ffffffff8116bdf3 <__mem_cgroup_commit_charge+0x123> Becomes: 0.00 : 30: lock btsl $0x0,(%r12) 100.00 : sbb %eax,%eax 0.00 : test %eax,%eax 0.00 : jne 28f 0.00 : mov (%r12),%rax 0.00 : test $0x2,%al 0.00 : jne 29e 0.00 : test %r9b,%r9b 0.00 : jne 160 0.00 : 56: xor %eax,%eax 0.00 : 58: mov %r13,0x8(%r12) 0.00 : lock orb $0x2,(%r12) 0.00 : test %r9b,%r9b 0.00 : je 123 I.e. We trow away all those useless addresses and keep just jump labels. Suggested-by: Linus Torvalds Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-r2vmbtgz0l8coluj8flztgrn@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 71 +++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 58ebfd0ac1e8..a1e942bb903b 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -11,11 +11,20 @@ #include #include +struct browser_disasm_line { + struct rb_node rb_node; + double percent; + u32 idx; + int idx_asm; + bool jump_target; +}; + struct annotate_browser { struct ui_browser b; struct rb_root entries; struct rb_node *curr_hot; struct disasm_line *selection; + struct disasm_line **offsets; u64 start; int nr_asm_entries; int nr_entries; @@ -25,13 +34,6 @@ struct annotate_browser { char search_bf[128]; }; -struct browser_disasm_line { - struct rb_node rb_node; - double percent; - u32 idx; - int idx_asm; -}; - static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl) { return (struct browser_disasm_line *)(dl + 1); @@ -53,6 +55,7 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro { struct annotate_browser *ab = container_of(self, struct annotate_browser, b); struct disasm_line *dl = list_entry(entry, struct disasm_line, node); + struct browser_disasm_line *bdl = disasm_line__browser(dl); bool current_entry = ui_browser__is_current_entry(self, row); bool change_color = (!ab->hide_src_code && (!current_entry || (self->use_navkeypressed && @@ -60,7 +63,6 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro int width = self->width; if (dl->offset != -1) { - struct browser_disasm_line *bdl = disasm_line__browser(dl); ui_browser__set_percent_color(self, bdl->percent, current_entry); slsmg_printf(" %7.2f ", bdl->percent); } else { @@ -90,7 +92,11 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro if (!ab->use_offset) addr += ab->start; - printed = scnprintf(bf, sizeof(bf), " %" PRIx64 ":", addr); + if (bdl->jump_target || !ab->use_offset) + printed = scnprintf(bf, sizeof(bf), " %" PRIx64 ":", addr); + else + printed = scnprintf(bf, sizeof(bf), " "); + if (change_color) color = ui_browser__set_color(self, HE_COLORSET_ADDR); slsmg_write_nstring(bf, printed); @@ -593,12 +599,39 @@ int hist_entry__tui_annotate(struct hist_entry *he, int evidx, timer, arg, delay_secs); } +static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, + size_t size) +{ + u64 offset; + + for (offset = 0; offset < size; ++offset) { + struct disasm_line *dl = browser->offsets[offset], *dlt; + struct browser_disasm_line *bdlt; + + if (!dl || !dl->ins || !ins__is_jump(dl->ins)) + continue; + + if (dl->target >= size) { + ui__error("jump to after symbol!\n" + "size: %zx, jump target: %" PRIx64, + size, dl->target); + continue; + } + + dlt = browser->offsets[dl->target]; + bdlt = disasm_line__browser(dlt); + bdlt->jump_target = true; + } + +} + int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, void(*timer)(void *arg), void *arg, int delay_secs) { struct disasm_line *pos, *n; struct annotation *notes; + const size_t size = symbol__size(sym); struct map_symbol ms = { .map = map, .sym = sym, @@ -613,7 +646,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, .use_navkeypressed = true, }, }; - int ret; + int ret = -1; if (sym == NULL) return -1; @@ -621,9 +654,15 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, if (map->dso->annotate_warned) return -1; + browser.offsets = zalloc(size * sizeof(struct disasm_line *)); + if (browser.offsets == NULL) { + ui__error("Not enough memory!"); + return -1; + } + if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) { ui__error("%s", ui_helpline__last_msg); - return -1; + goto out_free_offsets; } ui_helpline__push("Press <- or ESC to exit"); @@ -639,12 +678,15 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, browser.b.width = line_len; bpos = disasm_line__browser(pos); bpos->idx = browser.nr_entries++; - if (pos->offset != -1) + if (pos->offset != -1) { bpos->idx_asm = browser.nr_asm_entries++; - else + browser.offsets[pos->offset] = pos; + } else bpos->idx_asm = -1; } + annotate_browser__mark_jump_targets(&browser, size); + browser.b.nr_entries = browser.nr_entries; browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ @@ -653,5 +695,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, list_del(&pos->node); disasm_line__free(pos); } + +out_free_offsets: + free(browser.offsets); return ret; } From 61e04b332e9417720c331eb39c96a4ccb1aa0460 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Apr 2012 13:15:24 -0300 Subject: [PATCH 10/25] perf annotate browser: Align jump labels Find out at browser startup the max width and use it when rendering jump labels on the screen. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-7dxjiwqb77wz6f5lc05e0i0x@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 17 +++++++++++++---- tools/perf/util/util.c | 10 ++++++++++ tools/perf/util/util.h | 2 ++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index a1e942bb903b..c5ab21c50a74 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -31,6 +31,7 @@ struct annotate_browser { bool hide_src_code; bool use_offset; bool searching_backwards; + u8 offset_width; char search_bf[128]; }; @@ -92,10 +93,17 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro if (!ab->use_offset) addr += ab->start; - if (bdl->jump_target || !ab->use_offset) - printed = scnprintf(bf, sizeof(bf), " %" PRIx64 ":", addr); - else - printed = scnprintf(bf, sizeof(bf), " "); + if (!ab->use_offset) { + printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ":", addr); + } else { + if (bdl->jump_target) { + printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ":", + ab->offset_width, addr); + } else { + printed = scnprintf(bf, sizeof(bf), "%*s ", + ab->offset_width, " "); + } + } if (change_color) color = ui_browser__set_color(self, HE_COLORSET_ADDR); @@ -687,6 +695,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, annotate_browser__mark_jump_targets(&browser, size); + browser.offset_width = hex_width(size); browser.b.nr_entries = browser.nr_entries; browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 8109a907841e..d03599fbe78b 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -148,3 +148,13 @@ int readn(int fd, void *buf, size_t n) return buf - buf_start; } + +size_t hex_width(u64 v) +{ + size_t n = 1; + + while ((v >>= 4)) + ++n; + + return n; +} diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 0f99f394d8e0..6121e24fefc0 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -265,4 +265,6 @@ bool is_power_of_2(unsigned long n) return (n != 0 && ((n & (n - 1)) == 0)); } +size_t hex_width(u64 v); + #endif From 8bf39cb81bdad01ad0d830e8c3639b9e8f552d57 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Apr 2012 15:07:46 -0300 Subject: [PATCH 11/25] perf annotate browser: Make lines more compact But now we have a lot of space on the right... Perhaps we should add a "Trending on G+" gizmo... ;-) Requested-by: Linus Torvalds Cc: David Ahern Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-igoynvtg2wc6mdfinc69prp6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index c5ab21c50a74..34b86ea3e54d 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -82,11 +82,11 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro ui_browser__set_color(self, HE_COLORSET_CODE); if (!*dl->line) - slsmg_write_nstring(" ", width - 18); + slsmg_write_nstring(" ", width - 10); else if (dl->offset == -1) - slsmg_write_nstring(dl->line, width - 18); + slsmg_write_nstring(dl->line, width - 10); else { - char bf[256], *line = dl->line; + char bf[256]; u64 addr = dl->offset; int printed, color = -1; @@ -114,12 +114,12 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro dl->ins->ops->scnprintf(dl->ins, bf, sizeof(bf), !ab->use_offset ? dl->operands : NULL, dl->target); - line = bf; - slsmg_write_nstring(" ", 7); - printed += 7; - } + slsmg_write_nstring(" ", 2); + printed += 2; + } else + scnprintf(bf, sizeof(bf), " %-6.6s %s", dl->name, dl->operands); - slsmg_write_nstring(line, width - 18 - printed); + slsmg_write_nstring(bf, width - 10 - printed); } if (current_entry) @@ -653,6 +653,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, .priv = &ms, .use_navkeypressed = true, }, + .use_offset = true, }; int ret = -1; From cf2dacc5608ca950d6a7a92bf6a5f9f9bcf13b92 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Apr 2012 15:19:17 -0300 Subject: [PATCH 12/25] perf annotate browser: Use a vertical line as percentage separator Where we had ':'. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-l8gbejzpglnwiwk43450h31g@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 34b86ea3e54d..e760326efca0 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -71,8 +71,10 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro slsmg_write_nstring(" ", 9); } - SLsmg_write_char(':'); - slsmg_write_nstring(" ", 8); + SLsmg_set_char_set(1); + SLsmg_write_char(SLSMG_VLINE_CHAR); + SLsmg_set_char_set(0); + SLsmg_write_char(' '); /* The scroll bar isn't being used */ if (!self->navkeypressed) From 3f862fd076275c442dfe295eddb5650a6e0aecd4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Apr 2012 17:10:12 -0300 Subject: [PATCH 13/25] perf annotate: Add missing jump variants Taken from binutils: [acme@sandy binutils-2.22]$ grep ^j opcodes/i386-opc.tbl | cut -d, -f1 | sort -u Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-mwshob8n12jlsu458ghvheos@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index d8e2f414e610..e70cbb4f3bed 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -70,11 +70,40 @@ static struct ins instructions[] = { { .name = "call", .ops = &call_ops, }, { .name = "callq", .ops = &call_ops, }, { .name = "ja", .ops = &jump_ops, }, + { .name = "jae", .ops = &jump_ops, }, + { .name = "jb", .ops = &jump_ops, }, + { .name = "jbe", .ops = &jump_ops, }, + { .name = "jc", .ops = &jump_ops, }, + { .name = "jcxz", .ops = &jump_ops, }, { .name = "je", .ops = &jump_ops, }, + { .name = "jecxz", .ops = &jump_ops, }, + { .name = "jg", .ops = &jump_ops, }, + { .name = "jge", .ops = &jump_ops, }, + { .name = "jl", .ops = &jump_ops, }, + { .name = "jle", .ops = &jump_ops, }, { .name = "jmp", .ops = &jump_ops, }, { .name = "jmpq", .ops = &jump_ops, }, + { .name = "jna", .ops = &jump_ops, }, + { .name = "jnae", .ops = &jump_ops, }, + { .name = "jnb", .ops = &jump_ops, }, + { .name = "jnbe", .ops = &jump_ops, }, + { .name = "jnc", .ops = &jump_ops, }, { .name = "jne", .ops = &jump_ops, }, + { .name = "jng", .ops = &jump_ops, }, + { .name = "jnge", .ops = &jump_ops, }, + { .name = "jnl", .ops = &jump_ops, }, + { .name = "jnle", .ops = &jump_ops, }, + { .name = "jno", .ops = &jump_ops, }, + { .name = "jnp", .ops = &jump_ops, }, + { .name = "jns", .ops = &jump_ops, }, + { .name = "jnz", .ops = &jump_ops, }, + { .name = "jo", .ops = &jump_ops, }, + { .name = "jp", .ops = &jump_ops, }, + { .name = "jpe", .ops = &jump_ops, }, + { .name = "jpo", .ops = &jump_ops, }, + { .name = "jrcxz", .ops = &jump_ops, }, { .name = "js", .ops = &jump_ops, }, + { .name = "jz", .ops = &jump_ops, }, }; static int ins__cmp(const void *name, const void *insp) From c7e6ead7347813b5833efb9b32908c08ff131259 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 20 Apr 2012 14:38:46 -0300 Subject: [PATCH 14/25] perf annotate: Group operands members So that the ins_ops can handle them in a single place, instead of adding more and more functions or ins_ops parameters. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-pk4dqaum6ftiz104dvimwgtb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 17 +++++----- tools/perf/util/annotate.c | 56 +++++++++++++++---------------- tools/perf/util/annotate.h | 22 +++++++----- 3 files changed, 49 insertions(+), 46 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index e760326efca0..9c7b6d87822e 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -113,13 +113,12 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro if (change_color) ui_browser__set_color(self, color); if (dl->ins && dl->ins->ops->scnprintf) { - dl->ins->ops->scnprintf(dl->ins, bf, sizeof(bf), - !ab->use_offset ? dl->operands : NULL, - dl->target); + dl->ins->ops->scnprintf(dl->ins, bf, sizeof(bf), &dl->ops, + !ab->use_offset); slsmg_write_nstring(" ", 2); printed += 2; } else - scnprintf(bf, sizeof(bf), " %-6.6s %s", dl->name, dl->operands); + scnprintf(bf, sizeof(bf), " %-6.6s %s", dl->name, dl->ops.raw); slsmg_write_nstring(bf, width - 10 - printed); } @@ -294,7 +293,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, if (!ins__is_call(dl->ins)) return false; - ip = ms->map->map_ip(ms->map, dl->target); + ip = ms->map->map_ip(ms->map, dl->ops.target); target = map__find_symbol(ms->map, ip, NULL); if (target == NULL) { ui_helpline__puts("The called function was not found."); @@ -345,7 +344,7 @@ static bool annotate_browser__jump(struct annotate_browser *browser) if (!ins__is_jump(dl->ins)) return false; - dl = annotate_browser__find_offset(browser, dl->target, &idx); + dl = annotate_browser__find_offset(browser, dl->ops.target, &idx); if (dl == NULL) { ui_helpline__puts("Invallid jump offset"); return true; @@ -621,14 +620,14 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser if (!dl || !dl->ins || !ins__is_jump(dl->ins)) continue; - if (dl->target >= size) { + if (dl->ops.target >= size) { ui__error("jump to after symbol!\n" "size: %zx, jump target: %" PRIx64, - size, dl->target); + size, dl->ops.target); continue; } - dlt = browser->offsets[dl->target]; + dlt = browser->offsets[dl->ops.target]; bdlt = disasm_line__browser(dlt); bdlt->jump_target = true; } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index e70cbb4f3bed..7f6c14b3fd7f 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -18,14 +18,14 @@ const char *disassembler_style; -static int call_ops__parse_target(const char *operands, u64 *target) +static int call__parse(struct ins_operands *ops) { - *target = strtoull(operands, NULL, 16); + ops->target = strtoull(ops->raw, NULL, 16); return 0; } static struct ins_ops call_ops = { - .parse_target = call_ops__parse_target, + .parse = call__parse, }; bool ins__is_call(const struct ins *ins) @@ -33,29 +33,29 @@ bool ins__is_call(const struct ins *ins) return ins->ops == &call_ops; } -static int jump_ops__parse_target(const char *operands, u64 *target) +static int jump__parse(struct ins_operands *ops) { - const char *s = strchr(operands, '+'); + const char *s = strchr(ops->raw, '+'); if (s++ == NULL) return -1; - *target = strtoll(s, NULL, 16); + ops->target = strtoll(s, NULL, 16); return 0; } -static int jump_ops__scnprintf(struct ins *ins, char *bf, size_t size, - const char *operands, u64 target) +static int jump__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, bool addrs) { - if (operands) - return scnprintf(bf, size, "%-6.6s %s", ins->name, operands); + if (addrs) + return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw); - return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, target); + return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target); } static struct ins_ops jump_ops = { - .parse_target = jump_ops__parse_target, - .scnprintf = jump_ops__scnprintf, + .parse = jump__parse, + .scnprintf = jump__scnprintf, }; bool ins__is_jump(const struct ins *ins) @@ -190,8 +190,8 @@ static void disasm_line__init_ins(struct disasm_line *dl) if (!dl->ins->ops) return; - if (dl->ins->ops->parse_target) - dl->ins->ops->parse_target(dl->operands, &dl->target); + if (dl->ins->ops->parse) + dl->ins->ops->parse(&dl->ops); } static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) @@ -213,25 +213,25 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privs if (name[0] == '\0') goto out_delete; - dl->operands = name + 1; + dl->ops.raw = name + 1; - while (dl->operands[0] != '\0' && - !isspace(dl->operands[0])) - ++dl->operands; + while (dl->ops.raw[0] != '\0' && + !isspace(dl->ops.raw[0])) + ++dl->ops.raw; - tmp = dl->operands[0]; - dl->operands[0] = '\0'; + tmp = dl->ops.raw[0]; + dl->ops.raw[0] = '\0'; dl->name = strdup(name); if (dl->name == NULL) goto out_free_line; - dl->operands[0] = tmp; + dl->ops.raw[0] = tmp; - if (dl->operands[0] != '\0') { - dl->operands++; - while (isspace(dl->operands[0])) - ++dl->operands; + if (dl->ops.raw[0] != '\0') { + dl->ops.raw++; + while (isspace(dl->ops.raw[0])) + ++dl->ops.raw; } disasm_line__init_ins(dl); @@ -753,9 +753,9 @@ static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp) printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name); - if (dl->operands[0] != '\0') { + if (dl->ops.raw[0] != '\0') { printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", - dl->operands); + dl->ops.raw); } return printed + fprintf(fp, "\n"); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 6314335007f0..a6f60d5c5138 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -9,10 +9,15 @@ struct ins; +struct ins_operands { + char *raw; + u64 target; +}; + struct ins_ops { - int (*parse_target)(const char *operands, u64 *target); + int (*parse)(struct ins_operands *ops); int (*scnprintf)(struct ins *ins, char *bf, size_t size, - const char *operands, u64 target); + struct ins_operands *ops, bool addrs); }; struct ins { @@ -24,13 +29,12 @@ bool ins__is_jump(const struct ins *ins); bool ins__is_call(const struct ins *ins); struct disasm_line { - struct list_head node; - s64 offset; - u64 target; - char *line; - char *name; - struct ins *ins; - char *operands; + struct list_head node; + s64 offset; + char *line; + char *name; + struct ins *ins; + struct ins_operands ops; }; void disasm_line__free(struct disasm_line *dl); From 97148a97baf71536e15aa0acf3310b7b1409e2f4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 20 Apr 2012 15:17:50 -0300 Subject: [PATCH 15/25] perf annotate browser: Bandaid offsets/jump label objdump ambiguity We need to cope with things like: $ objdump -d --no-show-raw -S -C /lib/modules/3.4.0-rc2+/build/vmlinux ffffffff8125ec60 : * Output: * eax uncopied bytes or 0 if successful. */ ENTRY(copy_user_generic_unrolled) CFI_STARTPROC cmpl $8,%edx ffffffff8125ec60: cmp $0x8,%edx jb 20f /* less then 8 bytes, go to byte copy loop */ ffffffff8125ec63: jb ffffffff8125ecf5 ALIGN_DESTINATION ffffffff8125ec8d: je ffffffff8125ecd9 1: movq (%rsi),%r8 ffffffff8125ec8f: mov (%rsi),%r8 2: movq 1*8(%rsi),%r9 ffffffff8125ec92: mov 0x8(%rsi),%r9 3: movq 2*8(%rsi),%r10 ffffffff8125ec96: mov 0x10(%rsi),%r10 4: movq 3*8(%rsi),%r11 Probably expect that the length of the addr field be the same... Lazy move for now, back to supporting suppressing the address on callq lines... Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-7hp85vnvowpqj8799f8rxbu1@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 9c7b6d87822e..c2bbfc767d4f 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -690,7 +690,15 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, bpos->idx = browser.nr_entries++; if (pos->offset != -1) { bpos->idx_asm = browser.nr_asm_entries++; - browser.offsets[pos->offset] = pos; + /* + * FIXME: short term bandaid to cope with assembly + * routines that comes with labels in the same column + * as the address in objdump, sigh. + * + * E.g. copy_user_generic_unrolled + */ + if (pos->offset < (s64)size) + browser.offsets[pos->offset] = pos; } else bpos->idx_asm = -1; } From d22328855666464731ee95d9e1e8d35dc7a39d8d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 20 Apr 2012 15:26:47 -0300 Subject: [PATCH 16/25] perf annotate browser: Suppress the callq address 0.00 | callq ffffffff8112f190 <__mod_zone_page_state> Becomes: 0.00 | callq __mod_zone_page_state But if you press 'o' it gets verbose, i.e. as in objdump -dS: 0.00 | ffffffff8116bdda: callq ffffffff8112f190 <__mod_zone_page_state> Requested-by: Linus Torvalds Cc: David Ahern Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-bwse2wib954y0db7dq91bes5@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 43 ++++++++++++++++++++++++++++++++++++-- tools/perf/util/annotate.h | 1 + 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 7f6c14b3fd7f..b07d7d1425f9 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -20,12 +20,50 @@ const char *disassembler_style; static int call__parse(struct ins_operands *ops) { - ops->target = strtoull(ops->raw, NULL, 16); + char *endptr, *tok, *name; + + ops->target = strtoull(ops->raw, &endptr, 16); + + name = strchr(endptr, '<'); + if (name == NULL) + goto indirect_call; + + name++; + + tok = strchr(name, '>'); + if (tok == NULL) + return -1; + + *tok = '\0'; + ops->target_name = strdup(name); + *tok = '>'; + + return ops->target_name == NULL ? -1 : 0; + +indirect_call: + tok = strchr(endptr, '*'); + if (tok == NULL) + return -1; + + ops->target = strtoull(tok + 1, NULL, 16); return 0; } +static int call__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, bool addrs) +{ + if (addrs) + return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw); + + if (ops->target_name) + return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target_name); + + return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target); +} + static struct ins_ops call_ops = { - .parse = call__parse, + .parse = call__parse, + .scnprintf = call__scnprintf, }; bool ins__is_call(const struct ins *ins) @@ -251,6 +289,7 @@ void disasm_line__free(struct disasm_line *dl) { free(dl->line); free(dl->name); + free(dl->ops.target_name); free(dl); } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index a6f60d5c5138..8a8af0d82b07 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -11,6 +11,7 @@ struct ins; struct ins_operands { char *raw; + char *target_name; u64 target; }; From 51a0d455b5f44cb4680e0a89f99860b669e40d0f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 20 Apr 2012 15:40:20 -0300 Subject: [PATCH 17/25] perf annotate browser: Add visual cues on jump lines Using up/down arrows just before the instruction, replacing the actual chars with approximations to avoid mail encoding snafus: avtab_search_node 0.00 | push %rbp 0.00 | mov %rsp,%rbp 0.00 | callq mcount 0.00 | movzwl 0x6(%rsi),%edx 0.00 | and $0x7fff,%dx 0.00 | test %rdi,%rdi 0.00 | v jne 20 0.00 | 17: xor %eax,%eax 0.00 | 19: leaveq 0.00 | retq 0.00 | nopl 0x0(%rax,%rax,1) 0.00 | 20: mov (%rdi),%rax 0.00 | test %rax,%rax 0.00 | ^ je 17 0.00 | movzwl (%rsi),%ecx 0.00 | movzwl 0x2(%rsi),%r9d 0.00 | movzwl 0x4(%rsi),%r8d 0.00 | movzwl %cx,%esi 0.00 | movzwl %r9w,%r10d 0.00 | shl $0x9,%esi 0.00 | lea (%rsi,%r10,4),%esi 0.00 | lea (%r8,%rsi,1),%esi 0.00 | and 0x10(%rdi),%si 0.00 | movzwl %si,%esi 0.00 | mov (%rax,%rsi,8),%rax 0.00 | test %rax,%rax 0.00 | ^ je 19 0.00 | nopw 0x0(%rax,%rax,1) 0.00 | 60: cmp %cx,(%rax) 0.00 | v jne 7e 0.00 | cmp %r9w,0x2(%rax) 0.00 | v jne 7e 0.00 | cmp %r8w,0x4(%rax) 0.00 | v jne 79 0.00 | test %dx,0x6(%rax) 0.00 | ^ jne 19 0.00 | 79: cmp %r8w,0x4(%rax) 93.04 | 7e:^ ja 17 2.53 | mov 0x10(%rax),%rax 4.43 | test %rax,%rax 0.00 | ^ jne 60 0.00 | leaveq 0.00 | retq Next low hanging fruit is to use left arrow for retqs, then work on clearling marking loops. Requested-by: Linus Torvalds Cc: David Ahern Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-hkx848wdbs6n7bcp3ymr9yus@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index c2bbfc767d4f..63206ca4336b 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -113,9 +113,20 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro if (change_color) ui_browser__set_color(self, color); if (dl->ins && dl->ins->ops->scnprintf) { + if (ins__is_jump(dl->ins)) { + bool fwd = dl->ops.target > (u64)dl->offset; + + SLsmg_set_char_set(1); + SLsmg_write_char(fwd ? SLSMG_DARROW_CHAR : + SLSMG_UARROW_CHAR); + SLsmg_set_char_set(0); + SLsmg_write_char(' '); + } else { + slsmg_write_nstring(" ", 2); + } + dl->ins->ops->scnprintf(dl->ins, bf, sizeof(bf), &dl->ops, !ab->use_offset); - slsmg_write_nstring(" ", 2); printed += 2; } else scnprintf(bf, sizeof(bf), " %-6.6s %s", dl->name, dl->ops.raw); From 4ea08b522071c6c34098b7a880aac3551abecd75 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 20 Apr 2012 15:51:40 -0300 Subject: [PATCH 18/25] perf annotate browser: Add visual cue for retq instruction Just use a left arrow prefixing retqs. Requested-by: Linus Torvalds Cc: David Ahern Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-tnpfijuomrntbnl5vr6ibdwa@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 63206ca4336b..d0c606ecda05 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -127,11 +127,20 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro dl->ins->ops->scnprintf(dl->ins, bf, sizeof(bf), &dl->ops, !ab->use_offset); - printed += 2; - } else - scnprintf(bf, sizeof(bf), " %-6.6s %s", dl->name, dl->ops.raw); + } else { + if (strcmp(dl->name, "retq")) { + slsmg_write_nstring(" ", 2); + } else { + SLsmg_set_char_set(1); + SLsmg_write_char(SLSMG_LARROW_CHAR); + SLsmg_set_char_set(0); + SLsmg_write_char(' '); + } - slsmg_write_nstring(bf, width - 10 - printed); + scnprintf(bf, sizeof(bf), "%-6.6s %s", dl->name, dl->ops.raw); + } + + slsmg_write_nstring(bf, width - 12 - printed); } if (current_entry) From c4cceae3ba786c136b0cf568359863d74897a48a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 20 Apr 2012 15:57:15 -0300 Subject: [PATCH 19/25] perf annotate browser: Handle retq instructions By just returning to the previous function being annotated or to the top main screen when popping out the base of the annotation stack. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-x1dlc4d5aukj72g45o15s75k@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index d0c606ecda05..38f4c6f821c2 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -599,10 +599,15 @@ show_help: ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); else if (self->selection->offset == -1) ui_helpline__puts("Actions are only available for assembly lines."); - else if (!self->selection->ins || - !(annotate_browser__jump(self) || - annotate_browser__callq(self, evidx, timer, arg, delay_secs))) - ui_helpline__puts("Actions are only available for the 'callq' and jump instructions."); + else if (!self->selection->ins) { + if (strcmp(self->selection->name, "retq")) + goto show_sup_ins; + goto out; + } else if (!(annotate_browser__jump(self) || + annotate_browser__callq(self, evidx, timer, arg, delay_secs))) { +show_sup_ins: + ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions."); + } continue; case K_LEFT: case K_ESC: From 59d038d591f7f00e6752cbfadbbc1c0ca318c5c0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 20 Apr 2012 16:26:14 -0300 Subject: [PATCH 20/25] ui browser: Add method to write graphical characters To save typing on the switch char set slang stuff. It also helps in removing more slang direct calls, wrapping them at the ui_browser level, where at some point I'll try to implement those in terms of GTK+. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-63yhb2htv9g3g1olmojzptkd@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browser.c | 7 +++++++ tools/perf/ui/browser.h | 1 + tools/perf/ui/browsers/annotate.c | 14 ++++---------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index a1b140cf75ac..973ff74e3640 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c @@ -593,6 +593,13 @@ unsigned int ui_browser__argv_refresh(struct ui_browser *browser) return row; } +void ui_browser__write_graph(struct ui_browser *browser __used, int graph) +{ + SLsmg_set_char_set(1); + SLsmg_write_char(graph); + SLsmg_set_char_set(0); +} + void ui_browser__init(void) { int i = 0; diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h index 2550277db9f9..ce20975419d2 100644 --- a/tools/perf/ui/browser.h +++ b/tools/perf/ui/browser.h @@ -37,6 +37,7 @@ void ui_browser__refresh_dimensions(struct ui_browser *self); void ui_browser__reset_index(struct ui_browser *self); void ui_browser__gotorc(struct ui_browser *self, int y, int x); +void ui_browser__write_graph(struct ui_browser *browser, int graph); void __ui_browser__show_title(struct ui_browser *browser, const char *title); void ui_browser__show_title(struct ui_browser *browser, const char *title); int ui_browser__show(struct ui_browser *self, const char *title, diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 38f4c6f821c2..c3fc6f39f901 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -71,9 +71,7 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro slsmg_write_nstring(" ", 9); } - SLsmg_set_char_set(1); - SLsmg_write_char(SLSMG_VLINE_CHAR); - SLsmg_set_char_set(0); + ui_browser__write_graph(self, SLSMG_VLINE_CHAR); SLsmg_write_char(' '); /* The scroll bar isn't being used */ @@ -116,10 +114,8 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro if (ins__is_jump(dl->ins)) { bool fwd = dl->ops.target > (u64)dl->offset; - SLsmg_set_char_set(1); - SLsmg_write_char(fwd ? SLSMG_DARROW_CHAR : - SLSMG_UARROW_CHAR); - SLsmg_set_char_set(0); + ui_browser__write_graph(self, fwd ? SLSMG_DARROW_CHAR : + SLSMG_UARROW_CHAR); SLsmg_write_char(' '); } else { slsmg_write_nstring(" ", 2); @@ -131,9 +127,7 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro if (strcmp(dl->name, "retq")) { slsmg_write_nstring(" ", 2); } else { - SLsmg_set_char_set(1); - SLsmg_write_char(SLSMG_LARROW_CHAR); - SLsmg_set_char_set(0); + ui_browser__write_graph(self, SLSMG_LARROW_CHAR); SLsmg_write_char(' '); } From a3f895be1f1ed17f66e6e71adeef0cc7f937512c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 24 Apr 2012 14:24:28 -0300 Subject: [PATCH 21/25] perf annotate browser: Initial loop detection Simple algorithm, just look for the next backward jump that points to before the cursor. Then draw an arrow connecting the jump to its target. Do this as you move the cursor, entering/exiting possible loops. Ex (graph chars replaced to avoid mail encoding woes): avc_has_perm_flags 0.00 | nopl 0x0(%rax) 5.36 |+-> 68: mov (%rax),%rax 5.15 || test %rax,%rax 0.00 || v je 130 2.96 || 74: cmp -0x20(%rax),%ebx 47.38 || lea -0x20(%rax),%rcx 0.28 || ^ jne 68 3.16 || cmp -0x18(%rax),%dx 0.00 |+------^ jne 68 4.92 | cmp 0x4(%rcx),%r13d 0.00 | v jne 68 1.15 | test %rcx,%rcx 0.00 | v je 130 Suggested-by: Linus Torvalds Cc: David Ahern Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-5gairf6or7dazlx3ocxwvftm@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browser.c | 39 ++++++++++++++++++++ tools/perf/ui/browser.h | 2 + tools/perf/ui/browsers/annotate.c | 61 +++++++++++++++++++++++++++++-- 3 files changed, 98 insertions(+), 4 deletions(-) diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index 973ff74e3640..32ac1165100d 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c @@ -600,6 +600,45 @@ void ui_browser__write_graph(struct ui_browser *browser __used, int graph) SLsmg_set_char_set(0); } +void __ui_browser__line_arrow_up(struct ui_browser *browser, unsigned int column, + u64 start, u64 end, int start_width) +{ + unsigned int row, end_row; + + SLsmg_set_char_set(1); + + if (start < browser->top_idx + browser->height) { + row = start - browser->top_idx; + ui_browser__gotorc(browser, row, column); + SLsmg_write_char(SLSMG_LLCORN_CHAR); + ui_browser__gotorc(browser, row, column + 1); + SLsmg_draw_hline(start_width); + + if (row-- == 0) + goto out; + } else + row = browser->height - 1; + + if (end > browser->top_idx) + end_row = end - browser->top_idx; + else + end_row = 0; + + ui_browser__gotorc(browser, end_row, column); + SLsmg_draw_vline(row - end_row + 1); + + ui_browser__gotorc(browser, end_row, column); + if (end >= browser->top_idx) { + SLsmg_write_char(SLSMG_ULCORN_CHAR); + ui_browser__gotorc(browser, end_row, column + 1); + SLsmg_write_char(SLSMG_HLINE_CHAR); + ui_browser__gotorc(browser, end_row, column + 2); + SLsmg_write_char(SLSMG_RARROW_CHAR); + } +out: + SLsmg_set_char_set(0); +} + void ui_browser__init(void) { int i = 0; diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h index ce20975419d2..2f226cb79f6a 100644 --- a/tools/perf/ui/browser.h +++ b/tools/perf/ui/browser.h @@ -38,6 +38,8 @@ void ui_browser__reset_index(struct ui_browser *self); void ui_browser__gotorc(struct ui_browser *self, int y, int x); void ui_browser__write_graph(struct ui_browser *browser, int graph); +void __ui_browser__line_arrow_up(struct ui_browser *browser, unsigned int column, + u64 start, u64 end, int start_width); void __ui_browser__show_title(struct ui_browser *browser, const char *title); void ui_browser__show_title(struct ui_browser *browser, const char *title); int ui_browser__show(struct ui_browser *self, const char *title, diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index c3fc6f39f901..9e3310cd02cd 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -94,13 +94,13 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro addr += ab->start; if (!ab->use_offset) { - printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ":", addr); + printed = scnprintf(bf, sizeof(bf), " %" PRIx64 ":", addr); } else { if (bdl->jump_target) { - printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ":", + printed = scnprintf(bf, sizeof(bf), " %*" PRIx64 ":", ab->offset_width, addr); } else { - printed = scnprintf(bf, sizeof(bf), "%*s ", + printed = scnprintf(bf, sizeof(bf), " %*s ", ab->offset_width, " "); } } @@ -141,6 +141,59 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro ab->selection = dl; } +static void annotate_browser__draw_current_loop(struct ui_browser *browser) +{ + struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); + struct map_symbol *ms = browser->priv; + struct symbol *sym = ms->sym; + struct annotation *notes = symbol__annotation(sym); + struct disasm_line *cursor = ab->selection, *pos = cursor, *target; + struct browser_disasm_line *bcursor = disasm_line__browser(cursor), + *btarget, *bpos; + unsigned int from, to, start_width = 2; + + list_for_each_entry_from(pos, ¬es->src->source, node) { + if (!pos->ins || !ins__is_jump(pos->ins)) + continue; + + target = ab->offsets[pos->ops.target]; + if (!target) + continue; + + btarget = disasm_line__browser(target); + if (btarget->idx <= bcursor->idx) + goto found; + } + + return; + +found: + bpos = disasm_line__browser(pos); + if (ab->hide_src_code) { + from = bpos->idx_asm; + to = btarget->idx_asm; + } else { + from = (u64)bpos->idx; + to = (u64)btarget->idx; + } + + ui_browser__set_color(browser, HE_COLORSET_CODE); + + if (!bpos->jump_target) + start_width += ab->offset_width + 1; + + __ui_browser__line_arrow_up(browser, 10, from, to, start_width); +} + +static unsigned int annotate_browser__refresh(struct ui_browser *browser) +{ + int ret = ui_browser__list_head_refresh(browser); + + annotate_browser__draw_current_loop(browser); + + return ret; +} + static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx) { double percent = 0.0; @@ -666,7 +719,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, }; struct annotate_browser browser = { .b = { - .refresh = ui_browser__list_head_refresh, + .refresh = annotate_browser__refresh, .seek = ui_browser__list_head_seek, .write = annotate_browser__write, .filter = disasm_line__filter, From 9481ede909e08418c9379665ee9f25335d20dd06 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 25 Apr 2012 07:48:42 -0300 Subject: [PATCH 22/25] perf annotate browser: Handle NULL jump targets In annotate_browser__mark_jump_targets 702 dlt = browser->offsets[dl->ops.target]; 703 bdlt = disasm_line__browser(dlt); 704 bdlt->jump_target = true; 705 } 706 707 } (gdb) p size $5 = 2415 (gdb) p offset $6 = 140 (gdb) p dl->ops.target $7 = 143 (gdb) p browser->offsets[143] $8 = (struct disasm_line *) 0x0 (gdb) p dl->name $9 = 0x2363bd0 "je" (gdb) Really strange, the code assumed that at the jump target we would have an assembly line, but only in the previous instruction offset we have a 'lock': (gdb) p browser->offsets[144] $10 = (struct disasm_line *) 0x0 (gdb) p browser->offsets[142] $11 = (struct disasm_line *) 0x27bd620 (gdb) p browser->offsets[142]->name $12 = 0x237a8a0 "lock" (gdb) I'll study this more, but for now I'll just check if there is a disasm_line at dl->ops.target, i.e. a valid jump target. Reported-by: Hagen Paul Pfeifer Reported-by: Ingo Molnar Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-inzjrzyqhkzyv78met2vula6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 9e3310cd02cd..4c83fe3d7dad 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -700,6 +700,13 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser } dlt = browser->offsets[dl->ops.target]; + /* + * FIXME: Oops, no jump target? Buggy disassembler? Or do we + * have to adjust to the previous offset? + */ + if (dlt == NULL) + continue; + bdlt = disasm_line__browser(dlt); bdlt->jump_target = true; } From 44d1a3edfbd65f9da6725921e2425b10477772d8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 25 Apr 2012 08:00:23 -0300 Subject: [PATCH 23/25] perf annotate: Disambiguage offsets and addresses in operands We were using ins_ops->target for callq addresses and jump offsets, disambiguate by having ins_ops->target.addr and ins_ops->target.offset. For jumps we'll need both to fixup lines that don't have an offset on the <> part. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-3nlcmstua75u07ao7wja1rwx@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 14 +++++++------- tools/perf/util/annotate.c | 20 ++++++++++---------- tools/perf/util/annotate.h | 7 +++++-- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 4c83fe3d7dad..73e1ef0081d4 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -112,7 +112,7 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro ui_browser__set_color(self, color); if (dl->ins && dl->ins->ops->scnprintf) { if (ins__is_jump(dl->ins)) { - bool fwd = dl->ops.target > (u64)dl->offset; + bool fwd = dl->ops.target.offset > (u64)dl->offset; ui_browser__write_graph(self, fwd ? SLSMG_DARROW_CHAR : SLSMG_UARROW_CHAR); @@ -156,7 +156,7 @@ static void annotate_browser__draw_current_loop(struct ui_browser *browser) if (!pos->ins || !ins__is_jump(pos->ins)) continue; - target = ab->offsets[pos->ops.target]; + target = ab->offsets[pos->ops.target.offset]; if (!target) continue; @@ -360,7 +360,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, if (!ins__is_call(dl->ins)) return false; - ip = ms->map->map_ip(ms->map, dl->ops.target); + ip = ms->map->map_ip(ms->map, dl->ops.target.addr); target = map__find_symbol(ms->map, ip, NULL); if (target == NULL) { ui_helpline__puts("The called function was not found."); @@ -411,7 +411,7 @@ static bool annotate_browser__jump(struct annotate_browser *browser) if (!ins__is_jump(dl->ins)) return false; - dl = annotate_browser__find_offset(browser, dl->ops.target, &idx); + dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx); if (dl == NULL) { ui_helpline__puts("Invallid jump offset"); return true; @@ -692,14 +692,14 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser if (!dl || !dl->ins || !ins__is_jump(dl->ins)) continue; - if (dl->ops.target >= size) { + if (dl->ops.target.offset >= size) { ui__error("jump to after symbol!\n" "size: %zx, jump target: %" PRIx64, - size, dl->ops.target); + size, dl->ops.target.offset); continue; } - dlt = browser->offsets[dl->ops.target]; + dlt = browser->offsets[dl->ops.target.offset]; /* * FIXME: Oops, no jump target? Buggy disassembler? Or do we * have to adjust to the previous offset? diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index b07d7d1425f9..e1e7d0eb6145 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -22,7 +22,7 @@ static int call__parse(struct ins_operands *ops) { char *endptr, *tok, *name; - ops->target = strtoull(ops->raw, &endptr, 16); + ops->target.addr = strtoull(ops->raw, &endptr, 16); name = strchr(endptr, '<'); if (name == NULL) @@ -35,17 +35,17 @@ static int call__parse(struct ins_operands *ops) return -1; *tok = '\0'; - ops->target_name = strdup(name); + ops->target.name = strdup(name); *tok = '>'; - return ops->target_name == NULL ? -1 : 0; + return ops->target.name == NULL ? -1 : 0; indirect_call: tok = strchr(endptr, '*'); if (tok == NULL) return -1; - ops->target = strtoull(tok + 1, NULL, 16); + ops->target.addr = strtoull(tok + 1, NULL, 16); return 0; } @@ -55,10 +55,10 @@ static int call__scnprintf(struct ins *ins, char *bf, size_t size, if (addrs) return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw); - if (ops->target_name) - return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target_name); + if (ops->target.name) + return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name); - return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target); + return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr); } static struct ins_ops call_ops = { @@ -78,7 +78,7 @@ static int jump__parse(struct ins_operands *ops) if (s++ == NULL) return -1; - ops->target = strtoll(s, NULL, 16); + ops->target.offset = strtoll(s, NULL, 16); return 0; } @@ -88,7 +88,7 @@ static int jump__scnprintf(struct ins *ins, char *bf, size_t size, if (addrs) return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw); - return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target); + return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset); } static struct ins_ops jump_ops = { @@ -289,7 +289,7 @@ void disasm_line__free(struct disasm_line *dl) { free(dl->line); free(dl->name); - free(dl->ops.target_name); + free(dl->ops.target.name); free(dl); } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 8a8af0d82b07..2b9e3e038a84 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -11,8 +11,11 @@ struct ins; struct ins_operands { char *raw; - char *target_name; - u64 target; + struct { + char *name; + u64 offset; + u64 addr; + } target; }; struct ins_ops { From fb29fa58e36df09c807d252247d64a221fcd5bbb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 25 Apr 2012 14:16:03 -0300 Subject: [PATCH 24/25] perf annotate: Mark jump instructions with no offset I.e. jumps that go to code outside the current function, that is denoted in objdump -dS as: 399f877a9f: jne 399f87bcf4 <_L_lock_5154> I.e. without the + after the name of the current function, like in: 399f877aa5: jmp 399f877ab2 <_int_free+0x412> The browser will use that info to avoid drawing connectors to the start of the function, since ops.target.addr was zero. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-xrn35g2mlawz1ydo1p73w3q6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 9 ++++++--- tools/perf/util/annotate.h | 6 ++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index e1e7d0eb6145..5eb34123f55b 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -75,10 +75,13 @@ static int jump__parse(struct ins_operands *ops) { const char *s = strchr(ops->raw, '+'); - if (s++ == NULL) - return -1; + ops->target.addr = strtoll(ops->raw, NULL, 16); + + if (s++ != NULL) + ops->target.offset = strtoll(s, NULL, 16); + else + ops->target.offset = UINT64_MAX; - ops->target.offset = strtoll(s, NULL, 16); return 0; } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 2b9e3e038a84..13a21f10dabb 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -2,6 +2,7 @@ #define __PERF_ANNOTATE_H #include +#include #include "types.h" #include "symbol.h" #include @@ -41,6 +42,11 @@ struct disasm_line { struct ins_operands ops; }; +static inline bool disasm_line__has_offset(const struct disasm_line *dl) +{ + return dl->ops.target.offset != UINT64_MAX; +} + void disasm_line__free(struct disasm_line *dl); struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); size_t disasm__fprintf(struct list_head *head, FILE *fp); From 38b31bd0cefbb0e69a182d9a94b09a7e648549dc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 25 Apr 2012 14:18:42 -0300 Subject: [PATCH 25/25] perf annotate browser: Don't draw jump connectors for out of function jumps As described in the previous patch. Next step is to properly label those jumps by using a -> arrow, i.e. not backwards/forwards, and allow the user to navigate to this other function when enter or -> is pressed. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-ax2sss463eu88wgl9ee8a6b6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 73e1ef0081d4..077380baa1c0 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -153,7 +153,8 @@ static void annotate_browser__draw_current_loop(struct ui_browser *browser) unsigned int from, to, start_width = 2; list_for_each_entry_from(pos, ¬es->src->source, node) { - if (!pos->ins || !ins__is_jump(pos->ins)) + if (!pos->ins || !ins__is_jump(pos->ins) || + !disasm_line__has_offset(pos)) continue; target = ab->offsets[pos->ops.target.offset]; @@ -689,7 +690,8 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser struct disasm_line *dl = browser->offsets[offset], *dlt; struct browser_disasm_line *bdlt; - if (!dl || !dl->ins || !ins__is_jump(dl->ins)) + if (!dl || !dl->ins || !ins__is_jump(dl->ins) || + !disasm_line__has_offset(dl)) continue; if (dl->ops.target.offset >= size) {