diff options
77 files changed, 606 insertions, 358 deletions
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 4f34379ebd77..1f6c70594f0f 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -170,7 +170,16 @@ OPTIONS Trace decoding. The flags are "bcrosyiABEx" which stand for branch, call, return, conditional, system, asynchronous, interrupt, transaction abort, trace begin, trace end, and in transaction, - respectively. + respectively. Known combinations of flags are printed more nicely e.g. + "call" for "bc", "return" for "br", "jcc" for "bo", "jmp" for "b", + "int" for "bci", "iret" for "bri", "syscall" for "bcs", "sysret" for "brs", + "async" for "by", "hw int" for "bcyi", "tx abrt" for "bA", "tr strt" for "bB", + "tr end" for "bE". However the "x" flag will be display separately in those + cases e.g. "jcc (x)" for a condition branch within a transaction. + + The callindent field is synthesized and may have a value when + Instruction Trace decoding. For calls and returns, it will display the + name of the symbol indented with spaces to reflect the stack depth. Finally, a user may not set fields to none for all event types. i.e., -F "" is not allowed. diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index bde8cbae7dd9..d0a2cb11296f 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -254,7 +254,8 @@ PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPI) $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBTRACEEVENT_DYNAMIC_LIST) - $(QUIET_GEN)CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS)' \ + $(QUIET_GEN)LDSHARED="$(CC) -pthread -shared" \ + CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS)' \ $(PYTHON_WORD) util/setup.py \ --quiet build_ext; \ mkdir -p $(OUTPUT)python && \ diff --git a/tools/perf/arch/x86/tests/perf-time-to-tsc.c b/tools/perf/arch/x86/tests/perf-time-to-tsc.c index d4aa567a29c4..5c76cc83186a 100644 --- a/tools/perf/arch/x86/tests/perf-time-to-tsc.c +++ b/tools/perf/arch/x86/tests/perf-time-to-tsc.c @@ -154,10 +154,6 @@ next_event: err = 0; out_err: - if (evlist) { - perf_evlist__disable(evlist); - perf_evlist__delete(evlist); - } - + perf_evlist__delete(evlist); return err; } diff --git a/tools/perf/arch/x86/util/auxtrace.c b/tools/perf/arch/x86/util/auxtrace.c index 7a7805583e3f..cc1d865e31f1 100644 --- a/tools/perf/arch/x86/util/auxtrace.c +++ b/tools/perf/arch/x86/util/auxtrace.c @@ -37,7 +37,7 @@ struct auxtrace_record *auxtrace_record__init_intel(struct perf_evlist *evlist, intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME); if (evlist) { - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (intel_pt_pmu && evsel->attr.type == intel_pt_pmu->type) found_pt = true; diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c index 7dc30637cf66..5132775a044f 100644 --- a/tools/perf/arch/x86/util/intel-bts.c +++ b/tools/perf/arch/x86/util/intel-bts.c @@ -124,7 +124,7 @@ static int intel_bts_recording_options(struct auxtrace_record *itr, btsr->evlist = evlist; btsr->snapshot_mode = opts->auxtrace_snapshot_mode; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type == intel_bts_pmu->type) { if (intel_bts_evsel) { pr_err("There may be only one " INTEL_BTS_PMU_NAME " event\n"); @@ -327,7 +327,7 @@ static int intel_bts_snapshot_start(struct auxtrace_record *itr) container_of(itr, struct intel_bts_recording, itr); struct perf_evsel *evsel; - evlist__for_each(btsr->evlist, evsel) { + evlist__for_each_entry(btsr->evlist, evsel) { if (evsel->attr.type == btsr->intel_bts_pmu->type) return perf_evsel__disable(evsel); } @@ -340,7 +340,7 @@ static int intel_bts_snapshot_finish(struct auxtrace_record *itr) container_of(itr, struct intel_bts_recording, itr); struct perf_evsel *evsel; - evlist__for_each(btsr->evlist, evsel) { + evlist__for_each_entry(btsr->evlist, evsel) { if (evsel->attr.type == btsr->intel_bts_pmu->type) return perf_evsel__enable(evsel); } @@ -422,7 +422,7 @@ static int intel_bts_read_finish(struct auxtrace_record *itr, int idx) container_of(itr, struct intel_bts_recording, itr); struct perf_evsel *evsel; - evlist__for_each(btsr->evlist, evsel) { + evlist__for_each_entry(btsr->evlist, evsel) { if (evsel->attr.type == btsr->intel_bts_pmu->type) return perf_evlist__enable_event_idx(btsr->evlist, evsel, idx); diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index a07b9605e93b..fb51457ba338 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -131,7 +131,7 @@ static int intel_pt_read_config(struct perf_pmu *intel_pt_pmu, const char *str, if (!mask) return -EINVAL; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type == intel_pt_pmu->type) { *res = intel_pt_masked_bits(mask, evsel->attr.config); return 0; @@ -511,7 +511,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, ptr->evlist = evlist; ptr->snapshot_mode = opts->auxtrace_snapshot_mode; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type == intel_pt_pmu->type) { if (intel_pt_evsel) { pr_err("There may be only one " INTEL_PT_PMU_NAME " event\n"); @@ -725,7 +725,7 @@ static int intel_pt_snapshot_start(struct auxtrace_record *itr) container_of(itr, struct intel_pt_recording, itr); struct perf_evsel *evsel; - evlist__for_each(ptr->evlist, evsel) { + evlist__for_each_entry(ptr->evlist, evsel) { if (evsel->attr.type == ptr->intel_pt_pmu->type) return perf_evsel__disable(evsel); } @@ -738,7 +738,7 @@ static int intel_pt_snapshot_finish(struct auxtrace_record *itr) container_of(itr, struct intel_pt_recording, itr); struct perf_evsel *evsel; - evlist__for_each(ptr->evlist, evsel) { + evlist__for_each_entry(ptr->evlist, evsel) { if (evsel->attr.type == ptr->intel_pt_pmu->type) return perf_evsel__enable(evsel); } @@ -1011,7 +1011,7 @@ static int intel_pt_read_finish(struct auxtrace_record *itr, int idx) container_of(itr, struct intel_pt_recording, itr); struct perf_evsel *evsel; - evlist__for_each(ptr->evlist, evsel) { + evlist__for_each_entry(ptr->evlist, evsel) { if (evsel->attr.type == ptr->intel_pt_pmu->type) return perf_evlist__enable_event_idx(ptr->evlist, evsel, idx); diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index a2324e1892aa..b15e7683f38c 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -236,7 +236,7 @@ static int __cmd_annotate(struct perf_annotate *ann) perf_session__fprintf_dsos(session, stdout); total_nr_samples = 0; - evlist__for_each(session->evlist, pos) { + evlist__for_each_entry(session->evlist, pos) { struct hists *hists = evsel__hists(pos); u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index d75bded21fe0..76a4d03c7cd0 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c @@ -209,7 +209,7 @@ static int build_id_cache__purge_path(const char *pathname) if (err) goto out; - strlist__for_each(pos, list) { + strlist__for_each_entry(pos, list) { err = build_id_cache__remove_s(pos->s); pr_debug("Removing %s %s: %s\n", pos->s, pathname, err ? "FAIL" : "Ok"); @@ -343,7 +343,7 @@ int cmd_buildid_cache(int argc, const char **argv, if (add_name_list_str) { list = strlist__new(add_name_list_str, NULL); if (list) { - strlist__for_each(pos, list) + strlist__for_each_entry(pos, list) if (build_id_cache__add_file(pos->s)) { if (errno == EEXIST) { pr_debug("%s already in the cache\n", @@ -361,7 +361,7 @@ int cmd_buildid_cache(int argc, const char **argv, if (remove_name_list_str) { list = strlist__new(remove_name_list_str, NULL); if (list) { - strlist__for_each(pos, list) + strlist__for_each_entry(pos, list) if (build_id_cache__remove_file(pos->s)) { if (errno == ENOENT) { pr_debug("%s wasn't in the cache\n", @@ -379,7 +379,7 @@ int cmd_buildid_cache(int argc, const char **argv, if (purge_name_list_str) { list = strlist__new(purge_name_list_str, NULL); if (list) { - strlist__for_each(pos, list) + strlist__for_each_entry(pos, list) if (build_id_cache__purge_path(pos->s)) { if (errno == ENOENT) { pr_debug("%s wasn't in the cache\n", @@ -400,7 +400,7 @@ int cmd_buildid_cache(int argc, const char **argv, if (update_name_list_str) { list = strlist__new(update_name_list_str, NULL); if (list) { - strlist__for_each(pos, list) + strlist__for_each_entry(pos, list) if (build_id_cache__update_file(pos->s)) { if (errno == ENOENT) { pr_debug("%s wasn't in the cache\n", @@ -419,8 +419,7 @@ int cmd_buildid_cache(int argc, const char **argv, pr_warning("Couldn't add %s\n", kcore_filename); out: - if (session) - perf_session__delete(session); + perf_session__delete(session); return ret; } diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index fe1b77fa21f9..e4207a23b52c 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c @@ -37,23 +37,16 @@ static int show_config(struct perf_config_set *set) { struct perf_config_section *section; struct perf_config_item *item; - struct list_head *sections; if (set == NULL) return -1; - sections = &set->sections; - if (list_empty(sections)) - return -1; - - list_for_each_entry(section, sections, node) { - list_for_each_entry(item, §ion->items, node) { - char *value = item->value; + perf_config_set__for_each_entry(set, section, item) { + char *value = item->value; - if (value) - printf("%s.%s=%s\n", section->name, - item->name, value); - } + if (value) + printf("%s.%s=%s\n", section->name, + item->name, value); } return 0; @@ -80,6 +73,10 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) else if (use_user_config) config_exclusive_filename = user_config; + /* + * At only 'config' sub-command, individually use the config set + * because of reinitializing with options config file location. + */ set = perf_config_set__new(); if (!set) { ret = -1; diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 8b6735f35179..21ee753211ad 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -363,7 +363,7 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel, { struct perf_evsel *e; - evlist__for_each(evlist, e) { + evlist__for_each_entry(evlist, e) { if (perf_evsel__match2(evsel, e)) return e; } @@ -375,7 +375,7 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { struct hists *hists = evsel__hists(evsel); hists__collapse_resort(hists, NULL); @@ -681,7 +681,7 @@ static void data_process(void) struct perf_evsel *evsel_base; bool first = true; - evlist__for_each(evlist_base, evsel_base) { + evlist__for_each_entry(evlist_base, evsel_base) { struct hists *hists_base = evsel__hists(evsel_base); struct data__file *d; int i; @@ -756,9 +756,7 @@ static int __cmd_diff(void) out_delete: data__for_each_file(i, d) { - if (d->session) - perf_session__delete(d->session); - + perf_session__delete(d->session); data__free(d); } diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 8a31f511e1a0..e09c4287fe87 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -32,7 +32,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details if (session == NULL) return -1; - evlist__for_each(session->evlist, pos) { + evlist__for_each_entry(session->evlist, pos) { perf_evsel__fprintf(pos, details, stdout); if (pos->attr.type == PERF_TYPE_TRACEPOINT) diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index f9830c902b78..268ab732b8aa 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -4,7 +4,7 @@ * Builtin help command */ #include "perf.h" -#include "util/cache.h" +#include "util/config.h" #include "builtin.h" #include <subcmd/exec-cmd.h> #include "common-cmds.h" diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index e5afa8fe1bf1..73c1c4cc3600 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -562,7 +562,7 @@ static void strip_init(struct perf_inject *inject) inject->tool.context_switch = perf_event__drop; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) evsel->handler = drop_sample; } @@ -590,7 +590,7 @@ static bool ok_to_remove(struct perf_evlist *evlist, if (!has_tracking(evsel_to_remove)) return true; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->handler != drop_sample) { cnt += 1; if ((evsel->attr.sample_type & COMPAT_MASK) == @@ -608,7 +608,7 @@ static void strip_fini(struct perf_inject *inject) struct perf_evsel *evsel, *tmp; /* Remove non-synthesized evsels if possible */ - evlist__for_each_safe(evlist, tmp, evsel) { + evlist__for_each_entry_safe(evlist, tmp, evsel) { if (evsel->handler == drop_sample && ok_to_remove(evlist, evsel)) { pr_debug("Deleting %s\n", perf_evsel__name(evsel)); @@ -643,7 +643,7 @@ static int __cmd_inject(struct perf_inject *inject) } else if (inject->sched_stat) { struct perf_evsel *evsel; - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { const char *name = perf_evsel__name(evsel); if (!strcmp(name, "sched:sched_switch")) { diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 58adfee230de..b1d491c2e704 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -4,7 +4,7 @@ #include "util/evlist.h" #include "util/evsel.h" #include "util/util.h" -#include "util/cache.h" +#include "util/config.h" #include "util/symbol.h" #include "util/thread.h" #include "util/header.h" @@ -1354,7 +1354,7 @@ static int __cmd_kmem(struct perf_session *session) goto out; } - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (!strcmp(perf_evsel__name(evsel), "kmem:mm_page_alloc") && perf_evsel__field(evsel, "pfn")) { use_pfn = true; diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 6487c06d2708..f4efef9d1eb3 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -988,7 +988,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) * Note: exclude_{guest,host} do not apply here. * This command processes KVM tracepoints from host only */ - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { struct perf_event_attr *attr = &pos->attr; /* make sure these *are* set */ @@ -1426,11 +1426,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, err = kvm_events_live_report(kvm); out: - if (kvm->session) - perf_session__delete(kvm->session); + perf_session__delete(kvm->session); kvm->session = NULL; - if (kvm->evlist) - perf_evlist__delete(kvm->evlist); + perf_evlist__delete(kvm->evlist); return err; } diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 6d7ab4316449..34262329f405 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -389,7 +389,7 @@ static int perf_del_probe_events(struct strfilter *filter) ret = probe_file__get_events(kfd, filter, klist); if (ret == 0) { - strlist__for_each(ent, klist) + strlist__for_each_entry(ent, klist) pr_info("Removed event: %s\n", ent->s); ret = probe_file__del_strlist(kfd, klist); @@ -399,7 +399,7 @@ static int perf_del_probe_events(struct strfilter *filter) ret2 = probe_file__get_events(ufd, filter, ulist); if (ret2 == 0) { - strlist__for_each(ent, ulist) + strlist__for_each_entry(ent, ulist) pr_info("Removed event: %s\n", ent->s); ret2 = probe_file__del_strlist(ufd, ulist); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index b1304ebc8779..81411b14df4c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -13,6 +13,7 @@ #include "util/util.h" #include <subcmd/parse-options.h> #include "util/parse-events.h" +#include "util/config.h" #include "util/callchain.h" #include "util/cgroup.h" @@ -352,7 +353,7 @@ static int record__open(struct record *rec) perf_evlist__config(evlist, opts, &callchain_param); - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { try_again: if (perf_evsel__open(pos, pos->cpus, pos->threads) < 0) { if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 9f36b236f0f9..f6cb357986c6 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -8,7 +8,7 @@ #include "builtin.h" #include "util/util.h" -#include "util/cache.h" +#include "util/config.h" #include "util/annotate.h" #include "util/color.h" @@ -361,7 +361,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, struct perf_evsel *pos; fprintf(stdout, "#\n# Total Lost Samples: %" PRIu64 "\n#\n", evlist->stats.total_lost_samples); - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { struct hists *hists = evsel__hists(pos); const char *evname = perf_evsel__name(pos); @@ -478,7 +478,7 @@ static int report__collapse_hists(struct report *rep) ui_progress__init(&prog, rep->nr_entries, "Merging related events..."); - evlist__for_each(rep->session->evlist, pos) { + evlist__for_each_entry(rep->session->evlist, pos) { struct hists *hists = evsel__hists(pos); if (pos->idx == 0) @@ -511,7 +511,7 @@ static void report__output_resort(struct report *rep) ui_progress__init(&prog, rep->nr_entries, "Sorting events for output..."); - evlist__for_each(rep->session->evlist, pos) + evlist__for_each_entry(rep->session->evlist, pos) perf_evsel__output_resort(pos, &prog); ui_progress__finish(); @@ -552,7 +552,7 @@ static int __cmd_report(struct report *rep) report__warn_kptr_restrict(rep); - evlist__for_each(session->evlist, pos) + evlist__for_each_entry(session->evlist, pos) rep->nr_entries += evsel__hists(pos)->nr_entries; if (use_browser == 0) { @@ -583,7 +583,7 @@ static int __cmd_report(struct report *rep) * might be changed during the collapse phase. */ rep->nr_entries = 0; - evlist__for_each(session->evlist, pos) + evlist__for_each_entry(session->evlist, pos) rep->nr_entries += evsel__hists(pos)->nr_entries; if (rep->nr_entries == 0) { diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 46011235af5d..971ff91b16cb 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -21,6 +21,7 @@ #include "util/cpumap.h" #include "util/thread_map.h" #include "util/stat.h" +#include "util/thread-stack.h" #include <linux/bitmap.h> #include <linux/stringify.h> #include "asm/bug.h" @@ -63,6 +64,7 @@ enum perf_output_field { PERF_OUTPUT_DATA_SRC = 1U << 17, PERF_OUTPUT_WEIGHT = 1U << 18, PERF_OUTPUT_BPF_OUTPUT = 1U << 19, + PERF_OUTPUT_CALLINDENT = 1U << 20, }; struct output_option { @@ -89,6 +91,7 @@ struct output_option { {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC}, {.str = "weight", .field = PERF_OUTPUT_WEIGHT}, {.str = "bpf-output", .field = PERF_OUTPUT_BPF_OUTPUT}, + {.str = "callindent", .field = PERF_OUTPUT_CALLINDENT}, }; /* default set to maintain compatibility with current format */ @@ -369,7 +372,7 @@ static int perf_session__check_output_opt(struct perf_session *session) if (!no_callchain) { bool use_callchain = false; - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { use_callchain = true; break; @@ -389,7 +392,7 @@ static int perf_session__check_output_opt(struct perf_session *session) j = PERF_TYPE_TRACEPOINT; - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (evsel->attr.type != j) continue; @@ -562,6 +565,62 @@ static void print_sample_addr(struct perf_sample *sample, } } +static void print_sample_callindent(struct perf_sample *sample, + struct perf_evsel *evsel, + struct thread *thread, + struct addr_location *al) +{ + struct perf_event_attr *attr = &evsel->attr; + size_t depth = thread_stack__depth(thread); + struct addr_location addr_al; + const char *name = NULL; + static int spacing; + int len = 0; + u64 ip = 0; + + /* + * The 'return' has already been popped off the stack so the depth has + * to be adjusted to match the 'call'. + */ + if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN) + depth += 1; + + if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { + if (sample_addr_correlates_sym(attr)) { + thread__resolve(thread, &addr_al, sample); + if (addr_al.sym) + name = addr_al.sym->name; + else + ip = sample->addr; + } else { + ip = sample->addr; + } + } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) { + if (al->sym) + name = al->sym->name; + else + ip = sample->ip; + } + + if (name) + len = printf("%*s%s", (int)depth * 4, "", name); + else if (ip) + len = printf("%*s%16" PRIx64, (int)depth * 4, "", ip); + + if (len < 0) + return; + + /* + * Try to keep the output length from changing frequently so that the + * output lines up more nicely. + */ + if (len > spacing || (len && len < spacing - 52)) + spacing = round_up(len + 4, 32); + + if (len < spacing) + printf("%*s", spacing - len, ""); +} + static void print_sample_bts(struct perf_sample *sample, struct perf_evsel *evsel, struct thread *thread, @@ -570,6 +629,9 @@ static void print_sample_bts(struct perf_sample *sample, struct perf_event_attr *attr = &evsel->attr; bool print_srcline_last = false; + if (PRINT_FIELD(CALLINDENT)) + print_sample_callindent(sample, evsel, thread, al); + /* print branch_from information */ if (PRINT_FIELD(IP)) { unsigned int print_opts = output[attr->type].print_ip_opts; @@ -606,13 +668,42 @@ static void print_sample_bts(struct perf_sample *sample, printf("\n"); } +static struct { + u32 flags; + const char *name; +} sample_flags[] = { + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "jcc"}, + {PERF_IP_FLAG_BRANCH, "jmp"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT, "int"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT, "iret"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET, "syscall"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET, "sysret"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "async"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | PERF_IP_FLAG_INTERRUPT, "hw int"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "tx abrt"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "tr strt"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "tr end"}, + {0, NULL} +}; + static void print_sample_flags(u32 flags) { const char *chars = PERF_IP_FLAG_CHARS; const int n = strlen(PERF_IP_FLAG_CHARS); + bool in_tx = flags & PERF_IP_FLAG_IN_TX; + const char *name = NULL; char str[33]; int i, pos = 0; + for (i = 0; sample_flags[i].name ; i++) { + if (sample_flags[i].flags == (flags & ~PERF_IP_FLAG_IN_TX)) { + name = sample_flags[i].name; + break; + } + } + for (i = 0; i < n; i++, flags >>= 1) { if (flags & 1) str[pos++] = chars[i]; @@ -622,7 +713,11 @@ static void print_sample_flags(u32 flags) str[pos++] = '?'; } str[pos] = 0; - printf(" %-4s ", str); + + if (name) + printf(" %-7s%4s ", name, in_tx ? "(x)" : ""); + else + printf(" %-11s ", str); } struct printer_data { @@ -720,7 +815,7 @@ static int perf_evlist__max_name_len(struct perf_evlist *evlist) struct perf_evsel *evsel; int max = 0; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { int len = strlen(perf_evsel__name(evsel)); max = MAX(len, max); @@ -945,7 +1040,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, if (evsel->attr.type >= PERF_TYPE_MAX) return 0; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { if (pos->attr.type == evsel->attr.type && pos != evsel) return 0; } @@ -1671,7 +1766,7 @@ static int check_ev_match(char *dir_name, char *scriptname, snprintf(evname, len + 1, "%s", p); match = 0; - evlist__for_each(session->evlist, pos) { + evlist__for_each_entry(session->evlist, pos) { if (!strcmp(perf_evsel__name(pos), evname)) { match = 1; break; @@ -1873,7 +1968,7 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused, struct stat_round_event *round = &event->stat_round; struct perf_evsel *counter; - evlist__for_each(session->evlist, counter) { + evlist__for_each_entry(session->evlist, counter) { perf_stat_process_counter(&stat_config, counter); process_stat(counter, round->time); } @@ -2020,7 +2115,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) "comma separated output fields prepend with 'type:'. " "Valid types: hw,sw,trace,raw. " "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," - "addr,symoff,period,iregs,brstack,brstacksym,flags", parse_output_fields), + "addr,symoff,period,iregs,brstack,brstacksym,flags," + "callindent", parse_output_fields), OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", @@ -2259,6 +2355,9 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) script.session = session; script__setup_sample_type(&script); + if (output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) + itrace_synth_opts.thread_stack = true; + session->itrace_synth_opts = &itrace_synth_opts; if (cpu_list) { diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index dff63733dfb7..c367a43525e6 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -331,7 +331,7 @@ static void read_counters(bool close_counters) { struct perf_evsel *counter; - evlist__for_each(evsel_list, counter) { + evlist__for_each_entry(evsel_list, counter) { if (read_counter(counter)) pr_debug("failed to read counter %s\n", counter->name); @@ -417,7 +417,7 @@ static int perf_stat_synthesize_config(bool is_pipe) * Synthesize other events stuff not carried within * attr event - unit, scale, name */ - evlist__for_each(evsel_list, counter) { + evlist__for_each_entry(evsel_list, counter) { if (!counter->supported) continue; @@ -550,7 +550,7 @@ static int __run_perf_stat(int argc, const char **argv) if (group) perf_evlist__set_leader(evsel_list); - evlist__for_each(evsel_list, counter) { + evlist__for_each_entry(evsel_list, counter) { try_again: if (create_perf_stat_counter(counter) < 0) { /* @@ -1134,7 +1134,7 @@ static void aggr_update_shadow(void) for (s = 0; s < aggr_map->nr; s++) { id = aggr_map->map[s]; - evlist__for_each(evsel_list, counter) { + evlist__for_each_entry(evsel_list, counter) { val = 0; for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { s2 = aggr_get_id(evsel_list->cpus, cpu); @@ -1173,7 +1173,7 @@ static void print_aggr(char *prefix) id = aggr_map->map[s]; first = true; - evlist__for_each(evsel_list, counter) { + evlist__for_each_entry(evsel_list, counter) { val = ena = run = 0; nr = 0; for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { @@ -1292,7 +1292,7 @@ static void print_no_aggr_metric(char *prefix) if (prefix) fputs(prefix, stat_config.output); - evlist__for_each(evsel_list, counter) { + evlist__for_each_entry(evsel_list, counter) { if (first) { aggr_printout(counter, cpu, 0); first = false; @@ -1346,7 +1346,7 @@ static void print_metric_headers(const char *prefix, bool no_indent) } /* Print metrics headers only */ - evlist__for_each(evsel_list, counter) { + evlist__for_each_entry(evsel_list, counter) { os.evsel = counter; out.ctx = &os; out.print_metric = print_metric_header; @@ -1482,11 +1482,11 @@ static void print_counters(struct timespec *ts, int argc, const char **argv) print_aggr(prefix); break; case AGGR_THREAD: - evlist__for_each(evsel_list, counter) + evlist__for_each_entry(evsel_list, counter) print_aggr_thread(counter, prefix); break; case AGGR_GLOBAL: - evlist__for_each(evsel_list, counter) + evlist__for_each_entry(evsel_list, counter) print_counter_aggr(counter, prefix); if (metric_only) fputc('\n', stat_config.output); @@ -1495,7 +1495,7 @@ static void print_counters(struct timespec *ts, int argc, const char **argv) if (metric_only) print_no_aggr_metric(prefix); else { - evlist__for_each(evsel_list, counter) + evlist__for_each_entry(evsel_list, counter) print_counter(counter, prefix); } break; @@ -2149,7 +2149,7 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused, const char **argv = session->header.env.cmdline_argv; int argc = session->header.env.nr_cmdline; - evlist__for_each(evsel_list, counter) + evlist__for_each_entry(evsel_list, counter) perf_stat_process_counter(&stat_config, counter); if (stat_round->type == PERF_STAT_ROUND_TYPE__FINAL) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 81dba80a42b5..07fc7921980c 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -22,7 +22,7 @@ #include "perf.h" #include "util/annotate.h" -#include "util/cache.h" +#include "util/config.h" #include "util/color.h" #include "util/evlist.h" #include "util/evsel.h" @@ -479,7 +479,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) fprintf(stderr, "\nAvailable events:"); - evlist__for_each(top->evlist, top->sym_evsel) + evlist__for_each_entry(top->evlist, top->sym_evsel) fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel)); prompt_integer(&counter, "Enter details event counter"); @@ -490,7 +490,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) sleep(1); break; } - evlist__for_each(top->evlist, top->sym_evsel) + evlist__for_each_entry(top->evlist, top->sym_evsel) if (top->sym_evsel->idx == counter) break; } else @@ -583,7 +583,7 @@ static void *display_thread_tui(void *arg) * Zooming in/out UIDs. For now juse use whatever the user passed * via --uid. */ - evlist__for_each(top->evlist, pos) { + evlist__for_each_entry(top->evlist, pos) { struct hists *hists = evsel__hists(pos); hists->uid_filter_str = top->record_opts.target.uid_str; } @@ -888,7 +888,7 @@ static int perf_top__start_counters(struct perf_top *top) perf_evlist__config(evlist, opts, &callchain_param); - evlist__for_each(evlist, counter) { + evlist__for_each_entry(evlist, counter) { try_again: if (perf_evsel__open(counter, top->evlist->cpus, top->evlist->threads) < 0) { diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 5c50fe70d6b3..cf90de811523 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1247,7 +1247,7 @@ static int trace__validate_ev_qualifier(struct trace *trace) i = 0; - strlist__for_each(pos, trace->ev_qualifier) { + strlist__for_each_entry(pos, trace->ev_qualifier) { const char *sc = pos->s; int id = syscalltbl__id(trace->sctbl, sc); @@ -2483,7 +2483,7 @@ static int trace__replay(struct trace *trace) goto out; } - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (evsel->attr.type == PERF_TYPE_SOFTWARE && (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ || evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN || @@ -2550,7 +2550,7 @@ static size_t thread__dump_stats(struct thread_trace *ttrace, printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n"); printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n"); - resort_rb__for_each(nd, syscall_stats) { + resort_rb__for_each_entry(nd, syscall_stats) { struct stats *stats = syscall_stats_entry->stats; if (stats) { double min = (double)(stats->min) / NSEC_PER_MSEC; @@ -2627,7 +2627,7 @@ static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) return 0; } - resort_rb__for_each(nd, threads) + resort_rb__for_each_entry(nd, threads) printed += trace__fprintf_thread(fp, threads_entry->thread, trace); resort_rb__delete(threads); @@ -2714,7 +2714,7 @@ static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) evsel->handler = handler; } diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 634bf7c6c477..8f219223f305 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -10,7 +10,7 @@ #include "util/env.h" #include <subcmd/exec-cmd.h> -#include "util/cache.h" +#include "util/config.h" #include "util/quote.h" #include <subcmd/run-command.h> #include "util/parse-events.h" @@ -355,6 +355,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) perf_env__set_cmdline(&perf_env, argc, argv); status = p->fn(argc, argv, prefix); + perf_config__exit(); exit_browser(status); perf_env__exit(&perf_env); bpf__clear(); @@ -522,6 +523,7 @@ int main(int argc, const char **argv) srandom(time(NULL)); + perf_config__init(); perf_config(perf_default_config, NULL); set_buildid_dir(NULL); diff --git a/tools/perf/scripts/python/stackcollapse.py b/tools/perf/scripts/python/stackcollapse.py index a2dfcda41ae6..5a605f70ef32 100755 --- a/tools/perf/scripts/python/stackcollapse.py +++ b/tools/perf/scripts/python/stackcollapse.py @@ -1,5 +1,3 @@ -#!/usr/bin/perl -w -# # stackcollapse.py - format perf samples with one line per distinct call stack # # This script's output has two space-separated fields. The first is a semicolon diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c index d9ba991a9a30..e70313fac5a5 100644 --- a/tools/perf/tests/backward-ring-buffer.c +++ b/tools/perf/tests/backward-ring-buffer.c @@ -118,7 +118,7 @@ int test__backward_ring_buffer(int subtest __maybe_unused) perf_evlist__config(evlist, &opts, NULL); /* Set backward bit, ring buffer should be writing from end */ - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) evsel->attr.write_backward = 1; err = perf_evlist__open(evlist); diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c index 95fb744f6628..9f5698ac81ae 100644 --- a/tools/perf/tests/event-times.c +++ b/tools/perf/tests/event-times.c @@ -200,8 +200,7 @@ static int test_times(int (attach)(struct perf_evlist *), count.ena, count.run); out_err: - if (evlist) - perf_evlist__delete(evlist); + perf_evlist__delete(evlist); return !err ? TEST_OK : TEST_FAIL; } diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index 2de4a4f2c3ed..60926a1f6fd7 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c @@ -80,7 +80,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names) } err = 0; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) { --err; pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]); diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index e846f8c42013..62efb14f3a5a 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c @@ -56,7 +56,7 @@ static int add_hist_entries(struct perf_evlist *evlist, * (perf [perf] main) will be collapsed to an existing entry * so total 9 entries will be in the tree. */ - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { for (i = 0; i < ARRAY_SIZE(fake_samples); i++) { struct hist_entry_iter iter = { .evsel = evsel, @@ -136,7 +136,7 @@ int test__hists_filter(int subtest __maybe_unused) if (err < 0) goto out; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { struct hists *hists = evsel__hists(evsel); hists__collapse_resort(hists, NULL); diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 6f96ca4d4fc0..eddc7407ff8a 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -72,7 +72,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) * However the second evsel also has a collapsed entry for * "bash [libc] malloc" so total 9 entries will be in the tree. */ - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { struct hists *hists = evsel__hists(evsel); for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { @@ -301,7 +301,7 @@ int test__hists_link(int subtest __maybe_unused) if (err < 0) goto out; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { hists = evsel__hists(evsel); hists__collapse_resort(hists, NULL); diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 359e98fcd94c..aea33f5589c5 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -126,7 +126,7 @@ int test__basic_mmap(int subtest __maybe_unused) } err = 0; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { pr_debug("expected %d %s events, got %d\n", expected_nr_events[evsel->idx], diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index b2a2c74136a5..20c2e641c422 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -32,7 +32,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); TEST_ASSERT_VAL("wrong sample_type", @@ -207,7 +207,7 @@ test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c index 294c76b01b41..81c6eeaca0f5 100644 --- a/tools/perf/tests/parse-no-sample-id-all.c +++ b/tools/perf/tests/parse-no-sample-id-all.c @@ -44,8 +44,7 @@ static int process_events(union perf_event **events, size_t count) for (i = 0; i < count && !err; i++) err = process_event(&evlist, events[i]); - if (evlist) - perf_evlist__delete(evlist); + perf_evlist__delete(evlist); return err; } diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c index 39a689bf7574..7ddbe267d0ac 100644 --- a/tools/perf/tests/switch-tracking.c +++ b/tools/perf/tests/switch-tracking.c @@ -432,7 +432,7 @@ int test__switch_tracking(int subtest __maybe_unused) } /* Check non-tracking events are not tracking */ - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel != tracking_evsel) { if (evsel->attr.mmap || evsel->attr.comm) { pr_debug("Non-tracking event is tracking\n"); diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index af68a9d488bf..3eb3edb307a4 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c @@ -1,5 +1,5 @@ #include "../util.h" -#include "../cache.h" +#include "../config.h" #include "../../perf.h" #include "libslang.h" #include "ui.h" diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 4fc208e82c6f..0e106bb97525 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -8,6 +8,7 @@ #include "../../util/sort.h" #include "../../util/symbol.h" #include "../../util/evsel.h" +#include "../../util/config.h" #include <pthread.h> struct disasm_line_samples { diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index b1b60544a545..e08b8f7b6d3f 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -12,35 +12,17 @@ #include "../../util/top.h" #include "../../arch/common.h" -#include "../browser.h" +#include "../browsers/hists.h" #include "../helpline.h" #include "../util.h" #include "../ui.h" #include "map.h" #include "annotate.h" -struct hist_browser { - struct ui_browser b; - struct hists *hists; - struct hist_entry *he_selection; - struct map_symbol *selection; - struct hist_browser_timer *hbt; - struct pstack *pstack; - struct perf_env *env; - int print_seq; - bool show_dso; - bool show_headers; - float min_pcnt; - u64 nr_non_filtered_entries; - u64 nr_hierarchy_entries; - u64 nr_callchain_rows; -}; - extern void hist_browser__init_hpp(void); -static int hists__browser_title(struct hists *hists, - struct hist_browser_timer *hbt, - char *bf, size_t size); +static int perf_evsel_browser_title(struct hist_browser *browser, + char *bf, size_t size); static void hist_browser__update_nr_entries(struct hist_browser *hb); static struct rb_node *hists__filter_entries(struct rb_node *nd, @@ -585,7 +567,12 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser) "Or reduce the sampling frequency."); } -static int hist_browser__run(struct hist_browser *browser, const char *help) +static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size) +{ + return browser->title ? browser->title(browser, bf, size) : 0; +} + +int hist_browser__run(struct hist_browser *browser, const char *help) { int key; char title[160]; @@ -595,7 +582,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *help) browser->b.entries = &browser->hists->entries; browser->b.nr_entries = hist_browser__nr_entries(browser); - hists__browser_title(browser->hists, hbt, title, sizeof(title)); + hist_browser__title(browser, title, sizeof(title)); if (ui_browser__show(&browser->b, title, "%s", help) < 0) return -1; @@ -621,8 +608,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *help) ui_browser__warn_lost_events(&browser->b); } - hists__browser_title(browser->hists, - hbt, title, sizeof(title)); + hist_browser__title(browser, title, sizeof(title)); ui_browser__show_title(&browser->b, title); continue; } @@ -2056,27 +2042,50 @@ static int hist_browser__dump(struct hist_browser *browser) return 0; } -static struct hist_browser *hist_browser__new(struct hists *hists, - struct hist_browser_timer *hbt, - struct perf_env *env) +void hist_browser__init(struct hist_browser *browser, + struct hists *hists) +{ + struct perf_hpp_fmt *fmt; + + browser->hists = hists; + browser->b.refresh = hist_browser__refresh; + browser->b.refresh_dimensions = hist_browser__refresh_dimensions; + browser->b.seek = ui_browser__hists_seek; + browser->b.use_navkeypressed = true; + browser->show_headers = symbol_conf.show_hist_headers; + + hists__for_each_format(hists, fmt) { + perf_hpp__reset_width(fmt, hists); + ++browser->b.columns; + } +} + +struct hist_browser *hist_browser__new(struct hists *hists) { struct hist_browser *browser = zalloc(sizeof(*browser)); + if (browser) + hist_browser__init(browser, hists); + + return browser; +} + +static struct hist_browser * +perf_evsel_browser__new(struct perf_evsel *evsel, + struct hist_browser_timer *hbt, + struct perf_env *env) +{ + struct hist_browser *browser = hist_browser__new(evsel__hists(evsel)); + if (browser) { - browser->hists = hists; - browser->b.refresh = hist_browser__refresh; - browser->b.refresh_dimensions = hist_browser__refresh_dimensions; - browser->b.seek = ui_browser__hists_seek; - browser->b.use_navkeypressed = true; - browser->show_headers = symbol_conf.show_hist_headers; - browser->hbt = hbt; - browser->env = env; + browser->hbt = hbt; + browser->env = env; + browser->title = perf_evsel_browser_title; } - return browser; } -static void hist_browser__delete(struct hist_browser *browser) +void hist_browser__delete(struct hist_browser *browser) { free(browser); } @@ -2097,10 +2106,11 @@ static inline bool is_report_browser(void *timer) return timer == NULL; } -static int hists__browser_title(struct hists *hists, - struct hist_browser_timer *hbt, +static int perf_evsel_browser_title(struct hist_browser *browser, char *bf, size_t size) { + struct hist_browser_timer *hbt = browser->hbt; + struct hists *hists = browser->hists; char unit; int printed; const struct dso *dso = hists->dso_filter; @@ -2657,7 +2667,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, struct perf_env *env) { struct hists *hists = evsel__hists(evsel); - struct hist_browser *browser = hist_browser__new(hists, hbt, env); + struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env); struct branch_info *bi; #define MAX_OPTIONS 16 char *options[MAX_OPTIONS]; @@ -2666,7 +2676,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, int key = -1; char buf[64]; int delay_secs = hbt ? hbt->refresh : 0; - struct perf_hpp_fmt *fmt; #define HIST_BROWSER_HELP_COMMON \ "h/?/F1 Show this window\n" \ @@ -2725,18 +2734,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, memset(options, 0, sizeof(options)); memset(actions, 0, sizeof(actions)); - hists__for_each_format(browser->hists, fmt) { - perf_hpp__reset_width(fmt, hists); - /* - * This is done just once, and activates the horizontal scrolling - * code in the ui_browser code, it would be better to have a the - * counter in the perf_hpp code, but I couldn't find doing it here - * works, FIXME by setting this in hist_browser__new, for now, be - * clever 8-) - */ - ++browser->b.columns; - } - if (symbol_conf.col_width_list_str) perf_hpp__set_user_width(symbol_conf.col_width_list_str); @@ -3202,7 +3199,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, ui_helpline__push("Press ESC to exit"); - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { const char *ev_name = perf_evsel__name(pos); size_t line_len = strlen(ev_name) + 7; @@ -3233,7 +3230,7 @@ single_entry: struct perf_evsel *pos; nr_entries = 0; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { if (perf_evsel__is_group_leader(pos)) nr_entries++; } diff --git a/tools/perf/ui/browsers/hists.h b/tools/perf/ui/browsers/hists.h new file mode 100644 index 000000000000..39bd0f28f211 --- /dev/null +++ b/tools/perf/ui/browsers/hists.h @@ -0,0 +1,32 @@ +#ifndef _PERF_UI_BROWSER_HISTS_H_ +#define _PERF_UI_BROWSER_HISTS_H_ 1 + +#include "ui/browser.h" + +struct hist_browser { + struct ui_browser b; + struct hists *hists; + struct hist_entry *he_selection; + struct map_symbol *selection; + struct hist_browser_timer *hbt; + struct pstack *pstack; + struct perf_env *env; + int print_seq; + bool show_dso; + bool show_headers; + float min_pcnt; + u64 nr_non_filtered_entries; + u64 nr_hierarchy_entries; + u64 nr_callchain_rows; + + /* Get title string. */ + int (*title)(struct hist_browser *browser, + char *bf, size_t size); +}; + +struct hist_browser *hist_browser__new(struct hists *hists); +void hist_browser__delete(struct hist_browser *browser); +int hist_browser__run(struct hist_browser *browser, const char *help); +void hist_browser__init(struct hist_browser *browser, + struct hists *hists); +#endif /* _PERF_UI_BROWSER_HISTS_H_ */ diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index e5c1325b0340..c5f3677f6679 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -627,7 +627,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, gtk_container_add(GTK_CONTAINER(window), vbox); - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { struct hists *hists = evsel__hists(pos); const char *evname = perf_evsel__name(pos); GtkWidget *scrolled_window; diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 6940745aa77c..4274969ddc89 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -766,7 +766,7 @@ int perf_hpp__setup_hists_formats(struct perf_hpp_list *list, if (!symbol_conf.report_hierarchy) return 0; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { hists = evsel__hists(evsel); perf_hpp_list__for_each_sort_list(list, fmt) { diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c index c0b43ee40d95..6c80f830358b 100644 --- a/tools/perf/util/alias.c +++ b/tools/perf/util/alias.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" static const char *alias_key; static char *alias_val; diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 767989e0e312..ac5f0d7167e6 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -63,6 +63,7 @@ enum itrace_period_type { * @calls: limit branch samples to calls (can be combined with @returns) * @returns: limit branch samples to returns (can be combined with @calls) * @callchain: add callchain to 'instructions' events + * @thread_stack: feed branches to the thread_stack * @last_branch: add branch context to 'instruction' events * @callchain_sz: maximum callchain size * @last_branch_sz: branch context size @@ -82,6 +83,7 @@ struct itrace_synth_opts { bool calls; bool returns; bool callchain; + bool thread_stack; bool last_branch; unsigned int callchain_sz; unsigned int last_branch_sz; diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 369f382eedb6..9f90e36b56fb 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h @@ -18,17 +18,6 @@ #define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR" #define PERF_PAGER_ENVIRONMENT "PERF_PAGER" -extern const char *config_exclusive_filename; - -typedef int (*config_fn_t)(const char *, const char *, void *); -int perf_default_config(const char *, const char *, void *); -int perf_config(config_fn_t fn, void *); -int perf_config_int(const char *, const char *); -u64 perf_config_u64(const char *, const char *); -int perf_config_bool(const char *, const char *); -int config_error_nonbool(const char *); -const char *perf_etc_perfconfig(void); - char *alias_lookup(const char *alias); int split_cmdline(char *cmdline, const char ***argv); diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index 90aa1b46b2e5..8fdee24725a7 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c @@ -81,7 +81,7 @@ static int add_cgroup(struct perf_evlist *evlist, char *str) /* * check if cgrp is already defined, if so we reuse it */ - evlist__for_each(evlist, counter) { + evlist__for_each_entry(evlist, counter) { cgrp = counter->cgrp; if (!cgrp) continue; @@ -110,7 +110,7 @@ static int add_cgroup(struct perf_evlist *evlist, char *str) * if add cgroup N, then need to find event N */ n = 0; - evlist__for_each(evlist, counter) { + evlist__for_each_entry(evlist, counter) { if (n == nr_cgroups) goto found; n++; diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index 43e84aa27e4a..1210ba555d07 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c @@ -1,5 +1,6 @@ #include <linux/kernel.h> #include "cache.h" +#include "config.h" #include "color.h" #include <math.h> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index d15c59267644..18dae745034f 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -26,6 +26,7 @@ static FILE *config_file; static const char *config_file_name; static int config_linenr; static int config_file_eof; +static struct perf_config_set *config_set; const char *config_exclusive_filename; @@ -478,51 +479,6 @@ static int perf_config_global(void) return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0); } -int perf_config(config_fn_t fn, void *data) -{ - int ret = -1; - const char *home = NULL; - - /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ - if (config_exclusive_filename) - return perf_config_from_file(fn, config_exclusive_filename, data); - if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) { - if (perf_config_from_file(fn, perf_etc_perfconfig(), data) < 0) - goto out; - } - - home = getenv("HOME"); - if (perf_config_global() && home) { - char *user_config = strdup(mkpath("%s/.perfconfig", home)); - struct stat st; - - if (user_config == NULL) { - warning("Not enough memory to process %s/.perfconfig, " - "ignoring it.", home); - goto out; - } - - if (stat(user_config, &st) < 0) - goto out_free; - - if (st.st_uid && (st.st_uid != geteuid())) { - warning("File %s not owned by current user or root, " - "ignoring it.", user_config); - goto out_free; - } - - if (!st.st_size) - goto out_free; - - ret = perf_config_from_file(fn, user_config, data); - -out_free: - free(user_config); - } -out: - return ret; -} - static struct perf_config_section *find_section(struct list_head *sections, const char *section_name) { @@ -706,6 +662,52 @@ struct perf_config_set *perf_config_set__new(void) return set; } +int perf_config(config_fn_t fn, void *data) +{ + int ret = 0; + char key[BUFSIZ]; + struct perf_config_section *section; + struct perf_config_item *item; + + if (config_set == NULL) + return -1; + + perf_config_set__for_each_entry(config_set, section, item) { + char *value = item->value; + + if (value) { + scnprintf(key, sizeof(key), "%s.%s", + section->name, item->name); + ret = fn(key, value, data); + if (ret < 0) { + pr_err("Error: wrong config key-value pair %s=%s\n", + key, value); + break; + } + } + } + + return ret; +} + +void perf_config__init(void) +{ + if (config_set == NULL) + config_set = perf_config_set__new(); +} + +void perf_config__exit(void) +{ + perf_config_set__delete(config_set); + config_set = NULL; +} + +void perf_config__refresh(void) +{ + perf_config__exit(); + perf_config__init(); +} + static void perf_config_item__delete(struct perf_config_item *item) { zfree(&item->name); diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h index 22ec626ac718..6f813d46045e 100644 --- a/tools/perf/util/config.h +++ b/tools/perf/util/config.h @@ -20,7 +20,47 @@ struct perf_config_set { struct list_head sections; }; +extern const char *config_exclusive_filename; + +typedef int (*config_fn_t)(const char *, const char *, void *); +int perf_default_config(const char *, const char *, void *); +int perf_config(config_fn_t fn, void *); +int perf_config_int(const char *, const char *); +u64 perf_config_u64(const char *, const char *); +int perf_config_bool(const char *, const char *); +int config_error_nonbool(const char *); +const char *perf_etc_perfconfig(void); + struct perf_config_set *perf_config_set__new(void); void perf_config_set__delete(struct perf_config_set *set); +void perf_config__init(void); +void perf_config__exit(void); +void perf_config__refresh(void); + +/** + * perf_config_sections__for_each - iterate thru all the sections + * @list: list_head instance to iterate + * @section: struct perf_config_section iterator + */ +#define perf_config_sections__for_each_entry(list, section) \ + list_for_each_entry(section, list, node) + +/** + * perf_config_items__for_each - iterate thru all the items + * @list: list_head instance to iterate + * @item: struct perf_config_item iterator + */ +#define perf_config_items__for_each_entry(list, item) \ + list_for_each_entry(item, list, node) + +/** + * perf_config_set__for_each - iterate thru all the config section-item pairs + * @set: evlist instance to iterate + * @section: struct perf_config_section iterator + * @item: struct perf_config_item iterator + */ +#define perf_config_set__for_each_entry(set, section, item) \ + perf_config_sections__for_each_entry(&set->sections, section) \ + perf_config_items__for_each_entry(§ion->items, item) #endif /* __PERF_CONFIG_H */ diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 9f53020c3269..4b59879391c0 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -997,7 +997,7 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session) struct perf_evsel *evsel; int ret; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { ret = add_event(cw, evsel); if (ret) return ret; @@ -1010,7 +1010,7 @@ static void cleanup_events(struct perf_session *session) struct perf_evlist *evlist = session->evlist; struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { struct evsel_priv *priv; priv = evsel->priv; diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 1b918aa075d6..113507716044 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -100,7 +100,7 @@ static void perf_evlist__update_id_pos(struct perf_evlist *evlist) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) perf_evsel__calc_id_pos(evsel); perf_evlist__set_id_pos(evlist); @@ -110,7 +110,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist) { struct perf_evsel *pos, *n; - evlist__for_each_safe(evlist, n, pos) { + evlist__for_each_entry_safe(evlist, n, pos) { list_del_init(&pos->node); pos->evlist = NULL; perf_evsel__delete(pos); @@ -127,6 +127,9 @@ void perf_evlist__exit(struct perf_evlist *evlist) void perf_evlist__delete(struct perf_evlist *evlist) { + if (evlist == NULL) + return; + perf_evlist__munmap(evlist); perf_evlist__close(evlist); cpu_map__put(evlist->cpus); @@ -161,7 +164,7 @@ static void perf_evlist__propagate_maps(struct perf_evlist *evlist) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) __perf_evlist__propagate_maps(evlist, evsel); } @@ -190,7 +193,7 @@ void perf_evlist__splice_list_tail(struct perf_evlist *evlist, { struct perf_evsel *evsel, *temp; - __evlist__for_each_safe(list, temp, evsel) { + __evlist__for_each_entry_safe(list, temp, evsel) { list_del_init(&evsel->node); perf_evlist__add(evlist, evsel); } @@ -205,7 +208,7 @@ void __perf_evlist__set_leader(struct list_head *list) leader->nr_members = evsel->idx - leader->idx + 1; - __evlist__for_each(list, evsel) { + __evlist__for_each_entry(list, evsel) { evsel->leader = leader; } } @@ -296,7 +299,7 @@ static int perf_evlist__add_attrs(struct perf_evlist *evlist, return 0; out_delete_partial_list: - __evlist__for_each_safe(&head, n, evsel) + __evlist__for_each_entry_safe(&head, n, evsel) perf_evsel__delete(evsel); return -1; } @@ -317,7 +320,7 @@ perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type == PERF_TYPE_TRACEPOINT && (int)evsel->attr.config == id) return evsel; @@ -332,7 +335,7 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist, { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) && (strcmp(evsel->name, name) == 0)) return evsel; @@ -367,7 +370,7 @@ void perf_evlist__disable(struct perf_evlist *evlist) { struct perf_evsel *pos; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { if (!perf_evsel__is_group_leader(pos) || !pos->fd) continue; perf_evsel__disable(pos); @@ -380,7 +383,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) { struct perf_evsel *pos; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { if (!perf_evsel__is_group_leader(pos) || !pos->fd) continue; perf_evsel__enable(pos); @@ -448,7 +451,7 @@ int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) int nfds = 0; struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->system_wide) nfds += nr_cpus; else @@ -1012,7 +1015,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, struct perf_evsel *evsel; int revent; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { int fd; if (evsel->overwrite != (evlist->overwrite && evlist->backward)) @@ -1259,7 +1262,7 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, auxtrace_mmap_params__init(&mp.auxtrace_mp, evlist->mmap_len, auxtrace_pages, auxtrace_overwrite); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if ((evsel->attr.read_format & PERF_FORMAT_ID) && evsel->sample_id == NULL && perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0) @@ -1335,7 +1338,7 @@ void __perf_evlist__set_sample_bit(struct perf_evlist *evlist, { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) __perf_evsel__set_sample_bit(evsel, bit); } @@ -1344,7 +1347,7 @@ void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist, { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) __perf_evsel__reset_sample_bit(evsel, bit); } @@ -1355,7 +1358,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **e const int ncpus = cpu_map__nr(evlist->cpus), nthreads = thread_map__nr(evlist->threads); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->filter == NULL) continue; @@ -1378,7 +1381,7 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter) struct perf_evsel *evsel; int err = 0; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type != PERF_TYPE_TRACEPOINT) continue; @@ -1432,7 +1435,7 @@ bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) if (evlist->id_pos < 0 || evlist->is_pos < 0) return false; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { if (pos->id_pos != evlist->id_pos || pos->is_pos != evlist->is_pos) return false; @@ -1448,7 +1451,7 @@ u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist) if (evlist->combined_sample_type) return evlist->combined_sample_type; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) evlist->combined_sample_type |= evsel->attr.sample_type; return evlist->combined_sample_type; @@ -1465,7 +1468,7 @@ u64 perf_evlist__combined_branch_type(struct perf_evlist *evlist) struct perf_evsel *evsel; u64 branch_type = 0; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) branch_type |= evsel->attr.branch_sample_type; return branch_type; } @@ -1476,7 +1479,7 @@ bool perf_evlist__valid_read_format(struct perf_evlist *evlist) u64 read_format = first->attr.read_format; u64 sample_type = first->attr.sample_type; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { if (read_format != pos->attr.read_format) return false; } @@ -1533,7 +1536,7 @@ bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist) { struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; - evlist__for_each_continue(evlist, pos) { + evlist__for_each_entry_continue(evlist, pos) { if (first->attr.sample_id_all != pos->attr.sample_id_all) return false; } @@ -1560,7 +1563,7 @@ void perf_evlist__close(struct perf_evlist *evlist) int nthreads = thread_map__nr(evlist->threads); int n; - evlist__for_each_reverse(evlist, evsel) { + evlist__for_each_entry_reverse(evlist, evsel) { n = evsel->cpus ? evsel->cpus->nr : ncpus; perf_evsel__close(evsel, n, nthreads); } @@ -1614,7 +1617,7 @@ int perf_evlist__open(struct perf_evlist *evlist) perf_evlist__update_id_pos(evlist); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { err = perf_evsel__open(evsel, evsel->cpus, evsel->threads); if (err < 0) goto out_err; @@ -1775,7 +1778,7 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) struct perf_evsel *evsel; size_t printed = 0; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "", perf_evsel__name(evsel)); } @@ -1877,7 +1880,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, if (move_evsel == perf_evlist__first(evlist)) return; - evlist__for_each_safe(evlist, n, evsel) { + evlist__for_each_entry_safe(evlist, n, evsel) { if (evsel->leader == move_evsel->leader) list_move_tail(&evsel->node, &move); } @@ -1893,7 +1896,7 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist, if (tracking_evsel->tracking) return; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel != tracking_evsel) evsel->tracking = false; } @@ -1907,7 +1910,7 @@ perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (!evsel->name) continue; if (strcmp(str, evsel->name) == 0) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 68cb1361c97c..872912b392c9 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -251,70 +251,70 @@ void perf_evlist__to_front(struct perf_evlist *evlist, struct perf_evsel *move_evsel); /** - * __evlist__for_each - iterate thru all the evsels + * __evlist__for_each_entry - iterate thru all the evsels * @list: list_head instance to iterate * @evsel: struct evsel iterator */ -#define __evlist__for_each(list, evsel) \ +#define __evlist__for_each_entry(list, evsel) \ list_for_each_entry(evsel, list, node) /** - * evlist__for_each - iterate thru all the evsels + * evlist__for_each_entry - iterate thru all the evsels * @evlist: evlist instance to iterate * @evsel: struct evsel iterator */ -#define evlist__for_each(evlist, evsel) \ - __evlist__for_each(&(evlist)->entries, evsel) +#define evlist__for_each_entry(evlist, evsel) \ + __evlist__for_each_entry(&(evlist)->entries, evsel) /** - * __evlist__for_each_continue - continue iteration thru all the evsels + * __evlist__for_each_entry_continue - continue iteration thru all the evsels * @list: list_head instance to iterate * @evsel: struct evsel iterator */ -#define __evlist__for_each_continue(list, evsel) \ +#define __evlist__for_each_entry_continue(list, evsel) \ list_for_each_entry_continue(evsel, list, node) /** - * evlist__for_each_continue - continue iteration thru all the evsels + * evlist__for_each_entry_continue - continue iteration thru all the evsels * @evlist: evlist instance to iterate * @evsel: struct evsel iterator */ -#define evlist__for_each_continue(evlist, evsel) \ - __evlist__for_each_continue(&(evlist)->entries, evsel) +#define evlist__for_each_entry_continue(evlist, evsel) \ + __evlist__for_each_entry_continue(&(evlist)->entries, evsel) /** - * __evlist__for_each_reverse - iterate thru all the evsels in reverse order + * __evlist__for_each_entry_reverse - iterate thru all the evsels in reverse order * @list: list_head instance to iterate * @evsel: struct evsel iterator */ -#define __evlist__for_each_reverse(list, evsel) \ +#define __evlist__for_each_entry_reverse(list, evsel) \ list_for_each_entry_reverse(evsel, list, node) /** - * evlist__for_each_reverse - iterate thru all the evsels in reverse order + * evlist__for_each_entry_reverse - iterate thru all the evsels in reverse order * @evlist: evlist instance to iterate * @evsel: struct evsel iterator */ -#define evlist__for_each_reverse(evlist, evsel) \ - __evlist__for_each_reverse(&(evlist)->entries, evsel) +#define evlist__for_each_entry_reverse(evlist, evsel) \ + __evlist__for_each_entry_reverse(&(evlist)->entries, evsel) /** - * __evlist__for_each_safe - safely iterate thru all the evsels + * __evlist__for_each_entry_safe - safely iterate thru all the evsels * @list: list_head instance to iterate * @tmp: struct evsel temp iterator * @evsel: struct evsel iterator */ -#define __evlist__for_each_safe(list, tmp, evsel) \ +#define __evlist__for_each_entry_safe(list, tmp, evsel) \ list_for_each_entry_safe(evsel, tmp, list, node) /** - * evlist__for_each_safe - safely iterate thru all the evsels + * evlist__for_each_entry_safe - safely iterate thru all the evsels * @evlist: evlist instance to iterate * @evsel: struct evsel iterator * @tmp: struct evsel temp iterator */ -#define evlist__for_each_safe(evlist, tmp, evsel) \ - __evlist__for_each_safe(&(evlist)->entries, tmp, evsel) +#define evlist__for_each_entry_safe(evlist, tmp, evsel) \ + __evlist__for_each_entry_safe(&(evlist)->entries, tmp, evsel) void perf_evlist__set_tracking_event(struct perf_evlist *evlist, struct perf_evsel *tracking_evsel); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 08852dde1378..c5cd2698281f 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -336,7 +336,7 @@ static int write_event_desc(int fd, struct perf_header *h __maybe_unused, if (ret < 0) return ret; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { ret = do_write(fd, &evsel->attr, sz); if (ret < 0) return ret; @@ -801,7 +801,7 @@ static int write_group_desc(int fd, struct perf_header *h __maybe_unused, if (ret < 0) return ret; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1) { const char *name = evsel->group_name ?: "{anon_group}"; @@ -1425,7 +1425,7 @@ static void print_group_desc(struct perf_header *ph, int fd __maybe_unused, session = container_of(ph, struct perf_session, header); - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1) { fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", @@ -1703,7 +1703,7 @@ perf_evlist__find_by_index(struct perf_evlist *evlist, int idx) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->idx == idx) return evsel; } @@ -2075,7 +2075,7 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused, session->evlist->nr_groups = nr_groups; i = nr = 0; - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (evsel->idx == (int) desc[i].leader_idx) { evsel->leader = evsel; /* {anon_group} is a dummy name */ @@ -2383,7 +2383,7 @@ int perf_session__write_header(struct perf_session *session, lseek(fd, sizeof(f_header), SEEK_SET); - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { evsel->id_offset = lseek(fd, 0, SEEK_CUR); err = do_write(fd, evsel->id, evsel->ids * sizeof(u64)); if (err < 0) { @@ -2394,7 +2394,7 @@ int perf_session__write_header(struct perf_session *session, attr_offset = lseek(fd, 0, SEEK_CUR); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { f_attr = (struct perf_file_attr){ .attr = evsel->attr, .ids = { @@ -2828,7 +2828,7 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, { struct perf_evsel *pos; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { if (pos->attr.type == PERF_TYPE_TRACEPOINT && perf_evsel__prepare_tracepoint_event(pos, pevent)) return -1; @@ -3127,7 +3127,7 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_evsel *evsel; int err = 0; - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids, evsel->id, process); if (err) { diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c index d62ccaeeadd6..776e28562345 100644 --- a/tools/perf/util/help-unknown-cmd.c +++ b/tools/perf/util/help-unknown-cmd.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include <subcmd/help.h> #include "../builtin.h" #include "levenshtein.h" diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index d2647b1d82c0..e1fcc8d7c01a 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -79,7 +79,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) len = thread__comm_len(h->thread); if (hists__new_col_len(hists, HISTC_COMM, len)) - hists__set_col_len(hists, HISTC_THREAD, len + 6); + hists__set_col_len(hists, HISTC_THREAD, len + 8); if (h->ms.map) { len = dso__name_len(h->ms.map->dso); @@ -2199,7 +2199,7 @@ size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp) struct perf_evsel *pos; size_t ret = 0; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); ret += events_stats__fprintf(&evsel__hists(pos)->stats, fp); } diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index 9df996085563..749e6f2e37ca 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c @@ -422,7 +422,8 @@ static int intel_bts_get_branch_type(struct intel_bts_queue *btsq, } static int intel_bts_process_buffer(struct intel_bts_queue *btsq, - struct auxtrace_buffer *buffer) + struct auxtrace_buffer *buffer, + struct thread *thread) { struct branch *branch; size_t sz, bsz = sizeof(struct branch); @@ -444,6 +445,12 @@ static int intel_bts_process_buffer(struct intel_bts_queue *btsq, if (!branch->from && !branch->to) continue; intel_bts_get_branch_type(btsq, branch); + if (btsq->bts->synth_opts.thread_stack) + thread_stack__event(thread, btsq->sample_flags, + le64_to_cpu(branch->from), + le64_to_cpu(branch->to), + btsq->intel_pt_insn.length, + buffer->buffer_nr + 1); if (filter && !(filter & btsq->sample_flags)) continue; err = intel_bts_synth_branch_sample(btsq, branch); @@ -507,12 +514,13 @@ static int intel_bts_process_queue(struct intel_bts_queue *btsq, u64 *timestamp) goto out_put; } - if (!btsq->bts->synth_opts.callchain && thread && + if (!btsq->bts->synth_opts.callchain && + !btsq->bts->synth_opts.thread_stack && thread && (!old_buffer || btsq->bts->sampling_mode || (btsq->bts->snapshot_mode && !buffer->consecutive))) thread_stack__set_trace_nr(thread, buffer->buffer_nr + 1); - err = intel_bts_process_buffer(btsq, buffer); + err = intel_bts_process_buffer(btsq, buffer, thread); auxtrace_buffer__drop_data(buffer); @@ -777,7 +785,7 @@ static int intel_bts_synth_events(struct intel_bts *bts, u64 id; int err; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type == bts->pmu_type && evsel->ids) { found = true; break; @@ -905,10 +913,14 @@ int intel_bts_process_auxtrace_info(union perf_event *event, if (dump_trace) return 0; - if (session->itrace_synth_opts && session->itrace_synth_opts->set) + if (session->itrace_synth_opts && session->itrace_synth_opts->set) { bts->synth_opts = *session->itrace_synth_opts; - else + } else { itrace_synth_opts__set_default(&bts->synth_opts); + if (session->itrace_synth_opts) + bts->synth_opts.thread_stack = + session->itrace_synth_opts->thread_stack; + } if (bts->synth_opts.calls) bts->branches_filter |= PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 137196990012..551ff6f640be 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -39,6 +39,7 @@ #include "auxtrace.h" #include "tsc.h" #include "intel-pt.h" +#include "config.h" #include "intel-pt-decoder/intel-pt-log.h" #include "intel-pt-decoder/intel-pt-decoder.h" @@ -556,7 +557,7 @@ static bool intel_pt_exclude_kernel(struct intel_pt *pt) { struct perf_evsel *evsel; - evlist__for_each(pt->session->evlist, evsel) { + evlist__for_each_entry(pt->session->evlist, evsel) { if (intel_pt_get_config(pt, &evsel->attr, NULL) && !evsel->attr.exclude_kernel) return false; @@ -572,7 +573,7 @@ static bool intel_pt_return_compression(struct intel_pt *pt) if (!pt->noretcomp_bit) return true; - evlist__for_each(pt->session->evlist, evsel) { + evlist__for_each_entry(pt->session->evlist, evsel) { if (intel_pt_get_config(pt, &evsel->attr, &config) && (config & pt->noretcomp_bit)) return false; @@ -592,7 +593,7 @@ static unsigned int intel_pt_mtc_period(struct intel_pt *pt) for (shift = 0, config = pt->mtc_freq_bits; !(config & 1); shift++) config >>= 1; - evlist__for_each(pt->session->evlist, evsel) { + evlist__for_each_entry(pt->session->evlist, evsel) { if (intel_pt_get_config(pt, &evsel->attr, &config)) return (config & pt->mtc_freq_bits) >> shift; } @@ -608,7 +609,7 @@ static bool intel_pt_timeless_decoding(struct intel_pt *pt) if (!pt->tsc_bit || !pt->cap_user_time_zero) return true; - evlist__for_each(pt->session->evlist, evsel) { + evlist__for_each_entry(pt->session->evlist, evsel) { if (!(evsel->attr.sample_type & PERF_SAMPLE_TIME)) return true; if (intel_pt_get_config(pt, &evsel->attr, &config)) { @@ -625,7 +626,7 @@ static bool intel_pt_tracing_kernel(struct intel_pt *pt) { struct perf_evsel *evsel; - evlist__for_each(pt->session->evlist, evsel) { + evlist__for_each_entry(pt->session->evlist, evsel) { if (intel_pt_get_config(pt, &evsel->attr, NULL) && !evsel->attr.exclude_kernel) return true; @@ -642,7 +643,7 @@ static bool intel_pt_have_tsc(struct intel_pt *pt) if (!pt->tsc_bit) return false; - evlist__for_each(pt->session->evlist, evsel) { + evlist__for_each_entry(pt->session->evlist, evsel) { if (intel_pt_get_config(pt, &evsel->attr, &config)) { if (config & pt->tsc_bit) have_tsc = true; @@ -1233,7 +1234,7 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) if (!(state->type & INTEL_PT_BRANCH)) return 0; - if (pt->synth_opts.callchain) + if (pt->synth_opts.callchain || pt->synth_opts.thread_stack) thread_stack__event(ptq->thread, ptq->flags, state->from_ip, state->to_ip, ptq->insn_len, state->trace_nr); @@ -1850,7 +1851,7 @@ static int intel_pt_synth_events(struct intel_pt *pt, u64 id; int err; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type == pt->pmu_type && evsel->ids) { found = true; break; @@ -1930,7 +1931,7 @@ static int intel_pt_synth_events(struct intel_pt *pt, pt->sample_transactions = true; pt->transactions_id = id; id += 1; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->id && evsel->id[0] == pt->transactions_id) { if (evsel->name) zfree(&evsel->name); @@ -1968,7 +1969,7 @@ static struct perf_evsel *intel_pt_find_sched_switch(struct perf_evlist *evlist) { struct perf_evsel *evsel; - evlist__for_each_reverse(evlist, evsel) { + evlist__for_each_entry_reverse(evlist, evsel) { const char *name = perf_evsel__name(evsel); if (!strcmp(name, "sched:sched_switch")) @@ -1982,7 +1983,7 @@ static bool intel_pt_find_switch(struct perf_evlist *evlist) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.context_switch) return true; } @@ -2136,6 +2137,9 @@ int intel_pt_process_auxtrace_info(union perf_event *event, pt->synth_opts.branches = false; pt->synth_opts.callchain = true; } + if (session->itrace_synth_opts) + pt->synth_opts.thread_stack = + session->itrace_synth_opts->thread_stack; } if (pt->synth_opts.log) diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h index aa6877d36858..020b9ca1b47e 100644 --- a/tools/perf/util/intlist.h +++ b/tools/perf/util/intlist.h @@ -57,21 +57,21 @@ static inline struct int_node *intlist__next(struct int_node *in) } /** - * intlist_for_each - iterate over a intlist + * intlist__for_each_entry - iterate over a intlist * @pos: the &struct int_node to use as a loop cursor. * @ilist: the &struct intlist for loop. */ -#define intlist__for_each(pos, ilist) \ +#define intlist__for_each_entry(pos, ilist) \ for (pos = intlist__first(ilist); pos; pos = intlist__next(pos)) /** - * intlist_for_each_safe - iterate over a intlist safe against removal of + * intlist__for_each_entry_safe - iterate over a intlist safe against removal of * int_node * @pos: the &struct int_node to use as a loop cursor. * @n: another &struct int_node to use as temporary storage. * @ilist: the &struct intlist for loop. */ -#define intlist__for_each_safe(pos, n, ilist) \ +#define intlist__for_each_entry_safe(pos, n, ilist) \ for (pos = intlist__first(ilist), n = intlist__next(pos); pos;\ pos = n, n = intlist__next(n)) #endif /* __PERF_INTLIST_H */ diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c index 86afe9618bb0..9f3305f6b6d5 100644 --- a/tools/perf/util/jitdump.c +++ b/tools/perf/util/jitdump.c @@ -108,7 +108,7 @@ jit_validate_events(struct perf_session *session) /* * check that all events use CLOCK_MONOTONIC */ - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC) return -1; } diff --git a/tools/perf/util/libunwind/arm64.c b/tools/perf/util/libunwind/arm64.c index 4fb5395669f8..6559bc586643 100644 --- a/tools/perf/util/libunwind/arm64.c +++ b/tools/perf/util/libunwind/arm64.c @@ -13,7 +13,12 @@ #define REMOTE_UNWIND_LIBUNWIND +/* Define arch specific functions & regs for libunwind, should be + * defined before including "unwind.h" + */ #define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arm64_reg_id(regnum) +#define LIBUNWIND__ARCH_REG_IP PERF_REG_ARM64_PC +#define LIBUNWIND__ARCH_REG_SP PERF_REG_ARM64_SP #include "unwind.h" #include "debug.h" diff --git a/tools/perf/util/libunwind/x86_32.c b/tools/perf/util/libunwind/x86_32.c index d98c17e19a2b..957ffff72428 100644 --- a/tools/perf/util/libunwind/x86_32.c +++ b/tools/perf/util/libunwind/x86_32.c @@ -12,7 +12,13 @@ */ #define REMOTE_UNWIND_LIBUNWIND + +/* Define arch specific functions & regs for libunwind, should be + * defined before including "unwind.h" + */ #define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__x86_reg_id(regnum) +#define LIBUNWIND__ARCH_REG_IP PERF_REG_X86_IP +#define LIBUNWIND__ARCH_REG_SP PERF_REG_X86_SP #include "unwind.h" #include "debug.h" diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index 878a566763c3..40b6f7269cb4 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c @@ -8,6 +8,7 @@ #include <stdlib.h> #include "debug.h" #include "llvm-utils.h" +#include "config.h" #define CLANG_BPF_CMD_DEFAULT_TEMPLATE \ "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\ diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index a0c186acb1f3..bc2cdbd09a25 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -138,8 +138,10 @@ void machine__exit(struct machine *machine) void machine__delete(struct machine *machine) { - machine__exit(machine); - free(machine); + if (machine) { + machine__exit(machine); + free(machine); + } } void machines__init(struct machines *machines) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index d15e335842b7..ebd87b773f56 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1396,7 +1396,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add) if (!add && get_event_modifier(&mod, str, NULL)) return -EINVAL; - __evlist__for_each(list, evsel) { + __evlist__for_each_entry(list, evsel) { if (add && get_event_modifier(&mod, str, evsel)) return -EINVAL; @@ -1422,7 +1422,7 @@ int parse_events_name(struct list_head *list, char *name) { struct perf_evsel *evsel; - __evlist__for_each(list, evsel) { + __evlist__for_each_entry(list, evsel) { if (!evsel->name) evsel->name = strdup(name); } diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 084756c17309..55f41d5e20d1 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -102,10 +102,8 @@ out: void exit_probe_symbol_maps(void) { - if (host_machine) { - machine__delete(host_machine); - host_machine = NULL; - } + machine__delete(host_machine); + host_machine = NULL; symbol__exit(); } @@ -898,7 +896,7 @@ static int __show_line_range(struct line_range *lr, const char *module, goto end; } - intlist__for_each(ln, lr->line_list) { + intlist__for_each_entry(ln, lr->line_list) { for (; ln->i > l; l++) { ret = show_one_line(fp, l - lr->offset); if (ret < 0) @@ -982,7 +980,7 @@ static int show_available_vars_at(struct debuginfo *dinfo, zfree(&vl->point.symbol); nvars = 0; if (vl->vars) { - strlist__for_each(node, vl->vars) { + strlist__for_each_entry(node, vl->vars) { var = strchr(node->s, '\t') + 1; if (strfilter__compare(_filter, var)) { fprintf(stdout, "\t\t%s\n", node->s); @@ -2335,7 +2333,7 @@ static int __show_perf_probe_events(int fd, bool is_kprobe, if (!rawlist) return -ENOMEM; - strlist__for_each(ent, rawlist) { + strlist__for_each_entry(ent, rawlist) { ret = parse_probe_trace_command(ent->s, &tev); if (ret >= 0) { if (!filter_probe_trace_event(&tev, filter)) diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 25a40427003e..1c12c1ab19c9 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -178,7 +178,7 @@ static struct strlist *__probe_file__get_namelist(int fd, bool include_group) if (!rawlist) return NULL; sl = strlist__new(NULL, NULL); - strlist__for_each(ent, rawlist) { + strlist__for_each_entry(ent, rawlist) { ret = parse_probe_trace_command(ent->s, &tev); if (ret < 0) break; @@ -281,7 +281,7 @@ int probe_file__get_events(int fd, struct strfilter *filter, if (!namelist) return -ENOENT; - strlist__for_each(ent, namelist) { + strlist__for_each_entry(ent, namelist) { p = strchr(ent->s, ':'); if ((p && strfilter__compare(filter, p + 1)) || strfilter__compare(filter, ent->s)) { @@ -299,7 +299,7 @@ int probe_file__del_strlist(int fd, struct strlist *namelist) int ret = 0; struct str_node *ent; - strlist__for_each(ent, namelist) { + strlist__for_each_entry(ent, namelist) { ret = __del_trace_probe_event(fd, ent); if (ret < 0) break; @@ -612,7 +612,7 @@ static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd) if (ret < (int)iov[1].iov_len + 2) goto rollback; - strlist__for_each(snode, entry->tevlist) { + strlist__for_each_entry(snode, entry->tevlist) { iov[0].iov_base = (void *)snode->s; iov[0].iov_len = strlen(snode->s); iov[1].iov_base = (void *)"\n"; iov[1].iov_len = 1; diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 98f127abfa42..65c6c73d28fe 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -957,7 +957,7 @@ static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i) if (i >= pevlist->evlist.nr_entries) return NULL; - evlist__for_each(&pevlist->evlist, pos) { + evlist__for_each_entry(&pevlist->evlist, pos) { if (i-- == 0) break; } diff --git a/tools/perf/util/rb_resort.h b/tools/perf/util/rb_resort.h index abc76e3d3098..808cc45611fe 100644 --- a/tools/perf/util/rb_resort.h +++ b/tools/perf/util/rb_resort.h @@ -35,7 +35,7 @@ DEFINE_RB_RESORT_RB(threads, strcmp(a->thread->shortname, struct rb_node *nd; - resort_rb__for_each(nd, threads) { + resort_rb__for_each_entry(nd, threads) { struct thread *t = threads_entry; printf("%s: %d\n", t->shortname, t->tid); } @@ -123,7 +123,7 @@ static void __name##_sorted__init_entry(struct rb_node *nd, \ struct __name##_sorted_entry *__name##_entry; \ struct __name##_sorted *__name = __name##_sorted__new -#define resort_rb__for_each(__nd, __name) \ +#define resort_rb__for_each_entry(__nd, __name) \ for (__nd = rb_first(&__name->entries); \ __name##_entry = rb_entry(__nd, struct __name##_sorted_entry, \ rb_node), __nd; \ diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 481792c7484b..98bf584853ea 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -148,7 +148,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, use_comm_exec = perf_can_comm_exec(); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { perf_evsel__config(evsel, opts, callchain); if (evsel->tracking && use_comm_exec) evsel->attr.comm_exec = 1; @@ -161,18 +161,18 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, * match the id. */ use_sample_identifier = perf_can_sample_identifier(); - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) perf_evsel__set_sample_id(evsel, use_sample_identifier); } else if (evlist->nr_entries > 1) { struct perf_evsel *first = perf_evlist__first(evlist); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.sample_type == first->attr.sample_type) continue; use_sample_identifier = perf_can_sample_identifier(); break; } - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) perf_evsel__set_sample_id(evsel, use_sample_identifier); } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index dfedf097b9b1..078d49626494 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -83,7 +83,7 @@ static bool perf_session__has_comm_exec(struct perf_session *session) { struct perf_evsel *evsel; - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (evsel->attr.comm_exec) return true; } @@ -178,6 +178,8 @@ static void perf_session__delete_threads(struct perf_session *session) void perf_session__delete(struct perf_session *session) { + if (session == NULL) + return; auxtrace__free(session); auxtrace_index__free(&session->auxtrace_index); perf_session__destroy_kernel_maps(session); @@ -1870,7 +1872,7 @@ bool perf_session__has_traces(struct perf_session *session, const char *msg) { struct perf_evsel *evsel; - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (evsel->attr.type == PERF_TYPE_TRACEPOINT) return true; } @@ -1952,7 +1954,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, { struct perf_evsel *pos; - evlist__for_each(session->evlist, pos) { + evlist__for_each_entry(session->evlist, pos) { if (pos->attr.type == type) return pos; } @@ -2107,7 +2109,7 @@ int perf_event__synthesize_id_index(struct perf_tool *tool, max_nr = (UINT16_MAX - sizeof(struct id_index_event)) / sizeof(struct id_index_entry); - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) nr += evsel->ids; n = nr > max_nr ? max_nr : nr; @@ -2120,7 +2122,7 @@ int perf_event__synthesize_id_index(struct perf_tool *tool, ev->id_index.header.size = sz; ev->id_index.nr = n; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { u32 j; for (j = 0; j < evsel->ids; j++) { diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 896d34ebcc1e..5854b4660a49 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -79,8 +79,8 @@ static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf, { const char *comm = thread__comm_str(he->thread); - width = max(7U, width) - 6; - return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid, + width = max(7U, width) - 8; + return repsep_snprintf(bf, size, "%7d:%-*.*s", he->thread->tid, width, width, comm ?: ""); } @@ -95,7 +95,7 @@ static int hist_entry__thread_filter(struct hist_entry *he, int type, const void } struct sort_entry sort_thread = { - .se_header = " Pid:Command", + .se_header = " Pid:Command", .se_cmp = sort__thread_cmp, .se_snprintf = hist_entry__thread_snprintf, .se_filter = hist_entry__thread_filter, @@ -2069,7 +2069,7 @@ static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_nam } full_name = !!strchr(event_name, ':'); - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { /* case 2 */ if (full_name && !strcmp(pos->name, event_name)) return pos; @@ -2125,7 +2125,7 @@ static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace, int ret; struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type != PERF_TYPE_TRACEPOINT) continue; @@ -2143,7 +2143,7 @@ static int add_all_matching_fields(struct perf_evlist *evlist, struct perf_evsel *evsel; struct format_field *field; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type != PERF_TYPE_TRACEPOINT) continue; @@ -2456,7 +2456,7 @@ static const char *get_default_sort_order(struct perf_evlist *evlist) if (evlist == NULL) goto out_no_evlist; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { use_trace = false; break; diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index c1ba255f2abe..39345c2ddfc2 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -162,7 +162,7 @@ int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (perf_evsel__alloc_stats(evsel, alloc_raw)) goto out_free; } @@ -178,7 +178,7 @@ void perf_evlist__free_stats(struct perf_evlist *evlist) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { perf_evsel__free_stat_priv(evsel); perf_evsel__free_counts(evsel); perf_evsel__free_prev_raw_counts(evsel); @@ -189,7 +189,7 @@ void perf_evlist__reset_stats(struct perf_evlist *evlist) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { perf_evsel__reset_stat_priv(evsel); perf_evsel__reset_counts(evsel); } diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h index ca990029e243..19207e50fce5 100644 --- a/tools/perf/util/strlist.h +++ b/tools/perf/util/strlist.h @@ -73,7 +73,7 @@ static inline struct str_node *strlist__next(struct str_node *sn) * @pos: the &struct str_node to use as a loop cursor. * @slist: the &struct strlist for loop. */ -#define strlist__for_each(pos, slist) \ +#define strlist__for_each_entry(pos, slist) \ for (pos = strlist__first(slist); pos; pos = strlist__next(pos)) /** @@ -83,7 +83,7 @@ static inline struct str_node *strlist__next(struct str_node *sn) * @n: another &struct str_node to use as temporary storage. * @slist: the &struct strlist for loop. */ -#define strlist__for_each_safe(pos, n, slist) \ +#define strlist__for_each_entry_safe(pos, n, slist) \ for (pos = strlist__first(slist), n = strlist__next(pos); pos;\ pos = n, n = strlist__next(n)) #endif /* __PERF_STRLIST_H */ diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 09c5c34ae38d..b044f1a32d16 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1626,7 +1626,7 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) if (!dirs) return -1; - strlist__for_each(nd, dirs) { + strlist__for_each_entry(nd, dirs) { scnprintf(kallsyms_filename, sizeof(kallsyms_filename), "%s/%s/kallsyms", dir, nd->s); if (!validate_kcore_addresses(kallsyms_filename, map)) { diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c index 825086aa9a08..d3301529f6a7 100644 --- a/tools/perf/util/thread-stack.c +++ b/tools/perf/util/thread-stack.c @@ -616,3 +616,10 @@ int thread_stack__process(struct thread *thread, struct comm *comm, return err; } + +size_t thread_stack__depth(struct thread *thread) +{ + if (!thread->ts) + return 0; + return thread->ts->cnt; +} diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h index ad44c7944b8e..b7e41c4ebfdd 100644 --- a/tools/perf/util/thread-stack.h +++ b/tools/perf/util/thread-stack.h @@ -87,6 +87,7 @@ void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, size_t sz, u64 ip); int thread_stack__flush(struct thread *thread); void thread_stack__free(struct thread *thread); +size_t thread_stack__depth(struct thread *thread); struct call_return_processor * call_return_processor__new(int (*process)(struct call_return *cr, void *data), diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 5654fe15e036..40585f5b7027 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c @@ -202,7 +202,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) if (!slist) return NULL; - strlist__for_each(pos, slist) { + strlist__for_each_entry(pos, slist) { pid = strtol(pos->s, &end_ptr, 10); if (pid == INT_MIN || pid == INT_MAX || @@ -278,7 +278,7 @@ struct thread_map *thread_map__new_by_tid_str(const char *tid_str) if (!slist) return NULL; - strlist__for_each(pos, slist) { + strlist__for_each_entry(pos, slist) { tid = strtol(pos->s, &end_ptr, 10); if (tid == INT_MIN || tid == INT_MAX || diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 01c2e86977f4..97c0f8fc5561 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -462,7 +462,8 @@ static int access_mem(unw_addr_space_t __maybe_unused as, return 0; } - ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP); + ret = perf_reg_value(&start, &ui->sample->user_regs, + LIBUNWIND__ARCH_REG_SP); if (ret) return ret; @@ -621,7 +622,8 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, unw_cursor_t c; int ret, i = 0; - ret = perf_reg_value(&val, &ui->sample->user_regs, PERF_REG_IP); + ret = perf_reg_value(&val, &ui->sample->user_regs, + LIBUNWIND__ARCH_REG_IP); if (ret) return ret; diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index b07466240346..84c6d44d52f9 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -32,6 +32,15 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, #ifndef LIBUNWIND__ARCH_REG_ID #define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arch_reg_id(regnum) #endif + +#ifndef LIBUNWIND__ARCH_REG_SP +#define LIBUNWIND__ARCH_REG_SP PERF_REG_SP +#endif + +#ifndef LIBUNWIND__ARCH_REG_IP +#define LIBUNWIND__ARCH_REG_IP PERF_REG_IP +#endif + int LIBUNWIND__ARCH_REG_ID(int regnum); int unwind__prepare_access(struct thread *thread, struct map *map); void unwind__flush_access(struct thread *thread); diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 44d440da15dc..7bdcad484225 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -134,8 +134,6 @@ static struct dso *__machine__addnew_vdso(struct machine *machine, const char *s return dso; } -#if BITS_PER_LONG == 64 - static enum dso_type machine__thread_dso_type(struct machine *machine, struct thread *thread) { @@ -156,6 +154,8 @@ static enum dso_type machine__thread_dso_type(struct machine *machine, return dso_type; } +#if BITS_PER_LONG == 64 + static int vdso__do_copy_compat(FILE *f, int fd) { char buf[4096]; @@ -283,8 +283,38 @@ static int __machine__findnew_vdso_compat(struct machine *machine, #endif +static struct dso *machine__find_vdso(struct machine *machine, + struct thread *thread) +{ + struct dso *dso = NULL; + enum dso_type dso_type; + + dso_type = machine__thread_dso_type(machine, thread); + switch (dso_type) { + case DSO__TYPE_32BIT: + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO32, true); + if (!dso) { + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, + true); + if (dso && dso_type != dso__type(dso, machine)) + dso = NULL; + } + break; + case DSO__TYPE_X32BIT: + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSOX32, true); + break; + case DSO__TYPE_64BIT: + case DSO__TYPE_UNKNOWN: + default: + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true); + break; + } + + return dso; +} + struct dso *machine__findnew_vdso(struct machine *machine, - struct thread *thread __maybe_unused) + struct thread *thread) { struct vdso_info *vdso_info; struct dso *dso = NULL; @@ -297,6 +327,10 @@ struct dso *machine__findnew_vdso(struct machine *machine, if (!vdso_info) goto out_unlock; + dso = machine__find_vdso(machine, thread); + if (dso) + goto out_unlock; + #if BITS_PER_LONG == 64 if (__machine__findnew_vdso_compat(machine, thread, vdso_info, &dso)) goto out_unlock; |