diff options
Diffstat (limited to 'tools/perf/builtin-annotate.c')
-rw-r--r-- | tools/perf/builtin-annotate.c | 109 |
1 files changed, 99 insertions, 10 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index f15731a3d438..51709a961496 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -40,10 +40,11 @@ | |||
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; |
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,78 @@ 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 | |||
205 | static bool has_annotation(struct perf_annotate *ann) | ||
206 | { | ||
207 | return ui__has_annotation() || ann->use_stdio2; | ||
208 | } | ||
209 | |||
149 | static int perf_evsel__add_sample(struct perf_evsel *evsel, | 210 | static int perf_evsel__add_sample(struct perf_evsel *evsel, |
150 | struct perf_sample *sample, | 211 | struct perf_sample *sample, |
151 | struct addr_location *al, | 212 | struct addr_location *al, |
152 | struct perf_annotate *ann) | 213 | struct perf_annotate *ann, |
214 | struct machine *machine) | ||
153 | { | 215 | { |
154 | struct hists *hists = evsel__hists(evsel); | 216 | struct hists *hists = evsel__hists(evsel); |
155 | struct hist_entry *he; | 217 | struct hist_entry *he; |
156 | int ret; | 218 | int ret; |
157 | 219 | ||
158 | if (ann->sym_hist_filter != NULL && | 220 | if ((!ann->has_br_stack || !has_annotation(ann)) && |
221 | ann->sym_hist_filter != NULL && | ||
159 | (al->sym == NULL || | 222 | (al->sym == NULL || |
160 | strcmp(ann->sym_hist_filter, al->sym->name) != 0)) { | 223 | strcmp(ann->sym_hist_filter, al->sym->name) != 0)) { |
161 | /* We're only interested in a symbol named sym_hist_filter */ | 224 | /* We're only interested in a symbol named sym_hist_filter */ |
@@ -178,6 +241,9 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, | |||
178 | */ | 241 | */ |
179 | process_branch_stack(sample->branch_stack, al, sample); | 242 | process_branch_stack(sample->branch_stack, al, sample); |
180 | 243 | ||
244 | if (ann->has_br_stack && has_annotation(ann)) | ||
245 | return process_branch_callback(evsel, sample, al, ann, machine); | ||
246 | |||
181 | he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); | 247 | he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); |
182 | if (he == NULL) | 248 | if (he == NULL) |
183 | return -ENOMEM; | 249 | return -ENOMEM; |
@@ -206,7 +272,8 @@ static int process_sample_event(struct perf_tool *tool, | |||
206 | if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap)) | 272 | if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap)) |
207 | goto out_put; | 273 | goto out_put; |
208 | 274 | ||
209 | if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al, ann)) { | 275 | if (!al.filtered && |
276 | perf_evsel__add_sample(evsel, sample, &al, ann, machine)) { | ||
210 | pr_warning("problem incrementing symbol count, " | 277 | pr_warning("problem incrementing symbol count, " |
211 | "skipping event\n"); | 278 | "skipping event\n"); |
212 | ret = -1; | 279 | ret = -1; |
@@ -220,8 +287,11 @@ static int hist_entry__tty_annotate(struct hist_entry *he, | |||
220 | struct perf_evsel *evsel, | 287 | struct perf_evsel *evsel, |
221 | struct perf_annotate *ann) | 288 | struct perf_annotate *ann) |
222 | { | 289 | { |
223 | return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, | 290 | if (!ann->use_stdio2) |
224 | 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); | ||
225 | } | 295 | } |
226 | 296 | ||
227 | static void hists__find_annotations(struct hists *hists, | 297 | static void hists__find_annotations(struct hists *hists, |
@@ -238,6 +308,10 @@ static void hists__find_annotations(struct hists *hists, | |||
238 | if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) | 308 | if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) |
239 | goto find_next; | 309 | goto find_next; |
240 | 310 | ||
311 | if (ann->sym_hist_filter && | ||
312 | (strcmp(he->ms.sym->name, ann->sym_hist_filter) != 0)) | ||
313 | goto find_next; | ||
314 | |||
241 | notes = symbol__annotation(he->ms.sym); | 315 | notes = symbol__annotation(he->ms.sym); |
242 | if (notes->src == NULL) { | 316 | if (notes->src == NULL) { |
243 | find_next: | 317 | find_next: |
@@ -269,6 +343,7 @@ find_next: | |||
269 | nd = rb_next(nd); | 343 | nd = rb_next(nd); |
270 | } else if (use_browser == 1) { | 344 | } else if (use_browser == 1) { |
271 | key = hist_entry__tui_annotate(he, evsel, NULL); | 345 | key = hist_entry__tui_annotate(he, evsel, NULL); |
346 | |||
272 | switch (key) { | 347 | switch (key) { |
273 | case -1: | 348 | case -1: |
274 | if (!ann->skip_missing) | 349 | if (!ann->skip_missing) |
@@ -420,6 +495,9 @@ int cmd_annotate(int argc, const char **argv) | |||
420 | OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"), | 495 | OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"), |
421 | OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), | 496 | OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), |
422 | 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"), | ||
499 | OPT_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux, | ||
500 | "don't load vmlinux even if found"), | ||
423 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 501 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
424 | "file", "vmlinux pathname"), | 502 | "file", "vmlinux pathname"), |
425 | OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, | 503 | OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, |
@@ -489,20 +567,22 @@ int cmd_annotate(int argc, const char **argv) | |||
489 | if (annotate.session == NULL) | 567 | if (annotate.session == NULL) |
490 | return -1; | 568 | return -1; |
491 | 569 | ||
570 | annotate.has_br_stack = perf_header__has_feat(&annotate.session->header, | ||
571 | HEADER_BRANCH_STACK); | ||
572 | |||
492 | ret = symbol__annotation_init(); | 573 | ret = symbol__annotation_init(); |
493 | if (ret < 0) | 574 | if (ret < 0) |
494 | goto out_delete; | 575 | goto out_delete; |
495 | 576 | ||
577 | annotation_config__init(); | ||
578 | |||
496 | symbol_conf.try_vmlinux_path = true; | 579 | symbol_conf.try_vmlinux_path = true; |
497 | 580 | ||
498 | ret = symbol__init(&annotate.session->header.env); | 581 | ret = symbol__init(&annotate.session->header.env); |
499 | if (ret < 0) | 582 | if (ret < 0) |
500 | goto out_delete; | 583 | goto out_delete; |
501 | 584 | ||
502 | if (setup_sorting(NULL) < 0) | 585 | if (annotate.use_stdio || annotate.use_stdio2) |
503 | usage_with_options(annotate_usage, options); | ||
504 | |||
505 | if (annotate.use_stdio) | ||
506 | use_browser = 0; | 586 | use_browser = 0; |
507 | else if (annotate.use_tui) | 587 | else if (annotate.use_tui) |
508 | use_browser = 1; | 588 | use_browser = 1; |
@@ -511,6 +591,15 @@ int cmd_annotate(int argc, const char **argv) | |||
511 | 591 | ||
512 | setup_browser(true); | 592 | setup_browser(true); |
513 | 593 | ||
594 | if ((use_browser == 1 || annotate.use_stdio2) && annotate.has_br_stack) { | ||
595 | sort__mode = SORT_MODE__BRANCH; | ||
596 | if (setup_sorting(annotate.session->evlist) < 0) | ||
597 | usage_with_options(annotate_usage, options); | ||
598 | } else { | ||
599 | if (setup_sorting(NULL) < 0) | ||
600 | usage_with_options(annotate_usage, options); | ||
601 | } | ||
602 | |||
514 | ret = __cmd_annotate(&annotate); | 603 | ret = __cmd_annotate(&annotate); |
515 | 604 | ||
516 | out_delete: | 605 | out_delete: |