18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * builtin-annotate.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Builtin annotate command: Analyze the perf.data input file, 68c2ecf20Sopenharmony_ci * look up and read DSOs and symbol information and display 78c2ecf20Sopenharmony_ci * a histogram of results, along various sorting keys. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include "builtin.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "util/color.h" 128c2ecf20Sopenharmony_ci#include <linux/list.h> 138c2ecf20Sopenharmony_ci#include "util/cache.h" 148c2ecf20Sopenharmony_ci#include <linux/rbtree.h> 158c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 168c2ecf20Sopenharmony_ci#include "util/symbol.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "perf.h" 198c2ecf20Sopenharmony_ci#include "util/debug.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "util/evlist.h" 228c2ecf20Sopenharmony_ci#include "util/evsel.h" 238c2ecf20Sopenharmony_ci#include "util/annotate.h" 248c2ecf20Sopenharmony_ci#include "util/event.h" 258c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h> 268c2ecf20Sopenharmony_ci#include "util/parse-events.h" 278c2ecf20Sopenharmony_ci#include "util/sort.h" 288c2ecf20Sopenharmony_ci#include "util/hist.h" 298c2ecf20Sopenharmony_ci#include "util/dso.h" 308c2ecf20Sopenharmony_ci#include "util/machine.h" 318c2ecf20Sopenharmony_ci#include "util/map.h" 328c2ecf20Sopenharmony_ci#include "util/session.h" 338c2ecf20Sopenharmony_ci#include "util/tool.h" 348c2ecf20Sopenharmony_ci#include "util/data.h" 358c2ecf20Sopenharmony_ci#include "arch/common.h" 368c2ecf20Sopenharmony_ci#include "util/block-range.h" 378c2ecf20Sopenharmony_ci#include "util/map_symbol.h" 388c2ecf20Sopenharmony_ci#include "util/branch.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include <dlfcn.h> 418c2ecf20Sopenharmony_ci#include <errno.h> 428c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 438c2ecf20Sopenharmony_ci#include <linux/err.h> 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistruct perf_annotate { 468c2ecf20Sopenharmony_ci struct perf_tool tool; 478c2ecf20Sopenharmony_ci struct perf_session *session; 488c2ecf20Sopenharmony_ci struct annotation_options opts; 498c2ecf20Sopenharmony_ci bool use_tui, use_stdio, use_stdio2, use_gtk; 508c2ecf20Sopenharmony_ci bool skip_missing; 518c2ecf20Sopenharmony_ci bool has_br_stack; 528c2ecf20Sopenharmony_ci bool group_set; 538c2ecf20Sopenharmony_ci const char *sym_hist_filter; 548c2ecf20Sopenharmony_ci const char *cpu_list; 558c2ecf20Sopenharmony_ci DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci * Given one basic block: 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * from to branch_i 628c2ecf20Sopenharmony_ci * * ----> * 638c2ecf20Sopenharmony_ci * | 648c2ecf20Sopenharmony_ci * | block 658c2ecf20Sopenharmony_ci * v 668c2ecf20Sopenharmony_ci * * ----> * 678c2ecf20Sopenharmony_ci * from to branch_i+1 688c2ecf20Sopenharmony_ci * 698c2ecf20Sopenharmony_ci * where the horizontal are the branches and the vertical is the executed 708c2ecf20Sopenharmony_ci * block of instructions. 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * We count, for each 'instruction', the number of blocks that covered it as 738c2ecf20Sopenharmony_ci * well as count the ratio each branch is taken. 748c2ecf20Sopenharmony_ci * 758c2ecf20Sopenharmony_ci * We can do this without knowing the actual instruction stream by keeping 768c2ecf20Sopenharmony_ci * track of the address ranges. We break down ranges such that there is no 778c2ecf20Sopenharmony_ci * overlap and iterate from the start until the end. 788c2ecf20Sopenharmony_ci * 798c2ecf20Sopenharmony_ci * @acme: once we parse the objdump output _before_ processing the samples, 808c2ecf20Sopenharmony_ci * we can easily fold the branch.cycles IPC bits in. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_cistatic void process_basic_block(struct addr_map_symbol *start, 838c2ecf20Sopenharmony_ci struct addr_map_symbol *end, 848c2ecf20Sopenharmony_ci struct branch_flags *flags) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct symbol *sym = start->ms.sym; 878c2ecf20Sopenharmony_ci struct annotation *notes = sym ? symbol__annotation(sym) : NULL; 888c2ecf20Sopenharmony_ci struct block_range_iter iter; 898c2ecf20Sopenharmony_ci struct block_range *entry; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* 928c2ecf20Sopenharmony_ci * Sanity; NULL isn't executable and the CPU cannot execute backwards 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci if (!start->addr || start->addr > end->addr) 958c2ecf20Sopenharmony_ci return; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci iter = block_range__create(start->addr, end->addr); 988c2ecf20Sopenharmony_ci if (!block_range_iter__valid(&iter)) 998c2ecf20Sopenharmony_ci return; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* 1028c2ecf20Sopenharmony_ci * First block in range is a branch target. 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_ci entry = block_range_iter(&iter); 1058c2ecf20Sopenharmony_ci assert(entry->is_target); 1068c2ecf20Sopenharmony_ci entry->entry++; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci do { 1098c2ecf20Sopenharmony_ci entry = block_range_iter(&iter); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci entry->coverage++; 1128c2ecf20Sopenharmony_ci entry->sym = sym; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (notes) 1158c2ecf20Sopenharmony_ci notes->max_coverage = max(notes->max_coverage, entry->coverage); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci } while (block_range_iter__next(&iter)); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* 1208c2ecf20Sopenharmony_ci * Last block in rage is a branch. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci entry = block_range_iter(&iter); 1238c2ecf20Sopenharmony_ci assert(entry->is_branch); 1248c2ecf20Sopenharmony_ci entry->taken++; 1258c2ecf20Sopenharmony_ci if (flags->predicted) 1268c2ecf20Sopenharmony_ci entry->pred++; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void process_branch_stack(struct branch_stack *bs, struct addr_location *al, 1308c2ecf20Sopenharmony_ci struct perf_sample *sample) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct addr_map_symbol *prev = NULL; 1338c2ecf20Sopenharmony_ci struct branch_info *bi; 1348c2ecf20Sopenharmony_ci int i; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (!bs || !bs->nr) 1378c2ecf20Sopenharmony_ci return; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci bi = sample__resolve_bstack(sample, al); 1408c2ecf20Sopenharmony_ci if (!bi) 1418c2ecf20Sopenharmony_ci return; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci for (i = bs->nr - 1; i >= 0; i--) { 1448c2ecf20Sopenharmony_ci /* 1458c2ecf20Sopenharmony_ci * XXX filter against symbol 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci if (prev) 1488c2ecf20Sopenharmony_ci process_basic_block(prev, &bi[i].from, &bi[i].flags); 1498c2ecf20Sopenharmony_ci prev = &bi[i].to; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci free(bi); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int hist_iter__branch_callback(struct hist_entry_iter *iter, 1568c2ecf20Sopenharmony_ci struct addr_location *al __maybe_unused, 1578c2ecf20Sopenharmony_ci bool single __maybe_unused, 1588c2ecf20Sopenharmony_ci void *arg __maybe_unused) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct hist_entry *he = iter->he; 1618c2ecf20Sopenharmony_ci struct branch_info *bi; 1628c2ecf20Sopenharmony_ci struct perf_sample *sample = iter->sample; 1638c2ecf20Sopenharmony_ci struct evsel *evsel = iter->evsel; 1648c2ecf20Sopenharmony_ci int err; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci bi = he->branch_info; 1678c2ecf20Sopenharmony_ci err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (err) 1708c2ecf20Sopenharmony_ci goto out; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci err = addr_map_symbol__inc_samples(&bi->to, sample, evsel); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ciout: 1758c2ecf20Sopenharmony_ci return err; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic int process_branch_callback(struct evsel *evsel, 1798c2ecf20Sopenharmony_ci struct perf_sample *sample, 1808c2ecf20Sopenharmony_ci struct addr_location *al __maybe_unused, 1818c2ecf20Sopenharmony_ci struct perf_annotate *ann, 1828c2ecf20Sopenharmony_ci struct machine *machine) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct hist_entry_iter iter = { 1858c2ecf20Sopenharmony_ci .evsel = evsel, 1868c2ecf20Sopenharmony_ci .sample = sample, 1878c2ecf20Sopenharmony_ci .add_entry_cb = hist_iter__branch_callback, 1888c2ecf20Sopenharmony_ci .hide_unresolved = symbol_conf.hide_unresolved, 1898c2ecf20Sopenharmony_ci .ops = &hist_iter_branch, 1908c2ecf20Sopenharmony_ci }; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci struct addr_location a; 1938c2ecf20Sopenharmony_ci int ret; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (machine__resolve(machine, &a, sample) < 0) 1968c2ecf20Sopenharmony_ci return -1; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (a.sym == NULL) 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (a.map != NULL) 2028c2ecf20Sopenharmony_ci a.map->dso->hit = 1; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci hist__account_cycles(sample->branch_stack, al, sample, false, NULL); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci ret = hist_entry_iter__add(&iter, &a, PERF_MAX_STACK_DEPTH, ann); 2078c2ecf20Sopenharmony_ci return ret; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic bool has_annotation(struct perf_annotate *ann) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci return ui__has_annotation() || ann->use_stdio2; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic int evsel__add_sample(struct evsel *evsel, struct perf_sample *sample, 2168c2ecf20Sopenharmony_ci struct addr_location *al, struct perf_annotate *ann, 2178c2ecf20Sopenharmony_ci struct machine *machine) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct hists *hists = evsel__hists(evsel); 2208c2ecf20Sopenharmony_ci struct hist_entry *he; 2218c2ecf20Sopenharmony_ci int ret; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if ((!ann->has_br_stack || !has_annotation(ann)) && 2248c2ecf20Sopenharmony_ci ann->sym_hist_filter != NULL && 2258c2ecf20Sopenharmony_ci (al->sym == NULL || 2268c2ecf20Sopenharmony_ci strcmp(ann->sym_hist_filter, al->sym->name) != 0)) { 2278c2ecf20Sopenharmony_ci /* We're only interested in a symbol named sym_hist_filter */ 2288c2ecf20Sopenharmony_ci /* 2298c2ecf20Sopenharmony_ci * FIXME: why isn't this done in the symbol_filter when loading 2308c2ecf20Sopenharmony_ci * the DSO? 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci if (al->sym != NULL) { 2338c2ecf20Sopenharmony_ci rb_erase_cached(&al->sym->rb_node, 2348c2ecf20Sopenharmony_ci &al->map->dso->symbols); 2358c2ecf20Sopenharmony_ci symbol__delete(al->sym); 2368c2ecf20Sopenharmony_ci dso__reset_find_symbol_cache(al->map->dso); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* 2428c2ecf20Sopenharmony_ci * XXX filtered samples can still have branch entires pointing into our 2438c2ecf20Sopenharmony_ci * symbol and are missed. 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci process_branch_stack(sample->branch_stack, al, sample); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (ann->has_br_stack && has_annotation(ann)) 2488c2ecf20Sopenharmony_ci return process_branch_callback(evsel, sample, al, ann, machine); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); 2518c2ecf20Sopenharmony_ci if (he == NULL) 2528c2ecf20Sopenharmony_ci return -ENOMEM; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci ret = hist_entry__inc_addr_samples(he, sample, evsel, al->addr); 2558c2ecf20Sopenharmony_ci hists__inc_nr_samples(hists, true); 2568c2ecf20Sopenharmony_ci return ret; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int process_sample_event(struct perf_tool *tool, 2608c2ecf20Sopenharmony_ci union perf_event *event, 2618c2ecf20Sopenharmony_ci struct perf_sample *sample, 2628c2ecf20Sopenharmony_ci struct evsel *evsel, 2638c2ecf20Sopenharmony_ci struct machine *machine) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool); 2668c2ecf20Sopenharmony_ci struct addr_location al; 2678c2ecf20Sopenharmony_ci int ret = 0; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (machine__resolve(machine, &al, sample) < 0) { 2708c2ecf20Sopenharmony_ci pr_warning("problem processing %d event, skipping it.\n", 2718c2ecf20Sopenharmony_ci event->header.type); 2728c2ecf20Sopenharmony_ci return -1; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap)) 2768c2ecf20Sopenharmony_ci goto out_put; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (!al.filtered && 2798c2ecf20Sopenharmony_ci evsel__add_sample(evsel, sample, &al, ann, machine)) { 2808c2ecf20Sopenharmony_ci pr_warning("problem incrementing symbol count, " 2818c2ecf20Sopenharmony_ci "skipping event\n"); 2828c2ecf20Sopenharmony_ci ret = -1; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ciout_put: 2858c2ecf20Sopenharmony_ci addr_location__put(&al); 2868c2ecf20Sopenharmony_ci return ret; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int process_feature_event(struct perf_session *session, 2908c2ecf20Sopenharmony_ci union perf_event *event) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci if (event->feat.feat_id < HEADER_LAST_FEATURE) 2938c2ecf20Sopenharmony_ci return perf_event__process_feature(session, event); 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int hist_entry__tty_annotate(struct hist_entry *he, 2988c2ecf20Sopenharmony_ci struct evsel *evsel, 2998c2ecf20Sopenharmony_ci struct perf_annotate *ann) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci if (!ann->use_stdio2) 3028c2ecf20Sopenharmony_ci return symbol__tty_annotate(&he->ms, evsel, &ann->opts); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return symbol__tty_annotate2(&he->ms, evsel, &ann->opts); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void hists__find_annotations(struct hists *hists, 3088c2ecf20Sopenharmony_ci struct evsel *evsel, 3098c2ecf20Sopenharmony_ci struct perf_annotate *ann) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct rb_node *nd = rb_first_cached(&hists->entries), *next; 3128c2ecf20Sopenharmony_ci int key = K_RIGHT; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci while (nd) { 3158c2ecf20Sopenharmony_ci struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 3168c2ecf20Sopenharmony_ci struct annotation *notes; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) 3198c2ecf20Sopenharmony_ci goto find_next; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (ann->sym_hist_filter && 3228c2ecf20Sopenharmony_ci (strcmp(he->ms.sym->name, ann->sym_hist_filter) != 0)) 3238c2ecf20Sopenharmony_ci goto find_next; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci notes = symbol__annotation(he->ms.sym); 3268c2ecf20Sopenharmony_ci if (notes->src == NULL) { 3278c2ecf20Sopenharmony_cifind_next: 3288c2ecf20Sopenharmony_ci if (key == K_LEFT) 3298c2ecf20Sopenharmony_ci nd = rb_prev(nd); 3308c2ecf20Sopenharmony_ci else 3318c2ecf20Sopenharmony_ci nd = rb_next(nd); 3328c2ecf20Sopenharmony_ci continue; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (use_browser == 2) { 3368c2ecf20Sopenharmony_ci int ret; 3378c2ecf20Sopenharmony_ci int (*annotate)(struct hist_entry *he, 3388c2ecf20Sopenharmony_ci struct evsel *evsel, 3398c2ecf20Sopenharmony_ci struct hist_browser_timer *hbt); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci annotate = dlsym(perf_gtk_handle, 3428c2ecf20Sopenharmony_ci "hist_entry__gtk_annotate"); 3438c2ecf20Sopenharmony_ci if (annotate == NULL) { 3448c2ecf20Sopenharmony_ci ui__error("GTK browser not found!\n"); 3458c2ecf20Sopenharmony_ci return; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci ret = annotate(he, evsel, NULL); 3498c2ecf20Sopenharmony_ci if (!ret || !ann->skip_missing) 3508c2ecf20Sopenharmony_ci return; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* skip missing symbols */ 3538c2ecf20Sopenharmony_ci nd = rb_next(nd); 3548c2ecf20Sopenharmony_ci } else if (use_browser == 1) { 3558c2ecf20Sopenharmony_ci key = hist_entry__tui_annotate(he, evsel, NULL, &ann->opts); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci switch (key) { 3588c2ecf20Sopenharmony_ci case -1: 3598c2ecf20Sopenharmony_ci if (!ann->skip_missing) 3608c2ecf20Sopenharmony_ci return; 3618c2ecf20Sopenharmony_ci /* fall through */ 3628c2ecf20Sopenharmony_ci case K_RIGHT: 3638c2ecf20Sopenharmony_ci next = rb_next(nd); 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci case K_LEFT: 3668c2ecf20Sopenharmony_ci next = rb_prev(nd); 3678c2ecf20Sopenharmony_ci break; 3688c2ecf20Sopenharmony_ci default: 3698c2ecf20Sopenharmony_ci return; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (next != NULL) 3738c2ecf20Sopenharmony_ci nd = next; 3748c2ecf20Sopenharmony_ci } else { 3758c2ecf20Sopenharmony_ci hist_entry__tty_annotate(he, evsel, ann); 3768c2ecf20Sopenharmony_ci nd = rb_next(nd); 3778c2ecf20Sopenharmony_ci /* 3788c2ecf20Sopenharmony_ci * Since we have a hist_entry per IP for the same 3798c2ecf20Sopenharmony_ci * symbol, free he->ms.sym->src to signal we already 3808c2ecf20Sopenharmony_ci * processed this symbol. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_ci zfree(¬es->src->cycles_hist); 3838c2ecf20Sopenharmony_ci zfree(¬es->src); 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic int __cmd_annotate(struct perf_annotate *ann) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci int ret; 3918c2ecf20Sopenharmony_ci struct perf_session *session = ann->session; 3928c2ecf20Sopenharmony_ci struct evsel *pos; 3938c2ecf20Sopenharmony_ci u64 total_nr_samples; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (ann->cpu_list) { 3968c2ecf20Sopenharmony_ci ret = perf_session__cpu_bitmap(session, ann->cpu_list, 3978c2ecf20Sopenharmony_ci ann->cpu_bitmap); 3988c2ecf20Sopenharmony_ci if (ret) 3998c2ecf20Sopenharmony_ci goto out; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (!ann->opts.objdump_path) { 4038c2ecf20Sopenharmony_ci ret = perf_env__lookup_objdump(&session->header.env, 4048c2ecf20Sopenharmony_ci &ann->opts.objdump_path); 4058c2ecf20Sopenharmony_ci if (ret) 4068c2ecf20Sopenharmony_ci goto out; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci ret = perf_session__process_events(session); 4108c2ecf20Sopenharmony_ci if (ret) 4118c2ecf20Sopenharmony_ci goto out; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (dump_trace) { 4148c2ecf20Sopenharmony_ci perf_session__fprintf_nr_events(session, stdout); 4158c2ecf20Sopenharmony_ci perf_evlist__fprintf_nr_events(session->evlist, stdout); 4168c2ecf20Sopenharmony_ci goto out; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (verbose > 3) 4208c2ecf20Sopenharmony_ci perf_session__fprintf(session, stdout); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (verbose > 2) 4238c2ecf20Sopenharmony_ci perf_session__fprintf_dsos(session, stdout); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci total_nr_samples = 0; 4268c2ecf20Sopenharmony_ci evlist__for_each_entry(session->evlist, pos) { 4278c2ecf20Sopenharmony_ci struct hists *hists = evsel__hists(pos); 4288c2ecf20Sopenharmony_ci u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (nr_samples > 0) { 4318c2ecf20Sopenharmony_ci total_nr_samples += nr_samples; 4328c2ecf20Sopenharmony_ci hists__collapse_resort(hists, NULL); 4338c2ecf20Sopenharmony_ci /* Don't sort callchain */ 4348c2ecf20Sopenharmony_ci evsel__reset_sample_bit(pos, CALLCHAIN); 4358c2ecf20Sopenharmony_ci evsel__output_resort(pos, NULL); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (symbol_conf.event_group && !evsel__is_group_leader(pos)) 4388c2ecf20Sopenharmony_ci continue; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci hists__find_annotations(hists, pos, ann); 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (total_nr_samples == 0) { 4458c2ecf20Sopenharmony_ci ui__error("The %s data has no samples!\n", session->data->path); 4468c2ecf20Sopenharmony_ci goto out; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (use_browser == 2) { 4508c2ecf20Sopenharmony_ci void (*show_annotations)(void); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci show_annotations = dlsym(perf_gtk_handle, 4538c2ecf20Sopenharmony_ci "perf_gtk__show_annotations"); 4548c2ecf20Sopenharmony_ci if (show_annotations == NULL) { 4558c2ecf20Sopenharmony_ci ui__error("GTK browser not found!\n"); 4568c2ecf20Sopenharmony_ci goto out; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci show_annotations(); 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ciout: 4628c2ecf20Sopenharmony_ci return ret; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic const char * const annotate_usage[] = { 4668c2ecf20Sopenharmony_ci "perf annotate [<options>]", 4678c2ecf20Sopenharmony_ci NULL 4688c2ecf20Sopenharmony_ci}; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ciint cmd_annotate(int argc, const char **argv) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct perf_annotate annotate = { 4738c2ecf20Sopenharmony_ci .tool = { 4748c2ecf20Sopenharmony_ci .sample = process_sample_event, 4758c2ecf20Sopenharmony_ci .mmap = perf_event__process_mmap, 4768c2ecf20Sopenharmony_ci .mmap2 = perf_event__process_mmap2, 4778c2ecf20Sopenharmony_ci .comm = perf_event__process_comm, 4788c2ecf20Sopenharmony_ci .exit = perf_event__process_exit, 4798c2ecf20Sopenharmony_ci .fork = perf_event__process_fork, 4808c2ecf20Sopenharmony_ci .namespaces = perf_event__process_namespaces, 4818c2ecf20Sopenharmony_ci .attr = perf_event__process_attr, 4828c2ecf20Sopenharmony_ci .build_id = perf_event__process_build_id, 4838c2ecf20Sopenharmony_ci .tracing_data = perf_event__process_tracing_data, 4848c2ecf20Sopenharmony_ci .feature = process_feature_event, 4858c2ecf20Sopenharmony_ci .ordered_events = true, 4868c2ecf20Sopenharmony_ci .ordering_requires_timestamps = true, 4878c2ecf20Sopenharmony_ci }, 4888c2ecf20Sopenharmony_ci .opts = annotation__default_options, 4898c2ecf20Sopenharmony_ci }; 4908c2ecf20Sopenharmony_ci struct perf_data data = { 4918c2ecf20Sopenharmony_ci .mode = PERF_DATA_MODE_READ, 4928c2ecf20Sopenharmony_ci }; 4938c2ecf20Sopenharmony_ci struct option options[] = { 4948c2ecf20Sopenharmony_ci OPT_STRING('i', "input", &input_name, "file", 4958c2ecf20Sopenharmony_ci "input file name"), 4968c2ecf20Sopenharmony_ci OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 4978c2ecf20Sopenharmony_ci "only consider symbols in these dsos"), 4988c2ecf20Sopenharmony_ci OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol", 4998c2ecf20Sopenharmony_ci "symbol to annotate"), 5008c2ecf20Sopenharmony_ci OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"), 5018c2ecf20Sopenharmony_ci OPT_INCR('v', "verbose", &verbose, 5028c2ecf20Sopenharmony_ci "be more verbose (show symbol address, etc)"), 5038c2ecf20Sopenharmony_ci OPT_BOOLEAN('q', "quiet", &quiet, "do now show any message"), 5048c2ecf20Sopenharmony_ci OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 5058c2ecf20Sopenharmony_ci "dump raw trace in ASCII"), 5068c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"), 5078c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), 5088c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"), 5098c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "stdio2", &annotate.use_stdio2, "Use the stdio interface"), 5108c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux, 5118c2ecf20Sopenharmony_ci "don't load vmlinux even if found"), 5128c2ecf20Sopenharmony_ci OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 5138c2ecf20Sopenharmony_ci "file", "vmlinux pathname"), 5148c2ecf20Sopenharmony_ci OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 5158c2ecf20Sopenharmony_ci "load module symbols - WARNING: use only with -k and LIVE kernel"), 5168c2ecf20Sopenharmony_ci OPT_BOOLEAN('l', "print-line", &annotate.opts.print_lines, 5178c2ecf20Sopenharmony_ci "print matching source lines (may be slow)"), 5188c2ecf20Sopenharmony_ci OPT_BOOLEAN('P', "full-paths", &annotate.opts.full_path, 5198c2ecf20Sopenharmony_ci "Don't shorten the displayed pathnames"), 5208c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing, 5218c2ecf20Sopenharmony_ci "Skip symbols that cannot be annotated"), 5228c2ecf20Sopenharmony_ci OPT_BOOLEAN_SET(0, "group", &symbol_conf.event_group, 5238c2ecf20Sopenharmony_ci &annotate.group_set, 5248c2ecf20Sopenharmony_ci "Show event group information together"), 5258c2ecf20Sopenharmony_ci OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"), 5268c2ecf20Sopenharmony_ci OPT_CALLBACK(0, "symfs", NULL, "directory", 5278c2ecf20Sopenharmony_ci "Look for files with symbols relative to this directory", 5288c2ecf20Sopenharmony_ci symbol__config_symfs), 5298c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "source", &annotate.opts.annotate_src, 5308c2ecf20Sopenharmony_ci "Interleave source code with assembly code (default)"), 5318c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "asm-raw", &annotate.opts.show_asm_raw, 5328c2ecf20Sopenharmony_ci "Display raw encoding of assembly instructions (default)"), 5338c2ecf20Sopenharmony_ci OPT_STRING('M', "disassembler-style", &annotate.opts.disassembler_style, "disassembler style", 5348c2ecf20Sopenharmony_ci "Specify disassembler style (e.g. -M intel for intel syntax)"), 5358c2ecf20Sopenharmony_ci OPT_STRING(0, "prefix", &annotate.opts.prefix, "prefix", 5368c2ecf20Sopenharmony_ci "Add prefix to source file path names in programs (with --prefix-strip)"), 5378c2ecf20Sopenharmony_ci OPT_STRING(0, "prefix-strip", &annotate.opts.prefix_strip, "N", 5388c2ecf20Sopenharmony_ci "Strip first N entries of source file path name in programs (with --prefix)"), 5398c2ecf20Sopenharmony_ci OPT_STRING(0, "objdump", &annotate.opts.objdump_path, "path", 5408c2ecf20Sopenharmony_ci "objdump binary to use for disassembly and annotations"), 5418c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "group", &symbol_conf.event_group, 5428c2ecf20Sopenharmony_ci "Show event group information together"), 5438c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 5448c2ecf20Sopenharmony_ci "Show a column with the sum of periods"), 5458c2ecf20Sopenharmony_ci OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 5468c2ecf20Sopenharmony_ci "Show a column with the number of samples"), 5478c2ecf20Sopenharmony_ci OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode", 5488c2ecf20Sopenharmony_ci "'always' (default), 'never' or 'auto' only applicable to --stdio mode", 5498c2ecf20Sopenharmony_ci stdio__config_color, "always"), 5508c2ecf20Sopenharmony_ci OPT_CALLBACK(0, "percent-type", &annotate.opts, "local-period", 5518c2ecf20Sopenharmony_ci "Set percent type local/global-period/hits", 5528c2ecf20Sopenharmony_ci annotate_parse_percent_type), 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci OPT_END() 5558c2ecf20Sopenharmony_ci }; 5568c2ecf20Sopenharmony_ci int ret; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci set_option_flag(options, 0, "show-total-period", PARSE_OPT_EXCLUSIVE); 5598c2ecf20Sopenharmony_ci set_option_flag(options, 0, "show-nr-samples", PARSE_OPT_EXCLUSIVE); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci ret = hists__init(); 5638c2ecf20Sopenharmony_ci if (ret < 0) 5648c2ecf20Sopenharmony_ci return ret; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci annotation_config__init(&annotate.opts); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci argc = parse_options(argc, argv, options, annotate_usage, 0); 5698c2ecf20Sopenharmony_ci if (argc) { 5708c2ecf20Sopenharmony_ci /* 5718c2ecf20Sopenharmony_ci * Special case: if there's an argument left then assume that 5728c2ecf20Sopenharmony_ci * it's a symbol filter: 5738c2ecf20Sopenharmony_ci */ 5748c2ecf20Sopenharmony_ci if (argc > 1) 5758c2ecf20Sopenharmony_ci usage_with_options(annotate_usage, options); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci annotate.sym_hist_filter = argv[0]; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (annotate_check_args(&annotate.opts) < 0) 5818c2ecf20Sopenharmony_ci return -EINVAL; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (symbol_conf.show_nr_samples && annotate.use_gtk) { 5848c2ecf20Sopenharmony_ci pr_err("--show-nr-samples is not available in --gtk mode at this time\n"); 5858c2ecf20Sopenharmony_ci return ret; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (quiet) 5898c2ecf20Sopenharmony_ci perf_quiet_option(); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci data.path = input_name; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci annotate.session = perf_session__new(&data, false, &annotate.tool); 5948c2ecf20Sopenharmony_ci if (IS_ERR(annotate.session)) 5958c2ecf20Sopenharmony_ci return PTR_ERR(annotate.session); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci annotate.has_br_stack = perf_header__has_feat(&annotate.session->header, 5988c2ecf20Sopenharmony_ci HEADER_BRANCH_STACK); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (annotate.group_set) 6018c2ecf20Sopenharmony_ci perf_evlist__force_leader(annotate.session->evlist); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci ret = symbol__annotation_init(); 6048c2ecf20Sopenharmony_ci if (ret < 0) 6058c2ecf20Sopenharmony_ci goto out_delete; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci symbol_conf.try_vmlinux_path = true; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci ret = symbol__init(&annotate.session->header.env); 6108c2ecf20Sopenharmony_ci if (ret < 0) 6118c2ecf20Sopenharmony_ci goto out_delete; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (annotate.use_stdio || annotate.use_stdio2) 6148c2ecf20Sopenharmony_ci use_browser = 0; 6158c2ecf20Sopenharmony_ci else if (annotate.use_tui) 6168c2ecf20Sopenharmony_ci use_browser = 1; 6178c2ecf20Sopenharmony_ci else if (annotate.use_gtk) 6188c2ecf20Sopenharmony_ci use_browser = 2; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci setup_browser(true); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if ((use_browser == 1 || annotate.use_stdio2) && annotate.has_br_stack) { 6238c2ecf20Sopenharmony_ci sort__mode = SORT_MODE__BRANCH; 6248c2ecf20Sopenharmony_ci if (setup_sorting(annotate.session->evlist) < 0) 6258c2ecf20Sopenharmony_ci usage_with_options(annotate_usage, options); 6268c2ecf20Sopenharmony_ci } else { 6278c2ecf20Sopenharmony_ci if (setup_sorting(NULL) < 0) 6288c2ecf20Sopenharmony_ci usage_with_options(annotate_usage, options); 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci ret = __cmd_annotate(&annotate); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ciout_delete: 6348c2ecf20Sopenharmony_ci /* 6358c2ecf20Sopenharmony_ci * Speed up the exit process, for large files this can 6368c2ecf20Sopenharmony_ci * take quite a while. 6378c2ecf20Sopenharmony_ci * 6388c2ecf20Sopenharmony_ci * XXX Enable this when using valgrind or if we ever 6398c2ecf20Sopenharmony_ci * librarize this command. 6408c2ecf20Sopenharmony_ci * 6418c2ecf20Sopenharmony_ci * Also experiment with obstacks to see how much speed 6428c2ecf20Sopenharmony_ci * up we'll get here. 6438c2ecf20Sopenharmony_ci * 6448c2ecf20Sopenharmony_ci * perf_session__delete(session); 6458c2ecf20Sopenharmony_ci */ 6468c2ecf20Sopenharmony_ci return ret; 6478c2ecf20Sopenharmony_ci} 648