From 555fc3b1ef4c850c635be333024dcf67bc1e7cb8 Mon Sep 17 00:00:00 2001 From: Martin Vuille Date: Sun, 18 Mar 2018 13:50:53 -0400 Subject: [PATCH 01/44] perf unwind: Report error from dwfl_attach_state In verbose level 2, errors returned by libdw are reported in most cases, but not when calling dwfl_attach_state. Since elfutils v 0.160 (2014), dwfl_attach_state sets the error code to report failure cause. On failure, log the reported error. Signed-off-by: Martin Vuille Reviewed-by: Kim Phillips Link: http://lkml.kernel.org/r/20180318175053.4222-1-jpmv27@aim.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/unwind-libdw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 8e969f28cc597..7bdd239c795c1 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -236,7 +236,8 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, if (err) goto out; - if (!dwfl_attach_state(ui->dwfl, EM_NONE, thread->tid, &callbacks, ui)) + err = !dwfl_attach_state(ui->dwfl, EM_NONE, thread->tid, &callbacks, ui); + if (err) goto out; err = dwfl_getthread_frames(ui->dwfl, thread->tid, frame_callback, ui); From 98bc80b0a199619d2987e61e42415a1ae7a1d7fb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 10:03:34 -0300 Subject: [PATCH 02/44] perf annotate: Move annotation_options out of the TUI browser This will be useful when making parts of the TUI browser generic enough to be used for a new stdio mode, available even when the TUI is not built in, for explicit user decision or when the necessary library devel files, for the slang library currently, are not available in the build system. 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-45twzienhz7ypbad0sbvojku@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 10 +--------- tools/perf/util/annotate.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 618edf96353c4..69ec968ac0be8 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -31,15 +31,7 @@ struct browser_line { int jump_sources; }; -static struct annotate_browser_opt { - bool hide_src_code, - use_offset, - jump_arrows, - show_linenr, - show_nr_jumps, - show_nr_samples, - show_total_period; -} annotate_browser__opts = { +static struct annotation_options annotate_browser__opts = { .use_offset = true, .jump_arrows = true, }; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 7e914e834101b..e924033432a37 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -58,6 +58,16 @@ bool ins__is_lock(const struct ins *ins); int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2); +struct annotation_options { + bool hide_src_code, + use_offset, + jump_arrows, + show_linenr, + show_nr_jumps, + show_nr_samples, + show_total_period; +}; + struct annotation; struct sym_hist_entry { From c426e5849b6019a0da7957e1acce4762c77f7c71 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 10:26:17 -0300 Subject: [PATCH 03/44] perf annotate: Move cycles/IPC formatting width constants outside TUI These will be used in --stdio2 so lets move it first to reduce noise in the following patches. 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-fisud7pcak3prk7uwsvs3g2e@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 19 ++++++++----------- tools/perf/util/annotate.h | 3 +++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 69ec968ac0be8..ca3d99c1e4d96 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -22,9 +22,6 @@ struct disasm_line_samples { struct sym_hist_entry he; }; -#define IPC_WIDTH 6 -#define CYCLES_WIDTH 6 - struct browser_line { u32 idx; int idx_asm; @@ -107,7 +104,7 @@ static int annotate_browser__pcnt_width(struct annotate_browser *ab) static int annotate_browser__cycles_width(struct annotate_browser *ab) { - return ab->have_cycles ? IPC_WIDTH + CYCLES_WIDTH : 0; + return ab->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0; } static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser, @@ -194,19 +191,19 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int } if (ab->have_cycles) { if (al->ipc) - ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, al->ipc); + ui_browser__printf(browser, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc); else if (!show_title) - ui_browser__write_nstring(browser, " ", IPC_WIDTH); + ui_browser__write_nstring(browser, " ", ANNOTATION__IPC_WIDTH); else - ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC"); + ui_browser__printf(browser, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC"); if (al->cycles) ui_browser__printf(browser, "%*" PRIu64 " ", - CYCLES_WIDTH - 1, al->cycles); + ANNOTATION__CYCLES_WIDTH - 1, al->cycles); else if (!show_title) - ui_browser__write_nstring(browser, " ", CYCLES_WIDTH); + ui_browser__write_nstring(browser, " ", ANNOTATION__CYCLES_WIDTH); else - ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle"); + ui_browser__printf(browser, "%*s ", ANNOTATION__CYCLES_WIDTH - 1, "Cycle"); } SLsmg_write_char(' '); @@ -359,7 +356,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) } if (ab->have_cycles) - width = IPC_WIDTH + CYCLES_WIDTH; + width = ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH; ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); __ui_browser__line_arrow(browser, diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index e924033432a37..0407234b51574 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -58,6 +58,9 @@ bool ins__is_lock(const struct ins *ins); int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2); +#define ANNOTATION__IPC_WIDTH 6 +#define ANNOTATION__CYCLES_WIDTH 6 + struct annotation_options { bool hide_src_code, use_offset, From 00ea0eb21e9ba38636608e3eb0ac332fc022d5bb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 10:28:06 -0300 Subject: [PATCH 04/44] perf annotate tui: Use annotate_browser__cycles_width() mroe Instead of an open coded equivalent, will reduce a bit noise in the following patches. 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-pnwn1dg9345zawhgiorpsadf@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index ca3d99c1e4d96..0f84a52b40883 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -308,7 +308,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) struct map_symbol *ms = ab->b.priv; struct symbol *sym = ms->sym; u8 pcnt_width = annotate_browser__pcnt_width(ab); - int width = 0; + int width; /* PLT symbols contain external offsets */ if (strstr(sym->name, "@plt")) @@ -355,8 +355,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) to = (u64)btarget->idx; } - if (ab->have_cycles) - width = ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH; + width = annotate_browser__cycles_width(ab); ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); __ui_browser__line_arrow(browser, From 0e83a7e9e592cdf60696076071b2629adc569826 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 10:35:04 -0300 Subject: [PATCH 05/44] perf annotate tui: Move have_cycles to struct annotation This is to pave the way to have more functions shared between TUI, stdio and the upcoming stdio2 formatting, that will use the __scnprintf functions used by --tui in a --stdio fashion. This partially addresses the comments added in cset 30e863bb6f70 ("perf annotate: Compute IPC and basic block cycles"): /* * This should probably be in util/annotate.c to share with the tty * annotate, but right now we need the per byte offsets arrays, * which are only here. */ The following patches will address the rest. 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-yftvybgx1s8sevs6kp1an0ft@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 20 +++++++++----------- tools/perf/util/annotate.h | 6 ++++++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 0f84a52b40883..0dd64707125a2 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -49,7 +49,6 @@ struct annotate_browser { int max_jump_sources; int nr_jumps; bool searching_backwards; - bool have_cycles; u8 addr_width; u8 jumps_width; u8 target_width; @@ -102,11 +101,6 @@ static int annotate_browser__pcnt_width(struct annotate_browser *ab) return (annotate_browser__opts.show_total_period ? 12 : 7) * ab->nr_events; } -static int annotate_browser__cycles_width(struct annotate_browser *ab) -{ - return ab->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0; -} - static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser, char *bf, size_t size) { @@ -136,6 +130,9 @@ static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browse static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) { struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); + struct map_symbol *ms = browser->priv; + struct symbol *sym = ms->sym; + struct annotation *notes = symbol__annotation(sym); struct 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); @@ -144,7 +141,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int !browser->navkeypressed))); int width = browser->width, printed; int i, pcnt_width = annotate_browser__pcnt_width(ab), - cycles_width = annotate_browser__cycles_width(ab); + cycles_width = annotation__cycles_width(notes); double percent_max = 0.0; char bf[256]; bool show_title = false; @@ -155,7 +152,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int } if ((row == 0) && (al->offset == -1 || percent_max == 0.0)) { - if (ab->have_cycles) { + if (notes->have_cycles) { if (al->ipc == 0.0 && al->cycles == 0) show_title = true; } else @@ -189,7 +186,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int annotate_browser__opts.show_nr_samples ? "Samples" : "Percent"); } } - if (ab->have_cycles) { + if (notes->have_cycles) { if (al->ipc) ui_browser__printf(browser, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc); else if (!show_title) @@ -307,6 +304,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) unsigned int from, to; struct map_symbol *ms = ab->b.priv; struct symbol *sym = ms->sym; + struct annotation *notes = symbol__annotation(sym); u8 pcnt_width = annotate_browser__pcnt_width(ab); int width; @@ -355,7 +353,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) to = (u64)btarget->idx; } - width = annotate_browser__cycles_width(ab); + width = annotation__cycles_width(notes); ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); __ui_browser__line_arrow(browser, @@ -1033,7 +1031,7 @@ static void annotate__compute_ipc(struct annotate_browser *browser, size_t size, al = browser->offsets[offset]; if (al && ch->num_aggr) al->cycles = ch->cycles_aggr / ch->num_aggr; - browser->have_cycles = true; + notes->have_cycles = true; } } pthread_mutex_unlock(¬es->lock); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 0407234b51574..23d2f32b7bf0e 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -164,9 +164,15 @@ struct annotated_source { struct annotation { pthread_mutex_t lock; u64 max_coverage; + bool have_cycles; struct annotated_source *src; }; +static inline int annotation__cycles_width(struct annotation *notes) +{ + return notes->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0; +} + static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) { return (((void *)¬es->src->histograms) + From 9d6bb41d1ced7288b54a79a2c15d750085012215 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 10:47:54 -0300 Subject: [PATCH 06/44] perf annotate: Move annotation_line array from TUI to generic code This is needed to reduce the differences between the TUI mode and the other annotation UIs, next csets will move that code to the UI-neutral annotation library. Leaving it in place for now to ease review. 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-gz09ahsd5xm1eip7ura5ow6x@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 41 ++++++++++++++----------------- tools/perf/util/annotate.h | 1 + 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 0dd64707125a2..e89b68612408f 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -40,7 +40,6 @@ struct annotate_browser { struct rb_root entries; struct rb_node *curr_hot; struct annotation_line *selection; - struct annotation_line **offsets; struct arch *arch; int nr_events; u64 start; @@ -335,9 +334,9 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) * name right after the '<' token and probably treating this like a * 'call' instruction. */ - target = ab->offsets[cursor->ops.target.offset]; + target = notes->offsets[cursor->ops.target.offset]; if (target == NULL) { - ui_helpline__printf("WARN: jump target inconsistency, press 'o', ab->offsets[%#x] = NULL\n", + ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n", cursor->ops.target.offset); return; } @@ -969,25 +968,25 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, } -static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end) +static unsigned count_insn(struct annotation *notes, u64 start, u64 end) { unsigned n_insn = 0; u64 offset; for (offset = start; offset <= end; offset++) { - if (browser->offsets[offset]) + if (notes->offsets[offset]) n_insn++; } return n_insn; } -static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end, +static void count_and_fill(struct annotation *notes, u64 start, u64 end, struct cyc_hist *ch) { unsigned n_insn; u64 offset; - n_insn = count_insn(browser, start, end); + n_insn = count_insn(notes, start, end); if (n_insn && ch->num && ch->cycles) { float ipc = n_insn / ((double)ch->cycles / (double)ch->num); @@ -996,7 +995,7 @@ static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end, return; for (offset = start; offset <= end; offset++) { - struct annotation_line *al = browser->offsets[offset]; + struct annotation_line *al = notes->offsets[offset]; if (al) al->ipc = ipc; @@ -1009,11 +1008,9 @@ static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end, * annotate, but right now we need the per byte offsets arrays, * which are only here. */ -static void annotate__compute_ipc(struct annotate_browser *browser, size_t size, - struct symbol *sym) +static void annotate__compute_ipc(struct annotation *notes, size_t size) { u64 offset; - struct annotation *notes = symbol__annotation(sym); if (!notes->src || !notes->src->cycles_hist) return; @@ -1027,8 +1024,8 @@ static void annotate__compute_ipc(struct annotate_browser *browser, size_t size, struct annotation_line *al; if (ch->have_start) - count_and_fill(browser, ch->start, offset, ch); - al = browser->offsets[offset]; + 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; @@ -1043,13 +1040,14 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser u64 offset; struct map_symbol *ms = browser->b.priv; struct symbol *sym = ms->sym; + struct annotation *notes = symbol__annotation(sym); /* PLT symbols contain external offsets */ if (strstr(sym->name, "@plt")) return; for (offset = 0; offset < size; ++offset) { - struct annotation_line *al = browser->offsets[offset]; + struct annotation_line *al = notes->offsets[offset]; struct disasm_line *dl; struct browser_line *blt; @@ -1058,7 +1056,7 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser if (!disasm_line__is_valid_jump(dl, sym)) continue; - al = browser->offsets[dl->ops.target.offset]; + al = notes->offsets[dl->ops.target.offset]; /* * FIXME: Oops, no jump target? Buggy disassembler? Or do we @@ -1089,7 +1087,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, struct hist_browser_timer *hbt) { struct annotation_line *al; - struct annotation *notes; + struct annotation *notes = symbol__annotation(sym); size_t size; struct map_symbol ms = { .map = map, @@ -1116,8 +1114,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, if (map->dso->annotate_warned) return -1; - browser.offsets = zalloc(size * sizeof(struct annotation_line *)); - if (browser.offsets == NULL) { + notes->offsets = zalloc(size * sizeof(struct annotation_line *)); + if (notes->offsets == NULL) { ui__error("Not enough memory!"); return -1; } @@ -1137,7 +1135,6 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, ui_helpline__push("Press ESC to exit"); - notes = symbol__annotation(sym); browser.start = map__rip_2objdump(map, sym->start); list_for_each_entry(al, ¬es->src->source, node) { @@ -1158,13 +1155,13 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, * E.g. copy_user_generic_unrolled */ if (al->offset < (s64)size) - browser.offsets[al->offset] = al; + notes->offsets[al->offset] = al; } else bpos->idx_asm = -1; } annotate_browser__mark_jump_targets(&browser, size); - annotate__compute_ipc(&browser, size, sym); + annotate__compute_ipc(notes, size); browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); browser.max_addr_width = hex_width(sym->end); @@ -1184,7 +1181,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, annotated_source__purge(notes->src); out_free_offsets: - free(browser.offsets); + zfree(¬es->offsets); return ret; } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 23d2f32b7bf0e..d2c3436830a93 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -164,6 +164,7 @@ struct annotated_source { struct annotation { pthread_mutex_t lock; u64 max_coverage; + struct annotation_line **offsets; bool have_cycles; struct annotated_source *src; }; From f56c083bc4f9bca6f4d75d13b93720915185a8e8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 11:46:23 -0300 Subject: [PATCH 07/44] 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/ui/browsers/annotate.c | 69 +------------------------------ tools/perf/util/annotate.c | 60 +++++++++++++++++++++++++++ tools/perf/util/annotate.h | 2 + 3 files changed, 63 insertions(+), 68 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index e89b68612408f..353edff3fdbbf 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -967,73 +967,6 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, return map_symbol__tui_annotate(&he->ms, evsel, hbt); } - -static unsigned 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 count_and_fill(struct annotation *notes, u64 start, u64 end, - struct cyc_hist *ch) -{ - unsigned n_insn; - u64 offset; - - n_insn = 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; - } - } -} - -/* - * This should probably be in util/annotate.c to share with the tty - * annotate, but right now we need the per byte offsets arrays, - * which are only here. - */ -static void annotate__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) - 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); -} - static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, size_t size) { @@ -1161,7 +1094,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, } annotate_browser__mark_jump_targets(&browser, size); - annotate__compute_ipc(notes, size); + annotation__compute_ipc(notes, size); browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); browser.max_addr_width = hex_width(sym->end); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 535357c6ce02a..d737c33c87d03 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) { diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index d2c3436830a93..21fa5d7cd9e08 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -174,6 +174,8 @@ static inline int annotation__cycles_width(struct annotation *notes) return notes->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0; } +void annotation__compute_ipc(struct annotation *notes, size_t size); + static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) { return (((void *)¬es->src->histograms) + From 0553e83dc10831ac5127c86fa5a78af940fa92a2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 11:52:32 -0300 Subject: [PATCH 08/44] perf annotate: Move nr_events from annotate_browser to annotation struct Paving the way to move more stuff out of TUI and into the generic annotation 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-8vqax6wgfqohelot8j8zsfvs@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 11 ++++++----- tools/perf/util/annotate.h | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 353edff3fdbbf..8a110765b3283 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -41,7 +41,6 @@ struct annotate_browser { struct rb_node *curr_hot; struct annotation_line *selection; struct arch *arch; - int nr_events; u64 start; int nr_asm_entries; int nr_entries; @@ -97,7 +96,9 @@ static int annotate_browser__set_jumps_percent_color(struct annotate_browser *br static int annotate_browser__pcnt_width(struct annotate_browser *ab) { - return (annotate_browser__opts.show_total_period ? 12 : 7) * ab->nr_events; + struct map_symbol *ms = ab->b.priv; + struct annotation *notes = symbol__annotation(ms->sym); + return (annotate_browser__opts.show_total_period ? 12 : 7) * notes->nr_events; } static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser, @@ -145,7 +146,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int char bf[256]; bool show_title = false; - for (i = 0; i < ab->nr_events; i++) { + for (i = 0; i < notes->nr_events; i++) { if (al->samples[i].percent > percent_max) percent_max = al->samples[i].percent; } @@ -159,7 +160,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int } if (al->offset != -1 && percent_max != 0.0) { - for (i = 0; i < ab->nr_events; i++) { + for (i = 0; i < notes->nr_events; i++) { ui_browser__set_percent_color(browser, al->samples[i].percent, current_entry); @@ -1099,7 +1100,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); browser.max_addr_width = hex_width(sym->end); browser.jumps_width = width_jumps(browser.max_jump_sources); - browser.nr_events = nr_pcnt; + notes->nr_events = nr_pcnt; browser.b.nr_entries = browser.nr_entries; browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 21fa5d7cd9e08..5d15cdf22fc91 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -165,6 +165,7 @@ struct annotation { pthread_mutex_t lock; u64 max_coverage; struct annotation_line **offsets; + int nr_events; bool have_cycles; struct annotated_source *src; }; From 16932d77050fb3d76bc265c21c53eeec14639d5e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 12:33:56 -0300 Subject: [PATCH 09/44] perf annotate: Stop using a global config struct For the TUI, that is interactive, its interesting to have a configuration that one can go on changing and then when moving from one symbol annotation to another symbol, the options set while browsing the first symbol to be kept. But since we're trying to make this code reusable by a --stdio formatter, we better have a pointer in struct annotation and in the TUI case set it to the global, but use something else for other cases, such as --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-kv1ngr159jfu5h9ddgiuwcvg@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 84 ++++++++++++++++++------------- tools/perf/util/annotate.h | 1 + 2 files changed, 51 insertions(+), 34 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 8a110765b3283..b20e0ae72466b 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -63,10 +63,12 @@ static inline struct browser_line *browser_line(struct annotation_line *al) return ptr - sizeof(struct browser_line); } -static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, - void *entry) +static bool disasm_line__filter(struct ui_browser *browser, void *entry) { - if (annotate_browser__opts.hide_src_code) { + struct map_symbol *ms = browser->priv; + struct annotation *notes = symbol__annotation(ms->sym); + + if (notes->options->hide_src_code) { struct annotation_line *al = list_entry(entry, struct annotation_line, node); return al->offset == -1; @@ -98,12 +100,15 @@ static int annotate_browser__pcnt_width(struct annotate_browser *ab) { struct map_symbol *ms = ab->b.priv; struct annotation *notes = symbol__annotation(ms->sym); - return (annotate_browser__opts.show_total_period ? 12 : 7) * notes->nr_events; + return (notes->options->show_total_period ? 12 : 7) * notes->nr_events; } static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser, char *bf, size_t size) { + struct map_symbol *ms = browser->priv; + struct annotation *notes = symbol__annotation(ms->sym); + if (dl->ins.ops && dl->ins.ops->scnprintf) { if (ins__is_jump(&dl->ins)) { bool fwd = dl->ops.target.offset > dl->al.offset; @@ -124,7 +129,7 @@ static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browse ui_browser__write_nstring(browser, " ", 2); } - disasm_line__scnprintf(dl, bf, size, !annotate_browser__opts.use_offset); + disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset); } static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) @@ -136,7 +141,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int 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 = (!annotate_browser__opts.hide_src_code && + bool change_color = (!notes->options->hide_src_code && (!current_entry || (browser->use_navkeypressed && !browser->navkeypressed))); int width = browser->width, printed; @@ -164,10 +169,10 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int ui_browser__set_percent_color(browser, al->samples[i].percent, current_entry); - if (annotate_browser__opts.show_total_period) { + if (notes->options->show_total_period) { ui_browser__printf(browser, "%11" PRIu64 " ", al->samples[i].he.period); - } else if (annotate_browser__opts.show_nr_samples) { + } else if (notes->options->show_nr_samples) { ui_browser__printf(browser, "%6" PRIu64 " ", al->samples[i].he.nr_samples); } else { @@ -182,8 +187,8 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int ui_browser__write_nstring(browser, " ", pcnt_width); else { ui_browser__printf(browser, "%*s", pcnt_width, - annotate_browser__opts.show_total_period ? "Period" : - annotate_browser__opts.show_nr_samples ? "Samples" : "Percent"); + notes->options->show_total_period ? "Period" : + notes->options->show_nr_samples ? "Samples" : "Percent"); } } if (notes->have_cycles) { @@ -212,7 +217,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int if (!*al->line) ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width); else if (al->offset == -1) { - if (al->line_nr && annotate_browser__opts.show_linenr) + if (al->line_nr && notes->options->show_linenr) printed = scnprintf(bf, sizeof(bf), "%-*d ", ab->addr_width + 1, al->line_nr); else @@ -224,14 +229,14 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int u64 addr = al->offset; int color = -1; - if (!annotate_browser__opts.use_offset) + if (!notes->options->use_offset) addr += ab->start; - if (!annotate_browser__opts.use_offset) { + if (!notes->options->use_offset) { printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); } else { if (bl->jump_sources) { - if (annotate_browser__opts.show_nr_jumps) { + if (notes->options->show_nr_jumps) { int prev; printed = scnprintf(bf, sizeof(bf), "%*d ", ab->jumps_width, @@ -345,7 +350,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) bcursor = browser_line(&cursor->al); btarget = browser_line(target); - if (annotate_browser__opts.hide_src_code) { + if (notes->options->hide_src_code) { from = bcursor->idx_asm; to = btarget->idx_asm; } else { @@ -371,10 +376,12 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) static unsigned int annotate_browser__refresh(struct ui_browser *browser) { struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); + struct map_symbol *ms = browser->priv; + struct annotation *notes = symbol__annotation(ms->sym); int ret = ui_browser__list_head_refresh(browser); int pcnt_width = annotate_browser__pcnt_width(ab); - if (annotate_browser__opts.jump_arrows) + if (notes->options->jump_arrows) annotate_browser__draw_current_jump(browser); ui_browser__set_color(browser, HE_COLORSET_NORMAL); @@ -439,6 +446,8 @@ static void annotate_browser__set_top(struct annotate_browser *browser, static void annotate_browser__set_rb_top(struct annotate_browser *browser, struct rb_node *nd) { + struct map_symbol *ms = browser->b.priv; + struct annotation *notes = symbol__annotation(ms->sym); struct browser_line *bpos; struct annotation_line *pos; u32 idx; @@ -447,7 +456,7 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser, bpos = browser_line(pos); idx = bpos->idx; - if (annotate_browser__opts.hide_src_code) + if (notes->options->hide_src_code) idx = bpos->idx_asm; annotate_browser__set_top(browser, pos, idx); browser->curr_hot = nd; @@ -496,6 +505,8 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, static bool annotate_browser__toggle_source(struct annotate_browser *browser) { + struct map_symbol *ms = browser->b.priv; + struct annotation *notes = symbol__annotation(ms->sym); struct annotation_line *al; struct browser_line *bl; off_t offset = browser->b.index - browser->b.top_idx; @@ -504,12 +515,12 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) al = list_entry(browser->b.top, struct annotation_line, node); bl = browser_line(al); - if (annotate_browser__opts.hide_src_code) { + if (notes->options->hide_src_code) { if (bl->idx_asm < offset) offset = bl->idx; browser->b.nr_entries = browser->nr_entries; - annotate_browser__opts.hide_src_code = false; + notes->options->hide_src_code = false; browser->b.seek(&browser->b, -offset, SEEK_CUR); browser->b.top_idx = bl->idx - offset; browser->b.index = bl->idx; @@ -524,7 +535,7 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) offset = bl->idx_asm; browser->b.nr_entries = browser->nr_asm_entries; - annotate_browser__opts.hide_src_code = true; + notes->options->hide_src_code = true; browser->b.seek(&browser->b, -offset, SEEK_CUR); browser->b.top_idx = bl->idx_asm - offset; browser->b.index = bl->idx_asm; @@ -750,14 +761,17 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, static void annotate_browser__update_addr_width(struct annotate_browser *browser) { - if (annotate_browser__opts.use_offset) + struct map_symbol *ms = browser->b.priv; + struct annotation *notes = symbol__annotation(ms->sym); + + if (notes->options->use_offset) browser->target_width = browser->min_addr_width; else browser->target_width = browser->max_addr_width; browser->addr_width = browser->target_width; - if (annotate_browser__opts.show_nr_jumps) + if (notes->options->show_nr_jumps) browser->addr_width += browser->jumps_width + 1; } @@ -768,6 +782,7 @@ static int annotate_browser__run(struct annotate_browser *browser, struct rb_node *nd = NULL; struct map_symbol *ms = browser->b.priv; struct symbol *sym = ms->sym; + struct annotation *notes = symbol__annotation(ms->sym); const char *help = "Press 'h' for help on key bindings"; int delay_secs = hbt ? hbt->refresh : 0; int key; @@ -851,8 +866,7 @@ static int annotate_browser__run(struct annotate_browser *browser, continue; } case 'k': - annotate_browser__opts.show_linenr = - !annotate_browser__opts.show_linenr; + notes->options->show_linenr = !notes->options->show_linenr; break; case 'H': nd = browser->curr_hot; @@ -862,14 +876,14 @@ static int annotate_browser__run(struct annotate_browser *browser, ui_helpline__puts(help); continue; case 'o': - annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset; + notes->options->use_offset = !notes->options->use_offset; annotate_browser__update_addr_width(browser); continue; case 'j': - annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows; + notes->options->jump_arrows = !notes->options->jump_arrows; continue; case 'J': - annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps; + notes->options->show_nr_jumps = !notes->options->show_nr_jumps; annotate_browser__update_addr_width(browser); continue; case '/': @@ -920,13 +934,13 @@ static int annotate_browser__run(struct annotate_browser *browser, continue; } case 't': - if (annotate_browser__opts.show_total_period) { - annotate_browser__opts.show_total_period = false; - annotate_browser__opts.show_nr_samples = true; - } else if (annotate_browser__opts.show_nr_samples) - annotate_browser__opts.show_nr_samples = false; + if (notes->options->show_total_period) { + notes->options->show_total_period = false; + notes->options->show_nr_samples = true; + } else if (notes->options->show_nr_samples) + notes->options->show_nr_samples = false; else - annotate_browser__opts.show_total_period = true; + notes->options->show_total_period = true; annotate_browser__update_addr_width(browser); continue; case K_LEFT: @@ -1048,6 +1062,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, 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!"); @@ -1105,7 +1121,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ - if (annotate_browser__opts.hide_src_code) + if (notes->options->hide_src_code) annotate_browser__init_asm_mode(&browser); annotate_browser__update_addr_width(&browser); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 5d15cdf22fc91..5936605b5dac2 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -164,6 +164,7 @@ struct annotated_source { struct annotation { pthread_mutex_t lock; u64 max_coverage; + struct annotation_options *options; struct annotation_line **offsets; int nr_events; bool have_cycles; From 6af612d2b10593cdd8bba4427741a981bdd57c86 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 12:41:39 -0300 Subject: [PATCH 10/44] perf annotate: Move pcnt_with() to the annotation library Out of the TUI code, since now all it touches is what is in 'struct annotation'. 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-kh5bbbgd7l4agv9oc5hnw0ui@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 14 +++----------- tools/perf/util/annotate.h | 5 +++++ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index b20e0ae72466b..3b030ee4505fa 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -96,13 +96,6 @@ static int annotate_browser__set_jumps_percent_color(struct annotate_browser *br return ui_browser__set_color(&browser->b, color); } -static int annotate_browser__pcnt_width(struct annotate_browser *ab) -{ - struct map_symbol *ms = ab->b.priv; - struct annotation *notes = symbol__annotation(ms->sym); - return (notes->options->show_total_period ? 12 : 7) * notes->nr_events; -} - static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser, char *bf, size_t size) { @@ -145,7 +138,7 @@ 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 = annotate_browser__pcnt_width(ab), + int i, pcnt_width = annotation__pcnt_width(notes), cycles_width = annotation__cycles_width(notes); double percent_max = 0.0; char bf[256]; @@ -310,7 +303,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) struct map_symbol *ms = ab->b.priv; struct symbol *sym = ms->sym; struct annotation *notes = symbol__annotation(sym); - u8 pcnt_width = annotate_browser__pcnt_width(ab); + u8 pcnt_width = annotation__pcnt_width(notes); int width; /* PLT symbols contain external offsets */ @@ -375,11 +368,10 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) static unsigned int annotate_browser__refresh(struct ui_browser *browser) { - struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); struct map_symbol *ms = browser->priv; struct annotation *notes = symbol__annotation(ms->sym); int ret = ui_browser__list_head_refresh(browser); - int pcnt_width = annotate_browser__pcnt_width(ab); + int pcnt_width = annotation__pcnt_width(notes); if (notes->options->jump_arrows) annotate_browser__draw_current_jump(browser); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 5936605b5dac2..17cd5d274fe50 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -176,6 +176,11 @@ static inline int annotation__cycles_width(struct annotation *notes) return notes->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0; } +static inline int annotation__pcnt_width(struct annotation *notes) +{ + return (notes->options->show_total_period ? 12 : 7) * notes->nr_events; +} + void annotation__compute_ipc(struct annotation *notes, size_t size); static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) From 95aa89d92de8b8da6dc1469bfc560784ab177aba Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 15:04:33 -0300 Subject: [PATCH 11/44] perf annotate tui: Add browser__annotation() helper To reduce the boilerplate to get to the symbol being annotated from the struct browser ->priv area. 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-ficdyqhe9esjseflvkriskwn@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 40 +++++++++++++------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 3b030ee4505fa..c995d28d1a589 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -55,6 +55,12 @@ struct annotate_browser { char search_bf[128]; }; +static inline struct annotation *browser__annotation(struct ui_browser *browser) +{ + struct map_symbol *ms = browser->priv; + return symbol__annotation(ms->sym); +} + static inline struct browser_line *browser_line(struct annotation_line *al) { void *ptr = al; @@ -65,8 +71,7 @@ static inline struct browser_line *browser_line(struct annotation_line *al) static bool disasm_line__filter(struct ui_browser *browser, void *entry) { - struct map_symbol *ms = browser->priv; - struct annotation *notes = symbol__annotation(ms->sym); + struct annotation *notes = browser__annotation(browser); if (notes->options->hide_src_code) { struct annotation_line *al = list_entry(entry, struct annotation_line, node); @@ -99,8 +104,7 @@ static int annotate_browser__set_jumps_percent_color(struct annotate_browser *br static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser, char *bf, size_t size) { - struct map_symbol *ms = browser->priv; - struct annotation *notes = symbol__annotation(ms->sym); + struct annotation *notes = browser__annotation(browser); if (dl->ins.ops && dl->ins.ops->scnprintf) { if (ins__is_jump(&dl->ins)) { @@ -128,9 +132,7 @@ static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browse static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) { struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); - struct map_symbol *ms = browser->priv; - struct symbol *sym = ms->sym; - struct annotation *notes = symbol__annotation(sym); + struct 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); @@ -368,8 +370,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) static unsigned int annotate_browser__refresh(struct ui_browser *browser) { - struct map_symbol *ms = browser->priv; - struct annotation *notes = symbol__annotation(ms->sym); + struct annotation *notes = browser__annotation(browser); int ret = ui_browser__list_head_refresh(browser); int pcnt_width = annotation__pcnt_width(notes); @@ -438,8 +439,7 @@ static void annotate_browser__set_top(struct annotate_browser *browser, static void annotate_browser__set_rb_top(struct annotate_browser *browser, struct rb_node *nd) { - struct map_symbol *ms = browser->b.priv; - struct annotation *notes = symbol__annotation(ms->sym); + struct annotation *notes = browser__annotation(&browser->b); struct browser_line *bpos; struct annotation_line *pos; u32 idx; @@ -497,8 +497,7 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, static bool annotate_browser__toggle_source(struct annotate_browser *browser) { - struct map_symbol *ms = browser->b.priv; - struct annotation *notes = symbol__annotation(ms->sym); + struct annotation *notes = browser__annotation(&browser->b); struct annotation_line *al; struct browser_line *bl; off_t offset = browser->b.index - browser->b.top_idx; @@ -588,9 +587,7 @@ static struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser, s64 offset, s64 *idx) { - struct map_symbol *ms = browser->b.priv; - struct symbol *sym = ms->sym; - struct annotation *notes = symbol__annotation(sym); + struct annotation *notes = browser__annotation(&browser->b); struct disasm_line *pos; *idx = 0; @@ -629,9 +626,7 @@ static struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser, char *s, s64 *idx) { - struct map_symbol *ms = browser->b.priv; - struct symbol *sym = ms->sym; - struct annotation *notes = symbol__annotation(sym); + struct annotation *notes = browser__annotation(&browser->b); struct annotation_line *al = browser->selection; *idx = browser->b.index; @@ -668,9 +663,7 @@ static struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser, char *s, s64 *idx) { - struct map_symbol *ms = browser->b.priv; - struct symbol *sym = ms->sym; - struct annotation *notes = symbol__annotation(sym); + struct annotation *notes = browser__annotation(&browser->b); struct annotation_line *al = browser->selection; *idx = browser->b.index; @@ -753,8 +746,7 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, static void annotate_browser__update_addr_width(struct annotate_browser *browser) { - struct map_symbol *ms = browser->b.priv; - struct annotation *notes = symbol__annotation(ms->sym); + struct annotation *notes = browser__annotation(&browser->b); if (notes->options->use_offset) browser->target_width = browser->min_addr_width; From bc1c0f3dfa77619ad90f6fed290636cf54629d30 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 15:10:28 -0300 Subject: [PATCH 12/44] perf annotate: Move max_jump_sources to struct annotation This is not useful only for the TUI, we'll want to somehow mark the --stdio2 lines with the most jump sources too. And moving this will allow us to change some function signatures from annotate_browser to ui_browser, reducing boilerplate. 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-vyggbbqd05k3k4mvv7z9l5px@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 11 ++++++----- tools/perf/util/annotate.h | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index c995d28d1a589..3bc003fe0b1d1 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -44,7 +44,6 @@ struct annotate_browser { u64 start; int nr_asm_entries; int nr_entries; - int max_jump_sources; int nr_jumps; bool searching_backwards; u8 addr_width; @@ -85,9 +84,11 @@ static bool disasm_line__filter(struct ui_browser *browser, void *entry) static int annotate_browser__jumps_percent_color(struct annotate_browser *browser, int nr, bool current) { + struct annotation *notes = browser__annotation(&browser->b); + if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed)) return HE_COLORSET_SELECTED; - if (nr == browser->max_jump_sources) + if (nr == notes->max_jump_sources) return HE_COLORSET_TOP; if (nr > 1) return HE_COLORSET_MEDIUM; @@ -998,8 +999,8 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser continue; blt = browser_line(al); - if (++blt->jump_sources > browser->max_jump_sources) - browser->max_jump_sources = blt->jump_sources; + if (++blt->jump_sources > notes->max_jump_sources) + notes->max_jump_sources = blt->jump_sources; ++browser->nr_jumps; } @@ -1099,7 +1100,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); browser.max_addr_width = hex_width(sym->end); - browser.jumps_width = width_jumps(browser.max_jump_sources); + browser.jumps_width = width_jumps(notes->max_jump_sources); notes->nr_events = nr_pcnt; browser.b.nr_entries = browser.nr_entries; browser.b.entries = ¬es->src->source, diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 17cd5d274fe50..b8aca936ed559 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -167,6 +167,7 @@ struct annotation { struct annotation_options *options; struct annotation_line **offsets; int nr_events; + int max_jump_sources; bool have_cycles; struct annotated_source *src; }; From 27feb761c7211c6c35350277b6c65989b982b377 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 15:14:45 -0300 Subject: [PATCH 13/44] perf annotate: Move jumps_percent_color to ui_browser Since all it needs is in ui_browser and annotation structs members. 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-9f8c2f9aetbibcw33d615y9o@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 3bc003fe0b1d1..6e2eea09a9b0f 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -81,12 +81,11 @@ static bool disasm_line__filter(struct ui_browser *browser, void *entry) return false; } -static int annotate_browser__jumps_percent_color(struct annotate_browser *browser, - int nr, bool current) +static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current) { - struct annotation *notes = browser__annotation(&browser->b); + struct annotation *notes = browser__annotation(browser); - if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed)) + if (current && (!browser->use_navkeypressed || browser->navkeypressed)) return HE_COLORSET_SELECTED; if (nr == notes->max_jump_sources) return HE_COLORSET_TOP; @@ -95,11 +94,10 @@ static int annotate_browser__jumps_percent_color(struct annotate_browser *browse return HE_COLORSET_NORMAL; } -static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser, - int nr, bool current) +static int ui_browser__set_jumps_percent_color(struct ui_browser *browser, int nr, bool current) { - int color = annotate_browser__jumps_percent_color(browser, nr, current); - return ui_browser__set_color(&browser->b, color); + 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, @@ -237,8 +235,8 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int printed = scnprintf(bf, sizeof(bf), "%*d ", ab->jumps_width, bl->jump_sources); - prev = annotate_browser__set_jumps_percent_color(ab, bl->jump_sources, - current_entry); + prev = ui_browser__set_jumps_percent_color(browser, bl->jump_sources, + current_entry); ui_browser__write_nstring(browser, bf, printed); ui_browser__set_color(browser, prev); } From 6dcd57e8ae2080bca776d55e6e2b3d529677cae5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 15:20:12 -0300 Subject: [PATCH 14/44] perf annotate: Move nr_jumps to struct annotation This is another information that will be useful for the --stdio2 mode, to provide symbol statistics, so move it from the TUI and change the mark_jump_targets() method to struct annotation. 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-kpgle1qxe7thajvrqleuvi80@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 13 ++++--------- tools/perf/util/annotate.h | 1 + 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 6e2eea09a9b0f..d05a2f9912075 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -44,7 +44,6 @@ struct annotate_browser { u64 start; int nr_asm_entries; int nr_entries; - int nr_jumps; bool searching_backwards; u8 addr_width; u8 jumps_width; @@ -965,13 +964,9 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, return map_symbol__tui_annotate(&he->ms, evsel, hbt); } -static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, - size_t size) +static void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) { - u64 offset; - struct map_symbol *ms = browser->b.priv; - struct symbol *sym = ms->sym; - struct annotation *notes = symbol__annotation(sym); + u64 offset, size = symbol__size(sym); /* PLT symbols contain external offsets */ if (strstr(sym->name, "@plt")) @@ -1000,7 +995,7 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser if (++blt->jump_sources > notes->max_jump_sources) notes->max_jump_sources = blt->jump_sources; - ++browser->nr_jumps; + ++notes->nr_jumps; } } @@ -1093,7 +1088,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, bpos->idx_asm = -1; } - annotate_browser__mark_jump_targets(&browser, size); + annotation__mark_jump_targets(notes, sym); annotation__compute_ipc(notes, size); browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index b8aca936ed559..897a84712ab41 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -167,6 +167,7 @@ struct annotation { struct annotation_options *options; struct annotation_line **offsets; int nr_events; + int nr_jumps; int max_jump_sources; bool have_cycles; struct annotated_source *src; From 0db45bcfac8586c6f5b732f114f456f2f788b19f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 15:31:56 -0300 Subject: [PATCH 15/44] 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(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index d05a2f9912075..58be0cecb0819 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 d737c33c87d03..330275680a1aa 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 897a84712ab41..ab4a8b7710a06 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) { From 4850c92e40835ea9ded3cd2051d4c95b2b69e426 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 15:43:18 -0300 Subject: [PATCH 16/44] perf annotate: Nuke struct browser_line The information in there are all related to things already moved to struct annotation, so move those members to struct annotation_line. 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-uc2b9c8iocvuuvbl7hyind84@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 66 ++++++++++--------------------- tools/perf/util/annotate.h | 2 + 2 files changed, 22 insertions(+), 46 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 58be0cecb0819..50f8e671644f6 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -22,11 +22,6 @@ struct disasm_line_samples { struct sym_hist_entry he; }; -struct browser_line { - u32 idx; - int idx_asm; -}; - static struct annotation_options annotate_browser__opts = { .use_offset = true, .jump_arrows = true, @@ -58,14 +53,6 @@ static inline struct annotation *browser__annotation(struct ui_browser *browser) return symbol__annotation(ms->sym); } -static inline struct browser_line *browser_line(struct annotation_line *al) -{ - void *ptr = al; - - ptr = container_of(al, struct disasm_line, al); - return ptr - sizeof(struct browser_line); -} - static bool disasm_line__filter(struct ui_browser *browser, void *entry) { struct annotation *notes = browser__annotation(browser); @@ -285,7 +272,6 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); struct disasm_line *cursor = disasm_line(ab->selection); struct annotation_line *target; - struct browser_line *btarget, *bcursor; unsigned int from, to; struct map_symbol *ms = ab->b.priv; struct symbol *sym = ms->sym; @@ -327,15 +313,12 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) return; } - bcursor = browser_line(&cursor->al); - btarget = browser_line(target); - if (notes->options->hide_src_code) { - from = bcursor->idx_asm; - to = btarget->idx_asm; + from = cursor->al.idx_asm; + to = target->idx_asm; } else { - from = (u64)bcursor->idx; - to = (u64)btarget->idx; + from = (u64)cursor->al.idx; + to = (u64)target->idx; } width = annotation__cycles_width(notes); @@ -425,16 +408,11 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser, struct rb_node *nd) { struct annotation *notes = browser__annotation(&browser->b); - struct browser_line *bpos; - struct annotation_line *pos; - u32 idx; - - pos = rb_entry(nd, struct annotation_line, rb_node); - bpos = browser_line(pos); + struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node); + u32 idx = pos->idx; - idx = bpos->idx; if (notes->options->hide_src_code) - idx = bpos->idx_asm; + idx = pos->idx_asm; annotate_browser__set_top(browser, pos, idx); browser->curr_hot = nd; } @@ -484,37 +462,35 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) { struct annotation *notes = browser__annotation(&browser->b); struct annotation_line *al; - struct browser_line *bl; off_t offset = browser->b.index - browser->b.top_idx; browser->b.seek(&browser->b, offset, SEEK_CUR); al = list_entry(browser->b.top, struct annotation_line, node); - bl = browser_line(al); if (notes->options->hide_src_code) { - if (bl->idx_asm < offset) - offset = bl->idx; + if (al->idx_asm < offset) + offset = al->idx; browser->b.nr_entries = browser->nr_entries; notes->options->hide_src_code = false; browser->b.seek(&browser->b, -offset, SEEK_CUR); - browser->b.top_idx = bl->idx - offset; - browser->b.index = bl->idx; + browser->b.top_idx = al->idx - offset; + browser->b.index = al->idx; } else { - if (bl->idx_asm < 0) { + if (al->idx_asm < 0) { ui_helpline__puts("Only available for assembly lines."); browser->b.seek(&browser->b, -offset, SEEK_CUR); return false; } - if (bl->idx_asm < offset) - offset = bl->idx_asm; + if (al->idx_asm < offset) + offset = al->idx_asm; browser->b.nr_entries = browser->nr_asm_entries; notes->options->hide_src_code = true; browser->b.seek(&browser->b, -offset, SEEK_CUR); - browser->b.top_idx = bl->idx_asm - offset; - browser->b.index = bl->idx_asm; + browser->b.top_idx = al->idx_asm - offset; + browser->b.index = al->idx_asm; } return true; @@ -1003,7 +979,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, if (perf_evsel__is_group_event(evsel)) nr_pcnt = evsel->nr_members; - err = symbol__annotate(sym, map, evsel, sizeof(struct browser_line), &browser.arch); + err = symbol__annotate(sym, map, evsel, 0, &browser.arch); if (err) { char msg[BUFSIZ]; symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); @@ -1018,15 +994,13 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, browser.start = map__rip_2objdump(map, sym->start); list_for_each_entry(al, ¬es->src->source, node) { - struct browser_line *bpos; size_t line_len = strlen(al->line); if (browser.b.width < line_len) browser.b.width = line_len; - bpos = browser_line(al); - bpos->idx = browser.nr_entries++; + al->idx = browser.nr_entries++; if (al->offset != -1) { - bpos->idx_asm = browser.nr_asm_entries++; + al->idx_asm = browser.nr_asm_entries++; /* * FIXME: short term bandaid to cope with assembly * routines that comes with labels in the same column @@ -1037,7 +1011,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, if (al->offset < (s64)size) notes->offsets[al->offset] = al; } else - bpos->idx_asm = -1; + al->idx_asm = -1; } annotation__mark_jump_targets(notes, sym); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index ab4a8b7710a06..2018a47790c7a 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -95,6 +95,8 @@ struct annotation_line { u64 cycles; size_t privsize; char *path; + u32 idx; + int idx_asm; int samples_nr; struct annotation_data samples[0]; }; From 0ca693b315aa6893c9d3552fa6a5d536c38b6c4a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 15:46:22 -0300 Subject: [PATCH 17/44] perf annotate: Move 'start' to struct annotation Another field that is not TUI specific. 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-jj3dwswndft5mln8hu9k0idv@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 5 ++--- tools/perf/util/annotate.h | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 50f8e671644f6..7ec441f93f7e4 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -35,7 +35,6 @@ struct annotate_browser { struct rb_node *curr_hot; struct annotation_line *selection; struct arch *arch; - u64 start; int nr_asm_entries; int nr_entries; bool searching_backwards; @@ -208,7 +207,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int int color = -1; if (!notes->options->use_offset) - addr += ab->start; + addr += notes->start; if (!notes->options->use_offset) { printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); @@ -991,7 +990,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, ui_helpline__push("Press ESC to exit"); - browser.start = map__rip_2objdump(map, sym->start); + notes->start = map__rip_2objdump(map, sym->start); list_for_each_entry(al, ¬es->src->source, node) { size_t line_len = strlen(al->line); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 2018a47790c7a..0424c127b0049 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -169,6 +169,7 @@ struct annotated_source { struct annotation { pthread_mutex_t lock; u64 max_coverage; + u64 start; struct annotation_options *options; struct annotation_line **offsets; int nr_events; From 1cf5f98a5edbb4b628349bea37da0aa259ded07c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 15:52:33 -0300 Subject: [PATCH 18/44] perf annotate: Move nr_{asm_}entries to struct annotation More non-TUI stuff. 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-yd4g6q0rngq4i49hz6iymtta@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 23 +++++++++++------------ tools/perf/util/annotate.h | 2 ++ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 7ec441f93f7e4..00b88349a3c27 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -35,8 +35,6 @@ struct annotate_browser { struct rb_node *curr_hot; struct annotation_line *selection; struct arch *arch; - int nr_asm_entries; - int nr_entries; bool searching_backwards; u8 addr_width; u8 jumps_width; @@ -470,7 +468,7 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) if (al->idx_asm < offset) offset = al->idx; - browser->b.nr_entries = browser->nr_entries; + browser->b.nr_entries = notes->nr_entries; notes->options->hide_src_code = false; browser->b.seek(&browser->b, -offset, SEEK_CUR); browser->b.top_idx = al->idx - offset; @@ -485,7 +483,7 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) if (al->idx_asm < offset) offset = al->idx_asm; - browser->b.nr_entries = browser->nr_asm_entries; + browser->b.nr_entries = notes->nr_asm_entries; notes->options->hide_src_code = true; browser->b.seek(&browser->b, -offset, SEEK_CUR); browser->b.top_idx = al->idx_asm - offset; @@ -495,10 +493,11 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) return true; } -static void annotate_browser__init_asm_mode(struct annotate_browser *browser) +static void ui_browser__init_asm_mode(struct ui_browser *browser) { - ui_browser__reset_index(&browser->b); - browser->b.nr_entries = browser->nr_asm_entries; + struct annotation *notes = browser__annotation(browser); + ui_browser__reset_index(browser); + browser->nr_entries = notes->nr_asm_entries; } #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64) @@ -854,7 +853,7 @@ static int annotate_browser__run(struct annotate_browser *browser, browser->b.height, browser->b.index, browser->b.top_idx, - browser->nr_asm_entries); + notes->nr_asm_entries); } continue; case K_ENTER: @@ -997,9 +996,9 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, if (browser.b.width < line_len) browser.b.width = line_len; - al->idx = browser.nr_entries++; + al->idx = notes->nr_entries++; if (al->offset != -1) { - al->idx_asm = browser.nr_asm_entries++; + al->idx_asm = notes->nr_asm_entries++; /* * FIXME: short term bandaid to cope with assembly * routines that comes with labels in the same column @@ -1020,12 +1019,12 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, browser.max_addr_width = hex_width(sym->end); browser.jumps_width = width_jumps(notes->max_jump_sources); notes->nr_events = nr_pcnt; - browser.b.nr_entries = browser.nr_entries; + browser.b.nr_entries = notes->nr_entries; browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ if (notes->options->hide_src_code) - annotate_browser__init_asm_mode(&browser); + ui_browser__init_asm_mode(&browser.b); annotate_browser__update_addr_width(&browser); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 0424c127b0049..0c34eb0bd7c84 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -175,6 +175,8 @@ struct annotation { int nr_events; int nr_jumps; int max_jump_sources; + int nr_entries; + int nr_asm_entries; bool have_cycles; struct annotated_source *src; }; From 5bc49f6120203c9fbe8e63fdcb9598e0ba615de7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 15:59:01 -0300 Subject: [PATCH 19/44] 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(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 00b88349a3c27..977c7e9fdadbd 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 330275680a1aa..b976e39516621 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 0c34eb0bd7c84..8a61ec9a52911 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); From 9761e86e36c0957e76c1b7c328953687a1a38655 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 16:18:21 -0300 Subject: [PATCH 20/44] perf annotate: Move the column widths from the TUI to generic lib This also will be used in other output formats, such as --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-86h6ftebc62ij1rx8q9zkpwk@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 45 +++++++++++++------------------ tools/perf/util/annotate.h | 7 +++++ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 977c7e9fdadbd..07d0d22680084 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -36,11 +36,6 @@ struct annotate_browser { struct annotation_line *selection; struct arch *arch; bool searching_backwards; - u8 addr_width; - u8 jumps_width; - u8 target_width; - u8 min_addr_width; - u8 max_addr_width; char search_bf[128]; }; @@ -194,10 +189,10 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int else if (al->offset == -1) { if (al->line_nr && notes->options->show_linenr) printed = scnprintf(bf, sizeof(bf), "%-*d ", - ab->addr_width + 1, al->line_nr); + notes->widths.addr + 1, al->line_nr); else printed = scnprintf(bf, sizeof(bf), "%*s ", - ab->addr_width, " "); + 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 { @@ -214,7 +209,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int if (notes->options->show_nr_jumps) { int prev; printed = scnprintf(bf, sizeof(bf), "%*d ", - ab->jumps_width, + notes->widths.jumps, al->jump_sources); prev = ui_browser__set_jumps_percent_color(browser, al->jump_sources, current_entry); @@ -223,10 +218,10 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int } printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", - ab->target_width, addr); + notes->widths.target, addr); } else { printed = scnprintf(bf, sizeof(bf), "%*s ", - ab->addr_width, " "); + notes->widths.addr, " "); } } @@ -322,12 +317,12 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); __ui_browser__line_arrow(browser, - pcnt_width + 2 + ab->addr_width + width, + pcnt_width + 2 + notes->widths.addr + width, from, to); if (is_fused(ab, cursor)) { ui_browser__mark_fused(browser, - pcnt_width + 3 + ab->addr_width + width, + pcnt_width + 3 + notes->widths.addr + width, from - 1, to > from ? true : false); } @@ -703,19 +698,17 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, return __annotate_browser__search_reverse(browser); } -static void annotate_browser__update_addr_width(struct annotate_browser *browser) +static void annotation__update_column_widths(struct annotation *notes) { - struct annotation *notes = browser__annotation(&browser->b); - if (notes->options->use_offset) - browser->target_width = browser->min_addr_width; + notes->widths.target = notes->widths.min_addr; else - browser->target_width = browser->max_addr_width; + notes->widths.target = notes->widths.max_addr; - browser->addr_width = browser->target_width; + notes->widths.addr = notes->widths.target; if (notes->options->show_nr_jumps) - browser->addr_width += browser->jumps_width + 1; + notes->widths.addr += notes->widths.jumps + 1; } static int annotate_browser__run(struct annotate_browser *browser, @@ -820,14 +813,14 @@ static int annotate_browser__run(struct annotate_browser *browser, continue; case 'o': notes->options->use_offset = !notes->options->use_offset; - annotate_browser__update_addr_width(browser); + annotation__update_column_widths(notes); continue; case 'j': notes->options->jump_arrows = !notes->options->jump_arrows; continue; case 'J': notes->options->show_nr_jumps = !notes->options->show_nr_jumps; - annotate_browser__update_addr_width(browser); + annotation__update_column_widths(notes); continue; case '/': if (annotate_browser__search(browser, delay_secs)) { @@ -884,7 +877,7 @@ static int annotate_browser__run(struct annotate_browser *browser, notes->options->show_nr_samples = false; else notes->options->show_total_period = true; - annotate_browser__update_addr_width(browser); + annotation__update_column_widths(notes); continue; case K_LEFT: case K_ESC: @@ -995,9 +988,9 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, annotation__mark_jump_targets(notes, sym); annotation__compute_ipc(notes, size); - browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); - browser.max_addr_width = hex_width(sym->end); - browser.jumps_width = width_jumps(notes->max_jump_sources); + 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); notes->nr_events = nr_pcnt; browser.b.nr_entries = notes->nr_entries; browser.b.entries = ¬es->src->source, @@ -1006,7 +999,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, if (notes->options->hide_src_code) ui_browser__init_asm_mode(&browser.b); - annotate_browser__update_addr_width(&browser); + annotation__update_column_widths(notes); ret = annotate_browser__run(&browser, evsel, hbt); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 8a61ec9a52911..0aa77c154fe31 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -178,6 +178,13 @@ struct annotation { int nr_entries; int nr_asm_entries; u16 max_line_len; + struct { + u8 addr; + u8 jumps; + u8 target; + u8 min_addr; + u8 max_addr; + } widths; bool have_cycles; struct annotated_source *src; }; From 7232bf7a8954e4f6558e6b74fb6a2403e7a3b7be Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 16:19:59 -0300 Subject: [PATCH 21/44] 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(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 07d0d22680084..ab4d004fc184a 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 b976e39516621..8a2fda80a2214 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 0aa77c154fe31..a8bea758490aa 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) { From b8b0d819858e1140e98ce858a0c839f3d03cb0f5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 16:26:29 -0300 Subject: [PATCH 22/44] 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(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index ab4d004fc184a..06ad5ecaa67a8 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 8a2fda80a2214..9c05b534f428c 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 a8bea758490aa..c4528e03a031b 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) { From ecda45bd6cfe0badda0e8215c5a008eaf7647716 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 16:54:11 -0300 Subject: [PATCH 23/44] 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(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 06ad5ecaa67a8..ab21739f27ae3 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 9c05b534f428c..7ad6400a0d4f7 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 c4528e03a031b..f93c805473f9f 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, From 2f025ea0bac2f99a2800f43f139f57c226d3b08b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 17:04:53 -0300 Subject: [PATCH 24/44] 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(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index ab21739f27ae3..05f79f36e9069 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 7ad6400a0d4f7..3bd6f9b0147f6 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 f93c805473f9f..83484e236f337 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); From c52202434de2bd3e0c447c6dce992266fd7fc589 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 17:52:53 -0300 Subject: [PATCH 25/44] perf ui browser: Add vprintf() method We'll need it for some callbacks for the upcoming annotation__line_print() routines. 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-t3qiobj4ua38xzsq8cyw9ky5@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browser.c | 7 ++++++- tools/perf/ui/browser.h | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index 63399af3049f8..33c30325885f3 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c @@ -56,12 +56,17 @@ void ui_browser__write_nstring(struct ui_browser *browser __maybe_unused, const slsmg_write_nstring(msg, width); } +void ui_browser__vprintf(struct ui_browser *browser __maybe_unused, const char *fmt, va_list args) +{ + slsmg_vprintf(fmt, args); +} + void ui_browser__printf(struct ui_browser *browser __maybe_unused, const char *fmt, ...) { va_list args; va_start(args, fmt); - slsmg_vprintf(fmt, args); + ui_browser__vprintf(browser, fmt, args); va_end(args); } diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h index 03e1734412b95..9e69c6a435148 100644 --- a/tools/perf/ui/browser.h +++ b/tools/perf/ui/browser.h @@ -3,6 +3,7 @@ #define _PERF_UI_BROWSER_H_ 1 #include +#include #define HE_COLORSET_TOP 50 #define HE_COLORSET_MEDIUM 51 @@ -40,6 +41,7 @@ void ui_browser__reset_index(struct ui_browser *browser); void ui_browser__gotorc(struct ui_browser *browser, int y, int x); void ui_browser__write_nstring(struct ui_browser *browser, const char *msg, unsigned int width); +void ui_browser__vprintf(struct ui_browser *browser, const char *fmt, va_list args); void ui_browser__printf(struct ui_browser *browser, const char *fmt, ...); void ui_browser__write_graph(struct ui_browser *browser, int graph); void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column, From 2ba5eca10486eeb37030f8bce27cecda3763502f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 17:54:36 -0300 Subject: [PATCH 26/44] 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(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 05f79f36e9069..9b77a016e299b 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 3bd6f9b0147f6..046feda110525 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 83484e236f337..84c99774bfed6 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); From a1e9b74cc2ef80131b9f955c0e1acc25285dc88c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 19:12:39 -0300 Subject: [PATCH 27/44] 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(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 9b77a016e299b..2b18c462b8822 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 046feda110525..45a52e2658c82 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 84c99774bfed6..27fcdacbb4978 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); From c298304bd747d6a0b733f0becb470ff07ead0317 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 23:14:51 -0300 Subject: [PATCH 28/44] 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(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 2b18c462b8822..bed647807d378 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 45a52e2658c82..11ad732115384 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 27fcdacbb4978..6fbb34b9bd778 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); From 9b80d1f946ee40923f7bf51c69cb3a6ac6097e4a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Mar 2018 10:39:24 -0300 Subject: [PATCH 29/44] perf annotate: Introduce annotation_line__filter() Out of the TUI logic that allows toggling the presentation of source code lines. Will 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-g0ckz9ajy6unswrv2iy39mxk@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 19 +++++++------------ tools/perf/util/annotate.h | 4 ++++ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index bed647807d378..74a26f4e9b060 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -48,14 +48,8 @@ static inline struct annotation *browser__annotation(struct ui_browser *browser) static bool disasm_line__filter(struct ui_browser *browser, void *entry) { struct annotation *notes = browser__annotation(browser); - - if (notes->options->hide_src_code) { - struct annotation_line *al = list_entry(entry, struct annotation_line, node); - - return al->offset == -1; - } - - return false; + struct annotation_line *al = list_entry(entry, struct annotation_line, node); + return annotation_line__filter(al, notes); } static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current) @@ -268,6 +262,7 @@ static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line static void annotate_browser__set_top(struct annotate_browser *browser, struct annotation_line *pos, u32 idx) { + struct annotation *notes = browser__annotation(&browser->b); unsigned back; ui_browser__refresh_dimensions(&browser->b); @@ -277,7 +272,7 @@ static void annotate_browser__set_top(struct annotate_browser *browser, while (browser->b.top_idx != 0 && back != 0) { pos = list_entry(pos->node.prev, struct annotation_line, node); - if (disasm_line__filter(&browser->b, &pos->node)) + if (annotation_line__filter(pos, notes)) continue; --browser->b.top_idx; @@ -440,7 +435,7 @@ struct disasm_line *annotate_browser__find_offset(struct annotate_browser *brows list_for_each_entry(pos, ¬es->src->source, al.node) { if (pos->al.offset == offset) return pos; - if (!disasm_line__filter(&browser->b, &pos->al.node)) + if (!annotation_line__filter(&pos->al, notes)) ++*idx; } @@ -477,7 +472,7 @@ struct annotation_line *annotate_browser__find_string(struct annotate_browser *b *idx = browser->b.index; list_for_each_entry_continue(al, ¬es->src->source, node) { - if (disasm_line__filter(&browser->b, &al->node)) + if (annotation_line__filter(al, notes)) continue; ++*idx; @@ -514,7 +509,7 @@ struct annotation_line *annotate_browser__find_string_reverse(struct annotate_br *idx = browser->b.index; list_for_each_entry_continue_reverse(al, ¬es->src->source, node) { - if (disasm_line__filter(&browser->b, &al->node)) + if (annotation_line__filter(al, notes)) continue; --*idx; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 6fbb34b9bd778..165845de1243b 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -215,6 +215,10 @@ static inline int annotation__pcnt_width(struct annotation *notes) return (notes->options->show_total_period ? 12 : 7) * notes->nr_events; } +static inline bool annotation_line__filter(struct annotation_line *al, struct annotation *notes) +{ + return notes->options->hide_src_code && al->offset == -1; +} void annotation__set_offsets(struct annotation *notes, s64 size); void annotation__compute_ipc(struct annotation *notes, size_t size); From befd2a38a632b1f27ad652fea67c8cf97ce59409 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 15 Mar 2018 23:44:34 -0300 Subject: [PATCH 30/44] 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(-) diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index 292809c3c0ca5..c29c7fc930235 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 ead6ae4549e53..e03f9bea93036 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 11ad732115384..98cf3e5380bcd 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 165845de1243b..cf32cbc879301 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, From 7f0b6fde3111aec82487662ccef5a4ebecb93381 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Mar 2018 14:33:38 -0300 Subject: [PATCH 31/44] 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(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index e03f9bea93036..fd5aac3fd9497 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 91da129756426..1a82f38671a86 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -1340,6 +1340,7 @@ int cmd_report(int argc, const char **argv) 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 113c298ed38ba..f39bd60d2708c 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 33c30325885f3..9f6ce29b83b43 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 9e69c6a435148..70057178ee348 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 74a26f4e9b060..916f237c1df80 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 @@ static int annotate_browser__run(struct annotate_browser *browser, 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 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, 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 98cf3e5380bcd..cfa641bc1df6e 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 @@ int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *ev 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 cf32cbc879301..3faa58045b226 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 */ From 3563289208ecef339853692ecbf8690084744b53 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Mar 2018 14:37:33 -0300 Subject: [PATCH 32/44] 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(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index cfa641bc1df6e..ea83b9754ab0b 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; From 864298f224f20fb7b981b05dd0f77315c75eb189 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Mar 2018 15:17:23 -0300 Subject: [PATCH 33/44] 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(+) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ea83b9754ab0b..7a6a85f9fea6d 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); From be316409e9819423fc965e11486e6631734520ba Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Mar 2018 15:58:35 -0300 Subject: [PATCH 34/44] perf annotate: Introduce --ignore-vmlinux command line option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is already present in 'perf top', albeit undocumented (will fix), and is useful to use /proc/kcore instead of vmlinux and then get what is really in place, not what the kernel starts with, before alternatives, ftrace .text patching, etc, see the differences: # 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 [root@jouet ~]# perf annotate --ignore-vmlinux --stdio2 _raw_spin_lock_irqsave _raw_spin_lock_irqsave() /proc/kcore Event: anon group { cycles, instructions } 0.00 3.17 nop 0.00 7.94 push %rbx 0.00 23.81 pushfq 7.69 12.70 pop %rax nop mov %rax,%rbx 7.69 3.17 cli nop 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 *ffffffff820e96b0 mov %rbx,%rax pop %rbx ← retq # Diff of the output of those commands: # perf annotate --stdio2 _raw_spin_lock_irqsave > /tmp/vmlinux # perf annotate --ignore-vmlinux --stdio2 _raw_spin_lock_irqsave > /tmp/kcore # diff -y /tmp/vmlinux /tmp/kcore _raw_spin_lock_irqsave() vmlinux | _raw_spin_lock_irqsave() /proc/kcore Event: anon group { cycles, instructions } Event: anon group { cycles, instructions } 0.00 3.17 → callq __fentry__ | 0.00 3.17 nop 0.00 7.94 push %rbx 0.00 7.94 push %rbx 7.69 36.51 → callq __page_file_index | 0.00 23.81 pushfq > 7.69 12.70 pop %rax > nop mov %rax,%rbx mov %rax,%rbx 7.69 3.17 → callq *ffffffff82225cd0 | 7.69 3.17 cli > nop xor %eax,%eax xor %eax,%eax mov $0x1,%edx mov $0x1,%edx 80.77 49.21 lock cmpxchg %edx,(%rdi) 80.77 49.21 lock cmpxchg %edx,(%rdi) test %eax,%eax test %eax,%eax ↓ jne 2b ↓ jne 2b 3.85 0.00 mov %rbx,%rax 3.85 0.00 mov %rbx,%rax pop %rbx pop %rbx ← retq ← retq 2b: mov %eax,%esi 2b: mov %eax,%esi → callq queued_spin_lock_slowpath| → callq *ffffffff820e96b0 mov %rbx,%rax mov %rbx,%rax pop %rbx pop %rbx ← retq ← retq # This should be further streamlined by doing both annotations and allowing the TUI to toggle initial/current, and show the patched instructions in a slightly different color. 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-wz8d269hxkcwaczr0r4rhyjg@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-annotate.txt | 3 +++ tools/perf/builtin-annotate.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index c29c7fc930235..749cc6055dac3 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt @@ -55,6 +55,9 @@ OPTIONS --vmlinux=:: vmlinux pathname. +--ignore-vmlinux:: + Ignore vmlinux files. + -m:: --modules:: Load module symbols. WARNING: use only with -k and LIVE kernel. diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index fd5aac3fd9497..51709a961496d 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -496,6 +496,8 @@ int cmd_annotate(int argc, const char **argv) 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_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux, + "don't load vmlinux even if found"), OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, From 91340c5184f316d687d4522b9aa41b56d58a49b0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Mar 2018 16:27:04 -0300 Subject: [PATCH 35/44] perf report: Introduce --ignore-vmlinux command line option We've had this in 'perf top' for quite a while, useful if one wishes to force using /proc/kcore to do annotation using the patched kernel instead of the ELF image it started from, aka vmlinux. 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-ircpvox4wzsv7gasrpb28fw9@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-report.txt | 3 +++ tools/perf/builtin-report.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index cba16d8a970e4..e1a660e60849f 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -296,6 +296,9 @@ OPTIONS --vmlinux=:: vmlinux pathname +--ignore-vmlinux:: + Ignore vmlinux files. + --kallsyms=:: kallsyms pathname diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1a82f38671a86..0f198f6d9b77b 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -1018,6 +1018,8 @@ int cmd_report(int argc, const char **argv) OPT_BOOLEAN(0, "mmaps", &report.mmaps_mode, "Display recorded tasks memory maps"), OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), + OPT_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux, + "don't load vmlinux even if found"), OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", "kallsyms pathname"), OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"), From d9bd766584491dbb6f96c85a27562eb1289b2ca9 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Mar 2018 16:57:47 -0300 Subject: [PATCH 36/44] 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(+) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 916f237c1df80..3834b264ba41b 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 @@ static int annotate_browser__run(struct annotate_browser *browser, } 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 7a6a85f9fea6d..a7111871440e3 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 3faa58045b226..365e9df888cf3 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, From 425859ff0de33a2362bec2a2c7ca486f87c13100 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 20 Mar 2018 11:03:30 -0300 Subject: [PATCH 37/44] 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(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a7111871440e3..666f62c58e1af 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, From 85a84e4f813912ab77d872ff6882dd7b435fbf4e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 20 Mar 2018 16:19:08 -0300 Subject: [PATCH 38/44] 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(-) diff --git a/tools/perf/arch/s390/annotate/instructions.c b/tools/perf/arch/s390/annotate/instructions.c index 46c21831f2ac5..cee4e2f7c0578 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 666f62c58e1af..3ff829d891780 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 @@ static int disasm_line__parse(char *line, const char **namep, char **rawp) 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 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil 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 365e9df888cf3..c0bf0554a9ea6 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); }; From 751b1783da784299b0509adb6a9cd3024cc4f837 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 20 Mar 2018 17:20:43 -0300 Subject: [PATCH 39/44] 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(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 3ff829d891780..c299881c640a6 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 c0bf0554a9ea6..ad8baafaf9f98 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 { From 83428f2fad48e16fddff0cb445cb4fedf5afe4ab Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 22 Mar 2018 00:57:32 +0100 Subject: [PATCH 40/44] perf python: Reference Py_None before returning it Python None objects are handled just like all the other objects with respect to their reference counting. Before returning Py_None, its reference count thus needs to be bumped. Signed-off-by: Petr Machata Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Petr Machata Link: http://lkml.kernel.org/r/b1e565ecccf68064d8d54f37db5d028dda8fa522.1521675563.git.petrm@mellanox.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/python.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index b956868fd4450..863b61478edd6 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -1004,8 +1004,10 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, return PyErr_NoMemory(); evsel = perf_evlist__event2evsel(evlist, event); - if (!evsel) + if (!evsel) { + Py_INCREF(Py_None); return Py_None; + } pevent->evsel = evsel; From 2eff061162819e00ec6379874ceb47caef17bcba Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 23 Mar 2018 10:12:33 -0300 Subject: [PATCH 41/44] 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(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 3834b264ba41b..d77896a995702 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 c299881c640a6..9524f322f5977 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 ad8baafaf9f98..ff7e3df31efa7 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 * From e4cc91b8027dbbb8a1f7c24cdecf58cd0b50375f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 23 Mar 2018 10:50:35 -0300 Subject: [PATCH 42/44] 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(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index d77896a995702..c02fb437ac8e9 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 @@ static int annotate_browser__run(struct annotate_browser *browser, 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 9524f322f5977..5fa270b24eeab 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, ','); From c448234cfe46ec5abc0014dca8b3b49989bffe9e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 23 Mar 2018 10:57:08 -0300 Subject: [PATCH 43/44] 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(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 5fa270b24eeab..f730e0cf8a260 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, ','); From 980b68ec0694f250e967cb18c5705ef5de10fdd5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 23 Mar 2018 12:26:39 -0300 Subject: [PATCH 44/44] 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(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f730e0cf8a260..3a428d7c59b92 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;