diff options
author | Jin Yao <yao.jin@linux.intel.com> | 2018-02-27 04:38:47 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2018-03-08 09:30:52 -0500 |
commit | bb848c14f80d93059cb10b1e1446cc6823d77142 (patch) | |
tree | f5f0467d7f9be842dbb0323244ff004b0a56de3d /tools/perf/builtin-annotate.c | |
parent | ea85ab24c502720d2eb3dec30bedb6df06d4900b (diff) |
perf annotate: Support to display the IPC/Cycle in TUI mode
Unlike the perf report interactive annotate mode, the perf annotate
doesn't display the IPC/Cycle even if branch info is recorded in perf
data file.
perf record -b ...
perf annotate function
It should show IPC/cycle, but it doesn't.
This patch lets perf annotate support the displaying of IPC/Cycle if
branch info is in perf data.
For example,
perf annotate compute_flag
Percent│ IPC Cycle
│
│
│ Disassembly of section .text:
│
│ 0000000000400640 <compute_flag>:
│ compute_flag():
│ volatile int count;
│ static unsigned int s_randseed;
│
│ __attribute__((noinline))
│ int compute_flag()
│ {
22.96 │1.18 584 sub $0x8,%rsp
│ int i;
│
│ i = rand() % 2;
23.02 │1.18 1 → callq rand@plt
│
│ return i;
27.05 │3.37 mov %eax,%edx
│ }
│3.37 add $0x8,%rsp
│ {
│ int i;
│
│ i = rand() % 2;
│
│ return i;
│3.37 shr $0x1f,%edx
│3.37 add %edx,%eax
│3.37 and $0x1,%eax
│3.37 sub %edx,%eax
│ }
26.97 │3.37 2 ← retq
Note that, this patch only supports TUI mode. For stdio, now it just keeps
original behavior. Will support it in a follow-up patch.
$ perf annotate compute_flag --stdio
Percent | Source code & Disassembly of div for cycles:ppp (7993 samples)
------------------------------------------------------------------------------
:
:
:
: Disassembly of section .text:
:
: 0000000000400640 <compute_flag>:
: compute_flag():
: volatile int count;
: static unsigned int s_randseed;
:
: __attribute__((noinline))
: int compute_flag()
: {
0.29 : 400640: sub $0x8,%rsp # +100.00%
: int i;
:
: i = rand() % 2;
42.93 : 400644: callq 400490 <rand@plt> # -100.00% (p:100.00%)
:
: return i;
0.10 : 400649: mov %eax,%edx # +100.00%
: }
0.94 : 40064b: add $0x8,%rsp
: {
: int i;
:
: i = rand() % 2;
:
: return i;
27.02 : 40064f: shr $0x1f,%edx
0.15 : 400652: add %edx,%eax
1.24 : 400654: and $0x1,%eax
2.08 : 400657: sub %edx,%eax
: }
25.26 : 400659: retq # -100.00% (p:100.00%)
Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Acked-by: Andi Kleen <ak@linux.intel.com>
Link: http://lkml.kernel.org/r/20180223170210.GC7045@tassilo.jf.intel.com
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1519724327-7773-1-git-send-email-yao.jin@linux.intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-annotate.c')
-rw-r--r-- | tools/perf/builtin-annotate.c | 88 |
1 files changed, 82 insertions, 6 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index f15731a3d438..ead6ae4549e5 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -44,6 +44,7 @@ struct perf_annotate { | |||
44 | bool full_paths; | 44 | bool full_paths; |
45 | bool print_line; | 45 | bool print_line; |
46 | bool skip_missing; | 46 | bool skip_missing; |
47 | bool has_br_stack; | ||
47 | const char *sym_hist_filter; | 48 | const char *sym_hist_filter; |
48 | const char *cpu_list; | 49 | const char *cpu_list; |
49 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 50 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
@@ -146,16 +147,73 @@ static void process_branch_stack(struct branch_stack *bs, struct addr_location * | |||
146 | free(bi); | 147 | free(bi); |
147 | } | 148 | } |
148 | 149 | ||
150 | static int hist_iter__branch_callback(struct hist_entry_iter *iter, | ||
151 | struct addr_location *al __maybe_unused, | ||
152 | bool single __maybe_unused, | ||
153 | void *arg __maybe_unused) | ||
154 | { | ||
155 | struct hist_entry *he = iter->he; | ||
156 | struct branch_info *bi; | ||
157 | struct perf_sample *sample = iter->sample; | ||
158 | struct perf_evsel *evsel = iter->evsel; | ||
159 | int err; | ||
160 | |||
161 | hist__account_cycles(sample->branch_stack, al, sample, false); | ||
162 | |||
163 | bi = he->branch_info; | ||
164 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel->idx); | ||
165 | |||
166 | if (err) | ||
167 | goto out; | ||
168 | |||
169 | err = addr_map_symbol__inc_samples(&bi->to, sample, evsel->idx); | ||
170 | |||
171 | out: | ||
172 | return err; | ||
173 | } | ||
174 | |||
175 | static int process_branch_callback(struct perf_evsel *evsel, | ||
176 | struct perf_sample *sample, | ||
177 | struct addr_location *al __maybe_unused, | ||
178 | struct perf_annotate *ann, | ||
179 | struct machine *machine) | ||
180 | { | ||
181 | struct hist_entry_iter iter = { | ||
182 | .evsel = evsel, | ||
183 | .sample = sample, | ||
184 | .add_entry_cb = hist_iter__branch_callback, | ||
185 | .hide_unresolved = symbol_conf.hide_unresolved, | ||
186 | .ops = &hist_iter_branch, | ||
187 | }; | ||
188 | |||
189 | struct addr_location a; | ||
190 | int ret; | ||
191 | |||
192 | if (machine__resolve(machine, &a, sample) < 0) | ||
193 | return -1; | ||
194 | |||
195 | if (a.sym == NULL) | ||
196 | return 0; | ||
197 | |||
198 | if (a.map != NULL) | ||
199 | a.map->dso->hit = 1; | ||
200 | |||
201 | ret = hist_entry_iter__add(&iter, &a, PERF_MAX_STACK_DEPTH, ann); | ||
202 | return ret; | ||
203 | } | ||
204 | |||
149 | static int perf_evsel__add_sample(struct perf_evsel *evsel, | 205 | static int perf_evsel__add_sample(struct perf_evsel *evsel, |
150 | struct perf_sample *sample, | 206 | struct perf_sample *sample, |
151 | struct addr_location *al, | 207 | struct addr_location *al, |
152 | struct perf_annotate *ann) | 208 | struct perf_annotate *ann, |
209 | struct machine *machine) | ||
153 | { | 210 | { |
154 | struct hists *hists = evsel__hists(evsel); | 211 | struct hists *hists = evsel__hists(evsel); |
155 | struct hist_entry *he; | 212 | struct hist_entry *he; |
156 | int ret; | 213 | int ret; |
157 | 214 | ||
158 | if (ann->sym_hist_filter != NULL && | 215 | if ((!ann->has_br_stack || !ui__has_annotation()) && |
216 | ann->sym_hist_filter != NULL && | ||
159 | (al->sym == NULL || | 217 | (al->sym == NULL || |
160 | strcmp(ann->sym_hist_filter, al->sym->name) != 0)) { | 218 | strcmp(ann->sym_hist_filter, al->sym->name) != 0)) { |
161 | /* We're only interested in a symbol named sym_hist_filter */ | 219 | /* We're only interested in a symbol named sym_hist_filter */ |
@@ -178,6 +236,9 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, | |||
178 | */ | 236 | */ |
179 | process_branch_stack(sample->branch_stack, al, sample); | 237 | process_branch_stack(sample->branch_stack, al, sample); |
180 | 238 | ||
239 | if (ann->has_br_stack && ui__has_annotation()) | ||
240 | return process_branch_callback(evsel, sample, al, ann, machine); | ||
241 | |||
181 | he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); | 242 | he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); |
182 | if (he == NULL) | 243 | if (he == NULL) |
183 | return -ENOMEM; | 244 | return -ENOMEM; |
@@ -206,7 +267,8 @@ static int process_sample_event(struct perf_tool *tool, | |||
206 | if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap)) | 267 | if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap)) |
207 | goto out_put; | 268 | goto out_put; |
208 | 269 | ||
209 | if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al, ann)) { | 270 | if (!al.filtered && |
271 | perf_evsel__add_sample(evsel, sample, &al, ann, machine)) { | ||
210 | pr_warning("problem incrementing symbol count, " | 272 | pr_warning("problem incrementing symbol count, " |
211 | "skipping event\n"); | 273 | "skipping event\n"); |
212 | ret = -1; | 274 | ret = -1; |
@@ -238,6 +300,10 @@ static void hists__find_annotations(struct hists *hists, | |||
238 | if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) | 300 | if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) |
239 | goto find_next; | 301 | goto find_next; |
240 | 302 | ||
303 | if (ann->sym_hist_filter && | ||
304 | (strcmp(he->ms.sym->name, ann->sym_hist_filter) != 0)) | ||
305 | goto find_next; | ||
306 | |||
241 | notes = symbol__annotation(he->ms.sym); | 307 | notes = symbol__annotation(he->ms.sym); |
242 | if (notes->src == NULL) { | 308 | if (notes->src == NULL) { |
243 | find_next: | 309 | find_next: |
@@ -269,6 +335,7 @@ find_next: | |||
269 | nd = rb_next(nd); | 335 | nd = rb_next(nd); |
270 | } else if (use_browser == 1) { | 336 | } else if (use_browser == 1) { |
271 | key = hist_entry__tui_annotate(he, evsel, NULL); | 337 | key = hist_entry__tui_annotate(he, evsel, NULL); |
338 | |||
272 | switch (key) { | 339 | switch (key) { |
273 | case -1: | 340 | case -1: |
274 | if (!ann->skip_missing) | 341 | if (!ann->skip_missing) |
@@ -489,6 +556,9 @@ int cmd_annotate(int argc, const char **argv) | |||
489 | if (annotate.session == NULL) | 556 | if (annotate.session == NULL) |
490 | return -1; | 557 | return -1; |
491 | 558 | ||
559 | annotate.has_br_stack = perf_header__has_feat(&annotate.session->header, | ||
560 | HEADER_BRANCH_STACK); | ||
561 | |||
492 | ret = symbol__annotation_init(); | 562 | ret = symbol__annotation_init(); |
493 | if (ret < 0) | 563 | if (ret < 0) |
494 | goto out_delete; | 564 | goto out_delete; |
@@ -499,9 +569,6 @@ int cmd_annotate(int argc, const char **argv) | |||
499 | if (ret < 0) | 569 | if (ret < 0) |
500 | goto out_delete; | 570 | goto out_delete; |
501 | 571 | ||
502 | if (setup_sorting(NULL) < 0) | ||
503 | usage_with_options(annotate_usage, options); | ||
504 | |||
505 | if (annotate.use_stdio) | 572 | if (annotate.use_stdio) |
506 | use_browser = 0; | 573 | use_browser = 0; |
507 | else if (annotate.use_tui) | 574 | else if (annotate.use_tui) |
@@ -511,6 +578,15 @@ int cmd_annotate(int argc, const char **argv) | |||
511 | 578 | ||
512 | setup_browser(true); | 579 | setup_browser(true); |
513 | 580 | ||
581 | if (use_browser == 1 && annotate.has_br_stack) { | ||
582 | sort__mode = SORT_MODE__BRANCH; | ||
583 | if (setup_sorting(annotate.session->evlist) < 0) | ||
584 | usage_with_options(annotate_usage, options); | ||
585 | } else { | ||
586 | if (setup_sorting(NULL) < 0) | ||
587 | usage_with_options(annotate_usage, options); | ||
588 | } | ||
589 | |||
514 | ret = __cmd_annotate(&annotate); | 590 | ret = __cmd_annotate(&annotate); |
515 | 591 | ||
516 | out_delete: | 592 | out_delete: |