| .. | .. |
|---|
| 8 | 8 | */ |
|---|
| 9 | 9 | #include "builtin.h" |
|---|
| 10 | 10 | |
|---|
| 11 | | -#include "util/util.h" |
|---|
| 12 | 11 | #include "util/color.h" |
|---|
| 13 | 12 | #include <linux/list.h> |
|---|
| 14 | 13 | #include "util/cache.h" |
|---|
| 15 | 14 | #include <linux/rbtree.h> |
|---|
| 15 | +#include <linux/zalloc.h> |
|---|
| 16 | 16 | #include "util/symbol.h" |
|---|
| 17 | 17 | |
|---|
| 18 | 18 | #include "perf.h" |
|---|
| .. | .. |
|---|
| 24 | 24 | #include "util/event.h" |
|---|
| 25 | 25 | #include <subcmd/parse-options.h> |
|---|
| 26 | 26 | #include "util/parse-events.h" |
|---|
| 27 | | -#include "util/thread.h" |
|---|
| 28 | 27 | #include "util/sort.h" |
|---|
| 29 | 28 | #include "util/hist.h" |
|---|
| 29 | +#include "util/dso.h" |
|---|
| 30 | +#include "util/machine.h" |
|---|
| 31 | +#include "util/map.h" |
|---|
| 30 | 32 | #include "util/session.h" |
|---|
| 31 | 33 | #include "util/tool.h" |
|---|
| 32 | 34 | #include "util/data.h" |
|---|
| 33 | 35 | #include "arch/common.h" |
|---|
| 34 | 36 | #include "util/block-range.h" |
|---|
| 37 | +#include "util/map_symbol.h" |
|---|
| 38 | +#include "util/branch.h" |
|---|
| 35 | 39 | |
|---|
| 36 | 40 | #include <dlfcn.h> |
|---|
| 37 | 41 | #include <errno.h> |
|---|
| 38 | 42 | #include <linux/bitmap.h> |
|---|
| 43 | +#include <linux/err.h> |
|---|
| 39 | 44 | |
|---|
| 40 | 45 | struct perf_annotate { |
|---|
| 41 | 46 | struct perf_tool tool; |
|---|
| .. | .. |
|---|
| 78 | 83 | struct addr_map_symbol *end, |
|---|
| 79 | 84 | struct branch_flags *flags) |
|---|
| 80 | 85 | { |
|---|
| 81 | | - struct symbol *sym = start->sym; |
|---|
| 86 | + struct symbol *sym = start->ms.sym; |
|---|
| 82 | 87 | struct annotation *notes = sym ? symbol__annotation(sym) : NULL; |
|---|
| 83 | 88 | struct block_range_iter iter; |
|---|
| 84 | 89 | struct block_range *entry; |
|---|
| .. | .. |
|---|
| 155 | 160 | struct hist_entry *he = iter->he; |
|---|
| 156 | 161 | struct branch_info *bi; |
|---|
| 157 | 162 | struct perf_sample *sample = iter->sample; |
|---|
| 158 | | - struct perf_evsel *evsel = iter->evsel; |
|---|
| 163 | + struct evsel *evsel = iter->evsel; |
|---|
| 159 | 164 | int err; |
|---|
| 160 | | - |
|---|
| 161 | | - hist__account_cycles(sample->branch_stack, al, sample, false); |
|---|
| 162 | 165 | |
|---|
| 163 | 166 | bi = he->branch_info; |
|---|
| 164 | 167 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); |
|---|
| .. | .. |
|---|
| 172 | 175 | return err; |
|---|
| 173 | 176 | } |
|---|
| 174 | 177 | |
|---|
| 175 | | -static int process_branch_callback(struct perf_evsel *evsel, |
|---|
| 178 | +static int process_branch_callback(struct evsel *evsel, |
|---|
| 176 | 179 | struct perf_sample *sample, |
|---|
| 177 | 180 | struct addr_location *al __maybe_unused, |
|---|
| 178 | 181 | struct perf_annotate *ann, |
|---|
| .. | .. |
|---|
| 198 | 201 | if (a.map != NULL) |
|---|
| 199 | 202 | a.map->dso->hit = 1; |
|---|
| 200 | 203 | |
|---|
| 204 | + hist__account_cycles(sample->branch_stack, al, sample, false, NULL); |
|---|
| 205 | + |
|---|
| 201 | 206 | ret = hist_entry_iter__add(&iter, &a, PERF_MAX_STACK_DEPTH, ann); |
|---|
| 202 | 207 | return ret; |
|---|
| 203 | 208 | } |
|---|
| .. | .. |
|---|
| 207 | 212 | return ui__has_annotation() || ann->use_stdio2; |
|---|
| 208 | 213 | } |
|---|
| 209 | 214 | |
|---|
| 210 | | -static int perf_evsel__add_sample(struct perf_evsel *evsel, |
|---|
| 211 | | - struct perf_sample *sample, |
|---|
| 212 | | - struct addr_location *al, |
|---|
| 213 | | - struct perf_annotate *ann, |
|---|
| 214 | | - struct machine *machine) |
|---|
| 215 | +static int evsel__add_sample(struct evsel *evsel, struct perf_sample *sample, |
|---|
| 216 | + struct addr_location *al, struct perf_annotate *ann, |
|---|
| 217 | + struct machine *machine) |
|---|
| 215 | 218 | { |
|---|
| 216 | 219 | struct hists *hists = evsel__hists(evsel); |
|---|
| 217 | 220 | struct hist_entry *he; |
|---|
| .. | .. |
|---|
| 227 | 230 | * the DSO? |
|---|
| 228 | 231 | */ |
|---|
| 229 | 232 | if (al->sym != NULL) { |
|---|
| 230 | | - rb_erase(&al->sym->rb_node, |
|---|
| 233 | + rb_erase_cached(&al->sym->rb_node, |
|---|
| 231 | 234 | &al->map->dso->symbols); |
|---|
| 232 | 235 | symbol__delete(al->sym); |
|---|
| 233 | 236 | dso__reset_find_symbol_cache(al->map->dso); |
|---|
| .. | .. |
|---|
| 256 | 259 | static int process_sample_event(struct perf_tool *tool, |
|---|
| 257 | 260 | union perf_event *event, |
|---|
| 258 | 261 | struct perf_sample *sample, |
|---|
| 259 | | - struct perf_evsel *evsel, |
|---|
| 262 | + struct evsel *evsel, |
|---|
| 260 | 263 | struct machine *machine) |
|---|
| 261 | 264 | { |
|---|
| 262 | 265 | struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool); |
|---|
| .. | .. |
|---|
| 273 | 276 | goto out_put; |
|---|
| 274 | 277 | |
|---|
| 275 | 278 | if (!al.filtered && |
|---|
| 276 | | - perf_evsel__add_sample(evsel, sample, &al, ann, machine)) { |
|---|
| 279 | + evsel__add_sample(evsel, sample, &al, ann, machine)) { |
|---|
| 277 | 280 | pr_warning("problem incrementing symbol count, " |
|---|
| 278 | 281 | "skipping event\n"); |
|---|
| 279 | 282 | ret = -1; |
|---|
| .. | .. |
|---|
| 283 | 286 | return ret; |
|---|
| 284 | 287 | } |
|---|
| 285 | 288 | |
|---|
| 286 | | -static int process_feature_event(struct perf_tool *tool, |
|---|
| 287 | | - union perf_event *event, |
|---|
| 288 | | - struct perf_session *session) |
|---|
| 289 | +static int process_feature_event(struct perf_session *session, |
|---|
| 290 | + union perf_event *event) |
|---|
| 289 | 291 | { |
|---|
| 290 | 292 | if (event->feat.feat_id < HEADER_LAST_FEATURE) |
|---|
| 291 | | - return perf_event__process_feature(tool, event, session); |
|---|
| 293 | + return perf_event__process_feature(session, event); |
|---|
| 292 | 294 | return 0; |
|---|
| 293 | 295 | } |
|---|
| 294 | 296 | |
|---|
| 295 | 297 | static int hist_entry__tty_annotate(struct hist_entry *he, |
|---|
| 296 | | - struct perf_evsel *evsel, |
|---|
| 298 | + struct evsel *evsel, |
|---|
| 297 | 299 | struct perf_annotate *ann) |
|---|
| 298 | 300 | { |
|---|
| 299 | 301 | if (!ann->use_stdio2) |
|---|
| 300 | | - return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, &ann->opts); |
|---|
| 302 | + return symbol__tty_annotate(&he->ms, evsel, &ann->opts); |
|---|
| 301 | 303 | |
|---|
| 302 | | - return symbol__tty_annotate2(he->ms.sym, he->ms.map, evsel, &ann->opts); |
|---|
| 304 | + return symbol__tty_annotate2(&he->ms, evsel, &ann->opts); |
|---|
| 303 | 305 | } |
|---|
| 304 | 306 | |
|---|
| 305 | 307 | static void hists__find_annotations(struct hists *hists, |
|---|
| 306 | | - struct perf_evsel *evsel, |
|---|
| 308 | + struct evsel *evsel, |
|---|
| 307 | 309 | struct perf_annotate *ann) |
|---|
| 308 | 310 | { |
|---|
| 309 | | - struct rb_node *nd = rb_first(&hists->entries), *next; |
|---|
| 311 | + struct rb_node *nd = rb_first_cached(&hists->entries), *next; |
|---|
| 310 | 312 | int key = K_RIGHT; |
|---|
| 311 | 313 | |
|---|
| 312 | 314 | while (nd) { |
|---|
| .. | .. |
|---|
| 333 | 335 | if (use_browser == 2) { |
|---|
| 334 | 336 | int ret; |
|---|
| 335 | 337 | int (*annotate)(struct hist_entry *he, |
|---|
| 336 | | - struct perf_evsel *evsel, |
|---|
| 338 | + struct evsel *evsel, |
|---|
| 337 | 339 | struct hist_browser_timer *hbt); |
|---|
| 338 | 340 | |
|---|
| 339 | 341 | annotate = dlsym(perf_gtk_handle, |
|---|
| .. | .. |
|---|
| 387 | 389 | { |
|---|
| 388 | 390 | int ret; |
|---|
| 389 | 391 | struct perf_session *session = ann->session; |
|---|
| 390 | | - struct perf_evsel *pos; |
|---|
| 392 | + struct evsel *pos; |
|---|
| 391 | 393 | u64 total_nr_samples; |
|---|
| 392 | 394 | |
|---|
| 393 | 395 | if (ann->cpu_list) { |
|---|
| .. | .. |
|---|
| 429 | 431 | total_nr_samples += nr_samples; |
|---|
| 430 | 432 | hists__collapse_resort(hists, NULL); |
|---|
| 431 | 433 | /* Don't sort callchain */ |
|---|
| 432 | | - perf_evsel__reset_sample_bit(pos, CALLCHAIN); |
|---|
| 433 | | - perf_evsel__output_resort(pos, NULL); |
|---|
| 434 | + evsel__reset_sample_bit(pos, CALLCHAIN); |
|---|
| 435 | + evsel__output_resort(pos, NULL); |
|---|
| 434 | 436 | |
|---|
| 435 | | - if (symbol_conf.event_group && |
|---|
| 436 | | - !perf_evsel__is_group_leader(pos)) |
|---|
| 437 | + if (symbol_conf.event_group && !evsel__is_group_leader(pos)) |
|---|
| 437 | 438 | continue; |
|---|
| 438 | 439 | |
|---|
| 439 | 440 | hists__find_annotations(hists, pos, ann); |
|---|
| .. | .. |
|---|
| 441 | 442 | } |
|---|
| 442 | 443 | |
|---|
| 443 | 444 | if (total_nr_samples == 0) { |
|---|
| 444 | | - ui__error("The %s file has no samples!\n", session->data->file.path); |
|---|
| 445 | + ui__error("The %s data has no samples!\n", session->data->path); |
|---|
| 445 | 446 | goto out; |
|---|
| 446 | 447 | } |
|---|
| 447 | 448 | |
|---|
| .. | .. |
|---|
| 531 | 532 | "Display raw encoding of assembly instructions (default)"), |
|---|
| 532 | 533 | OPT_STRING('M', "disassembler-style", &annotate.opts.disassembler_style, "disassembler style", |
|---|
| 533 | 534 | "Specify disassembler style (e.g. -M intel for intel syntax)"), |
|---|
| 535 | + OPT_STRING(0, "prefix", &annotate.opts.prefix, "prefix", |
|---|
| 536 | + "Add prefix to source file path names in programs (with --prefix-strip)"), |
|---|
| 537 | + OPT_STRING(0, "prefix-strip", &annotate.opts.prefix_strip, "N", |
|---|
| 538 | + "Strip first N entries of source file path name in programs (with --prefix)"), |
|---|
| 534 | 539 | OPT_STRING(0, "objdump", &annotate.opts.objdump_path, "path", |
|---|
| 535 | 540 | "objdump binary to use for disassembly and annotations"), |
|---|
| 536 | 541 | OPT_BOOLEAN(0, "group", &symbol_conf.event_group, |
|---|
| .. | .. |
|---|
| 558 | 563 | if (ret < 0) |
|---|
| 559 | 564 | return ret; |
|---|
| 560 | 565 | |
|---|
| 566 | + annotation_config__init(&annotate.opts); |
|---|
| 567 | + |
|---|
| 561 | 568 | argc = parse_options(argc, argv, options, annotate_usage, 0); |
|---|
| 562 | 569 | if (argc) { |
|---|
| 563 | 570 | /* |
|---|
| .. | .. |
|---|
| 570 | 577 | annotate.sym_hist_filter = argv[0]; |
|---|
| 571 | 578 | } |
|---|
| 572 | 579 | |
|---|
| 580 | + if (annotate_check_args(&annotate.opts) < 0) |
|---|
| 581 | + return -EINVAL; |
|---|
| 582 | + |
|---|
| 573 | 583 | if (symbol_conf.show_nr_samples && annotate.use_gtk) { |
|---|
| 574 | 584 | pr_err("--show-nr-samples is not available in --gtk mode at this time\n"); |
|---|
| 575 | 585 | return ret; |
|---|
| .. | .. |
|---|
| 578 | 588 | if (quiet) |
|---|
| 579 | 589 | perf_quiet_option(); |
|---|
| 580 | 590 | |
|---|
| 581 | | - data.file.path = input_name; |
|---|
| 591 | + data.path = input_name; |
|---|
| 582 | 592 | |
|---|
| 583 | 593 | annotate.session = perf_session__new(&data, false, &annotate.tool); |
|---|
| 584 | | - if (annotate.session == NULL) |
|---|
| 585 | | - return -1; |
|---|
| 594 | + if (IS_ERR(annotate.session)) |
|---|
| 595 | + return PTR_ERR(annotate.session); |
|---|
| 586 | 596 | |
|---|
| 587 | 597 | annotate.has_br_stack = perf_header__has_feat(&annotate.session->header, |
|---|
| 588 | 598 | HEADER_BRANCH_STACK); |
|---|
| .. | .. |
|---|
| 593 | 603 | ret = symbol__annotation_init(); |
|---|
| 594 | 604 | if (ret < 0) |
|---|
| 595 | 605 | goto out_delete; |
|---|
| 596 | | - |
|---|
| 597 | | - annotation_config__init(); |
|---|
| 598 | 606 | |
|---|
| 599 | 607 | symbol_conf.try_vmlinux_path = true; |
|---|
| 600 | 608 | |
|---|