diff options
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: |