diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2018-03-15 22:44:34 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2018-03-21 11:53:26 -0400 |
commit | befd2a38a632b1f27ad652fea67c8cf97ce59409 (patch) | |
tree | 8389138ba03f646ed5467ef39c1d8b905465cd96 | |
parent | 9b80d1f946ee40923f7bf51c69cb3a6ac6097e4a (diff) |
perf annotate: Introduce the --stdio2 output mode
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 <load0>:
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 <yao.jin@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>
Link: https://lkml.kernel.org/n/tip-6cte5o8z84mbivbvqlg14uh1@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/Documentation/perf-annotate.txt | 2 | ||||
-rw-r--r-- | tools/perf/builtin-annotate.c | 23 | ||||
-rw-r--r-- | tools/perf/util/annotate.c | 92 | ||||
-rw-r--r-- | 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 292809c3c0ca..c29c7fc93023 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt | |||
@@ -69,6 +69,8 @@ OPTIONS | |||
69 | 69 | ||
70 | --stdio:: Use the stdio interface. | 70 | --stdio:: Use the stdio interface. |
71 | 71 | ||
72 | --stdio2:: Use the stdio2 interface, non-interactive, uses the TUI formatting. | ||
73 | |||
72 | --stdio-color=<mode>:: | 74 | --stdio-color=<mode>:: |
73 | 'always', 'never' or 'auto', allowing configuring color output | 75 | 'always', 'never' or 'auto', allowing configuring color output |
74 | via the command line, in addition to via "color.ui" .perfconfig. | 76 | via the command line, in addition to via "color.ui" .perfconfig. |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index ead6ae4549e5..e03f9bea9303 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -40,7 +40,7 @@ | |||
40 | struct perf_annotate { | 40 | struct perf_annotate { |
41 | struct perf_tool tool; | 41 | struct perf_tool tool; |
42 | struct perf_session *session; | 42 | struct perf_session *session; |
43 | bool use_tui, use_stdio, use_gtk; | 43 | bool use_tui, use_stdio, use_stdio2, use_gtk; |
44 | bool full_paths; | 44 | bool full_paths; |
45 | bool print_line; | 45 | bool print_line; |
46 | bool skip_missing; | 46 | bool skip_missing; |
@@ -202,6 +202,11 @@ static int process_branch_callback(struct perf_evsel *evsel, | |||
202 | return ret; | 202 | return ret; |
203 | } | 203 | } |
204 | 204 | ||
205 | static bool has_annotation(struct perf_annotate *ann) | ||
206 | { | ||
207 | return ui__has_annotation() || ann->use_stdio2; | ||
208 | } | ||
209 | |||
205 | static int perf_evsel__add_sample(struct perf_evsel *evsel, | 210 | static int perf_evsel__add_sample(struct perf_evsel *evsel, |
206 | struct perf_sample *sample, | 211 | struct perf_sample *sample, |
207 | struct addr_location *al, | 212 | struct addr_location *al, |
@@ -212,7 +217,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, | |||
212 | struct hist_entry *he; | 217 | struct hist_entry *he; |
213 | int ret; | 218 | int ret; |
214 | 219 | ||
215 | if ((!ann->has_br_stack || !ui__has_annotation()) && | 220 | if ((!ann->has_br_stack || !has_annotation(ann)) && |
216 | ann->sym_hist_filter != NULL && | 221 | ann->sym_hist_filter != NULL && |
217 | (al->sym == NULL || | 222 | (al->sym == NULL || |
218 | strcmp(ann->sym_hist_filter, al->sym->name) != 0)) { | 223 | strcmp(ann->sym_hist_filter, al->sym->name) != 0)) { |
@@ -236,7 +241,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, | |||
236 | */ | 241 | */ |
237 | process_branch_stack(sample->branch_stack, al, sample); | 242 | process_branch_stack(sample->branch_stack, al, sample); |
238 | 243 | ||
239 | if (ann->has_br_stack && ui__has_annotation()) | 244 | if (ann->has_br_stack && has_annotation(ann)) |
240 | return process_branch_callback(evsel, sample, al, ann, machine); | 245 | return process_branch_callback(evsel, sample, al, ann, machine); |
241 | 246 | ||
242 | he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); | 247 | 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, | |||
282 | struct perf_evsel *evsel, | 287 | struct perf_evsel *evsel, |
283 | struct perf_annotate *ann) | 288 | struct perf_annotate *ann) |
284 | { | 289 | { |
285 | return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, | 290 | if (!ann->use_stdio2) |
286 | ann->print_line, ann->full_paths, 0, 0); | 291 | return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, |
292 | ann->print_line, ann->full_paths, 0, 0); | ||
293 | return symbol__tty_annotate2(he->ms.sym, he->ms.map, evsel, | ||
294 | ann->print_line, ann->full_paths); | ||
287 | } | 295 | } |
288 | 296 | ||
289 | static void hists__find_annotations(struct hists *hists, | 297 | static void hists__find_annotations(struct hists *hists, |
@@ -487,6 +495,7 @@ int cmd_annotate(int argc, const char **argv) | |||
487 | OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"), | 495 | OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"), |
488 | OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), | 496 | OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), |
489 | OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"), | 497 | OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"), |
498 | OPT_BOOLEAN(0, "stdio2", &annotate.use_stdio2, "Use the stdio interface"), | ||
490 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 499 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
491 | "file", "vmlinux pathname"), | 500 | "file", "vmlinux pathname"), |
492 | OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, | 501 | OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, |
@@ -569,7 +578,7 @@ int cmd_annotate(int argc, const char **argv) | |||
569 | if (ret < 0) | 578 | if (ret < 0) |
570 | goto out_delete; | 579 | goto out_delete; |
571 | 580 | ||
572 | if (annotate.use_stdio) | 581 | if (annotate.use_stdio || annotate.use_stdio2) |
573 | use_browser = 0; | 582 | use_browser = 0; |
574 | else if (annotate.use_tui) | 583 | else if (annotate.use_tui) |
575 | use_browser = 1; | 584 | use_browser = 1; |
@@ -578,7 +587,7 @@ int cmd_annotate(int argc, const char **argv) | |||
578 | 587 | ||
579 | setup_browser(true); | 588 | setup_browser(true); |
580 | 589 | ||
581 | if (use_browser == 1 && annotate.has_br_stack) { | 590 | if ((use_browser == 1 || annotate.use_stdio2) && annotate.has_br_stack) { |
582 | sort__mode = SORT_MODE__BRANCH; | 591 | sort__mode = SORT_MODE__BRANCH; |
583 | if (setup_sorting(annotate.session->evlist) < 0) | 592 | if (setup_sorting(annotate.session->evlist) < 0) |
584 | usage_with_options(annotate_usage, options); | 593 | usage_with_options(annotate_usage, options); |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 11ad73211538..98cf3e5380bc 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -1965,6 +1965,72 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
1965 | return more; | 1965 | return more; |
1966 | } | 1966 | } |
1967 | 1967 | ||
1968 | static void FILE__set_percent_color(void *fp __maybe_unused, | ||
1969 | double percent __maybe_unused, | ||
1970 | bool current __maybe_unused) | ||
1971 | { | ||
1972 | } | ||
1973 | |||
1974 | static int FILE__set_jumps_percent_color(void *fp __maybe_unused, | ||
1975 | int nr __maybe_unused, bool current __maybe_unused) | ||
1976 | { | ||
1977 | return 0; | ||
1978 | } | ||
1979 | |||
1980 | static int FILE__set_color(void *fp __maybe_unused, int color __maybe_unused) | ||
1981 | { | ||
1982 | return 0; | ||
1983 | } | ||
1984 | |||
1985 | static void FILE__printf(void *fp, const char *fmt, ...) | ||
1986 | { | ||
1987 | va_list args; | ||
1988 | |||
1989 | va_start(args, fmt); | ||
1990 | vfprintf(fp, fmt, args); | ||
1991 | va_end(args); | ||
1992 | } | ||
1993 | |||
1994 | static void FILE__write_graph(void *fp, int graph) | ||
1995 | { | ||
1996 | const char *s; | ||
1997 | switch (graph) { | ||
1998 | |||
1999 | case DARROW_CHAR: s = "↓"; break; | ||
2000 | case UARROW_CHAR: s = "↑"; break; | ||
2001 | case LARROW_CHAR: s = "←"; break; | ||
2002 | case RARROW_CHAR: s = "→"; break; | ||
2003 | default: s = "?"; break; | ||
2004 | } | ||
2005 | |||
2006 | fputs(s, fp); | ||
2007 | } | ||
2008 | |||
2009 | int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) | ||
2010 | { | ||
2011 | struct annotation *notes = symbol__annotation(sym); | ||
2012 | struct annotation_write_ops ops = { | ||
2013 | .first_line = true, | ||
2014 | .obj = fp, | ||
2015 | .set_color = FILE__set_color, | ||
2016 | .set_percent_color = FILE__set_percent_color, | ||
2017 | .set_jumps_percent_color = FILE__set_jumps_percent_color, | ||
2018 | .printf = FILE__printf, | ||
2019 | .write_graph = FILE__write_graph, | ||
2020 | }; | ||
2021 | struct annotation_line *al; | ||
2022 | |||
2023 | list_for_each_entry(al, ¬es->src->source, node) { | ||
2024 | if (annotation_line__filter(al, notes)) | ||
2025 | continue; | ||
2026 | annotation_line__write(al, notes, &ops); | ||
2027 | fputc('\n', fp); | ||
2028 | ops.first_line = false; | ||
2029 | } | ||
2030 | |||
2031 | return 0; | ||
2032 | } | ||
2033 | |||
1968 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx) | 2034 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx) |
1969 | { | 2035 | { |
1970 | struct annotation *notes = symbol__annotation(sym); | 2036 | struct annotation *notes = symbol__annotation(sym); |
@@ -2165,6 +2231,32 @@ static void symbol__calc_lines(struct symbol *sym, struct map *map, | |||
2165 | annotation__calc_lines(notes, map, root, start); | 2231 | annotation__calc_lines(notes, map, root, start); |
2166 | } | 2232 | } |
2167 | 2233 | ||
2234 | int symbol__tty_annotate2(struct symbol *sym, struct map *map, | ||
2235 | struct perf_evsel *evsel, bool print_lines, | ||
2236 | bool full_paths) | ||
2237 | { | ||
2238 | struct dso *dso = map->dso; | ||
2239 | struct rb_root source_line = RB_ROOT; | ||
2240 | struct annotation_options opts = { | ||
2241 | .use_offset = true, | ||
2242 | }; | ||
2243 | |||
2244 | if (symbol__annotate2(sym, map, evsel, &opts, NULL) < 0) | ||
2245 | return -1; | ||
2246 | |||
2247 | if (print_lines) { | ||
2248 | srcline_full_filename = full_paths; | ||
2249 | symbol__calc_lines(sym, map, &source_line); | ||
2250 | print_summary(&source_line, dso->long_name); | ||
2251 | } | ||
2252 | |||
2253 | symbol__annotate_fprintf2(sym, stdout); | ||
2254 | |||
2255 | annotated_source__purge(symbol__annotation(sym)->src); | ||
2256 | |||
2257 | return 0; | ||
2258 | } | ||
2259 | |||
2168 | int symbol__tty_annotate(struct symbol *sym, struct map *map, | 2260 | int symbol__tty_annotate(struct symbol *sym, struct map *map, |
2169 | struct perf_evsel *evsel, bool print_lines, | 2261 | struct perf_evsel *evsel, bool print_lines, |
2170 | bool full_paths, int min_pcnt, int max_lines) | 2262 | bool full_paths, int min_pcnt, int max_lines) |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 165845de1243..cf32cbc87930 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -281,6 +281,7 @@ int symbol__strerror_disassemble(struct symbol *sym, struct map *map, | |||
281 | int symbol__annotate_printf(struct symbol *sym, struct map *map, | 281 | int symbol__annotate_printf(struct symbol *sym, struct map *map, |
282 | struct perf_evsel *evsel, bool full_paths, | 282 | struct perf_evsel *evsel, bool full_paths, |
283 | int min_pcnt, int max_lines, int context); | 283 | int min_pcnt, int max_lines, int context); |
284 | int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp); | ||
284 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); | 285 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); |
285 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); | 286 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); |
286 | void annotated_source__purge(struct annotated_source *as); | 287 | void annotated_source__purge(struct annotated_source *as); |
@@ -291,6 +292,10 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, | |||
291 | struct perf_evsel *evsel, bool print_lines, | 292 | struct perf_evsel *evsel, bool print_lines, |
292 | bool full_paths, int min_pcnt, int max_lines); | 293 | bool full_paths, int min_pcnt, int max_lines); |
293 | 294 | ||
295 | int symbol__tty_annotate2(struct symbol *sym, struct map *map, | ||
296 | struct perf_evsel *evsel, bool print_lines, | ||
297 | bool full_paths); | ||
298 | |||
294 | #ifdef HAVE_SLANG_SUPPORT | 299 | #ifdef HAVE_SLANG_SUPPORT |
295 | int symbol__tui_annotate(struct symbol *sym, struct map *map, | 300 | int symbol__tui_annotate(struct symbol *sym, struct map *map, |
296 | struct perf_evsel *evsel, | 301 | struct perf_evsel *evsel, |