From f56c083bc4f9bca6f4d75d13b93720915185a8e8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 11:46:23 -0300 Subject: perf annotate: Move compute_ipc() to annotation library Out of the TUI code, as it has nothing specific to that UI and should be used in the other output modes as well. Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-0jahghvqdodb8vu2591pkv3d@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 535357c6ce02..d737c33c87d0 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -833,6 +833,66 @@ int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, return err; } +static unsigned annotation__count_insn(struct annotation *notes, u64 start, u64 end) +{ + unsigned n_insn = 0; + u64 offset; + + for (offset = start; offset <= end; offset++) { + if (notes->offsets[offset]) + n_insn++; + } + return n_insn; +} + +static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 end, struct cyc_hist *ch) +{ + unsigned n_insn; + u64 offset; + + n_insn = annotation__count_insn(notes, start, end); + if (n_insn && ch->num && ch->cycles) { + float ipc = n_insn / ((double)ch->cycles / (double)ch->num); + + /* Hide data when there are too many overlaps. */ + if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2) + return; + + for (offset = start; offset <= end; offset++) { + struct annotation_line *al = notes->offsets[offset]; + + if (al) + al->ipc = ipc; + } + } +} + +void annotation__compute_ipc(struct annotation *notes, size_t size) +{ + u64 offset; + + if (!notes->src || !notes->src->cycles_hist) + return; + + pthread_mutex_lock(¬es->lock); + for (offset = 0; offset < size; ++offset) { + struct cyc_hist *ch; + + ch = ¬es->src->cycles_hist[offset]; + if (ch && ch->cycles) { + struct annotation_line *al; + + if (ch->have_start) + annotation__count_and_fill(notes, ch->start, offset, ch); + al = notes->offsets[offset]; + if (al && ch->num_aggr) + al->cycles = ch->cycles_aggr / ch->num_aggr; + notes->have_cycles = true; + } + } + pthread_mutex_unlock(¬es->lock); +} + int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, int evidx) { -- cgit v1.2.3 From 0db45bcfac8586c6f5b732f114f456f2f788b19f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 15:31:56 -0300 Subject: perf annotate: Move mark_jump_targets from the TUI to the annotation library This also is not TUI specific, should be used in the upcoming --stdio2 mode. Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-v827xec8z3hxrmgp7bwa6ohs@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 54 +++------------------------------------ tools/perf/util/annotate.c | 44 +++++++++++++++++++++++++++++++ tools/perf/util/annotate.h | 4 +++ 3 files changed, 51 insertions(+), 51 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index d05a2f991207..58be0cecb081 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -25,7 +25,6 @@ struct disasm_line_samples { struct browser_line { u32 idx; int idx_asm; - int jump_sources; }; static struct annotation_options annotate_browser__opts = { @@ -132,7 +131,6 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); struct annotation *notes = browser__annotation(browser); struct annotation_line *al = list_entry(entry, struct annotation_line, node); - struct browser_line *bl = browser_line(al); bool current_entry = ui_browser__is_current_entry(browser, row); bool change_color = (!notes->options->hide_src_code && (!current_entry || (browser->use_navkeypressed && @@ -228,13 +226,13 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int if (!notes->options->use_offset) { printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); } else { - if (bl->jump_sources) { + if (al->jump_sources) { if (notes->options->show_nr_jumps) { int prev; printed = scnprintf(bf, sizeof(bf), "%*d ", ab->jumps_width, - bl->jump_sources); - prev = ui_browser__set_jumps_percent_color(browser, bl->jump_sources, + al->jump_sources); + prev = ui_browser__set_jumps_percent_color(browser, al->jump_sources, current_entry); ui_browser__write_nstring(browser, bf, printed); ui_browser__set_color(browser, prev); @@ -263,17 +261,6 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int ab->selection = al; } -static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym) -{ - if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins) - || !disasm_line__has_offset(dl) - || dl->ops.target.offset < 0 - || dl->ops.target.offset >= (s64)symbol__size(sym)) - return false; - - return true; -} - static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor) { struct disasm_line *pos = list_prev_entry(cursor, al.node); @@ -964,41 +951,6 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, return map_symbol__tui_annotate(&he->ms, evsel, hbt); } -static void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) -{ - u64 offset, size = symbol__size(sym); - - /* PLT symbols contain external offsets */ - if (strstr(sym->name, "@plt")) - return; - - for (offset = 0; offset < size; ++offset) { - struct annotation_line *al = notes->offsets[offset]; - struct disasm_line *dl; - struct browser_line *blt; - - dl = disasm_line(al); - - if (!disasm_line__is_valid_jump(dl, sym)) - continue; - - al = notes->offsets[dl->ops.target.offset]; - - /* - * FIXME: Oops, no jump target? Buggy disassembler? Or do we - * have to adjust to the previous offset? - */ - if (al == NULL) - continue; - - blt = browser_line(al); - if (++blt->jump_sources > notes->max_jump_sources) - notes->max_jump_sources = blt->jump_sources; - - ++notes->nr_jumps; - } -} - static inline int width_jumps(int n) { if (n >= 100) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index d737c33c87d0..330275680a1a 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2012,6 +2012,50 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp) return printed; } + +bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym) +{ + if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins) || + !disasm_line__has_offset(dl) || dl->ops.target.offset < 0 || + dl->ops.target.offset >= (s64)symbol__size(sym)) + return false; + + return true; +} + +void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) +{ + u64 offset, size = symbol__size(sym); + + /* PLT symbols contain external offsets */ + if (strstr(sym->name, "@plt")) + return; + + for (offset = 0; offset < size; ++offset) { + struct annotation_line *al = notes->offsets[offset]; + struct disasm_line *dl; + + dl = disasm_line(al); + + if (!disasm_line__is_valid_jump(dl, sym)) + continue; + + al = notes->offsets[dl->ops.target.offset]; + + /* + * FIXME: Oops, no jump target? Buggy disassembler? Or do we + * have to adjust to the previous offset? + */ + if (al == NULL) + continue; + + if (++al->jump_sources > notes->max_jump_sources) + notes->max_jump_sources = al->jump_sources; + + ++notes->nr_jumps; + } +} + static void annotation__calc_lines(struct annotation *notes, struct map *map, struct rb_root *root, u64 start) { diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 897a84712ab4..ab4a8b7710a0 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -90,6 +90,7 @@ struct annotation_line { s64 offset; char *line; int line_nr; + int jump_sources; float ipc; u64 cycles; size_t privsize; @@ -116,6 +117,8 @@ static inline bool disasm_line__has_offset(const struct disasm_line *dl) return dl->ops.target.offset_avail; } +bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym); + void disasm_line__free(struct disasm_line *dl); struct annotation_line * annotation_line__next(struct annotation_line *pos, struct list_head *head); @@ -184,6 +187,7 @@ static inline int annotation__pcnt_width(struct annotation *notes) } void annotation__compute_ipc(struct annotation *notes, size_t size); +void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym); static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) { -- cgit v1.2.3 From 5bc49f6120203c9fbe8e63fdcb9598e0ba615de7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 15:59:01 -0300 Subject: perf annotate: Introduce set_offsets() method out of TUI code More non-strictly TUI code being moved to the UI neutral annotation library, to be used in the upcoming --stdio2 output mode. Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-ek20dnd8z2y5v54pcepihybz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 24 ++---------------------- tools/perf/util/annotate.c | 28 ++++++++++++++++++++++++++++ tools/perf/util/annotate.h | 3 +++ 3 files changed, 33 insertions(+), 22 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 00b88349a3c2..977c7e9fdadb 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -938,7 +938,6 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, struct hist_browser_timer *hbt) { - struct annotation_line *al; struct annotation *notes = symbol__annotation(sym); size_t size; struct map_symbol ms = { @@ -991,27 +990,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, notes->start = map__rip_2objdump(map, sym->start); - list_for_each_entry(al, ¬es->src->source, node) { - size_t line_len = strlen(al->line); - - if (browser.b.width < line_len) - browser.b.width = line_len; - al->idx = notes->nr_entries++; - if (al->offset != -1) { - al->idx_asm = notes->nr_asm_entries++; - /* - * 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 (al->offset < (s64)size) - notes->offsets[al->offset] = al; - } else - al->idx_asm = -1; - } - + annotation__set_offsets(notes, size); + browser.b.width = notes->max_line_len; annotation__mark_jump_targets(notes, sym); annotation__compute_ipc(notes, size); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 330275680a1a..b976e3951662 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2056,6 +2056,34 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) } } +void annotation__set_offsets(struct annotation *notes, s64 size) +{ + struct annotation_line *al; + + notes->max_line_len = 0; + + list_for_each_entry(al, ¬es->src->source, node) { + size_t line_len = strlen(al->line); + + if (notes->max_line_len < line_len) + notes->max_line_len = line_len; + al->idx = notes->nr_entries++; + if (al->offset != -1) { + al->idx_asm = notes->nr_asm_entries++; + /* + * 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 (al->offset < size) + notes->offsets[al->offset] = al; + } else + al->idx_asm = -1; + } +} + static void annotation__calc_lines(struct annotation *notes, struct map *map, struct rb_root *root, u64 start) { diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 0c34eb0bd7c8..8a61ec9a5291 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -177,6 +177,7 @@ struct annotation { int max_jump_sources; int nr_entries; int nr_asm_entries; + u16 max_line_len; bool have_cycles; struct annotated_source *src; }; @@ -191,6 +192,8 @@ static inline int annotation__pcnt_width(struct annotation *notes) return (notes->options->show_total_period ? 12 : 7) * notes->nr_events; } + +void annotation__set_offsets(struct annotation *notes, s64 size); void annotation__compute_ipc(struct annotation *notes, size_t size); void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym); -- cgit v1.2.3 From 7232bf7a8954e4f6558e6b74fb6a2403e7a3b7be Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 16:19:59 -0300 Subject: perf annotate: Move update_column_widths() to the generic lib Previous patch left it where it was to ease review, move it to its right place. Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-ikdjr014p7k5kachgyjrgiey@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 13 ------------- tools/perf/util/annotate.c | 13 +++++++++++++ tools/perf/util/annotate.h | 1 + 3 files changed, 14 insertions(+), 13 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 07d0d2268008..ab4d004fc184 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -698,19 +698,6 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, return __annotate_browser__search_reverse(browser); } -static void annotation__update_column_widths(struct annotation *notes) -{ - if (notes->options->use_offset) - notes->widths.target = notes->widths.min_addr; - else - notes->widths.target = notes->widths.max_addr; - - notes->widths.addr = notes->widths.target; - - if (notes->options->show_nr_jumps) - notes->widths.addr += notes->widths.jumps + 1; -} - static int annotate_browser__run(struct annotate_browser *browser, struct perf_evsel *evsel, struct hist_browser_timer *hbt) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index b976e3951662..8a2fda80a221 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2084,6 +2084,19 @@ void annotation__set_offsets(struct annotation *notes, s64 size) } } +void annotation__update_column_widths(struct annotation *notes) +{ + if (notes->options->use_offset) + notes->widths.target = notes->widths.min_addr; + else + notes->widths.target = notes->widths.max_addr; + + notes->widths.addr = notes->widths.target; + + if (notes->options->show_nr_jumps) + notes->widths.addr += notes->widths.jumps + 1; +} + static void annotation__calc_lines(struct annotation *notes, struct map *map, struct rb_root *root, u64 start) { diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 0aa77c154fe3..a8bea758490a 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -203,6 +203,7 @@ static inline int annotation__pcnt_width(struct annotation *notes) void annotation__set_offsets(struct annotation *notes, s64 size); void annotation__compute_ipc(struct annotation *notes, size_t size); void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym); +void annotation__update_column_widths(struct annotation *notes); static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) { -- cgit v1.2.3 From b8b0d819858e1140e98ce858a0c839f3d03cb0f5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 16:26:29 -0300 Subject: perf annotate: Introduce init_column_widths() method out of TUI code More non-TUI stuff goes to the UI-agnostic library Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-hngv7rpqvtta69ouj7ne770q@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 14 +------------- tools/perf/util/annotate.c | 17 +++++++++++++++++ tools/perf/util/annotate.h | 1 + 3 files changed, 19 insertions(+), 13 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index ab4d004fc184..06ad5ecaa67a 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -905,15 +905,6 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, return map_symbol__tui_annotate(&he->ms, evsel, hbt); } -static inline int width_jumps(int n) -{ - if (n >= 100) - return 5; - if (n / 10) - return 2; - return 1; -} - int symbol__tui_annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, struct hist_browser_timer *hbt) @@ -974,10 +965,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, browser.b.width = notes->max_line_len; annotation__mark_jump_targets(notes, sym); annotation__compute_ipc(notes, size); - - notes->widths.addr = notes->widths.target = notes->widths.min_addr = hex_width(size); - notes->widths.max_addr = hex_width(sym->end); - notes->widths.jumps = width_jumps(notes->max_jump_sources); + annotation__init_column_widths(notes, sym); notes->nr_events = nr_pcnt; browser.b.nr_entries = notes->nr_entries; browser.b.entries = ¬es->src->source, diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 8a2fda80a221..9c05b534f428 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2084,6 +2084,23 @@ void annotation__set_offsets(struct annotation *notes, s64 size) } } +static inline int width_jumps(int n) +{ + if (n >= 100) + return 5; + if (n / 10) + return 2; + return 1; +} + +void annotation__init_column_widths(struct annotation *notes, struct symbol *sym) +{ + notes->widths.addr = notes->widths.target = + notes->widths.min_addr = hex_width(symbol__size(sym)); + notes->widths.max_addr = hex_width(sym->end); + notes->widths.jumps = width_jumps(notes->max_jump_sources); +} + void annotation__update_column_widths(struct annotation *notes) { if (notes->options->use_offset) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index a8bea758490a..c4528e03a031 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -204,6 +204,7 @@ void annotation__set_offsets(struct annotation *notes, s64 size); void annotation__compute_ipc(struct annotation *notes, size_t size); void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym); void annotation__update_column_widths(struct annotation *notes); +void annotation__init_column_widths(struct annotation *notes, struct symbol *sym); static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) { -- cgit v1.2.3 From ecda45bd6cfe0badda0e8215c5a008eaf7647716 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 16:54:11 -0300 Subject: perf annotate: Introduce symbol__annotate2 method That does all the extended boilerplate the TUI browser did, leaving the symbol__annotate() function to be used by the old --stdio output mode. Now the upcoming --stdio2 output mode should just use this one to set things up. Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-e2x8wuf6gvdhzdryo229vj4i@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 28 +--------------------------- tools/perf/util/annotate.c | 39 +++++++++++++++++++++++++++++++++++++++ tools/perf/util/annotate.h | 4 ++++ 3 files changed, 44 insertions(+), 27 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 06ad5ecaa67a..ab21739f27ae 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -910,7 +910,6 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, struct hist_browser_timer *hbt) { struct annotation *notes = symbol__annotation(sym); - size_t size; struct map_symbol ms = { .map = map, .sym = sym, @@ -926,28 +925,14 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, }, }; int ret = -1, err; - int nr_pcnt = 1; if (sym == NULL) return -1; - size = symbol__size(sym); - if (map->dso->annotate_warned) return -1; - notes->options = &annotate_browser__opts; - - notes->offsets = zalloc(size * sizeof(struct annotation_line *)); - if (notes->offsets == NULL) { - ui__error("Not enough memory!"); - return -1; - } - - if (perf_evsel__is_group_event(evsel)) - nr_pcnt = evsel->nr_members; - - err = symbol__annotate(sym, map, evsel, 0, &browser.arch); + err = symbol__annotate2(sym, map, evsel, &annotate_browser__opts, &browser.arch); if (err) { char msg[BUFSIZ]; symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); @@ -955,18 +940,9 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, goto out_free_offsets; } - symbol__calc_percent(sym, evsel); - ui_helpline__push("Press ESC to exit"); - notes->start = map__rip_2objdump(map, sym->start); - - annotation__set_offsets(notes, size); browser.b.width = notes->max_line_len; - annotation__mark_jump_targets(notes, sym); - annotation__compute_ipc(notes, size); - annotation__init_column_widths(notes, sym); - notes->nr_events = nr_pcnt; browser.b.nr_entries = notes->nr_entries; browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ @@ -974,8 +950,6 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, if (notes->options->hide_src_code) ui_browser__init_asm_mode(&browser.b); - annotation__update_column_widths(notes); - ret = annotate_browser__run(&browser, evsel, hbt); annotated_source__purge(notes->src); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 9c05b534f428..7ad6400a0d4f 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2183,3 +2183,42 @@ bool ui__has_annotation(void) { return use_browser == 1 && perf_hpp_list.sym; } + +int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, + struct annotation_options *options, struct arch **parch) +{ + struct annotation *notes = symbol__annotation(sym); + size_t size = symbol__size(sym); + int nr_pcnt = 1, err; + + notes->offsets = zalloc(size * sizeof(struct annotation_line *)); + if (notes->offsets == NULL) + return -1; + + if (perf_evsel__is_group_event(evsel)) + nr_pcnt = evsel->nr_members; + + err = symbol__annotate(sym, map, evsel, 0, parch); + if (err) + goto out_free_offsets; + + notes->options = options; + + symbol__calc_percent(sym, evsel); + + notes->start = map__rip_2objdump(map, sym->start); + + annotation__set_offsets(notes, size); + annotation__mark_jump_targets(notes, sym); + annotation__compute_ipc(notes, size); + annotation__init_column_widths(notes, sym); + notes->nr_events = nr_pcnt; + + annotation__update_column_widths(notes); + + return 0; + +out_free_offsets: + zfree(¬es->offsets); + return -1; +} diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index c4528e03a031..f93c805473f9 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -233,6 +233,10 @@ void symbol__annotate_zero_histograms(struct symbol *sym); int symbol__annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, size_t privsize, struct arch **parch); +int symbol__annotate2(struct symbol *sym, struct map *map, + struct perf_evsel *evsel, + struct annotation_options *options, + struct arch **parch); enum symbol_disassemble_errno { SYMBOL_ANNOTATE_ERRNO__SUCCESS = 0, -- cgit v1.2.3 From 2f025ea0bac2f99a2800f43f139f57c226d3b08b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 17:04:53 -0300 Subject: perf annotate: Introduce annotation_line__max_percent() Out of the annotate_browser__write() routine, to be used in the --stdio2 mode. Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-0he0wyy4haswqi1qb35x37do@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 7 +------ tools/perf/util/annotate.c | 14 ++++++++++++++ tools/perf/util/annotate.h | 3 +++ 3 files changed, 18 insertions(+), 6 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index ab21739f27ae..05f79f36e906 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -117,15 +117,10 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int int width = browser->width, printed; int i, pcnt_width = annotation__pcnt_width(notes), cycles_width = annotation__cycles_width(notes); - double percent_max = 0.0; + double percent_max = annotation_line__max_percent(al, notes); char bf[256]; bool show_title = false; - for (i = 0; i < notes->nr_events; i++) { - if (al->samples[i].percent > percent_max) - percent_max = al->samples[i].percent; - } - if ((row == 0) && (al->offset == -1 || percent_max == 0.0)) { if (notes->have_cycles) { if (al->ipc == 0.0 && al->cycles == 0) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 7ad6400a0d4f..3bd6f9b0147f 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2184,6 +2184,20 @@ bool ui__has_annotation(void) return use_browser == 1 && perf_hpp_list.sym; } + +double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes) +{ + double percent_max = 0.0; + int i; + + for (i = 0; i < notes->nr_events; i++) { + if (al->samples[i].percent > percent_max) + percent_max = al->samples[i].percent; + } + + return percent_max; +} + int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, struct annotation_options *options, struct arch **parch) { diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index f93c805473f9..83484e236f33 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -124,6 +124,9 @@ bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym); void disasm_line__free(struct disasm_line *dl); struct annotation_line * annotation_line__next(struct annotation_line *pos, struct list_head *head); + +double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes); + int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); size_t disasm__fprintf(struct list_head *head, FILE *fp); void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); -- cgit v1.2.3 From 2ba5eca10486eeb37030f8bce27cecda3763502f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 17:54:36 -0300 Subject: perf annotate: Introduce annotation_line__print_start() out of TUI code For the --tui and --stdio2 cases using callbacks for print() and set_percent_color() end up being the easiest path, real GUI remains as an exercise. Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-1o7az1ng55g2g6ppr2jpeuct@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 82 ++++++++++----------------------------- tools/perf/util/annotate.c | 75 +++++++++++++++++++++++++++++++++++ tools/perf/util/annotate.h | 5 +++ 3 files changed, 101 insertions(+), 61 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 05f79f36e906..9b77a016e299 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -105,6 +105,20 @@ static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browse disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset); } +static void annotate_browser__set_percent_color(void *browser, double percent, bool current) +{ + ui_browser__set_percent_color(browser, percent, current); +} + +static void annotate_browser__printf(void *browser, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + ui_browser__vprintf(browser, fmt, args); + va_end(args); +} + static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) { struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); @@ -115,65 +129,13 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int (!current_entry || (browser->use_navkeypressed && !browser->navkeypressed))); int width = browser->width, printed; - int i, pcnt_width = annotation__pcnt_width(notes), - cycles_width = annotation__cycles_width(notes); - double percent_max = annotation_line__max_percent(al, notes); + int pcnt_width = annotation__pcnt_width(notes), + cycles_width = annotation__cycles_width(notes); char bf[256]; - bool show_title = false; - - if ((row == 0) && (al->offset == -1 || percent_max == 0.0)) { - if (notes->have_cycles) { - if (al->ipc == 0.0 && al->cycles == 0) - show_title = true; - } else - show_title = true; - } - - if (al->offset != -1 && percent_max != 0.0) { - for (i = 0; i < notes->nr_events; i++) { - ui_browser__set_percent_color(browser, - al->samples[i].percent, - current_entry); - if (notes->options->show_total_period) { - ui_browser__printf(browser, "%11" PRIu64 " ", - al->samples[i].he.period); - } else if (notes->options->show_nr_samples) { - ui_browser__printf(browser, "%6" PRIu64 " ", - al->samples[i].he.nr_samples); - } else { - ui_browser__printf(browser, "%6.2f ", - al->samples[i].percent); - } - } - } else { - ui_browser__set_percent_color(browser, 0, current_entry); - - if (!show_title) - ui_browser__write_nstring(browser, " ", pcnt_width); - else { - ui_browser__printf(browser, "%*s", pcnt_width, - notes->options->show_total_period ? "Period" : - notes->options->show_nr_samples ? "Samples" : "Percent"); - } - } - if (notes->have_cycles) { - if (al->ipc) - ui_browser__printf(browser, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc); - else if (!show_title) - ui_browser__write_nstring(browser, " ", ANNOTATION__IPC_WIDTH); - else - ui_browser__printf(browser, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC"); - - if (al->cycles) - ui_browser__printf(browser, "%*" PRIu64 " ", - ANNOTATION__CYCLES_WIDTH - 1, al->cycles); - else if (!show_title) - ui_browser__write_nstring(browser, " ", ANNOTATION__CYCLES_WIDTH); - else - ui_browser__printf(browser, "%*s ", ANNOTATION__CYCLES_WIDTH - 1, "Cycle"); - } - SLsmg_write_char(' '); + annotation_line__print_start(al, notes, row == 0, current_entry, browser, + annotate_browser__set_percent_color, + annotate_browser__printf); /* The scroll bar isn't being used */ if (!browser->navkeypressed) @@ -183,11 +145,9 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width); else if (al->offset == -1) { if (al->line_nr && notes->options->show_linenr) - printed = scnprintf(bf, sizeof(bf), "%-*d ", - notes->widths.addr + 1, al->line_nr); + printed = scnprintf(bf, sizeof(bf), "%-*d ", notes->widths.addr + 1, al->line_nr); else - printed = scnprintf(bf, sizeof(bf), "%*s ", - notes->widths.addr, " "); + printed = scnprintf(bf, sizeof(bf), "%*s ", notes->widths.addr, " "); ui_browser__write_nstring(browser, bf, printed); ui_browser__write_nstring(browser, al->line, width - printed - pcnt_width - cycles_width + 1); } else { diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 3bd6f9b0147f..046feda11052 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2198,6 +2198,81 @@ double annotation_line__max_percent(struct annotation_line *al, struct annotatio return percent_max; } +static void set_percent_color_stub(void *obj __maybe_unused, + double percent __maybe_unused, + bool current __maybe_unused) +{ +} + +void annotation_line__print_start(struct annotation_line *al, struct annotation *notes, + bool first_line, bool current_entry, + void *obj, + void (*obj__set_percent_color)(void *obj, double percent, bool current), + void (*obj__printf)(void *obj, const char *fmt, ...)) +{ + double percent_max = annotation_line__max_percent(al, notes); + bool show_title = false; + + if (first_line && (al->offset == -1 || percent_max == 0.0)) { + if (notes->have_cycles) { + if (al->ipc == 0.0 && al->cycles == 0) + show_title = true; + } else + show_title = true; + } + + if (!obj__set_percent_color) + obj__set_percent_color = set_percent_color_stub; + + if (al->offset != -1 && percent_max != 0.0) { + int i; + + for (i = 0; i < notes->nr_events; i++) { + obj__set_percent_color(obj, al->samples[i].percent, current_entry); + if (notes->options->show_total_period) { + obj__printf(obj, "%11" PRIu64 " ", al->samples[i].he.period); + } else if (notes->options->show_nr_samples) { + obj__printf(obj, "%6" PRIu64 " ", + al->samples[i].he.nr_samples); + } else { + obj__printf(obj, "%6.2f ", + al->samples[i].percent); + } + } + } else { + int pcnt_width = annotation__pcnt_width(notes); + + obj__set_percent_color(obj, 0, current_entry); + + if (!show_title) + obj__printf(obj, "%*s", pcnt_width, " "); + else { + obj__printf(obj, "%*s", pcnt_width, + notes->options->show_total_period ? "Period" : + notes->options->show_nr_samples ? "Samples" : "Percent"); + } + } + + if (notes->have_cycles) { + if (al->ipc) + obj__printf(obj, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc); + else if (!show_title) + obj__printf(obj, "%*s", ANNOTATION__IPC_WIDTH, " "); + else + obj__printf(obj, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC"); + + if (al->cycles) + obj__printf(obj, "%*" PRIu64 " ", + ANNOTATION__CYCLES_WIDTH - 1, al->cycles); + else if (!show_title) + obj__printf(obj, "%*s", ANNOTATION__CYCLES_WIDTH, " "); + else + obj__printf(obj, "%*s ", ANNOTATION__CYCLES_WIDTH - 1, "Cycle"); + } + + obj__printf(obj, " "); +} + int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, struct annotation_options *options, struct arch **parch) { diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 83484e236f33..84c99774bfed 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -126,6 +126,11 @@ struct annotation_line * annotation_line__next(struct annotation_line *pos, struct list_head *head); double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes); +void annotation_line__print_start(struct annotation_line *al, struct annotation *notes, + bool first_line, bool current_entry, + void *obj, + void (*obj__set_percent_color)(void *obj, double percent, bool current), + void (*obj__printf)(void *obj, const char *fmt, ...)); int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); size_t disasm__fprintf(struct list_head *head, FILE *fp); -- cgit v1.2.3 From a1e9b74cc2ef80131b9f955c0e1acc25285dc88c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 19:12:39 -0300 Subject: perf annotate: Finish the generalization of annotate_browser__write() We pass some more callbacks and all of annotate_browser__write() seems to be free of TUI code (except for some arrow constants, will fix). Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-5uo6yvwnxtsbe8y6v0ysaakf@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 97 +++++--------------------------- tools/perf/util/annotate.c | 113 +++++++++++++++++++++++++++++++++++--- tools/perf/util/annotate.h | 13 +++-- 3 files changed, 127 insertions(+), 96 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 9b77a016e299..2b18c462b882 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -71,38 +71,20 @@ static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, b return HE_COLORSET_NORMAL; } -static int ui_browser__set_jumps_percent_color(struct ui_browser *browser, int nr, bool current) +static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current) { int color = ui_browser__jumps_percent_color(browser, nr, current); return ui_browser__set_color(browser, color); } -static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser, - char *bf, size_t size) +static int annotate_browser__set_color(void *browser, int color) { - struct annotation *notes = browser__annotation(browser); - - if (dl->ins.ops && dl->ins.ops->scnprintf) { - if (ins__is_jump(&dl->ins)) { - bool fwd = dl->ops.target.offset > dl->al.offset; - - ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR : - SLSMG_UARROW_CHAR); - SLsmg_write_char(' '); - } else if (ins__is_call(&dl->ins)) { - ui_browser__write_graph(browser, SLSMG_RARROW_CHAR); - SLsmg_write_char(' '); - } else if (ins__is_ret(&dl->ins)) { - ui_browser__write_graph(browser, SLSMG_LARROW_CHAR); - SLsmg_write_char(' '); - } else { - ui_browser__write_nstring(browser, " ", 2); - } - } else { - ui_browser__write_nstring(browser, " ", 2); - } + return ui_browser__set_color(browser, color); +} - disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset); +static void annotate_browser__write_graph(void *browser, int graph) +{ + ui_browser__write_graph(browser, graph); } static void annotate_browser__set_percent_color(void *browser, double percent, bool current) @@ -128,68 +110,19 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int bool change_color = (!notes->options->hide_src_code && (!current_entry || (browser->use_navkeypressed && !browser->navkeypressed))); - int width = browser->width, printed; - int pcnt_width = annotation__pcnt_width(notes), - cycles_width = annotation__cycles_width(notes); - char bf[256]; - - annotation_line__print_start(al, notes, row == 0, current_entry, browser, - annotate_browser__set_percent_color, - annotate_browser__printf); + int width = browser->width; /* The scroll bar isn't being used */ if (!browser->navkeypressed) width += 1; - if (!*al->line) - ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width); - else if (al->offset == -1) { - if (al->line_nr && notes->options->show_linenr) - printed = scnprintf(bf, sizeof(bf), "%-*d ", notes->widths.addr + 1, al->line_nr); - else - printed = scnprintf(bf, sizeof(bf), "%*s ", notes->widths.addr, " "); - ui_browser__write_nstring(browser, bf, printed); - ui_browser__write_nstring(browser, al->line, width - printed - pcnt_width - cycles_width + 1); - } else { - u64 addr = al->offset; - int color = -1; - - if (!notes->options->use_offset) - addr += notes->start; - - if (!notes->options->use_offset) { - printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); - } else { - if (al->jump_sources) { - if (notes->options->show_nr_jumps) { - int prev; - printed = scnprintf(bf, sizeof(bf), "%*d ", - notes->widths.jumps, - al->jump_sources); - prev = ui_browser__set_jumps_percent_color(browser, al->jump_sources, - current_entry); - ui_browser__write_nstring(browser, bf, printed); - ui_browser__set_color(browser, prev); - } - - printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", - notes->widths.target, addr); - } else { - printed = scnprintf(bf, sizeof(bf), "%*s ", - notes->widths.addr, " "); - } - } - - if (change_color) - color = ui_browser__set_color(browser, HE_COLORSET_ADDR); - ui_browser__write_nstring(browser, bf, printed); - if (change_color) - ui_browser__set_color(browser, color); - - disasm_line__write(disasm_line(al), browser, bf, sizeof(bf)); - - ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed); - } + annotation_line__write(al, notes, row == 0, current_entry, change_color, + width, browser, + annotate_browser__set_color, + annotate_browser__set_percent_color, + ui_browser__set_jumps_percent_color, + annotate_browser__printf, + annotate_browser__write_graph); if (current_entry) ab->selection = al; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 046feda11052..45a52e2658c8 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -27,6 +27,18 @@ #include #include +/* FIXME: For the HE_COLORSET */ +#include "ui/browser.h" + +/* + * FIXME: Using the same values as slang.h, + * but that header may not be available everywhere + */ +#define LARROW_CHAR 0x1B +#define RARROW_CHAR 0x1A +#define DARROW_CHAR 0x19 +#define UARROW_CHAR 0x18 + #include "sane_ctype.h" const char *disassembler_style; @@ -2204,14 +2216,48 @@ static void set_percent_color_stub(void *obj __maybe_unused, { } -void annotation_line__print_start(struct annotation_line *al, struct annotation *notes, - bool first_line, bool current_entry, - void *obj, - void (*obj__set_percent_color)(void *obj, double percent, bool current), - void (*obj__printf)(void *obj, const char *fmt, ...)) +static void disasm_line__write(struct disasm_line *dl, struct annotation *notes, + void *obj, char *bf, size_t size, + void (*obj__printf)(void *obj, const char *fmt, ...), + void (*obj__write_graph)(void *obj, int graph)) +{ + if (dl->ins.ops && dl->ins.ops->scnprintf) { + if (ins__is_jump(&dl->ins)) { + bool fwd = dl->ops.target.offset > dl->al.offset; + + obj__write_graph(obj, fwd ? DARROW_CHAR : UARROW_CHAR); + obj__printf(obj, " "); + } else if (ins__is_call(&dl->ins)) { + obj__write_graph(obj, RARROW_CHAR); + obj__printf(obj, " "); + } else if (ins__is_ret(&dl->ins)) { + obj__write_graph(obj, LARROW_CHAR); + obj__printf(obj, " "); + } else { + obj__printf(obj, " "); + } + } else { + obj__printf(obj, " "); + } + + disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset); +} + +void annotation_line__write(struct annotation_line *al, struct annotation *notes, + bool first_line, bool current_entry, bool change_color, int width, + void *obj, + int (*obj__set_color)(void *obj, int color), + void (*obj__set_percent_color)(void *obj, double percent, bool current), + int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), + void (*obj__printf)(void *obj, const char *fmt, ...), + void (*obj__write_graph)(void *obj, int graph)) { double percent_max = annotation_line__max_percent(al, notes); + int pcnt_width = annotation__pcnt_width(notes), + cycles_width = annotation__cycles_width(notes); bool show_title = false; + char bf[256]; + int printed; if (first_line && (al->offset == -1 || percent_max == 0.0)) { if (notes->have_cycles) { @@ -2240,14 +2286,12 @@ void annotation_line__print_start(struct annotation_line *al, struct annotation } } } else { - int pcnt_width = annotation__pcnt_width(notes); - obj__set_percent_color(obj, 0, current_entry); if (!show_title) - obj__printf(obj, "%*s", pcnt_width, " "); + obj__printf(obj, "%-*s", pcnt_width, " "); else { - obj__printf(obj, "%*s", pcnt_width, + obj__printf(obj, "%-*s", pcnt_width, notes->options->show_total_period ? "Period" : notes->options->show_nr_samples ? "Samples" : "Percent"); } @@ -2271,6 +2315,57 @@ void annotation_line__print_start(struct annotation_line *al, struct annotation } obj__printf(obj, " "); + + if (!*al->line) + obj__printf(obj, "%-*s", width - pcnt_width - cycles_width, " "); + else if (al->offset == -1) { + if (al->line_nr && notes->options->show_linenr) + printed = scnprintf(bf, sizeof(bf), "%-*d ", notes->widths.addr + 1, al->line_nr); + else + printed = scnprintf(bf, sizeof(bf), "%-*s ", notes->widths.addr, " "); + obj__printf(obj, bf); + obj__printf(obj, "%-*s", width - printed - pcnt_width - cycles_width + 1, al->line); + } else { + u64 addr = al->offset; + int color = -1; + + if (!notes->options->use_offset) + addr += notes->start; + + if (!notes->options->use_offset) { + printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); + } else { + if (al->jump_sources) { + if (notes->options->show_nr_jumps) { + int prev; + printed = scnprintf(bf, sizeof(bf), "%*d ", + notes->widths.jumps, + al->jump_sources); + prev = obj__set_jumps_percent_color(obj, al->jump_sources, + current_entry); + obj__printf(obj, bf); + obj__set_color(obj, prev); + } + + printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", + notes->widths.target, addr); + } else { + printed = scnprintf(bf, sizeof(bf), "%-*s ", + notes->widths.addr, " "); + } + } + + if (change_color) + color = obj__set_color(obj, HE_COLORSET_ADDR); + obj__printf(obj, bf); + if (change_color) + obj__set_color(obj, color); + + disasm_line__write(disasm_line(al), notes, obj, bf, sizeof(bf), obj__printf, obj__write_graph); + + obj__printf(obj, "%-*s", width - pcnt_width - cycles_width - 3 - printed, bf); + } + } int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 84c99774bfed..27fcdacbb497 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -126,11 +126,14 @@ struct annotation_line * annotation_line__next(struct annotation_line *pos, struct list_head *head); double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes); -void annotation_line__print_start(struct annotation_line *al, struct annotation *notes, - bool first_line, bool current_entry, - void *obj, - void (*obj__set_percent_color)(void *obj, double percent, bool current), - void (*obj__printf)(void *obj, const char *fmt, ...)); +void annotation_line__write(struct annotation_line *al, struct annotation *notes, + bool first_line, bool current_entry, bool change_color, int width, + void *obj, + int (*obj__set_color)(void *obj, int color), + void (*obj__set_percent_color)(void *obj, double percent, bool current), + int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), + void (*obj__printf)(void *obj, const char *fmt, ...), + void (*obj__write_graph)(void *obj, int graph)); int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); size_t disasm__fprintf(struct list_head *head, FILE *fp); -- cgit v1.2.3 From c298304bd747d6a0b733f0becb470ff07ead0317 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 23:14:51 -0300 Subject: perf annotate: Use a ops table for annotation_line__write() To simplify the passing of arguments, the --stdio2 code will have to set all the fields with operations printing to stdout. Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-pcs3c7vdy9ucygxflo4nl1o7@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 32 +++++++++++++++------------- tools/perf/util/annotate.c | 44 ++++++++++++++++++++------------------- tools/perf/util/annotate.h | 19 ++++++++++------- 3 files changed, 53 insertions(+), 42 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 2b18c462b882..bed647807d37 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -106,25 +106,29 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); struct annotation *notes = browser__annotation(browser); struct annotation_line *al = list_entry(entry, struct annotation_line, node); - bool current_entry = ui_browser__is_current_entry(browser, row); - bool change_color = (!notes->options->hide_src_code && - (!current_entry || (browser->use_navkeypressed && - !browser->navkeypressed))); - int width = browser->width; + struct annotation_write_ops ops = { + .first_line = row == 0, + .current_entry = ui_browser__is_current_entry(browser, row), + .change_color = (!notes->options->hide_src_code && + (!ops.current_entry || + (browser->use_navkeypressed && + !browser->navkeypressed))), + .width = browser->width, + .obj = browser, + .set_color = annotate_browser__set_color, + .set_percent_color = annotate_browser__set_percent_color, + .set_jumps_percent_color = ui_browser__set_jumps_percent_color, + .printf = annotate_browser__printf, + .write_graph = annotate_browser__write_graph, + }; /* The scroll bar isn't being used */ if (!browser->navkeypressed) - width += 1; + ops.width += 1; - annotation_line__write(al, notes, row == 0, current_entry, change_color, - width, browser, - annotate_browser__set_color, - annotate_browser__set_percent_color, - ui_browser__set_jumps_percent_color, - annotate_browser__printf, - annotate_browser__write_graph); + annotation_line__write(al, notes, &ops); - if (current_entry) + if (ops.current_entry) ab->selection = al; } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 45a52e2658c8..11ad73211538 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -34,10 +34,10 @@ * FIXME: Using the same values as slang.h, * but that header may not be available everywhere */ -#define LARROW_CHAR 0x1B -#define RARROW_CHAR 0x1A -#define DARROW_CHAR 0x19 -#define UARROW_CHAR 0x18 +#define LARROW_CHAR ((unsigned char)',') +#define RARROW_CHAR ((unsigned char)'+') +#define DARROW_CHAR ((unsigned char)'.') +#define UARROW_CHAR ((unsigned char)'-') #include "sane_ctype.h" @@ -2210,12 +2210,6 @@ double annotation_line__max_percent(struct annotation_line *al, struct annotatio return percent_max; } -static void set_percent_color_stub(void *obj __maybe_unused, - double percent __maybe_unused, - bool current __maybe_unused) -{ -} - static void disasm_line__write(struct disasm_line *dl, struct annotation *notes, void *obj, char *bf, size_t size, void (*obj__printf)(void *obj, const char *fmt, ...), @@ -2243,14 +2237,15 @@ static void disasm_line__write(struct disasm_line *dl, struct annotation *notes, disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset); } -void annotation_line__write(struct annotation_line *al, struct annotation *notes, - bool first_line, bool current_entry, bool change_color, int width, - void *obj, - int (*obj__set_color)(void *obj, int color), - void (*obj__set_percent_color)(void *obj, double percent, bool current), - int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), - void (*obj__printf)(void *obj, const char *fmt, ...), - void (*obj__write_graph)(void *obj, int graph)) +static void __annotation_line__write(struct annotation_line *al, struct annotation *notes, + bool first_line, bool current_entry, bool change_color, int width, + void *obj, + int (*obj__set_color)(void *obj, int color), + void (*obj__set_percent_color)(void *obj, double percent, bool current), + int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), + void (*obj__printf)(void *obj, const char *fmt, ...), + void (*obj__write_graph)(void *obj, int graph)) + { double percent_max = annotation_line__max_percent(al, notes); int pcnt_width = annotation__pcnt_width(notes), @@ -2267,9 +2262,6 @@ void annotation_line__write(struct annotation_line *al, struct annotation *notes show_title = true; } - if (!obj__set_percent_color) - obj__set_percent_color = set_percent_color_stub; - if (al->offset != -1 && percent_max != 0.0) { int i; @@ -2368,6 +2360,16 @@ void annotation_line__write(struct annotation_line *al, struct annotation *notes } +void annotation_line__write(struct annotation_line *al, struct annotation *notes, + struct annotation_write_ops *ops) +{ + __annotation_line__write(al, notes, ops->first_line, ops->current_entry, + ops->change_color, ops->width, ops->obj, + ops->set_color, ops->set_percent_color, + ops->set_jumps_percent_color, ops->printf, + ops->write_graph); +} + int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, struct annotation_options *options, struct arch **parch) { diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 27fcdacbb497..6fbb34b9bd77 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -125,15 +125,20 @@ void disasm_line__free(struct disasm_line *dl); struct annotation_line * annotation_line__next(struct annotation_line *pos, struct list_head *head); +struct annotation_write_ops { + bool first_line, current_entry, change_color; + int width; + void *obj; + int (*set_color)(void *obj, int color); + void (*set_percent_color)(void *obj, double percent, bool current); + int (*set_jumps_percent_color)(void *obj, int nr, bool current); + void (*printf)(void *obj, const char *fmt, ...); + void (*write_graph)(void *obj, int graph); +}; + double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes); void annotation_line__write(struct annotation_line *al, struct annotation *notes, - bool first_line, bool current_entry, bool change_color, int width, - void *obj, - int (*obj__set_color)(void *obj, int color), - void (*obj__set_percent_color)(void *obj, double percent, bool current), - int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), - void (*obj__printf)(void *obj, const char *fmt, ...), - void (*obj__write_graph)(void *obj, int graph)); + struct annotation_write_ops *ops); int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); size_t disasm__fprintf(struct list_head *head, FILE *fp); -- cgit v1.2.3 From befd2a38a632b1f27ad652fea67c8cf97ce59409 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 23:44:34 -0300 Subject: perf annotate: Introduce the --stdio2 output mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This uses the TUI augmented formatting routines, modulo interactivity. # perf annotate --ignore-vmlinux --stdio2 _raw_spin_lock_irqsave _raw_spin_lock_irqsave() /proc/kcore Event: cycles:ppp Percent Disassembly of section load0: ffffffff9a8734b0 : nop push %rbx 50.00 pushfq pop %rax nop mov %rax,%rbx cli nop xor %eax,%eax mov $0x1,%edx 50.00 lock cmpxchg %edx,(%rdi) test %eax,%eax ↓ jne 2b mov %rbx,%rax pop %rbx ← retq 2b: mov %eax,%esi → callq queued_spin_lock_slowpath mov %rbx,%rax pop %rbx ← retq Tested-by: Jin Yao Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-6cte5o8z84mbivbvqlg14uh1@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-annotate.txt | 2 + tools/perf/builtin-annotate.c | 23 +++++--- tools/perf/util/annotate.c | 92 ++++++++++++++++++++++++++++++ tools/perf/util/annotate.h | 5 ++ 4 files changed, 115 insertions(+), 7 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index 292809c3c0ca..c29c7fc93023 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt @@ -69,6 +69,8 @@ OPTIONS --stdio:: Use the stdio interface. +--stdio2:: Use the stdio2 interface, non-interactive, uses the TUI formatting. + --stdio-color=:: 'always', 'never' or 'auto', allowing configuring color output via the command line, in addition to via "color.ui" .perfconfig. diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index ead6ae4549e5..e03f9bea9303 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -40,7 +40,7 @@ struct perf_annotate { struct perf_tool tool; struct perf_session *session; - bool use_tui, use_stdio, use_gtk; + bool use_tui, use_stdio, use_stdio2, use_gtk; bool full_paths; bool print_line; bool skip_missing; @@ -202,6 +202,11 @@ static int process_branch_callback(struct perf_evsel *evsel, return ret; } +static bool has_annotation(struct perf_annotate *ann) +{ + return ui__has_annotation() || ann->use_stdio2; +} + static int perf_evsel__add_sample(struct perf_evsel *evsel, struct perf_sample *sample, struct addr_location *al, @@ -212,7 +217,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, struct hist_entry *he; int ret; - if ((!ann->has_br_stack || !ui__has_annotation()) && + if ((!ann->has_br_stack || !has_annotation(ann)) && ann->sym_hist_filter != NULL && (al->sym == NULL || strcmp(ann->sym_hist_filter, al->sym->name) != 0)) { @@ -236,7 +241,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, */ process_branch_stack(sample->branch_stack, al, sample); - if (ann->has_br_stack && ui__has_annotation()) + if (ann->has_br_stack && has_annotation(ann)) return process_branch_callback(evsel, sample, al, ann, machine); he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); @@ -282,8 +287,11 @@ static int hist_entry__tty_annotate(struct hist_entry *he, struct perf_evsel *evsel, struct perf_annotate *ann) { - return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, - ann->print_line, ann->full_paths, 0, 0); + if (!ann->use_stdio2) + return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, + ann->print_line, ann->full_paths, 0, 0); + return symbol__tty_annotate2(he->ms.sym, he->ms.map, evsel, + ann->print_line, ann->full_paths); } static void hists__find_annotations(struct hists *hists, @@ -487,6 +495,7 @@ int cmd_annotate(int argc, const char **argv) OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"), OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"), + OPT_BOOLEAN(0, "stdio2", &annotate.use_stdio2, "Use the stdio interface"), OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, @@ -569,7 +578,7 @@ int cmd_annotate(int argc, const char **argv) if (ret < 0) goto out_delete; - if (annotate.use_stdio) + if (annotate.use_stdio || annotate.use_stdio2) use_browser = 0; else if (annotate.use_tui) use_browser = 1; @@ -578,7 +587,7 @@ int cmd_annotate(int argc, const char **argv) setup_browser(true); - if (use_browser == 1 && annotate.has_br_stack) { + if ((use_browser == 1 || annotate.use_stdio2) && annotate.has_br_stack) { sort__mode = SORT_MODE__BRANCH; if (setup_sorting(annotate.session->evlist) < 0) usage_with_options(annotate_usage, options); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 11ad73211538..98cf3e5380bc 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1965,6 +1965,72 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, return more; } +static void FILE__set_percent_color(void *fp __maybe_unused, + double percent __maybe_unused, + bool current __maybe_unused) +{ +} + +static int FILE__set_jumps_percent_color(void *fp __maybe_unused, + int nr __maybe_unused, bool current __maybe_unused) +{ + return 0; +} + +static int FILE__set_color(void *fp __maybe_unused, int color __maybe_unused) +{ + return 0; +} + +static void FILE__printf(void *fp, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vfprintf(fp, fmt, args); + va_end(args); +} + +static void FILE__write_graph(void *fp, int graph) +{ + const char *s; + switch (graph) { + + case DARROW_CHAR: s = "↓"; break; + case UARROW_CHAR: s = "↑"; break; + case LARROW_CHAR: s = "←"; break; + case RARROW_CHAR: s = "→"; break; + default: s = "?"; break; + } + + fputs(s, fp); +} + +int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) +{ + struct annotation *notes = symbol__annotation(sym); + struct annotation_write_ops ops = { + .first_line = true, + .obj = fp, + .set_color = FILE__set_color, + .set_percent_color = FILE__set_percent_color, + .set_jumps_percent_color = FILE__set_jumps_percent_color, + .printf = FILE__printf, + .write_graph = FILE__write_graph, + }; + struct annotation_line *al; + + list_for_each_entry(al, ¬es->src->source, node) { + if (annotation_line__filter(al, notes)) + continue; + annotation_line__write(al, notes, &ops); + fputc('\n', fp); + ops.first_line = false; + } + + return 0; +} + void symbol__annotate_zero_histogram(struct symbol *sym, int evidx) { struct annotation *notes = symbol__annotation(sym); @@ -2165,6 +2231,32 @@ static void symbol__calc_lines(struct symbol *sym, struct map *map, annotation__calc_lines(notes, map, root, start); } +int symbol__tty_annotate2(struct symbol *sym, struct map *map, + struct perf_evsel *evsel, bool print_lines, + bool full_paths) +{ + struct dso *dso = map->dso; + struct rb_root source_line = RB_ROOT; + struct annotation_options opts = { + .use_offset = true, + }; + + if (symbol__annotate2(sym, map, evsel, &opts, NULL) < 0) + return -1; + + if (print_lines) { + srcline_full_filename = full_paths; + symbol__calc_lines(sym, map, &source_line); + print_summary(&source_line, dso->long_name); + } + + symbol__annotate_fprintf2(sym, stdout); + + annotated_source__purge(symbol__annotation(sym)->src); + + return 0; +} + int symbol__tty_annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, 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 165845de1243..cf32cbc87930 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -281,6 +281,7 @@ int symbol__strerror_disassemble(struct symbol *sym, struct map *map, int symbol__annotate_printf(struct symbol *sym, struct map *map, struct perf_evsel *evsel, bool full_paths, int min_pcnt, int max_lines, int context); +int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp); void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); void annotated_source__purge(struct annotated_source *as); @@ -291,6 +292,10 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, bool print_lines, bool full_paths, int min_pcnt, int max_lines); +int symbol__tty_annotate2(struct symbol *sym, struct map *map, + struct perf_evsel *evsel, bool print_lines, + bool full_paths); + #ifdef HAVE_SLANG_SUPPORT int symbol__tui_annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, -- cgit v1.2.3 From 7f0b6fde3111aec82487662ccef5a4ebecb93381 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Mar 2018 14:33:38 -0300 Subject: perf annotate: Move the default annotate options to the library One more thing that goes from the TUI code to be used more widely, for instance it'll affect the default options used by: perf annotate --stdio2 Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-0nsz0dm0akdbo30vgja2a10e@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 2 ++ tools/perf/builtin-report.c | 1 + tools/perf/builtin-top.c | 2 ++ tools/perf/ui/browser.c | 2 -- tools/perf/ui/browser.h | 1 - tools/perf/ui/browsers/annotate.c | 67 +-------------------------------------- tools/perf/util/annotate.c | 62 ++++++++++++++++++++++++++++++++++++ tools/perf/util/annotate.h | 4 +++ 8 files changed, 72 insertions(+), 69 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index e03f9bea9303..fd5aac3fd949 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -572,6 +572,8 @@ int cmd_annotate(int argc, const char **argv) if (ret < 0) goto out_delete; + annotation_config__init(); + symbol_conf.try_vmlinux_path = true; ret = symbol__init(&annotate.session->header.env); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 91da12975642..1a82f38671a8 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -1340,6 +1340,7 @@ repeat: symbol_conf.priv_size += sizeof(u32); symbol_conf.sort_by_name = true; } + annotation_config__init(); } if (symbol__init(&session->header.env) < 0) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 113c298ed38b..f39bd60d2708 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1493,6 +1493,8 @@ int cmd_top(int argc, const char **argv) if (status < 0) goto out_delete_evlist; + annotation_config__init(); + symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); if (symbol__init(NULL) < 0) return -1; diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index 33c30325885f..9f6ce29b83b4 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c @@ -784,6 +784,4 @@ void ui_browser__init(void) struct ui_browser_colorset *c = &ui_browser__colorsets[i++]; sltt_set_color(c->colorset, c->name, c->fg, c->bg); } - - annotate_browser__init(); } diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h index 9e69c6a43514..70057178ee34 100644 --- a/tools/perf/ui/browser.h +++ b/tools/perf/ui/browser.h @@ -79,5 +79,4 @@ void ui_browser__list_head_seek(struct ui_browser *browser, off_t offset, int wh unsigned int ui_browser__list_head_refresh(struct ui_browser *browser); void ui_browser__init(void); -void annotate_browser__init(void); #endif /* _PERF_UI_BROWSER_H_ */ diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 74a26f4e9b06..916f237c1df8 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -9,7 +9,6 @@ #include "../../util/sort.h" #include "../../util/symbol.h" #include "../../util/evsel.h" -#include "../../util/config.h" #include "../../util/evlist.h" #include #include @@ -22,11 +21,6 @@ struct disasm_line_samples { struct sym_hist_entry he; }; -static struct annotation_options annotate_browser__opts = { - .use_offset = true, - .jump_arrows = true, -}; - struct arch; struct annotate_browser { @@ -773,12 +767,6 @@ out: int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, struct hist_browser_timer *hbt) { - /* Set default value for show_total_period and show_nr_samples */ - annotate_browser__opts.show_total_period = - symbol_conf.show_total_period; - annotate_browser__opts.show_nr_samples = - symbol_conf.show_nr_samples; - return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt); } @@ -819,7 +807,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, if (map->dso->annotate_warned) return -1; - err = symbol__annotate2(sym, map, evsel, &annotate_browser__opts, &browser.arch); + err = symbol__annotate2(sym, map, evsel, &annotation__default_options, &browser.arch); if (err) { char msg[BUFSIZ]; symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); @@ -845,56 +833,3 @@ out_free_offsets: zfree(¬es->offsets); return ret; } - -#define ANNOTATE_CFG(n) \ - { .name = #n, .value = &annotate_browser__opts.n, } - -/* - * Keep the entries sorted, they are bsearch'ed - */ -static struct annotate_config { - const char *name; - bool *value; -} annotate__configs[] = { - ANNOTATE_CFG(hide_src_code), - ANNOTATE_CFG(jump_arrows), - ANNOTATE_CFG(show_linenr), - ANNOTATE_CFG(show_nr_jumps), - ANNOTATE_CFG(show_nr_samples), - ANNOTATE_CFG(show_total_period), - ANNOTATE_CFG(use_offset), -}; - -#undef ANNOTATE_CFG - -static int annotate_config__cmp(const void *name, const void *cfgp) -{ - const struct annotate_config *cfg = cfgp; - - return strcmp(name, cfg->name); -} - -static int annotate__config(const char *var, const char *value, - void *data __maybe_unused) -{ - struct annotate_config *cfg; - const char *name; - - if (!strstarts(var, "annotate.")) - return 0; - - name = var + 9; - cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs), - sizeof(struct annotate_config), annotate_config__cmp); - - if (cfg == NULL) - ui__warning("%s variable unknown, ignoring...", var); - else - *cfg->value = perf_config_bool(name, value); - return 0; -} - -void annotate_browser__init(void) -{ - perf_config(annotate__config, NULL); -} diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 98cf3e5380bc..cfa641bc1df6 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -14,6 +14,7 @@ #include "sort.h" #include "build-id.h" #include "color.h" +#include "config.h" #include "cache.h" #include "symbol.h" #include "debug.h" @@ -41,6 +42,11 @@ #include "sane_ctype.h" +struct annotation_options annotation__default_options = { + .use_offset = true, + .jump_arrows = true, +}; + const char *disassembler_style; const char *objdump_path; static regex_t file_lineno; @@ -2500,3 +2506,59 @@ out_free_offsets: zfree(¬es->offsets); return -1; } + +#define ANNOTATION__CFG(n) \ + { .name = #n, .value = &annotation__default_options.n, } + +/* + * Keep the entries sorted, they are bsearch'ed + */ +static struct annotation_config { + const char *name; + bool *value; +} annotation__configs[] = { + ANNOTATION__CFG(hide_src_code), + ANNOTATION__CFG(jump_arrows), + ANNOTATION__CFG(show_linenr), + ANNOTATION__CFG(show_nr_jumps), + ANNOTATION__CFG(show_nr_samples), + ANNOTATION__CFG(show_total_period), + ANNOTATION__CFG(use_offset), +}; + +#undef ANNOTATION__CFG + +static int annotation_config__cmp(const void *name, const void *cfgp) +{ + const struct annotation_config *cfg = cfgp; + + return strcmp(name, cfg->name); +} + +static int annotation__config(const char *var, const char *value, + void *data __maybe_unused) +{ + struct annotation_config *cfg; + const char *name; + + if (!strstarts(var, "annotate.")) + return 0; + + name = var + 9; + cfg = bsearch(name, annotation__configs, ARRAY_SIZE(annotation__configs), + sizeof(struct annotation_config), annotation_config__cmp); + + if (cfg == NULL) + pr_debug("%s variable unknown, ignoring...", var); + else + *cfg->value = perf_config_bool(name, value); + return 0; +} + +void annotation_config__init(void) +{ + perf_config(annotation__config, NULL); + + annotation__default_options.show_total_period = symbol_conf.show_total_period; + annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples; +} diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index cf32cbc87930..3faa58045b22 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -71,6 +71,8 @@ struct annotation_options { show_total_period; }; +extern struct annotation_options annotation__default_options; + struct annotation; struct sym_hist_entry { @@ -313,4 +315,6 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, extern const char *disassembler_style; +void annotation_config__init(void); + #endif /* __PERF_ANNOTATE_H */ -- cgit v1.2.3 From 3563289208ecef339853692ecbf8690084744b53 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Mar 2018 14:37:33 -0300 Subject: perf annotate: Use the default annotation options for --stdio2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With an empty '[annotate]' section in ~/.perfconfig: # perf record -a --all-kernel -e '{cycles,instructions}:P' sleep 5 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 2.243 MB perf.data (5513 samples) ] # perf annotate --stdio2 _raw_spin_lock | head -20 Disassembly of section .text: ffffffff81868790 <_raw_spin_lock>: _raw_spin_lock(): EXPORT_SYMBOL(_raw_spin_trylock_bh); #endif #ifndef CONFIG_INLINE_SPIN_LOCK void __lockfunc _raw_spin_lock(raw_spinlock_t *lock) { → callq __fentry__ atomic_cmpxchg(): return xadd(&v->counter, -i); } static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) { # perf annotate --stdio2 _raw_spin_lock | head -20 → callq __fentry__ xor %eax,%eax mov $0x1,%edx 87.50 100.00 lock cmpxchg %edx,(%rdi) 6.25 0.00 test %eax,%eax ↓ jne 16 6.25 0.00 repz retq 16: mov %eax,%esi ↑ jmpq ffffffff810e96b0 # # cat ~/.perfconfig [annotate] hide_src_code = false show_linenr = true # perf annotate --stdio2 _raw_spin_lock | head -20 3 Disassembly of section .text: 5 ffffffff81868790 <_raw_spin_lock>: 6 _raw_spin_lock(): 143 EXPORT_SYMBOL(_raw_spin_trylock_bh); 144 #endif 146 #ifndef CONFIG_INLINE_SPIN_LOCK 147 void __lockfunc _raw_spin_lock(raw_spinlock_t *lock) 148 { → callq __fentry__ 150 atomic_cmpxchg(): 187 return xadd(&v->counter, -i); 188 } 190 static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) 191 { # # cat ~/.perfconfig [annotate] hide_src_code = true show_total_period = true # perf annotate --stdio2 _raw_spin_lock | head -20 → callq __fentry__ xor %eax,%eax mov $0x1,%edx 1411316 152339 lock cmpxchg %edx,(%rdi) 344694 0 test %eax,%eax ↓ jne 16 80806 0 repz retq 16: mov %eax,%esi ↑ jmpq ffffffff810e96b0 # Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-nu4rxg5zkdtgs1b2gc40p7v7@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index cfa641bc1df6..ea83b9754ab0 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2243,9 +2243,7 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, { struct dso *dso = map->dso; struct rb_root source_line = RB_ROOT; - struct annotation_options opts = { - .use_offset = true, - }; + struct annotation_options opts = annotation__default_options; if (symbol__annotate2(sym, map, evsel, &opts, NULL) < 0) return -1; -- cgit v1.2.3 From 864298f224f20fb7b981b05dd0f77315c75eb189 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Mar 2018 15:17:23 -0300 Subject: perf annotate: Add function header to --stdio2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # perf annotate --stdio2 _raw_spin_lock_irqsave _raw_spin_lock_irqsave() /lib/modules/4.16.0-rc4/build/vmlinux Event: anon group { cycles, instructions } 0.00 3.17 → callq __fentry__ 0.00 7.94 push %rbx 7.69 36.51 → callq __page_file_index mov %rax,%rbx 7.69 3.17 → callq *ffffffff82225cd0 xor %eax,%eax mov $0x1,%edx 80.77 49.21 lock cmpxchg %edx,(%rdi) test %eax,%eax ↓ jne 2b 3.85 0.00 mov %rbx,%rax pop %rbx ← retq 2b: mov %eax,%esi → callq queued_spin_lock_slowpath mov %rbx,%rax pop %rbx ← retq # Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-i86yfyzl8m194ioxgj1jo32f@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ea83b9754ab0..7a6a85f9fea6 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2244,6 +2244,8 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, struct dso *dso = map->dso; struct rb_root source_line = RB_ROOT; struct annotation_options opts = annotation__default_options; + const char *ev_name = perf_evsel__name(evsel); + char buf[1024]; if (symbol__annotate2(sym, map, evsel, &opts, NULL) < 0) return -1; @@ -2254,6 +2256,12 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, print_summary(&source_line, dso->long_name); } + if (perf_evsel__is_group_event(evsel)) { + perf_evsel__group_desc(evsel, buf, sizeof(buf)); + ev_name = buf; + } + + fprintf(stdout, "%s() %s\nEvent: %s\n\n", sym->name, dso->long_name, ev_name); symbol__annotate_fprintf2(sym, stdout); annotated_source__purge(symbol__annotation(sym)->src); -- cgit v1.2.3 From d9bd766584491dbb6f96c85a27562eb1289b2ca9 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Mar 2018 16:57:47 -0300 Subject: perf annotate browser: Add 'P' hotkey to dump annotation to file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just like we have in the histograms browser used as the main screen for 'perf top --tui' and 'perf report --tui', to print the current annotation to a file with a named composed by the symbol name and the ".annotation" suffix. Here is one example of pressing 'A' on 'perf top' to live annotate a kernel function and then press 'P' to dump that annotation, the resulting file: # cat _raw_spin_lock_irqsave.annotation _raw_spin_lock_irqsave() /proc/kcore Event: cycles:ppp 7.14 nop 21.43 push %rbx 7.14 pushfq pop %rax nop mov %rax,%rbx cli nop xor %eax,%eax mov $0x1,%edx 64.29 lock cmpxchg %edx,(%rdi) test %eax,%eax ↓ jne 2b mov %rbx,%rax pop %rbx ← retq 2b: mov %eax,%esi → callq queued_spin_lock_slowpath mov %rbx,%rax pop %rbx ← retq # Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-zzmnrwugb5vtk7bvg0rbx150@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 4 ++++ tools/perf/util/annotate.c | 31 +++++++++++++++++++++++++++++++ tools/perf/util/annotate.h | 2 ++ 3 files changed, 37 insertions(+) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 916f237c1df8..3834b264ba41 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -661,6 +661,7 @@ static int annotate_browser__run(struct annotate_browser *browser, "t Circulate percent, total period, samples view\n" "/ Search string\n" "k Toggle line numbers\n" + "P Print to [symbol_name].annotation file.\n" "r Run available scripts\n" "? Search string backwards\n"); continue; @@ -737,6 +738,9 @@ show_sup_ins: } continue; } + case 'P': + map_symbol__annotation_dump(ms, evsel); + continue; case 't': if (notes->options->show_total_period) { notes->options->show_total_period = false; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 7a6a85f9fea6..a7111871440e 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2037,6 +2037,37 @@ int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) return 0; } +int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel) +{ + const char *ev_name = perf_evsel__name(evsel); + char buf[1024]; + char *filename; + int err = -1; + FILE *fp; + + if (asprintf(&filename, "%s.annotation", ms->sym->name) < 0) + return -1; + + fp = fopen(filename, "w"); + if (fp == NULL) + goto out_free_filename; + + if (perf_evsel__is_group_event(evsel)) { + perf_evsel__group_desc(evsel, buf, sizeof(buf)); + ev_name = buf; + } + + fprintf(fp, "%s() %s\nEvent: %s\n\n", + ms->sym->name, ms->map->dso->long_name, ev_name); + symbol__annotate_fprintf2(ms->sym, fp); + + fclose(fp); + err = 0; +out_free_filename: + free(filename); + return err; +} + void symbol__annotate_zero_histogram(struct symbol *sym, int evidx) { struct annotation *notes = symbol__annotation(sym); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 3faa58045b22..365e9df888cf 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -288,6 +288,8 @@ void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); void annotated_source__purge(struct annotated_source *as); +int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel); + bool ui__has_annotation(void); int symbol__tty_annotate(struct symbol *sym, struct map *map, -- cgit v1.2.3 From 425859ff0de33a2362bec2a2c7ca486f87c13100 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 20 Mar 2018 11:03:30 -0300 Subject: perf annotate: No need to calculate notes->start twice Since we already set notes->start to map__rip_2objdump(map, sym->start) in symbol__annotate2(), no need to calculate that address again in symbol__calc_lines(), just use notes->start. Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-ycxlg8mm5ueuj21w6gi62l7g@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a7111871440e..666f62c58e1a 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2230,7 +2230,7 @@ void annotation__update_column_widths(struct annotation *notes) } static void annotation__calc_lines(struct annotation *notes, struct map *map, - struct rb_root *root, u64 start) + struct rb_root *root) { struct annotation_line *al; struct rb_root tmp_root = RB_ROOT; @@ -2251,8 +2251,8 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, if (percent_max <= 0.5) continue; - al->path = get_srcline(map->dso, start + al->offset, NULL, - false, true, start + al->offset); + al->path = get_srcline(map->dso, notes->start + al->offset, NULL, + false, true, notes->start + al->offset); insert_source_line(&tmp_root, al); } @@ -2263,9 +2263,8 @@ static void symbol__calc_lines(struct symbol *sym, struct map *map, struct rb_root *root) { struct annotation *notes = symbol__annotation(sym); - u64 start = map__rip_2objdump(map, sym->start); - annotation__calc_lines(notes, map, root, start); + annotation__calc_lines(notes, map, root); } int symbol__tty_annotate2(struct symbol *sym, struct map *map, -- cgit v1.2.3 From 85a84e4f813912ab77d872ff6882dd7b435fbf4e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 20 Mar 2018 16:19:08 -0300 Subject: perf annotate: Pass function descriptor to its instruction parsing routines We need that to figure out if jumps have targets in a different function. E.g. _cpp_lex_token(), in /usr/libexec/gcc/x86_64-redhat-linux/5.3.1/cc1 has a line like this: jne c469be Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-ris0ioziyp469pofpzix2atb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/s390/annotate/instructions.c | 5 +++-- tools/perf/util/annotate.c | 30 ++++++++++++++++------------ tools/perf/util/annotate.h | 2 +- 3 files changed, 21 insertions(+), 16 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/arch/s390/annotate/instructions.c b/tools/perf/arch/s390/annotate/instructions.c index 46c21831f2ac..cee4e2f7c057 100644 --- a/tools/perf/arch/s390/annotate/instructions.c +++ b/tools/perf/arch/s390/annotate/instructions.c @@ -2,9 +2,10 @@ #include static int s390_call__parse(struct arch *arch, struct ins_operands *ops, - struct map *map) + struct map_symbol *ms) { char *endptr, *tok, *name; + struct map *map = ms->map; struct addr_map_symbol target = { .map = map, }; @@ -54,7 +55,7 @@ static struct ins_ops s390_call_ops = { static int s390_mov__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, - struct map *map __maybe_unused) + struct map_symbol *ms __maybe_unused) { char *s = strchr(ops->raw, ','), *target, *endptr; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 666f62c58e1a..3ff829d89178 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -202,9 +202,10 @@ bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2) return arch->ins_is_fused(arch, ins1, ins2); } -static int call__parse(struct arch *arch, struct ins_operands *ops, struct map *map) +static int call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) { char *endptr, *tok, *name; + struct map *map = ms->map; struct addr_map_symbol target = { .map = map, }; @@ -272,7 +273,7 @@ bool ins__is_call(const struct ins *ins) return ins->ops == &call_ops || ins->ops == &s390_call_ops; } -static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused) +static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms __maybe_unused) { const char *s = strchr(ops->raw, '+'); const char *c = strchr(ops->raw, ','); @@ -365,7 +366,7 @@ static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) return 0; } -static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map *map) +static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) { ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); if (ops->locked.ops == NULL) @@ -380,7 +381,7 @@ static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map * goto out_free_ops; if (ops->locked.ins.ops->parse && - ops->locked.ins.ops->parse(arch, ops->locked.ops, map) < 0) + ops->locked.ins.ops->parse(arch, ops->locked.ops, ms) < 0) goto out_free_ops; return 0; @@ -423,7 +424,7 @@ static struct ins_ops lock_ops = { .scnprintf = lock__scnprintf, }; -static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map *map __maybe_unused) +static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms __maybe_unused) { char *s = strchr(ops->raw, ','), *target, *comment, prev; @@ -484,7 +485,7 @@ static struct ins_ops mov_ops = { .scnprintf = mov__scnprintf, }; -static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused) +static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms __maybe_unused) { char *target, *comment, *s, prev; @@ -923,14 +924,14 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *samp return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip, sample); } -static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map *map) +static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map_symbol *ms) { dl->ins.ops = ins__find(arch, dl->ins.name); if (!dl->ins.ops) return; - if (dl->ins.ops->parse && dl->ins.ops->parse(arch, &dl->ops, map) < 0) + if (dl->ins.ops->parse && dl->ins.ops->parse(arch, &dl->ops, ms) < 0) dl->ins.ops = NULL; } @@ -967,7 +968,7 @@ out_free_name: struct annotate_args { size_t privsize; struct arch *arch; - struct map *map; + struct map_symbol ms; struct perf_evsel *evsel; s64 offset; char *line; @@ -1049,7 +1050,7 @@ static struct disasm_line *disasm_line__new(struct annotate_args *args) if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0) goto out_free_line; - disasm_line__init_ins(dl, args->arch, args->map); + disasm_line__init_ins(dl, args->arch, &args->ms); } } @@ -1307,7 +1308,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file, struct annotate_args *args, int *line_nr) { - struct map *map = args->map; + struct map *map = args->ms.map; struct annotation *notes = symbol__annotation(sym); struct disasm_line *dl; char *line = NULL, *parsed_line, *tmp, *tmp2; @@ -1354,6 +1355,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file, args->offset = offset; args->line = parsed_line; args->line_nr = *line_nr; + args->ms.sym = sym; dl = disasm_line__new(args); free(line); @@ -1506,7 +1508,7 @@ fallback: static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) { - struct map *map = args->map; + struct map *map = args->ms.map; struct dso *dso = map->dso; char *command; FILE *file; @@ -1705,7 +1707,6 @@ int symbol__annotate(struct symbol *sym, struct map *map, { struct annotate_args args = { .privsize = privsize, - .map = map, .evsel = evsel, }; struct perf_env *env = perf_evsel__env(evsel); @@ -1731,6 +1732,9 @@ int symbol__annotate(struct symbol *sym, struct map *map, } } + args.ms.map = map; + args.ms.sym = sym; + return symbol__disassemble(sym, &args); } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 365e9df888cf..c0bf0554a9ea 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -46,7 +46,7 @@ struct arch; struct ins_ops { void (*free)(struct ins_operands *ops); - int (*parse)(struct arch *arch, struct ins_operands *ops, struct map *map); + int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms); int (*scnprintf)(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); }; -- cgit v1.2.3 From 751b1783da784299b0509adb6a9cd3024cc4f837 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 20 Mar 2018 17:20:43 -0300 Subject: perf annotate: Mark jumps to outher functions with the call arrow Things like this in _cpp_lex_token (gcc's cc1 program): cpp_named_operator2name@@Base+0xa72 Point to a place that is after the cpp_named_operator2name boundaries, i.e. in the ELF symbol table for cc1 cpp_named_operator2name is marked as being 32-bytes long, but it in fact is much larger than that, so we seem to need a symbols__find() routine that looks for >= current->start and < next_symbol->start, possibly just for C++ objects? For now lets just make some progress by marking jumps to outside the current function as call like. Actual navigation will come next, with further understanding of how the symbol searching and disassembly should be done. Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-aiys0a0bsgm3e00hbi6fg7yy@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 55 +++++++++++++++++++++++++++++++++++++++++++--- tools/perf/util/annotate.h | 1 + 2 files changed, 53 insertions(+), 3 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 3ff829d89178..c299881c640a 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -273,11 +273,27 @@ bool ins__is_call(const struct ins *ins) return ins->ops == &call_ops || ins->ops == &s390_call_ops; } -static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms __maybe_unused) +static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms) { + struct map *map = ms->map; + struct symbol *sym = ms->sym; + struct addr_map_symbol target = { + .map = map, + }; const char *s = strchr(ops->raw, '+'); const char *c = strchr(ops->raw, ','); - + u64 start, end; + /* + * Examples of lines to parse for the _cpp_lex_token@@Base + * function: + * + * 1159e6c: jne 115aa32 <_cpp_lex_token@@Base+0xf92> + * 1159e8b: jne c469be + * + * The first is a jump to an offset inside the same function, + * the second is to another function, i.e. that 0xa72 is an + * offset in the cpp_named_operator2name@@base function. + */ /* * skip over possible up to 2 operands to get to address, e.g.: * tbnz w0, #26, ffff0000083cd190 @@ -293,6 +309,35 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op ops->target.addr = strtoull(ops->raw, NULL, 16); } + target.addr = map__objdump_2mem(map, ops->target.addr); + start = map->unmap_ip(map, sym->start), + end = map->unmap_ip(map, sym->end); + + ops->target.outside = target.addr < start || target.addr > end; + + /* + * FIXME: things like this in _cpp_lex_token (gcc's cc1 program): + + cpp_named_operator2name@@Base+0xa72 + + * Point to a place that is after the cpp_named_operator2name + * boundaries, i.e. in the ELF symbol table for cc1 + * cpp_named_operator2name is marked as being 32-bytes long, but it in + * fact is much larger than that, so we seem to need a symbols__find() + * routine that looks for >= current->start and < next_symbol->start, + * possibly just for C++ objects? + * + * For now lets just make some progress by marking jumps to outside the + * current function as call like. + * + * Actual navigation will come next, with further understanding of how + * the symbol searching and disassembly should be done. + + if (map_groups__find_ams(&target) == 0 && + map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr) + ops->target.sym = target.sym; + */ + if (s++ != NULL) { ops->target.offset = strtoull(s, NULL, 16); ops->target.offset_avail = true; @@ -2355,11 +2400,15 @@ static void disasm_line__write(struct disasm_line *dl, struct annotation *notes, { if (dl->ins.ops && dl->ins.ops->scnprintf) { if (ins__is_jump(&dl->ins)) { - bool fwd = dl->ops.target.offset > dl->al.offset; + bool fwd; + if (dl->ops.target.outside) + goto call_like; + fwd = dl->ops.target.offset > dl->al.offset; obj__write_graph(obj, fwd ? DARROW_CHAR : UARROW_CHAR); obj__printf(obj, " "); } else if (ins__is_call(&dl->ins)) { +call_like: obj__write_graph(obj, RARROW_CHAR); obj__printf(obj, " "); } else if (ins__is_ret(&dl->ins)) { diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index c0bf0554a9ea..ad8baafaf9f9 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -28,6 +28,7 @@ struct ins_operands { u64 addr; s64 offset; bool offset_avail; + bool outside; } target; union { struct { -- cgit v1.2.3 From 2eff061162819e00ec6379874ceb47caef17bcba Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 23 Mar 2018 10:12:33 -0300 Subject: perf annotate: Add "_local" to jump/offset validation routines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because they all really check if we can access data structures/visual constructs where a "jump" instruction targets code in the same function, i.e. things like: __pthread_mutex_lock /usr/lib64/libpthread-2.26.so 1.95 │ mov __pthread_force_elision,%ecx │ ┌──test %ecx,%ecx 0.07 │ ├──je 60 │ │ test $0x300,%esi │ │↓ jne 60 │ │ or $0x100,%esi │ │ mov %esi,0x10(%rdi) │ 42:│ mov %esi,%edx │ │ lea 0x16(%r8),%rsi │ │ mov %r8,%rdi │ │ and $0x80,%edx │ │ add $0x8,%rsp │ │→ jmpq __lll_lock_elision │ │ nop 0.29 │ 60:└─→and $0x80,%esi 0.07 │ mov $0x1,%edi 0.29 │ xor %eax,%eax 2.53 │ lock cmpxchg %edi,(%r8) And not things like that "jmpq __lll_lock_elision", that instead should behave like a "call" instruction and "jump" to the disassembly of "___lll_lock_elision". Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-3cwx39u3h66dfw9xjrlt7ca2@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 2 +- tools/perf/util/annotate.c | 9 ++++----- tools/perf/util/annotate.h | 14 +++++++++++--- 3 files changed, 16 insertions(+), 9 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 3834b264ba41..d77896a99570 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -155,7 +155,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) if (strstr(sym->name, "@plt")) return; - if (!disasm_line__is_valid_jump(cursor, sym)) + if (!disasm_line__is_valid_local_jump(cursor, sym)) return; /* diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index c299881c640a..9524f322f597 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1409,7 +1409,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file, if (dl == NULL) return -1; - if (!disasm_line__has_offset(dl)) { + if (!disasm_line__has_local_offset(dl)) { dl->ops.target.offset = dl->ops.target.addr - map__rip_2objdump(map, sym->start); dl->ops.target.offset_avail = true; @@ -2176,11 +2176,10 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp) return printed; } - -bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym) +bool disasm_line__is_valid_local_jump(struct disasm_line *dl, struct symbol *sym) { if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins) || - !disasm_line__has_offset(dl) || dl->ops.target.offset < 0 || + !disasm_line__has_local_offset(dl) || dl->ops.target.offset < 0 || dl->ops.target.offset >= (s64)symbol__size(sym)) return false; @@ -2201,7 +2200,7 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) dl = disasm_line(al); - if (!disasm_line__is_valid_jump(dl, sym)) + if (!disasm_line__is_valid_local_jump(dl, sym)) continue; al = notes->offsets[dl->ops.target.offset]; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index ad8baafaf9f9..ff7e3df31efa 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -117,12 +117,20 @@ static inline struct disasm_line *disasm_line(struct annotation_line *al) return al ? container_of(al, struct disasm_line, al) : NULL; } -static inline bool disasm_line__has_offset(const struct disasm_line *dl) +/* + * Is this offset in the same function as the line it is used? + * asm functions jump to other functions, for instance. + */ +static inline bool disasm_line__has_local_offset(const struct disasm_line *dl) { - return dl->ops.target.offset_avail; + return dl->ops.target.offset_avail && !dl->ops.target.outside; } -bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym); +/* + * Can we draw an arrow from the jump to its target, for instance? I.e. + * is the jump and its target in the same function? + */ +bool disasm_line__is_valid_local_jump(struct disasm_line *dl, struct symbol *sym); void disasm_line__free(struct disasm_line *dl); struct annotation_line * -- cgit v1.2.3 From e4cc91b8027dbbb8a1f7c24cdecf58cd0b50375f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 23 Mar 2018 10:50:35 -0300 Subject: perf annotate: Support jumping from one function to another MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For instance: entry_SYSCALL_64 /lib/modules/4.16.0-rc5-00086-gdf09348f78dc/build/vmlinux 5.50 │ → callq do_syscall_64 14.56 │ mov 0x58(%rsp),%rcx 7.44 │ mov 0x80(%rsp),%r11 0.32 │ cmp %rcx,%r11 │ → jne swapgs_restore_regs_and_return_to_usermode 0.32 │ shl $0x10,%rcx 0.32 │ sar $0x10,%rcx 3.24 │ cmp %rcx,%r11 │ → jne swapgs_restore_regs_and_return_to_usermode 2.27 │ cmpq $0x33,0x88(%rsp) 1.29 │ → jne swapgs_restore_regs_and_return_to_usermode │ mov 0x30(%rsp),%r11 8.74 │ cmp %r11,0x90(%rsp) │ → jne swapgs_restore_regs_and_return_to_usermode 0.32 │ test $0x10100,%r11 │ → jne swapgs_restore_regs_and_return_to_usermode 0.32 │ cmpq $0x2b,0xa0(%rsp) 0.65 │ → jne swapgs_restore_regs_and_return_to_usermode It'll behave just like a "call" instruction, i.e. press enter or right arrow over one such line and the browser will navigate to the annotated disassembly of that function, which when exited, via left arrow or esc, will come back to the calling function. Now to support jump to an offset on a different function... Reported-by: Linus Torvalds Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-78o508mqvr8inhj63ddtw7mo@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 23 ++++++++++++++++++----- tools/perf/util/annotate.c | 6 ++++-- 2 files changed, 22 insertions(+), 7 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index d77896a99570..c02fb437ac8e 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -384,6 +384,15 @@ static int sym_title(struct symbol *sym, struct map *map, char *title, return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name); } +/* + * This can be called from external jumps, i.e. jumps from one functon + * to another, like from the kernel's entry_SYSCALL_64 function to the + * swapgs_restore_regs_and_return_to_usermode() function. + * + * So all we check here is that dl->ops.target.sym is set, if it is, just + * go to that function and when exiting from its disassembly, come back + * to the calling function. + */ static bool annotate_browser__callq(struct annotate_browser *browser, struct perf_evsel *evsel, struct hist_browser_timer *hbt) @@ -393,9 +402,6 @@ static bool annotate_browser__callq(struct annotate_browser *browser, struct annotation *notes; char title[SYM_TITLE_MAX_SIZE]; - if (!ins__is_call(&dl->ins)) - return false; - if (!dl->ops.target.sym) { ui_helpline__puts("The called function was not found."); return true; @@ -436,7 +442,9 @@ struct disasm_line *annotate_browser__find_offset(struct annotate_browser *brows return NULL; } -static bool annotate_browser__jump(struct annotate_browser *browser) +static bool annotate_browser__jump(struct annotate_browser *browser, + struct perf_evsel *evsel, + struct hist_browser_timer *hbt) { struct disasm_line *dl = disasm_line(browser->selection); u64 offset; @@ -445,6 +453,11 @@ static bool annotate_browser__jump(struct annotate_browser *browser) if (!ins__is_jump(&dl->ins)) return false; + if (dl->ops.target.outside) { + annotate_browser__callq(browser, evsel, hbt); + return true; + } + offset = dl->ops.target.offset; dl = annotate_browser__find_offset(browser, offset, &idx); if (dl == NULL) { @@ -731,7 +744,7 @@ show_help: goto show_sup_ins; else if (ins__is_ret(&dl->ins)) goto out; - else if (!(annotate_browser__jump(browser) || + else if (!(annotate_browser__jump(browser, evsel, hbt) || annotate_browser__callq(browser, evsel, hbt))) { show_sup_ins: ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions."); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 9524f322f597..5fa270b24eea 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -332,11 +332,10 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op * * Actual navigation will come next, with further understanding of how * the symbol searching and disassembly should be done. - + */ if (map_groups__find_ams(&target) == 0 && map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr) ops->target.sym = target.sym; - */ if (s++ != NULL) { ops->target.offset = strtoull(s, NULL, 16); @@ -356,6 +355,9 @@ static int jump__scnprintf(struct ins *ins, char *bf, size_t size, if (!ops->target.addr || ops->target.offset < 0) return ins__raw_scnprintf(ins, bf, size, ops); + if (ops->target.outside && ops->target.sym != NULL) + return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.sym->name); + if (c != NULL) { const char *c2 = strchr(c + 1, ','); -- cgit v1.2.3 From c448234cfe46ec5abc0014dca8b3b49989bffe9e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 23 Mar 2018 10:57:08 -0300 Subject: perf annotate: Defer searching for comma in raw line till it is needed That strchr() in jump__scnprintf() needs to be nuked somehow, as it, IIRC is already done in jump__parse() and if needed at scnprintf() time, should be stashed in the struct filled in parse() time. For now jus defer it to just before where it is used. Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-j0t5hagnphoz9xw07bh3ha3g@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 5fa270b24eea..f730e0cf8a26 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -350,7 +350,7 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op static int jump__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { - const char *c = strchr(ops->raw, ','); + const char *c; if (!ops->target.addr || ops->target.offset < 0) return ins__raw_scnprintf(ins, bf, size, ops); @@ -358,6 +358,7 @@ static int jump__scnprintf(struct ins *ins, char *bf, size_t size, if (ops->target.outside && ops->target.sym != NULL) return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.sym->name); + c = strchr(ops->raw, ','); if (c != NULL) { const char *c2 = strchr(c + 1, ','); -- cgit v1.2.3 From 980b68ec0694f250e967cb18c5705ef5de10fdd5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 23 Mar 2018 12:26:39 -0300 Subject: perf annotate: Use absolute addresses to calculate jump target offsets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These types of jumps were confusing the annotate browser: entry_SYSCALL_64 /lib/modules/4.16.0-rc5-00086-gdf09348f78dc/build/vmlinux entry_SYSCALL_64 /lib/modules/4.16.0-rc5-00086-gdf09348f78dc/build/vmlinux Percent│ffffffff81a00020: swapgs │ffffffff81a00128: ↓ jae ffffffff81a00139 │ffffffff81a00155: → jmpq *0x825d2d(%rip) # ffffffff82225e88 I.e. the syscall_return_via_sysret function is actually "inside" the entry_SYSCALL_64 function, and the offsets in jumps like these (+0x53) are relative to syscall_return_via_sysret, not to syscall_return_via_sysret. Or this may be some artifact in how the assembler marks the start and end of a function and how this ends up in the ELF symtab for vmlinux, i.e. syscall_return_via_sysret() isn't "inside" entry_SYSCALL_64, but just right after it. From readelf -sw vmlinux: 80267: ffffffff81a00020 315 NOTYPE GLOBAL DEFAULT 1 entry_SYSCALL_64 316: ffffffff81a000e6 0 NOTYPE LOCAL DEFAULT 1 syscall_return_via_sysret 0xffffffff81a00020 + 315 > 0xffffffff81a000e6 So instead of looking for offsets after that last '+' sign, calculate offsets for jump target addresses that are inside the function being disassembled from the absolute address, 0xffffffff81a00139 in this case, subtracting from it the objdump address for the start of the function being disassembled, entry_SYSCALL_64() in this case. So, before this patch: entry_SYSCALL_64 /lib/modules/4.16.0-rc5-00086-gdf09348f78dc/build/vmlinux Percent│ pop %r10 │ pop %r9 │ pop %r8 │ pop %rax │ pop %rsi │ pop %rdx │ pop %rsi │ mov %rsp,%rdi │ mov %gs:0x5004,%rsp │ pushq 0x28(%rdi) │ pushq (%rdi) │ push %rax │ ↑ jmp 6c │ mov %cr3,%rdi │ ↑ jmp 62 │ mov %rdi,%rax │ and $0x7ff,%rdi │ bt %rdi,%gs:0x2219a │ ↑ jae 53 │ btr %rdi,%gs:0x2219a │ mov %rax,%rdi │ ↑ jmp 5b After: entry_SYSCALL_64 /lib/modules/4.16.0-rc5-00086-gdf09348f78dc/build/vmlinux 0.65 │ → jne swapgs_restore_regs_and_return_to_usermode │ pop %r10 │ pop %r9 │ pop %r8 │ pop %rax │ pop %rsi │ pop %rdx │ pop %rsi │ mov %rsp,%rdi │ mov %gs:0x5004,%rsp │ pushq 0x28(%rdi) │ pushq (%rdi) │ push %rax │ ↓ jmp 132 │ mov %cr3,%rdi │ ┌──jmp 128 │ │ mov %rdi,%rax │ │ and $0x7ff,%rdi │ │ bt %rdi,%gs:0x2219a │ │↓ jae 119 │ │ btr %rdi,%gs:0x2219a │ │ mov %rax,%rdi │ │↓ jmp 121 │119:│ mov %rax,%rdi │ │ bts $0x3f,%rdi │121:│ or $0x800,%rdi │128:└─→or $0x1000,%rdi │ mov %rdi,%cr3 │132: pop %rax │ pop %rdi │ pop %rsp │ → jmpq *0x825d2d(%rip) # ffffffff82225e88 With those at least navigating to the right destination, an improvement for these cases seems to be to be to somehow mark those inner functions, which in this case could be: entry_SYSCALL_64 /lib/modules/4.16.0-rc5-00086-gdf09348f78dc/build/vmlinux │syscall_return_via_sysret: │ pop %r15 │ pop %r14 │ pop %r13 │ pop %r12 │ pop %rbp │ pop %rbx │ pop %rsi │ pop %r10 │ pop %r9 │ pop %r8 │ pop %rax │ pop %rsi │ pop %rdx │ pop %rsi │ mov %rsp,%rdi │ mov %gs:0x5004,%rsp │ pushq 0x28(%rdi) │ pushq (%rdi) │ push %rax │ ↓ jmp 132 │ mov %cr3,%rdi │ ┌──jmp 128 │ │ mov %rdi,%rax │ │ and $0x7ff,%rdi │ │ bt %rdi,%gs:0x2219a │ │↓ jae 119 │ │ btr %rdi,%gs:0x2219a │ │ mov %rax,%rdi │ │↓ jmp 121 │119:│ mov %rax,%rdi │ │ bts $0x3f,%rdi │121:│ or $0x800,%rdi │128:└─→or $0x1000,%rdi │ mov %rdi,%cr3 │132: pop %rax │ pop %rdi │ pop %rsp │ → jmpq *0x825d2d(%rip) # ffffffff82225e88 This all gets much better viewed if one uses 'perf report --ignore-vmlinux' forcing the usage of /proc/kcore + /proc/kallsyms, when the above actually gets down to: # perf report --ignore-vmlinux ## do '/64', will show the function names containing '64', ## navigate to /entry_SYSCALL_64_after_hwframe.annotation, ## press 'A' to annotate, then 'P' to print that annotation ## to a file ## From another xterm (or see on screen, this 'P' thing is for ## getting rid of those right side scroll bars/spaces): # cat /entry_SYSCALL_64_after_hwframe.annotation entry_SYSCALL_64_after_hwframe() /proc/kcore Event: cycles:ppp Percent Disassembly of section load0: ffffffff9aa00044 : 11.97 push %rax 4.85 push %rdi push %rsi 2.59 push %rdx 2.27 push %rcx 0.32 pushq $0xffffffffffffffda 1.29 push %r8 xor %r8d,%r8d 1.62 push %r9 0.65 xor %r9d,%r9d 1.62 push %r10 xor %r10d,%r10d 5.50 push %r11 xor %r11d,%r11d 3.56 push %rbx xor %ebx,%ebx 4.21 push %rbp xor %ebp,%ebp 2.59 push %r12 0.97 xor %r12d,%r12d 3.24 push %r13 xor %r13d,%r13d 2.27 push %r14 xor %r14d,%r14d 4.21 push %r15 xor %r15d,%r15d 0.97 mov %rsp,%rdi 5.50 → callq do_syscall_64 14.56 mov 0x58(%rsp),%rcx 7.44 mov 0x80(%rsp),%r11 0.32 cmp %rcx,%r11 → jne swapgs_restore_regs_and_return_to_usermode 0.32 shl $0x10,%rcx 0.32 sar $0x10,%rcx 3.24 cmp %rcx,%r11 → jne swapgs_restore_regs_and_return_to_usermode 2.27 cmpq $0x33,0x88(%rsp) 1.29 → jne swapgs_restore_regs_and_return_to_usermode mov 0x30(%rsp),%r11 8.74 cmp %r11,0x90(%rsp) → jne swapgs_restore_regs_and_return_to_usermode 0.32 test $0x10100,%r11 → jne swapgs_restore_regs_and_return_to_usermode 0.32 cmpq $0x2b,0xa0(%rsp) 0.65 → jne swapgs_restore_regs_and_return_to_usermode I.e. using kallsyms makes the function start/end be done differently than using what is in the vmlinux ELF symtab and actually the hits goes to entry_SYSCALL_64_after_hwframe, which is a GLOBAL() after the start of entry_SYSCALL_64: ENTRY(entry_SYSCALL_64) UNWIND_HINT_EMPTY pushq $__USER_CS /* pt_regs->cs */ pushq %rcx /* pt_regs->ip */ GLOBAL(entry_SYSCALL_64_after_hwframe) pushq %rax /* pt_regs->orig_ax */ PUSH_AND_CLEAR_REGS rax=$-ENOSYS And it goes and ends at: cmpq $__USER_DS, SS(%rsp) /* SS must match SYSRET */ jne swapgs_restore_regs_and_return_to_usermode /* * We win! This label is here just for ease of understanding * perf profiles. Nothing jumps here. */ syscall_return_via_sysret: /* rcx and r11 are already restored (see code above) */ UNWIND_HINT_EMPTY POP_REGS pop_rdi=0 skip_r11rcx=1 So perhaps some people should really just play with '--ignore-vmlinux' to force /proc/kcore + kallsyms. One idea is to do both, i.e. have a vmlinux annotation and a kcore+kallsyms one, when possible, and even show the patched location, etc. Reported-by: Linus Torvalds Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-r11knxv8voesav31xokjiuo6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f730e0cf8a26..3a428d7c59b9 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -280,7 +280,6 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op struct addr_map_symbol target = { .map = map, }; - const char *s = strchr(ops->raw, '+'); const char *c = strchr(ops->raw, ','); u64 start, end; /* @@ -337,8 +336,8 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr) ops->target.sym = target.sym; - if (s++ != NULL) { - ops->target.offset = strtoull(s, NULL, 16); + if (!ops->target.outside) { + ops->target.offset = target.addr - start; ops->target.offset_avail = true; } else { ops->target.offset_avail = false; -- cgit v1.2.3