From faa0abae75f7116d461415ab268f70cacb736741 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:23 -0700 Subject: perf util: Sort includes and add missed explicit dependencies Fix missing includes found while cleaning the evsel/evlist header files. Sort the remaining header files for consistency with the rest of the code. Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/bpf_off_cpu.c | 30 ++++++------ tools/perf/util/bpf_trace_augment.c | 8 ++-- tools/perf/util/evlist.c | 91 +++++++++++++++++++------------------ tools/perf/util/map.h | 9 ++-- tools/perf/util/perf_api_probe.c | 18 +++++--- tools/perf/util/s390-sample-raw.c | 19 ++++---- tools/perf/util/stat-shadow.c | 20 ++++---- tools/perf/util/stat.c | 16 ++++--- 8 files changed, 113 insertions(+), 98 deletions(-) diff --git a/tools/perf/util/bpf_off_cpu.c b/tools/perf/util/bpf_off_cpu.c index a3b699a5322f..48cb930cdd2e 100644 --- a/tools/perf/util/bpf_off_cpu.c +++ b/tools/perf/util/bpf_off_cpu.c @@ -1,23 +1,25 @@ // SPDX-License-Identifier: GPL-2.0 -#include "util/bpf_counter.h" -#include "util/debug.h" -#include "util/evsel.h" -#include "util/evlist.h" -#include "util/off_cpu.h" -#include "util/perf-hooks.h" -#include "util/record.h" -#include "util/session.h" -#include "util/target.h" -#include "util/cpumap.h" -#include "util/thread_map.h" -#include "util/cgroup.h" -#include "util/strlist.h" +#include + #include #include #include -#include +#include "bpf_counter.h" #include "bpf_skel/off_cpu.skel.h" +#include "cgroup.h" +#include "cpumap.h" +#include "debug.h" +#include "evlist.h" +#include "evsel.h" +#include "off_cpu.h" +#include "parse-events.h" +#include "perf-hooks.h" +#include "record.h" +#include "session.h" +#include "strlist.h" +#include "target.h" +#include "thread_map.h" #define MAX_STACKS 32 #define MAX_PROC 4096 diff --git a/tools/perf/util/bpf_trace_augment.c b/tools/perf/util/bpf_trace_augment.c index 9e706f0fa53d..a9cf2a77ded1 100644 --- a/tools/perf/util/bpf_trace_augment.c +++ b/tools/perf/util/bpf_trace_augment.c @@ -1,11 +1,11 @@ #include #include -#include "util/debug.h" -#include "util/evlist.h" -#include "util/trace_augment.h" - #include "bpf_skel/augmented_raw_syscalls.skel.h" +#include "debug.h" +#include "evlist.h" +#include "parse-events.h" +#include "trace_augment.h" static struct augmented_raw_syscalls_bpf *skel; static struct evsel *bpf_output; diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 1a238b245b3a..ab6bf5e935f4 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -5,67 +5,68 @@ * Parts came from builtin-{top,stat,record}.c, see those files for further * copyright notes. */ -#include +#include "evlist.h" + #include #include -#include -#include "cpumap.h" -#include "util/mmap.h" -#include "thread_map.h" -#include "target.h" -#include "dwarf-regs.h" -#include "evlist.h" -#include "evsel.h" -#include "record.h" -#include "debug.h" -#include "units.h" -#include "bpf_counter.h" -#include // page_size -#include "affinity.h" -#include "../perf.h" -#include "asm/bug.h" -#include "bpf-event.h" -#include "util/event.h" -#include "util/string2.h" -#include "util/perf_api_probe.h" -#include "util/evsel_fprintf.h" -#include "util/pmu.h" -#include "util/sample.h" -#include "util/bpf-filter.h" -#include "util/stat.h" -#include "util/util.h" -#include "util/env.h" -#include "util/intel-tpebs.h" -#include "util/metricgroup.h" -#include "util/strbuf.h" #include -#include -#include #include -#include "parse-events.h" -#include - #include -#include -#include -#include -#include -#include - #include +#include #include #include -#include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include // page_size +#include +#include #include #include -#include #include +#include -#include +#include "../perf.h" +#include "affinity.h" +#include "asm/bug.h" +#include "bpf-event.h" +#include "bpf-filter.h" +#include "bpf_counter.h" +#include "cpumap.h" +#include "debug.h" +#include "dwarf-regs.h" +#include "env.h" +#include "event.h" +#include "evsel.h" +#include "evsel_fprintf.h" +#include "intel-tpebs.h" +#include "metricgroup.h" +#include "mmap.h" +#include "parse-events.h" +#include "perf_api_probe.h" +#include "pmu.h" +#include "pmus.h" +#include "record.h" +#include "sample.h" +#include "stat.h" +#include "strbuf.h" +#include "string2.h" +#include "target.h" +#include "thread_map.h" +#include "units.h" +#include "util.h" #ifdef LACKS_SIGQUEUE_PROTOTYPE int sigqueue(pid_t pid, int sig, const union sigval value); diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 979b3e11b9bc..fb0279810ae9 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -2,14 +2,13 @@ #ifndef __PERF_MAP_H #define __PERF_MAP_H -#include -#include -#include -#include +#include #include #include -#include + +#include #include + #include struct dso; diff --git a/tools/perf/util/perf_api_probe.c b/tools/perf/util/perf_api_probe.c index 6ecf38314f01..e1904a330b28 100644 --- a/tools/perf/util/perf_api_probe.c +++ b/tools/perf/util/perf_api_probe.c @@ -1,14 +1,18 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#include "perf_api_probe.h" -#include "perf-sys.h" -#include "util/cloexec.h" -#include "util/evlist.h" -#include "util/evsel.h" -#include "util/parse-events.h" -#include "util/perf_api_probe.h" -#include #include +#include + +#include "cloexec.h" +#include "evlist.h" +#include "evsel.h" +#include "parse-events.h" +#include "perf-sys.h" +#include "pmu.h" +#include "pmus.h" + typedef void (*setup_probe_fn_t)(struct evsel *evsel); static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const char *str) diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c index 52bbca5c56c8..01111c4e3488 100644 --- a/tools/perf/util/s390-sample-raw.c +++ b/tools/perf/util/s390-sample-raw.c @@ -12,25 +12,26 @@ * sample was taken from. */ -#include +#include #include #include -#include -#include +#include #include #include -#include +#include +#include +#include "color.h" #include "debug.h" -#include "session.h" #include "evlist.h" -#include "color.h" #include "hashmap.h" -#include "sample-raw.h" +#include "pmu.h" +#include "pmus.h" #include "s390-cpumcf-kernel.h" -#include "util/pmu.h" -#include "util/sample.h" +#include "sample-raw.h" +#include "sample.h" +#include "session.h" static size_t ctrset_size(struct cf_ctrset_entry *set) { diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index c17373bb0e1e..35062f964618 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -2,20 +2,24 @@ #include #include #include -#include "evsel.h" -#include "stat.h" + +#include + +#include "cgroup.h" #include "color.h" #include "debug.h" -#include "pmu.h" -#include "rblist.h" #include "evlist.h" +#include "evsel.h" #include "expr.h" -#include "metricgroup.h" -#include "cgroup.h" -#include "units.h" +#include "hashmap.h" #include "iostat.h" -#include "util/hashmap.h" +#include "metricgroup.h" +#include "pmu.h" +#include "pmus.h" +#include "rblist.h" +#include "stat.h" #include "tool_pmu.h" +#include "units.h" static bool tool_pmu__is_time_event(const struct perf_stat_config *config, const struct evsel *evsel, int *tool_aggr_idx) diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 14d169e22e8f..66eb9a66a4f7 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -1,21 +1,25 @@ // SPDX-License-Identifier: GPL-2.0 +#include "stat.h" + #include -#include #include #include #include + +#include +#include + #include "counts.h" #include "cpumap.h" #include "debug.h" +#include "evlist.h" +#include "evsel.h" +#include "hashmap.h" #include "header.h" -#include "stat.h" +#include "pmu.h" #include "session.h" #include "target.h" -#include "evlist.h" -#include "evsel.h" #include "thread_map.h" -#include "util/hashmap.h" -#include void update_stats(struct stats *stats, u64 val) { -- cgit v1.2.3 From 01fa2d416aceab51f97ec2769e8da9971a605eeb Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:24 -0700 Subject: perf python: Add missed explicit dependencies Fix missing #include of pmus.h found while cleaning the evsel/evlist header files. Also define PY_SSIZE_T_CLEAN before including Python.h to comply with modern Python 3 C-API requirements, and introduce CHECK_INITIALIZED and CHECK_INITIALIZED_INT safety macros to be used by subsequent patches. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/python.c | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index cc1019d29a5d..98a8dd9b673d 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -1,30 +1,37 @@ // SPDX-License-Identifier: GPL-2.0 +#define PY_SSIZE_T_CLEAN #include -#include + #include -#include + #include +#include + +#include #include -#ifdef HAVE_LIBTRACEEVENT -#include -#endif #include +#include + #include "callchain.h" #include "counts.h" +#include "event.h" #include "evlist.h" #include "evsel.h" -#include "event.h" #include "expr.h" +#include "metricgroup.h" +#include "mmap.h" +#include "pmus.h" #include "print_binary.h" #include "record.h" #include "strbuf.h" #include "thread_map.h" #include "tp_pmu.h" #include "trace-event.h" -#include "metricgroup.h" -#include "mmap.h" #include "util/sample.h" -#include + +#ifdef HAVE_LIBTRACEEVENT +#include +#endif PyMODINIT_FUNC PyInit_perf(void); @@ -38,6 +45,22 @@ PyMODINIT_FUNC PyInit_perf(void); offsetof(struct pyrf_event, sample) + offsetof(struct perf_sample, member), \ 0, help } +#define CHECK_INITIALIZED(ptr, msg) \ + do { \ + if (!(ptr)) { \ + PyErr_SetString(PyExc_ValueError, msg " not initialized"); \ + return NULL; \ + } \ + } while (0) + +#define CHECK_INITIALIZED_INT(ptr, msg) \ + do { \ + if (!(ptr)) { \ + PyErr_SetString(PyExc_ValueError, msg " not initialized"); \ + return -1; \ + } \ + } while (0) + struct pyrf_event { PyObject_HEAD struct evsel *evsel; -- cgit v1.2.3 From 7c11450939c88c82104c2e3d00d0c70fe484f2f8 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:25 -0700 Subject: perf evsel/evlist: Avoid unnecessary #includes Use forward declarations and remove unnecessary #includes in evsel.h. Sort the forward declarations in evsel.h and evlist.h. Move some PMU code into evsel.c. Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Peter Zijlstra Cc: Thomas Richter [ Add an include for pmu.h in util/aslr.h that was being obtained indirectly ] Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/aslr.c | 1 + tools/perf/util/evlist.h | 15 +++++++++------ tools/perf/util/evsel.c | 5 +++++ tools/perf/util/evsel.h | 25 ++++++++++++------------- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/tools/perf/util/aslr.c b/tools/perf/util/aslr.c index 6a7542e7db82..027695d96779 100644 --- a/tools/perf/util/aslr.c +++ b/tools/perf/util/aslr.c @@ -13,6 +13,7 @@ #include "session.h" #include "data.h" #include "dso.h" +#include "pmu.h" #include "pmus.h" #include /* page_size */ diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index e507f5f20ef6..e54761c670b6 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -2,29 +2,32 @@ #ifndef __PERF_EVLIST_H #define __PERF_EVLIST_H 1 +#include + #include #include -#include #include +#include +#include +#include + #include #include #include #include + #include "affinity.h" #include "events_stats.h" #include "evsel.h" #include "rblist.h" -#include -#include -#include -struct pollfd; -struct thread_map; struct perf_cpu_map; struct perf_stat_config; +struct pollfd; struct record_opts; struct strbuf; struct target; +struct thread_map; /* * State machine of bkw_mmap_state: diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ea9fa04429f0..4326650ac803 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -422,6 +422,11 @@ void evsel__set_sample_id(struct evsel *evsel, evsel->core.attr.read_format |= PERF_FORMAT_ID; } +bool evsel__is_non_perf_event_open_pmu(const struct evsel *evsel) +{ + return evsel->pmu && evsel->pmu->type > PERF_PMU_TYPE_PE_END; +} + /** * evsel__is_function_event - Return whether given evsel is a function * trace event diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 163fc2b6a7ea..f85040d5528b 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -2,28 +2,30 @@ #ifndef __PERF_EVSEL_H #define __PERF_EVSEL_H 1 -#include #include -#include + +#include #include #include +#include + #include #include + #include "symbol_conf.h" -#include "pmus.h" -#include "pmu.h" +struct bperf_follower_bpf; +struct bperf_leader_bpf; +struct bpf_counter_ops; struct bpf_object; struct cgroup; +struct hashmap; struct perf_counts; +struct perf_pmu; struct perf_stat_config; struct perf_stat_evsel; -union perf_event; -struct bpf_counter_ops; struct target; -struct hashmap; -struct bperf_leader_bpf; -struct bperf_follower_bpf; +union perf_event; typedef int (evsel__sb_cb_t)(union perf_event *event, void *data); @@ -361,10 +363,6 @@ void arch_evsel__apply_ratio_to_prev(struct evsel *evsel, struct perf_event_attr int evsel__set_filter(struct evsel *evsel, const char *filter); int evsel__append_tp_filter(struct evsel *evsel, const char *filter); int evsel__append_addr_filter(struct evsel *evsel, const char *filter); -static inline bool evsel__is_non_perf_event_open_pmu(const struct evsel *evsel) -{ - return evsel->pmu && evsel->pmu->type > PERF_PMU_TYPE_PE_END; -} int evsel__enable_cpu(struct evsel *evsel, int cpu_map_idx); int evsel__enable(struct evsel *evsel); @@ -503,6 +501,7 @@ static inline bool evsel__is_group_event(struct evsel *evsel) return evsel__is_group_leader(evsel) && evsel->core.nr_members > 1; } +bool evsel__is_non_perf_event_open_pmu(const struct evsel *evsel); bool evsel__is_function_event(struct evsel *evsel); static inline bool evsel__is_bpf_output(struct evsel *evsel) -- cgit v1.2.3 From ea43eb11517b08d218b77e7b472bd4634a4a99b5 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:26 -0700 Subject: perf data: Add open flag Avoid double opens and ensure only open files are closed. This addresses some issues with python integration where the data file wants to be opened before being given to a session. Assisted-by: Gemini:gemini-3.1-pro-preview Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/data.c | 27 ++++++++++++++++++++++----- tools/perf/util/data.h | 4 +++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index 94dc534a7386..33fd1b82019e 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c @@ -345,9 +345,10 @@ static int open_dir(struct perf_data *data) if (asprintf(&data->file.path, "%s/data", data->path) < 0) return -1; - if (perf_data__is_write(data) && - mkdir(data->path, S_IRWXU) < 0) + if (perf_data__is_write(data) && mkdir(data->path, 0700) < 0) { + zfree(&data->file.path); return -1; + } ret = open_file(data); @@ -360,9 +361,16 @@ static int open_dir(struct perf_data *data) int perf_data__open(struct perf_data *data) { - if (check_pipe(data)) + int ret; + + if (data->open) return 0; + if (check_pipe(data)) { + data->open = true; + return 0; + } + /* currently it allows stdio for pipe only */ data->file.use_stdio = false; @@ -375,16 +383,24 @@ int perf_data__open(struct perf_data *data) if (perf_data__is_read(data)) data->is_dir = is_dir(data); - return perf_data__is_dir(data) ? - open_dir(data) : open_file_dup(data); + ret = perf_data__is_dir(data) ? open_dir(data) : open_file_dup(data); + + if (!ret) + data->open = true; + + return ret; } void perf_data__close(struct perf_data *data) { + if (!data->open) + return; + if (perf_data__is_dir(data)) perf_data__close_dir(data); perf_data_file__close(&data->file); + data->open = false; } static ssize_t perf_data_file__read(struct perf_data_file *file, void *buf, size_t size) @@ -457,6 +473,7 @@ int perf_data__switch(struct perf_data *data, if (!at_exit) { perf_data_file__close(&data->file); + data->open = false; ret = perf_data__open(data); if (ret < 0) goto out; diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h index 8299fb5fa7da..76f57f60361f 100644 --- a/tools/perf/util/data.h +++ b/tools/perf/util/data.h @@ -50,6 +50,8 @@ struct perf_data { const char *path; /** @file: Underlying file to be used. */ struct perf_data_file file; + /** @open: Has the file or directory been opened. */ + bool open; /** @is_pipe: Underlying file is a pipe. */ bool is_pipe; /** @is_dir: Underlying file is a directory. */ @@ -59,7 +61,7 @@ struct perf_data { /** @in_place_update: A file opened for reading but will be written to. */ bool in_place_update; /** @mode: Read or write mode. */ - enum perf_data_mode mode; + enum perf_data_mode mode:8; struct { /** @version: perf_dir_version. */ -- cgit v1.2.3 From 3c45ce5ae3703d41a87d1dee6735b82c29014f98 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:27 -0700 Subject: perf evlist: Add reference count This a no-op for most of the perf tool. The reference count is set to 1 at allocation, the put will see the 1, decrement it and perform the delete. The purpose for adding the reference count is for the python code. Prior to this change the python code would clone evlists, but this has issues if events are opened, etc. This change adds a reference count for the evlists and a later change will add it to evsels. The combination is needed for the python code to operate correctly (not hit asserts in the evsel clone), but the changes are broken apart for the sake of smaller patches. Assisted-by: Gemini:gemini-3.1-pro-preview Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/arch/x86/tests/hybrid.c | 2 +- tools/perf/arch/x86/tests/topdown.c | 4 +- tools/perf/arch/x86/util/iostat.c | 2 +- tools/perf/bench/evlist-open-close.c | 18 +-- tools/perf/builtin-ftrace.c | 8 +- tools/perf/builtin-kvm.c | 4 +- tools/perf/builtin-lock.c | 2 +- tools/perf/builtin-record.c | 4 +- tools/perf/builtin-sched.c | 6 +- tools/perf/builtin-script.c | 2 +- tools/perf/builtin-stat.c | 10 +- tools/perf/builtin-top.c | 52 +++--- tools/perf/builtin-trace.c | 26 +-- tools/perf/tests/backward-ring-buffer.c | 18 +-- tools/perf/tests/code-reading.c | 4 +- tools/perf/tests/event-times.c | 4 +- tools/perf/tests/event_update.c | 2 +- tools/perf/tests/evsel-roundtrip-name.c | 8 +- tools/perf/tests/expand-cgroup.c | 8 +- tools/perf/tests/hists_cumulate.c | 2 +- tools/perf/tests/hists_filter.c | 2 +- tools/perf/tests/hists_link.c | 2 +- tools/perf/tests/hists_output.c | 2 +- tools/perf/tests/hwmon_pmu.c | 2 +- tools/perf/tests/keep-tracking.c | 2 +- tools/perf/tests/mmap-basic.c | 18 +-- tools/perf/tests/openat-syscall-tp-fields.c | 18 +-- tools/perf/tests/parse-events.c | 4 +- tools/perf/tests/parse-metric.c | 4 +- tools/perf/tests/parse-no-sample-id-all.c | 2 +- tools/perf/tests/perf-record.c | 18 +-- tools/perf/tests/perf-time-to-tsc.c | 2 +- tools/perf/tests/pfm.c | 4 +- tools/perf/tests/pmu-events.c | 6 +- tools/perf/tests/pmu.c | 4 +- tools/perf/tests/sw-clock.c | 14 +- tools/perf/tests/switch-tracking.c | 2 +- tools/perf/tests/task-exit.c | 14 +- tools/perf/tests/tool_pmu.c | 2 +- tools/perf/tests/topology.c | 2 +- tools/perf/tests/uncore-event-sorting.c | 2 +- tools/perf/util/cgroup.c | 4 +- tools/perf/util/data-convert-bt.c | 2 +- tools/perf/util/evlist.c | 20 ++- tools/perf/util/evlist.h | 7 +- tools/perf/util/expr.c | 2 +- tools/perf/util/header.c | 22 +-- tools/perf/util/metricgroup.c | 6 +- tools/perf/util/parse-events.c | 4 +- tools/perf/util/perf_api_probe.c | 2 +- tools/perf/util/python.c | 242 +++++++++++++--------------- tools/perf/util/record.c | 2 +- tools/perf/util/session.c | 2 +- tools/perf/util/sideband_evlist.c | 16 +- 54 files changed, 315 insertions(+), 328 deletions(-) diff --git a/tools/perf/arch/x86/tests/hybrid.c b/tools/perf/arch/x86/tests/hybrid.c index e221ea104174..dfb0ffc0d030 100644 --- a/tools/perf/arch/x86/tests/hybrid.c +++ b/tools/perf/arch/x86/tests/hybrid.c @@ -268,7 +268,7 @@ static int test_event(const struct evlist_test *e) ret = e->check(evlist); } parse_events_error__exit(&err); - evlist__delete(evlist); + evlist__put(evlist); return ret; } diff --git a/tools/perf/arch/x86/tests/topdown.c b/tools/perf/arch/x86/tests/topdown.c index 221f2c4bbb61..2b6f47ce4932 100644 --- a/tools/perf/arch/x86/tests/topdown.c +++ b/tools/perf/arch/x86/tests/topdown.c @@ -56,7 +56,7 @@ static int event_cb(void *state, struct pmu_event_info *info) *ret = TEST_FAIL; } } - evlist__delete(evlist); + evlist__put(evlist); return 0; } @@ -174,7 +174,7 @@ static int test_sort(const char *str, int expected_slots_group_size, CHECK_COND(slots_seen, "slots seen"); ret = TEST_OK; out_err: - evlist__delete(evlist); + evlist__put(evlist); parse_events_error__exit(&err); return ret; } diff --git a/tools/perf/arch/x86/util/iostat.c b/tools/perf/arch/x86/util/iostat.c index 7442a2cd87ed..e0417552b0cb 100644 --- a/tools/perf/arch/x86/util/iostat.c +++ b/tools/perf/arch/x86/util/iostat.c @@ -337,7 +337,7 @@ int iostat_prepare(struct evlist *evlist, struct perf_stat_config *config) if (evlist->core.nr_entries > 0) { pr_warning("The -e and -M options are not supported." "All chosen events/metrics will be dropped\n"); - evlist__delete(evlist); + evlist__put(evlist); evlist = evlist__new(); if (!evlist) return -ENOMEM; diff --git a/tools/perf/bench/evlist-open-close.c b/tools/perf/bench/evlist-open-close.c index faf9c34b4a5d..304929d1f67f 100644 --- a/tools/perf/bench/evlist-open-close.c +++ b/tools/perf/bench/evlist-open-close.c @@ -76,7 +76,7 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str) parse_events_error__exit(&err); pr_err("Run 'perf list' for a list of valid events\n"); ret = 1; - goto out_delete_evlist; + goto out_put_evlist; } parse_events_error__exit(&err); if (uid_str) { @@ -85,24 +85,24 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str) if (uid == UINT_MAX) { pr_err("Invalid User: %s", uid_str); ret = -EINVAL; - goto out_delete_evlist; + goto out_put_evlist; } ret = parse_uid_filter(evlist, uid); if (ret) - goto out_delete_evlist; + goto out_put_evlist; } ret = evlist__create_maps(evlist, &opts.target); if (ret < 0) { pr_err("Not enough memory to create thread/cpu maps\n"); - goto out_delete_evlist; + goto out_put_evlist; } evlist__config(evlist, &opts, NULL); return evlist; -out_delete_evlist: - evlist__delete(evlist); +out_put_evlist: + evlist__put(evlist); return NULL; } @@ -151,7 +151,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str) evlist->core.nr_entries, evlist__count_evsel_fds(evlist)); printf(" Number of iterations:\t%d\n", iterations); - evlist__delete(evlist); + evlist__put(evlist); for (i = 0; i < iterations; i++) { pr_debug("Started iteration %d\n", i); @@ -162,7 +162,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str) gettimeofday(&start, NULL); err = bench__do_evlist_open_close(evlist); if (err) { - evlist__delete(evlist); + evlist__put(evlist); return err; } @@ -171,7 +171,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str) runtime_us = timeval2usec(&diff); update_stats(&time_stats, runtime_us); - evlist__delete(evlist); + evlist__put(evlist); pr_debug("Iteration %d took:\t%" PRIu64 "us\n", i, runtime_us); } diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index 8a7dbfb14535..676239148b87 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -1999,20 +1999,20 @@ int cmd_ftrace(int argc, const char **argv) ret = evlist__create_maps(ftrace.evlist, &ftrace.target); if (ret < 0) - goto out_delete_evlist; + goto out_put_evlist; if (argc) { ret = evlist__prepare_workload(ftrace.evlist, &ftrace.target, argv, false, ftrace__workload_exec_failed_signal); if (ret < 0) - goto out_delete_evlist; + goto out_put_evlist; } ret = cmd_func(&ftrace); -out_delete_evlist: - evlist__delete(ftrace.evlist); +out_put_evlist: + evlist__put(ftrace.evlist); out_delete_filters: delete_filter_func(&ftrace.filters); diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 394302ebdb16..993dabff2a72 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1810,7 +1810,7 @@ static struct evlist *kvm_live_event_list(void) out: if (err) { - evlist__delete(evlist); + evlist__put(evlist); evlist = NULL; } @@ -1941,7 +1941,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, out: perf_session__delete(kvm->session); kvm->session = NULL; - evlist__delete(kvm->evlist); + evlist__put(kvm->evlist); return err; } diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 5841d43be971..d925543a68c0 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -2149,7 +2149,7 @@ static int __cmd_contention(int argc, const char **argv) out_delete: lock_filter_finish(); - evlist__delete(con.evlist); + evlist__put(con.evlist); lock_contention_finish(&con); perf_session__delete(session); perf_env__exit(&host_env); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index e91539055675..e4fa77a40dac 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -4291,7 +4291,7 @@ int cmd_record(int argc, const char **argv) goto out; evlist__splice_list_tail(rec->evlist, &def_evlist->core.entries); - evlist__delete(def_evlist); + evlist__put(def_evlist); } if (rec->opts.target.tid && !rec->opts.no_inherit_set) @@ -4401,7 +4401,7 @@ out: auxtrace_record__free(rec->itr); out_opts: evlist__close_control(rec->opts.ctl_fd, rec->opts.ctl_fd_ack, &rec->opts.ctl_fd_close); - evlist__delete(rec->evlist); + evlist__put(rec->evlist); return err; } diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 7fd63a9db457..54ce9933ef09 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -3924,7 +3924,7 @@ static int perf_sched__schedstat_record(struct perf_sched *sched, session = perf_session__new(&data, &sched->tool); if (IS_ERR(session)) { pr_err("Perf session creation failed.\n"); - evlist__delete(evlist); + evlist__put(evlist); return PTR_ERR(session); } @@ -4023,7 +4023,7 @@ out: else fprintf(stderr, "[ perf sched stats: Failed !! ]\n"); - evlist__delete(evlist); + evlist__put(evlist); close(fd); return err; } @@ -4927,7 +4927,7 @@ static int perf_sched__schedstat_live(struct perf_sched *sched, free_cpu_domain_info(cd_map, sv, nr); out: free_schedstat(&cpu_head); - evlist__delete(evlist); + evlist__put(evlist); return err; } diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 9ac29bdc3cd5..0df13927001b 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2274,7 +2274,7 @@ static int script_find_metrics(const struct pmu_metric *pm, } pr_debug("Found metric '%s' whose evsels match those of in the perf data\n", pm->metric_name); - evlist__delete(metric_evlist); + evlist__put(metric_evlist); out: return 0; } diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a04466ea3b0a..bf621202da69 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -2119,7 +2119,7 @@ static int add_default_events(void) stat_config.user_requested_cpu_list, stat_config.system_wide, stat_config.hardware_aware_grouping) < 0) { - evlist__delete(metric_evlist); + evlist__put(metric_evlist); ret = -1; break; } @@ -2131,7 +2131,7 @@ static int add_default_events(void) metricgroup__copy_metric_events(evlist, /*cgrp=*/NULL, &evlist->metric_events, &metric_evlist->metric_events); - evlist__delete(metric_evlist); + evlist__put(metric_evlist); } list_sort(/*priv=*/NULL, &evlist->core.entries, default_evlist_evsel_cmp); @@ -2152,7 +2152,7 @@ out: metricgroup__copy_metric_events(evsel_list, /*cgrp=*/NULL, &evsel_list->metric_events, &evlist->metric_events); - evlist__delete(evlist); + evlist__put(evlist); return ret; } @@ -2387,7 +2387,7 @@ static int __cmd_report(int argc, const char **argv) perf_stat.session = session; stat_config.output = stderr; - evlist__delete(evsel_list); + evlist__put(evsel_list); evsel_list = session->evlist; ret = perf_session__process_events(session); @@ -3066,7 +3066,7 @@ out: if (smi_cost && smi_reset) sysfs__write_int(FREEZE_ON_SMI_PATH, 0); - evlist__delete(evsel_list); + evlist__put(evsel_list); evlist__close_control(stat_config.ctl_fd, stat_config.ctl_fd_ack, &stat_config.ctl_fd_close); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 1211401616ee..ff24ae35c67f 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1652,14 +1652,14 @@ int cmd_top(int argc, const char **argv) perf_env__init(&host_env); status = perf_config(perf_top_config, &top); if (status) - goto out_delete_evlist; + goto out_put_evlist; /* * Since the per arch annotation init routine may need the cpuid, read * it here, since we are not getting this from the perf.data header. */ status = perf_env__set_cmdline(&host_env, argc, argv); if (status) - goto out_delete_evlist; + goto out_put_evlist; status = perf_env__read_cpuid(&host_env); if (status) { @@ -1680,30 +1680,30 @@ int cmd_top(int argc, const char **argv) annotate_opts.disassembler_style = strdup(disassembler_style); if (!annotate_opts.disassembler_style) { status = -ENOMEM; - goto out_delete_evlist; + goto out_put_evlist; } } if (objdump_path) { annotate_opts.objdump_path = strdup(objdump_path); if (!annotate_opts.objdump_path) { status = -ENOMEM; - goto out_delete_evlist; + goto out_put_evlist; } } if (addr2line_path) { symbol_conf.addr2line_path = strdup(addr2line_path); if (!symbol_conf.addr2line_path) { status = -ENOMEM; - goto out_delete_evlist; + goto out_put_evlist; } } status = symbol__validate_sym_arguments(); if (status) - goto out_delete_evlist; + goto out_put_evlist; if (annotate_check_args() < 0) - goto out_delete_evlist; + goto out_put_evlist; status = target__validate(target); if (status) { @@ -1718,15 +1718,15 @@ int cmd_top(int argc, const char **argv) struct evlist *def_evlist = evlist__new_default(target, callchain_param.enabled); if (!def_evlist) - goto out_delete_evlist; + goto out_put_evlist; evlist__splice_list_tail(top.evlist, &def_evlist->core.entries); - evlist__delete(def_evlist); + evlist__put(def_evlist); } status = evswitch__init(&top.evswitch, top.evlist, stderr); if (status) - goto out_delete_evlist; + goto out_put_evlist; if (symbol_conf.report_hierarchy) { /* disable incompatible options */ @@ -1737,18 +1737,18 @@ int cmd_top(int argc, const char **argv) pr_err("Error: --hierarchy and --fields options cannot be used together\n"); parse_options_usage(top_usage, options, "fields", 0); parse_options_usage(NULL, options, "hierarchy", 0); - goto out_delete_evlist; + goto out_put_evlist; } } if (top.stitch_lbr && !(callchain_param.record_mode == CALLCHAIN_LBR)) { pr_err("Error: --stitch-lbr must be used with --call-graph lbr\n"); - goto out_delete_evlist; + goto out_put_evlist; } if (nr_cgroups > 0 && opts->record_cgroup) { pr_err("--cgroup and --all-cgroups cannot be used together\n"); - goto out_delete_evlist; + goto out_put_evlist; } if (branch_call_mode) { @@ -1772,7 +1772,7 @@ int cmd_top(int argc, const char **argv) status = perf_env__read_core_pmu_caps(&host_env); if (status) { pr_err("PMU capability data is not available\n"); - goto out_delete_evlist; + goto out_put_evlist; } } @@ -1795,7 +1795,7 @@ int cmd_top(int argc, const char **argv) if (IS_ERR(top.session)) { status = PTR_ERR(top.session); top.session = NULL; - goto out_delete_evlist; + goto out_put_evlist; } top.evlist->session = top.session; @@ -1805,7 +1805,7 @@ int cmd_top(int argc, const char **argv) if (field_order) parse_options_usage(sort_order ? NULL : top_usage, options, "fields", 0); - goto out_delete_evlist; + goto out_put_evlist; } if (top.uid_str) { @@ -1814,18 +1814,18 @@ int cmd_top(int argc, const char **argv) if (uid == UINT_MAX) { ui__error("Invalid User: %s", top.uid_str); status = -EINVAL; - goto out_delete_evlist; + goto out_put_evlist; } status = parse_uid_filter(top.evlist, uid); if (status) - goto out_delete_evlist; + goto out_put_evlist; } if (evlist__create_maps(top.evlist, target) < 0) { ui__error("Couldn't create thread/CPU maps: %s\n", errno == ENOENT ? "No such process" : str_error_r(errno, errbuf, sizeof(errbuf))); status = -errno; - goto out_delete_evlist; + goto out_put_evlist; } if (top.delay_secs < 1) @@ -1833,7 +1833,7 @@ int cmd_top(int argc, const char **argv) if (record_opts__config(opts)) { status = -EINVAL; - goto out_delete_evlist; + goto out_put_evlist; } top.sym_evsel = evlist__first(top.evlist); @@ -1848,14 +1848,14 @@ int cmd_top(int argc, const char **argv) status = symbol__annotation_init(); if (status < 0) - goto out_delete_evlist; + goto out_put_evlist; annotation_config__init(); symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); status = symbol__init(NULL); if (status < 0) - goto out_delete_evlist; + goto out_put_evlist; sort__setup_elide(stdout); @@ -1875,13 +1875,13 @@ int cmd_top(int argc, const char **argv) if (top.sb_evlist == NULL) { pr_err("Couldn't create side band evlist.\n."); status = -EINVAL; - goto out_delete_evlist; + goto out_put_evlist; } if (evlist__add_bpf_sb_event(top.sb_evlist, &host_env)) { pr_err("Couldn't ask for PERF_RECORD_BPF_EVENT side band events.\n."); status = -EINVAL; - goto out_delete_evlist; + goto out_put_evlist; } } #endif @@ -1896,8 +1896,8 @@ int cmd_top(int argc, const char **argv) if (!opts->no_bpf_event) evlist__stop_sb_thread(top.sb_evlist); -out_delete_evlist: - evlist__delete(top.evlist); +out_put_evlist: + evlist__put(top.evlist); perf_session__delete(top.session); annotation_options__exit(); perf_env__exit(&host_env); diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index ba0f8749fc7d..37de15646715 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -4439,7 +4439,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) if (trace->summary_bpf) { if (trace_prepare_bpf_summary(trace->summary_mode) < 0) - goto out_delete_evlist; + goto out_put_evlist; if (trace->summary_only) goto create_maps; @@ -4507,19 +4507,19 @@ create_maps: err = evlist__create_maps(evlist, &trace->opts.target); if (err < 0) { fprintf(trace->output, "Problems parsing the target to trace, check your options!\n"); - goto out_delete_evlist; + goto out_put_evlist; } err = trace__symbols_init(trace, argc, argv, evlist); if (err < 0) { fprintf(trace->output, "Problems initializing symbol libraries!\n"); - goto out_delete_evlist; + goto out_put_evlist; } if (trace->summary_mode == SUMMARY__BY_TOTAL && !trace->summary_bpf) { trace->syscall_stats = alloc_syscall_stats(); if (!trace->syscall_stats) - goto out_delete_evlist; + goto out_put_evlist; } evlist__config(evlist, &trace->opts, &callchain_param); @@ -4528,7 +4528,7 @@ create_maps: err = evlist__prepare_workload(evlist, &trace->opts.target, argv, false, NULL); if (err < 0) { fprintf(trace->output, "Couldn't run the workload!\n"); - goto out_delete_evlist; + goto out_put_evlist; } workload_pid = evlist->workload.pid; } @@ -4576,7 +4576,7 @@ create_maps: err = trace__expand_filters(trace, &evsel); if (err) - goto out_delete_evlist; + goto out_put_evlist; err = evlist__apply_filters(evlist, &evsel, &trace->opts.target); if (err < 0) goto out_error_apply_filters; @@ -4693,12 +4693,12 @@ out_disable: } } -out_delete_evlist: +out_put_evlist: trace_cleanup_bpf_summary(); delete_syscall_stats(trace->syscall_stats); trace__symbols__exit(trace); evlist__free_syscall_tp_fields(evlist); - evlist__delete(evlist); + evlist__put(evlist); cgroup__put(trace->cgroup); trace->evlist = NULL; trace->live = false; @@ -4723,21 +4723,21 @@ out_error_open: out_error: fprintf(trace->output, "%s\n", errbuf); - goto out_delete_evlist; + goto out_put_evlist; out_error_apply_filters: fprintf(trace->output, "Failed to set filter \"%s\" on event %s: %m\n", evsel->filter, evsel__name(evsel)); - goto out_delete_evlist; + goto out_put_evlist; } out_error_mem: fprintf(trace->output, "Not enough memory to run!\n"); - goto out_delete_evlist; + goto out_put_evlist; out_errno: fprintf(trace->output, "%m\n"); - goto out_delete_evlist; + goto out_put_evlist; } static int trace__replay(struct trace *trace) @@ -5417,7 +5417,7 @@ static void trace__exit(struct trace *trace) zfree(&trace->syscalls.table); } zfree(&trace->perfconfig_events); - evlist__delete(trace->evlist); + evlist__put(trace->evlist); trace->evlist = NULL; ordered_events__free(&trace->oe.data); #ifdef HAVE_LIBBPF_SUPPORT diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c index c5e7999f2817..2b49b002d749 100644 --- a/tools/perf/tests/backward-ring-buffer.c +++ b/tools/perf/tests/backward-ring-buffer.c @@ -111,7 +111,7 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in err = evlist__create_maps(evlist, &opts.target); if (err < 0) { pr_debug("Not enough memory to create thread/cpu maps\n"); - goto out_delete_evlist; + goto out_put_evlist; } parse_events_error__init(&parse_error); @@ -124,7 +124,7 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in if (err) { pr_debug("Failed to parse tracepoint event, try use root\n"); ret = TEST_SKIP; - goto out_delete_evlist; + goto out_put_evlist; } evlist__config(evlist, &opts, NULL); @@ -133,19 +133,19 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in if (err < 0) { pr_debug("perf_evlist__open: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); - goto out_delete_evlist; + goto out_put_evlist; } ret = TEST_FAIL; err = do_test(evlist, opts.mmap_pages, &sample_count, &comm_count); if (err != TEST_OK) - goto out_delete_evlist; + goto out_put_evlist; if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) { pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n", sample_count, comm_count); - goto out_delete_evlist; + goto out_put_evlist; } evlist__close(evlist); @@ -154,16 +154,16 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in if (err < 0) { pr_debug("perf_evlist__open: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); - goto out_delete_evlist; + goto out_put_evlist; } err = do_test(evlist, 1, &sample_count, &comm_count); if (err != TEST_OK) - goto out_delete_evlist; + goto out_put_evlist; ret = TEST_OK; -out_delete_evlist: - evlist__delete(evlist); +out_put_evlist: + evlist__put(evlist); return ret; } diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index e82ecdc95777..3c88b7e8387a 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -810,7 +810,7 @@ static int do_test_code_reading(bool try_kcore) } perf_evlist__set_maps(&evlist->core, NULL, NULL); - evlist__delete(evlist); + evlist__put(evlist); evlist = NULL; continue; } @@ -847,7 +847,7 @@ static int do_test_code_reading(bool try_kcore) out_put: thread__put(thread); out_err: - evlist__delete(evlist); + evlist__put(evlist); perf_cpu_map__put(cpus); perf_thread_map__put(threads); machine__delete(machine); diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c index ae3b98bb42cf..94ab54ecd3f9 100644 --- a/tools/perf/tests/event-times.c +++ b/tools/perf/tests/event-times.c @@ -186,7 +186,7 @@ static int test_times(int (attach)(struct evlist *), err = attach(evlist); if (err == TEST_SKIP) { pr_debug(" SKIP : not enough rights\n"); - evlist__delete(evlist); + evlist__put(evlist); return err; } @@ -205,7 +205,7 @@ static int test_times(int (attach)(struct evlist *), count.ena, count.run); out_err: - evlist__delete(evlist); + evlist__put(evlist); return !err ? TEST_OK : TEST_FAIL; } diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c index facc65e29f20..73141b122d2f 100644 --- a/tools/perf/tests/event_update.c +++ b/tools/perf/tests/event_update.c @@ -117,7 +117,7 @@ static int test__event_update(struct test_suite *test __maybe_unused, int subtes TEST_ASSERT_VAL("failed to synthesize attr update cpus", !perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus)); - evlist__delete(evlist); + evlist__put(evlist); return 0; } diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index 1922cac13a24..6a220634c52f 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c @@ -33,7 +33,7 @@ static int perf_evsel__roundtrip_cache_name_test(void) if (err) { pr_debug("Failure to parse cache event '%s' possibly as PMUs don't support it", name); - evlist__delete(evlist); + evlist__put(evlist); continue; } evlist__for_each_entry(evlist, evsel) { @@ -42,7 +42,7 @@ static int perf_evsel__roundtrip_cache_name_test(void) ret = TEST_FAIL; } } - evlist__delete(evlist); + evlist__put(evlist); } } } @@ -66,7 +66,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names) if (err) { pr_debug("failed to parse event '%s', err %d\n", names[i], err); - evlist__delete(evlist); + evlist__put(evlist); ret = TEST_FAIL; continue; } @@ -76,7 +76,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names) ret = TEST_FAIL; } } - evlist__delete(evlist); + evlist__put(evlist); } return ret; } diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c index dd547f2f77cc..a7a445f12693 100644 --- a/tools/perf/tests/expand-cgroup.c +++ b/tools/perf/tests/expand-cgroup.c @@ -106,7 +106,7 @@ static int expand_default_events(void) TEST_ASSERT_VAL("failed to get evlist", evlist); ret = test_expand_events(evlist); - evlist__delete(evlist); + evlist__put(evlist); return ret; } @@ -133,7 +133,7 @@ static int expand_group_events(void) ret = test_expand_events(evlist); out: parse_events_error__exit(&err); - evlist__delete(evlist); + evlist__put(evlist); return ret; } @@ -164,7 +164,7 @@ static int expand_libpfm_events(void) ret = test_expand_events(evlist); out: - evlist__delete(evlist); + evlist__put(evlist); return ret; } @@ -188,7 +188,7 @@ static int expand_metric_events(void) ret = test_expand_events(evlist); out: - evlist__delete(evlist); + evlist__put(evlist); return ret; } diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index 09ee08085b06..9356451a172e 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c @@ -744,7 +744,7 @@ static int test__hists_cumulate(struct test_suite *test __maybe_unused, int subt out: /* tear down everything */ - evlist__delete(evlist); + evlist__put(evlist); machines__exit(&machines); put_fake_samples(); diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index ac5affb7afff..f9eaa511487b 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c @@ -332,7 +332,7 @@ static int test__hists_filter(struct test_suite *test __maybe_unused, int subtes out: /* tear down everything */ - evlist__delete(evlist); + evlist__put(evlist); reset_output_field(); machines__exit(&machines); put_fake_samples(); diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index e55990163865..d88591bcbe50 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -353,7 +353,7 @@ static int test__hists_link(struct test_suite *test __maybe_unused, int subtest out: /* tear down everything */ - evlist__delete(evlist); + evlist__put(evlist); reset_output_field(); machines__exit(&machines); put_fake_samples(); diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index 5e59dba92e81..f58c8d18fe33 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c @@ -631,7 +631,7 @@ static int test__hists_output(struct test_suite *test __maybe_unused, int subtes out: /* tear down everything */ - evlist__delete(evlist); + evlist__put(evlist); machines__exit(&machines); put_fake_samples(); diff --git a/tools/perf/tests/hwmon_pmu.c b/tools/perf/tests/hwmon_pmu.c index 62e0841a6c31..9e89051e7fdc 100644 --- a/tools/perf/tests/hwmon_pmu.c +++ b/tools/perf/tests/hwmon_pmu.c @@ -215,7 +215,7 @@ static int do_test(size_t i, bool with_pmu, bool with_alias) out: parse_events_error__exit(&err); - evlist__delete(evlist); + evlist__put(evlist); return ret; } diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index 729cc9cc1cb7..51cfd6522867 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c @@ -153,7 +153,7 @@ static int test__keep_tracking(struct test_suite *test __maybe_unused, int subte out_err: if (evlist) { evlist__disable(evlist); - evlist__delete(evlist); + evlist__put(evlist); } perf_cpu_map__put(cpus); perf_thread_map__put(threads); diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index a69cd1046e9a..5ff58eb2af8d 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -94,7 +94,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest /* Permissions failure, flag the failure as a skip. */ err = TEST_SKIP; } - goto out_delete_evlist; + goto out_put_evlist; } evsels[i]->core.attr.wakeup_events = 1; @@ -106,7 +106,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", str_error_r(errno, sbuf, sizeof(sbuf))); - goto out_delete_evlist; + goto out_put_evlist; } nr_events[i] = 0; @@ -116,7 +116,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest if (evlist__mmap(evlist, 128) < 0) { pr_debug("failed to mmap events: %d (%s)\n", errno, str_error_r(errno, sbuf, sizeof(sbuf))); - goto out_delete_evlist; + goto out_put_evlist; } for (i = 0; i < nsyscalls; ++i) @@ -134,7 +134,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest if (event->header.type != PERF_RECORD_SAMPLE) { pr_debug("unexpected %s event\n", perf_event__name(event->header.type)); - goto out_delete_evlist; + goto out_put_evlist; } perf_sample__init(&sample, /*all=*/false); @@ -142,7 +142,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest if (err) { pr_err("Can't parse sample, err = %d\n", err); perf_sample__exit(&sample); - goto out_delete_evlist; + goto out_put_evlist; } err = -1; @@ -153,7 +153,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest if (evsel == NULL) { pr_debug("event with id %" PRIu64 " doesn't map to an evsel\n", sample.id); - goto out_delete_evlist; + goto out_put_evlist; } nr_events[evsel->core.idx]++; perf_mmap__consume(&md->core); @@ -168,12 +168,12 @@ out_init: expected_nr_events[evsel->core.idx], evsel__name(evsel), nr_events[evsel->core.idx]); err = -1; - goto out_delete_evlist; + goto out_put_evlist; } } -out_delete_evlist: - evlist__delete(evlist); +out_put_evlist: + evlist__put(evlist); out_free_cpus: perf_cpu_map__put(cpus); out_free_threads: diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c index 9ff8caff98c3..b30f286fb421 100644 --- a/tools/perf/tests/openat-syscall-tp-fields.c +++ b/tools/perf/tests/openat-syscall-tp-fields.c @@ -51,7 +51,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused if (IS_ERR(evsel)) { pr_debug("%s: evsel__newtp\n", __func__); ret = PTR_ERR(evsel) == -EACCES ? TEST_SKIP : TEST_FAIL; - goto out_delete_evlist; + goto out_put_evlist; } evlist__add(evlist, evsel); @@ -59,7 +59,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused err = evlist__create_maps(evlist, &opts.target); if (err < 0) { pr_debug("%s: evlist__create_maps\n", __func__); - goto out_delete_evlist; + goto out_put_evlist; } evsel__config(evsel, &opts, NULL); @@ -70,14 +70,14 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused if (err < 0) { pr_debug("perf_evlist__open: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); - goto out_delete_evlist; + goto out_put_evlist; } err = evlist__mmap(evlist, UINT_MAX); if (err < 0) { pr_debug("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); - goto out_delete_evlist; + goto out_put_evlist; } evlist__enable(evlist); @@ -115,7 +115,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused if (err) { pr_debug("Can't parse sample, err = %d\n", err); perf_sample__exit(&sample); - goto out_delete_evlist; + goto out_put_evlist; } tp_flags = perf_sample__intval(&sample, "flags"); @@ -126,7 +126,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused (tp_flags & flags) != flags) { pr_debug("%s: Expected flags=%#x, got %#x\n", __func__, flags, tp_flags); - goto out_delete_evlist; + goto out_put_evlist; } goto out_ok; @@ -139,13 +139,13 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused if (++nr_polls > 5) { pr_debug("%s: no events!\n", __func__); - goto out_delete_evlist; + goto out_put_evlist; } } out_ok: ret = TEST_OK; -out_delete_evlist: - evlist__delete(evlist); +out_put_evlist: + evlist__put(evlist); out: return ret; } diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 05c3e899b425..19dc7b7475d2 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -2568,7 +2568,7 @@ static int test_event(const struct evlist_test *e) ret = e->check(evlist); } parse_events_error__exit(&err); - evlist__delete(evlist); + evlist__put(evlist); return ret; } @@ -2594,7 +2594,7 @@ static int test_event_fake_pmu(const char *str) } parse_events_error__exit(&err); - evlist__delete(evlist); + evlist__put(evlist); return ret; } diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c index 7c7f489a5eb0..3f0ec839c056 100644 --- a/tools/perf/tests/parse-metric.c +++ b/tools/perf/tests/parse-metric.c @@ -84,7 +84,7 @@ static int __compute_metric(const char *name, struct value *vals, cpus = perf_cpu_map__new("0"); if (!cpus) { - evlist__delete(evlist); + evlist__put(evlist); return -ENOMEM; } @@ -113,7 +113,7 @@ out: /* ... cleanup. */ evlist__free_stats(evlist); perf_cpu_map__put(cpus); - evlist__delete(evlist); + evlist__put(evlist); return err; } diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c index 8ac862c94879..78bb8db19240 100644 --- a/tools/perf/tests/parse-no-sample-id-all.c +++ b/tools/perf/tests/parse-no-sample-id-all.c @@ -49,7 +49,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]); - evlist__delete(evlist); + evlist__put(evlist); return err; } diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index ad44cc68820b..f95752b2ed1c 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -105,7 +105,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest err = evlist__create_maps(evlist, &opts.target); if (err < 0) { pr_debug("Not enough memory to create thread/cpu maps\n"); - goto out_delete_evlist; + goto out_put_evlist; } /* @@ -117,7 +117,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest err = evlist__prepare_workload(evlist, &opts.target, argv, false, NULL); if (err < 0) { pr_debug("Couldn't run the workload!\n"); - goto out_delete_evlist; + goto out_put_evlist; } /* @@ -134,7 +134,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest pr_debug("sched__get_first_possible_cpu: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); evlist__cancel_workload(evlist); - goto out_delete_evlist; + goto out_put_evlist; } cpu = err; @@ -146,7 +146,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest pr_debug("sched_setaffinity: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); evlist__cancel_workload(evlist); - goto out_delete_evlist; + goto out_put_evlist; } /* @@ -158,7 +158,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest pr_debug("perf_evlist__open: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); evlist__cancel_workload(evlist); - goto out_delete_evlist; + goto out_put_evlist; } /* @@ -171,7 +171,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest pr_debug("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); evlist__cancel_workload(evlist); - goto out_delete_evlist; + goto out_put_evlist; } /* @@ -209,7 +209,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest if (verbose > 0) perf_event__fprintf(event, NULL, stderr); pr_debug("Couldn't parse sample\n"); - goto out_delete_evlist; + goto out_put_evlist; } if (verbose > 0) { @@ -350,9 +350,9 @@ found_exit: pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]"); ++errs; } -out_delete_evlist: +out_put_evlist: CPU_FREE(cpu_mask); - evlist__delete(evlist); + evlist__put(evlist); out: perf_sample__exit(&sample); if (err == -EACCES) diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c index cca41bd37ae3..d3538fa20af3 100644 --- a/tools/perf/tests/perf-time-to-tsc.c +++ b/tools/perf/tests/perf-time-to-tsc.c @@ -201,7 +201,7 @@ next_event: err = TEST_OK; out_err: - evlist__delete(evlist); + evlist__put(evlist); perf_cpu_map__put(cpus); perf_thread_map__put(threads); return err; diff --git a/tools/perf/tests/pfm.c b/tools/perf/tests/pfm.c index fca4a86452df..8d19b1bfecbc 100644 --- a/tools/perf/tests/pfm.c +++ b/tools/perf/tests/pfm.c @@ -80,7 +80,7 @@ static int test__pfm_events(struct test_suite *test __maybe_unused, evlist__nr_groups(evlist), 0); - evlist__delete(evlist); + evlist__put(evlist); } return 0; } @@ -165,7 +165,7 @@ static int test__pfm_group(struct test_suite *test __maybe_unused, evlist__nr_groups(evlist), table[i].nr_groups); - evlist__delete(evlist); + evlist__put(evlist); } return 0; } diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index fd5630f0a13c..4ea6d392085b 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -798,7 +798,7 @@ static int check_parse_id(const char *id, struct parse_events_error *error) /*warn_if_reordered=*/true, /*fake_tp=*/false); free(dup); - evlist__delete(evlist); + evlist__put(evlist); return ret; } @@ -865,7 +865,7 @@ static int test__parsing_callback(const struct pmu_metric *pm, cpus = perf_cpu_map__new("0"); if (!cpus) { - evlist__delete(evlist); + evlist__put(evlist); return -ENOMEM; } @@ -919,7 +919,7 @@ out_err: /* ... cleanup. */ evlist__free_stats(evlist); perf_cpu_map__put(cpus); - evlist__delete(evlist); + evlist__put(evlist); return err; } diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c index d7be9d1c6f52..13e8d7fa80af 100644 --- a/tools/perf/tests/pmu.c +++ b/tools/perf/tests/pmu.c @@ -294,7 +294,7 @@ static int test__pmu_config_helpers(struct test_suite *test __maybe_unused, ret = TEST_OK; err_out: parse_events_terms__exit(&terms); - evlist__delete(evlist); + evlist__put(evlist); test_pmu_put(dir, pmu); return ret; } @@ -346,7 +346,7 @@ static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest ret = TEST_OK; err_out: parse_events_error__exit(&err); - evlist__delete(evlist); + evlist__put(evlist); test_pmu_put(dir, pmu); return ret; } diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c index b6e46975379c..bb6b62cf51d1 100644 --- a/tools/perf/tests/sw-clock.c +++ b/tools/perf/tests/sw-clock.c @@ -59,7 +59,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) evsel = evsel__new(&attr); if (evsel == NULL) { pr_debug("evsel__new\n"); - goto out_delete_evlist; + goto out_put_evlist; } evlist__add(evlist, evsel); @@ -68,7 +68,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) if (!cpus || !threads) { err = -ENOMEM; pr_debug("Not enough memory to create thread/cpu maps\n"); - goto out_delete_evlist; + goto out_put_evlist; } perf_evlist__set_maps(&evlist->core, cpus, threads); @@ -80,14 +80,14 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n", str_error_r(errno, sbuf, sizeof(sbuf)), knob, (u64)attr.sample_freq); - goto out_delete_evlist; + goto out_put_evlist; } err = evlist__mmap(evlist, 128); if (err < 0) { pr_debug("failed to mmap event: %d (%s)\n", errno, str_error_r(errno, sbuf, sizeof(sbuf))); - goto out_delete_evlist; + goto out_put_evlist; } evlist__enable(evlist); @@ -113,7 +113,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) if (err < 0) { pr_debug("Error during parse sample\n"); perf_sample__exit(&sample); - goto out_delete_evlist; + goto out_put_evlist; } total_periods += sample.period; @@ -131,10 +131,10 @@ out_init: err = -1; } -out_delete_evlist: +out_put_evlist: perf_cpu_map__put(cpus); perf_thread_map__put(threads); - evlist__delete(evlist); + evlist__put(evlist); return err; } diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c index e32331fee277..abd08d60179c 100644 --- a/tools/perf/tests/switch-tracking.c +++ b/tools/perf/tests/switch-tracking.c @@ -582,7 +582,7 @@ static int test__switch_tracking(struct test_suite *test __maybe_unused, int sub out: if (evlist) { evlist__disable(evlist); - evlist__delete(evlist); + evlist__put(evlist); } perf_cpu_map__put(cpus); perf_thread_map__put(threads); diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index 4053ff2813bb..a46650b10689 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c @@ -74,7 +74,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _ if (!cpus || !threads) { err = -ENOMEM; pr_debug("Not enough memory to create thread/cpu maps\n"); - goto out_delete_evlist; + goto out_put_evlist; } perf_evlist__set_maps(&evlist->core, cpus, threads); @@ -82,7 +82,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _ err = evlist__prepare_workload(evlist, &target, argv, false, workload_exec_failed_signal); if (err < 0) { pr_debug("Couldn't run the workload!\n"); - goto out_delete_evlist; + goto out_put_evlist; } evsel = evlist__first(evlist); @@ -101,14 +101,14 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _ if (err < 0) { pr_debug("Couldn't open the evlist: %s\n", str_error_r(-err, sbuf, sizeof(sbuf))); - goto out_delete_evlist; + goto out_put_evlist; } if (evlist__mmap(evlist, 128) < 0) { pr_debug("failed to mmap events: %d (%s)\n", errno, str_error_r(errno, sbuf, sizeof(sbuf))); err = -1; - goto out_delete_evlist; + goto out_put_evlist; } evlist__start_workload(evlist); @@ -133,7 +133,7 @@ out_init: if (retry_count++ > 1000) { pr_debug("Failed after retrying 1000 times\n"); err = -1; - goto out_delete_evlist; + goto out_put_evlist; } goto retry; @@ -144,10 +144,10 @@ out_init: err = -1; } -out_delete_evlist: +out_put_evlist: perf_cpu_map__put(cpus); perf_thread_map__put(threads); - evlist__delete(evlist); + evlist__put(evlist); return err; } diff --git a/tools/perf/tests/tool_pmu.c b/tools/perf/tests/tool_pmu.c index 1e900ef92e37..e78ff9dcea97 100644 --- a/tools/perf/tests/tool_pmu.c +++ b/tools/perf/tests/tool_pmu.c @@ -67,7 +67,7 @@ static int do_test(enum tool_pmu_event ev, bool with_pmu) out: parse_events_error__exit(&err); - evlist__delete(evlist); + evlist__put(evlist); return ret; } diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c index bd7b859dea66..15741abec8c6 100644 --- a/tools/perf/tests/topology.c +++ b/tools/perf/tests/topology.c @@ -58,7 +58,7 @@ static int session_write_header(char *path) !perf_session__write_header(session, session->evlist, perf_data__fd(&data), true)); - evlist__delete(session->evlist); + evlist__put(session->evlist); perf_session__delete(session); return 0; diff --git a/tools/perf/tests/uncore-event-sorting.c b/tools/perf/tests/uncore-event-sorting.c index 7d2fc304e21f..2e741aef4a59 100644 --- a/tools/perf/tests/uncore-event-sorting.c +++ b/tools/perf/tests/uncore-event-sorting.c @@ -165,7 +165,7 @@ static int test__uncore_event_sorting(struct test_suite *test __maybe_unused, ret = TEST_OK; out_err: - evlist__delete(evlist); + evlist__put(evlist); parse_events_error__exit(&err); zfree(&pmu_prefix); zfree(&m.event1); diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index 1b5664d1481f..652a45aac828 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c @@ -520,8 +520,8 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro cgrp_event_expanded = true; out_err: - evlist__delete(orig_list); - evlist__delete(tmp_list); + evlist__put(orig_list); + evlist__put(tmp_list); metricgroup__rblist_exit(&orig_metric_events); release_cgroup_list(); diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 5ff46bfcd0e1..e222371394c0 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -1362,7 +1362,7 @@ static void cleanup_events(struct perf_session *session) zfree(&evsel->priv); } - evlist__delete(evlist); + evlist__put(evlist); session->evlist = NULL; } diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index ab6bf5e935f4..82cc33259d81 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -75,7 +75,7 @@ int sigqueue(pid_t pid, int sig, const union sigval value); #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) #define SID(e, x, y) xyarray__entry(e->core.sample_id, x, y) -void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus, +static void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus, struct perf_thread_map *threads) { perf_evlist__init(&evlist->core); @@ -88,6 +88,7 @@ void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus, evlist->nr_br_cntr = -1; metricgroup__rblist_init(&evlist->metric_events); INIT_LIST_HEAD(&evlist->deferred_samples); + refcount_set(&evlist->refcnt, 1); } struct evlist *evlist__new(void) @@ -139,7 +140,7 @@ struct evlist *evlist__new_default(const struct target *target, bool sample_call return evlist; out_err: - evlist__delete(evlist); + evlist__put(evlist); return NULL; } @@ -148,13 +149,19 @@ struct evlist *evlist__new_dummy(void) struct evlist *evlist = evlist__new(); if (evlist && evlist__add_dummy(evlist)) { - evlist__delete(evlist); + evlist__put(evlist); evlist = NULL; } return evlist; } +struct evlist *evlist__get(struct evlist *evlist) +{ + refcount_inc(&evlist->refcnt); + return evlist; +} + /** * evlist__set_id_pos - set the positions of event ids. * @evlist: selected event list @@ -193,7 +200,7 @@ static void evlist__purge(struct evlist *evlist) evlist->core.nr_entries = 0; } -void evlist__exit(struct evlist *evlist) +static void evlist__exit(struct evlist *evlist) { metricgroup__rblist_exit(&evlist->metric_events); event_enable_timer__exit(&evlist->eet); @@ -202,11 +209,14 @@ void evlist__exit(struct evlist *evlist) perf_evlist__exit(&evlist->core); } -void evlist__delete(struct evlist *evlist) +void evlist__put(struct evlist *evlist) { if (evlist == NULL) return; + if (!refcount_dec_and_test(&evlist->refcnt)) + return; + evlist__free_stats(evlist); evlist__munmap(evlist); evlist__close(evlist); diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index e54761c670b6..a9820a6aad5b 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -61,6 +61,7 @@ struct event_enable_timer; struct evlist { struct perf_evlist core; + refcount_t refcnt; bool enabled; bool no_affinity; int id_pos; @@ -109,10 +110,8 @@ struct evsel_str_handler { struct evlist *evlist__new(void); struct evlist *evlist__new_default(const struct target *target, bool sample_callchains); struct evlist *evlist__new_dummy(void); -void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus, - struct perf_thread_map *threads); -void evlist__exit(struct evlist *evlist); -void evlist__delete(struct evlist *evlist); +struct evlist *evlist__get(struct evlist *evlist); +void evlist__put(struct evlist *evlist); void evlist__add(struct evlist *evlist, struct evsel *entry); void evlist__remove(struct evlist *evlist, struct evsel *evsel); diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c index 232998fef72b..8aef3c7418f7 100644 --- a/tools/perf/util/expr.c +++ b/tools/perf/util/expr.c @@ -468,7 +468,7 @@ double expr__has_event(const struct expr_parse_ctx *ctx, bool compute_ids, const ret = parse_event(tmp, id) ? 0 : 1; } out: - evlist__delete(tmp); + evlist__put(tmp); return ret; } diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 091d8f7f6bd2..167ec2703d0e 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -5186,7 +5186,7 @@ int perf_session__read_header(struct perf_session *session) pr_err("Invalid ids section size %" PRIu64 " for attr %d, not aligned to u64\n", f_attr.ids.size, i); err = -EINVAL; - goto out_delete_evlist; + goto out_put_evlist; } /* @@ -5199,7 +5199,7 @@ int perf_session__read_header(struct perf_session *session) pr_err("Invalid ids section size %" PRIu64 " for attr %d, too many IDs\n", f_attr.ids.size, i); err = -EINVAL; - goto out_delete_evlist; + goto out_put_evlist; } /* @@ -5212,19 +5212,19 @@ int perf_session__read_header(struct perf_session *session) pr_err("Invalid ids section for attr %d: offset=%" PRIu64 " size=%" PRIu64 " exceeds file size %" PRIu64 "\n", i, f_attr.ids.offset, f_attr.ids.size, (u64)input_stat.st_size); err = -EINVAL; - goto out_delete_evlist; + goto out_put_evlist; } tmp = lseek(fd, 0, SEEK_CUR); evsel = evsel__new(&f_attr.attr); if (evsel == NULL) - goto out_delete_evlist; + goto out_put_evlist; evsel->needs_swap = header->needs_swap; /* * Do it before so that if perf_evsel__alloc_id fails, this - * entry gets purged too at evlist__delete(). + * entry gets purged too at evlist__put(). */ evlist__add(session->evlist, evsel); @@ -5235,7 +5235,7 @@ int perf_session__read_header(struct perf_session *session) * hattr->ids threads. */ if (perf_evsel__alloc_id(&evsel->core, 1, nr_ids)) - goto out_delete_evlist; + goto out_put_evlist; lseek(fd, f_attr.ids.offset, SEEK_SET); @@ -5265,18 +5265,18 @@ int perf_session__read_header(struct perf_session *session) err = perf_header__process_sections(header, fd, &session->tevent, perf_file_section__process); if (err < 0) - goto out_delete_evlist; + goto out_put_evlist; if (evlist__prepare_tracepoint_events(session->evlist, session->tevent.pevent)) { err = -ENOMEM; - goto out_delete_evlist; + goto out_put_evlist; } #else err = perf_header__process_sections(header, fd, NULL, perf_file_section__process); if (err < 0) - goto out_delete_evlist; + goto out_put_evlist; #endif } @@ -5302,8 +5302,8 @@ int perf_session__read_header(struct perf_session *session) out_errno: return -errno; -out_delete_evlist: - evlist__delete(session->evlist); +out_put_evlist: + evlist__put(session->evlist); session->evlist = NULL; return err; } diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index c2ce3e53aaee..2c4e9fefb41f 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -214,7 +214,7 @@ static void metric__free(struct metric *m) zfree(&m->metric_refs); expr__ctx_free(m->pctx); zfree(&m->modifier); - evlist__delete(m->evlist); + evlist__put(m->evlist); free(m); } @@ -1331,7 +1331,7 @@ static int parse_ids(bool metric_no_merge, bool fake_pmu, parsed_evlist = NULL; err_out: parse_events_error__exit(&parse_error); - evlist__delete(parsed_evlist); + evlist__put(parsed_evlist); strbuf_release(&events); return ret; } @@ -1542,7 +1542,7 @@ static int parse_groups(struct evlist *perf_evlist, if (combined_evlist) { evlist__splice_list_tail(perf_evlist, &combined_evlist->core.entries); - evlist__delete(combined_evlist); + evlist__put(combined_evlist); } list_for_each_entry(m, &metric_list, nd) { diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 943569e82b82..8fb5626d5d37 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2343,7 +2343,7 @@ int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filte /* * There are 2 users - builtin-record and builtin-test objects. - * Both call evlist__delete in case of error, so we dont + * Both call evlist__put in case of error, so we dont * need to bother. */ return ret; @@ -2546,7 +2546,7 @@ int parse_events_option_new_evlist(const struct option *opt, const char *str, in } ret = parse_events_option(opt, str, unset); if (ret) { - evlist__delete(*args->evlistp); + evlist__put(*args->evlistp); *args->evlistp = NULL; } diff --git a/tools/perf/util/perf_api_probe.c b/tools/perf/util/perf_api_probe.c index e1904a330b28..f61c4ec52827 100644 --- a/tools/perf/util/perf_api_probe.c +++ b/tools/perf/util/perf_api_probe.c @@ -57,7 +57,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const cha err = 0; out_delete: - evlist__delete(evlist); + evlist__put(evlist); return err; } diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 98a8dd9b673d..7483741c024a 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -1292,7 +1292,7 @@ static int pyrf_evsel__setup_types(void) struct pyrf_evlist { PyObject_HEAD - struct evlist evlist; + struct evlist *evlist; }; static int pyrf_evlist__init(struct pyrf_evlist *pevlist, @@ -1302,18 +1302,27 @@ static int pyrf_evlist__init(struct pyrf_evlist *pevlist, struct perf_cpu_map *cpus; struct perf_thread_map *threads; - if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads)) + if (!PyArg_ParseTuple(args, "O!O!", + &pyrf_cpu_map__type, &pcpus, + &pyrf_thread_map__type, &pthreads)) return -1; + evlist__put(pevlist->evlist); + pevlist->evlist = evlist__new(); + if (!pevlist->evlist) { + PyErr_NoMemory(); + return -1; + } threads = ((struct pyrf_thread_map *)pthreads)->threads; cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; - evlist__init(&pevlist->evlist, cpus, threads); + perf_evlist__set_maps(&pevlist->evlist->core, cpus, threads); + return 0; } static void pyrf_evlist__delete(struct pyrf_evlist *pevlist) { - evlist__exit(&pevlist->evlist); + evlist__put(pevlist->evlist); Py_TYPE(pevlist)->tp_free((PyObject*)pevlist); } @@ -1322,7 +1331,7 @@ static PyObject *pyrf_evlist__all_cpus(struct pyrf_evlist *pevlist) struct pyrf_cpu_map *pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type); if (pcpu_map) - pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist.core.all_cpus); + pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist->core.all_cpus); return (PyObject *)pcpu_map; } @@ -1335,7 +1344,7 @@ static PyObject *pyrf_evlist__metrics(struct pyrf_evlist *pevlist) if (!list) return NULL; - for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node; + for (node = rb_first_cached(&pevlist->evlist->metric_events.entries); node; node = rb_next(node)) { struct metric_event *me = container_of(node, struct metric_event, nd); struct list_head *pos; @@ -1441,7 +1450,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist, if (!PyArg_ParseTuple(args, "sii", &metric, &cpu, &thread)) return NULL; - for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); + for (node = rb_first_cached(&pevlist->evlist->metric_events.entries); mexp == NULL && node; node = rb_next(node)) { struct metric_event *me = container_of(node, struct metric_event, nd); @@ -1457,7 +1466,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist, if (e->metric_events[0] == NULL) continue; - evlist__for_each_entry(&pevlist->evlist, pos2) { + evlist__for_each_entry(pevlist->evlist, pos2) { if (pos2->metric_leader != e->metric_events[0]) continue; cpu_idx = perf_cpu_map__idx(pos2->core.cpus, @@ -1502,7 +1511,7 @@ done: static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct evlist *evlist = &pevlist->evlist; + struct evlist *evlist = pevlist->evlist; static char *kwlist[] = { "pages", "overwrite", NULL }; int pages = 128, overwrite = false; @@ -1522,7 +1531,7 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist, static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct evlist *evlist = &pevlist->evlist; + struct evlist *evlist = pevlist->evlist; static char *kwlist[] = { "timeout", NULL }; int timeout = -1, n; @@ -1542,7 +1551,7 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist, PyObject *args __maybe_unused, PyObject *kwargs __maybe_unused) { - struct evlist *evlist = &pevlist->evlist; + struct evlist *evlist = pevlist->evlist; PyObject *list = PyList_New(0); int i; @@ -1571,7 +1580,7 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs __maybe_unused) { - struct evlist *evlist = &pevlist->evlist; + struct evlist *evlist = pevlist->evlist; PyObject *pevsel; struct evsel *evsel; @@ -1603,7 +1612,7 @@ static struct mmap *get_md(struct evlist *evlist, int cpu) static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct evlist *evlist = &pevlist->evlist; + struct evlist *evlist = pevlist->evlist; union perf_event *event; int sample_id_all = 1, cpu; static char *kwlist[] = { "cpu", "sample_id_all", NULL }; @@ -1660,7 +1669,7 @@ end: static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct evlist *evlist = &pevlist->evlist; + struct evlist *evlist = pevlist->evlist; if (evlist__open(evlist) < 0) { PyErr_SetFromErrno(PyExc_OSError); @@ -1673,7 +1682,7 @@ static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist, static PyObject *pyrf_evlist__close(struct pyrf_evlist *pevlist) { - struct evlist *evlist = &pevlist->evlist; + struct evlist *evlist = pevlist->evlist; evlist__close(evlist); @@ -1699,7 +1708,7 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist) .no_buffering = true, .no_inherit = true, }; - struct evlist *evlist = &pevlist->evlist; + struct evlist *evlist = pevlist->evlist; evlist__config(evlist, &opts, &callchain_param); Py_INCREF(Py_None); @@ -1708,14 +1717,14 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist) static PyObject *pyrf_evlist__disable(struct pyrf_evlist *pevlist) { - evlist__disable(&pevlist->evlist); + evlist__disable(pevlist->evlist); Py_INCREF(Py_None); return Py_None; } static PyObject *pyrf_evlist__enable(struct pyrf_evlist *pevlist) { - evlist__enable(&pevlist->evlist); + evlist__enable(pevlist->evlist); Py_INCREF(Py_None); return Py_None; } @@ -1806,7 +1815,26 @@ static Py_ssize_t pyrf_evlist__length(PyObject *obj) { struct pyrf_evlist *pevlist = (void *)obj; - return pevlist->evlist.core.nr_entries; + if (!pevlist->evlist) + return 0; + + return pevlist->evlist->core.nr_entries; +} + +static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel) +{ + struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type); + + if (!pevsel) + return NULL; + + memset(&pevsel->evsel, 0, sizeof(pevsel->evsel)); + evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx); + + evsel__clone(&pevsel->evsel, evsel); + if (evsel__is_group_leader(evsel)) + evsel__set_leader(&pevsel->evsel, &pevsel->evsel); + return (PyObject *)pevsel; } static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i) @@ -1814,17 +1842,16 @@ static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i) struct pyrf_evlist *pevlist = (void *)obj; struct evsel *pos; - if (i >= pevlist->evlist.core.nr_entries) { + if (!pevlist->evlist || i >= pevlist->evlist->core.nr_entries) { PyErr_SetString(PyExc_IndexError, "Index out of range"); return NULL; } - evlist__for_each_entry(&pevlist->evlist, pos) { + evlist__for_each_entry(pevlist->evlist, pos) { if (i-- == 0) break; } - - return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel)); + return pyrf_evsel__from_evsel(pos); } static PyObject *pyrf_evlist__str(PyObject *self) @@ -1835,8 +1862,11 @@ static PyObject *pyrf_evlist__str(PyObject *self) bool first = true; PyObject *result; + if (!pevlist->evlist) + return PyUnicode_FromString("evlist(uninitialized)"); + strbuf_addstr(&sb, "evlist(["); - evlist__for_each_entry(&pevlist->evlist, pos) { + evlist__for_each_entry(pevlist->evlist, pos) { if (!first) strbuf_addch(&sb, ','); if (!pos->pmu) @@ -1858,6 +1888,24 @@ static PySequenceMethods pyrf_evlist__sequence_methods = { static const char pyrf_evlist__doc[] = PyDoc_STR("perf event selector list object."); +static PyObject *pyrf_evlist__getattro(struct pyrf_evlist *pevlist, PyObject *attr_name) +{ + if (!pevlist->evlist) { + PyErr_SetString(PyExc_ValueError, "evlist not initialized"); + return NULL; + } + return PyObject_GenericGetAttr((PyObject *) pevlist, attr_name); +} + +static int pyrf_evlist__setattro(struct pyrf_evlist *pevlist, PyObject *attr_name, PyObject *value) +{ + if (!pevlist->evlist) { + PyErr_SetString(PyExc_ValueError, "evlist not initialized"); + return -1; + } + return PyObject_GenericSetAttr((PyObject *) pevlist, attr_name, value); +} + static PyTypeObject pyrf_evlist__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.evlist", @@ -1870,11 +1918,23 @@ static PyTypeObject pyrf_evlist__type = { .tp_init = (initproc)pyrf_evlist__init, .tp_repr = pyrf_evlist__str, .tp_str = pyrf_evlist__str, + .tp_getattro = (getattrofunc) pyrf_evlist__getattro, + .tp_setattro = (setattrofunc) pyrf_evlist__setattro, }; +static PyObject *pyrf_evlist__new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + struct pyrf_evlist *pevlist; + + pevlist = (struct pyrf_evlist *)PyType_GenericNew(type, args, kwargs); + if (pevlist) + pevlist->evlist = NULL; + return (PyObject *)pevlist; +} + static int pyrf_evlist__setup_types(void) { - pyrf_evlist__type.tp_new = PyType_GenericNew; + pyrf_evlist__type.tp_new = pyrf_evlist__new; return PyType_Ready(&pyrf_evlist__type); } @@ -1977,157 +2037,74 @@ static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel, return PyLong_FromLong(tp_pmu__id(sys, name)); } -static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel) -{ - struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type); - - if (!pevsel) - return NULL; - - memset(&pevsel->evsel, 0, sizeof(pevsel->evsel)); - evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx); - - evsel__clone(&pevsel->evsel, evsel); - if (evsel__is_group_leader(evsel)) - evsel__set_leader(&pevsel->evsel, &pevsel->evsel); - return (PyObject *)pevsel; -} - -static int evlist__pos(struct evlist *evlist, struct evsel *evsel) -{ - struct evsel *pos; - int idx = 0; - - evlist__for_each_entry(evlist, pos) { - if (evsel == pos) - return idx; - idx++; - } - return -1; -} - -static struct evsel *evlist__at(struct evlist *evlist, int idx) -{ - struct evsel *pos; - int idx2 = 0; - - evlist__for_each_entry(evlist, pos) { - if (idx == idx2) - return pos; - idx2++; - } - return NULL; -} - static PyObject *pyrf_evlist__from_evlist(struct evlist *evlist) { struct pyrf_evlist *pevlist = PyObject_New(struct pyrf_evlist, &pyrf_evlist__type); - struct evsel *pos; - struct rb_node *node; if (!pevlist) return NULL; - memset(&pevlist->evlist, 0, sizeof(pevlist->evlist)); - evlist__init(&pevlist->evlist, evlist->core.all_cpus, evlist->core.threads); - evlist__for_each_entry(evlist, pos) { - struct pyrf_evsel *pevsel = (void *)pyrf_evsel__from_evsel(pos); - - evlist__add(&pevlist->evlist, &pevsel->evsel); - } - evlist__for_each_entry(&pevlist->evlist, pos) { - struct evsel *leader = evsel__leader(pos); - - if (pos != leader) { - int idx = evlist__pos(evlist, leader); - - if (idx >= 0) - evsel__set_leader(pos, evlist__at(&pevlist->evlist, idx)); - else if (leader == NULL) - evsel__set_leader(pos, pos); - } - - leader = pos->metric_leader; - - if (pos != leader) { - int idx = evlist__pos(evlist, leader); - - if (idx >= 0) - pos->metric_leader = evlist__at(&pevlist->evlist, idx); - else if (leader == NULL) - pos->metric_leader = pos; - } - } - metricgroup__copy_metric_events(&pevlist->evlist, /*cgrp=*/NULL, - &pevlist->evlist.metric_events, - &evlist->metric_events); - for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node; - node = rb_next(node)) { - struct metric_event *me = container_of(node, struct metric_event, nd); - struct list_head *mpos; - int idx = evlist__pos(evlist, me->evsel); - - if (idx >= 0) - me->evsel = evlist__at(&pevlist->evlist, idx); - list_for_each(mpos, &me->head) { - struct metric_expr *e = container_of(mpos, struct metric_expr, nd); - - for (int j = 0; e->metric_events[j]; j++) { - idx = evlist__pos(evlist, e->metric_events[j]); - if (idx >= 0) - e->metric_events[j] = evlist__at(&pevlist->evlist, idx); - } - } - } + pevlist->evlist = evlist__get(evlist); return (PyObject *)pevlist; } static PyObject *pyrf__parse_events(PyObject *self, PyObject *args) { const char *input; - struct evlist evlist = {}; + struct evlist *evlist = evlist__new(); struct parse_events_error err; PyObject *result; PyObject *pcpus = NULL, *pthreads = NULL; struct perf_cpu_map *cpus; struct perf_thread_map *threads; - if (!PyArg_ParseTuple(args, "s|OO", &input, &pcpus, &pthreads)) + if (!evlist) + return PyErr_NoMemory(); + + if (!PyArg_ParseTuple(args, "s|OO", &input, &pcpus, &pthreads)) { + evlist__put(evlist); return NULL; + } threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL; cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL; parse_events_error__init(&err); - evlist__init(&evlist, cpus, threads); - if (parse_events(&evlist, input, &err)) { + perf_evlist__set_maps(&evlist->core, cpus, threads); + if (parse_events(evlist, input, &err)) { parse_events_error__print(&err, input); PyErr_SetFromErrno(PyExc_OSError); + evlist__put(evlist); return NULL; } - result = pyrf_evlist__from_evlist(&evlist); - evlist__exit(&evlist); + result = pyrf_evlist__from_evlist(evlist); + evlist__put(evlist); return result; } static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args) { const char *input, *pmu = NULL; - struct evlist evlist = {}; + struct evlist *evlist = evlist__new(); PyObject *result; PyObject *pcpus = NULL, *pthreads = NULL; struct perf_cpu_map *cpus; struct perf_thread_map *threads; int ret; - if (!PyArg_ParseTuple(args, "s|sOO", &input, &pmu, &pcpus, &pthreads)) + if (!evlist) + return PyErr_NoMemory(); + + if (!PyArg_ParseTuple(args, "s|sOO", &input, &pmu, &pcpus, &pthreads)) { + evlist__put(evlist); return NULL; + } threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL; cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL; - evlist__init(&evlist, cpus, threads); - ret = metricgroup__parse_groups(&evlist, pmu ?: "all", input, + perf_evlist__set_maps(&evlist->core, cpus, threads); + ret = metricgroup__parse_groups(evlist, pmu ?: "all", input, /*metric_no_group=*/ false, /*metric_no_merge=*/ false, /*metric_no_threshold=*/ true, @@ -2135,12 +2112,13 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args) /*system_wide=*/true, /*hardware_aware_grouping=*/ false); if (ret) { + evlist__put(evlist); errno = -ret; PyErr_SetFromErrno(PyExc_OSError); return NULL; } - result = pyrf_evlist__from_evlist(&evlist); - evlist__exit(&evlist); + result = pyrf_evlist__from_evlist(evlist); + evlist__put(evlist); return result; } diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index e867de8ddaaa..8a5fc7d5e43c 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -264,7 +264,7 @@ bool evlist__can_select_event(struct evlist *evlist, const char *str) ret = true; out_delete: - evlist__delete(temp_evlist); + evlist__put(temp_evlist); return ret; } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index f391a822480d..384bf5d1571f 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -265,7 +265,7 @@ void perf_session__delete(struct perf_session *session) machines__exit(&session->machines); if (session->data) { if (perf_data__is_read(session->data)) - evlist__delete(session->evlist); + evlist__put(session->evlist); perf_data__close(session->data); } #ifdef HAVE_LIBTRACEEVENT diff --git a/tools/perf/util/sideband_evlist.c b/tools/perf/util/sideband_evlist.c index 388846f17bc1..b84a5463e039 100644 --- a/tools/perf/util/sideband_evlist.c +++ b/tools/perf/util/sideband_evlist.c @@ -102,7 +102,7 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target) return 0; if (evlist__create_maps(evlist, target)) - goto out_delete_evlist; + goto out_put_evlist; if (evlist->core.nr_entries > 1) { bool can_sample_identifier = perf_can_sample_identifier(); @@ -116,25 +116,25 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target) evlist__for_each_entry(evlist, counter) { if (evsel__open(counter, evlist->core.user_requested_cpus, evlist->core.threads) < 0) - goto out_delete_evlist; + goto out_put_evlist; } if (evlist__mmap(evlist, UINT_MAX)) - goto out_delete_evlist; + goto out_put_evlist; evlist__for_each_entry(evlist, counter) { if (evsel__enable(counter)) - goto out_delete_evlist; + goto out_put_evlist; } evlist->thread.done = 0; if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist)) - goto out_delete_evlist; + goto out_put_evlist; return 0; -out_delete_evlist: - evlist__delete(evlist); +out_put_evlist: + evlist__put(evlist); evlist = NULL; return -1; } @@ -145,5 +145,5 @@ void evlist__stop_sb_thread(struct evlist *evlist) return; evlist->thread.done = 1; pthread_join(evlist->thread.th, NULL); - evlist__delete(evlist); + evlist__put(evlist); } -- cgit v1.2.3 From 3b6a78b0a4420e5d161e1bb6e8394fc5b3c62d04 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:28 -0700 Subject: perf evsel: Add reference count As with evlist this a no-op for most of the perf tool. The reference count is set to 1 at allocation, the put will see the 1, decrement it and perform the delete. The purpose for adding the reference count is for the python code. Prior to this change the python code would clone evsels, but this has issues if events are opened, etc. leading to assertion failures. With a reference count the same evsel can be used and the reference count incremented for the python usage. To not change the python evsel API getset functions are added for the evsel members, no set function is provided for size as it doesn't make sense to alter this. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/builtin-trace.c | 12 +- tools/perf/tests/evsel-tp-sched.c | 4 +- tools/perf/tests/openat-syscall-all-cpus.c | 6 +- tools/perf/tests/openat-syscall.c | 6 +- tools/perf/util/bpf_counter_cgroup.c | 2 +- tools/perf/util/cgroup.c | 2 +- tools/perf/util/evlist.c | 2 +- tools/perf/util/evsel.c | 26 ++- tools/perf/util/evsel.h | 11 +- tools/perf/util/parse-events.y | 2 +- tools/perf/util/pfm.c | 2 +- tools/perf/util/print-events.c | 2 +- tools/perf/util/python.c | 325 ++++++++++++++++++++++++----- tools/perf/util/session.c | 3 + 14 files changed, 321 insertions(+), 84 deletions(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 37de15646715..496863e82502 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -460,10 +460,10 @@ static int evsel__init_tp_ptr_field(struct evsel *evsel, struct tp_field *field, ({ struct syscall_tp *sc = __evsel__syscall_tp(evsel);\ evsel__init_tp_ptr_field(evsel, &sc->name, #name); }) -static void evsel__delete_priv(struct evsel *evsel) +static void evsel__put_and_free_priv(struct evsel *evsel) { zfree(&evsel->priv); - evsel__delete(evsel); + evsel__put(evsel); } static int evsel__init_syscall_tp(struct evsel *evsel) @@ -543,7 +543,7 @@ static struct evsel *perf_evsel__raw_syscall_newtp(const char *direction, void * return evsel; out_delete: - evsel__delete_priv(evsel); + evsel__put_and_free_priv(evsel); return NULL; } @@ -3633,7 +3633,7 @@ static bool evlist__add_vfs_getname(struct evlist *evlist) list_del_init(&evsel->core.node); evsel->evlist = NULL; - evsel__delete(evsel); + evsel__put(evsel); } return found; @@ -3749,9 +3749,9 @@ out: return ret; out_delete_sys_exit: - evsel__delete_priv(sys_exit); + evsel__put_and_free_priv(sys_exit); out_delete_sys_enter: - evsel__delete_priv(sys_enter); + evsel__put_and_free_priv(sys_enter); goto out; } diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c index 226196fb9677..9e456f88a13a 100644 --- a/tools/perf/tests/evsel-tp-sched.c +++ b/tools/perf/tests/evsel-tp-sched.c @@ -64,7 +64,7 @@ static int test__perf_evsel__tp_sched_test(struct test_suite *test __maybe_unuse if (evsel__test_field(evsel, "next_prio", 4, true)) ret = TEST_FAIL; - evsel__delete(evsel); + evsel__put(evsel); evsel = evsel__newtp("sched", "sched_wakeup"); @@ -85,7 +85,7 @@ static int test__perf_evsel__tp_sched_test(struct test_suite *test __maybe_unuse if (evsel__test_field(evsel, "target_cpu", 4, true)) ret = TEST_FAIL; - evsel__delete(evsel); + evsel__put(evsel); return ret; } diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index 0be43f8db3bd..cc63df2b3bc5 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c @@ -59,7 +59,7 @@ static int test__openat_syscall_event_on_all_cpus(struct test_suite *test __mayb "tweak /proc/sys/kernel/perf_event_paranoid?\n", str_error_r(errno, sbuf, sizeof(sbuf))); err = TEST_SKIP; - goto out_evsel_delete; + goto out_evsel_put; } perf_cpu_map__for_each_cpu(cpu, idx, cpus) { @@ -116,8 +116,8 @@ static int test__openat_syscall_event_on_all_cpus(struct test_suite *test __mayb evsel__free_counts(evsel); out_close_fd: perf_evsel__close_fd(&evsel->core); -out_evsel_delete: - evsel__delete(evsel); +out_evsel_put: + evsel__put(evsel); out_cpu_map_delete: perf_cpu_map__put(cpus); out_thread_map_delete: diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c index b54cbe5f1808..9f16f0dd3a29 100644 --- a/tools/perf/tests/openat-syscall.c +++ b/tools/perf/tests/openat-syscall.c @@ -42,7 +42,7 @@ static int test__openat_syscall_event(struct test_suite *test __maybe_unused, "tweak /proc/sys/kernel/perf_event_paranoid?\n", str_error_r(errno, sbuf, sizeof(sbuf))); err = TEST_SKIP; - goto out_evsel_delete; + goto out_evsel_put; } for (i = 0; i < nr_openat_calls; ++i) { @@ -64,8 +64,8 @@ static int test__openat_syscall_event(struct test_suite *test __maybe_unused, err = TEST_OK; out_close_fd: perf_evsel__close_fd(&evsel->core); -out_evsel_delete: - evsel__delete(evsel); +out_evsel_put: + evsel__put(evsel); out_thread_map_delete: perf_thread_map__put(threads); return err; diff --git a/tools/perf/util/bpf_counter_cgroup.c b/tools/perf/util/bpf_counter_cgroup.c index e1ce5aa3b957..6842c9f6d71e 100644 --- a/tools/perf/util/bpf_counter_cgroup.c +++ b/tools/perf/util/bpf_counter_cgroup.c @@ -336,7 +336,7 @@ static int bperf_cgrp__destroy(struct evsel *evsel) return 0; bperf_cgroup_bpf__destroy(skel); - evsel__delete(cgrp_switch); // it'll destroy on_switch progs too + evsel__put(cgrp_switch); // it'll destroy on_switch progs too return 0; } diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index 652a45aac828..914744724467 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c @@ -469,7 +469,7 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro /* copy the list and set to the new cgroup. */ evlist__for_each_entry(orig_list, pos) { - struct evsel *evsel = evsel__clone(/*dest=*/NULL, pos); + struct evsel *evsel = evsel__clone(pos); if (evsel == NULL) goto out_err; diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 82cc33259d81..1721a2470fb6 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -194,7 +194,7 @@ static void evlist__purge(struct evlist *evlist) evlist__for_each_entry_safe(evlist, n, pos) { list_del_init(&pos->core.node); pos->evlist = NULL; - evsel__delete(pos); + evsel__put(pos); } evlist->core.nr_entries = 0; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 4326650ac803..c563aa9c37b0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -445,10 +445,11 @@ bool evsel__is_function_event(struct evsel *evsel) #undef FUNCTION_EVENT } -void evsel__init(struct evsel *evsel, +static void evsel__init(struct evsel *evsel, struct perf_event_attr *attr, int idx) { perf_evsel__init(&evsel->core, attr, idx); + refcount_set(&evsel->refcnt, 1); evsel->tracking = !idx; evsel->unit = strdup(""); evsel->scale = 1.0; @@ -530,7 +531,7 @@ static int evsel__copy_config_terms(struct evsel *dst, struct evsel *src) * The assumption is that @orig is not configured nor opened yet. * So we only care about the attributes that can be set while it's parsed. */ -struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig) +struct evsel *evsel__clone(struct evsel *orig) { struct evsel *evsel; @@ -543,11 +544,7 @@ struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig) if (orig->bpf_obj) return NULL; - if (dest) - evsel = dest; - else - evsel = evsel__new(&orig->core.attr); - + evsel = evsel__new(&orig->core.attr); if (evsel == NULL) return NULL; @@ -632,7 +629,7 @@ struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig) return evsel; out_err: - evsel__delete(evsel); + evsel__put(evsel); return NULL; } @@ -691,6 +688,12 @@ out_err: return ERR_PTR(err); } +struct evsel *evsel__get(struct evsel *evsel) +{ + refcount_inc(&evsel->refcnt); + return evsel; +} + #ifdef HAVE_LIBTRACEEVENT struct tep_event *evsel__tp_format(struct evsel *evsel) { @@ -2029,7 +2032,7 @@ void evsel__set_priv_destructor(void (*destructor)(void *priv)) evsel__priv_destructor = destructor; } -void evsel__exit(struct evsel *evsel) +static void evsel__exit(struct evsel *evsel) { assert(list_empty(&evsel->core.node)); assert(evsel->evlist == NULL); @@ -2066,11 +2069,14 @@ void evsel__exit(struct evsel *evsel) } } -void evsel__delete(struct evsel *evsel) +void evsel__put(struct evsel *evsel) { if (!evsel) return; + if (!refcount_dec_and_test(&evsel->refcnt)) + return; + evsel__exit(evsel); free(evsel); } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index f85040d5528b..c63ab60c4732 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -47,6 +48,7 @@ typedef int (evsel__sb_cb_t)(union perf_event *event, void *data); struct evsel { struct perf_evsel core; struct evlist *evlist; + refcount_t refcnt; off_t id_offset; int id_pos; int is_pos; @@ -273,7 +275,7 @@ static inline struct evsel *evsel__new(struct perf_event_attr *attr) return evsel__new_idx(attr, 0); } -struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig); +struct evsel *evsel__clone(struct evsel *orig); int copy_config_terms(struct list_head *dst, struct list_head *src); void free_config_terms(struct list_head *config_terms); @@ -288,14 +290,13 @@ static inline struct evsel *evsel__newtp(const char *sys, const char *name) return evsel__newtp_idx(sys, name, 0, true); } +struct evsel *evsel__get(struct evsel *evsel); +void evsel__put(struct evsel *evsel); + #ifdef HAVE_LIBTRACEEVENT struct tep_event *evsel__tp_format(struct evsel *evsel); #endif -void evsel__init(struct evsel *evsel, struct perf_event_attr *attr, int idx); -void evsel__exit(struct evsel *evsel); -void evsel__delete(struct evsel *evsel); - void evsel__set_priv_destructor(void (*destructor)(void *priv)); struct callchain_param; diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index c194de5ec1ec..b531b1f0ceb3 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -47,7 +47,7 @@ static void free_list_evsel(struct list_head* list_evsel) list_for_each_entry_safe(evsel, tmp, list_evsel, core.node) { list_del_init(&evsel->core.node); - evsel__delete(evsel); + evsel__put(evsel); } free(list_evsel); } diff --git a/tools/perf/util/pfm.c b/tools/perf/util/pfm.c index d9043f4afbe7..5f53c2f68a96 100644 --- a/tools/perf/util/pfm.c +++ b/tools/perf/util/pfm.c @@ -159,7 +159,7 @@ static bool is_libpfm_event_supported(const char *name, struct perf_cpu_map *cpu result = false; evsel__close(evsel); - evsel__delete(evsel); + evsel__put(evsel); return result; } diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c index cb27e2898aa0..0242243681b6 100644 --- a/tools/perf/util/print-events.c +++ b/tools/perf/util/print-events.c @@ -174,7 +174,7 @@ bool is_event_supported(u8 type, u64 config) } evsel__close(evsel); - evsel__delete(evsel); + evsel__put(evsel); } perf_thread_map__put(tmap); diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 7483741c024a..5482b68b8c0b 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -294,8 +294,9 @@ static PyMemberDef pyrf_sample_event__members[] = { static void pyrf_sample_event__delete(struct pyrf_event *pevent) { + evsel__put(pevent->evsel); perf_sample__exit(&pevent->sample); - Py_TYPE(pevent)->tp_free((PyObject*)pevent); + Py_TYPE(pevent)->tp_free((PyObject *)pevent); } static PyObject *pyrf_sample_event__repr(const struct pyrf_event *pevent) @@ -526,8 +527,10 @@ static PyObject *pyrf_event__new(const union perf_event *event) ptype = pyrf_event__type[event->header.type]; pevent = PyObject_New(struct pyrf_event, ptype); - if (pevent != NULL) + if (pevent != NULL) { memcpy(&pevent->event, event, event->header.size); + pevent->evsel = NULL; + } return (PyObject *)pevent; } @@ -965,7 +968,7 @@ static int pyrf_counts_values__setup_types(void) struct pyrf_evsel { PyObject_HEAD - struct evsel evsel; + struct evsel *evsel; }; static int pyrf_evsel__init(struct pyrf_evsel *pevsel, @@ -1006,6 +1009,7 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel, "bp_type", "bp_addr", "bp_len", + "idx", NULL }; u64 sample_period = 0; @@ -1027,11 +1031,11 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel, watermark = 0, precise_ip = 0, mmap_data = 0, - sample_id_all = 1; - int idx = 0; + sample_id_all = 1, + idx = 0; if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "|iKiKKiiiiiiiiiiiiiiiiiiiiiiKK", kwlist, + "|iKiKKiiiiiiiiiiiiiiiiiiiiiiKKi", kwlist, &attr.type, &attr.config, &attr.sample_freq, &sample_period, &attr.sample_type, &attr.read_format, &disabled, &inherit, @@ -1073,26 +1077,33 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel, attr.sample_id_all = sample_id_all; attr.size = sizeof(attr); - evsel__init(&pevsel->evsel, &attr, idx); + evsel__put(pevsel->evsel); + pevsel->evsel = evsel__new(&attr); + if (!pevsel->evsel) { + PyErr_NoMemory(); + return -1; + } return 0; } static void pyrf_evsel__delete(struct pyrf_evsel *pevsel) { - evsel__exit(&pevsel->evsel); + evsel__put(pevsel->evsel); Py_TYPE(pevsel)->tp_free((PyObject*)pevsel); } static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, PyObject *args, PyObject *kwargs) { - struct evsel *evsel = &pevsel->evsel; + struct evsel *evsel = pevsel->evsel; struct perf_cpu_map *cpus = NULL; struct perf_thread_map *threads = NULL; PyObject *pcpus = NULL, *pthreads = NULL; int group = 0, inherit = 0; static char *kwlist[] = { "cpus", "threads", "group", "inherit", NULL }; + CHECK_INITIALIZED(evsel, "evsel"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, &pcpus, &pthreads, &group, &inherit)) return NULL; @@ -1119,21 +1130,26 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, static PyObject *pyrf_evsel__cpus(struct pyrf_evsel *pevsel) { - struct pyrf_cpu_map *pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type); + struct pyrf_cpu_map *pcpu_map; + CHECK_INITIALIZED(pevsel->evsel, "evsel"); + + pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type); if (pcpu_map) - pcpu_map->cpus = perf_cpu_map__get(pevsel->evsel.core.cpus); + pcpu_map->cpus = perf_cpu_map__get(pevsel->evsel->core.cpus); return (PyObject *)pcpu_map; } static PyObject *pyrf_evsel__threads(struct pyrf_evsel *pevsel) { - struct pyrf_thread_map *pthread_map = - PyObject_New(struct pyrf_thread_map, &pyrf_thread_map__type); + struct pyrf_thread_map *pthread_map; + + CHECK_INITIALIZED(pevsel->evsel, "evsel"); + pthread_map = PyObject_New(struct pyrf_thread_map, &pyrf_thread_map__type); if (pthread_map) - pthread_map->threads = perf_thread_map__get(pevsel->evsel.core.threads); + pthread_map->threads = perf_thread_map__get(pevsel->evsel->core.threads); return (PyObject *)pthread_map; } @@ -1167,12 +1183,15 @@ static int evsel__ensure_counts(struct evsel *evsel) static PyObject *pyrf_evsel__read(struct pyrf_evsel *pevsel, PyObject *args, PyObject *kwargs) { - struct evsel *evsel = &pevsel->evsel; + struct evsel *evsel = pevsel->evsel; int cpu = 0, cpu_idx, thread = 0, thread_idx; struct perf_counts_values *old_count, *new_count; - struct pyrf_counts_values *count_values = PyObject_New(struct pyrf_counts_values, - &pyrf_counts_values__type); + struct pyrf_counts_values *count_values; + + CHECK_INITIALIZED(evsel, "evsel"); + count_values = PyObject_New(struct pyrf_counts_values, + &pyrf_counts_values__type); if (!count_values) return NULL; @@ -1212,7 +1231,10 @@ static PyObject *pyrf_evsel__read(struct pyrf_evsel *pevsel, static PyObject *pyrf_evsel__str(PyObject *self) { struct pyrf_evsel *pevsel = (void *)self; - struct evsel *evsel = &pevsel->evsel; + struct evsel *evsel = pevsel->evsel; + + if (!evsel) + return PyUnicode_FromString("evsel(uninitialized)"); return PyUnicode_FromFormat("evsel(%s/%s/)", evsel__pmu_name(evsel), evsel__name(evsel)); } @@ -1245,30 +1267,227 @@ static PyMethodDef pyrf_evsel__methods[] = { { .ml_name = NULL, } }; -#define evsel_member_def(member, ptype, help) \ - { #member, ptype, \ - offsetof(struct pyrf_evsel, evsel.member), \ - 0, help } +static PyObject *pyrf_evsel__get_tracking(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; -#define evsel_attr_member_def(member, ptype, help) \ - { #member, ptype, \ - offsetof(struct pyrf_evsel, evsel.core.attr.member), \ - 0, help } + CHECK_INITIALIZED(pevsel->evsel, "evsel"); -static PyMemberDef pyrf_evsel__members[] = { - evsel_member_def(tracking, T_BOOL, "tracking event."), - evsel_attr_member_def(type, T_UINT, "attribute type."), - evsel_attr_member_def(size, T_UINT, "attribute size."), - evsel_attr_member_def(config, T_ULONGLONG, "attribute config."), - evsel_attr_member_def(sample_period, T_ULONGLONG, "attribute sample_period."), - evsel_attr_member_def(sample_type, T_ULONGLONG, "attribute sample_type."), - evsel_attr_member_def(read_format, T_ULONGLONG, "attribute read_format."), - evsel_attr_member_def(wakeup_events, T_UINT, "attribute wakeup_events."), - { .name = NULL, }, + if (pevsel->evsel->tracking) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static int pyrf_evsel__set_tracking(PyObject *self, PyObject *val, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; + int is_true; + + CHECK_INITIALIZED_INT(pevsel->evsel, "evsel"); + + is_true = PyObject_IsTrue(val); + if (is_true < 0) + return -1; + + pevsel->evsel->tracking = is_true; + return 0; +} + +static int pyrf_evsel__set_attr_config(PyObject *self, PyObject *val, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; + + CHECK_INITIALIZED_INT(pevsel->evsel, "evsel"); + + pevsel->evsel->core.attr.config = PyLong_AsUnsignedLongLong(val); + return PyErr_Occurred() ? -1 : 0; +} + +static PyObject *pyrf_evsel__get_attr_config(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; + + CHECK_INITIALIZED(pevsel->evsel, "evsel"); + + return PyLong_FromUnsignedLongLong(pevsel->evsel->core.attr.config); +} + +static int pyrf_evsel__set_attr_read_format(PyObject *self, PyObject *val, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; + + CHECK_INITIALIZED_INT(pevsel->evsel, "evsel"); + + pevsel->evsel->core.attr.read_format = PyLong_AsUnsignedLongLong(val); + return PyErr_Occurred() ? -1 : 0; +} + +static PyObject *pyrf_evsel__get_attr_read_format(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; + + CHECK_INITIALIZED(pevsel->evsel, "evsel"); + + return PyLong_FromUnsignedLongLong(pevsel->evsel->core.attr.read_format); +} + +static int pyrf_evsel__set_attr_sample_period(PyObject *self, PyObject *val, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; + + CHECK_INITIALIZED_INT(pevsel->evsel, "evsel"); + + pevsel->evsel->core.attr.sample_period = PyLong_AsUnsignedLongLong(val); + return PyErr_Occurred() ? -1 : 0; +} + +static PyObject *pyrf_evsel__get_attr_sample_period(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; + + CHECK_INITIALIZED(pevsel->evsel, "evsel"); + + return PyLong_FromUnsignedLongLong(pevsel->evsel->core.attr.sample_period); +} + +static int pyrf_evsel__set_attr_sample_type(PyObject *self, PyObject *val, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; + + CHECK_INITIALIZED_INT(pevsel->evsel, "evsel"); + + pevsel->evsel->core.attr.sample_type = PyLong_AsUnsignedLongLong(val); + return PyErr_Occurred() ? -1 : 0; +} + +static PyObject *pyrf_evsel__get_attr_sample_type(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; + + CHECK_INITIALIZED(pevsel->evsel, "evsel"); + + return PyLong_FromUnsignedLongLong(pevsel->evsel->core.attr.sample_type); +} + +static PyObject *pyrf_evsel__get_attr_size(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; + + CHECK_INITIALIZED(pevsel->evsel, "evsel"); + + return PyLong_FromUnsignedLong(pevsel->evsel->core.attr.size); +} + +static int pyrf_evsel__set_attr_type(PyObject *self, PyObject *val, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; + + CHECK_INITIALIZED_INT(pevsel->evsel, "evsel"); + + pevsel->evsel->core.attr.type = PyLong_AsUnsignedLong(val); + return PyErr_Occurred() ? -1 : 0; +} + +static PyObject *pyrf_evsel__get_attr_type(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; + + CHECK_INITIALIZED(pevsel->evsel, "evsel"); + + return PyLong_FromUnsignedLong(pevsel->evsel->core.attr.type); +} + +static int pyrf_evsel__set_attr_wakeup_events(PyObject *self, PyObject *val, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; + + CHECK_INITIALIZED_INT(pevsel->evsel, "evsel"); + + pevsel->evsel->core.attr.wakeup_events = PyLong_AsUnsignedLong(val); + return PyErr_Occurred() ? -1 : 0; +} + +static PyObject *pyrf_evsel__get_attr_wakeup_events(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_evsel *pevsel = (void *)self; + + CHECK_INITIALIZED(pevsel->evsel, "evsel"); + + return PyLong_FromUnsignedLong(pevsel->evsel->core.attr.wakeup_events); +} + +static PyGetSetDef pyrf_evsel__getset[] = { + { + .name = "tracking", + .get = pyrf_evsel__get_tracking, + .set = pyrf_evsel__set_tracking, + .doc = "tracking event.", + }, + { + .name = "config", + .get = pyrf_evsel__get_attr_config, + .set = pyrf_evsel__set_attr_config, + .doc = "attribute config.", + }, + { + .name = "read_format", + .get = pyrf_evsel__get_attr_read_format, + .set = pyrf_evsel__set_attr_read_format, + .doc = "attribute read_format.", + }, + { + .name = "sample_period", + .get = pyrf_evsel__get_attr_sample_period, + .set = pyrf_evsel__set_attr_sample_period, + .doc = "attribute sample_period.", + }, + { + .name = "sample_type", + .get = pyrf_evsel__get_attr_sample_type, + .set = pyrf_evsel__set_attr_sample_type, + .doc = "attribute sample_type.", + }, + { + .name = "size", + .get = pyrf_evsel__get_attr_size, + .doc = "attribute size.", + }, + { + .name = "type", + .get = pyrf_evsel__get_attr_type, + .set = pyrf_evsel__set_attr_type, + .doc = "attribute type.", + }, + { + .name = "wakeup_events", + .get = pyrf_evsel__get_attr_wakeup_events, + .set = pyrf_evsel__set_attr_wakeup_events, + .doc = "attribute wakeup_events.", + }, + { .name = NULL}, }; static const char pyrf_evsel__doc[] = PyDoc_STR("perf event selector list object."); +static PyObject *pyrf_evsel__getattro(struct pyrf_evsel *pevsel, PyObject *attr_name) +{ + if (!pevsel->evsel) { + PyErr_SetString(PyExc_ValueError, "evsel not initialized"); + return NULL; + } + return PyObject_GenericGetAttr((PyObject *) pevsel, attr_name); +} + +static int pyrf_evsel__setattro(struct pyrf_evsel *pevsel, PyObject *attr_name, PyObject *value) +{ + if (!pevsel->evsel) { + PyErr_SetString(PyExc_ValueError, "evsel not initialized"); + return -1; + } + return PyObject_GenericSetAttr((PyObject *) pevsel, attr_name, value); +} + static PyTypeObject pyrf_evsel__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.evsel", @@ -1276,16 +1495,28 @@ static PyTypeObject pyrf_evsel__type = { .tp_dealloc = (destructor)pyrf_evsel__delete, .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, .tp_doc = pyrf_evsel__doc, - .tp_members = pyrf_evsel__members, + .tp_getset = pyrf_evsel__getset, .tp_methods = pyrf_evsel__methods, .tp_init = (initproc)pyrf_evsel__init, .tp_str = pyrf_evsel__str, .tp_repr = pyrf_evsel__str, + .tp_getattro = (getattrofunc) pyrf_evsel__getattro, + .tp_setattro = (setattrofunc) pyrf_evsel__setattro, }; +static PyObject *pyrf_evsel__new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + struct pyrf_evsel *pevsel; + + pevsel = (struct pyrf_evsel *)PyType_GenericNew(type, args, kwargs); + if (pevsel) + pevsel->evsel = NULL; + return (PyObject *)pevsel; +} + static int pyrf_evsel__setup_types(void) { - pyrf_evsel__type.tp_new = PyType_GenericNew; + pyrf_evsel__type.tp_new = pyrf_evsel__new; return PyType_Ready(&pyrf_evsel__type); } @@ -1584,13 +1815,14 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist, PyObject *pevsel; struct evsel *evsel; - if (!PyArg_ParseTuple(args, "O", &pevsel)) + if (!PyArg_ParseTuple(args, "O!", &pyrf_evsel__type, &pevsel)) return NULL; - Py_INCREF(pevsel); - evsel = &((struct pyrf_evsel *)pevsel)->evsel; + CHECK_INITIALIZED(((struct pyrf_evsel *)pevsel)->evsel, "evsel"); + + evsel = ((struct pyrf_evsel *)pevsel)->evsel; evsel->core.idx = evlist->core.nr_entries; - evlist__add(evlist, evsel); + evlist__add(evlist, evsel__get(evsel)); return Py_BuildValue("i", evlist->core.nr_entries); } @@ -1648,7 +1880,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, return Py_None; } - pevent->evsel = evsel; + pevent->evsel = evsel__get(evsel); perf_mmap__consume(&md->core); @@ -1828,12 +2060,7 @@ static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel) if (!pevsel) return NULL; - memset(&pevsel->evsel, 0, sizeof(pevsel->evsel)); - evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx); - - evsel__clone(&pevsel->evsel, evsel); - if (evsel__is_group_leader(evsel)) - evsel__set_leader(&pevsel->evsel, &pevsel->evsel); + pevsel->evsel = evsel__get(evsel); return (PyObject *)pevsel; } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 384bf5d1571f..9962b830a402 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1845,7 +1845,10 @@ static int evlist__deliver_deferred_callchain(struct evlist *evlist, struct evsel *saved_evsel = sample->evsel; sample->evsel = evlist__id2evsel(evlist, sample->id); + if (sample->evsel) + sample->evsel = evsel__get(sample->evsel); ret = tool->callchain_deferred(tool, event, sample, machine); + evsel__put(sample->evsel); sample->evsel = saved_evsel; return ret; } -- cgit v1.2.3 From ab24487aaa42e7ca18580f6b4336615156d49452 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:29 -0700 Subject: perf evlist: Add reference count checking Now the evlist is reference counted, add reference count checking so that gets and puts are paired and easy to debug. Reference count checking is documented here: https://perfwiki.github.io/main/reference-count-checking/ This large patch is adding accessors to evlist functions and switching to their use. There was some minor renaming as evlist__mmap is now an accessor to the mmap variable, and the original evlist__mmap is renamed to evlist__do_mmap. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/arch/arm/util/cs-etm.c | 10 +- tools/perf/arch/arm64/util/arm-spe.c | 8 +- tools/perf/arch/arm64/util/hisi-ptt.c | 2 +- tools/perf/arch/x86/tests/hybrid.c | 20 +- tools/perf/arch/x86/util/auxtrace.c | 2 +- tools/perf/arch/x86/util/intel-bts.c | 6 +- tools/perf/arch/x86/util/intel-pt.c | 9 +- tools/perf/arch/x86/util/iostat.c | 12 +- tools/perf/bench/evlist-open-close.c | 11 +- tools/perf/builtin-annotate.c | 7 +- tools/perf/builtin-ftrace.c | 6 +- tools/perf/builtin-inject.c | 4 +- tools/perf/builtin-kvm.c | 10 +- tools/perf/builtin-kwork.c | 8 +- tools/perf/builtin-lock.c | 2 +- tools/perf/builtin-record.c | 91 +++---- tools/perf/builtin-report.c | 6 +- tools/perf/builtin-sched.c | 24 +- tools/perf/builtin-script.c | 13 +- tools/perf/builtin-stat.c | 73 ++--- tools/perf/builtin-top.c | 52 ++-- tools/perf/builtin-trace.c | 22 +- tools/perf/tests/backward-ring-buffer.c | 8 +- tools/perf/tests/code-reading.c | 10 +- tools/perf/tests/event-times.c | 2 +- tools/perf/tests/event_update.c | 2 +- tools/perf/tests/expand-cgroup.c | 4 +- tools/perf/tests/hwmon_pmu.c | 5 +- tools/perf/tests/keep-tracking.c | 8 +- tools/perf/tests/mmap-basic.c | 6 +- tools/perf/tests/openat-syscall-tp-fields.c | 8 +- tools/perf/tests/parse-events.c | 135 +++++----- tools/perf/tests/parse-metric.c | 4 +- tools/perf/tests/perf-record.c | 22 +- tools/perf/tests/perf-time-to-tsc.c | 10 +- tools/perf/tests/pfm.c | 8 +- tools/perf/tests/pmu-events.c | 5 +- tools/perf/tests/sample-parsing.c | 45 ++-- tools/perf/tests/sw-clock.c | 6 +- tools/perf/tests/switch-tracking.c | 9 +- tools/perf/tests/task-exit.c | 6 +- tools/perf/tests/time-utils-test.c | 14 +- tools/perf/tests/tool_pmu.c | 5 +- tools/perf/tests/topology.c | 2 +- tools/perf/tests/uncore-event-sorting.c | 4 +- tools/perf/ui/browsers/annotate.c | 2 +- tools/perf/ui/browsers/hists.c | 22 +- tools/perf/util/amd-sample-raw.c | 2 +- tools/perf/util/annotate-data.c | 2 +- tools/perf/util/annotate.c | 10 +- tools/perf/util/auxtrace.c | 14 +- tools/perf/util/block-info.c | 4 +- tools/perf/util/bpf_counter.c | 2 +- tools/perf/util/bpf_counter_cgroup.c | 12 +- tools/perf/util/bpf_ftrace.c | 9 +- tools/perf/util/bpf_lock_contention.c | 12 +- tools/perf/util/bpf_off_cpu.c | 14 +- tools/perf/util/cgroup.c | 20 +- tools/perf/util/cs-etm.c | 5 +- tools/perf/util/evlist.c | 395 ++++++++++++++++------------ tools/perf/util/evlist.h | 251 ++++++++++++++++-- tools/perf/util/evsel.c | 6 +- tools/perf/util/evsel.h | 4 +- tools/perf/util/header.c | 47 ++-- tools/perf/util/header.h | 2 +- tools/perf/util/intel-tpebs.c | 7 +- tools/perf/util/iostat.c | 2 +- tools/perf/util/iostat.h | 2 +- tools/perf/util/metricgroup.c | 6 +- tools/perf/util/parse-events.c | 6 +- tools/perf/util/pfm.c | 2 +- tools/perf/util/python.c | 90 +++++-- tools/perf/util/record.c | 9 +- tools/perf/util/sample-raw.c | 4 +- tools/perf/util/session.c | 43 ++- tools/perf/util/sideband_evlist.c | 24 +- tools/perf/util/sort.c | 2 +- tools/perf/util/stat-display.c | 6 +- tools/perf/util/stat-shadow.c | 4 +- tools/perf/util/stat.c | 4 +- tools/perf/util/stream.c | 4 +- tools/perf/util/synthetic-events.c | 11 +- tools/perf/util/time-utils.c | 12 +- tools/perf/util/top.c | 4 +- 84 files changed, 1085 insertions(+), 718 deletions(-) diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index cdf8e3e60606..d2861d66a661 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -201,7 +201,7 @@ static int cs_etm_validate_config(struct perf_pmu *cs_etm_pmu, { unsigned int idx; int err = 0; - struct perf_cpu_map *event_cpus = evsel->evlist->core.user_requested_cpus; + struct perf_cpu_map *event_cpus = evlist__core(evsel->evlist)->user_requested_cpus; struct perf_cpu_map *intersect_cpus; struct perf_cpu cpu; @@ -325,7 +325,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, container_of(itr, struct cs_etm_recording, itr); struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; struct evsel *evsel, *cs_etm_evsel = NULL; - struct perf_cpu_map *cpus = evlist->core.user_requested_cpus; + struct perf_cpu_map *cpus = evlist__core(evlist)->user_requested_cpus; bool privileged = perf_event_paranoid_check(-1); int err = 0; @@ -551,7 +551,7 @@ cs_etm_info_priv_size(struct auxtrace_record *itr, { unsigned int idx; int etmv3 = 0, etmv4 = 0, ete = 0; - struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus; + struct perf_cpu_map *event_cpus = evlist__core(evlist)->user_requested_cpus; struct perf_cpu_map *intersect_cpus; struct perf_cpu cpu; struct perf_pmu *cs_etm_pmu = cs_etm_get_pmu(itr); @@ -790,7 +790,7 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, u32 offset; u64 nr_cpu, type; struct perf_cpu_map *cpu_map; - struct perf_cpu_map *event_cpus = session->evlist->core.user_requested_cpus; + struct perf_cpu_map *event_cpus = evlist__core(session->evlist)->user_requested_cpus; struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); @@ -800,7 +800,7 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, if (priv_size != cs_etm_info_priv_size(itr, session->evlist)) return -EINVAL; - if (!session->evlist->core.nr_mmaps) + if (!evlist__core(session->evlist)->nr_mmaps) return -EINVAL; /* If the cpu_map has the "any" CPU all online CPUs are involved */ diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 91bb28cad79a..1ba803a8d9b4 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -60,7 +60,7 @@ static bool arm_spe_is_set_freq(struct evsel *evsel) */ static struct perf_cpu_map *arm_spe_find_cpus(struct evlist *evlist) { - struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus; + struct perf_cpu_map *event_cpus = evlist__core(evlist)->user_requested_cpus; struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); struct perf_cpu_map *intersect_cpus; @@ -157,7 +157,7 @@ static int arm_spe_info_fill(struct auxtrace_record *itr, if (priv_size != arm_spe_info_priv_size(itr, session->evlist)) return -EINVAL; - if (!session->evlist->core.nr_mmaps) + if (!evlist__core(session->evlist)->nr_mmaps) return -EINVAL; cpu_map = arm_spe_find_cpus(session->evlist); @@ -363,7 +363,7 @@ static int arm_spe_setup_tracking_event(struct evlist *evlist, { int err; struct evsel *tracking_evsel; - struct perf_cpu_map *cpus = evlist->core.user_requested_cpus; + struct perf_cpu_map *cpus = evlist__core(evlist)->user_requested_cpus; /* Add dummy event to keep tracking */ err = parse_event(evlist, "dummy:u"); @@ -396,7 +396,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, struct arm_spe_recording *sper = container_of(itr, struct arm_spe_recording, itr); struct evsel *evsel, *tmp; - struct perf_cpu_map *cpus = evlist->core.user_requested_cpus; + struct perf_cpu_map *cpus = evlist__core(evlist)->user_requested_cpus; bool discard = false; int err; u64 discard_bit; diff --git a/tools/perf/arch/arm64/util/hisi-ptt.c b/tools/perf/arch/arm64/util/hisi-ptt.c index fe457fd58c9e..52257715d2b7 100644 --- a/tools/perf/arch/arm64/util/hisi-ptt.c +++ b/tools/perf/arch/arm64/util/hisi-ptt.c @@ -53,7 +53,7 @@ static int hisi_ptt_info_fill(struct auxtrace_record *itr, if (priv_size != HISI_PTT_AUXTRACE_PRIV_SIZE) return -EINVAL; - if (!session->evlist->core.nr_mmaps) + if (!evlist__core(session->evlist)->nr_mmaps) return -EINVAL; auxtrace_info->type = PERF_AUXTRACE_HISI_PTT; diff --git a/tools/perf/arch/x86/tests/hybrid.c b/tools/perf/arch/x86/tests/hybrid.c index dfb0ffc0d030..0477e17b8e53 100644 --- a/tools/perf/arch/x86/tests/hybrid.c +++ b/tools/perf/arch/x86/tests/hybrid.c @@ -26,7 +26,7 @@ static int test__hybrid_hw_event_with_pmu(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist__nr_entries(evlist)); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); @@ -38,7 +38,7 @@ static int test__hybrid_hw_group_event(struct evlist *evlist) struct evsel *evsel, *leader; evsel = leader = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist__nr_entries(evlist)); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); @@ -57,7 +57,7 @@ static int test__hybrid_sw_hw_group_event(struct evlist *evlist) struct evsel *evsel, *leader; evsel = leader = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist__nr_entries(evlist)); TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); @@ -74,7 +74,7 @@ static int test__hybrid_hw_sw_group_event(struct evlist *evlist) struct evsel *evsel, *leader; evsel = leader = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist__nr_entries(evlist)); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); @@ -91,7 +91,7 @@ static int test__hybrid_group_modifier1(struct evlist *evlist) struct evsel *evsel, *leader; evsel = leader = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist__nr_entries(evlist)); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); @@ -113,7 +113,7 @@ static int test__hybrid_raw1(struct evlist *evlist) { struct perf_evsel *evsel; - perf_evlist__for_each_evsel(&evlist->core, evsel) { + perf_evlist__for_each_evsel(evlist__core(evlist), evsel) { struct perf_pmu *pmu = perf_pmus__find_by_type(evsel->attr.type); TEST_ASSERT_VAL("missing pmu", pmu); @@ -127,7 +127,7 @@ static int test__hybrid_raw2(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist__nr_entries(evlist)); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", test_config(evsel, 0x1a)); return TEST_OK; @@ -137,7 +137,7 @@ static int test__hybrid_cache_event(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist__nr_entries(evlist)); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0x2 == (evsel->core.attr.config & 0xffffffff)); return TEST_OK; @@ -148,7 +148,7 @@ static int test__checkevent_pmu(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist__nr_entries(evlist)); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 10 == evsel->core.attr.config); TEST_ASSERT_VAL("wrong config1", 1 == evsel->core.attr.config1); @@ -168,7 +168,7 @@ static int test__hybrid_hw_group_event_2(struct evlist *evlist) struct evsel *evsel, *leader; evsel = leader = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist__nr_entries(evlist)); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); diff --git a/tools/perf/arch/x86/util/auxtrace.c b/tools/perf/arch/x86/util/auxtrace.c index ecbf61a7eb3a..84fce0b51ccf 100644 --- a/tools/perf/arch/x86/util/auxtrace.c +++ b/tools/perf/arch/x86/util/auxtrace.c @@ -55,7 +55,7 @@ struct auxtrace_record *auxtrace_record__init(struct evlist *evlist, int *err) { char buffer[64]; - struct perf_cpu cpu = perf_cpu_map__min(evlist->core.all_cpus); + struct perf_cpu cpu = perf_cpu_map__min(evlist__core(evlist)->all_cpus); int ret; *err = 0; diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c index 100a23d27998..d44d568a6d21 100644 --- a/tools/perf/arch/x86/util/intel-bts.c +++ b/tools/perf/arch/x86/util/intel-bts.c @@ -79,10 +79,10 @@ static int intel_bts_info_fill(struct auxtrace_record *itr, if (priv_size != INTEL_BTS_AUXTRACE_PRIV_SIZE) return -EINVAL; - if (!session->evlist->core.nr_mmaps) + if (!evlist__core(session->evlist)->nr_mmaps) return -EINVAL; - pc = session->evlist->mmap[0].core.base; + pc = evlist__mmap(session->evlist)[0].core.base; if (pc) { err = perf_read_tsc_conversion(pc, &tc); if (err) { @@ -114,7 +114,7 @@ static int intel_bts_recording_options(struct auxtrace_record *itr, container_of(itr, struct intel_bts_recording, itr); struct perf_pmu *intel_bts_pmu = btsr->intel_bts_pmu; struct evsel *evsel, *intel_bts_evsel = NULL; - const struct perf_cpu_map *cpus = evlist->core.user_requested_cpus; + const struct perf_cpu_map *cpus = evlist__core(evlist)->user_requested_cpus; bool privileged = perf_event_paranoid_check(-1); if (opts->auxtrace_sample_mode) { diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index 0307ff15d9fc..a533114c0048 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -360,10 +360,10 @@ static int intel_pt_info_fill(struct auxtrace_record *itr, filter = intel_pt_find_filter(session->evlist, ptr->intel_pt_pmu); filter_str_len = filter ? strlen(filter) : 0; - if (!session->evlist->core.nr_mmaps) + if (!evlist__core(session->evlist)->nr_mmaps) return -EINVAL; - pc = session->evlist->mmap[0].core.base; + pc = evlist__mmap(session->evlist)[0].core.base; if (pc) { err = perf_read_tsc_conversion(pc, &tc); if (err) { @@ -376,7 +376,8 @@ static int intel_pt_info_fill(struct auxtrace_record *itr, ui__warning("Intel Processor Trace: TSC not available\n"); } - per_cpu_mmaps = !perf_cpu_map__is_any_cpu_or_is_empty(session->evlist->core.user_requested_cpus); + per_cpu_mmaps = !perf_cpu_map__is_any_cpu_or_is_empty( + evlist__core(session->evlist)->user_requested_cpus); auxtrace_info->type = PERF_AUXTRACE_INTEL_PT; auxtrace_info->priv[INTEL_PT_PMU_TYPE] = intel_pt_pmu->type; @@ -621,7 +622,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, struct perf_pmu *intel_pt_pmu = ptr->intel_pt_pmu; bool have_timing_info, need_immediate = false; struct evsel *evsel, *intel_pt_evsel = NULL; - const struct perf_cpu_map *cpus = evlist->core.user_requested_cpus; + const struct perf_cpu_map *cpus = evlist__core(evlist)->user_requested_cpus; bool privileged = perf_event_paranoid_check(-1); u64 tsc_bit; int err; diff --git a/tools/perf/arch/x86/util/iostat.c b/tools/perf/arch/x86/util/iostat.c index e0417552b0cb..b13abea3a6f4 100644 --- a/tools/perf/arch/x86/util/iostat.c +++ b/tools/perf/arch/x86/util/iostat.c @@ -332,13 +332,15 @@ err: return ret; } -int iostat_prepare(struct evlist *evlist, struct perf_stat_config *config) +int iostat_prepare(struct evlist **evlist_ptr, struct perf_stat_config *config) { - if (evlist->core.nr_entries > 0) { + struct evlist *evlist = *evlist_ptr; + + if (evlist__nr_entries(evlist) > 0) { pr_warning("The -e and -M options are not supported." "All chosen events/metrics will be dropped\n"); evlist__put(evlist); - evlist = evlist__new(); + *evlist_ptr = evlist = evlist__new(); if (!evlist) return -ENOMEM; } @@ -400,7 +402,7 @@ void iostat_prefix(struct evlist *evlist, struct perf_stat_config *config, char *prefix, struct timespec *ts) { - struct iio_root_port *rp = evlist->selected->priv; + struct iio_root_port *rp = evlist__selected(evlist)->priv; if (rp) { /* @@ -463,7 +465,7 @@ void iostat_print_counters(struct evlist *evlist, iostat_prefix(evlist, config, prefix, ts); fprintf(config->output, "%s", prefix); evlist__for_each_entry(evlist, counter) { - perf_device = evlist->selected->priv; + perf_device = evlist__selected(evlist)->priv; if (perf_device && perf_device != counter->priv) { evlist__set_selected(evlist, counter); iostat_prefix(evlist, config, prefix, ts); diff --git a/tools/perf/bench/evlist-open-close.c b/tools/perf/bench/evlist-open-close.c index 304929d1f67f..748ebbe458f4 100644 --- a/tools/perf/bench/evlist-open-close.c +++ b/tools/perf/bench/evlist-open-close.c @@ -116,7 +116,7 @@ static int bench__do_evlist_open_close(struct evlist *evlist) return err; } - err = evlist__mmap(evlist, opts.mmap_pages); + err = evlist__do_mmap(evlist, opts.mmap_pages); if (err < 0) { pr_err("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); return err; @@ -124,7 +124,7 @@ static int bench__do_evlist_open_close(struct evlist *evlist) evlist__enable(evlist); evlist__disable(evlist); - evlist__munmap(evlist); + evlist__do_munmap(evlist); evlist__close(evlist); return 0; @@ -145,10 +145,11 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str) init_stats(&time_stats); - printf(" Number of cpus:\t%d\n", perf_cpu_map__nr(evlist->core.user_requested_cpus)); - printf(" Number of threads:\t%d\n", evlist->core.threads->nr); + printf(" Number of cpus:\t%d\n", + perf_cpu_map__nr(evlist__core(evlist)->user_requested_cpus)); + printf(" Number of threads:\t%d\n", evlist__core(evlist)->threads->nr); printf(" Number of events:\t%d (%d fds)\n", - evlist->core.nr_entries, evlist__count_evsel_fds(evlist)); + evlist__nr_entries(evlist), evlist__count_evsel_fds(evlist)); printf(" Number of iterations:\t%d\n", iterations); evlist__put(evlist); diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 8a0eb30eac24..69cb72b2082a 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -562,7 +562,7 @@ static int __cmd_annotate(struct perf_annotate *ann) goto out; if ((use_browser == 1 || ann->use_stdio2) && ann->has_br_stack) - if (session->evlist->nr_br_cntr > 0) + if (evlist__nr_br_cntr(session->evlist) > 0) annotate_opts.show_br_cntr = true; if (dump_trace) { @@ -928,8 +928,11 @@ int cmd_annotate(int argc, const char **argv) * branch counters, if the corresponding branch info is available * in the perf data in the TUI mode. */ - if ((use_browser == 1 || annotate.use_stdio2) && annotate.has_br_stack) + if ((use_browser == 1 || annotate.use_stdio2) && annotate.has_br_stack) { sort__mode = SORT_MODE__BRANCH; + if (evlist__nr_br_cntr(annotate.session->evlist) > 0) + annotate_opts.show_br_cntr = true; + } if (setup_sorting(/*evlist=*/NULL, perf_session__env(annotate.session)) < 0) usage_with_options(annotate_usage, options); diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index 676239148b87..9e4c5220d43c 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -377,9 +377,9 @@ static int set_tracing_pid(struct perf_ftrace *ftrace) if (target__has_cpu(&ftrace->target)) return 0; - for (i = 0; i < perf_thread_map__nr(ftrace->evlist->core.threads); i++) { + for (i = 0; i < perf_thread_map__nr(evlist__core(ftrace->evlist)->threads); i++) { scnprintf(buf, sizeof(buf), "%d", - perf_thread_map__pid(ftrace->evlist->core.threads, i)); + perf_thread_map__pid(evlist__core(ftrace->evlist)->threads, i)); if (append_tracing_file("set_ftrace_pid", buf) < 0) return -1; } @@ -413,7 +413,7 @@ static int set_tracing_cpumask(struct perf_cpu_map *cpumap) static int set_tracing_cpu(struct perf_ftrace *ftrace) { - struct perf_cpu_map *cpumap = ftrace->evlist->core.user_requested_cpus; + struct perf_cpu_map *cpumap = evlist__core(ftrace->evlist)->user_requested_cpus; if (!target__has_cpu(&ftrace->target)) return 0; diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 6d6cce4765a7..b13ce4caf809 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -1520,7 +1520,7 @@ static int synthesize_id_index(struct perf_inject *inject, size_t new_cnt) struct perf_session *session = inject->session; struct evlist *evlist = session->evlist; struct machine *machine = &session->machines.host; - size_t from = evlist->core.nr_entries - new_cnt; + size_t from = evlist__nr_entries(evlist) - new_cnt; return __perf_event__synthesize_id_index(&inject->tool, perf_event__repipe, evlist, machine, from); @@ -2055,7 +2055,7 @@ static int host__finished_init(const struct perf_tool *tool, struct perf_session if (ret) return ret; - ret = synthesize_id_index(inject, gs->session->evlist->core.nr_entries); + ret = synthesize_id_index(inject, evlist__nr_entries(gs->session->evlist)); if (ret) { pr_err("Failed to synthesize id_index\n"); return ret; diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 993dabff2a72..2c6aef1e13a0 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1221,7 +1221,7 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx, int err; *mmap_time = ULLONG_MAX; - md = &evlist->mmap[idx]; + md = &evlist__mmap(evlist)[idx]; err = perf_mmap__read_init(&md->core); if (err < 0) return (err == -EAGAIN) ? 0 : -1; @@ -1266,7 +1266,7 @@ static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm) s64 n, ntotal = 0; u64 flush_time = ULLONG_MAX, mmap_time; - for (i = 0; i < kvm->evlist->core.nr_mmaps; i++) { + for (i = 0; i < evlist__core(kvm->evlist)->nr_mmaps; i++) { n = perf_kvm__mmap_read_idx(kvm, i, &mmap_time); if (n < 0) return -1; @@ -1449,7 +1449,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) evlist__enable(kvm->evlist); while (!done) { - struct fdarray *fda = &kvm->evlist->core.pollfd; + struct fdarray *fda = &evlist__core(kvm->evlist)->pollfd; int rc; rc = perf_kvm__mmap_read(kvm); @@ -1531,7 +1531,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) goto out; } - if (evlist__mmap(evlist, kvm->opts.mmap_pages) < 0) { + if (evlist__do_mmap(evlist, kvm->opts.mmap_pages) < 0) { ui__error("Failed to mmap the events: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); evlist__close(evlist); @@ -1931,7 +1931,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, perf_session__set_id_hdr_size(kvm->session); ordered_events__set_copy_on_queue(&kvm->session->ordered_events, true); machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target, - kvm->evlist->core.threads, true, false, 1); + evlist__core(kvm->evlist)->threads, true, false, 1); err = kvm_live_open_events(kvm); if (err) goto out; diff --git a/tools/perf/builtin-kwork.c b/tools/perf/builtin-kwork.c index 7b61168e01e9..fce588441e49 100644 --- a/tools/perf/builtin-kwork.c +++ b/tools/perf/builtin-kwork.c @@ -1814,7 +1814,7 @@ static int perf_kwork__check_config(struct perf_kwork *kwork, } } - list_for_each_entry(evsel, &session->evlist->core.entries, core.node) { + list_for_each_entry(evsel, &evlist__core(session->evlist)->entries, core.node) { if (kwork->show_callchain && !evsel__has_callchain(evsel)) { pr_debug("Samples do not have callchains\n"); kwork->show_callchain = 0; @@ -1864,9 +1864,9 @@ static int perf_kwork__read_events(struct perf_kwork *kwork) goto out_delete; } - kwork->nr_events = session->evlist->stats.nr_events[0]; - kwork->nr_lost_events = session->evlist->stats.total_lost; - kwork->nr_lost_chunks = session->evlist->stats.nr_events[PERF_RECORD_LOST]; + kwork->nr_events = evlist__stats(session->evlist)->nr_events[0]; + kwork->nr_lost_events = evlist__stats(session->evlist)->total_lost; + kwork->nr_lost_chunks = evlist__stats(session->evlist)->nr_events[PERF_RECORD_LOST]; out_delete: perf_session__delete(session); diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index d925543a68c0..d5c0d55cb82d 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -2129,7 +2129,7 @@ static int __cmd_contention(int argc, const char **argv) evlist__start_workload(con.evlist); while (!done) { - if (argc && waitpid(con.evlist->workload.pid, NULL, WNOHANG) > 0) + if (argc && waitpid(evlist__workload_pid(con.evlist), NULL, WNOHANG) > 0) break; sleep(1); } diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index e4fa77a40dac..ebd3ed0c9b3e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -502,12 +502,12 @@ static void record__aio_mmap_read_sync(struct record *rec) { int i; struct evlist *evlist = rec->evlist; - struct mmap *maps = evlist->mmap; + struct mmap *maps = evlist__mmap(evlist); if (!record__aio_enabled(rec)) return; - for (i = 0; i < evlist->core.nr_mmaps; i++) { + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { struct mmap *map = &maps[i]; if (map->core.base) @@ -811,8 +811,8 @@ static int record__auxtrace_read_snapshot_all(struct record *rec) int i; int rc = 0; - for (i = 0; i < rec->evlist->core.nr_mmaps; i++) { - struct mmap *map = &rec->evlist->mmap[i]; + for (i = 0; i < evlist__core(rec->evlist)->nr_mmaps; i++) { + struct mmap *map = &evlist__mmap(rec->evlist)[i]; if (!map->auxtrace_mmap.base) continue; @@ -1055,15 +1055,15 @@ static void record__thread_data_close_pipes(struct record_thread *thread_data) static bool evlist__per_thread(struct evlist *evlist) { - return cpu_map__is_dummy(evlist->core.user_requested_cpus); + return cpu_map__is_dummy(evlist__core(evlist)->user_requested_cpus); } static int record__thread_data_init_maps(struct record_thread *thread_data, struct evlist *evlist) { - int m, tm, nr_mmaps = evlist->core.nr_mmaps; - struct mmap *mmap = evlist->mmap; - struct mmap *overwrite_mmap = evlist->overwrite_mmap; - struct perf_cpu_map *cpus = evlist->core.all_cpus; + int m, tm, nr_mmaps = evlist__core(evlist)->nr_mmaps; + struct mmap *mmap = evlist__mmap(evlist); + struct mmap *overwrite_mmap = evlist__overwrite_mmap(evlist); + struct perf_cpu_map *cpus = evlist__core(evlist)->all_cpus; bool per_thread = evlist__per_thread(evlist); if (per_thread) @@ -1118,16 +1118,17 @@ static int record__thread_data_init_pollfd(struct record_thread *thread_data, st overwrite_map = thread_data->overwrite_maps ? thread_data->overwrite_maps[tm] : NULL; - for (f = 0; f < evlist->core.pollfd.nr; f++) { - void *ptr = evlist->core.pollfd.priv[f].ptr; + for (f = 0; f < evlist__core(evlist)->pollfd.nr; f++) { + void *ptr = evlist__core(evlist)->pollfd.priv[f].ptr; if ((map && ptr == map) || (overwrite_map && ptr == overwrite_map)) { pos = fdarray__dup_entry_from(&thread_data->pollfd, f, - &evlist->core.pollfd); + &evlist__core(evlist)->pollfd); if (pos < 0) return pos; pr_debug2("thread_data[%p]: pollfd[%d] <- event_fd=%d\n", - thread_data, pos, evlist->core.pollfd.entries[f].fd); + thread_data, pos, + evlist__core(evlist)->pollfd.entries[f].fd); } } } @@ -1171,7 +1172,7 @@ static int record__update_evlist_pollfd_from_thread(struct record *rec, struct evlist *evlist, struct record_thread *thread_data) { - struct pollfd *e_entries = evlist->core.pollfd.entries; + struct pollfd *e_entries = evlist__core(evlist)->pollfd.entries; struct pollfd *t_entries = thread_data->pollfd.entries; int err = 0; size_t i; @@ -1195,7 +1196,7 @@ static int record__dup_non_perf_events(struct record *rec, struct evlist *evlist, struct record_thread *thread_data) { - struct fdarray *fda = &evlist->core.pollfd; + struct fdarray *fda = &evlist__core(evlist)->pollfd; int i, ret; for (i = 0; i < fda->nr; i++) { @@ -1322,17 +1323,17 @@ static int record__mmap_evlist(struct record *rec, return ret; if (record__threads_enabled(rec)) { - ret = perf_data__create_dir(&rec->data, evlist->core.nr_mmaps); + ret = perf_data__create_dir(&rec->data, evlist__core(evlist)->nr_mmaps); if (ret) { errno = -ret; pr_err("Failed to create data directory: %m\n"); return ret; } - for (i = 0; i < evlist->core.nr_mmaps; i++) { - if (evlist->mmap) - evlist->mmap[i].file = &rec->data.dir.files[i]; - if (evlist->overwrite_mmap) - evlist->overwrite_mmap[i].file = &rec->data.dir.files[i]; + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { + if (evlist__mmap(evlist)) + evlist__mmap(evlist)[i].file = &rec->data.dir.files[i]; + if (evlist__overwrite_mmap(evlist)) + evlist__overwrite_mmap(evlist)[i].file = &rec->data.dir.files[i]; } } @@ -1481,11 +1482,11 @@ out: static void set_timestamp_boundary(struct record *rec, u64 sample_time) { - if (rec->evlist->first_sample_time == 0) - rec->evlist->first_sample_time = sample_time; + if (evlist__first_sample_time(rec->evlist) == 0) + evlist__set_first_sample_time(rec->evlist, sample_time); if (sample_time) - rec->evlist->last_sample_time = sample_time; + evlist__set_last_sample_time(rec->evlist, sample_time); } static int process_sample_event(const struct perf_tool *tool, @@ -1653,7 +1654,7 @@ static int record__mmap_read_evlist(struct record *rec, struct evlist *evlist, if (!maps) return 0; - if (overwrite && evlist->bkw_mmap_state != BKW_MMAP_DATA_PENDING) + if (overwrite && evlist__bkw_mmap_state(evlist) != BKW_MMAP_DATA_PENDING) return 0; if (record__aio_enabled(rec)) @@ -1808,7 +1809,7 @@ static void record__init_features(struct record *rec) if (rec->no_buildid) perf_header__clear_feat(&session->header, HEADER_BUILD_ID); - if (!have_tracepoints(&rec->evlist->core.entries)) + if (!have_tracepoints(&evlist__core(rec->evlist)->entries)) perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); if (!rec->opts.branch_stack) @@ -1874,7 +1875,7 @@ static int record__synthesize_workload(struct record *rec, bool tail) if (rec->opts.tail_synthesize != tail) return 0; - thread_map = thread_map__new_by_tid(rec->evlist->workload.pid); + thread_map = thread_map__new_by_tid(evlist__workload_pid(rec->evlist)); if (thread_map == NULL) return -1; @@ -2067,10 +2068,10 @@ static void alarm_sig_handler(int sig); static const struct perf_event_mmap_page *evlist__pick_pc(struct evlist *evlist) { if (evlist) { - if (evlist->mmap && evlist->mmap[0].core.base) - return evlist->mmap[0].core.base; - if (evlist->overwrite_mmap && evlist->overwrite_mmap[0].core.base) - return evlist->overwrite_mmap[0].core.base; + if (evlist__mmap(evlist) && evlist__mmap(evlist)[0].core.base) + return evlist__mmap(evlist)[0].core.base; + if (evlist__overwrite_mmap(evlist) && evlist__overwrite_mmap(evlist)[0].core.base) + return evlist__overwrite_mmap(evlist)[0].core.base; } return NULL; } @@ -2150,7 +2151,7 @@ static int record__synthesize(struct record *rec, bool tail) if (err) goto out; - err = perf_event__synthesize_thread_map2(&rec->tool, rec->evlist->core.threads, + err = perf_event__synthesize_thread_map2(&rec->tool, evlist__core(rec->evlist)->threads, process_synthesized_event, NULL); if (err < 0) { @@ -2158,7 +2159,7 @@ static int record__synthesize(struct record *rec, bool tail) return err; } - err = perf_event__synthesize_cpu_map(&rec->tool, rec->evlist->core.all_cpus, + err = perf_event__synthesize_cpu_map(&rec->tool, evlist__core(rec->evlist)->all_cpus, process_synthesized_event, NULL); if (err < 0) { pr_err("Couldn't synthesize cpu map.\n"); @@ -2191,7 +2192,7 @@ static int record__synthesize(struct record *rec, bool tail) bool needs_mmap = rec->opts.synth & PERF_SYNTH_MMAP; err = __machine__synthesize_threads(machine, tool, &opts->target, - rec->evlist->core.threads, + evlist__core(rec->evlist)->threads, f, needs_mmap, opts->record_data_mmap, rec->opts.nr_threads_synthesize); } @@ -2544,7 +2545,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) * because we synthesize event name through the pipe * and need the id for that. */ - if (data->is_pipe && rec->evlist->core.nr_entries == 1) + if (data->is_pipe && evlist__nr_entries(rec->evlist) == 1) rec->opts.sample_id = true; if (rec->timestamp_filename && perf_data__is_pipe(data)) { @@ -2568,7 +2569,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) } /* Debug message used by test scripts */ pr_debug3("perf record done opening and mmapping events\n"); - env->comp_mmap_len = session->evlist->core.mmap_len; + env->comp_mmap_len = evlist__core(session->evlist)->mmap_len; if (rec->opts.kcore) { err = record__kcore_copy(&session->machines.host, data); @@ -2669,7 +2670,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) * Synthesize COMM event to prevent it. */ tgid = perf_event__synthesize_comm(tool, event, - rec->evlist->workload.pid, + evlist__workload_pid(rec->evlist), process_synthesized_event, machine); free(event); @@ -2689,7 +2690,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) * Synthesize NAMESPACES event for the command specified. */ perf_event__synthesize_namespaces(tool, event, - rec->evlist->workload.pid, + evlist__workload_pid(rec->evlist), tgid, process_synthesized_event, machine); free(event); @@ -2706,7 +2707,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) } } - err = event_enable_timer__start(rec->evlist->eet); + err = event_enable_timer__start(evlist__event_enable_timer(rec->evlist)); if (err) goto out_child; @@ -2768,7 +2769,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) * record__mmap_read_all() didn't collect data from * overwritable ring buffer. Read again. */ - if (rec->evlist->bkw_mmap_state == BKW_MMAP_RUNNING) + if (evlist__bkw_mmap_state(rec->evlist) == BKW_MMAP_RUNNING) continue; trigger_ready(&switch_output_trigger); @@ -2837,7 +2838,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) } } - err = event_enable_timer__process(rec->evlist->eet); + err = event_enable_timer__process(evlist__event_enable_timer(rec->evlist)); if (err < 0) goto out_child; if (err) { @@ -2909,7 +2910,7 @@ out_free_threads: int exit_status; if (!child_finished) - kill(rec->evlist->workload.pid, SIGTERM); + kill(evlist__workload_pid(rec->evlist), SIGTERM); wait(&exit_status); @@ -4032,7 +4033,7 @@ static int record__init_thread_default_masks(struct record *rec, struct perf_cpu static int record__init_thread_masks(struct record *rec) { int ret = 0; - struct perf_cpu_map *cpus = rec->evlist->core.all_cpus; + struct perf_cpu_map *cpus = evlist__core(rec->evlist)->all_cpus; if (!record__threads_enabled(rec)) return record__init_thread_default_masks(rec, cpus); @@ -4283,14 +4284,14 @@ int cmd_record(int argc, const char **argv) if (record.opts.overwrite) record.opts.tail_synthesize = true; - if (rec->evlist->core.nr_entries == 0) { + if (evlist__nr_entries(rec->evlist) == 0) { struct evlist *def_evlist = evlist__new_default(&rec->opts.target, callchain_param.enabled); if (!def_evlist) goto out; - evlist__splice_list_tail(rec->evlist, &def_evlist->core.entries); + evlist__splice_list_tail(rec->evlist, &evlist__core(def_evlist)->entries); evlist__put(def_evlist); } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index dd1309c32094..10db1e5f1e6c 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -561,7 +561,7 @@ static int evlist__tty_browse_hists(struct evlist *evlist, struct report *rep, c if (!quiet) { fprintf(stdout, "#\n# Total Lost Samples: %" PRIu64 "\n#\n", - evlist->stats.total_lost_samples); + evlist__stats(evlist)->total_lost_samples); } evlist__for_each_entry(evlist, pos) { @@ -1156,7 +1156,7 @@ static int __cmd_report(struct report *rep) PERF_HPP_REPORT__BLOCK_AVG_CYCLES, }; - if (session->evlist->nr_br_cntr > 0) + if (evlist__nr_br_cntr(session->evlist) > 0) block_hpps[nr_hpps++] = PERF_HPP_REPORT__BLOCK_BRANCH_COUNTER; block_hpps[nr_hpps++] = PERF_HPP_REPORT__BLOCK_RANGE; @@ -1291,7 +1291,7 @@ static int process_attr(const struct perf_tool *tool __maybe_unused, * on events sample_type. */ sample_type = evlist__combined_sample_type(*pevlist); - session = (*pevlist)->session; + session = evlist__session(*pevlist); callchain_param_setup(sample_type, perf_session__e_machine(session, /*e_flags=*/NULL)); return 0; } diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 54ce9933ef09..ae033ffd1079 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -2025,9 +2025,9 @@ static int perf_sched__read_events(struct perf_sched *sched) goto out_delete; } - sched->nr_events = session->evlist->stats.nr_events[0]; - sched->nr_lost_events = session->evlist->stats.total_lost; - sched->nr_lost_chunks = session->evlist->stats.nr_events[PERF_RECORD_LOST]; + sched->nr_events = evlist__stats(session->evlist)->nr_events[0]; + sched->nr_lost_events = evlist__stats(session->evlist)->total_lost; + sched->nr_lost_chunks = evlist__stats(session->evlist)->nr_events[PERF_RECORD_LOST]; } rc = 0; @@ -3303,7 +3303,7 @@ static int timehist_check_attr(struct perf_sched *sched, struct evsel *evsel; struct evsel_runtime *er; - list_for_each_entry(evsel, &evlist->core.entries, core.node) { + list_for_each_entry(evsel, &evlist__core(evlist)->entries, core.node) { er = evsel__get_runtime(evsel); if (er == NULL) { pr_err("Failed to allocate memory for evsel runtime data\n"); @@ -3475,9 +3475,9 @@ static int perf_sched__timehist(struct perf_sched *sched) goto out; } - sched->nr_events = evlist->stats.nr_events[0]; - sched->nr_lost_events = evlist->stats.total_lost; - sched->nr_lost_chunks = evlist->stats.nr_events[PERF_RECORD_LOST]; + sched->nr_events = evlist__stats(evlist)->nr_events[0]; + sched->nr_lost_events = evlist__stats(evlist)->total_lost; + sched->nr_lost_chunks = evlist__stats(evlist)->nr_events[PERF_RECORD_LOST]; if (sched->summary) timehist_print_summary(sched, session); @@ -3982,7 +3982,7 @@ static int perf_sched__schedstat_record(struct perf_sched *sched, if (err < 0) goto out; - user_requested_cpus = evlist->core.user_requested_cpus; + user_requested_cpus = evlist__core(evlist)->user_requested_cpus; err = perf_event__synthesize_schedstat(&(sched->tool), process_synthesized_schedstat_event, @@ -3998,7 +3998,7 @@ static int perf_sched__schedstat_record(struct perf_sched *sched, evlist__start_workload(evlist); while (!done) { - if (argc && waitpid(evlist->workload.pid, NULL, WNOHANG) > 0) + if (argc && waitpid(evlist__workload_pid(evlist), NULL, WNOHANG) > 0) break; sleep(1); } @@ -4699,7 +4699,7 @@ static int perf_sched__schedstat_report(struct perf_sched *sched) if (err < 0) goto out; - user_requested_cpus = session->evlist->core.user_requested_cpus; + user_requested_cpus = evlist__core(session->evlist)->user_requested_cpus; err = perf_session__process_events(session); @@ -4875,7 +4875,7 @@ static int perf_sched__schedstat_live(struct perf_sched *sched, if (err < 0) goto out; - user_requested_cpus = evlist->core.user_requested_cpus; + user_requested_cpus = evlist__core(evlist)->user_requested_cpus; err = perf_event__synthesize_schedstat(&(sched->tool), process_synthesized_event_live, @@ -4891,7 +4891,7 @@ static int perf_sched__schedstat_live(struct perf_sched *sched, evlist__start_workload(evlist); while (!done) { - if (argc && waitpid(evlist->workload.pid, NULL, WNOHANG) > 0) + if (argc && waitpid(evlist__workload_pid(evlist), NULL, WNOHANG) > 0) break; sleep(1); } diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 0df13927001b..47afd8cdc2b7 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2229,9 +2229,10 @@ static int script_find_metrics(const struct pmu_metric *pm, evlist__for_each_entry(metric_evlist, metric_evsel) { struct evsel *script_evsel = map_metric_evsel_to_script_evsel(script_evlist, metric_evsel); - struct metric_event *metric_me = metricgroup__lookup(&metric_evlist->metric_events, - metric_evsel, - /*create=*/false); + struct metric_event *metric_me = + metricgroup__lookup(evlist__metric_events(metric_evlist), + metric_evsel, + /*create=*/false); if (script_evsel->metric_id == NULL) { script_evsel->metric_id = metric_evsel->metric_id; @@ -2251,7 +2252,7 @@ static int script_find_metrics(const struct pmu_metric *pm, if (metric_me) { struct metric_expr *expr; struct metric_event *script_me = - metricgroup__lookup(&script_evlist->metric_events, + metricgroup__lookup(evlist__metric_events(script_evlist), script_evsel, /*create=*/true); @@ -2321,7 +2322,7 @@ static void perf_sample__fprint_metric(struct thread *thread, assert(stat_config.aggr_mode == AGGR_GLOBAL); stat_config.aggr_get_id = script_aggr_cpu_id_get; stat_config.aggr_map = - cpu_aggr_map__new(evsel->evlist->core.user_requested_cpus, + cpu_aggr_map__new(evlist__core(evsel->evlist)->user_requested_cpus, aggr_cpu_id__global, /*data=*/NULL, /*needs_sort=*/false); } @@ -3909,7 +3910,7 @@ static int set_maps(struct perf_script *script) if (WARN_ONCE(script->allocated, "stats double allocation\n")) return -EINVAL; - perf_evlist__set_maps(&evlist->core, script->cpus, script->threads); + perf_evlist__set_maps(evlist__core(evlist), script->cpus, script->threads); if (evlist__alloc_stats(&stat_config, evlist, /*alloc_raw=*/true)) return -ENOMEM; diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index bf621202da69..3f897b2e8638 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -321,7 +321,7 @@ static int read_single_counter(struct evsel *counter, int cpu_map_idx, int threa */ static int read_counter_cpu(struct evsel *counter, int cpu_map_idx) { - int nthreads = perf_thread_map__nr(evsel_list->core.threads); + int nthreads = perf_thread_map__nr(evlist__core(evsel_list)->threads); int thread; if (!counter->supported) @@ -628,11 +628,12 @@ static int dispatch_events(bool forks, int timeout, int interval, int *times) time_to_sleep = sleep_time; while (!done) { - if (forks) + if (forks) { child_exited = waitpid(child_pid, &status, WNOHANG); - else - child_exited = !is_target_alive(&target, evsel_list->core.threads) ? 1 : 0; - + } else { + child_exited = !is_target_alive(&target, + evlist__core(evsel_list)->threads) ? 1 : 0; + } if (child_exited) break; @@ -681,14 +682,15 @@ static enum counter_recovery stat_handle_error(struct evsel *counter, int err) return COUNTER_RETRY; } if (target__has_per_thread(&target) && err != EOPNOTSUPP && - evsel_list->core.threads && evsel_list->core.threads->err_thread != -1) { + evlist__core(evsel_list)->threads && + evlist__core(evsel_list)->threads->err_thread != -1) { /* * For global --per-thread case, skip current * error thread. */ - if (!thread_map__remove(evsel_list->core.threads, - evsel_list->core.threads->err_thread)) { - evsel_list->core.threads->err_thread = -1; + if (!thread_map__remove(evlist__core(evsel_list)->threads, + evlist__core(evsel_list)->threads->err_thread)) { + evlist__core(evsel_list)->threads->err_thread = -1; counter->supported = true; return COUNTER_RETRY; } @@ -787,11 +789,12 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx) bool second_pass = false, has_supported_counters; if (forks) { - if (evlist__prepare_workload(evsel_list, &target, argv, is_pipe, workload_exec_failed_signal) < 0) { + if (evlist__prepare_workload(evsel_list, &target, argv, is_pipe, + workload_exec_failed_signal) < 0) { perror("failed to prepare workload"); return -1; } - child_pid = evsel_list->workload.pid; + child_pid = evlist__workload_pid(evsel_list); } evlist__for_each_entry(evsel_list, counter) { @@ -1199,7 +1202,7 @@ static int parse_cputype(const struct option *opt, const struct perf_pmu *pmu; struct evlist *evlist = *(struct evlist **)opt->value; - if (!list_empty(&evlist->core.entries)) { + if (!list_empty(&evlist__core(evlist)->entries)) { fprintf(stderr, "Must define cputype before events/metrics\n"); return -1; } @@ -1220,7 +1223,7 @@ static int parse_pmu_filter(const struct option *opt, { struct evlist *evlist = *(struct evlist **)opt->value; - if (!list_empty(&evlist->core.entries)) { + if (!list_empty(&evlist__core(evlist)->entries)) { fprintf(stderr, "Must define pmu-filter before events/metrics\n"); return -1; } @@ -1586,8 +1589,9 @@ static int perf_stat_init_aggr_mode(void) if (get_id) { bool needs_sort = stat_config.aggr_mode != AGGR_NONE; - stat_config.aggr_map = cpu_aggr_map__new(evsel_list->core.user_requested_cpus, - get_id, /*data=*/NULL, needs_sort); + stat_config.aggr_map = cpu_aggr_map__new( + evlist__core(evsel_list)->user_requested_cpus, + get_id, /*data=*/NULL, needs_sort); if (!stat_config.aggr_map) { pr_err("cannot build %s map\n", aggr_mode__string[stat_config.aggr_mode]); return -1; @@ -1596,7 +1600,7 @@ static int perf_stat_init_aggr_mode(void) } if (stat_config.aggr_mode == AGGR_THREAD) { - nr = perf_thread_map__nr(evsel_list->core.threads); + nr = perf_thread_map__nr(evlist__core(evsel_list)->threads); stat_config.aggr_map = cpu_aggr_map__empty_new(nr); if (stat_config.aggr_map == NULL) return -ENOMEM; @@ -1615,7 +1619,7 @@ static int perf_stat_init_aggr_mode(void) * taking the highest cpu number to be the size of * the aggregation translate cpumap. */ - nr = perf_cpu_map__max(evsel_list->core.all_cpus).cpu + 1; + nr = perf_cpu_map__max(evlist__core(evsel_list)->all_cpus).cpu + 1; stat_config.cpus_aggr_map = cpu_aggr_map__empty_new(nr); return stat_config.cpus_aggr_map ? 0 : -ENOMEM; } @@ -1902,7 +1906,7 @@ static int perf_stat_init_aggr_mode_file(struct perf_stat *st) bool needs_sort = stat_config.aggr_mode != AGGR_NONE; if (stat_config.aggr_mode == AGGR_THREAD) { - int nr = perf_thread_map__nr(evsel_list->core.threads); + int nr = perf_thread_map__nr(evlist__core(evsel_list)->threads); stat_config.aggr_map = cpu_aggr_map__empty_new(nr); if (stat_config.aggr_map == NULL) @@ -1920,7 +1924,7 @@ static int perf_stat_init_aggr_mode_file(struct perf_stat *st) if (!get_id) return 0; - stat_config.aggr_map = cpu_aggr_map__new(evsel_list->core.user_requested_cpus, + stat_config.aggr_map = cpu_aggr_map__new(evlist__core(evsel_list)->user_requested_cpus, get_id, env, needs_sort); if (!stat_config.aggr_map) { pr_err("cannot build %s map\n", aggr_mode__string[stat_config.aggr_mode]); @@ -2088,7 +2092,7 @@ static int add_default_events(void) if (!stat_config.topdown_level) stat_config.topdown_level = 1; - if (!evlist->core.nr_entries && !evsel_list->core.nr_entries) { + if (!evlist__nr_entries(evlist) && !evlist__nr_entries(evsel_list)) { /* * Add Default metrics. To minimize multiplexing, don't request * threshold computation, but it will be computed if the events @@ -2127,13 +2131,13 @@ static int add_default_events(void) evlist__for_each_entry(metric_evlist, evsel) evsel->default_metricgroup = true; - evlist__splice_list_tail(evlist, &metric_evlist->core.entries); + evlist__splice_list_tail(evlist, &evlist__core(metric_evlist)->entries); metricgroup__copy_metric_events(evlist, /*cgrp=*/NULL, - &evlist->metric_events, - &metric_evlist->metric_events); + evlist__metric_events(evlist), + evlist__metric_events(metric_evlist)); evlist__put(metric_evlist); } - list_sort(/*priv=*/NULL, &evlist->core.entries, default_evlist_evsel_cmp); + list_sort(/*priv=*/NULL, &evlist__core(evlist)->entries, default_evlist_evsel_cmp); } out: @@ -2148,10 +2152,10 @@ out: } } parse_events_error__exit(&err); - evlist__splice_list_tail(evsel_list, &evlist->core.entries); + evlist__splice_list_tail(evsel_list, &evlist__core(evlist)->entries); metricgroup__copy_metric_events(evsel_list, /*cgrp=*/NULL, - &evsel_list->metric_events, - &evlist->metric_events); + evlist__metric_events(evsel_list), + evlist__metric_events(evlist)); evlist__put(evlist); return ret; } @@ -2272,7 +2276,7 @@ static int set_maps(struct perf_stat *st) if (WARN_ONCE(st->maps_allocated, "stats double allocation\n")) return -EINVAL; - perf_evlist__set_maps(&evsel_list->core, st->cpus, st->threads); + perf_evlist__set_maps(evlist__core(evsel_list), st->cpus, st->threads); if (evlist__alloc_stats(&stat_config, evsel_list, /*alloc_raw=*/true)) return -ENOMEM; @@ -2424,7 +2428,7 @@ static void setup_system_wide(int forks) } } - if (evsel_list->core.nr_entries) + if (evlist__nr_entries(evsel_list)) target.system_wide = true; } } @@ -2651,7 +2655,7 @@ int cmd_stat(int argc, const char **argv) stat_config.csv_sep = DEFAULT_SEPARATOR; if (affinity_set) - evsel_list->no_affinity = !affinity; + evlist__set_no_affinity(evsel_list, !affinity); if (argc && strlen(argv[0]) > 2 && strstarts("record", argv[0])) { argc = __cmd_record(stat_options, &opt_mode, argc, argv); @@ -2818,7 +2822,7 @@ int cmd_stat(int argc, const char **argv) } if (stat_config.iostat_run) { - status = iostat_prepare(evsel_list, &stat_config); + status = iostat_prepare(&evsel_list, &stat_config); if (status) goto out; if (iostat_mode == IOSTAT_LIST) { @@ -2882,9 +2886,10 @@ int cmd_stat(int argc, const char **argv) } #ifdef HAVE_BPF_SKEL if (target.use_bpf && nr_cgroups && - (evsel_list->core.nr_entries / nr_cgroups) > BPERF_CGROUP__MAX_EVENTS) { + (evlist__nr_entries(evsel_list) / nr_cgroups) > BPERF_CGROUP__MAX_EVENTS) { pr_warning("Disabling BPF counters due to more events (%d) than the max (%d)\n", - evsel_list->core.nr_entries / nr_cgroups, BPERF_CGROUP__MAX_EVENTS); + evlist__nr_entries(evsel_list) / nr_cgroups, + BPERF_CGROUP__MAX_EVENTS); target.use_bpf = false; } #endif // HAVE_BPF_SKEL @@ -2922,7 +2927,7 @@ int cmd_stat(int argc, const char **argv) * so we could print it out on output. */ if (stat_config.aggr_mode == AGGR_THREAD) { - thread_map__read_comms(evsel_list->core.threads); + thread_map__read_comms(evlist__core(evsel_list)->threads); } if (stat_config.aggr_mode == AGGR_NODE) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index ff24ae35c67f..5933c46ee137 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -141,7 +141,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) notes = symbol__annotation(sym); annotation__lock(notes); - if (!symbol__hists(sym, top->evlist->core.nr_entries)) { + if (!symbol__hists(sym, evlist__nr_entries(top->evlist))) { annotation__unlock(notes); pr_err("Not enough memory for annotating '%s' symbol!\n", sym->name); @@ -267,7 +267,7 @@ static void perf_top__show_details(struct perf_top *top) more = hist_entry__annotate_printf(he, top->sym_evsel); - if (top->evlist->enabled) { + if (evlist__enabled(top->evlist)) { if (top->zero) symbol__annotate_zero_histogram(symbol, top->sym_evsel); else @@ -293,7 +293,7 @@ static void perf_top__resort_hists(struct perf_top *t) */ hists__unlink(hists); - if (evlist->enabled) { + if (evlist__enabled(evlist)) { if (t->zero) { hists__delete_entries(hists); } else { @@ -334,13 +334,13 @@ static void perf_top__print_sym_table(struct perf_top *top) printf("%-*.*s\n", win_width, win_width, graph_dotted_line); if (!top->record_opts.overwrite && - (top->evlist->stats.nr_lost_warned != - top->evlist->stats.nr_events[PERF_RECORD_LOST])) { - top->evlist->stats.nr_lost_warned = - top->evlist->stats.nr_events[PERF_RECORD_LOST]; + (evlist__stats(top->evlist)->nr_lost_warned != + evlist__stats(top->evlist)->nr_events[PERF_RECORD_LOST])) { + evlist__stats(top->evlist)->nr_lost_warned = + evlist__stats(top->evlist)->nr_events[PERF_RECORD_LOST]; color_fprintf(stdout, PERF_COLOR_RED, "WARNING: LOST %d chunks, Check IO/CPU overload", - top->evlist->stats.nr_lost_warned); + evlist__stats(top->evlist)->nr_lost_warned); ++printed; } @@ -447,7 +447,7 @@ static void perf_top__print_mapped_keys(struct perf_top *top) fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top->delay_secs); fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries); - if (top->evlist->core.nr_entries > 1) + if (evlist__nr_entries(top->evlist) > 1) fprintf(stdout, "\t[E] active event counter. \t(%s)\n", evsel__name(top->sym_evsel)); fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); @@ -482,7 +482,7 @@ static int perf_top__key_mapped(struct perf_top *top, int c) case 'S': return 1; case 'E': - return top->evlist->core.nr_entries > 1 ? 1 : 0; + return evlist__nr_entries(top->evlist) > 1 ? 1 : 0; default: break; } @@ -528,7 +528,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) } break; case 'E': - if (top->evlist->core.nr_entries > 1) { + if (evlist__nr_entries(top->evlist) > 1) { /* Select 0 as the default event: */ int counter = 0; @@ -539,7 +539,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) prompt_integer(&counter, "Enter details event counter"); - if (counter >= top->evlist->core.nr_entries) { + if (counter >= evlist__nr_entries(top->evlist)) { top->sym_evsel = evlist__first(top->evlist); fprintf(stderr, "Sorry, no such event, using %s.\n", evsel__name(top->sym_evsel)); sleep(1); @@ -598,8 +598,8 @@ static void perf_top__sort_new_samples(void *arg) { struct perf_top *t = arg; - if (t->evlist->selected != NULL) - t->sym_evsel = t->evlist->selected; + if (evlist__selected(t->evlist) != NULL) + t->sym_evsel = evlist__selected(t->evlist); perf_top__resort_hists(t); @@ -766,7 +766,7 @@ static void perf_event__process_sample(const struct perf_tool *tool, if (!machine) { pr_err("%u unprocessable samples recorded.\r", - top->session->evlist->stats.nr_unprocessable_samples++); + evlist__stats(top->session->evlist)->nr_unprocessable_samples++); return; } @@ -859,7 +859,7 @@ perf_top__process_lost(struct perf_top *top, union perf_event *event, { top->lost += event->lost.lost; top->lost_total += event->lost.lost; - evsel->evlist->stats.total_lost += event->lost.lost; + evlist__stats(evsel->evlist)->total_lost += event->lost.lost; } static void @@ -869,7 +869,7 @@ perf_top__process_lost_samples(struct perf_top *top, { top->lost += event->lost_samples.lost; top->lost_total += event->lost_samples.lost; - evsel->evlist->stats.total_lost_samples += event->lost_samples.lost; + evlist__stats(evsel->evlist)->total_lost_samples += event->lost_samples.lost; } static u64 last_timestamp; @@ -881,7 +881,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) struct mmap *md; union perf_event *event; - md = opts->overwrite ? &evlist->overwrite_mmap[idx] : &evlist->mmap[idx]; + md = opts->overwrite ? &evlist__overwrite_mmap(evlist)[idx] : &evlist__mmap(evlist)[idx]; if (perf_mmap__read_init(&md->core) < 0) return; @@ -918,7 +918,7 @@ static void perf_top__mmap_read(struct perf_top *top) if (overwrite) evlist__toggle_bkw_mmap(evlist, BKW_MMAP_DATA_PENDING); - for (i = 0; i < top->evlist->core.nr_mmaps; i++) + for (i = 0; i < evlist__core(top->evlist)->nr_mmaps; i++) perf_top__mmap_read_idx(top, i); if (overwrite) { @@ -1063,7 +1063,7 @@ try_again: goto out_err; } - if (evlist__mmap(evlist, opts->mmap_pages) < 0) { + if (evlist__do_mmap(evlist, opts->mmap_pages) < 0) { ui__error("Failed to mmap with %d (%s)\n", errno, str_error_r(errno, msg, sizeof(msg))); goto out_err; @@ -1218,10 +1218,10 @@ static int deliver_event(struct ordered_events *qe, } else if (event->header.type == PERF_RECORD_LOST_SAMPLES) { perf_top__process_lost_samples(top, event, evsel); } else if (event->header.type < PERF_RECORD_MAX) { - events_stats__inc(&session->evlist->stats, event->header.type); + events_stats__inc(evlist__stats(session->evlist), event->header.type); machine__process_event(machine, event, &sample); } else - ++session->evlist->stats.nr_unknown_events; + ++evlist__stats(session->evlist)->nr_unknown_events; ret = 0; next_event: @@ -1296,7 +1296,7 @@ static int __cmd_top(struct perf_top *top) pr_debug("Couldn't synthesize cgroup events.\n"); machine__synthesize_threads(&top->session->machines.host, &opts->target, - top->evlist->core.threads, true, false, + evlist__core(top->evlist)->threads, true, false, top->nr_threads_synthesize); perf_set_multithreaded(); @@ -1714,13 +1714,13 @@ int cmd_top(int argc, const char **argv) if (target__none(target)) target->system_wide = true; - if (!top.evlist->core.nr_entries) { + if (!evlist__nr_entries(top.evlist)) { struct evlist *def_evlist = evlist__new_default(target, callchain_param.enabled); if (!def_evlist) goto out_put_evlist; - evlist__splice_list_tail(top.evlist, &def_evlist->core.entries); + evlist__splice_list_tail(top.evlist, &evlist__core(def_evlist)->entries); evlist__put(def_evlist); } @@ -1797,7 +1797,7 @@ int cmd_top(int argc, const char **argv) top.session = NULL; goto out_put_evlist; } - top.evlist->session = top.session; + evlist__set_session(top.evlist, top.session); if (setup_sorting(top.evlist, perf_session__env(top.session)) < 0) { if (sort_order) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 496863e82502..b605bd7e519e 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2023,7 +2023,7 @@ static int trace__symbols_init(struct trace *trace, int argc, const char **argv, goto out; err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target, - evlist->core.threads, trace__tool_process, + evlist__core(evlist)->threads, trace__tool_process, /*needs_mmap=*/callchain_param.enabled && !trace->summary_only, /*mmap_data=*/false, @@ -4216,7 +4216,7 @@ static int trace__set_filter_pids(struct trace *trace) err = augmented_syscalls__set_filter_pids(trace->filter_pids.nr, trace->filter_pids.entries); } - } else if (perf_thread_map__pid(trace->evlist->core.threads, 0) == -1) { + } else if (perf_thread_map__pid(evlist__core(trace->evlist)->threads, 0) == -1) { err = trace__set_filter_loop_pids(trace); } @@ -4530,7 +4530,7 @@ create_maps: fprintf(trace->output, "Couldn't run the workload!\n"); goto out_put_evlist; } - workload_pid = evlist->workload.pid; + workload_pid = evlist__workload_pid(evlist); } err = evlist__open(evlist); @@ -4582,7 +4582,7 @@ create_maps: goto out_error_apply_filters; if (!trace->summary_only || !trace->summary_bpf) { - err = evlist__mmap(evlist, trace->opts.mmap_pages); + err = evlist__do_mmap(evlist, trace->opts.mmap_pages); if (err < 0) goto out_error_mmap; } @@ -4601,8 +4601,8 @@ create_maps: if (trace->summary_bpf) trace_start_bpf_summary(); - trace->multiple_threads = perf_thread_map__pid(evlist->core.threads, 0) == -1 || - perf_thread_map__nr(evlist->core.threads) > 1 || + trace->multiple_threads = perf_thread_map__pid(evlist__core(evlist)->threads, 0) == -1 || + perf_thread_map__nr(evlist__core(evlist)->threads) > 1 || evlist__first(evlist)->core.attr.inherit; /* @@ -4619,11 +4619,11 @@ create_maps: again: before = trace->nr_events; - for (i = 0; i < evlist->core.nr_mmaps; i++) { + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { union perf_event *event; struct mmap *md; - md = &evlist->mmap[i]; + md = &evlist__mmap(evlist)[i]; if (perf_mmap__read_init(&md->core) < 0) continue; @@ -5325,7 +5325,7 @@ static int trace__parse_cgroups(const struct option *opt, const char *str, int u { struct trace *trace = opt->value; - if (!list_empty(&trace->evlist->core.entries)) { + if (!list_empty(&evlist__core(trace->evlist)->entries)) { struct option o = { .value = &trace->evlist, }; @@ -5599,7 +5599,7 @@ int cmd_trace(int argc, const char **argv) * .perfconfig trace.add_events, and filter those out. */ if (!trace.trace_syscalls && !trace.trace_pgfaults && - trace.evlist->core.nr_entries == 0 /* Was --events used? */) { + evlist__nr_entries(trace.evlist) == 0 /* Was --events used? */) { trace.trace_syscalls = true; } /* @@ -5685,7 +5685,7 @@ skip_augmentation: symbol_conf.use_callchain = true; } - if (trace.evlist->core.nr_entries > 0) { + if (evlist__nr_entries(trace.evlist) > 0) { bool use_btf = false; evlist__set_default_evsel_handler(trace.evlist, trace__event_handler); diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c index 2b49b002d749..2735cc26d7ee 100644 --- a/tools/perf/tests/backward-ring-buffer.c +++ b/tools/perf/tests/backward-ring-buffer.c @@ -34,8 +34,8 @@ static int count_samples(struct evlist *evlist, int *sample_count, { int i; - for (i = 0; i < evlist->core.nr_mmaps; i++) { - struct mmap *map = &evlist->overwrite_mmap[i]; + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { + struct mmap *map = &evlist__overwrite_mmap(evlist)[i]; union perf_event *event; perf_mmap__read_init(&map->core); @@ -65,7 +65,7 @@ static int do_test(struct evlist *evlist, int mmap_pages, int err; char sbuf[STRERR_BUFSIZE]; - err = evlist__mmap(evlist, mmap_pages); + err = evlist__do_mmap(evlist, mmap_pages); if (err < 0) { pr_debug("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); @@ -77,7 +77,7 @@ static int do_test(struct evlist *evlist, int mmap_pages, evlist__disable(evlist); err = count_samples(evlist, sample_count, comm_count); - evlist__munmap(evlist); + evlist__do_munmap(evlist); return err; } diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 3c88b7e8387a..f0e8ea8754ef 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -592,8 +592,8 @@ static int process_events(struct machine *machine, struct evlist *evlist, struct mmap *md; int i, ret; - for (i = 0; i < evlist->core.nr_mmaps; i++) { - md = &evlist->mmap[i]; + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { + md = &evlist__mmap(evlist)[i]; if (perf_mmap__read_init(&md->core) < 0) continue; @@ -781,7 +781,7 @@ static int do_test_code_reading(bool try_kcore) goto out_put; } - perf_evlist__set_maps(&evlist->core, cpus, threads); + perf_evlist__set_maps(evlist__core(evlist), cpus, threads); str = events[evidx]; pr_debug("Parsing event '%s'\n", str); @@ -809,7 +809,7 @@ static int do_test_code_reading(bool try_kcore) pr_debug("perf_evlist__open() failed!\n%s\n", errbuf); } - perf_evlist__set_maps(&evlist->core, NULL, NULL); + perf_evlist__set_maps(evlist__core(evlist), NULL, NULL); evlist__put(evlist); evlist = NULL; continue; @@ -820,7 +820,7 @@ static int do_test_code_reading(bool try_kcore) if (events[evidx] == NULL) goto out_put; - ret = evlist__mmap(evlist, UINT_MAX); + ret = evlist__do_mmap(evlist, UINT_MAX); if (ret < 0) { pr_debug("evlist__mmap failed\n"); goto out_put; diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c index 94ab54ecd3f9..56dd37ca760e 100644 --- a/tools/perf/tests/event-times.c +++ b/tools/perf/tests/event-times.c @@ -50,7 +50,7 @@ static int attach__enable_on_exec(struct evlist *evlist) static int detach__enable_on_exec(struct evlist *evlist) { - waitpid(evlist->workload.pid, NULL, 0); + waitpid(evlist__workload_pid(evlist), NULL, 0); return 0; } diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c index 73141b122d2f..220cc0347747 100644 --- a/tools/perf/tests/event_update.c +++ b/tools/perf/tests/event_update.c @@ -92,7 +92,7 @@ static int test__event_update(struct test_suite *test __maybe_unused, int subtes TEST_ASSERT_VAL("failed to allocate ids", !perf_evsel__alloc_id(&evsel->core, 1, 1)); - perf_evlist__id_add(&evlist->core, &evsel->core, 0, 0, 123); + perf_evlist__id_add(evlist__core(evlist), &evsel->core, 0, 0, 123); free((char *)evsel->unit); evsel->unit = strdup("KRAVA"); diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c index a7a445f12693..549fbd473ab7 100644 --- a/tools/perf/tests/expand-cgroup.c +++ b/tools/perf/tests/expand-cgroup.c @@ -28,7 +28,7 @@ static int test_expand_events(struct evlist *evlist) TEST_ASSERT_VAL("evlist is empty", !evlist__empty(evlist)); - nr_events = evlist->core.nr_entries; + nr_events = evlist__nr_entries(evlist); ev_name = calloc(nr_events, sizeof(*ev_name)); if (ev_name == NULL) { pr_debug("memory allocation failure\n"); @@ -54,7 +54,7 @@ static int test_expand_events(struct evlist *evlist) } ret = TEST_FAIL; - if (evlist->core.nr_entries != nr_events * nr_cgrps) { + if (evlist__nr_entries(evlist) != nr_events * nr_cgrps) { pr_debug("event count doesn't match\n"); goto out; } diff --git a/tools/perf/tests/hwmon_pmu.c b/tools/perf/tests/hwmon_pmu.c index 9e89051e7fdc..e26b3fe3fab1 100644 --- a/tools/perf/tests/hwmon_pmu.c +++ b/tools/perf/tests/hwmon_pmu.c @@ -184,9 +184,10 @@ static int do_test(size_t i, bool with_pmu, bool with_alias) } ret = TEST_OK; - if (with_pmu ? (evlist->core.nr_entries != 1) : (evlist->core.nr_entries < 1)) { + if (with_pmu ? (evlist__nr_entries(evlist) != 1) + : (evlist__nr_entries(evlist) < 1)) { pr_debug("FAILED %s:%d Unexpected number of events for '%s' of %d\n", - __FILE__, __LINE__, str, evlist->core.nr_entries); + __FILE__, __LINE__, str, evlist__nr_entries(evlist)); ret = TEST_FAIL; goto out; } diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index 51cfd6522867..b760041bed30 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c @@ -37,8 +37,8 @@ static int find_comm(struct evlist *evlist, const char *comm) int i, found; found = 0; - for (i = 0; i < evlist->core.nr_mmaps; i++) { - md = &evlist->mmap[i]; + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { + md = &evlist__mmap(evlist)[i]; if (perf_mmap__read_init(&md->core) < 0) continue; while ((event = perf_mmap__read_event(&md->core)) != NULL) { @@ -87,7 +87,7 @@ static int test__keep_tracking(struct test_suite *test __maybe_unused, int subte evlist = evlist__new(); CHECK_NOT_NULL__(evlist); - perf_evlist__set_maps(&evlist->core, cpus, threads); + perf_evlist__set_maps(evlist__core(evlist), cpus, threads); CHECK__(parse_event(evlist, "dummy:u")); CHECK__(parse_event(evlist, "cpu-cycles:u")); @@ -106,7 +106,7 @@ static int test__keep_tracking(struct test_suite *test __maybe_unused, int subte goto out_err; } - CHECK__(evlist__mmap(evlist, UINT_MAX)); + CHECK__(evlist__do_mmap(evlist, UINT_MAX)); /* * First, test that a 'comm' event can be found when the event is diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 5ff58eb2af8d..5cec7644952c 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -81,7 +81,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest goto out_free_cpus; } - perf_evlist__set_maps(&evlist->core, cpus, threads); + perf_evlist__set_maps(evlist__core(evlist), cpus, threads); for (i = 0; i < nsyscalls; ++i) { char name[64]; @@ -113,7 +113,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest expected_nr_events[i] = 1 + rand() % 127; } - if (evlist__mmap(evlist, 128) < 0) { + if (evlist__do_mmap(evlist, 128) < 0) { pr_debug("failed to mmap events: %d (%s)\n", errno, str_error_r(errno, sbuf, sizeof(sbuf))); goto out_put_evlist; @@ -124,7 +124,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest syscalls[i](); } - md = &evlist->mmap[0]; + md = &evlist__mmap(evlist)[0]; if (perf_mmap__read_init(&md->core) < 0) goto out_init; diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c index b30f286fb421..5365889d326f 100644 --- a/tools/perf/tests/openat-syscall-tp-fields.c +++ b/tools/perf/tests/openat-syscall-tp-fields.c @@ -64,7 +64,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused evsel__config(evsel, &opts, NULL); - perf_thread_map__set_pid(evlist->core.threads, 0, getpid()); + perf_thread_map__set_pid(evlist__core(evlist)->threads, 0, getpid()); err = evlist__open(evlist); if (err < 0) { @@ -73,7 +73,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused goto out_put_evlist; } - err = evlist__mmap(evlist, UINT_MAX); + err = evlist__do_mmap(evlist, UINT_MAX); if (err < 0) { pr_debug("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); @@ -90,11 +90,11 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused while (1) { int before = nr_events; - for (i = 0; i < evlist->core.nr_mmaps; i++) { + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { union perf_event *event; struct mmap *md; - md = &evlist->mmap[i]; + md = &evlist__mmap(evlist)[i]; if (perf_mmap__read_init(&md->core) < 0) continue; diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 19dc7b7475d2..0ad0273da923 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -109,7 +109,7 @@ static int test__checkevent_tracepoint(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVLIST("wrong number of groups", 0 == evlist__nr_groups(evlist), evlist); TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_TRACEPOINT == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong sample_type", @@ -122,7 +122,7 @@ static int test__checkevent_tracepoint_multi(struct evlist *evlist) { struct evsel *evsel; - TEST_ASSERT_EVLIST("wrong number of entries", evlist->core.nr_entries > 1, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", evlist__nr_entries(evlist) > 1, evlist); TEST_ASSERT_EVLIST("wrong number of groups", 0 == evlist__nr_groups(evlist), evlist); evlist__for_each_entry(evlist, evsel) { @@ -144,7 +144,7 @@ static int test__checkevent_raw(struct evlist *evlist) struct evsel *evsel; bool raw_type_match = false; - TEST_ASSERT_EVLIST("wrong number of entries", 0 != evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 0 != evlist__nr_entries(evlist), evlist); evlist__for_each_entry(evlist, evsel) { struct perf_pmu *pmu __maybe_unused = NULL; @@ -182,7 +182,7 @@ static int test__checkevent_numeric(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong type", 1 == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong config", 1 == evsel->core.attr.config, evsel); return TEST_OK; @@ -193,7 +193,7 @@ static int test__checkevent_symbolic_name(struct evlist *evlist) { struct evsel *evsel; - TEST_ASSERT_EVLIST("wrong number of entries", 0 != evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 0 != evlist__nr_entries(evlist), evlist); evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_EVSEL("unexpected event", @@ -207,7 +207,7 @@ static int test__checkevent_symbolic_name_config(struct evlist *evlist) { struct evsel *evsel; - TEST_ASSERT_EVLIST("wrong number of entries", 0 != evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 0 != evlist__nr_entries(evlist), evlist); evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_EVSEL("unexpected event", @@ -228,7 +228,7 @@ static int test__checkevent_symbolic_alias(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong type/config", evsel__match(evsel, SOFTWARE, SW_PAGE_FAULTS), evsel); return TEST_OK; @@ -238,7 +238,7 @@ static int test__checkevent_genhw(struct evlist *evlist) { struct evsel *evsel; - TEST_ASSERT_EVLIST("wrong number of entries", 0 != evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 0 != evlist__nr_entries(evlist), evlist); evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_HW_CACHE == evsel->core.attr.type, evsel); @@ -251,7 +251,7 @@ static int test__checkevent_breakpoint(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong config", 0 == evsel->core.attr.config, evsel); TEST_ASSERT_EVSEL("wrong bp_type", @@ -265,7 +265,7 @@ static int test__checkevent_breakpoint_x(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong config", 0 == evsel->core.attr.config, evsel); TEST_ASSERT_EVSEL("wrong bp_type", HW_BREAKPOINT_X == evsel->core.attr.bp_type, evsel); @@ -278,7 +278,7 @@ static int test__checkevent_breakpoint_r(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong config", 0 == evsel->core.attr.config, evsel); TEST_ASSERT_EVSEL("wrong bp_type", HW_BREAKPOINT_R == evsel->core.attr.bp_type, evsel); @@ -290,7 +290,7 @@ static int test__checkevent_breakpoint_w(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong config", 0 == evsel->core.attr.config, evsel); TEST_ASSERT_EVSEL("wrong bp_type", HW_BREAKPOINT_W == evsel->core.attr.bp_type, evsel); @@ -302,7 +302,7 @@ static int test__checkevent_breakpoint_rw(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong config", 0 == evsel->core.attr.config, evsel); TEST_ASSERT_EVSEL("wrong bp_type", @@ -316,7 +316,7 @@ static int test__checkevent_tracepoint_modifier(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); @@ -330,7 +330,7 @@ test__checkevent_tracepoint_multi_modifier(struct evlist *evlist) { struct evsel *evsel; - TEST_ASSERT_EVLIST("wrong number of entries", evlist->core.nr_entries > 1, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", evlist__nr_entries(evlist) > 1, evlist); evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); @@ -346,7 +346,7 @@ static int test__checkevent_raw_modifier(struct evlist *evlist) { struct evsel *evsel; - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); @@ -361,7 +361,7 @@ static int test__checkevent_numeric_modifier(struct evlist *evlist) { struct evsel *evsel; - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); @@ -377,7 +377,7 @@ static int test__checkevent_symbolic_name_modifier(struct evlist *evlist) struct evsel *evsel; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); evlist__for_each_entry(evlist, evsel) { @@ -394,7 +394,7 @@ static int test__checkevent_exclude_host_modifier(struct evlist *evlist) struct evsel *evsel; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); evlist__for_each_entry(evlist, evsel) { @@ -409,7 +409,7 @@ static int test__checkevent_exclude_guest_modifier(struct evlist *evlist) struct evsel *evsel; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); evlist__for_each_entry(evlist, evsel) { @@ -423,7 +423,8 @@ static int test__checkevent_symbolic_alias_modifier(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", + 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); @@ -437,7 +438,7 @@ static int test__checkevent_genhw_modifier(struct evlist *evlist) struct evsel *evsel; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); evlist__for_each_entry(evlist, evsel) { @@ -454,7 +455,7 @@ static int test__checkevent_exclude_idle_modifier(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong exclude idle", evsel->core.attr.exclude_idle, evsel); @@ -473,7 +474,7 @@ static int test__checkevent_exclude_idle_modifier_1(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong exclude idle", evsel->core.attr.exclude_idle, evsel); @@ -622,7 +623,7 @@ static int test__checkevent_breakpoint_2_events(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVSEL("wrong number of entries", 2 == evlist->core.nr_entries, evsel); + TEST_ASSERT_EVSEL("wrong number of entries", 2 == evlist__nr_entries(evlist), evsel); TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "breakpoint1"), evsel); @@ -641,7 +642,7 @@ static int test__checkevent_pmu(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); struct perf_pmu *core_pmu = perf_pmus__find_core_pmu(); - TEST_ASSERT_EVSEL("wrong number of entries", 1 == evlist->core.nr_entries, evsel); + TEST_ASSERT_EVSEL("wrong number of entries", 1 == evlist__nr_entries(evlist), evsel); TEST_ASSERT_EVSEL("wrong type", core_pmu->type == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong config", test_hw_config(evsel, 10), evsel); TEST_ASSERT_EVSEL("wrong config1", 1 == evsel->core.attr.config1, evsel); @@ -661,7 +662,7 @@ static int test__checkevent_list(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVSEL("wrong number of entries", 3 <= evlist->core.nr_entries, evsel); + TEST_ASSERT_EVSEL("wrong number of entries", 3 <= evlist__nr_entries(evlist), evsel); /* r1 */ TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_TRACEPOINT != evsel->core.attr.type, evsel); @@ -707,14 +708,15 @@ static int test__checkevent_pmu_name(struct evlist *evlist) char buf[256]; /* default_core/config=1,name=krava/u */ - TEST_ASSERT_EVLIST("wrong number of entries", 2 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", + 2 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong type", core_pmu->type == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong config", 1 == evsel->core.attr.config, evsel); TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "krava"), evsel); /* default_core/config=2/u" */ evsel = evsel__next(evsel); - TEST_ASSERT_EVSEL("wrong number of entries", 2 == evlist->core.nr_entries, evsel); + TEST_ASSERT_EVSEL("wrong number of entries", 2 == evlist__nr_entries(evlist), evsel); TEST_ASSERT_EVSEL("wrong type", core_pmu->type == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong config", 2 == evsel->core.attr.config, evsel); snprintf(buf, sizeof(buf), "%s/config=2/u", core_pmu->name); @@ -729,7 +731,8 @@ static int test__checkevent_pmu_partial_time_callgraph(struct evlist *evlist) struct perf_pmu *core_pmu = perf_pmus__find_core_pmu(); /* default_core/config=1,call-graph=fp,time,period=100000/ */ - TEST_ASSERT_EVLIST("wrong number of entries", 2 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", + 2 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong type", core_pmu->type == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong config", 1 == evsel->core.attr.config, evsel); /* @@ -760,7 +763,7 @@ static int test__checkevent_pmu_events(struct evlist *evlist) struct evsel *evsel; struct perf_pmu *core_pmu = perf_pmus__find_core_pmu(); - TEST_ASSERT_EVLIST("wrong number of entries", 1 <= evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 <= evlist__nr_entries(evlist), evlist); evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_EVSEL("wrong type", @@ -787,8 +790,9 @@ static int test__checkevent_pmu_events_mix(struct evlist *evlist) * The wild card event will be opened at least once, but it may be * opened on each core PMU. */ - TEST_ASSERT_EVLIST("wrong number of entries", evlist->core.nr_entries >= 2, evlist); - for (int i = 0; i < evlist->core.nr_entries - 1; i++) { + TEST_ASSERT_EVLIST("wrong number of entries", + evlist__nr_entries(evlist) >= 2, evlist); + for (int i = 0; i < evlist__nr_entries(evlist) - 1; i++) { evsel = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); /* pmu-event:u */ TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); @@ -905,7 +909,7 @@ static int test__group1(struct evlist *evlist) struct evsel *evsel = NULL, *leader; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == (num_core_entries(evlist) * 2), + evlist__nr_entries(evlist) == (num_core_entries(evlist) * 2), evlist); TEST_ASSERT_EVLIST("wrong number of groups", evlist__nr_groups(evlist) == num_core_entries(evlist), @@ -950,7 +954,7 @@ static int test__group2(struct evlist *evlist) struct evsel *evsel, *leader = NULL; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == (2 * num_core_entries(evlist) + 1), + evlist__nr_entries(evlist) == (2 * num_core_entries(evlist) + 1), evlist); /* * TODO: Currently the software event won't be grouped with the hardware @@ -1018,7 +1022,7 @@ static int test__group3(struct evlist *evlist __maybe_unused) struct evsel *evsel, *group1_leader = NULL, *group2_leader = NULL; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == (3 * perf_pmus__num_core_pmus() + 2), + evlist__nr_entries(evlist) == (3 * perf_pmus__num_core_pmus() + 2), evlist); /* * Currently the software event won't be grouped with the hardware event @@ -1144,7 +1148,7 @@ static int test__group4(struct evlist *evlist __maybe_unused) struct evsel *evsel = NULL, *leader; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == (num_core_entries(evlist) * 2), + evlist__nr_entries(evlist) == (num_core_entries(evlist) * 2), evlist); TEST_ASSERT_EVLIST("wrong number of groups", num_core_entries(evlist) == evlist__nr_groups(evlist), @@ -1191,7 +1195,7 @@ static int test__group5(struct evlist *evlist __maybe_unused) struct evsel *evsel = NULL, *leader; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == (5 * num_core_entries(evlist)), + evlist__nr_entries(evlist) == (5 * num_core_entries(evlist)), evlist); TEST_ASSERT_EVLIST("wrong number of groups", evlist__nr_groups(evlist) == (2 * num_core_entries(evlist)), @@ -1284,7 +1288,7 @@ static int test__group_gh1(struct evlist *evlist) struct evsel *evsel = NULL, *leader; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == (2 * num_core_entries(evlist)), + evlist__nr_entries(evlist) == (2 * num_core_entries(evlist)), evlist); TEST_ASSERT_EVLIST("wrong number of groups", evlist__nr_groups(evlist) == num_core_entries(evlist), @@ -1329,7 +1333,7 @@ static int test__group_gh2(struct evlist *evlist) struct evsel *evsel = NULL, *leader; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == (2 * num_core_entries(evlist)), + evlist__nr_entries(evlist) == (2 * num_core_entries(evlist)), evlist); TEST_ASSERT_EVLIST("wrong number of groups", evlist__nr_groups(evlist) == num_core_entries(evlist), @@ -1374,7 +1378,7 @@ static int test__group_gh3(struct evlist *evlist) struct evsel *evsel = NULL, *leader; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == (2 * num_core_entries(evlist)), + evlist__nr_entries(evlist) == (2 * num_core_entries(evlist)), evlist); TEST_ASSERT_EVLIST("wrong number of groups", evlist__nr_groups(evlist) == num_core_entries(evlist), @@ -1419,7 +1423,7 @@ static int test__group_gh4(struct evlist *evlist) struct evsel *evsel = NULL, *leader; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == (2 * num_core_entries(evlist)), + evlist__nr_entries(evlist) == (2 * num_core_entries(evlist)), evlist); TEST_ASSERT_EVLIST("wrong number of groups", evlist__nr_groups(evlist) == num_core_entries(evlist), @@ -1464,7 +1468,7 @@ static int test__leader_sample1(struct evlist *evlist) struct evsel *evsel = NULL, *leader; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == (3 * num_core_entries(evlist)), + evlist__nr_entries(evlist) == (3 * num_core_entries(evlist)), evlist); for (int i = 0; i < num_core_entries(evlist); i++) { @@ -1520,7 +1524,7 @@ static int test__leader_sample2(struct evlist *evlist __maybe_unused) struct evsel *evsel = NULL, *leader; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == (2 * num_core_entries(evlist)), + evlist__nr_entries(evlist) == (2 * num_core_entries(evlist)), evlist); for (int i = 0; i < num_core_entries(evlist); i++) { @@ -1562,7 +1566,7 @@ static int test__checkevent_pinned_modifier(struct evlist *evlist) struct evsel *evsel = NULL; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); for (int i = 0; i < num_core_entries(evlist); i++) { @@ -1581,7 +1585,7 @@ static int test__pinned_group(struct evlist *evlist) struct evsel *evsel = NULL, *leader; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == (3 * num_core_entries(evlist)), + evlist__nr_entries(evlist) == (3 * num_core_entries(evlist)), evlist); for (int i = 0; i < num_core_entries(evlist); i++) { @@ -1618,7 +1622,7 @@ static int test__checkevent_exclusive_modifier(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); @@ -1634,7 +1638,7 @@ static int test__exclusive_group(struct evlist *evlist) struct evsel *evsel = NULL, *leader; TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == 3 * num_core_entries(evlist), + evlist__nr_entries(evlist) == 3 * num_core_entries(evlist), evlist); for (int i = 0; i < num_core_entries(evlist); i++) { @@ -1669,7 +1673,7 @@ static int test__checkevent_breakpoint_len(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong config", 0 == evsel->core.attr.config, evsel); TEST_ASSERT_EVSEL("wrong bp_type", @@ -1684,7 +1688,7 @@ static int test__checkevent_breakpoint_len_w(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong config", 0 == evsel->core.attr.config, evsel); TEST_ASSERT_EVSEL("wrong bp_type", HW_BREAKPOINT_W == evsel->core.attr.bp_type, evsel); @@ -1698,7 +1702,7 @@ test__checkevent_breakpoint_len_rw_modifier(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); @@ -1712,7 +1716,7 @@ static int test__checkevent_precise_max_modifier(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == 1 + num_core_entries(evlist), + evlist__nr_entries(evlist) == 1 + num_core_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong type/config", evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK), evsel); return TEST_OK; @@ -1723,7 +1727,7 @@ static int test__checkevent_config_symbol(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong name setting", evsel__name_is(evsel, "insn"), evsel); return TEST_OK; @@ -1733,7 +1737,7 @@ static int test__checkevent_config_raw(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong name setting", evsel__name_is(evsel, "rawpmu"), evsel); return TEST_OK; } @@ -1742,7 +1746,7 @@ static int test__checkevent_config_num(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong name setting", evsel__name_is(evsel, "numpmu"), evsel); return TEST_OK; } @@ -1752,7 +1756,7 @@ static int test__checkevent_config_cache(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong name setting", evsel__name_is(evsel, "cachepmu"), evsel); return test__checkevent_genhw(evlist); @@ -1777,7 +1781,7 @@ static int test__intel_pt(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong name setting", evsel__name_is(evsel, "intel_pt//u"), evsel); return TEST_OK; } @@ -1798,7 +1802,8 @@ static int test__ratio_to_prev(struct evlist *evlist) { struct evsel *evsel, *leader; - TEST_ASSERT_VAL("wrong number of entries", 2 * perf_pmus__num_core_pmus() == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong number of entries", + 2 * perf_pmus__num_core_pmus() == evlist__nr_entries(evlist)); evlist__for_each_entry(evlist, evsel) { if (evsel != evsel__leader(evsel) || @@ -1842,7 +1847,7 @@ static int test__checkevent_complex_name(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong complex name parsing", evsel__name_is(evsel, @@ -1855,7 +1860,7 @@ static int test__checkevent_raw_pmu(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist__nr_entries(evlist), evlist); TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type, evsel); TEST_ASSERT_EVSEL("wrong config", 0x1a == evsel->core.attr.config, evsel); return TEST_OK; @@ -1866,7 +1871,7 @@ static int test__sym_event_slash(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); TEST_ASSERT_EVSEL("unexpected event", evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), evsel); TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); @@ -1878,7 +1883,7 @@ static int test__sym_event_dc(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); TEST_ASSERT_EVSEL("unexpected event", evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), evsel); TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); @@ -1890,7 +1895,7 @@ static int test__term_equal_term(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); TEST_ASSERT_EVSEL("unexpected event", evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), evsel); TEST_ASSERT_EVSEL("wrong name setting", strcmp(evsel->name, "name") == 0, evsel); @@ -1902,7 +1907,7 @@ static int test__term_equal_legacy(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_EVLIST("wrong number of entries", - evlist->core.nr_entries == num_core_entries(evlist), + evlist__nr_entries(evlist) == num_core_entries(evlist), evlist); TEST_ASSERT_EVSEL("unexpected event", evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), evsel); TEST_ASSERT_EVSEL("wrong name setting", strcmp(evsel->name, "l1d") == 0, evsel); @@ -1958,7 +1963,7 @@ static int count_tracepoints(void) static int test__all_tracepoints(struct evlist *evlist) { TEST_ASSERT_VAL("wrong events count", - count_tracepoints() == evlist->core.nr_entries); + count_tracepoints() == evlist__nr_entries(evlist)); return test__checkevent_tracepoint_multi(evlist); } diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c index 3f0ec839c056..8f9211eaf341 100644 --- a/tools/perf/tests/parse-metric.c +++ b/tools/perf/tests/parse-metric.c @@ -53,7 +53,7 @@ static double compute_single(struct evlist *evlist, const char *name) struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - me = metricgroup__lookup(&evlist->metric_events, evsel, false); + me = metricgroup__lookup(evlist__metric_events(evlist), evsel, false); if (me != NULL) { list_for_each_entry (mexp, &me->head, nd) { if (strcmp(mexp->metric_name, name)) @@ -88,7 +88,7 @@ static int __compute_metric(const char *name, struct value *vals, return -ENOMEM; } - perf_evlist__set_maps(&evlist->core, cpus, NULL); + perf_evlist__set_maps(evlist__core(evlist), cpus, NULL); /* Parse the metric into metric_events list. */ pme_test = find_core_metrics_table("testarch", "testcpu"); diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index f95752b2ed1c..0cac6ae1a1fc 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -129,7 +129,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest evsel__set_sample_bit(evsel, TIME); evlist__config(evlist, &opts, NULL); - err = sched__get_first_possible_cpu(evlist->workload.pid, cpu_mask); + err = sched__get_first_possible_cpu(evlist__workload_pid(evlist), cpu_mask); if (err < 0) { pr_debug("sched__get_first_possible_cpu: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); @@ -142,7 +142,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest /* * So that we can check perf_sample.cpu on all the samples. */ - if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, cpu_mask) < 0) { + if (sched_setaffinity(evlist__workload_pid(evlist), cpu_mask_size, cpu_mask) < 0) { pr_debug("sched_setaffinity: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); evlist__cancel_workload(evlist); @@ -166,7 +166,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest * fds in the same CPU to be injected in the same mmap ring buffer * (using ioctl(PERF_EVENT_IOC_SET_OUTPUT)). */ - err = evlist__mmap(evlist, opts.mmap_pages); + err = evlist__do_mmap(evlist, opts.mmap_pages); if (err < 0) { pr_debug("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); @@ -188,11 +188,11 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest while (1) { int before = total_events; - for (i = 0; i < evlist->core.nr_mmaps; i++) { + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { union perf_event *event; struct mmap *md; - md = &evlist->mmap[i]; + md = &evlist__mmap(evlist)[i]; if (perf_mmap__read_init(&md->core) < 0) continue; @@ -231,15 +231,15 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest ++errs; } - if ((pid_t)sample.pid != evlist->workload.pid) { + if ((pid_t)sample.pid != evlist__workload_pid(evlist)) { pr_debug("%s with unexpected pid, expected %d, got %d\n", - name, evlist->workload.pid, sample.pid); + name, evlist__workload_pid(evlist), sample.pid); ++errs; } - if ((pid_t)sample.tid != evlist->workload.pid) { + if ((pid_t)sample.tid != evlist__workload_pid(evlist)) { pr_debug("%s with unexpected tid, expected %d, got %d\n", - name, evlist->workload.pid, sample.tid); + name, evlist__workload_pid(evlist), sample.tid); ++errs; } @@ -248,7 +248,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest type == PERF_RECORD_MMAP2 || type == PERF_RECORD_FORK || type == PERF_RECORD_EXIT) && - (pid_t)event->comm.pid != evlist->workload.pid) { + (pid_t)event->comm.pid != evlist__workload_pid(evlist)) { pr_debug("%s with unexpected pid/tid\n", name); ++errs; } @@ -352,9 +352,9 @@ found_exit: } out_put_evlist: CPU_FREE(cpu_mask); - evlist__put(evlist); out: perf_sample__exit(&sample); + evlist__put(evlist); if (err == -EACCES) return TEST_SKIP; if (err < 0 || errs != 0) diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c index d3538fa20af3..f8f71fdd32b1 100644 --- a/tools/perf/tests/perf-time-to-tsc.c +++ b/tools/perf/tests/perf-time-to-tsc.c @@ -99,7 +99,7 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su evlist = evlist__new(); CHECK_NOT_NULL__(evlist); - perf_evlist__set_maps(&evlist->core, cpus, threads); + perf_evlist__set_maps(evlist__core(evlist), cpus, threads); CHECK__(parse_event(evlist, "cpu-cycles:u")); @@ -121,9 +121,9 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su goto out_err; } - CHECK__(evlist__mmap(evlist, UINT_MAX)); + CHECK__(evlist__do_mmap(evlist, UINT_MAX)); - pc = evlist->mmap[0].core.base; + pc = evlist__mmap(evlist)[0].core.base; ret = perf_read_tsc_conversion(pc, &tc); if (ret) { if (ret == -EOPNOTSUPP) { @@ -145,8 +145,8 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su evlist__disable(evlist); - for (i = 0; i < evlist->core.nr_mmaps; i++) { - md = &evlist->mmap[i]; + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { + md = &evlist__mmap(evlist)[i]; if (perf_mmap__read_init(&md->core) < 0) continue; diff --git a/tools/perf/tests/pfm.c b/tools/perf/tests/pfm.c index 8d19b1bfecbc..f7bf55be5e6e 100644 --- a/tools/perf/tests/pfm.c +++ b/tools/perf/tests/pfm.c @@ -69,12 +69,12 @@ static int test__pfm_events(struct test_suite *test __maybe_unused, if (evlist == NULL) return -ENOMEM; - opt.value = evlist; + opt.value = &evlist; parse_libpfm_events_option(&opt, table[i].events, 0); TEST_ASSERT_EQUAL(table[i].events, - count_pfm_events(&evlist->core), + count_pfm_events(evlist__core(evlist)), table[i].nr_events); TEST_ASSERT_EQUAL(table[i].events, evlist__nr_groups(evlist), @@ -154,12 +154,12 @@ static int test__pfm_group(struct test_suite *test __maybe_unused, if (evlist == NULL) return -ENOMEM; - opt.value = evlist; + opt.value = &evlist; parse_libpfm_events_option(&opt, table[i].events, 0); TEST_ASSERT_EQUAL(table[i].events, - count_pfm_events(&evlist->core), + count_pfm_events(evlist__core(evlist)), table[i].nr_events); TEST_ASSERT_EQUAL(table[i].events, evlist__nr_groups(evlist), diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 4ea6d392085b..4c6fc1207b6d 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -869,7 +869,7 @@ static int test__parsing_callback(const struct pmu_metric *pm, return -ENOMEM; } - perf_evlist__set_maps(&evlist->core, cpus, NULL); + perf_evlist__set_maps(evlist__core(evlist), cpus, NULL); err = metricgroup__parse_groups_test(evlist, table, pm->metric_name); if (err) { @@ -895,7 +895,8 @@ static int test__parsing_callback(const struct pmu_metric *pm, k++; } evlist__for_each_entry(evlist, evsel) { - struct metric_event *me = metricgroup__lookup(&evlist->metric_events, evsel, false); + struct metric_event *me = metricgroup__lookup(evlist__metric_events(evlist), + evsel, false); if (me != NULL) { struct metric_expr *mexp; diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c index 55f0b73ca20e..20cab91ceaeb 100644 --- a/tools/perf/tests/sample-parsing.c +++ b/tools/perf/tests/sample-parsing.c @@ -205,15 +205,11 @@ static bool samples_same(struct perf_sample *s1, static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) { - struct evsel evsel = { - .needs_swap = false, - .core = { - . attr = { - .sample_type = sample_type, - .read_format = read_format, - }, - }, + struct perf_event_attr attr = { + .sample_type = sample_type, + .read_format = read_format, }; + struct evsel *evsel; union perf_event *event; union { struct ip_callchain callchain; @@ -287,16 +283,21 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) size_t i, sz, bufsz; int err, ret = -1; + evsel = evsel__new(&attr); + if (!evsel) { + pr_debug("evsel__new failed\n"); + return -1; + } perf_sample__init(&sample_out, /*all=*/false); perf_sample__init(&sample_out_endian, /*all=*/false); if (sample_type & PERF_SAMPLE_REGS_USER) - evsel.core.attr.sample_regs_user = sample_regs; + evsel->core.attr.sample_regs_user = sample_regs; if (sample_type & PERF_SAMPLE_REGS_INTR) - evsel.core.attr.sample_regs_intr = sample_regs; + evsel->core.attr.sample_regs_intr = sample_regs; if (sample_type & PERF_SAMPLE_BRANCH_STACK) - evsel.core.attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX; + evsel->core.attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX; for (i = 0; i < sizeof(regs); i++) *(i + (u8 *)regs) = i & 0xfe; @@ -311,12 +312,12 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) } sz = perf_event__sample_event_size(&sample, sample_type, read_format, - evsel.core.attr.branch_sample_type); + evsel->core.attr.branch_sample_type); bufsz = sz + 4096; /* Add a bit for overrun checking */ event = malloc(bufsz); if (!event) { pr_debug("malloc failed\n"); - return -1; + goto out_free; } memset(event, 0xff, bufsz); @@ -325,7 +326,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) event->header.size = sz; err = perf_event__synthesize_sample(event, sample_type, read_format, - evsel.core.attr.branch_sample_type, &sample); + evsel->core.attr.branch_sample_type, &sample); if (err) { pr_debug("%s failed for sample_type %#"PRIx64", error %d\n", "perf_event__synthesize_sample", sample_type, err); @@ -343,32 +344,33 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) goto out_free; } - evsel.sample_size = __evsel__sample_size(sample_type); + evsel->sample_size = __evsel__sample_size(sample_type); - err = evsel__parse_sample(&evsel, event, &sample_out); + err = evsel__parse_sample(evsel, event, &sample_out); if (err) { pr_debug("%s failed for sample_type %#"PRIx64", error %d\n", "evsel__parse_sample", sample_type, err); goto out_free; } - if (!samples_same(&sample, &sample_out, sample_type, read_format, evsel.needs_swap)) { + if (!samples_same(&sample, &sample_out, sample_type, read_format, evsel->needs_swap)) { pr_debug("parsing failed for sample_type %#"PRIx64"\n", sample_type); goto out_free; } if (sample_type == PERF_SAMPLE_BRANCH_STACK) { - evsel.needs_swap = true; - evsel.sample_size = __evsel__sample_size(sample_type); - err = evsel__parse_sample(&evsel, event, &sample_out_endian); + evsel->needs_swap = true; + evsel->sample_size = __evsel__sample_size(sample_type); + err = evsel__parse_sample(evsel, event, &sample_out_endian); if (err) { pr_debug("%s failed for sample_type %#"PRIx64", error %d\n", "evsel__parse_sample", sample_type, err); goto out_free; } - if (!samples_same(&sample, &sample_out_endian, sample_type, read_format, evsel.needs_swap)) { + if (!samples_same(&sample, &sample_out_endian, sample_type, + read_format, evsel->needs_swap)) { pr_debug("parsing failed for sample_type %#"PRIx64"\n", sample_type); goto out_free; @@ -380,6 +382,7 @@ out_free: free(event); perf_sample__exit(&sample_out_endian); perf_sample__exit(&sample_out); + evsel__put(evsel); if (ret && read_format) pr_debug("read_format %#"PRIx64"\n", read_format); return ret; diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c index bb6b62cf51d1..d18185881635 100644 --- a/tools/perf/tests/sw-clock.c +++ b/tools/perf/tests/sw-clock.c @@ -71,7 +71,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) goto out_put_evlist; } - perf_evlist__set_maps(&evlist->core, cpus, threads); + perf_evlist__set_maps(evlist__core(evlist), cpus, threads); if (evlist__open(evlist)) { const char *knob = "/proc/sys/kernel/perf_event_max_sample_rate"; @@ -83,7 +83,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) goto out_put_evlist; } - err = evlist__mmap(evlist, 128); + err = evlist__do_mmap(evlist, 128); if (err < 0) { pr_debug("failed to mmap event: %d (%s)\n", errno, str_error_r(errno, sbuf, sizeof(sbuf))); @@ -98,7 +98,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) evlist__disable(evlist); - md = &evlist->mmap[0]; + md = &evlist__mmap(evlist)[0]; if (perf_mmap__read_init(&md->core) < 0) goto out_init; diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c index abd08d60179c..73568c782d72 100644 --- a/tools/perf/tests/switch-tracking.c +++ b/tools/perf/tests/switch-tracking.c @@ -237,6 +237,7 @@ static int add_event(struct evlist *evlist, struct list_head *events, if (evlist__parse_sample(evlist, event, &sample)) { pr_debug("evlist__parse_sample failed\n"); + perf_sample__exit(&sample); return -1; } @@ -282,8 +283,8 @@ static int process_events(struct evlist *evlist, struct mmap *md; int i, ret; - for (i = 0; i < evlist->core.nr_mmaps; i++) { - md = &evlist->mmap[i]; + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { + md = &evlist__mmap(evlist)[i]; if (perf_mmap__read_init(&md->core) < 0) continue; @@ -374,7 +375,7 @@ static int test__switch_tracking(struct test_suite *test __maybe_unused, int sub goto out_err; } - perf_evlist__set_maps(&evlist->core, cpus, threads); + perf_evlist__set_maps(evlist__core(evlist), cpus, threads); /* First event */ err = parse_event(evlist, "cpu-clock:u"); @@ -471,7 +472,7 @@ static int test__switch_tracking(struct test_suite *test __maybe_unused, int sub goto out; } - err = evlist__mmap(evlist, UINT_MAX); + err = evlist__do_mmap(evlist, UINT_MAX); if (err) { pr_debug("evlist__mmap failed!\n"); goto out_err; diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index a46650b10689..95393edbfe36 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c @@ -77,7 +77,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _ goto out_put_evlist; } - perf_evlist__set_maps(&evlist->core, cpus, threads); + perf_evlist__set_maps(evlist__core(evlist), cpus, threads); err = evlist__prepare_workload(evlist, &target, argv, false, workload_exec_failed_signal); if (err < 0) { @@ -104,7 +104,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _ goto out_put_evlist; } - if (evlist__mmap(evlist, 128) < 0) { + if (evlist__do_mmap(evlist, 128) < 0) { pr_debug("failed to mmap events: %d (%s)\n", errno, str_error_r(errno, sbuf, sizeof(sbuf))); err = -1; @@ -114,7 +114,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _ evlist__start_workload(evlist); retry: - md = &evlist->mmap[0]; + md = &evlist__mmap(evlist)[0]; if (perf_mmap__read_init(&md->core) < 0) goto out_init; diff --git a/tools/perf/tests/time-utils-test.c b/tools/perf/tests/time-utils-test.c index 38df10373c1e..90a9a4b4f178 100644 --- a/tools/perf/tests/time-utils-test.c +++ b/tools/perf/tests/time-utils-test.c @@ -69,16 +69,19 @@ struct test_data { static bool test__perf_time__parse_for_ranges(struct test_data *d) { - struct evlist evlist = { - .first_sample_time = d->first, - .last_sample_time = d->last, - }; - struct perf_session session = { .evlist = &evlist }; + struct evlist *evlist = evlist__new(); + struct perf_session session = { .evlist = evlist }; struct perf_time_interval *ptime = NULL; int range_size, range_num; bool pass = false; int i, err; + if (!evlist) { + pr_debug("Missing evlist\n"); + return false; + } + evlist__set_first_sample_time(evlist, d->first); + evlist__set_last_sample_time(evlist, d->last); pr_debug("\nperf_time__parse_for_ranges(\"%s\")\n", d->str); if (strchr(d->str, '%')) @@ -127,6 +130,7 @@ static bool test__perf_time__parse_for_ranges(struct test_data *d) pass = true; out: + evlist__put(evlist); free(ptime); return pass; } diff --git a/tools/perf/tests/tool_pmu.c b/tools/perf/tests/tool_pmu.c index e78ff9dcea97..c6c5ebf0e935 100644 --- a/tools/perf/tests/tool_pmu.c +++ b/tools/perf/tests/tool_pmu.c @@ -40,9 +40,10 @@ static int do_test(enum tool_pmu_event ev, bool with_pmu) } ret = TEST_OK; - if (with_pmu ? (evlist->core.nr_entries != 1) : (evlist->core.nr_entries < 1)) { + if (with_pmu ? (evlist__nr_entries(evlist) != 1) + : (evlist__nr_entries(evlist) < 1)) { pr_debug("FAILED %s:%d Unexpected number of events for '%s' of %d\n", - __FILE__, __LINE__, str, evlist->core.nr_entries); + __FILE__, __LINE__, str, evlist__nr_entries(evlist)); ret = TEST_FAIL; goto out; } diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c index 15741abec8c6..77cb8318c0b1 100644 --- a/tools/perf/tests/topology.c +++ b/tools/perf/tests/topology.c @@ -46,7 +46,7 @@ static int session_write_header(char *path) session->evlist = evlist__new_default(&target, /*sample_callchains=*/false); TEST_ASSERT_VAL("can't get evlist", session->evlist); - session->evlist->session = session; + evlist__set_session(session->evlist, session); perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY); perf_header__set_feat(&session->header, HEADER_NRCPUS); diff --git a/tools/perf/tests/uncore-event-sorting.c b/tools/perf/tests/uncore-event-sorting.c index 2e741aef4a59..7756777c54c2 100644 --- a/tools/perf/tests/uncore-event-sorting.c +++ b/tools/perf/tests/uncore-event-sorting.c @@ -147,8 +147,8 @@ static int test__uncore_event_sorting(struct test_suite *test __maybe_unused, goto out_err; } - CHECK_COND(evlist->core.nr_entries >= 4, "Number of events is >= 4"); - CHECK_EQUAL(evlist->core.nr_entries % 2, 0, "Number of events is a multiple of 2"); + CHECK_COND(evlist__nr_entries(evlist) >= 4, "Number of events is >= 4"); + CHECK_EQUAL(evlist__nr_entries(evlist) % 2, 0, "Number of events is a multiple of 2"); evlist__for_each_entry(evlist, evsel) { struct evsel *next; diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 97ae4c86bebb..d25761a8d25e 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -597,7 +597,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, notes = symbol__annotation(dl->ops.target.sym); annotation__lock(notes); - if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) { + if (!symbol__hists(dl->ops.target.sym, evlist__nr_entries(evsel->evlist))) { annotation__unlock(notes); ui__warning("Not enough memory for annotating '%s' symbol!\n", dl->ops.target.sym->name); diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index cfa6386e6e1d..da7cc195b9f4 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -688,10 +688,10 @@ static int hist_browser__handle_hotkey(struct hist_browser *browser, bool warn_l ui_browser__update_nr_entries(&browser->b, nr_entries); if (warn_lost_event && - (evsel->evlist->stats.nr_lost_warned != - evsel->evlist->stats.nr_events[PERF_RECORD_LOST])) { - evsel->evlist->stats.nr_lost_warned = - evsel->evlist->stats.nr_events[PERF_RECORD_LOST]; + (evlist__stats(evsel->evlist)->nr_lost_warned != + evlist__stats(evsel->evlist)->nr_events[PERF_RECORD_LOST])) { + evlist__stats(evsel->evlist)->nr_lost_warned = + evlist__stats(evsel->evlist)->nr_events[PERF_RECORD_LOST]; ui_browser__warn_lost_events(&browser->b); } @@ -3321,7 +3321,7 @@ do_hotkey: // key came straight from options ui__popup_menu() * No need to refresh, resort/decay histogram * entries if we are not collecting samples: */ - if (top->evlist->enabled) { + if (evlist__enabled(top->evlist)) { helpline = "Press 'f' to disable the events or 'h' to see other hotkeys"; hbt->refresh = delay_secs; } else { @@ -3493,7 +3493,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser, unit, unit == ' ' ? "" : " ", ev_name); ui_browser__printf(browser, "%s", bf); - nr_events = evsel->evlist->stats.nr_events[PERF_RECORD_LOST]; + nr_events = evlist__stats(evsel->evlist)->nr_events[PERF_RECORD_LOST]; if (nr_events != 0) { menu->lost_events = true; if (!current_entry) @@ -3559,13 +3559,13 @@ browse_hists: ui_browser__show_title(&menu->b, title); switch (key) { case K_TAB: - if (pos->core.node.next == &evlist->core.entries) + if (pos->core.node.next == &evlist__core(evlist)->entries) pos = evlist__first(evlist); else pos = evsel__next(pos); goto browse_hists; case K_UNTAB: - if (pos->core.node.prev == &evlist->core.entries) + if (pos->core.node.prev == &evlist__core(evlist)->entries) pos = evlist__last(evlist); else pos = evsel__prev(pos); @@ -3618,7 +3618,7 @@ static int __evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, con struct evsel *pos; struct evsel_menu menu = { .b = { - .entries = &evlist->core.entries, + .entries = &evlist__core(evlist)->entries, .refresh = ui_browser__list_head_refresh, .seek = ui_browser__list_head_seek, .write = perf_evsel_menu__write, @@ -3646,7 +3646,7 @@ static int __evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, con static bool evlist__single_entry(struct evlist *evlist) { - int nr_entries = evlist->core.nr_entries; + int nr_entries = evlist__nr_entries(evlist); if (nr_entries == 1) return true; @@ -3664,7 +3664,7 @@ static bool evlist__single_entry(struct evlist *evlist) int evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env, bool warn_lost_event) { - int nr_entries = evlist->core.nr_entries; + int nr_entries = evlist__nr_entries(evlist); if (evlist__single_entry(evlist)) { single_entry: { diff --git a/tools/perf/util/amd-sample-raw.c b/tools/perf/util/amd-sample-raw.c index 394c061fbeb3..cda3836329c3 100644 --- a/tools/perf/util/amd-sample-raw.c +++ b/tools/perf/util/amd-sample-raw.c @@ -421,7 +421,7 @@ static void parse_cpuid(struct perf_env *env) */ bool evlist__has_amd_ibs(struct evlist *evlist) { - struct perf_env *env = perf_session__env(evlist->session); + struct perf_env *env = perf_session__env(evlist__session(evlist)); int ret, nr_pmu_mappings = perf_env__nr_pmu_mappings(env); const char *pmu_mapping = perf_env__pmu_mappings(env); char name[sizeof("ibs_fetch")]; diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 63e3c54fab42..4e4c58764082 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -1829,7 +1829,7 @@ int annotated_data_type__update_samples(struct annotated_data_type *adt, return 0; if (adt->histograms == NULL) { - int nr = evsel->evlist->core.nr_entries; + int nr = evlist__nr_entries(evsel->evlist); if (alloc_data_type_histograms(adt, nr) < 0) return -1; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 02505222d8c2..53b2a224b21d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -328,7 +328,7 @@ static int symbol__inc_addr_samples(struct map_symbol *ms, if (sym == NULL) return 0; - src = symbol__hists(sym, sample->evsel->evlist->core.nr_entries); + src = symbol__hists(sym, evlist__nr_entries(sample->evsel->evlist)); return src ? __symbol__inc_addr_samples(ms, src, addr, sample) : 0; } @@ -339,7 +339,7 @@ static int symbol__account_br_cntr(struct annotated_branch *branch, { unsigned int br_cntr_nr = evsel__leader(evsel)->br_cntr_nr; unsigned int base = evsel__leader(evsel)->br_cntr_idx; - unsigned int off = offset * evsel->evlist->nr_br_cntr; + unsigned int off = offset * evlist__nr_br_cntr(evsel->evlist); u64 *branch_br_cntr = branch->br_cntr; unsigned int i, mask, width; @@ -369,7 +369,7 @@ static int symbol__account_cycles(u64 addr, u64 start, struct symbol *sym, if (sym == NULL) return 0; - branch = symbol__find_branch_hist(sym, evsel->evlist->nr_br_cntr); + branch = symbol__find_branch_hist(sym, evlist__nr_br_cntr(evsel->evlist)); if (!branch) return -ENOMEM; if (addr < sym->start || addr >= sym->end) @@ -511,7 +511,7 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 static int annotation__compute_ipc(struct annotation *notes, size_t size, struct evsel *evsel) { - unsigned int br_cntr_nr = evsel->evlist->nr_br_cntr; + unsigned int br_cntr_nr = evlist__nr_br_cntr(evsel->evlist); int err = 0; s64 offset; @@ -1813,7 +1813,7 @@ int annotation_br_cntr_abbr_list(char **str, struct evsel *evsel, bool header) struct evsel *pos; struct strbuf sb; - if (evsel->evlist->nr_br_cntr <= 0) + if (evlist__nr_br_cntr(evsel->evlist) <= 0) return -ENOTSUP; strbuf_init(&sb, /*hint=*/ 0); diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 4cd2caf54015..0b851f32e98c 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -191,7 +191,7 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, struct evlist *evlist, struct evsel *evsel, int idx) { - bool per_cpu = !perf_cpu_map__has_any_cpu(evlist->core.user_requested_cpus); + bool per_cpu = !perf_cpu_map__has_any_cpu(evlist__core(evlist)->user_requested_cpus); mp->mmap_needed = evsel->needs_auxtrace_mmap; @@ -201,11 +201,11 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, mp->idx = idx; if (per_cpu) { - mp->cpu = perf_cpu_map__cpu(evlist->core.all_cpus, idx); - mp->tid = perf_thread_map__pid(evlist->core.threads, 0); + mp->cpu = perf_cpu_map__cpu(evlist__core(evlist)->all_cpus, idx); + mp->tid = perf_thread_map__pid(evlist__core(evlist)->threads, 0); } else { mp->cpu.cpu = -1; - mp->tid = perf_thread_map__pid(evlist->core.threads, idx); + mp->tid = perf_thread_map__pid(evlist__core(evlist)->threads, idx); } } @@ -668,10 +668,10 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, static int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx) { - bool per_cpu_mmaps = !perf_cpu_map__has_any_cpu(evlist->core.user_requested_cpus); + bool per_cpu_mmaps = !perf_cpu_map__has_any_cpu(evlist__core(evlist)->user_requested_cpus); if (per_cpu_mmaps) { - struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->core.all_cpus, idx); + struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist__core(evlist)->all_cpus, idx); int cpu_map_idx = perf_cpu_map__idx(evsel->core.cpus, evlist_cpu); if (cpu_map_idx == -1) @@ -1838,7 +1838,7 @@ void perf_session__auxtrace_error_inc(struct perf_session *session, struct perf_record_auxtrace_error *e = &event->auxtrace_error; if (e->type < PERF_AUXTRACE_ERROR_MAX) - session->evlist->stats.nr_auxtrace_errors[e->type] += 1; + evlist__stats(session->evlist)->nr_auxtrace_errors[e->type] += 1; } void events_stats__auxtrace_error_warn(const struct events_stats *stats) diff --git a/tools/perf/util/block-info.c b/tools/perf/util/block-info.c index 8d3a9a661f26..1135e54f4c7f 100644 --- a/tools/perf/util/block-info.c +++ b/tools/perf/util/block-info.c @@ -472,7 +472,7 @@ struct block_report *block_info__create_report(struct evlist *evlist, int *nr_reps) { struct block_report *block_reports; - int nr_hists = evlist->core.nr_entries, i = 0; + int nr_hists = evlist__nr_entries(evlist), i = 0; struct evsel *pos; block_reports = calloc(nr_hists, sizeof(struct block_report)); @@ -483,7 +483,7 @@ struct block_report *block_info__create_report(struct evlist *evlist, struct hists *hists = evsel__hists(pos); process_block_report(hists, &block_reports[i], total_cycles, - block_hpps, nr_hpps, evlist->nr_br_cntr); + block_hpps, nr_hpps, evlist__nr_br_cntr(evlist)); i++; } diff --git a/tools/perf/util/bpf_counter.c b/tools/perf/util/bpf_counter.c index 34b6b0da18b7..9362e45e17ce 100644 --- a/tools/perf/util/bpf_counter.c +++ b/tools/perf/util/bpf_counter.c @@ -443,7 +443,7 @@ static int bperf_check_target(struct evsel *evsel, } else if (target->tid) { *filter_type = BPERF_FILTER_PID; *filter_entry_cnt = perf_thread_map__nr(evsel->core.threads); - } else if (target->pid || evsel->evlist->workload.pid != -1) { + } else if (target->pid || evlist__workload_pid(evsel->evlist) != -1) { *filter_type = BPERF_FILTER_TGID; *filter_entry_cnt = perf_thread_map__nr(evsel->core.threads); } else { diff --git a/tools/perf/util/bpf_counter_cgroup.c b/tools/perf/util/bpf_counter_cgroup.c index 6842c9f6d71e..4e5f4b9dd442 100644 --- a/tools/perf/util/bpf_counter_cgroup.c +++ b/tools/perf/util/bpf_counter_cgroup.c @@ -104,7 +104,7 @@ static int bperf_load_program(struct evlist *evlist) set_max_rlimit(); - if (nr_cgroups == 0 || evlist->core.nr_entries % nr_cgroups != 0) { + if (nr_cgroups == 0 || evlist__nr_entries(evlist) % nr_cgroups != 0) { pr_err("Invalid cgroup or event count\n"); return -EINVAL; } @@ -116,7 +116,7 @@ static int bperf_load_program(struct evlist *evlist) pr_err("Failed to open cgroup skeleton\n"); return -1; } - setup_rodata(skel, evlist->core.nr_entries); + setup_rodata(skel, evlist__nr_entries(evlist)); err = bperf_cgroup_bpf__load(skel); if (err) { @@ -127,12 +127,12 @@ static int bperf_load_program(struct evlist *evlist) err = -1; cgrp_switch = evsel__new(&cgrp_switch_attr); - if (evsel__open_per_cpu(cgrp_switch, evlist->core.all_cpus, -1) < 0) { + if (evsel__open_per_cpu(cgrp_switch, evlist__core(evlist)->all_cpus, -1) < 0) { pr_err("Failed to open cgroup switches event\n"); goto out; } - perf_cpu_map__for_each_cpu(cpu, i, evlist->core.all_cpus) { + perf_cpu_map__for_each_cpu(cpu, i, evlist__core(evlist)->all_cpus) { link = bpf_program__attach_perf_event(skel->progs.on_cgrp_switch, FD(cgrp_switch, i)); if (IS_ERR(link)) { @@ -197,7 +197,7 @@ static int bperf_load_program(struct evlist *evlist) */ { struct evsel *leader; - int num_events = evlist->core.nr_entries / nr_cgroups; + int num_events = evlist__nr_entries(evlist) / nr_cgroups; evlist__for_each_entry(evlist, evsel) { leader = evlist__find_evsel(evlist, evsel->core.idx % num_events); @@ -258,7 +258,7 @@ static int bperf_cgrp__sync_counters(struct evlist *evlist) unsigned int idx; int prog_fd = bpf_program__fd(skel->progs.trigger_read); - perf_cpu_map__for_each_cpu(cpu, idx, evlist->core.all_cpus) + perf_cpu_map__for_each_cpu(cpu, idx, evlist__core(evlist)->all_cpus) bperf_trigger_reading(prog_fd, cpu.cpu); return 0; diff --git a/tools/perf/util/bpf_ftrace.c b/tools/perf/util/bpf_ftrace.c index c456d24efa30..abeafd406e8e 100644 --- a/tools/perf/util/bpf_ftrace.c +++ b/tools/perf/util/bpf_ftrace.c @@ -59,13 +59,13 @@ int perf_ftrace__latency_prepare_bpf(struct perf_ftrace *ftrace) /* don't need to set cpu filter for system-wide mode */ if (ftrace->target.cpu_list) { - ncpus = perf_cpu_map__nr(ftrace->evlist->core.user_requested_cpus); + ncpus = perf_cpu_map__nr(evlist__core(ftrace->evlist)->user_requested_cpus); bpf_map__set_max_entries(skel->maps.cpu_filter, ncpus); skel->rodata->has_cpu = 1; } if (target__has_task(&ftrace->target) || target__none(&ftrace->target)) { - ntasks = perf_thread_map__nr(ftrace->evlist->core.threads); + ntasks = perf_thread_map__nr(evlist__core(ftrace->evlist)->threads); bpf_map__set_max_entries(skel->maps.task_filter, ntasks); skel->rodata->has_task = 1; } @@ -87,7 +87,8 @@ int perf_ftrace__latency_prepare_bpf(struct perf_ftrace *ftrace) fd = bpf_map__fd(skel->maps.cpu_filter); for (i = 0; i < ncpus; i++) { - cpu = perf_cpu_map__cpu(ftrace->evlist->core.user_requested_cpus, i).cpu; + cpu = perf_cpu_map__cpu( + evlist__core(ftrace->evlist)->user_requested_cpus, i).cpu; bpf_map_update_elem(fd, &cpu, &val, BPF_ANY); } } @@ -99,7 +100,7 @@ int perf_ftrace__latency_prepare_bpf(struct perf_ftrace *ftrace) fd = bpf_map__fd(skel->maps.task_filter); for (i = 0; i < ntasks; i++) { - pid = perf_thread_map__pid(ftrace->evlist->core.threads, i); + pid = perf_thread_map__pid(evlist__core(ftrace->evlist)->threads, i); bpf_map_update_elem(fd, &pid, &val, BPF_ANY); } } diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c index b1cfa63a488f..c20bd075664e 100644 --- a/tools/perf/util/bpf_lock_contention.c +++ b/tools/perf/util/bpf_lock_contention.c @@ -223,11 +223,11 @@ int lock_contention_prepare(struct lock_contention *con) if (target__has_cpu(target)) { skel->rodata->has_cpu = 1; - ncpus = perf_cpu_map__nr(evlist->core.user_requested_cpus); + ncpus = perf_cpu_map__nr(evlist__core(evlist)->user_requested_cpus); } if (target__has_task(target)) { skel->rodata->has_task = 1; - ntasks = perf_thread_map__nr(evlist->core.threads); + ntasks = perf_thread_map__nr(evlist__core(evlist)->threads); } if (con->filters->nr_types) { skel->rodata->has_type = 1; @@ -334,7 +334,7 @@ int lock_contention_prepare(struct lock_contention *con) fd = bpf_map__fd(skel->maps.cpu_filter); for (i = 0; i < ncpus; i++) { - cpu = perf_cpu_map__cpu(evlist->core.user_requested_cpus, i).cpu; + cpu = perf_cpu_map__cpu(evlist__core(evlist)->user_requested_cpus, i).cpu; bpf_map_update_elem(fd, &cpu, &val, BPF_ANY); } } @@ -346,13 +346,13 @@ int lock_contention_prepare(struct lock_contention *con) fd = bpf_map__fd(skel->maps.task_filter); for (i = 0; i < ntasks; i++) { - pid = perf_thread_map__pid(evlist->core.threads, i); + pid = perf_thread_map__pid(evlist__core(evlist)->threads, i); bpf_map_update_elem(fd, &pid, &val, BPF_ANY); } } - if (target__none(target) && evlist->workload.pid > 0) { - u32 pid = evlist->workload.pid; + if (target__none(target) && evlist__workload_pid(evlist) > 0) { + u32 pid = evlist__workload_pid(evlist); u8 val = 1; fd = bpf_map__fd(skel->maps.task_filter); diff --git a/tools/perf/util/bpf_off_cpu.c b/tools/perf/util/bpf_off_cpu.c index 48cb930cdd2e..c4639f6a5776 100644 --- a/tools/perf/util/bpf_off_cpu.c +++ b/tools/perf/util/bpf_off_cpu.c @@ -73,13 +73,13 @@ static void off_cpu_start(void *arg) /* update task filter for the given workload */ if (skel->rodata->has_task && skel->rodata->uses_tgid && - perf_thread_map__pid(evlist->core.threads, 0) != -1) { + perf_thread_map__pid(evlist__core(evlist)->threads, 0) != -1) { int fd; u32 pid; u8 val = 1; fd = bpf_map__fd(skel->maps.task_filter); - pid = perf_thread_map__pid(evlist->core.threads, 0); + pid = perf_thread_map__pid(evlist__core(evlist)->threads, 0); bpf_map_update_elem(fd, &pid, &val, BPF_ANY); } @@ -168,7 +168,7 @@ int off_cpu_prepare(struct evlist *evlist, struct target *target, /* don't need to set cpu filter for system-wide mode */ if (target->cpu_list) { - ncpus = perf_cpu_map__nr(evlist->core.user_requested_cpus); + ncpus = perf_cpu_map__nr(evlist__core(evlist)->user_requested_cpus); bpf_map__set_max_entries(skel->maps.cpu_filter, ncpus); skel->rodata->has_cpu = 1; } @@ -199,7 +199,7 @@ int off_cpu_prepare(struct evlist *evlist, struct target *target, skel->rodata->has_task = 1; skel->rodata->uses_tgid = 1; } else if (target__has_task(target)) { - ntasks = perf_thread_map__nr(evlist->core.threads); + ntasks = perf_thread_map__nr(evlist__core(evlist)->threads); bpf_map__set_max_entries(skel->maps.task_filter, ntasks); skel->rodata->has_task = 1; } else if (target__none(target)) { @@ -209,7 +209,7 @@ int off_cpu_prepare(struct evlist *evlist, struct target *target, } if (evlist__first(evlist)->cgrp) { - ncgrps = evlist->core.nr_entries - 1; /* excluding a dummy */ + ncgrps = evlist__nr_entries(evlist) - 1; /* excluding a dummy */ bpf_map__set_max_entries(skel->maps.cgroup_filter, ncgrps); if (!cgroup_is_v2("perf_event")) @@ -240,7 +240,7 @@ int off_cpu_prepare(struct evlist *evlist, struct target *target, fd = bpf_map__fd(skel->maps.cpu_filter); for (i = 0; i < ncpus; i++) { - cpu = perf_cpu_map__cpu(evlist->core.user_requested_cpus, i).cpu; + cpu = perf_cpu_map__cpu(evlist__core(evlist)->user_requested_cpus, i).cpu; bpf_map_update_elem(fd, &cpu, &val, BPF_ANY); } } @@ -269,7 +269,7 @@ int off_cpu_prepare(struct evlist *evlist, struct target *target, fd = bpf_map__fd(skel->maps.task_filter); for (i = 0; i < ntasks; i++) { - pid = perf_thread_map__pid(evlist->core.threads, i); + pid = perf_thread_map__pid(evlist__core(evlist)->threads, i); bpf_map_update_elem(fd, &pid, &val, BPF_ANY); } } diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index 914744724467..c7be16a7915e 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c @@ -367,7 +367,7 @@ int parse_cgroups(const struct option *opt, const char *str, char *s; int ret, i; - if (list_empty(&evlist->core.entries)) { + if (list_empty(&evlist__core(evlist)->entries)) { fprintf(stderr, "must define events before cgroups\n"); return -1; } @@ -423,7 +423,7 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro int ret = -1; int prefix_len; - if (evlist->core.nr_entries == 0) { + if (evlist__nr_entries(evlist) == 0) { fprintf(stderr, "must define events before cgroups\n"); return -EINVAL; } @@ -436,11 +436,11 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro } /* save original events and init evlist */ - evlist__splice_list_tail(orig_list, &evlist->core.entries); - evlist->core.nr_entries = 0; + evlist__splice_list_tail(orig_list, &evlist__core(evlist)->entries); + evlist__core(evlist)->nr_entries = 0; - orig_metric_events = evlist->metric_events; - metricgroup__rblist_init(&evlist->metric_events); + orig_metric_events = *evlist__metric_events(evlist); + metricgroup__rblist_init(evlist__metric_events(evlist)); if (has_pattern_string(str)) prefix_len = match_cgroups(str); @@ -503,15 +503,15 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro nr_cgroups++; if (metricgroup__copy_metric_events(tmp_list, cgrp, - &evlist->metric_events, + evlist__metric_events(evlist), &orig_metric_events) < 0) goto out_err; - evlist__splice_list_tail(evlist, &tmp_list->core.entries); - tmp_list->core.nr_entries = 0; + evlist__splice_list_tail(evlist, &evlist__core(tmp_list)->entries); + evlist__core(tmp_list)->nr_entries = 0; } - if (list_empty(&evlist->core.entries)) { + if (list_empty(&evlist__core(evlist)->entries)) { fprintf(stderr, "no cgroup matched: %s\n", str); goto out_err; } diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 5d0664ff73b7..2284cda78abe 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -1691,8 +1691,9 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq, { int ret = 0; struct cs_etm_auxtrace *etm = etmq->etm; - struct perf_sample sample = {.ip = 0,}; + struct perf_sample sample; union perf_event *event = tidq->event_buf; + struct dummy_branch_stack { u64 nr; u64 hw_idx; @@ -1700,6 +1701,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq, } dummy_bs; u64 ip; + perf_sample__init(&sample, /*all=*/true); ip = cs_etm__last_executed_instr(tidq->prev_packet); event->sample.header.type = PERF_RECORD_SAMPLE; @@ -1752,6 +1754,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq, "CS ETM Trace: failed to deliver instruction event, error %d\n", ret); + perf_sample__exit(&sample); return ret; } diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 1721a2470fb6..eb7c0d7be064 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -31,6 +31,7 @@ #include #include // page_size +#include #include #include #include @@ -75,30 +76,31 @@ int sigqueue(pid_t pid, int sig, const union sigval value); #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) #define SID(e, x, y) xyarray__entry(e->core.sample_id, x, y) -static void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus, - struct perf_thread_map *threads) -{ - perf_evlist__init(&evlist->core); - perf_evlist__set_maps(&evlist->core, cpus, threads); - evlist->workload.pid = -1; - evlist->bkw_mmap_state = BKW_MMAP_NOTREADY; - evlist->ctl_fd.fd = -1; - evlist->ctl_fd.ack = -1; - evlist->ctl_fd.pos = -1; - evlist->nr_br_cntr = -1; - metricgroup__rblist_init(&evlist->metric_events); - INIT_LIST_HEAD(&evlist->deferred_samples); - refcount_set(&evlist->refcnt, 1); -} +static void event_enable_timer__exit(struct event_enable_timer **ep); struct evlist *evlist__new(void) { - struct evlist *evlist = zalloc(sizeof(*evlist)); - - if (evlist != NULL) - evlist__init(evlist, NULL, NULL); - - return evlist; + struct evlist *result; + RC_STRUCT(evlist) *evlist; + + evlist = zalloc(sizeof(*evlist)); + if (ADD_RC_CHK(result, evlist)) { + perf_evlist__init(evlist__core(result)); + perf_evlist__set_maps(evlist__core(result), /*cpus=*/NULL, /*threads=*/NULL); + evlist__set_workload_pid(result, -1); + evlist__set_bkw_mmap_state(result, BKW_MMAP_NOTREADY); + evlist__set_ctl_fd_fd(result, -1); + evlist__set_ctl_fd_ack(result, -1); + evlist__set_ctl_fd_pos(result, -1); + evlist__set_nr_br_cntr(result, -1); + metricgroup__rblist_init(evlist__metric_events(result)); + INIT_LIST_HEAD(&evlist->deferred_samples); + refcount_set(evlist__refcnt(result), 1); + } else { + free(evlist); + result = NULL; + } + return result; } struct evlist *evlist__new_default(const struct target *target, bool sample_callchains) @@ -106,7 +108,6 @@ struct evlist *evlist__new_default(const struct target *target, bool sample_call struct evlist *evlist = evlist__new(); bool can_profile_kernel; struct perf_pmu *pmu = NULL; - struct evsel *evsel; char buf[256]; int err; @@ -133,7 +134,9 @@ struct evlist *evlist__new_default(const struct target *target, bool sample_call } /* If there is only 1 event a sample identifier isn't necessary. */ - if (evlist->core.nr_entries > 1) { + if (evlist__nr_entries(evlist) > 1) { + struct evsel *evsel; + evlist__for_each_entry(evlist, evsel) evsel__set_sample_id(evsel, /*can_sample_identifier=*/false); } @@ -158,8 +161,12 @@ struct evlist *evlist__new_dummy(void) struct evlist *evlist__get(struct evlist *evlist) { - refcount_inc(&evlist->refcnt); - return evlist; + struct evlist *result; + + if (RC_CHK_GET(result, evlist)) + refcount_inc(evlist__refcnt(evlist)); + + return result; } /** @@ -173,8 +180,8 @@ void evlist__set_id_pos(struct evlist *evlist) { struct evsel *first = evlist__first(evlist); - evlist->id_pos = first->id_pos; - evlist->is_pos = first->is_pos; + RC_CHK_ACCESS(evlist)->id_pos = first->id_pos; + RC_CHK_ACCESS(evlist)->is_pos = first->is_pos; } static void evlist__update_id_pos(struct evlist *evlist) @@ -193,52 +200,85 @@ static void evlist__purge(struct evlist *evlist) evlist__for_each_entry_safe(evlist, n, pos) { list_del_init(&pos->core.node); + if (pos->evlist) { + if (!RC_CHK_EQUAL(pos->evlist, evlist)) { + evlist__put(pos->evlist); + } else { + refcount_dec_and_test(evlist__refcnt(pos->evlist)); + RC_CHK_PUT(pos->evlist); + } + } pos->evlist = NULL; evsel__put(pos); } - evlist->core.nr_entries = 0; + evlist__core(evlist)->nr_entries = 0; } static void evlist__exit(struct evlist *evlist) { - metricgroup__rblist_exit(&evlist->metric_events); - event_enable_timer__exit(&evlist->eet); - zfree(&evlist->mmap); - zfree(&evlist->overwrite_mmap); - perf_evlist__exit(&evlist->core); + metricgroup__rblist_exit(evlist__metric_events(evlist)); + event_enable_timer__exit(&RC_CHK_ACCESS(evlist)->eet); + free(evlist__mmap(evlist)); + free(evlist__overwrite_mmap(evlist)); + perf_evlist__exit(evlist__core(evlist)); } void evlist__put(struct evlist *evlist) { + struct evsel *evsel; + unsigned int count, ref_cnt; + if (evlist == NULL) return; - if (!refcount_dec_and_test(&evlist->refcnt)) - return; + if (refcount_dec_and_test(evlist__refcnt(evlist))) + goto out_delete; + +retry: + count = refcount_read(evlist__refcnt(evlist)); + ref_cnt = count; + evlist__for_each_entry(evlist, evsel) { + if (RC_CHK_EQUAL(evsel->evlist, evlist) && count && + refcount_read(&evsel->refcnt) == 1) + count--; + } + if (refcount_read(evlist__refcnt(evlist)) != ref_cnt) + goto retry; + if (count != 0) { + /* + * Not the last reference except for back references from + * evsels. + */ + RC_CHK_PUT(evlist); + return; + } +out_delete: evlist__free_stats(evlist); - evlist__munmap(evlist); + evlist__do_munmap(evlist); evlist__close(evlist); evlist__purge(evlist); evlist__exit(evlist); - free(evlist); + RC_CHK_FREE(evlist); } void evlist__add(struct evlist *evlist, struct evsel *entry) { - perf_evlist__add(&evlist->core, &entry->core); - entry->evlist = evlist; + perf_evlist__add(evlist__core(evlist), &entry->core); + evlist__put(entry->evlist); + entry->evlist = evlist__get(evlist); entry->tracking = !entry->core.idx; - if (evlist->core.nr_entries == 1) + if (evlist__nr_entries(evlist) == 1) evlist__set_id_pos(evlist); } void evlist__remove(struct evlist *evlist, struct evsel *evsel) { + perf_evlist__remove(evlist__core(evlist), &evsel->core); + evlist__put(evsel->evlist); evsel->evlist = NULL; - perf_evlist__remove(&evlist->core, &evsel->core); } void evlist__splice_list_tail(struct evlist *evlist, struct list_head *list) @@ -287,7 +327,7 @@ out: static void evlist__set_leader(struct evlist *evlist) { - perf_evlist__set_leader(&evlist->core); + perf_evlist__set_leader(evlist__core(evlist)); } static struct evsel *evlist__dummy_event(struct evlist *evlist) @@ -301,7 +341,7 @@ static struct evsel *evlist__dummy_event(struct evlist *evlist) .sample_period = 1, }; - return evsel__new_idx(&attr, evlist->core.nr_entries); + return evsel__new_idx(&attr, evlist__nr_entries(evlist)); } int evlist__add_dummy(struct evlist *evlist) @@ -390,8 +430,8 @@ static bool evlist__use_affinity(struct evlist *evlist) struct perf_cpu_map *used_cpus = NULL; bool ret = false; - if (evlist->no_affinity || !evlist->core.user_requested_cpus || - cpu_map__is_dummy(evlist->core.user_requested_cpus)) + if (evlist__no_affinity(evlist) || !evlist__core(evlist)->user_requested_cpus || + cpu_map__is_dummy(evlist__core(evlist)->user_requested_cpus)) return false; evlist__for_each_entry(evlist, pos) { @@ -446,7 +486,7 @@ void evlist_cpu_iterator__init(struct evlist_cpu_iterator *itr, struct evlist *e .evsel = NULL, .cpu_map_idx = 0, .evlist_cpu_map_idx = 0, - .evlist_cpu_map_nr = perf_cpu_map__nr(evlist->core.all_cpus), + .evlist_cpu_map_nr = perf_cpu_map__nr(evlist__core(evlist)->all_cpus), .cpu = (struct perf_cpu){ .cpu = -1}, .affinity = NULL, }; @@ -462,7 +502,7 @@ void evlist_cpu_iterator__init(struct evlist_cpu_iterator *itr, struct evlist *e itr->affinity = &itr->saved_affinity; } itr->evsel = evlist__first(evlist); - itr->cpu = perf_cpu_map__cpu(evlist->core.all_cpus, 0); + itr->cpu = perf_cpu_map__cpu(evlist__core(evlist)->all_cpus, 0); if (itr->affinity) affinity__set(itr->affinity, itr->cpu.cpu); itr->cpu_map_idx = perf_cpu_map__idx(itr->evsel->core.cpus, itr->cpu); @@ -497,7 +537,7 @@ void evlist_cpu_iterator__next(struct evlist_cpu_iterator *evlist_cpu_itr) if (evlist_cpu_itr->evlist_cpu_map_idx < evlist_cpu_itr->evlist_cpu_map_nr) { evlist_cpu_itr->evsel = evlist__first(evlist_cpu_itr->container); evlist_cpu_itr->cpu = - perf_cpu_map__cpu(evlist_cpu_itr->container->core.all_cpus, + perf_cpu_map__cpu(evlist__core(evlist_cpu_itr->container)->all_cpus, evlist_cpu_itr->evlist_cpu_map_idx); if (evlist_cpu_itr->affinity) affinity__set(evlist_cpu_itr->affinity, evlist_cpu_itr->cpu.cpu); @@ -524,7 +564,7 @@ static int evsel__strcmp(struct evsel *pos, char *evsel_name) return !evsel__name_is(pos, evsel_name); } -static int evlist__is_enabled(struct evlist *evlist) +static bool evlist__is_enabled(struct evlist *evlist) { struct evsel *pos; @@ -581,10 +621,7 @@ static void __evlist__disable(struct evlist *evlist, char *evsel_name, bool excl * If we disabled only single event, we need to check * the enabled state of the evlist manually. */ - if (evsel_name) - evlist->enabled = evlist__is_enabled(evlist); - else - evlist->enabled = false; + evlist__set_enabled(evlist, evsel_name ? evlist__is_enabled(evlist) : false); } void evlist__disable(struct evlist *evlist) @@ -635,7 +672,7 @@ static void __evlist__enable(struct evlist *evlist, char *evsel_name, bool excl_ * so the toggle can work properly and toggle to * 'disabled' state. */ - evlist->enabled = true; + evlist__set_enabled(evlist, true); } void evlist__enable(struct evlist *evlist) @@ -655,23 +692,24 @@ void evlist__enable_evsel(struct evlist *evlist, char *evsel_name) void evlist__toggle_enable(struct evlist *evlist) { - (evlist->enabled ? evlist__disable : evlist__enable)(evlist); + (evlist__enabled(evlist) ? evlist__disable : evlist__enable)(evlist); } int evlist__add_pollfd(struct evlist *evlist, int fd) { - return perf_evlist__add_pollfd(&evlist->core, fd, NULL, POLLIN, fdarray_flag__default); + return perf_evlist__add_pollfd(evlist__core(evlist), fd, NULL, POLLIN, + fdarray_flag__default); } int evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask) { - return perf_evlist__filter_pollfd(&evlist->core, revents_and_mask); + return perf_evlist__filter_pollfd(evlist__core(evlist), revents_and_mask); } #ifdef HAVE_EVENTFD_SUPPORT int evlist__add_wakeup_eventfd(struct evlist *evlist, int fd) { - return perf_evlist__add_pollfd(&evlist->core, fd, NULL, POLLIN, + return perf_evlist__add_pollfd(evlist__core(evlist), fd, NULL, POLLIN, fdarray_flag__nonfilterable | fdarray_flag__non_perf_event); } @@ -679,7 +717,7 @@ int evlist__add_wakeup_eventfd(struct evlist *evlist, int fd) int evlist__poll(struct evlist *evlist, int timeout) { - return perf_evlist__poll(&evlist->core, timeout); + return perf_evlist__poll(evlist__core(evlist), timeout); } struct perf_sample_id *evlist__id2sid(struct evlist *evlist, u64 id) @@ -689,7 +727,7 @@ struct perf_sample_id *evlist__id2sid(struct evlist *evlist, u64 id) int hash; hash = hash_64(id, PERF_EVLIST__HLIST_BITS); - head = &evlist->core.heads[hash]; + head = &evlist__core(evlist)->heads[hash]; hlist_for_each_entry(sid, head, node) if (sid->id == id) @@ -702,7 +740,7 @@ struct evsel *evlist__id2evsel(struct evlist *evlist, u64 id) { struct perf_sample_id *sid; - if (evlist->core.nr_entries == 1 || !id) + if (evlist__nr_entries(evlist) == 1 || !id) return evlist__first(evlist); sid = evlist__id2sid(evlist, id); @@ -737,13 +775,13 @@ static int evlist__event2id(struct evlist *evlist, union perf_event *event, u64 n = (event->header.size - sizeof(event->header)) >> 3; if (event->header.type == PERF_RECORD_SAMPLE) { - if (evlist->id_pos >= n) + if (evlist__id_pos(evlist) >= n) return -1; - *id = array[evlist->id_pos]; + *id = array[evlist__id_pos(evlist)]; } else { - if (evlist->is_pos > n) + if (evlist__is_pos(evlist) > n) return -1; - n -= evlist->is_pos; + n -= evlist__is_pos(evlist); *id = array[n]; } return 0; @@ -757,7 +795,7 @@ struct evsel *evlist__event2evsel(struct evlist *evlist, union perf_event *event int hash; u64 id; - if (evlist->core.nr_entries == 1) + if (evlist__nr_entries(evlist) == 1) return first; if (!first->core.attr.sample_id_all && @@ -772,7 +810,7 @@ struct evsel *evlist__event2evsel(struct evlist *evlist, union perf_event *event return first; hash = hash_64(id, PERF_EVLIST__HLIST_BITS); - head = &evlist->core.heads[hash]; + head = &evlist__core(evlist)->heads[hash]; hlist_for_each_entry(sid, head, node) { if (sid->id == id) @@ -785,11 +823,11 @@ static int evlist__set_paused(struct evlist *evlist, bool value) { int i; - if (!evlist->overwrite_mmap) + if (!evlist__overwrite_mmap(evlist)) return 0; - for (i = 0; i < evlist->core.nr_mmaps; i++) { - int fd = evlist->overwrite_mmap[i].core.fd; + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { + int fd = evlist__overwrite_mmap(evlist)[i].core.fd; int err; if (fd < 0) @@ -815,20 +853,20 @@ static void evlist__munmap_nofree(struct evlist *evlist) { int i; - if (evlist->mmap) - for (i = 0; i < evlist->core.nr_mmaps; i++) - perf_mmap__munmap(&evlist->mmap[i].core); + if (evlist__mmap(evlist)) + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) + perf_mmap__munmap(&evlist__mmap(evlist)[i].core); - if (evlist->overwrite_mmap) - for (i = 0; i < evlist->core.nr_mmaps; i++) - perf_mmap__munmap(&evlist->overwrite_mmap[i].core); + if (evlist__overwrite_mmap(evlist)) + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) + perf_mmap__munmap(&evlist__overwrite_mmap(evlist)[i].core); } -void evlist__munmap(struct evlist *evlist) +void evlist__do_munmap(struct evlist *evlist) { evlist__munmap_nofree(evlist); - zfree(&evlist->mmap); - zfree(&evlist->overwrite_mmap); + zfree(&RC_CHK_ACCESS(evlist)->mmap); + zfree(&RC_CHK_ACCESS(evlist)->overwrite_mmap); } static void perf_mmap__unmap_cb(struct perf_mmap *map) @@ -842,12 +880,12 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist, bool overwrite) { int i; - struct mmap *map = calloc(evlist->core.nr_mmaps, sizeof(struct mmap)); + struct mmap *map = calloc(evlist__core(evlist)->nr_mmaps, sizeof(struct mmap)); if (!map) return NULL; - for (i = 0; i < evlist->core.nr_mmaps; i++) { + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { struct perf_mmap *prev = i ? &map[i - 1].core : NULL; /* @@ -865,41 +903,73 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist, return map; } +static struct evlist *from_list_start(struct perf_evlist *core) +{ +#ifdef REFCNT_CHECKING + RC_STRUCT(evlist) *core_evlist = container_of(core, RC_STRUCT(evlist), core); + struct evlist *evlist; + + if (ADD_RC_CHK(evlist, core_evlist)) + refcount_inc(evlist__refcnt(evlist)); + + return evlist; +#else + return container_of(core, struct evlist, core); +#endif +} + +static void from_list_end(struct evlist *evlist __maybe_unused) +{ +#ifdef REFCNT_CHECKING + evlist__put(evlist); +#endif +} + static void perf_evlist__mmap_cb_idx(struct perf_evlist *_evlist, struct perf_evsel *_evsel, struct perf_mmap_param *_mp, int idx) { - struct evlist *evlist = container_of(_evlist, struct evlist, core); + struct evlist *evlist = from_list_start(_evlist); struct mmap_params *mp = container_of(_mp, struct mmap_params, core); struct evsel *evsel = container_of(_evsel, struct evsel, core); + if (!evlist) + return; + auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, evsel, idx); + + from_list_end(evlist); } static struct perf_mmap* perf_evlist__mmap_cb_get(struct perf_evlist *_evlist, bool overwrite, int idx) { - struct evlist *evlist = container_of(_evlist, struct evlist, core); + struct evlist *evlist = from_list_start(_evlist); struct mmap *maps; - maps = overwrite ? evlist->overwrite_mmap : evlist->mmap; + if (!evlist) + return NULL; + + maps = overwrite ? evlist__overwrite_mmap(evlist) : evlist__mmap(evlist); if (!maps) { maps = evlist__alloc_mmap(evlist, overwrite); - if (!maps) + if (!maps) { + from_list_end(evlist); return NULL; + } if (overwrite) { - evlist->overwrite_mmap = maps; - if (evlist->bkw_mmap_state == BKW_MMAP_NOTREADY) + RC_CHK_ACCESS(evlist)->overwrite_mmap = maps; + if (evlist__bkw_mmap_state(evlist) == BKW_MMAP_NOTREADY) evlist__toggle_bkw_mmap(evlist, BKW_MMAP_RUNNING); } else { - evlist->mmap = maps; + RC_CHK_ACCESS(evlist)->mmap = maps; } } - + from_list_end(evlist); return &maps[idx].core; } @@ -1056,16 +1126,16 @@ int evlist__mmap_ex(struct evlist *evlist, unsigned int pages, .mmap = perf_evlist__mmap_cb_mmap, }; - evlist->core.mmap_len = evlist__mmap_size(pages); - pr_debug("mmap size %zuB\n", evlist->core.mmap_len); + evlist__core(evlist)->mmap_len = evlist__mmap_size(pages); + pr_debug("mmap size %zuB\n", evlist__core(evlist)->mmap_len); - auxtrace_mmap_params__init(&mp.auxtrace_mp, evlist->core.mmap_len, + auxtrace_mmap_params__init(&mp.auxtrace_mp, evlist__core(evlist)->mmap_len, auxtrace_pages, auxtrace_overwrite); - return perf_evlist__mmap_ops(&evlist->core, &ops, &mp.core); + return perf_evlist__mmap_ops(evlist__core(evlist), &ops, &mp.core); } -int evlist__mmap(struct evlist *evlist, unsigned int pages) +int evlist__do_mmap(struct evlist *evlist, unsigned int pages) { return evlist__mmap_ex(evlist, pages, 0, false, 0, PERF_AFFINITY_SYS, 1, 0); } @@ -1107,9 +1177,9 @@ int evlist__create_maps(struct evlist *evlist, struct target *target) if (!cpus) goto out_delete_threads; - evlist->core.has_user_cpus = !!target->cpu_list; + evlist__core(evlist)->has_user_cpus = !!target->cpu_list; - perf_evlist__set_maps(&evlist->core, cpus, threads); + perf_evlist__set_maps(evlist__core(evlist), cpus, threads); /* as evlist now has references, put count here */ perf_cpu_map__put(cpus); @@ -1249,15 +1319,15 @@ bool evlist__valid_sample_type(struct evlist *evlist) { struct evsel *pos; - if (evlist->core.nr_entries == 1) + if (evlist__nr_entries(evlist) == 1) return true; - if (evlist->id_pos < 0 || evlist->is_pos < 0) + if (evlist__id_pos(evlist) < 0 || evlist__is_pos(evlist) < 0) return false; evlist__for_each_entry(evlist, pos) { - if (pos->id_pos != evlist->id_pos || - pos->is_pos != evlist->is_pos) + if (pos->id_pos != evlist__id_pos(evlist) || + pos->is_pos != evlist__is_pos(evlist)) return false; } @@ -1268,18 +1338,18 @@ u64 __evlist__combined_sample_type(struct evlist *evlist) { struct evsel *evsel; - if (evlist->combined_sample_type) - return evlist->combined_sample_type; + if (RC_CHK_ACCESS(evlist)->combined_sample_type) + return RC_CHK_ACCESS(evlist)->combined_sample_type; evlist__for_each_entry(evlist, evsel) - evlist->combined_sample_type |= evsel->core.attr.sample_type; + RC_CHK_ACCESS(evlist)->combined_sample_type |= evsel->core.attr.sample_type; - return evlist->combined_sample_type; + return RC_CHK_ACCESS(evlist)->combined_sample_type; } u64 evlist__combined_sample_type(struct evlist *evlist) { - evlist->combined_sample_type = 0; + RC_CHK_ACCESS(evlist)->combined_sample_type = 0; return __evlist__combined_sample_type(evlist); } @@ -1356,7 +1426,7 @@ void evlist__update_br_cntr(struct evlist *evlist) evlist__new_abbr_name(evsel->abbr_name); } } - evlist->nr_br_cntr = i; + evlist__set_nr_br_cntr(evlist, i); } bool evlist__valid_read_format(struct evlist *evlist) @@ -1406,11 +1476,6 @@ bool evlist__sample_id_all(struct evlist *evlist) return first->core.attr.sample_id_all; } -void evlist__set_selected(struct evlist *evlist, struct evsel *evsel) -{ - evlist->selected = evsel; -} - void evlist__close(struct evlist *evlist) { struct evsel *evsel; @@ -1427,7 +1492,7 @@ void evlist__close(struct evlist *evlist) perf_evsel__free_fd(&evsel->core); perf_evsel__free_id(&evsel->core); } - perf_evlist__reset_id_hash(&evlist->core); + perf_evlist__reset_id_hash(evlist__core(evlist)); } static int evlist__create_syswide_maps(struct evlist *evlist) @@ -1454,7 +1519,7 @@ static int evlist__create_syswide_maps(struct evlist *evlist) return -ENOMEM; } - perf_evlist__set_maps(&evlist->core, cpus, threads); + perf_evlist__set_maps(evlist__core(evlist), cpus, threads); perf_thread_map__put(threads); perf_cpu_map__put(cpus); return 0; @@ -1469,7 +1534,8 @@ int evlist__open(struct evlist *evlist) * Default: one fd per CPU, all threads, aka systemwide * as sys_perf_event_open(cpu = -1, thread = -1) is EINVAL */ - if (evlist->core.threads == NULL && evlist->core.user_requested_cpus == NULL) { + if (evlist__core(evlist)->threads == NULL && + evlist__core(evlist)->user_requested_cpus == NULL) { err = evlist__create_syswide_maps(evlist); if (err < 0) goto out_err; @@ -1496,7 +1562,7 @@ int evlist__prepare_workload(struct evlist *evlist, struct target *target, const int child_ready_pipe[2], go_pipe[2]; char bf; - evlist->workload.cork_fd = -1; + evlist__set_workload_cork_fd(evlist, -1); if (pipe(child_ready_pipe) < 0) { perror("failed to create 'ready' pipe"); @@ -1508,13 +1574,13 @@ int evlist__prepare_workload(struct evlist *evlist, struct target *target, const goto out_close_ready_pipe; } - evlist->workload.pid = fork(); - if (evlist->workload.pid < 0) { + evlist__set_workload_pid(evlist, fork()); + if (evlist__workload_pid(evlist) < 0) { perror("failed to fork"); goto out_close_pipes; } - if (!evlist->workload.pid) { + if (!evlist__workload_pid(evlist)) { int ret; if (pipe_output) @@ -1580,12 +1646,13 @@ int evlist__prepare_workload(struct evlist *evlist, struct target *target, const } if (target__none(target)) { - if (evlist->core.threads == NULL) { + if (evlist__core(evlist)->threads == NULL) { fprintf(stderr, "FATAL: evlist->threads need to be set at this point (%s:%d).\n", __func__, __LINE__); goto out_close_pipes; } - perf_thread_map__set_pid(evlist->core.threads, 0, evlist->workload.pid); + perf_thread_map__set_pid(evlist__core(evlist)->threads, 0, + evlist__workload_pid(evlist)); } close(child_ready_pipe[1]); @@ -1599,7 +1666,7 @@ int evlist__prepare_workload(struct evlist *evlist, struct target *target, const } fcntl(go_pipe[1], F_SETFD, FD_CLOEXEC); - evlist->workload.cork_fd = go_pipe[1]; + evlist__set_workload_cork_fd(evlist, go_pipe[1]); close(child_ready_pipe[0]); return 0; @@ -1614,18 +1681,18 @@ out_close_ready_pipe: int evlist__start_workload(struct evlist *evlist) { - if (evlist->workload.cork_fd >= 0) { + if (evlist__workload_cork_fd(evlist) >= 0) { char bf = 0; int ret; /* * Remove the cork, let it rip! */ - ret = write(evlist->workload.cork_fd, &bf, 1); + ret = write(evlist__workload_cork_fd(evlist), &bf, 1); if (ret < 0) perror("unable to write to pipe"); - close(evlist->workload.cork_fd); - evlist->workload.cork_fd = -1; + close(evlist__workload_cork_fd(evlist)); + evlist__set_workload_cork_fd(evlist, -1); return ret; } @@ -1636,10 +1703,10 @@ void evlist__cancel_workload(struct evlist *evlist) { int status; - if (evlist->workload.cork_fd >= 0) { - close(evlist->workload.cork_fd); - evlist->workload.cork_fd = -1; - waitpid(evlist->workload.pid, &status, WNOHANG); + if (evlist__workload_cork_fd(evlist) >= 0) { + close(evlist__workload_cork_fd(evlist)); + evlist__set_workload_cork_fd(evlist, -1); + waitpid(evlist__workload_pid(evlist), &status, WNOHANG); } } @@ -1733,7 +1800,8 @@ out_default: int evlist__strerror_mmap(struct evlist *evlist, int err, char *buf, size_t size) { - int pages_attempted = evlist->core.mmap_len / 1024, pages_max_per_user, printed = 0; + int pages_attempted = evlist__core(evlist)->mmap_len / 1024; + int pages_max_per_user, printed = 0; switch (err) { case EPERM: @@ -1776,7 +1844,7 @@ void evlist__to_front(struct evlist *evlist, struct evsel *move_evsel) list_move_tail(&evsel->core.node, &move); } - list_splice(&move, &evlist->core.entries); + list_splice(&move, &evlist__core(evlist)->entries); } struct evsel *evlist__get_tracking_event(struct evlist *evlist) @@ -1818,7 +1886,7 @@ struct evsel *evlist__findnew_tracking_event(struct evlist *evlist, bool system_ evlist__set_tracking_event(evlist, evsel); } else if (system_wide) { - perf_evlist__go_system_wide(&evlist->core, &evsel->core); + perf_evlist__go_system_wide(evlist__core(evlist), &evsel->core); } return evsel; @@ -1840,14 +1908,14 @@ struct evsel *evlist__find_evsel_by_str(struct evlist *evlist, const char *str) void evlist__toggle_bkw_mmap(struct evlist *evlist, enum bkw_mmap_state state) { - enum bkw_mmap_state old_state = evlist->bkw_mmap_state; + enum bkw_mmap_state old_state = evlist__bkw_mmap_state(evlist); enum action { NONE, PAUSE, RESUME, } action = NONE; - if (!evlist->overwrite_mmap) + if (!evlist__overwrite_mmap(evlist)) return; switch (old_state) { @@ -1877,7 +1945,7 @@ void evlist__toggle_bkw_mmap(struct evlist *evlist, enum bkw_mmap_state state) WARN_ONCE(1, "Shouldn't get there\n"); } - evlist->bkw_mmap_state = state; + evlist__set_bkw_mmap_state(evlist, state); switch (action) { case PAUSE: @@ -2055,40 +2123,41 @@ int evlist__initialize_ctlfd(struct evlist *evlist, int fd, int ack) return 0; } - evlist->ctl_fd.pos = perf_evlist__add_pollfd(&evlist->core, fd, NULL, POLLIN, - fdarray_flag__nonfilterable | - fdarray_flag__non_perf_event); - if (evlist->ctl_fd.pos < 0) { - evlist->ctl_fd.pos = -1; + evlist__set_ctl_fd_pos(evlist, + perf_evlist__add_pollfd(evlist__core(evlist), fd, NULL, POLLIN, + fdarray_flag__nonfilterable | + fdarray_flag__non_perf_event)); + if (evlist__ctl_fd_pos(evlist) < 0) { + evlist__set_ctl_fd_pos(evlist, -1); pr_err("Failed to add ctl fd entry: %m\n"); return -1; } - evlist->ctl_fd.fd = fd; - evlist->ctl_fd.ack = ack; + evlist__set_ctl_fd_fd(evlist, fd); + evlist__set_ctl_fd_ack(evlist, ack); return 0; } bool evlist__ctlfd_initialized(struct evlist *evlist) { - return evlist->ctl_fd.pos >= 0; + return evlist__ctl_fd_pos(evlist) >= 0; } int evlist__finalize_ctlfd(struct evlist *evlist) { - struct pollfd *entries = evlist->core.pollfd.entries; + struct pollfd *entries = evlist__core(evlist)->pollfd.entries; if (!evlist__ctlfd_initialized(evlist)) return 0; - entries[evlist->ctl_fd.pos].fd = -1; - entries[evlist->ctl_fd.pos].events = 0; - entries[evlist->ctl_fd.pos].revents = 0; + entries[evlist__ctl_fd_pos(evlist)].fd = -1; + entries[evlist__ctl_fd_pos(evlist)].events = 0; + entries[evlist__ctl_fd_pos(evlist)].revents = 0; - evlist->ctl_fd.pos = -1; - evlist->ctl_fd.ack = -1; - evlist->ctl_fd.fd = -1; + evlist__set_ctl_fd_pos(evlist, -1); + evlist__set_ctl_fd_ack(evlist, -1); + evlist__set_ctl_fd_fd(evlist, -1); return 0; } @@ -2105,7 +2174,7 @@ static int evlist__ctlfd_recv(struct evlist *evlist, enum evlist_ctl_cmd *cmd, data_size--; do { - err = read(evlist->ctl_fd.fd, &c, 1); + err = read(evlist__ctl_fd_fd(evlist), &c, 1); if (err > 0) { if (c == '\n' || c == '\0') break; @@ -2119,7 +2188,8 @@ static int evlist__ctlfd_recv(struct evlist *evlist, enum evlist_ctl_cmd *cmd, if (errno == EAGAIN || errno == EWOULDBLOCK) err = 0; else - pr_err("Failed to read from ctlfd %d: %m\n", evlist->ctl_fd.fd); + pr_err("Failed to read from ctlfd %d: %m\n", + evlist__ctl_fd_fd(evlist)); } break; } while (1); @@ -2157,13 +2227,13 @@ int evlist__ctlfd_ack(struct evlist *evlist) { int err; - if (evlist->ctl_fd.ack == -1) + if (evlist__ctl_fd_ack(evlist) == -1) return 0; - err = write(evlist->ctl_fd.ack, EVLIST_CTL_CMD_ACK_TAG, + err = write(evlist__ctl_fd_ack(evlist), EVLIST_CTL_CMD_ACK_TAG, sizeof(EVLIST_CTL_CMD_ACK_TAG)); if (err == -1) - pr_err("failed to write to ctl_ack_fd %d: %m\n", evlist->ctl_fd.ack); + pr_err("failed to write to ctl_ack_fd %d: %m\n", evlist__ctl_fd_ack(evlist)); return err; } @@ -2264,8 +2334,8 @@ int evlist__ctlfd_process(struct evlist *evlist, enum evlist_ctl_cmd *cmd) { int err = 0; char cmd_data[EVLIST_CTL_CMD_MAX_LEN]; - int ctlfd_pos = evlist->ctl_fd.pos; - struct pollfd *entries = evlist->core.pollfd.entries; + int ctlfd_pos = evlist__ctl_fd_pos(evlist); + struct pollfd *entries = evlist__core(evlist)->pollfd.entries; if (!evlist__ctlfd_initialized(evlist) || !entries[ctlfd_pos].revents) return 0; @@ -2436,14 +2506,15 @@ int evlist__parse_event_enable_time(struct evlist *evlist, struct record_opts *o goto free_eet_times; } - eet->pollfd_pos = perf_evlist__add_pollfd(&evlist->core, eet->timerfd, NULL, POLLIN, flags); + eet->pollfd_pos = perf_evlist__add_pollfd(evlist__core(evlist), eet->timerfd, + NULL, POLLIN, flags); if (eet->pollfd_pos < 0) { err = eet->pollfd_pos; goto close_timerfd; } eet->evlist = evlist; - evlist->eet = eet; + RC_CHK_ACCESS(evlist)->eet = eet; opts->target.initial_delay = eet->times[0].start; return 0; @@ -2493,7 +2564,7 @@ int event_enable_timer__process(struct event_enable_timer *eet) if (!eet) return 0; - entries = eet->evlist->core.pollfd.entries; + entries = evlist__core(eet->evlist)->pollfd.entries; revents = entries[eet->pollfd_pos].revents; entries[eet->pollfd_pos].revents = 0; @@ -2529,7 +2600,7 @@ int event_enable_timer__process(struct event_enable_timer *eet) return 0; } -void event_enable_timer__exit(struct event_enable_timer **ep) +static void event_enable_timer__exit(struct event_enable_timer **ep) { if (!ep || !*ep) return; @@ -2633,7 +2704,7 @@ void evlist__warn_user_requested_cpus(struct evlist *evlist, const char *cpu_lis } /* Should uniquify be disabled for the evlist? */ -static bool evlist__disable_uniquify(const struct evlist *evlist) +static bool evlist__disable_uniquify(struct evlist *evlist) { struct evsel *counter; struct perf_pmu *last_pmu = NULL; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index a9820a6aad5b..838e263b76f3 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "affinity.h" @@ -59,7 +60,7 @@ enum bkw_mmap_state { struct event_enable_timer; -struct evlist { +DECLARE_RC_STRUCT(evlist) { struct perf_evlist core; refcount_t refcnt; bool enabled; @@ -86,7 +87,7 @@ struct evlist { struct { pthread_t th; volatile int done; - } thread; + } sb_thread; struct { int fd; /* control file descriptor */ int ack; /* ack file descriptor for control commands */ @@ -107,6 +108,227 @@ struct evsel_str_handler { void *handler; }; +static inline struct perf_evlist *evlist__core(struct evlist *evlist) +{ + return &RC_CHK_ACCESS(evlist)->core; +} + +static inline const struct perf_evlist *evlist__const_core(const struct evlist *evlist) +{ + return &RC_CHK_ACCESS(evlist)->core; +} + +static inline int evlist__nr_entries(const struct evlist *evlist) +{ + return evlist__const_core(evlist)->nr_entries; +} + +static inline bool evlist__enabled(const struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->enabled; +} + +static inline void evlist__set_enabled(struct evlist *evlist, bool enabled) +{ + RC_CHK_ACCESS(evlist)->enabled = enabled; +} + +static inline bool evlist__no_affinity(const struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->no_affinity; +} + +static inline void evlist__set_no_affinity(struct evlist *evlist, bool no_affinity) +{ + RC_CHK_ACCESS(evlist)->no_affinity = no_affinity; +} + +static inline int evlist__sb_thread_done(const struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->sb_thread.done; +} + +static inline void evlist__set_sb_thread_done(struct evlist *evlist, int done) +{ + RC_CHK_ACCESS(evlist)->sb_thread.done = done; +} + +static inline pthread_t *evlist__sb_thread_th(struct evlist *evlist) +{ + return &RC_CHK_ACCESS(evlist)->sb_thread.th; +} + +static inline int evlist__id_pos(const struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->id_pos; +} + +static inline int evlist__is_pos(const struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->is_pos; +} + +static inline struct event_enable_timer *evlist__event_enable_timer(struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->eet; +} + +static inline enum bkw_mmap_state evlist__bkw_mmap_state(const struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->bkw_mmap_state; +} + +static inline void evlist__set_bkw_mmap_state(struct evlist *evlist, enum bkw_mmap_state state) +{ + RC_CHK_ACCESS(evlist)->bkw_mmap_state = state; +} + +static inline struct mmap *evlist__mmap(struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->mmap; +} + +static inline struct mmap *evlist__overwrite_mmap(struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->overwrite_mmap; +} + +static inline struct events_stats *evlist__stats(struct evlist *evlist) +{ + return &RC_CHK_ACCESS(evlist)->stats; +} + +static inline u64 evlist__first_sample_time(const struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->first_sample_time; +} + +static inline void evlist__set_first_sample_time(struct evlist *evlist, u64 first) +{ + RC_CHK_ACCESS(evlist)->first_sample_time = first; +} + +static inline u64 evlist__last_sample_time(const struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->last_sample_time; +} + +static inline void evlist__set_last_sample_time(struct evlist *evlist, u64 last) +{ + RC_CHK_ACCESS(evlist)->last_sample_time = last; +} + +static inline int evlist__nr_br_cntr(const struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->nr_br_cntr; +} + +static inline void evlist__set_nr_br_cntr(struct evlist *evlist, int nr) +{ + RC_CHK_ACCESS(evlist)->nr_br_cntr = nr; +} + +static inline struct perf_session *evlist__session(struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->session; +} + +static inline void evlist__set_session(struct evlist *evlist, struct perf_session *session) +{ + RC_CHK_ACCESS(evlist)->session = session; +} + +static inline void (*evlist__trace_event_sample_raw(struct evlist *evlist)) + (struct evlist *evlist, + union perf_event *event, + struct perf_sample *sample) +{ + return RC_CHK_ACCESS(evlist)->trace_event_sample_raw; +} + +static inline void evlist__set_trace_event_sample_raw(struct evlist *evlist, + void (*fun)(struct evlist *evlist, + union perf_event *event, + struct perf_sample *sample)) +{ + RC_CHK_ACCESS(evlist)->trace_event_sample_raw = fun; +} + +static inline pid_t evlist__workload_pid(const struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->workload.pid; +} + +static inline void evlist__set_workload_pid(struct evlist *evlist, pid_t pid) +{ + RC_CHK_ACCESS(evlist)->workload.pid = pid; +} + +static inline int evlist__workload_cork_fd(const struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->workload.cork_fd; +} + +static inline void evlist__set_workload_cork_fd(struct evlist *evlist, int cork_fd) +{ + RC_CHK_ACCESS(evlist)->workload.cork_fd = cork_fd; +} + +static inline int evlist__ctl_fd_fd(const struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->ctl_fd.fd; +} + +static inline void evlist__set_ctl_fd_fd(struct evlist *evlist, int fd) +{ + RC_CHK_ACCESS(evlist)->ctl_fd.fd = fd; +} + +static inline int evlist__ctl_fd_ack(const struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->ctl_fd.ack; +} + +static inline void evlist__set_ctl_fd_ack(struct evlist *evlist, int ack) +{ + RC_CHK_ACCESS(evlist)->ctl_fd.ack = ack; +} + +static inline int evlist__ctl_fd_pos(const struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->ctl_fd.pos; +} + +static inline void evlist__set_ctl_fd_pos(struct evlist *evlist, int pos) +{ + RC_CHK_ACCESS(evlist)->ctl_fd.pos = pos; +} + +static inline refcount_t *evlist__refcnt(struct evlist *evlist) +{ + return &RC_CHK_ACCESS(evlist)->refcnt; +} + +static inline struct rblist *evlist__metric_events(struct evlist *evlist) +{ + return &RC_CHK_ACCESS(evlist)->metric_events; +} + +static inline struct list_head *evlist__deferred_samples(struct evlist *evlist) +{ + return &RC_CHK_ACCESS(evlist)->deferred_samples; +} + +static inline struct evsel *evlist__selected(struct evlist *evlist) +{ + return RC_CHK_ACCESS(evlist)->selected; +} + +static inline void evlist__set_selected(struct evlist *evlist, struct evsel *evsel) +{ + RC_CHK_ACCESS(evlist)->selected = evsel; +} + struct evlist *evlist__new(void); struct evlist *evlist__new_default(const struct target *target, bool sample_callchains); struct evlist *evlist__new_dummy(void); @@ -200,8 +422,8 @@ int evlist__mmap_ex(struct evlist *evlist, unsigned int pages, unsigned int auxtrace_pages, bool auxtrace_overwrite, int nr_cblocks, int affinity, int flush, int comp_level); -int evlist__mmap(struct evlist *evlist, unsigned int pages); -void evlist__munmap(struct evlist *evlist); +int evlist__do_mmap(struct evlist *evlist, unsigned int pages); +void evlist__do_munmap(struct evlist *evlist); size_t evlist__mmap_size(unsigned long pages); @@ -213,8 +435,6 @@ void evlist__enable_evsel(struct evlist *evlist, char *evsel_name); void evlist__disable_non_dummy(struct evlist *evlist); void evlist__enable_non_dummy(struct evlist *evlist); -void evlist__set_selected(struct evlist *evlist, struct evsel *evsel); - int evlist__create_maps(struct evlist *evlist, struct target *target); int evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel, struct target *target); @@ -237,26 +457,26 @@ void evlist__splice_list_tail(struct evlist *evlist, struct list_head *list); static inline bool evlist__empty(struct evlist *evlist) { - return list_empty(&evlist->core.entries); + return list_empty(&evlist__core(evlist)->entries); } static inline struct evsel *evlist__first(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(&evlist->core); + struct perf_evsel *evsel = perf_evlist__first(evlist__core(evlist)); return container_of(evsel, struct evsel, core); } static inline struct evsel *evlist__last(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__last(&evlist->core); + struct perf_evsel *evsel = perf_evlist__last(evlist__core(evlist)); return container_of(evsel, struct evsel, core); } static inline int evlist__nr_groups(struct evlist *evlist) { - return perf_evlist__nr_groups(&evlist->core); + return perf_evlist__nr_groups(evlist__core(evlist)); } int evlist__strerror_open(struct evlist *evlist, int err, char *buf, size_t size); @@ -279,7 +499,7 @@ void evlist__to_front(struct evlist *evlist, struct evsel *move_evsel); * @evsel: struct evsel iterator */ #define evlist__for_each_entry(evlist, evsel) \ - __evlist__for_each_entry(&(evlist)->core.entries, evsel) + __evlist__for_each_entry(&evlist__core(evlist)->entries, evsel) /** * __evlist__for_each_entry_continue - continue iteration thru all the evsels @@ -295,7 +515,7 @@ void evlist__to_front(struct evlist *evlist, struct evsel *move_evsel); * @evsel: struct evsel iterator */ #define evlist__for_each_entry_continue(evlist, evsel) \ - __evlist__for_each_entry_continue(&(evlist)->core.entries, evsel) + __evlist__for_each_entry_continue(&evlist__core(evlist)->entries, evsel) /** * __evlist__for_each_entry_from - continue iteration from @evsel (included) @@ -311,7 +531,7 @@ void evlist__to_front(struct evlist *evlist, struct evsel *move_evsel); * @evsel: struct evsel iterator */ #define evlist__for_each_entry_from(evlist, evsel) \ - __evlist__for_each_entry_from(&(evlist)->core.entries, evsel) + __evlist__for_each_entry_from(&evlist__core(evlist)->entries, evsel) /** * __evlist__for_each_entry_reverse - iterate thru all the evsels in reverse order @@ -327,7 +547,7 @@ void evlist__to_front(struct evlist *evlist, struct evsel *move_evsel); * @evsel: struct evsel iterator */ #define evlist__for_each_entry_reverse(evlist, evsel) \ - __evlist__for_each_entry_reverse(&(evlist)->core.entries, evsel) + __evlist__for_each_entry_reverse(&evlist__core(evlist)->entries, evsel) /** * __evlist__for_each_entry_safe - safely iterate thru all the evsels @@ -345,7 +565,7 @@ void evlist__to_front(struct evlist *evlist, struct evsel *move_evsel); * @tmp: struct evsel temp iterator */ #define evlist__for_each_entry_safe(evlist, tmp, evsel) \ - __evlist__for_each_entry_safe(&(evlist)->core.entries, tmp, evsel) + __evlist__for_each_entry_safe(&evlist__core(evlist)->entries, tmp, evsel) /** Iterator state for evlist__for_each_cpu */ struct evlist_cpu_iterator { @@ -451,7 +671,6 @@ int evlist__ctlfd_ack(struct evlist *evlist); int evlist__parse_event_enable_time(struct evlist *evlist, struct record_opts *opts, const char *str, int unset); int event_enable_timer__start(struct event_enable_timer *eet); -void event_enable_timer__exit(struct event_enable_timer **ep); int event_enable_timer__process(struct event_enable_timer *eet); struct evsel *evlist__find_evsel(struct evlist *evlist, int idx); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index c563aa9c37b0..314f31d1ac35 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -3361,7 +3361,7 @@ static inline bool evsel__has_branch_counters(const struct evsel *evsel) if (!leader || !evsel->evlist) return false; - if (evsel->evlist->nr_br_cntr < 0) + if (evlist__nr_br_cntr(evsel->evlist) < 0) evlist__update_br_cntr(evsel->evlist); if (leader->br_cntr_nr > 0) @@ -4393,7 +4393,7 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target, struct perf_session *evsel__session(struct evsel *evsel) { - return evsel && evsel->evlist ? evsel->evlist->session : NULL; + return evsel && evsel->evlist ? evlist__session(evsel->evlist) : NULL; } struct perf_env *evsel__env(struct evsel *evsel) @@ -4418,7 +4418,7 @@ static int store_evsel_ids(struct evsel *evsel, struct evlist *evlist) thread++) { int fd = FD(evsel, cpu_map_idx, thread); - if (perf_evlist__id_add_fd(&evlist->core, &evsel->core, + if (perf_evlist__id_add_fd(evlist__core(evlist), &evsel->core, cpu_map_idx, thread, fd) < 0) return -1; } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index c63ab60c4732..6b0c08958616 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -534,7 +534,7 @@ for ((_evsel) = list_entry((_leader)->core.node.next, struct evsel, core.node); (_evsel) = list_entry((_evsel)->core.node.next, struct evsel, core.node)) #define for_each_group_member(_evsel, _leader) \ - for_each_group_member_head(_evsel, _leader, &(_leader)->evlist->core.entries) + for_each_group_member_head(_evsel, _leader, &evlist__core((_leader)->evlist)->entries) /* Iterates group WITH the leader. */ #define for_each_group_evsel_head(_evsel, _leader, _head) \ @@ -544,7 +544,7 @@ for ((_evsel) = _leader; \ (_evsel) = list_entry((_evsel)->core.node.next, struct evsel, core.node)) #define for_each_group_evsel(_evsel, _leader) \ - for_each_group_evsel_head(_evsel, _leader, &(_leader)->evlist->core.entries) + for_each_group_evsel_head(_evsel, _leader, &evlist__core((_leader)->evlist)->entries) static inline bool evsel__has_branch_callstack(const struct evsel *evsel) { diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 167ec2703d0e..e90e541f546b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -385,7 +385,7 @@ static int write_tracing_data(struct feat_fd *ff, return -1; #ifdef HAVE_LIBTRACEEVENT - return read_tracing_data(ff->fd, &evlist->core.entries); + return read_tracing_data(ff->fd, &evlist__core(evlist)->entries); #else pr_err("ERROR: Trying to write tracing data without libtraceevent support.\n"); return -1; @@ -434,8 +434,8 @@ static int write_osrelease(struct feat_fd *ff, struct utsname uts; const char *release = NULL; - if (evlist->session) - release = perf_env__os_release(perf_session__env(evlist->session)); + if (evlist__session(evlist)) + release = perf_env__os_release(perf_session__env(evlist__session(evlist))); if (!release) { int ret = uname(&uts); @@ -452,8 +452,8 @@ static int write_arch(struct feat_fd *ff, struct evlist *evlist) struct utsname uts; const char *arch = NULL; - if (evlist->session) - arch = perf_env__arch(perf_session__env(evlist->session)); + if (evlist__session(evlist)) + arch = perf_env__arch(perf_session__env(evlist__session(evlist))); if (!arch) { int ret = uname(&uts); @@ -469,7 +469,7 @@ static int write_e_machine(struct feat_fd *ff, struct evlist *evlist) { /* e_machine expanded from 16 to 32-bits for alignment. */ uint32_t e_flags; - uint32_t e_machine = perf_session__e_machine(evlist->session, &e_flags); + uint32_t e_machine = perf_session__e_machine(evlist__session(evlist), &e_flags); int ret; ret = do_write(ff, &e_machine, sizeof(e_machine)); @@ -605,7 +605,7 @@ static int write_event_desc(struct feat_fd *ff, u32 nre, nri, sz; int ret; - nre = evlist->core.nr_entries; + nre = evlist__nr_entries(evlist); /* * write number of events @@ -987,7 +987,7 @@ int __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused, static int write_cpuid(struct feat_fd *ff, struct evlist *evlist) { - struct perf_cpu cpu = perf_cpu_map__min(evlist->core.all_cpus); + struct perf_cpu cpu = perf_cpu_map__min(evlist__core(evlist)->all_cpus); char buffer[64]; int ret; @@ -1420,14 +1420,14 @@ static int write_sample_time(struct feat_fd *ff, struct evlist *evlist) { int ret; + u64 data = evlist__first_sample_time(evlist); - ret = do_write(ff, &evlist->first_sample_time, - sizeof(evlist->first_sample_time)); + ret = do_write(ff, &data, sizeof(data)); if (ret < 0) return ret; - return do_write(ff, &evlist->last_sample_time, - sizeof(evlist->last_sample_time)); + data = evlist__last_sample_time(evlist); + return do_write(ff, &data, sizeof(data)); } @@ -2551,16 +2551,16 @@ static void print_sample_time(struct feat_fd *ff, FILE *fp) session = container_of(ff->ph, struct perf_session, header); - timestamp__scnprintf_usec(session->evlist->first_sample_time, + timestamp__scnprintf_usec(evlist__first_sample_time(session->evlist), time_buf, sizeof(time_buf)); fprintf(fp, "# time of first sample : %s\n", time_buf); - timestamp__scnprintf_usec(session->evlist->last_sample_time, + timestamp__scnprintf_usec(evlist__last_sample_time(session->evlist), time_buf, sizeof(time_buf)); fprintf(fp, "# time of last sample : %s\n", time_buf); - d = (double)(session->evlist->last_sample_time - - session->evlist->first_sample_time) / NSEC_PER_MSEC; + d = (double)(evlist__last_sample_time(session->evlist) - + evlist__first_sample_time(session->evlist)) / NSEC_PER_MSEC; fprintf(fp, "# sample duration : %10.3f ms\n", d); } @@ -3519,8 +3519,8 @@ static int process_sample_time(struct feat_fd *ff, void *data __maybe_unused) if (ret) return -1; - session->evlist->first_sample_time = first_sample_time; - session->evlist->last_sample_time = last_sample_time; + evlist__set_first_sample_time(session->evlist, first_sample_time); + evlist__set_last_sample_time(session->evlist, last_sample_time); return 0; } @@ -4610,7 +4610,7 @@ int perf_session__write_header(struct perf_session *session, /*write_attrs_after_data=*/false); } -size_t perf_session__data_offset(const struct evlist *evlist) +size_t perf_session__data_offset(struct evlist *evlist) { struct evsel *evsel; size_t data_offset; @@ -4619,7 +4619,7 @@ size_t perf_session__data_offset(const struct evlist *evlist) evlist__for_each_entry(evlist, evsel) { data_offset += evsel->core.ids * sizeof(u64); } - data_offset += evlist->core.nr_entries * sizeof(struct perf_file_attr); + data_offset += evlist__nr_entries(evlist) * sizeof(struct perf_file_attr); return data_offset; } @@ -5110,7 +5110,7 @@ int perf_session__read_header(struct perf_session *session) if (session->evlist == NULL) return -ENOMEM; - session->evlist->session = session; + evlist__set_session(session->evlist, session); session->machines.host.env = &header->env; /* @@ -5243,7 +5243,8 @@ int perf_session__read_header(struct perf_session *session) if (perf_header__getbuffer64(header, fd, &f_id, sizeof(f_id))) goto out_errno; - perf_evlist__id_add(&session->evlist->core, &evsel->core, 0, j, f_id); + perf_evlist__id_add(evlist__core(session->evlist), + &evsel->core, 0, j, f_id); } lseek(fd, tmp, SEEK_SET); @@ -5607,7 +5608,7 @@ int perf_event__process_attr(const struct perf_tool *tool __maybe_unused, */ ids = (void *)&event->attr.attr + attr_size; for (i = 0; i < n_ids; i++) { - perf_evlist__id_add(&evlist->core, &evsel->core, 0, i, ids[i]); + perf_evlist__id_add(evlist__core(evlist), &evsel->core, 0, i, ids[i]); } return 0; diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 86b1a72026d3..5e03f884b7cc 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -158,7 +158,7 @@ int perf_session__inject_header(struct perf_session *session, struct feat_copier *fc, bool write_attrs_after_data); -size_t perf_session__data_offset(const struct evlist *evlist); +size_t perf_session__data_offset(struct evlist *evlist); void perf_header__set_feat(struct perf_header *header, int feat); void perf_header__clear_feat(struct perf_header *header, int feat); diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c index bc3b79bfa01a..b41171b5df77 100644 --- a/tools/perf/util/intel-tpebs.c +++ b/tools/perf/util/intel-tpebs.c @@ -98,8 +98,9 @@ static int evsel__tpebs_start_perf_record(struct evsel *evsel) record_argv[i++] = "-o"; record_argv[i++] = PERF_DATA; - if (!perf_cpu_map__is_any_cpu_or_is_empty(evsel->evlist->core.user_requested_cpus)) { - cpu_map__snprint(evsel->evlist->core.user_requested_cpus, cpumap_buf, + if (!perf_cpu_map__is_any_cpu_or_is_empty( + evlist__core(evsel->evlist)->user_requested_cpus)) { + cpu_map__snprint(evlist__core(evsel->evlist)->user_requested_cpus, cpumap_buf, sizeof(cpumap_buf)); record_argv[i++] = "-C"; record_argv[i++] = cpumap_buf; @@ -176,7 +177,7 @@ static bool should_ignore_sample(const struct perf_sample *sample, const struct if (t->evsel->evlist == NULL) return true; - workload_pid = t->evsel->evlist->workload.pid; + workload_pid = evlist__workload_pid(t->evsel->evlist); if (workload_pid < 0 || workload_pid == sample_pid) return false; diff --git a/tools/perf/util/iostat.c b/tools/perf/util/iostat.c index b770bd473af7..c9d5028a47f3 100644 --- a/tools/perf/util/iostat.c +++ b/tools/perf/util/iostat.c @@ -4,7 +4,7 @@ enum iostat_mode_t iostat_mode = IOSTAT_NONE; -__weak int iostat_prepare(struct evlist *evlist __maybe_unused, +__weak int iostat_prepare(struct evlist **evlist __maybe_unused, struct perf_stat_config *config __maybe_unused) { return -1; diff --git a/tools/perf/util/iostat.h b/tools/perf/util/iostat.h index a4e7299c5c2f..df8a241fbc32 100644 --- a/tools/perf/util/iostat.h +++ b/tools/perf/util/iostat.h @@ -30,7 +30,7 @@ extern enum iostat_mode_t iostat_mode; typedef void (*iostat_print_counter_t)(struct perf_stat_config *, struct evsel *, void *); -int iostat_prepare(struct evlist *evlist, struct perf_stat_config *config); +int iostat_prepare(struct evlist **evlist, struct perf_stat_config *config); int iostat_parse(const struct option *opt, const char *str, int unset __maybe_unused); void iostat_list(struct evlist *evlist, struct perf_stat_config *config); diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 2c4e9fefb41f..8c7b299a55db 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -1490,7 +1490,7 @@ static int parse_groups(struct evlist *perf_evlist, goto out; } - me = metricgroup__lookup(&perf_evlist->metric_events, + me = metricgroup__lookup(evlist__metric_events(perf_evlist), pick_display_evsel(&metric_list, metric_events), /*create=*/true); @@ -1541,13 +1541,13 @@ static int parse_groups(struct evlist *perf_evlist, if (combined_evlist) { - evlist__splice_list_tail(perf_evlist, &combined_evlist->core.entries); + evlist__splice_list_tail(perf_evlist, &evlist__core(combined_evlist)->entries); evlist__put(combined_evlist); } list_for_each_entry(m, &metric_list, nd) { if (m->evlist) - evlist__splice_list_tail(perf_evlist, &m->evlist->core.entries); + evlist__splice_list_tail(perf_evlist, &evlist__core(m->evlist)->entries); } out: diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 8fb5626d5d37..194bc94dfc1e 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2294,7 +2294,7 @@ int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filte { struct parse_events_state parse_state = { .list = LIST_HEAD_INIT(parse_state.list), - .idx = evlist->core.nr_entries, + .idx = evlist__nr_entries(evlist), .error = err, .stoken = PE_START_EVENTS, .fake_pmu = fake_pmu, @@ -2568,7 +2568,7 @@ foreach_evsel_in_last_glob(struct evlist *evlist, * * So no need to WARN here, let *func do this. */ - if (evlist->core.nr_entries > 0) + if (evlist__nr_entries(evlist) > 0) last = evlist__last(evlist); do { @@ -2578,7 +2578,7 @@ foreach_evsel_in_last_glob(struct evlist *evlist, if (!last) return 0; - if (last->core.node.prev == &evlist->core.entries) + if (last->core.node.prev == &evlist__core(evlist)->entries) return 0; last = list_entry(last->core.node.prev, struct evsel, core.node); } while (!last->cmdline_group_boundary); diff --git a/tools/perf/util/pfm.c b/tools/perf/util/pfm.c index 5f53c2f68a96..f80d6b0df47a 100644 --- a/tools/perf/util/pfm.c +++ b/tools/perf/util/pfm.c @@ -85,7 +85,7 @@ int parse_libpfm_events_option(const struct option *opt, const char *str, } pmu = perf_pmus__find_by_type((unsigned int)attr.type); - evsel = parse_events__add_event(evlist->core.nr_entries, + evsel = parse_events__add_event(evlist__nr_entries(evlist), &attr, q, /*metric_id=*/NULL, pmu); if (evsel == NULL) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 5482b68b8c0b..58d8644bf06a 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -1546,7 +1546,7 @@ static int pyrf_evlist__init(struct pyrf_evlist *pevlist, } threads = ((struct pyrf_thread_map *)pthreads)->threads; cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; - perf_evlist__set_maps(&pevlist->evlist->core, cpus, threads); + perf_evlist__set_maps(evlist__core(pevlist->evlist), cpus, threads); return 0; } @@ -1559,23 +1559,29 @@ static void pyrf_evlist__delete(struct pyrf_evlist *pevlist) static PyObject *pyrf_evlist__all_cpus(struct pyrf_evlist *pevlist) { - struct pyrf_cpu_map *pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type); + struct pyrf_cpu_map *pcpu_map; + + CHECK_INITIALIZED(pevlist->evlist, "evlist"); + pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type); if (pcpu_map) - pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist->core.all_cpus); + pcpu_map->cpus = perf_cpu_map__get(evlist__core(pevlist->evlist)->all_cpus); return (PyObject *)pcpu_map; } static PyObject *pyrf_evlist__metrics(struct pyrf_evlist *pevlist) { - PyObject *list = PyList_New(/*len=*/0); + PyObject *list; struct rb_node *node; + CHECK_INITIALIZED(pevlist->evlist, "evlist"); + + list = PyList_New(/*len=*/0); if (!list) return NULL; - for (node = rb_first_cached(&pevlist->evlist->metric_events.entries); node; + for (node = rb_first_cached(&evlist__metric_events(pevlist->evlist)->entries); node; node = rb_next(node)) { struct metric_event *me = container_of(node, struct metric_event, nd); struct list_head *pos; @@ -1678,10 +1684,12 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist, double result = 0; struct evsel *metric_evsel = NULL; + CHECK_INITIALIZED(pevlist->evlist, "evlist"); + if (!PyArg_ParseTuple(args, "sii", &metric, &cpu, &thread)) return NULL; - for (node = rb_first_cached(&pevlist->evlist->metric_events.entries); + for (node = rb_first_cached(&evlist__metric_events(pevlist->evlist)->entries); mexp == NULL && node; node = rb_next(node)) { struct metric_event *me = container_of(node, struct metric_event, nd); @@ -1742,15 +1750,18 @@ done: static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct evlist *evlist = pevlist->evlist; + struct evlist *evlist; static char *kwlist[] = { "pages", "overwrite", NULL }; int pages = 128, overwrite = false; + CHECK_INITIALIZED(pevlist->evlist, "evlist"); + + evlist = pevlist->evlist; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", kwlist, &pages, &overwrite)) return NULL; - if (evlist__mmap(evlist, pages) < 0) { + if (evlist__do_mmap(evlist, pages) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -1762,10 +1773,13 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist, static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct evlist *evlist = pevlist->evlist; + struct evlist *evlist; static char *kwlist[] = { "timeout", NULL }; int timeout = -1, n; + CHECK_INITIALIZED(pevlist->evlist, "evlist"); + + evlist = pevlist->evlist; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout)) return NULL; @@ -1782,13 +1796,18 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist, PyObject *args __maybe_unused, PyObject *kwargs __maybe_unused) { - struct evlist *evlist = pevlist->evlist; - PyObject *list = PyList_New(0); + struct evlist *evlist; + PyObject *list; int i; - for (i = 0; i < evlist->core.pollfd.nr; ++i) { + CHECK_INITIALIZED(pevlist->evlist, "evlist"); + + evlist = pevlist->evlist; + list = PyList_New(0); + + for (i = 0; i < evlist__core(evlist)->pollfd.nr; ++i) { PyObject *file; - file = PyFile_FromFd(evlist->core.pollfd.entries[i].fd, "perf", "r", -1, + file = PyFile_FromFd(evlist__core(evlist)->pollfd.entries[i].fd, "perf", "r", -1, NULL, NULL, NULL, 0); if (file == NULL) goto free_list; @@ -1811,28 +1830,33 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs __maybe_unused) { - struct evlist *evlist = pevlist->evlist; + struct evlist *evlist; PyObject *pevsel; struct evsel *evsel; + CHECK_INITIALIZED(pevlist->evlist, "evlist"); + + evlist = pevlist->evlist; if (!PyArg_ParseTuple(args, "O!", &pyrf_evsel__type, &pevsel)) return NULL; CHECK_INITIALIZED(((struct pyrf_evsel *)pevsel)->evsel, "evsel"); evsel = ((struct pyrf_evsel *)pevsel)->evsel; - evsel->core.idx = evlist->core.nr_entries; + CHECK_INITIALIZED(evsel, "evsel"); + + evsel->core.idx = evlist__nr_entries(evlist); evlist__add(evlist, evsel__get(evsel)); - return Py_BuildValue("i", evlist->core.nr_entries); + return Py_BuildValue("i", evlist__nr_entries(evlist)); } static struct mmap *get_md(struct evlist *evlist, int cpu) { int i; - for (i = 0; i < evlist->core.nr_mmaps; i++) { - struct mmap *md = &evlist->mmap[i]; + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { + struct mmap *md = &evlist__mmap(evlist)[i]; if (md->core.cpu.cpu == cpu) return md; @@ -1844,13 +1868,16 @@ static struct mmap *get_md(struct evlist *evlist, int cpu) static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct evlist *evlist = pevlist->evlist; + struct evlist *evlist; union perf_event *event; int sample_id_all = 1, cpu; static char *kwlist[] = { "cpu", "sample_id_all", NULL }; struct mmap *md; int err; + CHECK_INITIALIZED(pevlist->evlist, "evlist"); + + evlist = pevlist->evlist; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist, &cpu, &sample_id_all)) return NULL; @@ -1901,8 +1928,11 @@ end: static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct evlist *evlist = pevlist->evlist; + struct evlist *evlist; + + CHECK_INITIALIZED(pevlist->evlist, "evlist"); + evlist = pevlist->evlist; if (evlist__open(evlist) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; @@ -1914,8 +1944,11 @@ static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist, static PyObject *pyrf_evlist__close(struct pyrf_evlist *pevlist) { - struct evlist *evlist = pevlist->evlist; + struct evlist *evlist; + CHECK_INITIALIZED(pevlist->evlist, "evlist"); + + evlist = pevlist->evlist; evlist__close(evlist); Py_INCREF(Py_None); @@ -1940,8 +1973,11 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist) .no_buffering = true, .no_inherit = true, }; - struct evlist *evlist = pevlist->evlist; + struct evlist *evlist; + + CHECK_INITIALIZED(pevlist->evlist, "evlist"); + evlist = pevlist->evlist; evlist__config(evlist, &opts, &callchain_param); Py_INCREF(Py_None); return Py_None; @@ -1949,6 +1985,7 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist) static PyObject *pyrf_evlist__disable(struct pyrf_evlist *pevlist) { + CHECK_INITIALIZED(pevlist->evlist, "evlist"); evlist__disable(pevlist->evlist); Py_INCREF(Py_None); return Py_None; @@ -1956,6 +1993,7 @@ static PyObject *pyrf_evlist__disable(struct pyrf_evlist *pevlist) static PyObject *pyrf_evlist__enable(struct pyrf_evlist *pevlist) { + CHECK_INITIALIZED(pevlist->evlist, "evlist"); evlist__enable(pevlist->evlist); Py_INCREF(Py_None); return Py_None; @@ -2050,7 +2088,7 @@ static Py_ssize_t pyrf_evlist__length(PyObject *obj) if (!pevlist->evlist) return 0; - return pevlist->evlist->core.nr_entries; + return evlist__nr_entries(pevlist->evlist); } static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel) @@ -2069,7 +2107,7 @@ static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i) struct pyrf_evlist *pevlist = (void *)obj; struct evsel *pos; - if (!pevlist->evlist || i >= pevlist->evlist->core.nr_entries) { + if (!pevlist->evlist || i >= evlist__nr_entries(pevlist->evlist)) { PyErr_SetString(PyExc_IndexError, "Index out of range"); return NULL; } @@ -2297,7 +2335,7 @@ static PyObject *pyrf__parse_events(PyObject *self, PyObject *args) cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL; parse_events_error__init(&err); - perf_evlist__set_maps(&evlist->core, cpus, threads); + perf_evlist__set_maps(evlist__core(evlist), cpus, threads); if (parse_events(evlist, input, &err)) { parse_events_error__print(&err, input); PyErr_SetFromErrno(PyExc_OSError); @@ -2330,7 +2368,7 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args) threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL; cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL; - perf_evlist__set_maps(&evlist->core, cpus, threads); + perf_evlist__set_maps(evlist__core(evlist), cpus, threads); ret = metricgroup__parse_groups(evlist, pmu ?: "all", input, /*metric_no_group=*/ false, /*metric_no_merge=*/ false, diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 8a5fc7d5e43c..38e8aee3106b 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -99,7 +99,7 @@ void evlist__config(struct evlist *evlist, struct record_opts *opts, struct call bool use_comm_exec; bool sample_id = opts->sample_id; - if (perf_cpu_map__cpu(evlist->core.user_requested_cpus, 0).cpu < 0) + if (perf_cpu_map__cpu(evlist__core(evlist)->user_requested_cpus, 0).cpu < 0) opts->no_inherit = true; use_comm_exec = perf_can_comm_exec(); @@ -122,7 +122,7 @@ void evlist__config(struct evlist *evlist, struct record_opts *opts, struct call */ use_sample_identifier = perf_can_sample_identifier(); sample_id = true; - } else if (evlist->core.nr_entries > 1) { + } else if (evlist__nr_entries(evlist) > 1) { struct evsel *first = evlist__first(evlist); evlist__for_each_entry(evlist, evsel) { @@ -237,7 +237,8 @@ bool evlist__can_select_event(struct evlist *evlist, const char *str) evsel = evlist__last(temp_evlist); - if (!evlist || perf_cpu_map__is_any_cpu_or_is_empty(evlist->core.user_requested_cpus)) { + if (!evlist || + perf_cpu_map__is_any_cpu_or_is_empty(evlist__core(evlist)->user_requested_cpus)) { struct perf_cpu_map *cpus = perf_cpu_map__new_online_cpus(); if (cpus) @@ -245,7 +246,7 @@ bool evlist__can_select_event(struct evlist *evlist, const char *str) perf_cpu_map__put(cpus); } else { - cpu = perf_cpu_map__cpu(evlist->core.user_requested_cpus, 0); + cpu = perf_cpu_map__cpu(evlist__core(evlist)->user_requested_cpus, 0); } while (1) { diff --git a/tools/perf/util/sample-raw.c b/tools/perf/util/sample-raw.c index e20b73c0c5bd..f5ae9f468983 100644 --- a/tools/perf/util/sample-raw.c +++ b/tools/perf/util/sample-raw.c @@ -18,11 +18,11 @@ void evlist__init_trace_event_sample_raw(struct evlist *evlist, struct perf_env uint16_t e_machine = perf_env__e_machine(env, /*e_flags=*/NULL); if (e_machine == EM_S390) { - evlist->trace_event_sample_raw = evlist__s390_sample_raw; + evlist__set_trace_event_sample_raw(evlist, evlist__s390_sample_raw); } else if (e_machine == EM_X86_64 || e_machine == EM_386) { const char *cpuid = perf_env__cpuid(env); if (cpuid && strstarts(cpuid, "AuthenticAMD") && evlist__has_amd_ibs(evlist)) - evlist->trace_event_sample_raw = evlist__amd_sample_raw; + evlist__set_trace_event_sample_raw(evlist, evlist__amd_sample_raw); } } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 9962b830a402..10d8942f86da 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -205,7 +205,7 @@ struct perf_session *__perf_session__new(struct perf_data *data, session->machines.host.env = host_env; } if (session->evlist) - session->evlist->session = session; + evlist__set_session(session->evlist, session); session->machines.host.single_address_space = perf_env__single_address_space(session->machines.host.env); @@ -1549,8 +1549,8 @@ static void dump_event(struct evlist *evlist, union perf_event *event, file_offset, file_path, event->header.size, event->header.type); trace_event(event); - if (event->header.type == PERF_RECORD_SAMPLE && evlist->trace_event_sample_raw) - evlist->trace_event_sample_raw(evlist, event, sample); + if (event->header.type == PERF_RECORD_SAMPLE && evlist__trace_event_sample_raw(evlist)) + evlist__trace_event_sample_raw(evlist)(evlist, event, sample); if (sample) evlist__print_tstamp(evlist, event, sample); @@ -1751,7 +1751,7 @@ static int deliver_sample_value(struct evlist *evlist, } if (!storage || sid->evsel == NULL) { - ++evlist->stats.nr_unknown_id; + ++evlist__stats(evlist)->nr_unknown_id; return 0; } @@ -1853,7 +1853,7 @@ static int evlist__deliver_deferred_callchain(struct evlist *evlist, return ret; } - list_for_each_entry_safe(de, tmp, &evlist->deferred_samples, list) { + list_for_each_entry_safe(de, tmp, evlist__deferred_samples(evlist), list) { struct perf_sample orig_sample; perf_sample__init(&orig_sample, /*all=*/false); @@ -1902,7 +1902,7 @@ static int session__flush_deferred_samples(struct perf_session *session, struct deferred_event *de, *tmp; int ret = 0; - list_for_each_entry_safe(de, tmp, &evlist->deferred_samples, list) { + list_for_each_entry_safe(de, tmp, evlist__deferred_samples(evlist), list) { struct perf_sample sample; perf_sample__init(&sample, /*all=*/false); @@ -1964,17 +1964,16 @@ static int machines__deliver_event(struct machines *machines, sample->evsel = evlist__id2evsel(evlist, sample->id); else assert(sample->evsel == evlist__id2evsel(evlist, sample->id)); - machine = machines__find_for_cpumode(machines, event, sample); switch (event->header.type) { case PERF_RECORD_SAMPLE: if (sample->evsel == NULL) { - ++evlist->stats.nr_unknown_id; + ++evlist__stats(evlist)->nr_unknown_id; return 0; } if (machine == NULL) { - ++evlist->stats.nr_unprocessable_samples; + ++evlist__stats(evlist)->nr_unprocessable_samples; dump_sample(machine, event, sample); return 0; } @@ -1993,7 +1992,7 @@ static int machines__deliver_event(struct machines *machines, } memcpy(de->event, event, sz); de->file_offset = sample->file_offset; - list_add_tail(&de->list, &evlist->deferred_samples); + list_add_tail(&de->list, evlist__deferred_samples(evlist)); return 0; } return evlist__deliver_sample(evlist, tool, event, sample, machine); @@ -2005,7 +2004,7 @@ static int machines__deliver_event(struct machines *machines, return tool->mmap(tool, event, sample, machine); case PERF_RECORD_MMAP2: if (event->header.misc & PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT) - ++evlist->stats.nr_proc_map_timeout; + ++evlist__stats(evlist)->nr_proc_map_timeout; if (!perf_event__check_nul(event->mmap2.filename, (void *)event + event->header.size, "MMAP2", file_offset)) @@ -2050,13 +2049,13 @@ static int machines__deliver_event(struct machines *machines, return tool->exit(tool, event, sample, machine); case PERF_RECORD_LOST: if (tool->lost == perf_event__process_lost) - evlist->stats.total_lost += event->lost.lost; + evlist__stats(evlist)->total_lost += event->lost.lost; return tool->lost(tool, event, sample, machine); case PERF_RECORD_LOST_SAMPLES: if (event->header.misc & PERF_RECORD_MISC_LOST_SAMPLES_BPF) - evlist->stats.total_dropped_samples += event->lost_samples.lost; + evlist__stats(evlist)->total_dropped_samples += event->lost_samples.lost; else if (tool->lost_samples == perf_event__process_lost_samples) - evlist->stats.total_lost_samples += event->lost_samples.lost; + evlist__stats(evlist)->total_lost_samples += event->lost_samples.lost; return tool->lost_samples(tool, event, sample, machine); case PERF_RECORD_READ: dump_read(sample->evsel, event); @@ -2068,11 +2067,11 @@ static int machines__deliver_event(struct machines *machines, case PERF_RECORD_AUX: if (tool->aux == perf_event__process_aux) { if (event->aux.flags & PERF_AUX_FLAG_TRUNCATED) - evlist->stats.total_aux_lost += 1; + evlist__stats(evlist)->total_aux_lost += 1; if (event->aux.flags & PERF_AUX_FLAG_PARTIAL) - evlist->stats.total_aux_partial += 1; + evlist__stats(evlist)->total_aux_partial += 1; if (event->aux.flags & PERF_AUX_FLAG_COLLISION) - evlist->stats.total_aux_collision += 1; + evlist__stats(evlist)->total_aux_collision += 1; } return tool->aux(tool, event, sample, machine); case PERF_RECORD_ITRACE_START: @@ -2108,7 +2107,7 @@ static int machines__deliver_event(struct machines *machines, return evlist__deliver_deferred_callchain(evlist, tool, event, sample, machine); default: - ++evlist->stats.nr_unknown_events; + ++evlist__stats(evlist)->nr_unknown_events; return -1; } } @@ -2520,7 +2519,7 @@ int perf_session__deliver_synth_event(struct perf_session *session, struct evlist *evlist = session->evlist; const struct perf_tool *tool = session->tool; - events_stats__inc(&evlist->stats, event->header.type); + events_stats__inc(evlist__stats(evlist), event->header.type); if (event->header.type >= PERF_RECORD_USER_TYPE_START) return perf_session__process_user_event(session, event, 0, NULL); @@ -2930,7 +2929,7 @@ static s64 perf_session__process_event(struct perf_session *session, return 0; } - events_stats__inc(&evlist->stats, event->header.type); + events_stats__inc(evlist__stats(evlist), event->header.type); if (event->header.type >= PERF_RECORD_USER_TYPE_START) return perf_session__process_user_event(session, event, file_offset, file_path); @@ -2991,7 +2990,7 @@ perf_session__warn_order(const struct perf_session *session) static void perf_session__warn_about_errors(const struct perf_session *session) { - const struct events_stats *stats = &session->evlist->stats; + const struct events_stats *stats = evlist__stats(session->evlist); if (session->tool->lost == perf_event__process_lost && stats->nr_events[PERF_RECORD_LOST] != 0) { @@ -3824,7 +3823,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) ret = fprintf(fp, "\nAggregated stats:%s\n", msg); - ret += events_stats__fprintf(&session->evlist->stats, fp); + ret += events_stats__fprintf(evlist__stats(session->evlist), fp); return ret; } diff --git a/tools/perf/util/sideband_evlist.c b/tools/perf/util/sideband_evlist.c index b84a5463e039..c07dacf3c54c 100644 --- a/tools/perf/util/sideband_evlist.c +++ b/tools/perf/util/sideband_evlist.c @@ -22,7 +22,7 @@ int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr, attr->sample_id_all = 1; } - evsel = evsel__new_idx(attr, evlist->core.nr_entries); + evsel = evsel__new_idx(attr, evlist__nr_entries(evlist)); if (!evsel) return -1; @@ -49,14 +49,14 @@ static void *perf_evlist__poll_thread(void *arg) while (!done) { bool got_data = false; - if (evlist->thread.done) + if (evlist__sb_thread_done(evlist)) draining = true; if (!draining) evlist__poll(evlist, 1000); - for (i = 0; i < evlist->core.nr_mmaps; i++) { - struct mmap *map = &evlist->mmap[i]; + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { + struct mmap *map = &evlist__mmap(evlist)[i]; union perf_event *event; if (perf_mmap__read_init(&map->core)) @@ -104,7 +104,7 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target) if (evlist__create_maps(evlist, target)) goto out_put_evlist; - if (evlist->core.nr_entries > 1) { + if (evlist__nr_entries(evlist) > 1) { bool can_sample_identifier = perf_can_sample_identifier(); evlist__for_each_entry(evlist, counter) @@ -114,12 +114,12 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target) } evlist__for_each_entry(evlist, counter) { - if (evsel__open(counter, evlist->core.user_requested_cpus, - evlist->core.threads) < 0) + if (evsel__open(counter, evlist__core(evlist)->user_requested_cpus, + evlist__core(evlist)->threads) < 0) goto out_put_evlist; } - if (evlist__mmap(evlist, UINT_MAX)) + if (evlist__do_mmap(evlist, UINT_MAX)) goto out_put_evlist; evlist__for_each_entry(evlist, counter) { @@ -127,8 +127,8 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target) goto out_put_evlist; } - evlist->thread.done = 0; - if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist)) + evlist__set_sb_thread_done(evlist, 0); + if (pthread_create(evlist__sb_thread_th(evlist), NULL, perf_evlist__poll_thread, evlist)) goto out_put_evlist; return 0; @@ -143,7 +143,7 @@ void evlist__stop_sb_thread(struct evlist *evlist) { if (!evlist) return; - evlist->thread.done = 1; - pthread_join(evlist->thread.th, NULL); + evlist__set_sb_thread_done(evlist, 1); + pthread_join(*evlist__sb_thread_th(evlist), NULL); evlist__put(evlist); } diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 005e7d85dc4a..dcf9189786f8 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -3487,7 +3487,7 @@ static struct evsel *find_evsel(struct evlist *evlist, char *event_name) if (event_name[0] == '%') { int nr = strtol(event_name+1, NULL, 0); - if (nr > evlist->core.nr_entries) + if (nr > evlist__nr_entries(evlist)) return NULL; evsel = evlist__first(evlist); diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c index 0a5750bb59fa..f94f1324d24a 100644 --- a/tools/perf/util/stat-display.c +++ b/tools/perf/util/stat-display.c @@ -667,7 +667,7 @@ static void print_metric_header(struct perf_stat_config *config, /* In case of iostat, print metric header for first root port only */ if (config->iostat_run && - os->evsel->priv != os->evsel->evlist->selected->priv) + os->evsel->priv != evlist__selected(os->evsel->evlist)->priv) return; if (os->evsel->cgrp != os->cgrp) @@ -1126,7 +1126,7 @@ static void print_no_aggr_metric(struct perf_stat_config *config, unsigned int all_idx; struct perf_cpu cpu; - perf_cpu_map__for_each_cpu(cpu, all_idx, evlist->core.user_requested_cpus) { + perf_cpu_map__for_each_cpu(cpu, all_idx, evlist__core(evlist)->user_requested_cpus) { struct evsel *counter; bool first = true; @@ -1543,7 +1543,7 @@ void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *conf evlist__uniquify_evsel_names(evlist, config); if (config->iostat_run) - evlist->selected = evlist__first(evlist); + evlist__set_selected(evlist, evlist__first(evlist)); if (config->interval) prepare_timestamp(config, &os, ts); diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index 35062f964618..525a3fe4a46e 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -287,7 +287,7 @@ void *perf_stat__print_shadow_stats_metricgroup(struct perf_stat_config *config, void *ctxp = out->ctx; bool header_printed = false; const char *name = NULL; - struct rblist *metric_events = &evsel->evlist->metric_events; + struct rblist *metric_events = evlist__metric_events(evsel->evlist); me = metricgroup__lookup(metric_events, evsel, false); if (me == NULL) @@ -355,5 +355,5 @@ bool perf_stat__skip_metric_event(struct evsel *evsel) if (!evsel->default_metricgroup) return false; - return !metricgroup__lookup(&evsel->evlist->metric_events, evsel, false); + return !metricgroup__lookup(evlist__metric_events(evsel->evlist), evsel, false); } diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 66eb9a66a4f7..25f31a174368 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -547,8 +547,8 @@ static void evsel__merge_aliases(struct evsel *evsel) struct evlist *evlist = evsel->evlist; struct evsel *alias; - alias = list_prepare_entry(evsel, &(evlist->core.entries), core.node); - list_for_each_entry_continue(alias, &evlist->core.entries, core.node) { + alias = list_prepare_entry(evsel, &(evlist__core(evlist)->entries), core.node); + list_for_each_entry_continue(alias, &evlist__core(evlist)->entries, core.node) { if (alias->first_wildcard_match == evsel) { /* Merge the same events on different PMUs. */ evsel__merge_aggr_counters(evsel, alias); diff --git a/tools/perf/util/stream.c b/tools/perf/util/stream.c index 3de4a6130853..7bccd2378344 100644 --- a/tools/perf/util/stream.c +++ b/tools/perf/util/stream.c @@ -131,7 +131,7 @@ static int evlist__init_callchain_streams(struct evlist *evlist, struct evsel *pos; int i = 0; - BUG_ON(els->nr_evsel < evlist->core.nr_entries); + BUG_ON(els->nr_evsel < evlist__nr_entries(evlist)); evlist__for_each_entry(evlist, pos) { struct hists *hists = evsel__hists(pos); @@ -148,7 +148,7 @@ static int evlist__init_callchain_streams(struct evlist *evlist, struct evlist_streams *evlist__create_streams(struct evlist *evlist, int nr_streams_max) { - int nr_evsel = evlist->core.nr_entries, ret = -1; + int nr_evsel = evlist__nr_entries(evlist), ret = -1; struct evlist_streams *els = evlist_streams__new(nr_evsel, nr_streams_max); diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c index 5307d707711d..b75f9dcf4dbf 100644 --- a/tools/perf/util/synthetic-events.c +++ b/tools/perf/util/synthetic-events.c @@ -2247,7 +2247,7 @@ int perf_event__synthesize_tracing_data(const struct perf_tool *tool, int fd, st * - write the tracing data from the temp file * to the pipe */ - tdata = tracing_data_get(&evlist->core.entries, fd, true); + tdata = tracing_data_get(&evlist__core(evlist)->entries, fd, true); if (!tdata) return -1; @@ -2404,13 +2404,16 @@ int perf_event__synthesize_stat_events(struct perf_stat_config *config, const st } err = perf_event__synthesize_extra_attr(tool, evlist, process, attrs); - err = perf_event__synthesize_thread_map2(tool, evlist->core.threads, process, NULL); + err = perf_event__synthesize_thread_map2(tool, evlist__core(evlist)->threads, + process, /*machine=*/NULL); if (err < 0) { pr_err("Couldn't synthesize thread map.\n"); return err; } - err = perf_event__synthesize_cpu_map(tool, evlist->core.user_requested_cpus, process, NULL); + err = perf_event__synthesize_cpu_map(tool, + evlist__core(evlist)->user_requested_cpus, + process, /*machine=*/NULL); if (err < 0) { pr_err("Couldn't synthesize thread map.\n"); return err; @@ -2518,7 +2521,7 @@ int perf_event__synthesize_for_pipe(const struct perf_tool *tool, ret += err; #ifdef HAVE_LIBTRACEEVENT - if (have_tracepoints(&evlist->core.entries)) { + if (have_tracepoints(&evlist__core(evlist)->entries)) { int fd = perf_data__fd(data); /* diff --git a/tools/perf/util/time-utils.c b/tools/perf/util/time-utils.c index d43c4577d7eb..5558a5a0fea4 100644 --- a/tools/perf/util/time-utils.c +++ b/tools/perf/util/time-utils.c @@ -473,8 +473,8 @@ int perf_time__parse_for_ranges_reltime(const char *time_str, return -ENOMEM; if (has_percent || reltime) { - if (session->evlist->first_sample_time == 0 && - session->evlist->last_sample_time == 0) { + if (evlist__first_sample_time(session->evlist) == 0 && + evlist__last_sample_time(session->evlist) == 0) { pr_err("HINT: no first/last sample time found in perf data.\n" "Please use latest perf binary to execute 'perf record'\n" "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n"); @@ -486,8 +486,8 @@ int perf_time__parse_for_ranges_reltime(const char *time_str, num = perf_time__percent_parse_str( ptime_range, size, time_str, - session->evlist->first_sample_time, - session->evlist->last_sample_time); + evlist__first_sample_time(session->evlist), + evlist__last_sample_time(session->evlist)); } else { num = perf_time__parse_strs(ptime_range, time_str, size); } @@ -499,8 +499,8 @@ int perf_time__parse_for_ranges_reltime(const char *time_str, int i; for (i = 0; i < num; i++) { - ptime_range[i].start += session->evlist->first_sample_time; - ptime_range[i].end += session->evlist->first_sample_time; + ptime_range[i].start += evlist__first_sample_time(session->evlist); + ptime_range[i].end += evlist__first_sample_time(session->evlist); } } diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index b06e10a116bb..851a26be6931 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c @@ -71,7 +71,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) esamples_percent); } - if (top->evlist->core.nr_entries == 1) { + if (evlist__nr_entries(top->evlist) == 1) { struct evsel *first = evlist__first(top->evlist); ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", (uint64_t)first->core.attr.sample_period, @@ -94,7 +94,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) else ret += SNPRINTF(bf + ret, size - ret, " (all"); - nr_cpus = perf_cpu_map__nr(top->evlist->core.user_requested_cpus); + nr_cpus = perf_cpu_map__nr(evlist__core(top->evlist)->user_requested_cpus); if (target->cpu_list) ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", nr_cpus > 1 ? "s" : "", -- cgit v1.2.3 From 674ca42f13c7610bf45d78ad58cd40b7bf05029e Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:30 -0700 Subject: perf python: Use evsel in sample in pyrf_event Avoid a duplicated evsel by using the one in sample. Add evsel__get/put to the evsel in perf_sample. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/builtin-inject.c | 5 ++++- tools/perf/builtin-trace.c | 5 ++++- tools/perf/util/evsel.c | 2 +- tools/perf/util/intel-pt.c | 8 +++++--- tools/perf/util/python.c | 10 +++------- tools/perf/util/s390-sample-raw.c | 1 + tools/perf/util/sample.c | 17 ++++++++++++----- tools/perf/util/session.c | 19 ++++++++++++++++--- 8 files changed, 46 insertions(+), 21 deletions(-) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index b13ce4caf809..70bbfad5653e 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -726,8 +726,11 @@ static int perf_event__repipe_common_mmap(const struct perf_tool *tool, } if (dso && !dso__hit(dso)) { - if (!sample->evsel) + if (!sample->evsel) { sample->evsel = evlist__event2evsel(inject->session->evlist, event); + if (sample->evsel) + evsel__get(sample->evsel); + } if (sample->evsel) { dso__set_hit(dso); diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index b605bd7e519e..845a9fe47f0b 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -3678,8 +3678,11 @@ static void trace__handle_event(struct trace *trace, union perf_event *event, st return; } - if (sample->evsel == NULL) + if (sample->evsel == NULL) { sample->evsel = evlist__id2evsel(trace->evlist, sample->id); + if (sample->evsel) + evsel__get(sample->evsel); + } if (sample->evsel == NULL) { fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 314f31d1ac35..d0484e4ee679 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -3418,7 +3418,7 @@ int __evsel__parse_sample(struct evsel *evsel, union perf_event *event, union u64_swap u; perf_sample__init(data, /*all=*/true); - data->evsel = evsel; + data->evsel = evsel__get(evsel); data->cpu = data->pid = data->tid = -1; data->stream_id = data->id = data->time = -1ULL; data->period = evsel->core.attr.sample_period; diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 56a9e439f5f8..d83439c8c7b0 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -1830,9 +1830,9 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) ptq->last_br_cyc_cnt = ptq->ipc_cyc_cnt; } - perf_sample__exit(&sample); ret = intel_pt_deliver_synth_event(pt, event, &sample, pt->branches_sample_type); + perf_sample__exit(&sample); return ret; } @@ -1967,6 +1967,7 @@ static int intel_pt_synth_ptwrite_sample(struct intel_pt_queue *ptq) union perf_event *event = ptq->event_buf; struct perf_sample sample = { .ip = 0, }; struct perf_synth_intel_ptwrite raw; + int ret; if (intel_pt_skip_event(pt)) return 0; @@ -1983,8 +1984,9 @@ static int intel_pt_synth_ptwrite_sample(struct intel_pt_queue *ptq) sample.raw_size = perf_synth__raw_size(raw); sample.raw_data = perf_synth__raw_data(&raw); - return intel_pt_deliver_synth_event(pt, event, &sample, - pt->ptwrites_sample_type); + ret = intel_pt_deliver_synth_event(pt, event, &sample, pt->ptwrites_sample_type); + perf_sample__exit(&sample); + return ret; } static int intel_pt_synth_cbr_sample(struct intel_pt_queue *ptq) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 58d8644bf06a..cea5fd9b5f79 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -63,7 +63,6 @@ PyMODINIT_FUNC PyInit_perf(void); struct pyrf_event { PyObject_HEAD - struct evsel *evsel; struct perf_sample sample; union perf_event event; }; @@ -294,7 +293,6 @@ static PyMemberDef pyrf_sample_event__members[] = { static void pyrf_sample_event__delete(struct pyrf_event *pevent) { - evsel__put(pevent->evsel); perf_sample__exit(&pevent->sample); Py_TYPE(pevent)->tp_free((PyObject *)pevent); } @@ -316,7 +314,7 @@ static PyObject *pyrf_sample_event__repr(const struct pyrf_event *pevent) #ifdef HAVE_LIBTRACEEVENT static bool is_tracepoint(const struct pyrf_event *pevent) { - return pevent->evsel->core.attr.type == PERF_TYPE_TRACEPOINT; + return pevent->sample.evsel->core.attr.type == PERF_TYPE_TRACEPOINT; } static PyObject* @@ -363,7 +361,7 @@ tracepoint_field(const struct pyrf_event *pe, struct tep_format_field *field) static PyObject* get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name) { - struct evsel *evsel = pevent->evsel; + struct evsel *evsel = pevent->sample.evsel; struct tep_event *tp_format = evsel__tp_format(evsel); struct tep_format_field *field; @@ -529,7 +527,7 @@ static PyObject *pyrf_event__new(const union perf_event *event) pevent = PyObject_New(struct pyrf_event, ptype); if (pevent != NULL) { memcpy(&pevent->event, event, event->header.size); - pevent->evsel = NULL; + perf_sample__init(&pevent->sample, /*all=*/false); } return (PyObject *)pevent; } @@ -1907,8 +1905,6 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, return Py_None; } - pevent->evsel = evsel__get(evsel); - perf_mmap__consume(&md->core); err = evsel__parse_sample(evsel, &pevent->event, &pevent->sample); diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c index 01111c4e3488..aaf8838b2cb2 100644 --- a/tools/perf/util/s390-sample-raw.c +++ b/tools/perf/util/s390-sample-raw.c @@ -343,6 +343,7 @@ void evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event, sample->evsel = evlist__event2evsel(evlist, event); if (!sample->evsel) return; + evsel__get(sample->evsel); } /* Check for raw data in sample */ diff --git a/tools/perf/util/sample.c b/tools/perf/util/sample.c index cf73329326d7..bccc19e2aaf2 100644 --- a/tools/perf/util/sample.c +++ b/tools/perf/util/sample.c @@ -1,18 +1,23 @@ /* SPDX-License-Identifier: GPL-2.0 */ #include "sample.h" + +#include +#include + +#include +#include + +#include "../../arch/x86/include/asm/insn.h" #include "debug.h" +#include "evsel.h" #include "thread.h" -#include + #ifndef EM_CSKY #define EM_CSKY 252 #endif #ifndef EM_LOONGARCH #define EM_LOONGARCH 258 #endif -#include -#include -#include -#include "../../arch/x86/include/asm/insn.h" void perf_sample__init(struct perf_sample *sample, bool all) { @@ -29,6 +34,8 @@ void perf_sample__init(struct perf_sample *sample, bool all) void perf_sample__exit(struct perf_sample *sample) { + evsel__put(sample->evsel); + sample->evsel = NULL; zfree(&sample->user_regs); zfree(&sample->intr_regs); if (sample->merged_callchain) { diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 10d8942f86da..4129e15e4654 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1855,6 +1855,7 @@ static int evlist__deliver_deferred_callchain(struct evlist *evlist, list_for_each_entry_safe(de, tmp, evlist__deferred_samples(evlist), list) { struct perf_sample orig_sample; + struct evsel *new_evsel; perf_sample__init(&orig_sample, /*all=*/false); ret = evlist__parse_sample(evlist, de->event, &orig_sample); @@ -1875,7 +1876,11 @@ static int evlist__deliver_deferred_callchain(struct evlist *evlist, else orig_sample.deferred_callchain = false; - orig_sample.evsel = evlist__id2evsel(evlist, orig_sample.id); + new_evsel = evlist__id2evsel(evlist, orig_sample.id); + if (new_evsel != orig_sample.evsel) { + evsel__put(orig_sample.evsel); + orig_sample.evsel = evsel__get(new_evsel); + } ret = evlist__deliver_sample(evlist, tool, de->event, &orig_sample, machine); @@ -1904,6 +1909,7 @@ static int session__flush_deferred_samples(struct perf_session *session, list_for_each_entry_safe(de, tmp, evlist__deferred_samples(evlist), list) { struct perf_sample sample; + struct evsel *new_evsel; perf_sample__init(&sample, /*all=*/false); ret = evlist__parse_sample(evlist, de->event, &sample); @@ -1914,7 +1920,11 @@ static int session__flush_deferred_samples(struct perf_session *session, } sample.file_offset = de->file_offset; - sample.evsel = evlist__id2evsel(evlist, sample.id); + new_evsel = evlist__id2evsel(evlist, sample.id); + if (new_evsel != sample.evsel) { + evsel__put(sample.evsel); + sample.evsel = evsel__get(new_evsel); + } ret = evlist__deliver_sample(evlist, tool, de->event, &sample, machine); @@ -1960,8 +1970,11 @@ static int machines__deliver_event(struct machines *machines, dump_event(evlist, event, file_offset, sample, file_path); - if (!sample->evsel) + if (!sample->evsel) { sample->evsel = evlist__id2evsel(evlist, sample->id); + if (sample->evsel) + sample->evsel = evsel__get(sample->evsel); + } else assert(sample->evsel == evlist__id2evsel(evlist, sample->id)); machine = machines__find_for_cpumode(machines, event, sample); -- cgit v1.2.3 From 27e59401c78c4d8ebad4eb233b5b987fa47a8e21 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:31 -0700 Subject: perf python: Add wrapper for perf_data file abstraction The perf_data struct is needed for session support. Signed-off-by: Ian Rogers Assisted-by: Gemini:gemini-3.1-pro-preview Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/python.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index cea5fd9b5f79..31da1283fc15 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -14,6 +15,7 @@ #include "callchain.h" #include "counts.h" +#include "data.h" #include "event.h" #include "evlist.h" #include "evsel.h" @@ -2462,6 +2464,121 @@ static PyObject *pyrf__metrics(PyObject *self, PyObject *args) return list; } +struct pyrf_data { + PyObject_HEAD + + struct perf_data data; +}; + +static int pyrf_data__init(struct pyrf_data *pdata, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "path", "fd", NULL }; + char *path = NULL; + int fd = -1; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|si", kwlist, &path, &fd)) + return -1; + + if (pdata->data.open) + perf_data__close(&pdata->data); + free((char *)pdata->data.path); + pdata->data.path = NULL; + + if (fd != -1) { + struct stat st; + + if (fstat(fd, &st) < 0 || !S_ISFIFO(st.st_mode)) { + PyErr_SetString(PyExc_ValueError, + "fd argument is only supported for pipes"); + return -1; + } + if (!path) + path = "-"; + else if (strcmp(path, "-") != 0) { + PyErr_SetString(PyExc_ValueError, + "path must be '-' when fd is provided"); + return -1; + } + fd = dup(fd); + if (fd < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + } else if (path && strcmp(path, "-") == 0) { + fd = dup(0); + if (fd < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + } + + if (!path) + path = "perf.data"; + + pdata->data.path = strdup(path); + if (!pdata->data.path) { + if (fd != -1) + close(fd); + PyErr_NoMemory(); + return -1; + } + + pdata->data.mode = PERF_DATA_MODE_READ; + pdata->data.file.fd = fd; + if (perf_data__open(&pdata->data) < 0) { + PyErr_Format(PyExc_IOError, "Failed to open perf data: %s", + pdata->data.path ? pdata->data.path : "perf.data"); + return -1; + } + return 0; +} + +static void pyrf_data__delete(struct pyrf_data *pdata) +{ + perf_data__close(&pdata->data); + free((char *)pdata->data.path); + Py_TYPE(pdata)->tp_free((PyObject *)pdata); +} + +static PyObject *pyrf_data__str(PyObject *self) +{ + const struct pyrf_data *pdata = (const struct pyrf_data *)self; + + if (!pdata->data.path) + return PyUnicode_FromString("[uninitialized]"); + return PyUnicode_FromString(pdata->data.path); +} + +static PyObject *pyrf_data__new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + struct pyrf_data *pdata; + + pdata = (struct pyrf_data *)PyType_GenericNew(type, args, kwargs); + if (pdata) + memset(&pdata->data, 0, sizeof(pdata->data)); + return (PyObject *)pdata; +} + +static const char pyrf_data__doc[] = PyDoc_STR("perf data file object."); + +static PyTypeObject pyrf_data__type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "perf.data", + .tp_basicsize = sizeof(struct pyrf_data), + .tp_dealloc = (destructor)pyrf_data__delete, + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_doc = pyrf_data__doc, + .tp_init = (initproc)pyrf_data__init, + .tp_repr = pyrf_data__str, + .tp_str = pyrf_data__str, +}; + +static int pyrf_data__setup_types(void) +{ + pyrf_data__type.tp_new = pyrf_data__new; + return PyType_Ready(&pyrf_data__type); +} + static PyMethodDef perf__methods[] = { { .ml_name = "metrics", @@ -2524,7 +2641,8 @@ PyMODINIT_FUNC PyInit_perf(void) pyrf_cpu_map__setup_types() < 0 || pyrf_pmu_iterator__setup_types() < 0 || pyrf_pmu__setup_types() < 0 || - pyrf_counts_values__setup_types() < 0) + pyrf_counts_values__setup_types() < 0 || + pyrf_data__setup_types() < 0) return module; /* The page_size is placed in util object. */ @@ -2572,6 +2690,9 @@ PyMODINIT_FUNC PyInit_perf(void) Py_INCREF(&pyrf_counts_values__type); PyModule_AddObject(module, "counts_values", (PyObject *)&pyrf_counts_values__type); + Py_INCREF(&pyrf_data__type); + PyModule_AddObject(module, "data", (PyObject *)&pyrf_data__type); + dict = PyModule_GetDict(module); if (dict == NULL) goto error; -- cgit v1.2.3 From b4e38080066d3010488e89f19e57fce38746cb51 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:32 -0700 Subject: perf python: Add python session abstraction wrapping perf's session Sessions are necessary to be able to use perf.data files within a tool. Add a wrapper python type that incorporates the tool. Allow a sample callback to be passed when creating the session. When process_events is run this callback will be called, if supplied, for sample events. An example use looks like: ``` $ perf record -e cycles,instructions -a sleep 3 $ PYTHONPATH=..../perf/python python3 Python 3.13.7 (main, Aug 20 2025, 22:17:40) [GCC 14.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import perf >>> count=0 ... def handle_sample(x): ... global count ... if count < 3: ... print(dir(x)) ... count = count + 1 ... perf.session(perf.data("perf.data"),sample=handle_sample).process_events() ... ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'sample_addr', 'sample_cpu', 'sample_id', 'sample_ip', 'sample_period', 'sample_pid', 'sample_stream_id', 'sample_tid', 'sample_time', 'type'] ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'sample_addr', 'sample_cpu', 'sample_id', 'sample_ip', 'sample_period', 'sample_pid', 'sample_stream_id', 'sample_tid', 'sample_time', 'type'] ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'sample_addr', 'sample_cpu', 'sample_id', 'sample_ip', 'sample_period', 'sample_pid', 'sample_stream_id', 'sample_tid', 'sample_time', 'type'] ``` Also, add the ability to get the thread associated with a session. For threads, allow the comm string to be retrieved. This can be useful for filtering threads. Connect up some of the standard event handling in psession->tool to better support queries of the machine. Also connect up the symbols. Signed-off-by: Ian Rogers Assisted-by: Gemini:gemini-3.1-pro-preview Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/python.c | 357 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 351 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 31da1283fc15..dc71fe7e3787 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -14,8 +14,10 @@ #include #include "callchain.h" +#include "comm.h" #include "counts.h" #include "data.h" +#include "debug.h" #include "event.h" #include "evlist.h" #include "evsel.h" @@ -25,8 +27,14 @@ #include "pmus.h" #include "print_binary.h" #include "record.h" +#include "session.h" #include "strbuf.h" +#include "symbol.h" +#include "stat.h" +#include "header.h" +#include "thread.h" #include "thread_map.h" +#include "tool.h" #include "tp_pmu.h" #include "trace-event.h" #include "util/sample.h" @@ -2579,6 +2587,332 @@ static int pyrf_data__setup_types(void) return PyType_Ready(&pyrf_data__type); } +struct pyrf_thread { + PyObject_HEAD + + struct thread *thread; +}; + +static void pyrf_thread__delete(struct pyrf_thread *pthread) +{ + thread__put(pthread->thread); + Py_TYPE(pthread)->tp_free((PyObject *)pthread); +} + +static PyObject *pyrf_thread__comm(PyObject *obj) +{ + struct pyrf_thread *pthread = (void *)obj; + const char *str; + + CHECK_INITIALIZED(pthread->thread, "perf.thread"); + + str = thread__comm_str(pthread->thread); + + if (!str) + Py_RETURN_NONE; + + return PyUnicode_FromString(str); +} + +static PyMethodDef pyrf_thread__methods[] = { + { + .ml_name = "comm", + .ml_meth = (PyCFunction)pyrf_thread__comm, + .ml_flags = METH_NOARGS, + .ml_doc = PyDoc_STR("Comm(and) associated with this thread.") + }, + { .ml_name = NULL, } +}; + +static PyObject *pyrf_thread__get_pid(struct pyrf_thread *pthread, void *closure __maybe_unused) +{ + return PyLong_FromLong(thread__pid(pthread->thread)); +} + +static PyObject *pyrf_thread__get_tid(struct pyrf_thread *pthread, void *closure __maybe_unused) +{ + return PyLong_FromLong(thread__tid(pthread->thread)); +} + +static PyObject *pyrf_thread__get_ppid(struct pyrf_thread *pthread, void *closure __maybe_unused) +{ + return PyLong_FromLong(thread__ppid(pthread->thread)); +} + +static PyObject *pyrf_thread__get_cpu(struct pyrf_thread *pthread, void *closure __maybe_unused) +{ + return PyLong_FromLong(thread__cpu(pthread->thread)); +} + +static PyGetSetDef pyrf_thread__getset[] = { + { .name = "pid", .get = (getter)pyrf_thread__get_pid, .doc = "process ID" }, + { .name = "tid", .get = (getter)pyrf_thread__get_tid, .doc = "thread ID" }, + { .name = "ppid", .get = (getter)pyrf_thread__get_ppid, .doc = "parent process ID" }, + { .name = "cpu", .get = (getter)pyrf_thread__get_cpu, .doc = "cpu number" }, + { .name = NULL } +}; + +static const char pyrf_thread__doc[] = PyDoc_STR("perf thread object."); + +static PyTypeObject pyrf_thread__type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "perf.thread", + .tp_basicsize = sizeof(struct pyrf_thread), + .tp_dealloc = (destructor)pyrf_thread__delete, + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_methods = pyrf_thread__methods, + .tp_getset = pyrf_thread__getset, + .tp_doc = pyrf_thread__doc, +}; + +static int pyrf_thread__setup_types(void) +{ + return PyType_Ready(&pyrf_thread__type); +} + +static PyObject *pyrf_thread__from_thread(struct thread *thread) +{ + struct pyrf_thread *pthread = PyObject_New(struct pyrf_thread, &pyrf_thread__type); + + if (!pthread) + return NULL; + + pthread->thread = thread__get(thread); + return (PyObject *)pthread; +} + +struct pyrf_session { + PyObject_HEAD + + struct perf_session *session; + struct perf_tool tool; + struct pyrf_data *pdata; + PyObject *sample; +}; + +static int pyrf_session_tool__sample(const struct perf_tool *tool, + union perf_event *event, + struct perf_sample *sample, + struct machine *machine __maybe_unused) +{ + struct pyrf_session *psession = container_of(tool, struct pyrf_session, tool); + PyObject *pyevent = pyrf_event__new(event); + struct pyrf_event *pevent = (struct pyrf_event *)pyevent; + PyObject *ret; + bool needs_swap; + + if (pyevent == NULL) + return -ENOMEM; + + needs_swap = sample->evsel->needs_swap; + + memcpy(&pevent->event, event, event->header.size); + /* The event is already swapped, disable swapping temporarily */ + sample->evsel->needs_swap = false; + if (evsel__parse_sample(sample->evsel, &pevent->event, &pevent->sample) < 0) { + sample->evsel->needs_swap = needs_swap; + Py_DECREF(pyevent); + return -1; + } + sample->evsel->needs_swap = needs_swap; + + ret = PyObject_CallFunction(psession->sample, "O", pyevent); + if (!ret) { + Py_DECREF(pyevent); + return -1; + } + Py_DECREF(ret); + Py_DECREF(pyevent); + return 0; +} + +static PyObject *pyrf_session__find_thread(struct pyrf_session *psession, PyObject *args) +{ + struct machine *machine; + struct thread *thread = NULL; + PyObject *result; + int pid; + + CHECK_INITIALIZED(psession->session, "session"); + + if (!PyArg_ParseTuple(args, "i", &pid)) + return NULL; + + machine = &psession->session->machines.host; + thread = machine__find_thread(machine, pid, pid); + + if (!thread) { + machine = perf_session__find_machine(psession->session, pid); + if (machine) + thread = machine__find_thread(machine, pid, pid); + } + + if (!thread) { + PyErr_Format(PyExc_TypeError, "Failed to find thread %d", pid); + return NULL; + } + result = pyrf_thread__from_thread(thread); + thread__put(thread); + return result; +} + +static PyObject *pyrf_session__new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + struct pyrf_data *pdata; + PyObject *sample = NULL; + static char *kwlist[] = { "data", "sample", NULL }; + struct pyrf_session *psession; + struct perf_session *session; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|O", kwlist, &pyrf_data__type, &pdata, + &sample)) + return NULL; + + psession = PyObject_New(struct pyrf_session, type); + if (!psession) + return NULL; + + psession->session = NULL; + psession->sample = NULL; + psession->pdata = NULL; + + Py_INCREF(pdata); + psession->pdata = pdata; + + perf_tool__init(&psession->tool, /*ordered_events=*/true); + psession->tool.ordering_requires_timestamps = true; + + #define ADD_TOOL(name) \ + do { \ + if (name) { \ + if (!PyCallable_Check(name)) { \ + PyErr_SetString(PyExc_TypeError, #name " must be callable"); \ + goto err_out; \ + } \ + psession->tool.name = pyrf_session_tool__##name; \ + Py_INCREF(name); \ + psession->name = name; \ + } \ + } while (0) + + ADD_TOOL(sample); + #undef ADD_TOOL + + psession->tool.comm = perf_event__process_comm; + psession->tool.mmap = perf_event__process_mmap; + psession->tool.mmap2 = perf_event__process_mmap2; + psession->tool.namespaces = perf_event__process_namespaces; + psession->tool.cgroup = perf_event__process_cgroup; + psession->tool.exit = perf_event__process_exit; + psession->tool.fork = perf_event__process_fork; + psession->tool.ksymbol = perf_event__process_ksymbol; + psession->tool.text_poke = perf_event__process_text_poke; + psession->tool.build_id = perf_event__process_build_id; + psession->tool.attr = perf_event__process_attr; + psession->tool.feature = perf_event__process_feature; + psession->tool.stat = perf_event__process_stat_event; + session = perf_session__new(&pdata->data, &psession->tool); + if (IS_ERR(session)) { + PyErr_Format(PyExc_IOError, "failed to create session: %ld", PTR_ERR(session)); + goto err_out; + } + psession->session = session; + + if (symbol__init(perf_session__env(session)) < 0) { + PyErr_SetString(PyExc_OSError, "perf: symbol__init failed"); + goto err_out; + } + + + + return (PyObject *)psession; +err_out: + Py_DECREF(psession); + return NULL; +} + +static void pyrf_session__delete(struct pyrf_session *psession) +{ + perf_session__delete(psession->session); + Py_XDECREF(psession->pdata); + Py_XDECREF(psession->sample); + Py_TYPE(psession)->tp_free((PyObject *)psession); +} + +static PyObject *pyrf_session__find_thread_events(struct pyrf_session *psession) +{ + int err; + + CHECK_INITIALIZED(psession->session, "session"); + + err = perf_session__process_events(psession->session); + + if (PyErr_Occurred()) + return NULL; + + if (err < 0) { + PyErr_Format(PyExc_OSError, "Process events failed: %d", err); + return NULL; + } + + Py_RETURN_NONE; +} + +static PyMethodDef pyrf_session__methods[] = { + { + .ml_name = "process_events", + .ml_meth = (PyCFunction)pyrf_session__find_thread_events, + .ml_flags = METH_NOARGS, + .ml_doc = PyDoc_STR("Iterate and process events.") + }, + { + .ml_name = "find_thread", + .ml_meth = (PyCFunction)pyrf_session__find_thread, + .ml_flags = METH_VARARGS, + .ml_doc = PyDoc_STR("Returns the thread associated with a pid.") + }, + { .ml_name = NULL, } +}; + +static const char pyrf_session__doc[] = PyDoc_STR("perf session object."); + +static PyObject *pyrf_session__getattro(struct pyrf_session *psession, PyObject *attr_name) +{ + if (!psession->session) { + PyErr_SetString(PyExc_ValueError, "session not initialized"); + return NULL; + } + return PyObject_GenericGetAttr((PyObject *) psession, attr_name); +} + +static int pyrf_session__setattro(struct pyrf_session *psession, PyObject *attr_name, + PyObject *value) +{ + if (!psession->session) { + PyErr_SetString(PyExc_ValueError, "session not initialized"); + return -1; + } + return PyObject_GenericSetAttr((PyObject *) psession, attr_name, value); +} + +static PyTypeObject pyrf_session__type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "perf.session", + .tp_basicsize = sizeof(struct pyrf_session), + .tp_dealloc = (destructor)pyrf_session__delete, + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_methods = pyrf_session__methods, + .tp_doc = pyrf_session__doc, + .tp_new = pyrf_session__new, + .tp_getattro = (getattrofunc) pyrf_session__getattro, + .tp_setattro = (setattrofunc) pyrf_session__setattro, +}; + +static int pyrf_session__setup_types(void) +{ + return PyType_Ready(&pyrf_session__type); +} + static PyMethodDef perf__methods[] = { { .ml_name = "metrics", @@ -2633,8 +2967,10 @@ PyMODINIT_FUNC PyInit_perf(void) }; PyObject *module = PyModule_Create(&moduledef); - if (module == NULL || - pyrf_event__setup_types() < 0 || + if (module == NULL) + return NULL; + + if (pyrf_event__setup_types() < 0 || pyrf_evlist__setup_types() < 0 || pyrf_evsel__setup_types() < 0 || pyrf_thread_map__setup_types() < 0 || @@ -2642,8 +2978,12 @@ PyMODINIT_FUNC PyInit_perf(void) pyrf_pmu_iterator__setup_types() < 0 || pyrf_pmu__setup_types() < 0 || pyrf_counts_values__setup_types() < 0 || - pyrf_data__setup_types() < 0) - return module; + pyrf_data__setup_types() < 0 || + pyrf_session__setup_types() < 0 || + pyrf_thread__setup_types() < 0) { + Py_DECREF(module); + return NULL; + } /* The page_size is placed in util object. */ page_size = sysconf(_SC_PAGE_SIZE); @@ -2693,6 +3033,9 @@ PyMODINIT_FUNC PyInit_perf(void) Py_INCREF(&pyrf_data__type); PyModule_AddObject(module, "data", (PyObject *)&pyrf_data__type); + Py_INCREF(&pyrf_session__type); + PyModule_AddObject(module, "session", (PyObject *)&pyrf_session__type); + dict = PyModule_GetDict(module); if (dict == NULL) goto error; @@ -2706,7 +3049,9 @@ PyMODINIT_FUNC PyInit_perf(void) } error: - if (PyErr_Occurred()) - PyErr_SetString(PyExc_ImportError, "perf: Init failed!"); + if (PyErr_Occurred()) { + Py_XDECREF(module); + return NULL; + } return module; } -- cgit v1.2.3 From 600a22ef7eb5520a98e63f3640065cb9397139c2 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:33 -0700 Subject: perf python: Refactor and add accessors to sample event Add common evsel field for events and move sample specific fields to only be present in sample events. Add accessors for sample events. Ensure offsets are within the bounds of the event. Allocate just enough memory for the copied event, don't make the maximum event size each time. Assisted-by: Gemini:gemini-3.1-pro-preview Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/python.c | 519 +++++++++++++++++++++++++++++++++++++--------- tools/perf/util/session.c | 2 +- tools/perf/util/session.h | 2 + 3 files changed, 429 insertions(+), 94 deletions(-) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index dc71fe7e3787..72d297156ad0 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -13,21 +13,28 @@ #include #include +#include "addr_location.h" +#include "build-id.h" #include "callchain.h" #include "comm.h" #include "counts.h" #include "data.h" #include "debug.h" +#include "dso.h" #include "event.h" #include "evlist.h" #include "evsel.h" #include "expr.h" +#include "map.h" #include "metricgroup.h" #include "mmap.h" #include "pmus.h" #include "print_binary.h" #include "record.h" +#include "sample.h" #include "session.h" +#include "srccode.h" +#include "srcline.h" #include "strbuf.h" #include "symbol.h" #include "stat.h" @@ -37,7 +44,6 @@ #include "tool.h" #include "tp_pmu.h" #include "trace-event.h" -#include "util/sample.h" #ifdef HAVE_LIBTRACEEVENT #include @@ -45,6 +51,8 @@ PyMODINIT_FUNC PyInit_perf(void); +static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel); + #define member_def(type, member, ptype, help) \ { #member, ptype, \ offsetof(struct pyrf_event, event) + offsetof(struct type, member), \ @@ -73,21 +81,53 @@ PyMODINIT_FUNC PyInit_perf(void); struct pyrf_event { PyObject_HEAD + /** @sample: The parsed sample from the event. */ struct perf_sample sample; - union perf_event event; + /** @al: The address location from machine__resolve, lazily computed. */ + struct addr_location al; + /** @al_resolved: True when machine__resolve been called. */ + bool al_resolved; + /** @event: The underlying perf_event that may be in a file or ring buffer. */ + union perf_event event; }; #define sample_members \ - sample_member_def(sample_ip, ip, T_ULONGLONG, "event ip"), \ sample_member_def(sample_pid, pid, T_INT, "event pid"), \ sample_member_def(sample_tid, tid, T_INT, "event tid"), \ sample_member_def(sample_time, time, T_ULONGLONG, "event timestamp"), \ - sample_member_def(sample_addr, addr, T_ULONGLONG, "event addr"), \ sample_member_def(sample_id, id, T_ULONGLONG, "event id"), \ sample_member_def(sample_stream_id, stream_id, T_ULONGLONG, "event stream id"), \ sample_member_def(sample_period, period, T_ULONGLONG, "event period"), \ sample_member_def(sample_cpu, cpu, T_UINT, "event cpu"), +static PyObject *pyrf_event__get_evsel(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_event *pevent = (void *)self; + + if (!pevent->sample.evsel) + Py_RETURN_NONE; + + return pyrf_evsel__from_evsel(pevent->sample.evsel); +} + +static PyGetSetDef pyrf_event__getset[] = { + { + .name = "evsel", + .get = pyrf_event__get_evsel, + .set = NULL, + .doc = "tracking event.", + }, + { .name = NULL, }, +}; + +static void pyrf_event__delete(struct pyrf_event *pevent) +{ + if (pevent->al_resolved) + addr_location__exit(&pevent->al); + perf_sample__exit(&pevent->sample); + Py_TYPE(pevent)->tp_free((PyObject *)pevent); +} + static const char pyrf_mmap_event__doc[] = PyDoc_STR("perf mmap event object."); static PyMemberDef pyrf_mmap_event__members[] = { @@ -126,9 +166,11 @@ static PyTypeObject pyrf_mmap_event__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.mmap_event", .tp_basicsize = sizeof(struct pyrf_event), + .tp_dealloc = (destructor)pyrf_event__delete, .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, .tp_doc = pyrf_mmap_event__doc, .tp_members = pyrf_mmap_event__members, + .tp_getset = pyrf_event__getset, .tp_repr = (reprfunc)pyrf_mmap_event__repr, }; @@ -161,9 +203,11 @@ static PyTypeObject pyrf_task_event__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.task_event", .tp_basicsize = sizeof(struct pyrf_event), + .tp_dealloc = (destructor)pyrf_event__delete, .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, .tp_doc = pyrf_task_event__doc, .tp_members = pyrf_task_event__members, + .tp_getset = pyrf_event__getset, .tp_repr = (reprfunc)pyrf_task_event__repr, }; @@ -190,9 +234,11 @@ static PyTypeObject pyrf_comm_event__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.comm_event", .tp_basicsize = sizeof(struct pyrf_event), + .tp_dealloc = (destructor)pyrf_event__delete, .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, .tp_doc = pyrf_comm_event__doc, .tp_members = pyrf_comm_event__members, + .tp_getset = pyrf_event__getset, .tp_repr = (reprfunc)pyrf_comm_event__repr, }; @@ -222,9 +268,11 @@ static PyTypeObject pyrf_throttle_event__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.throttle_event", .tp_basicsize = sizeof(struct pyrf_event), + .tp_dealloc = (destructor)pyrf_event__delete, .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, .tp_doc = pyrf_throttle_event__doc, .tp_members = pyrf_throttle_event__members, + .tp_getset = pyrf_event__getset, .tp_repr = (reprfunc)pyrf_throttle_event__repr, }; @@ -232,6 +280,7 @@ static const char pyrf_lost_event__doc[] = PyDoc_STR("perf lost event object."); static PyMemberDef pyrf_lost_event__members[] = { sample_members + member_def(perf_event_header, type, T_UINT, "event type"), member_def(perf_record_lost, id, T_ULONGLONG, "event id"), member_def(perf_record_lost, lost, T_ULONGLONG, "number of lost events"), { .name = NULL, }, @@ -257,9 +306,11 @@ static PyTypeObject pyrf_lost_event__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.lost_event", .tp_basicsize = sizeof(struct pyrf_event), + .tp_dealloc = (destructor)pyrf_event__delete, .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, .tp_doc = pyrf_lost_event__doc, .tp_members = pyrf_lost_event__members, + .tp_getset = pyrf_event__getset, .tp_repr = (reprfunc)pyrf_lost_event__repr, }; @@ -267,6 +318,7 @@ static const char pyrf_read_event__doc[] = PyDoc_STR("perf read event object."); static PyMemberDef pyrf_read_event__members[] = { sample_members + member_def(perf_event_header, type, T_UINT, "event type"), member_def(perf_record_read, pid, T_UINT, "event pid"), member_def(perf_record_read, tid, T_UINT, "event tid"), { .name = NULL, }, @@ -287,9 +339,11 @@ static PyTypeObject pyrf_read_event__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.read_event", .tp_basicsize = sizeof(struct pyrf_event), + .tp_dealloc = (destructor)pyrf_event__delete, .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, .tp_doc = pyrf_read_event__doc, .tp_members = pyrf_read_event__members, + .tp_getset = pyrf_event__getset, .tp_repr = (reprfunc)pyrf_read_event__repr, }; @@ -297,16 +351,17 @@ static const char pyrf_sample_event__doc[] = PyDoc_STR("perf sample event object static PyMemberDef pyrf_sample_event__members[] = { sample_members + sample_member_def(sample_ip, ip, T_ULONGLONG, "event ip"), + sample_member_def(sample_addr, addr, T_ULONGLONG, "event addr"), + sample_member_def(sample_phys_addr, phys_addr, T_ULONGLONG, "event physical addr"), + sample_member_def(sample_weight, weight, T_ULONGLONG, "event weight"), + sample_member_def(sample_data_src, data_src, T_ULONGLONG, "event data source"), + sample_member_def(sample_insn_count, insn_cnt, T_ULONGLONG, "event instruction count"), + sample_member_def(sample_cyc_count, cyc_cnt, T_ULONGLONG, "event cycle count"), member_def(perf_event_header, type, T_UINT, "event type"), { .name = NULL, }, }; -static void pyrf_sample_event__delete(struct pyrf_event *pevent) -{ - perf_sample__exit(&pevent->sample); - Py_TYPE(pevent)->tp_free((PyObject *)pevent); -} - static PyObject *pyrf_sample_event__repr(const struct pyrf_event *pevent) { PyObject *ret; @@ -324,6 +379,8 @@ static PyObject *pyrf_sample_event__repr(const struct pyrf_event *pevent) #ifdef HAVE_LIBTRACEEVENT static bool is_tracepoint(const struct pyrf_event *pevent) { + if (!pevent->sample.evsel) + return false; return pevent->sample.evsel->core.attr.type == PERF_TYPE_TRACEPOINT; } @@ -394,6 +451,199 @@ get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name) } #endif /* HAVE_LIBTRACEEVENT */ +static int pyrf_sample_event__resolve_al(struct pyrf_event *pevent) +{ + struct evsel *evsel = pevent->sample.evsel; + struct evlist *evlist = evsel ? evsel->evlist : NULL; + struct perf_session *session = evlist ? evlist__session(evlist) : NULL; + + if (pevent->al_resolved) + return 0; + + if (!session) + return -1; + + addr_location__init(&pevent->al); + if (machine__resolve(&session->machines.host, &pevent->al, &pevent->sample) < 0) { + addr_location__exit(&pevent->al); + return -1; + } + + pevent->al_resolved = true; + return 0; +} + +static PyObject *pyrf_sample_event__get_dso(struct pyrf_event *pevent, + void *closure __maybe_unused) +{ + if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.map) + Py_RETURN_NONE; + + return PyUnicode_FromString(dso__name(map__dso(pevent->al.map))); +} + +static PyObject *pyrf_sample_event__get_dso_long_name(struct pyrf_event *pevent, + void *closure __maybe_unused) +{ + if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.map) + Py_RETURN_NONE; + + return PyUnicode_FromString(dso__long_name(map__dso(pevent->al.map))); +} + +static PyObject *pyrf_sample_event__get_dso_bid(struct pyrf_event *pevent, + void *closure __maybe_unused) +{ + char sbuild_id[SBUILD_ID_SIZE]; + + if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.map) + Py_RETURN_NONE; + + build_id__snprintf(dso__bid(map__dso(pevent->al.map)), sbuild_id, sizeof(sbuild_id)); + return PyUnicode_FromString(sbuild_id); +} + +static PyObject *pyrf_sample_event__get_map_start(struct pyrf_event *pevent, + void *closure __maybe_unused) +{ + if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.map) + Py_RETURN_NONE; + + return PyLong_FromUnsignedLong(map__start(pevent->al.map)); +} + +static PyObject *pyrf_sample_event__get_map_end(struct pyrf_event *pevent, + void *closure __maybe_unused) +{ + if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.map) + Py_RETURN_NONE; + + return PyLong_FromUnsignedLong(map__end(pevent->al.map)); +} + +static PyObject *pyrf_sample_event__get_map_pgoff(struct pyrf_event *pevent, + void *closure __maybe_unused) +{ + if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.map) + Py_RETURN_NONE; + + return PyLong_FromUnsignedLongLong(map__pgoff(pevent->al.map)); +} + +static PyObject *pyrf_sample_event__get_symbol(struct pyrf_event *pevent, + void *closure __maybe_unused) +{ + if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.sym) + Py_RETURN_NONE; + + return PyUnicode_FromString(pevent->al.sym->name); +} + +static PyObject *pyrf_sample_event__get_sym_start(struct pyrf_event *pevent, + void *closure __maybe_unused) +{ + if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.sym) + Py_RETURN_NONE; + + return PyLong_FromUnsignedLongLong(pevent->al.sym->start); +} + +static PyObject *pyrf_sample_event__get_sym_end(struct pyrf_event *pevent, + void *closure __maybe_unused) +{ + if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.sym) + Py_RETURN_NONE; + + return PyLong_FromUnsignedLongLong(pevent->al.sym->end); +} + +static PyObject *pyrf_sample_event__get_raw_buf(struct pyrf_event *pevent, + void *closure __maybe_unused) +{ + if (pevent->event.header.type != PERF_RECORD_SAMPLE) + Py_RETURN_NONE; + + return PyBytes_FromStringAndSize((const char *)pevent->sample.raw_data, + pevent->sample.raw_size); +} + +static PyObject *pyrf_sample_event__srccode(PyObject *self, PyObject *args) +{ + struct pyrf_event *pevent = (void *)self; + u64 addr = pevent->sample.ip; + char *srcfile = NULL; + char *srccode = NULL; + unsigned int line = 0; + int len = 0; + PyObject *result; + struct addr_location al; + + if (!PyArg_ParseTuple(args, "|K", &addr)) + return NULL; + + if (pyrf_sample_event__resolve_al(pevent) < 0) + Py_RETURN_NONE; + + if (addr != pevent->sample.ip) { + addr_location__init(&al); + thread__find_symbol_fb(pevent->al.thread, pevent->sample.cpumode, addr, &al); + } else { + addr_location__init(&al); + al.thread = thread__get(pevent->al.thread); + al.map = map__get(pevent->al.map); + al.sym = pevent->al.sym; + al.addr = pevent->al.addr; + } + + if (al.map) { + struct dso *dso = map__dso(al.map); + + if (dso) { + srcfile = get_srcline_split(dso, map__rip_2objdump(al.map, addr), + &line); + } + } + addr_location__exit(&al); + + if (srcfile) { + srccode = find_sourceline(srcfile, line, &len); + result = Py_BuildValue("(sIs#)", srcfile, line, srccode, (Py_ssize_t)len); + free(srcfile); + } else { + result = Py_BuildValue("(sIs#)", NULL, 0, NULL, (Py_ssize_t)0); + } + + return result; +} + +static PyObject *pyrf_sample_event__insn(PyObject *self, PyObject *args __maybe_unused) +{ + struct pyrf_event *pevent = (void *)self; + struct thread *thread; + struct machine *machine; + + if (pyrf_sample_event__resolve_al(pevent) < 0) + Py_RETURN_NONE; + + thread = pevent->al.thread; + + if (!thread || !thread__maps(thread)) + Py_RETURN_NONE; + + machine = maps__machine(thread__maps(thread)); + if (!machine) + Py_RETURN_NONE; + + if (pevent->sample.ip && !pevent->sample.insn_len) + perf_sample__fetch_insn(&pevent->sample, thread, machine); + + if (!pevent->sample.insn_len) + Py_RETURN_NONE; + + return PyBytes_FromStringAndSize((const char *)pevent->sample.insn, + pevent->sample.insn_len); +} + static PyObject* pyrf_sample_event__getattro(struct pyrf_event *pevent, PyObject *attr_name) { @@ -407,13 +657,102 @@ pyrf_sample_event__getattro(struct pyrf_event *pevent, PyObject *attr_name) return obj ?: PyObject_GenericGetAttr((PyObject *) pevent, attr_name); } +static PyGetSetDef pyrf_sample_event__getset[] = { + { + .name = "raw_buf", + .get = (getter)pyrf_sample_event__get_raw_buf, + .set = NULL, + .doc = "event raw buffer.", + }, + { + .name = "evsel", + .get = pyrf_event__get_evsel, + .set = NULL, + .doc = "tracking event.", + }, + { + .name = "dso", + .get = (getter)pyrf_sample_event__get_dso, + .set = NULL, + .doc = "event dso short name.", + }, + { + .name = "dso_long_name", + .get = (getter)pyrf_sample_event__get_dso_long_name, + .set = NULL, + .doc = "event dso long name.", + }, + { + .name = "dso_bid", + .get = (getter)pyrf_sample_event__get_dso_bid, + .set = NULL, + .doc = "event dso build id.", + }, + { + .name = "map_start", + .get = (getter)pyrf_sample_event__get_map_start, + .set = NULL, + .doc = "event map start address.", + }, + { + .name = "map_end", + .get = (getter)pyrf_sample_event__get_map_end, + .set = NULL, + .doc = "event map end address.", + }, + { + .name = "map_pgoff", + .get = (getter)pyrf_sample_event__get_map_pgoff, + .set = NULL, + .doc = "event map page offset.", + }, + { + .name = "symbol", + .get = (getter)pyrf_sample_event__get_symbol, + .set = NULL, + .doc = "event symbol name.", + }, + { + .name = "sym_start", + .get = (getter)pyrf_sample_event__get_sym_start, + .set = NULL, + .doc = "event symbol start address.", + }, + { + .name = "sym_end", + .get = (getter)pyrf_sample_event__get_sym_end, + .set = NULL, + .doc = "event symbol end address.", + }, + { .name = NULL, }, +}; + +static PyMethodDef pyrf_sample_event__methods[] = { + { + .ml_name = "srccode", + .ml_meth = (PyCFunction)pyrf_sample_event__srccode, + .ml_flags = METH_VARARGS, + .ml_doc = PyDoc_STR("Get source code for an address.") + }, + { + .ml_name = "insn", + .ml_meth = (PyCFunction)pyrf_sample_event__insn, + .ml_flags = METH_NOARGS, + .ml_doc = PyDoc_STR("Get instruction bytes for a sample.") + }, + { .ml_name = NULL, } +}; + static PyTypeObject pyrf_sample_event__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.sample_event", .tp_basicsize = sizeof(struct pyrf_event), + .tp_dealloc = (destructor)pyrf_event__delete, .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, .tp_doc = pyrf_sample_event__doc, .tp_members = pyrf_sample_event__members, + .tp_getset = pyrf_sample_event__getset, + .tp_methods = pyrf_sample_event__methods, .tp_repr = (reprfunc)pyrf_sample_event__repr, .tp_getattro = (getattrofunc) pyrf_sample_event__getattro, }; @@ -449,25 +788,17 @@ static PyTypeObject pyrf_context_switch_event__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.context_switch_event", .tp_basicsize = sizeof(struct pyrf_event), + .tp_dealloc = (destructor)pyrf_event__delete, .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, .tp_doc = pyrf_context_switch_event__doc, .tp_members = pyrf_context_switch_event__members, + .tp_getset = pyrf_event__getset, .tp_repr = (reprfunc)pyrf_context_switch_event__repr, }; static int pyrf_event__setup_types(void) { int err; - pyrf_mmap_event__type.tp_new = - pyrf_task_event__type.tp_new = - pyrf_comm_event__type.tp_new = - pyrf_lost_event__type.tp_new = - pyrf_read_event__type.tp_new = - pyrf_sample_event__type.tp_new = - pyrf_context_switch_event__type.tp_new = - pyrf_throttle_event__type.tp_new = PyType_GenericNew; - - pyrf_sample_event__type.tp_dealloc = (destructor)pyrf_sample_event__delete, err = PyType_Ready(&pyrf_mmap_event__type); if (err < 0) @@ -511,33 +842,57 @@ static PyTypeObject *pyrf_event__type[] = { [PERF_RECORD_SWITCH_CPU_WIDE] = &pyrf_context_switch_event__type, }; -static PyObject *pyrf_event__new(const union perf_event *event) +static PyObject *pyrf_event__new(const union perf_event *event, struct evsel *evsel) { struct pyrf_event *pevent; - PyTypeObject *ptype; + int err; + u32 min_size; + bool needs_swap; - if ((event->header.type < PERF_RECORD_MMAP || - event->header.type > PERF_RECORD_SAMPLE) && - !(event->header.type == PERF_RECORD_SWITCH || - event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)) { - PyErr_Format(PyExc_TypeError, "Unexpected header type %u", + if (event->header.type >= ARRAY_SIZE(pyrf_event__type) || + pyrf_event__type[event->header.type] == NULL) { + return PyErr_Format(PyExc_TypeError, "Unexpected header type %u", event->header.type); - return NULL; } - // FIXME this better be dynamic or we need to parse everything - // before calling perf_mmap__consume(), including tracepoint fields. - if (sizeof(pevent->event) < event->header.size) { - PyErr_Format(PyExc_TypeError, "Unexpected event size: %zd < %u", - sizeof(pevent->event), event->header.size); - return NULL; + if (perf_event__too_small(event, &min_size)) { + return PyErr_Format(PyExc_ValueError, "Event size %u too small for type %u", + event->header.size, event->header.type); } - ptype = pyrf_event__type[event->header.type]; - pevent = PyObject_New(struct pyrf_event, ptype); - if (pevent != NULL) { - memcpy(&pevent->event, event, event->header.size); - perf_sample__init(&pevent->sample, /*all=*/false); + size_t copy_size = event->header.size; + + if (copy_size > sizeof(pevent->event)) { + return PyErr_Format(PyExc_TypeError, "Unexpected event size: %zd < %zu", + sizeof(pevent->event), copy_size); + } + + pevent = PyObject_New(struct pyrf_event, pyrf_event__type[event->header.type]); + if (pevent == NULL) + return PyErr_NoMemory(); + + /* Copy the event for memory safety and initialize variables. */ + memcpy(&pevent->event, event, copy_size); + if (copy_size < sizeof(pevent->event)) + memset((char *)&pevent->event + copy_size, 0, sizeof(pevent->event) - copy_size); + + perf_sample__init(&pevent->sample, /*all=*/true); + pevent->al_resolved = false; + addr_location__init(&pevent->al); + + if (!evsel) + return (PyObject *)pevent; + + /* Parse the sample again so that pointers are within the copied event. */ + needs_swap = evsel->needs_swap; + + evsel->needs_swap = false; + err = evsel__parse_sample(evsel, &pevent->event, &pevent->sample); + evsel->needs_swap = needs_swap; + if (err < 0) { + Py_DECREF(pevent); + return PyErr_Format(PyExc_OSError, + "perf: can't parse sample, err=%d", err); } return (PyObject *)pevent; } @@ -1244,7 +1599,7 @@ static PyObject *pyrf_evsel__str(PyObject *self) if (!evsel) return PyUnicode_FromString("evsel(uninitialized)"); - return PyUnicode_FromFormat("evsel(%s/%s/)", evsel__pmu_name(evsel), evsel__name(evsel)); + return PyUnicode_FromFormat("evsel(%s)", evsel__name(evsel)); } static PyMethodDef pyrf_evsel__methods[] = { @@ -1878,9 +2233,11 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, { struct evlist *evlist; union perf_event *event; + struct evsel *evsel; int sample_id_all = 1, cpu; static char *kwlist[] = { "cpu", "sample_id_all", NULL }; struct mmap *md; + PyObject *pyevent; int err; CHECK_INITIALIZED(pevlist->evlist, "evlist"); @@ -1891,44 +2248,33 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, return NULL; md = get_md(evlist, cpu); - if (!md) { - PyErr_Format(PyExc_TypeError, "Unknown CPU '%d'", cpu); - return NULL; - } + if (!md) + return PyErr_Format(PyExc_TypeError, "Unknown CPU '%d'", cpu); - if (perf_mmap__read_init(&md->core) < 0) - goto end; + err = perf_mmap__read_init(&md->core); + if (err < 0) { + if (err == -EAGAIN) + Py_RETURN_NONE; + return PyErr_Format(PyExc_OSError, + "perf: error mmap read init, err=%d", err); + } event = perf_mmap__read_event(&md->core); - if (event != NULL) { - PyObject *pyevent = pyrf_event__new(event); - struct pyrf_event *pevent = (struct pyrf_event *)pyevent; - struct evsel *evsel; - - if (pyevent == NULL) - return PyErr_NoMemory(); - - evsel = evlist__event2evsel(evlist, event); - if (!evsel) { - Py_DECREF(pyevent); - Py_INCREF(Py_None); - return Py_None; - } + if (event == NULL) + Py_RETURN_NONE; + evsel = evlist__event2evsel(evlist, event); + if (!evsel) { + /* Unknown evsel. */ perf_mmap__consume(&md->core); - - err = evsel__parse_sample(evsel, &pevent->event, &pevent->sample); - if (err) { - Py_DECREF(pyevent); - return PyErr_Format(PyExc_OSError, - "perf: can't parse sample, err=%d", err); - } - - return pyevent; + Py_RETURN_NONE; } -end: - Py_INCREF(Py_None); - return Py_None; + pyevent = pyrf_event__new(event, evsel); + perf_mmap__consume(&md->core); + if (pyevent == NULL) + return PyErr_Occurred() ? NULL : PyErr_NoMemory(); + + return pyevent; } static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist, @@ -2140,10 +2486,7 @@ static PyObject *pyrf_evlist__str(PyObject *self) evlist__for_each_entry(pevlist->evlist, pos) { if (!first) strbuf_addch(&sb, ','); - if (!pos->pmu) - strbuf_addstr(&sb, evsel__name(pos)); - else - strbuf_addf(&sb, "%s/%s/", pos->pmu->name, evsel__name(pos)); + strbuf_addstr(&sb, evsel__name(pos)); first = false; } strbuf_addstr(&sb, "])"); @@ -2225,6 +2568,7 @@ static const struct perf_constant perf__constants[] = { PERF_CONST(TYPE_BREAKPOINT), PERF_CONST(COUNT_HW_CPU_CYCLES), + PERF_CONST(COUNT_HW_REF_CPU_CYCLES), PERF_CONST(COUNT_HW_INSTRUCTIONS), PERF_CONST(COUNT_HW_CACHE_REFERENCES), PERF_CONST(COUNT_HW_CACHE_MISSES), @@ -2696,26 +3040,12 @@ static int pyrf_session_tool__sample(const struct perf_tool *tool, struct machine *machine __maybe_unused) { struct pyrf_session *psession = container_of(tool, struct pyrf_session, tool); - PyObject *pyevent = pyrf_event__new(event); - struct pyrf_event *pevent = (struct pyrf_event *)pyevent; + PyObject *pyevent = pyrf_event__new(event, sample->evsel); PyObject *ret; - bool needs_swap; if (pyevent == NULL) return -ENOMEM; - needs_swap = sample->evsel->needs_swap; - - memcpy(&pevent->event, event, event->header.size); - /* The event is already swapped, disable swapping temporarily */ - sample->evsel->needs_swap = false; - if (evsel__parse_sample(sample->evsel, &pevent->event, &pevent->sample) < 0) { - sample->evsel->needs_swap = needs_swap; - Py_DECREF(pyevent); - return -1; - } - sample->evsel->needs_swap = needs_swap; - ret = PyObject_CallFunction(psession->sample, "O", pyevent); if (!ret) { Py_DECREF(pyevent); @@ -2989,10 +3319,13 @@ PyMODINIT_FUNC PyInit_perf(void) page_size = sysconf(_SC_PAGE_SIZE); Py_INCREF(&pyrf_evlist__type); - PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type); + PyModule_AddObject(module, "evlist", (PyObject *)&pyrf_evlist__type); Py_INCREF(&pyrf_evsel__type); - PyModule_AddObject(module, "evsel", (PyObject*)&pyrf_evsel__type); + PyModule_AddObject(module, "evsel", (PyObject *)&pyrf_evsel__type); + + Py_INCREF(&pyrf_thread__type); + PyModule_AddObject(module, "thread", (PyObject *)&pyrf_thread__type); Py_INCREF(&pyrf_mmap_event__type); PyModule_AddObject(module, "mmap_event", (PyObject *)&pyrf_mmap_event__type); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 4129e15e4654..3237870a1a34 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -2673,7 +2673,7 @@ static const u32 perf_event__min_size[PERF_RECORD_HEADER_MAX] = { * Caller must ensure event->header.type < PERF_RECORD_HEADER_MAX. * If min is non-NULL, stores the required minimum on failure. */ -static bool perf_event__too_small(const union perf_event *event, u32 *min) +bool perf_event__too_small(const union perf_event *event, u32 *min) { u32 min_sz = perf_event__min_size[event->header.type]; diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index d554e2a1a50e..ac5803d5fb4e 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -122,6 +122,8 @@ void perf_session__delete(struct perf_session *session); void perf_event_header__bswap(struct perf_event_header *hdr); +bool perf_event__too_small(const union perf_event *event, u32 *min); + int perf_session__peek_event(struct perf_session *session, off_t file_offset, void *buf, size_t buf_sz, union perf_event **event_ptr, -- cgit v1.2.3 From 64344eee2d7825c6465638d5cd0d22ca57d5eead Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:34 -0700 Subject: perf python: Add mmap2 event If mmap is handled so should mmap2 events. Add support as a distinct python event type. Assisted-by: Gemini:gemini-3.1-pro-preview Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/python.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 72d297156ad0..1d27df207cc5 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -133,7 +133,7 @@ static const char pyrf_mmap_event__doc[] = PyDoc_STR("perf mmap event object."); static PyMemberDef pyrf_mmap_event__members[] = { sample_members member_def(perf_event_header, type, T_UINT, "event type"), - member_def(perf_event_header, misc, T_UINT, "event misc"), + member_def(perf_event_header, misc, T_USHORT, "event misc"), member_def(perf_record_mmap, pid, T_UINT, "event pid"), member_def(perf_record_mmap, tid, T_UINT, "event tid"), member_def(perf_record_mmap, start, T_ULONGLONG, "start of the map"), @@ -174,6 +174,147 @@ static PyTypeObject pyrf_mmap_event__type = { .tp_repr = (reprfunc)pyrf_mmap_event__repr, }; +static const char pyrf_mmap2_event__doc[] = PyDoc_STR("perf mmap2 event object."); + +static PyObject *pyrf_mmap2_event__get_maj(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_event *pevent = (void *)self; + + if (pevent->event.header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) + Py_RETURN_NONE; + + return PyLong_FromUnsignedLong(pevent->event.mmap2.maj); +} + +static PyObject *pyrf_mmap2_event__get_min(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_event *pevent = (void *)self; + + if (pevent->event.header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) + Py_RETURN_NONE; + + return PyLong_FromUnsignedLong(pevent->event.mmap2.min); +} + +static PyObject *pyrf_mmap2_event__get_ino(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_event *pevent = (void *)self; + + if (pevent->event.header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) + Py_RETURN_NONE; + + return PyLong_FromUnsignedLongLong(pevent->event.mmap2.ino); +} + +static PyObject *pyrf_mmap2_event__get_ino_generation(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_event *pevent = (void *)self; + + if (pevent->event.header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) + Py_RETURN_NONE; + + return PyLong_FromUnsignedLongLong(pevent->event.mmap2.ino_generation); +} + +static PyObject *pyrf_mmap2_event__get_build_id(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_event *pevent = (void *)self; + + if (!(pevent->event.header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID)) + Py_RETURN_NONE; + + int size = pevent->event.mmap2.build_id_size; + + if (size > 20) + size = 20; + + return PyBytes_FromStringAndSize((const char *)pevent->event.mmap2.build_id, size); +} + +static PyGetSetDef pyrf_mmap2_event__getset[] = { + { + .name = "evsel", + .get = pyrf_event__get_evsel, + .set = NULL, + .doc = "tracking event.", + }, + { + .name = "maj", + .get = pyrf_mmap2_event__get_maj, + .set = NULL, + .doc = "major number.", + }, + { + .name = "min", + .get = pyrf_mmap2_event__get_min, + .set = NULL, + .doc = "minor number.", + }, + { + .name = "ino", + .get = pyrf_mmap2_event__get_ino, + .set = NULL, + .doc = "inode number.", + }, + { + .name = "ino_generation", + .get = pyrf_mmap2_event__get_ino_generation, + .set = NULL, + .doc = "inode generation.", + }, + { + .name = "build_id", + .get = pyrf_mmap2_event__get_build_id, + .set = NULL, + .doc = "binary build ID.", + }, + { .name = NULL, }, +}; + +static PyMemberDef pyrf_mmap2_event__members[] = { + sample_members + member_def(perf_event_header, type, T_UINT, "event type"), + member_def(perf_event_header, misc, T_USHORT, "event misc"), + member_def(perf_record_mmap2, pid, T_UINT, "event pid"), + member_def(perf_record_mmap2, tid, T_UINT, "event tid"), + member_def(perf_record_mmap2, start, T_ULONGLONG, "start of the map"), + member_def(perf_record_mmap2, len, T_ULONGLONG, "map length"), + member_def(perf_record_mmap2, pgoff, T_ULONGLONG, "page offset"), + member_def(perf_record_mmap2, prot, T_UINT, "protection"), + member_def(perf_record_mmap2, flags, T_UINT, "flags"), + member_def(perf_record_mmap2, filename, T_STRING_INPLACE, "backing store"), + { .name = NULL, }, +}; + +static PyObject *pyrf_mmap2_event__repr(const struct pyrf_event *pevent) +{ + PyObject *ret; + char *s; + + if (asprintf(&s, "{ type: mmap2, pid: %u, tid: %u, start: %#" PRI_lx64 ", length: %#" PRI_lx64 ", offset: %#" PRI_lx64 ", flags: %#x, prot: %#x, filename: %s }", + pevent->event.mmap2.pid, pevent->event.mmap2.tid, + pevent->event.mmap2.start, pevent->event.mmap2.len, + pevent->event.mmap2.pgoff, pevent->event.mmap2.flags, + pevent->event.mmap2.prot, pevent->event.mmap2.filename) < 0) + return PyErr_NoMemory(); + + ret = PyUnicode_FromString(s); + free(s); + return ret; +} + +static PyTypeObject pyrf_mmap2_event__type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "perf.mmap2_event", + .tp_basicsize = sizeof(struct pyrf_event), + .tp_dealloc = (destructor)pyrf_event__delete, + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_doc = pyrf_mmap2_event__doc, + .tp_members = pyrf_mmap2_event__members, + .tp_getset = pyrf_mmap2_event__getset, + .tp_repr = (reprfunc)pyrf_mmap2_event__repr, +}; + static const char pyrf_task_event__doc[] = PyDoc_STR("perf task (fork/exit) event object."); static PyMemberDef pyrf_task_event__members[] = { @@ -801,6 +942,9 @@ static int pyrf_event__setup_types(void) int err; err = PyType_Ready(&pyrf_mmap_event__type); + if (err < 0) + goto out; + err = PyType_Ready(&pyrf_mmap2_event__type); if (err < 0) goto out; err = PyType_Ready(&pyrf_lost_event__type); @@ -830,6 +974,7 @@ out: static PyTypeObject *pyrf_event__type[] = { [PERF_RECORD_MMAP] = &pyrf_mmap_event__type, + [PERF_RECORD_MMAP2] = &pyrf_mmap2_event__type, [PERF_RECORD_LOST] = &pyrf_lost_event__type, [PERF_RECORD_COMM] = &pyrf_comm_event__type, [PERF_RECORD_EXIT] = &pyrf_task_event__type, @@ -876,6 +1021,9 @@ static PyObject *pyrf_event__new(const union perf_event *event, struct evsel *ev if (copy_size < sizeof(pevent->event)) memset((char *)&pevent->event + copy_size, 0, sizeof(pevent->event) - copy_size); + if (event->header.type == PERF_RECORD_MMAP2) + pevent->event.mmap2.filename[sizeof(pevent->event.mmap2.filename) - 1] = '\0'; + perf_sample__init(&pevent->sample, /*all=*/true); pevent->al_resolved = false; addr_location__init(&pevent->al); @@ -3330,6 +3478,9 @@ PyMODINIT_FUNC PyInit_perf(void) Py_INCREF(&pyrf_mmap_event__type); PyModule_AddObject(module, "mmap_event", (PyObject *)&pyrf_mmap_event__type); + Py_INCREF(&pyrf_mmap2_event__type); + PyModule_AddObject(module, "mmap2_event", (PyObject *)&pyrf_mmap2_event__type); + Py_INCREF(&pyrf_lost_event__type); PyModule_AddObject(module, "lost_event", (PyObject *)&pyrf_lost_event__type); -- cgit v1.2.3 From 88439191ad5e779cf7f957491c3c807d65d7a8ad Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:35 -0700 Subject: perf python: Add callchain support Implement pyrf_callchain_node and pyrf_callchain types for lazy iteration over callchain frames. Add callchain property to sample_event. Assisted-by: Gemini:gemini-3.1-pro-preview Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/python.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 217 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 1d27df207cc5..01369d8b3e65 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -87,6 +87,8 @@ struct pyrf_event { struct addr_location al; /** @al_resolved: True when machine__resolve been called. */ bool al_resolved; + /** @callchain: Resolved callchain, eagerly computed if requested. */ + PyObject *callchain; /** @event: The underlying perf_event that may be in a file or ring buffer. */ union perf_event event; }; @@ -124,6 +126,7 @@ static void pyrf_event__delete(struct pyrf_event *pevent) { if (pevent->al_resolved) addr_location__exit(&pevent->al); + Py_XDECREF(pevent->callchain); perf_sample__exit(&pevent->sample); Py_TYPE(pevent)->tp_free((PyObject *)pevent); } @@ -785,6 +788,144 @@ static PyObject *pyrf_sample_event__insn(PyObject *self, PyObject *args __maybe_ pevent->sample.insn_len); } +struct pyrf_callchain_node { + PyObject_HEAD + u64 ip; + struct map *map; + struct symbol *sym; +}; + +static void pyrf_callchain_node__delete(struct pyrf_callchain_node *pnode) +{ + map__put(pnode->map); + Py_TYPE(pnode)->tp_free((PyObject *)pnode); +} + +static PyObject *pyrf_callchain_node__get_ip(struct pyrf_callchain_node *pnode, + void *closure __maybe_unused) +{ + return PyLong_FromUnsignedLongLong(pnode->ip); +} + +static PyObject *pyrf_callchain_node__get_symbol(struct pyrf_callchain_node *pnode, + void *closure __maybe_unused) +{ + if (pnode->sym) + return PyUnicode_FromString(pnode->sym->name); + return PyUnicode_FromString("[unknown]"); +} + +static PyObject *pyrf_callchain_node__get_dso(struct pyrf_callchain_node *pnode, + void *closure __maybe_unused) +{ + const char *dsoname = "[unknown]"; + + if (pnode->map) { + struct dso *dso = map__dso(pnode->map); + + if (dso) { + if (symbol_conf.show_kernel_path && dso__long_name(dso)) + dsoname = dso__long_name(dso); + else + dsoname = dso__name(dso); + } + } + return PyUnicode_FromString(dsoname); +} + +static PyGetSetDef pyrf_callchain_node__getset[] = { + { .name = "ip", .get = (getter)pyrf_callchain_node__get_ip, }, + { .name = "symbol", .get = (getter)pyrf_callchain_node__get_symbol, }, + { .name = "dso", .get = (getter)pyrf_callchain_node__get_dso, }, + { .name = NULL, }, +}; + +static PyTypeObject pyrf_callchain_node__type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "perf.callchain_node", + .tp_basicsize = sizeof(struct pyrf_callchain_node), + .tp_dealloc = (destructor)pyrf_callchain_node__delete, + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_doc = "perf callchain node object.", + .tp_getset = pyrf_callchain_node__getset, +}; + +struct pyrf_callchain_frame { + u64 ip; + struct map *map; + struct symbol *sym; +}; + +struct pyrf_callchain { + PyObject_HEAD + struct pyrf_callchain_frame *frames; + u64 nr_frames; +}; + +static void pyrf_callchain__delete(struct pyrf_callchain *pchain) +{ + if (pchain->frames) { + for (u64 i = 0; i < pchain->nr_frames; i++) + map__put(pchain->frames[i].map); + free(pchain->frames); + } + Py_TYPE(pchain)->tp_free((PyObject *)pchain); +} + +static Py_ssize_t pyrf_callchain__length(PyObject *obj) +{ + struct pyrf_callchain *pchain = (void *)obj; + + return pchain->nr_frames; +} + +static PyObject *pyrf_callchain__item(PyObject *obj, Py_ssize_t i) +{ + struct pyrf_callchain *pchain = (void *)obj; + struct pyrf_callchain_node *pnode; + + if (i < 0 || i >= (Py_ssize_t)pchain->nr_frames) { + PyErr_SetString(PyExc_IndexError, "Index out of range"); + return NULL; + } + + pnode = PyObject_New(struct pyrf_callchain_node, &pyrf_callchain_node__type); + if (!pnode) + return NULL; + + pnode->ip = pchain->frames[i].ip; + pnode->map = map__get(pchain->frames[i].map); + pnode->sym = pchain->frames[i].sym; + + return (PyObject *)pnode; +} + +static PySequenceMethods pyrf_callchain__sequence_methods = { + .sq_length = pyrf_callchain__length, + .sq_item = pyrf_callchain__item, +}; + +static PyTypeObject pyrf_callchain__type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "perf.callchain", + .tp_basicsize = sizeof(struct pyrf_callchain), + .tp_dealloc = (destructor)pyrf_callchain__delete, + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_doc = "perf callchain object.", + .tp_as_sequence = &pyrf_callchain__sequence_methods, +}; + +static PyObject *pyrf_sample_event__get_callchain(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_event *pevent = (void *)self; + + if (!pevent->callchain) + Py_RETURN_NONE; + + Py_INCREF(pevent->callchain); + return pevent->callchain; +} + static PyObject* pyrf_sample_event__getattro(struct pyrf_event *pevent, PyObject *attr_name) { @@ -799,6 +940,12 @@ pyrf_sample_event__getattro(struct pyrf_event *pevent, PyObject *attr_name) } static PyGetSetDef pyrf_sample_event__getset[] = { + { + .name = "callchain", + .get = pyrf_sample_event__get_callchain, + .set = NULL, + .doc = "event callchain.", + }, { .name = "raw_buf", .get = (getter)pyrf_sample_event__get_raw_buf, @@ -968,6 +1115,12 @@ static int pyrf_event__setup_types(void) err = PyType_Ready(&pyrf_context_switch_event__type); if (err < 0) goto out; + err = PyType_Ready(&pyrf_callchain_node__type); + if (err < 0) + goto out; + err = PyType_Ready(&pyrf_callchain__type); + if (err < 0) + goto out; out: return err; } @@ -987,13 +1140,19 @@ static PyTypeObject *pyrf_event__type[] = { [PERF_RECORD_SWITCH_CPU_WIDE] = &pyrf_context_switch_event__type, }; -static PyObject *pyrf_event__new(const union perf_event *event, struct evsel *evsel) +static PyObject *pyrf_event__new(const union perf_event *event, struct evsel *evsel, + struct perf_session *session, + struct machine *machine) { struct pyrf_event *pevent; + struct perf_sample *sample; int err; u32 min_size; bool needs_swap; + if (!machine) + machine = session ? &session->machines.host : NULL; + if (event->header.type >= ARRAY_SIZE(pyrf_event__type) || pyrf_event__type[event->header.type] == NULL) { return PyErr_Format(PyExc_TypeError, "Unexpected header type %u", @@ -1025,6 +1184,7 @@ static PyObject *pyrf_event__new(const union perf_event *event, struct evsel *ev pevent->event.mmap2.filename[sizeof(pevent->event.mmap2.filename) - 1] = '\0'; perf_sample__init(&pevent->sample, /*all=*/true); + pevent->callchain = NULL; pevent->al_resolved = false; addr_location__init(&pevent->al); @@ -1042,6 +1202,50 @@ static PyObject *pyrf_event__new(const union perf_event *event, struct evsel *ev return PyErr_Format(PyExc_OSError, "perf: can't parse sample, err=%d", err); } + sample = &pevent->sample; + if (machine && sample->callchain) { + struct addr_location al; + struct callchain_cursor *cursor; + u64 i; + struct pyrf_callchain *pchain; + + addr_location__init(&al); + if (machine__resolve(machine, &al, sample) >= 0) { + cursor = get_tls_callchain_cursor(); + if (thread__resolve_callchain(al.thread, cursor, sample, + NULL, NULL, PERF_MAX_STACK_DEPTH) == 0) { + callchain_cursor_commit(cursor); + + pchain = PyObject_New(struct pyrf_callchain, &pyrf_callchain__type); + if (!pchain) { + addr_location__exit(&al); + Py_DECREF(pevent); + return NULL; + } + pchain->nr_frames = cursor->nr; + pchain->frames = calloc(pchain->nr_frames, + sizeof(*pchain->frames)); + if (!pchain->frames) { + Py_DECREF(pchain); + addr_location__exit(&al); + Py_DECREF(pevent); + return PyErr_NoMemory(); + } + struct callchain_cursor_node *node; + + for (i = 0; i < pchain->nr_frames; i++) { + node = callchain_cursor_current(cursor); + pchain->frames[i].ip = node->ip; + pchain->frames[i].map = + map__get(node->ms.map); + pchain->frames[i].sym = node->ms.sym; + callchain_cursor_advance(cursor); + } + pevent->callchain = (PyObject *)pchain; + } + addr_location__exit(&al); + } + } return (PyObject *)pevent; } @@ -2417,7 +2621,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, perf_mmap__consume(&md->core); Py_RETURN_NONE; } - pyevent = pyrf_event__new(event, evsel); + pyevent = pyrf_event__new(event, evsel, evlist__session(evlist), /*machine=*/NULL); perf_mmap__consume(&md->core); if (pyevent == NULL) return PyErr_Occurred() ? NULL : PyErr_NoMemory(); @@ -3185,10 +3389,10 @@ struct pyrf_session { static int pyrf_session_tool__sample(const struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct machine *machine __maybe_unused) + struct machine *machine) { struct pyrf_session *psession = container_of(tool, struct pyrf_session, tool); - PyObject *pyevent = pyrf_event__new(event, sample->evsel); + PyObject *pyevent = pyrf_event__new(event, sample->evsel, psession->session, machine); PyObject *ret; if (pyevent == NULL) @@ -3296,6 +3500,9 @@ static PyObject *pyrf_session__new(PyTypeObject *type, PyObject *args, PyObject } psession->session = session; + symbol_conf.use_callchain = true; + symbol_conf.show_kernel_path = true; + symbol_conf.inline_name = false; if (symbol__init(perf_session__env(session)) < 0) { PyErr_SetString(PyExc_OSError, "perf: symbol__init failed"); goto err_out; @@ -3475,6 +3682,12 @@ PyMODINIT_FUNC PyInit_perf(void) Py_INCREF(&pyrf_thread__type); PyModule_AddObject(module, "thread", (PyObject *)&pyrf_thread__type); + Py_INCREF(&pyrf_callchain__type); + PyModule_AddObject(module, "callchain", (PyObject *)&pyrf_callchain__type); + + Py_INCREF(&pyrf_callchain_node__type); + PyModule_AddObject(module, "callchain_node", (PyObject *)&pyrf_callchain_node__type); + Py_INCREF(&pyrf_mmap_event__type); PyModule_AddObject(module, "mmap_event", (PyObject *)&pyrf_mmap_event__type); -- cgit v1.2.3 From 231007698a653091059854ab370c2f95c1799f66 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:36 -0700 Subject: perf python: Extend API for stat events in python.c Add stat information to the session. Add call backs for stat events. Assisted-by: Gemini:gemini-3.1-pro-preview Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/python.c | 189 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 184 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 01369d8b3e65..db7f4a8ebcd1 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -458,6 +458,77 @@ static PyTypeObject pyrf_lost_event__type = { .tp_repr = (reprfunc)pyrf_lost_event__repr, }; +static const char pyrf_stat_event__doc[] = PyDoc_STR("perf stat event object."); + +static PyMemberDef pyrf_stat_event__members[] = { + sample_members + member_def(perf_event_header, type, T_UINT, "event type"), + member_def(perf_record_stat, id, T_ULONGLONG, "event id"), + member_def(perf_record_stat, cpu, T_UINT, "event cpu"), + member_def(perf_record_stat, thread, T_UINT, "event thread"), + member_def(perf_record_stat, val, T_ULONGLONG, "counter value"), + member_def(perf_record_stat, ena, T_ULONGLONG, "enabled time"), + member_def(perf_record_stat, run, T_ULONGLONG, "running time"), + { .name = NULL, }, +}; + +static PyObject *pyrf_stat_event__repr(const struct pyrf_event *pevent) +{ + return PyUnicode_FromFormat( + "{ type: stat, id: %llu, cpu: %u, thread: %u, val: %llu, ena: %llu, run: %llu }", + pevent->event.stat.id, + pevent->event.stat.cpu, + pevent->event.stat.thread, + pevent->event.stat.val, + pevent->event.stat.ena, + pevent->event.stat.run); +} + +static PyTypeObject pyrf_stat_event__type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "perf.stat_event", + .tp_basicsize = sizeof(struct pyrf_event), + .tp_new = PyType_GenericNew, + .tp_dealloc = (destructor)pyrf_event__delete, + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_doc = pyrf_stat_event__doc, + .tp_members = pyrf_stat_event__members, + .tp_getset = pyrf_event__getset, + .tp_repr = (reprfunc)pyrf_stat_event__repr, +}; + +static const char pyrf_stat_round_event__doc[] = PyDoc_STR("perf stat round event object."); + +static PyMemberDef pyrf_stat_round_event__members[] = { + sample_members + member_def(perf_event_header, type, T_UINT, "event type"), + { .name = "stat_round_type", .type = T_ULONGLONG, + .offset = offsetof(struct pyrf_event, event) + offsetof(struct perf_record_stat_round, type), + .doc = "round type" }, + member_def(perf_record_stat_round, time, T_ULONGLONG, "round time"), + { .name = NULL, }, +}; + +static PyObject *pyrf_stat_round_event__repr(const struct pyrf_event *pevent) +{ + return PyUnicode_FromFormat("{ type: stat_round, type: %llu, time: %llu }", + pevent->event.stat_round.type, + pevent->event.stat_round.time); +} + +static PyTypeObject pyrf_stat_round_event__type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "perf.stat_round_event", + .tp_basicsize = sizeof(struct pyrf_event), + .tp_new = PyType_GenericNew, + .tp_dealloc = (destructor)pyrf_event__delete, + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_doc = pyrf_stat_round_event__doc, + .tp_members = pyrf_stat_round_event__members, + .tp_getset = pyrf_event__getset, + .tp_repr = (reprfunc)pyrf_stat_round_event__repr, +}; + static const char pyrf_read_event__doc[] = PyDoc_STR("perf read event object."); static PyMemberDef pyrf_read_event__members[] = { @@ -1113,6 +1184,12 @@ static int pyrf_event__setup_types(void) if (err < 0) goto out; err = PyType_Ready(&pyrf_context_switch_event__type); + if (err < 0) + goto out; + err = PyType_Ready(&pyrf_stat_event__type); + if (err < 0) + goto out; + err = PyType_Ready(&pyrf_stat_round_event__type); if (err < 0) goto out; err = PyType_Ready(&pyrf_callchain_node__type); @@ -1138,6 +1215,8 @@ static PyTypeObject *pyrf_event__type[] = { [PERF_RECORD_SAMPLE] = &pyrf_sample_event__type, [PERF_RECORD_SWITCH] = &pyrf_context_switch_event__type, [PERF_RECORD_SWITCH_CPU_WIDE] = &pyrf_context_switch_event__type, + [PERF_RECORD_STAT] = &pyrf_stat_event__type, + [PERF_RECORD_STAT_ROUND] = &pyrf_stat_round_event__type, }; static PyObject *pyrf_event__new(const union perf_event *event, struct evsel *evsel, @@ -2132,7 +2211,45 @@ static PyObject *pyrf_evsel__get_attr_wakeup_events(PyObject *self, void *closur return PyLong_FromUnsignedLong(pevsel->evsel->core.attr.wakeup_events); } +static PyObject *pyrf_evsel__get_ids(struct pyrf_evsel *pevsel, void *closure __maybe_unused) +{ + struct evsel *evsel; + PyObject *list; + + CHECK_INITIALIZED(pevsel->evsel, "evsel"); + + evsel = pevsel->evsel; + list = PyList_New(0); + + if (!list) + return NULL; + + for (u32 i = 0; i < evsel->core.ids; i++) { + PyObject *id = PyLong_FromUnsignedLongLong(evsel->core.id[i]); + int ret; + + if (!id) { + Py_DECREF(list); + return NULL; + } + ret = PyList_Append(list, id); + Py_DECREF(id); + if (ret < 0) { + Py_DECREF(list); + return NULL; + } + } + + return list; +} + static PyGetSetDef pyrf_evsel__getset[] = { + { + .name = "ids", + .get = (getter)pyrf_evsel__get_ids, + .set = NULL, + .doc = "event IDs.", + }, { .name = "tracking", .get = pyrf_evsel__get_tracking, @@ -2985,6 +3102,8 @@ static const struct perf_constant perf__constants[] = { PERF_CONST(RECORD_LOST_SAMPLES), PERF_CONST(RECORD_SWITCH), PERF_CONST(RECORD_SWITCH_CPU_WIDE), + PERF_CONST(RECORD_STAT), + PERF_CONST(RECORD_STAT_ROUND), PERF_CONST(RECORD_MISC_SWITCH_OUT), { .name = NULL, }, @@ -3384,6 +3503,7 @@ struct pyrf_session { struct perf_tool tool; struct pyrf_data *pdata; PyObject *sample; + PyObject *stat; }; static int pyrf_session_tool__sample(const struct perf_tool *tool, @@ -3408,6 +3528,52 @@ static int pyrf_session_tool__sample(const struct perf_tool *tool, return 0; } +static int pyrf_session_tool__stat(const struct perf_tool *tool, + struct perf_session *session, + union perf_event *event) +{ + struct pyrf_session *psession = container_of(tool, struct pyrf_session, tool); + struct evsel *evsel = evlist__id2evsel(session->evlist, event->stat.id); + PyObject *pyevent = pyrf_event__new(event, /*evsel=*/NULL, psession->session, + /*machine=*/NULL); + const char *name = evsel ? evsel__name(evsel) : "unknown"; + PyObject *ret; + + if (pyevent == NULL) + return -ENOMEM; + + ret = PyObject_CallFunction(psession->stat, "Oz", pyevent, name); + if (!ret) { + Py_DECREF(pyevent); + return -1; + } + Py_DECREF(ret); + Py_DECREF(pyevent); + return 0; +} + +static int pyrf_session_tool__stat_round(const struct perf_tool *tool, + struct perf_session *session __maybe_unused, + union perf_event *event) +{ + struct pyrf_session *psession = container_of(tool, struct pyrf_session, tool); + PyObject *pyevent = pyrf_event__new(event, /*evsel=*/NULL, psession->session, + /*machine=*/NULL); + PyObject *ret; + + if (pyevent == NULL) + return -ENOMEM; + + ret = PyObject_CallFunction(psession->stat, "Oz", pyevent, NULL); + if (!ret) { + Py_DECREF(pyevent); + return -1; + } + Py_DECREF(ret); + Py_DECREF(pyevent); + return 0; +} + static PyObject *pyrf_session__find_thread(struct pyrf_session *psession, PyObject *args) { struct machine *machine; @@ -3441,13 +3607,13 @@ static PyObject *pyrf_session__find_thread(struct pyrf_session *psession, PyObje static PyObject *pyrf_session__new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { struct pyrf_data *pdata; - PyObject *sample = NULL; - static char *kwlist[] = { "data", "sample", NULL }; + PyObject *sample = NULL, *stat = NULL; + static char *kwlist[] = { "data", "sample", "stat", NULL }; struct pyrf_session *psession; struct perf_session *session; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|O", kwlist, &pyrf_data__type, &pdata, - &sample)) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OO", kwlist, &pyrf_data__type, &pdata, + &sample, &stat)) return NULL; psession = PyObject_New(struct pyrf_session, type); @@ -3456,6 +3622,7 @@ static PyObject *pyrf_session__new(PyTypeObject *type, PyObject *args, PyObject psession->session = NULL; psession->sample = NULL; + psession->stat = NULL; psession->pdata = NULL; Py_INCREF(pdata); @@ -3478,8 +3645,13 @@ static PyObject *pyrf_session__new(PyTypeObject *type, PyObject *args, PyObject } while (0) ADD_TOOL(sample); + ADD_TOOL(stat); #undef ADD_TOOL + if (stat) + psession->tool.stat_round = pyrf_session_tool__stat_round; + + psession->tool.comm = perf_event__process_comm; psession->tool.mmap = perf_event__process_mmap; psession->tool.mmap2 = perf_event__process_mmap2; @@ -3492,7 +3664,7 @@ static PyObject *pyrf_session__new(PyTypeObject *type, PyObject *args, PyObject psession->tool.build_id = perf_event__process_build_id; psession->tool.attr = perf_event__process_attr; psession->tool.feature = perf_event__process_feature; - psession->tool.stat = perf_event__process_stat_event; + session = perf_session__new(&pdata->data, &psession->tool); if (IS_ERR(session)) { PyErr_Format(PyExc_IOError, "failed to create session: %ld", PTR_ERR(session)); @@ -3521,6 +3693,7 @@ static void pyrf_session__delete(struct pyrf_session *psession) perf_session__delete(psession->session); Py_XDECREF(psession->pdata); Py_XDECREF(psession->sample); + Py_XDECREF(psession->stat); Py_TYPE(psession)->tp_free((PyObject *)psession); } @@ -3718,6 +3891,12 @@ PyMODINIT_FUNC PyInit_perf(void) Py_INCREF(&pyrf_context_switch_event__type); PyModule_AddObject(module, "switch_event", (PyObject *)&pyrf_context_switch_event__type); + Py_INCREF(&pyrf_stat_event__type); + PyModule_AddObject(module, "stat_event", (PyObject *)&pyrf_stat_event__type); + + Py_INCREF(&pyrf_stat_round_event__type); + PyModule_AddObject(module, "stat_round_event", (PyObject *)&pyrf_stat_round_event__type); + Py_INCREF(&pyrf_thread_map__type); PyModule_AddObject(module, "thread_map", (PyObject*)&pyrf_thread_map__type); -- cgit v1.2.3 From cc47714fd7afbcf72fbb6c5c0f884c5afca4d3ae Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:37 -0700 Subject: perf python: Expose brstack in sample event Implement pyrf_branch_entry and pyrf_branch_stack for lazy iteration over branch stack entries. Assisted-by: Gemini:gemini-3.1-pro-preview Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/python.c | 198 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index db7f4a8ebcd1..05691a513184 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -22,6 +22,7 @@ #include "debug.h" #include "dso.h" #include "event.h" +#include "branch.h" #include "evlist.h" #include "evsel.h" #include "expr.h" @@ -89,6 +90,8 @@ struct pyrf_event { bool al_resolved; /** @callchain: Resolved callchain, eagerly computed if requested. */ PyObject *callchain; + /** @brstack: Resolved branch stack, eagerly computed if requested. */ + PyObject *brstack; /** @event: The underlying perf_event that may be in a file or ring buffer. */ union perf_event event; }; @@ -127,6 +130,7 @@ static void pyrf_event__delete(struct pyrf_event *pevent) if (pevent->al_resolved) addr_location__exit(&pevent->al); Py_XDECREF(pevent->callchain); + Py_XDECREF(pevent->brstack); perf_sample__exit(&pevent->sample); Py_TYPE(pevent)->tp_free((PyObject *)pevent); } @@ -997,6 +1001,154 @@ static PyObject *pyrf_sample_event__get_callchain(PyObject *self, void *closure return pevent->callchain; } +struct pyrf_branch_entry { + PyObject_HEAD + u64 from; + u64 to; + struct branch_flags flags; +}; + +static void pyrf_branch_entry__delete(struct pyrf_branch_entry *pentry) +{ + Py_TYPE(pentry)->tp_free((PyObject *)pentry); +} + +static PyObject *pyrf_branch_entry__get_from(struct pyrf_branch_entry *pentry, + void *closure __maybe_unused) +{ + return PyLong_FromUnsignedLongLong(pentry->from); +} + +static PyObject *pyrf_branch_entry__get_to(struct pyrf_branch_entry *pentry, + void *closure __maybe_unused) +{ + return PyLong_FromUnsignedLongLong(pentry->to); +} + +static PyObject *pyrf_branch_entry__get_mispred(struct pyrf_branch_entry *pentry, + void *closure __maybe_unused) +{ + return PyBool_FromLong(pentry->flags.mispred); +} + +static PyObject *pyrf_branch_entry__get_predicted(struct pyrf_branch_entry *pentry, + void *closure __maybe_unused) +{ + return PyBool_FromLong(pentry->flags.predicted); +} + +static PyObject *pyrf_branch_entry__get_in_tx(struct pyrf_branch_entry *pentry, + void *closure __maybe_unused) +{ + return PyBool_FromLong(pentry->flags.in_tx); +} + +static PyObject *pyrf_branch_entry__get_abort(struct pyrf_branch_entry *pentry, + void *closure __maybe_unused) +{ + return PyBool_FromLong(pentry->flags.abort); +} + +static PyObject *pyrf_branch_entry__get_cycles(struct pyrf_branch_entry *pentry, + void *closure __maybe_unused) +{ + return PyLong_FromUnsignedLongLong(pentry->flags.cycles); +} + +static PyObject *pyrf_branch_entry__get_type(struct pyrf_branch_entry *pentry, + void *closure __maybe_unused) +{ + return PyLong_FromUnsignedLongLong((unsigned long long)pentry->flags.type); +} + +static PyGetSetDef pyrf_branch_entry__getset[] = { + { .name = "from_ip", .get = (getter)pyrf_branch_entry__get_from, }, + { .name = "to_ip", .get = (getter)pyrf_branch_entry__get_to, }, + { .name = "mispred", .get = (getter)pyrf_branch_entry__get_mispred, }, + { .name = "predicted", .get = (getter)pyrf_branch_entry__get_predicted, }, + { .name = "in_tx", .get = (getter)pyrf_branch_entry__get_in_tx, }, + { .name = "abort", .get = (getter)pyrf_branch_entry__get_abort, }, + { .name = "cycles", .get = (getter)pyrf_branch_entry__get_cycles, }, + { .name = "type", .get = (getter)pyrf_branch_entry__get_type, }, + { .name = NULL, }, +}; + +static PyTypeObject pyrf_branch_entry__type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "perf.branch_entry", + .tp_basicsize = sizeof(struct pyrf_branch_entry), + .tp_dealloc = (destructor)pyrf_branch_entry__delete, + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_doc = "perf branch entry object.", + .tp_getset = pyrf_branch_entry__getset, +}; + +struct pyrf_branch_stack { + PyObject_HEAD + struct branch_entry *entries; + u64 nr; +}; + +static void pyrf_branch_stack__delete(struct pyrf_branch_stack *pstack) +{ + free(pstack->entries); + Py_TYPE(pstack)->tp_free((PyObject *)pstack); +} + +static Py_ssize_t pyrf_branch_stack__length(PyObject *obj) +{ + struct pyrf_branch_stack *pstack = (void *)obj; + + return pstack->nr; +} + +static PyObject *pyrf_branch_stack__item(PyObject *obj, Py_ssize_t i) +{ + struct pyrf_branch_stack *pstack = (void *)obj; + struct pyrf_branch_entry *pentry; + + if (i < 0 || i >= (Py_ssize_t)pstack->nr) { + PyErr_SetString(PyExc_IndexError, "Index out of range"); + return NULL; + } + + pentry = PyObject_New(struct pyrf_branch_entry, &pyrf_branch_entry__type); + if (!pentry) + return NULL; + + pentry->from = pstack->entries[i].from; + pentry->to = pstack->entries[i].to; + pentry->flags = pstack->entries[i].flags; + + return (PyObject *)pentry; +} + +static PySequenceMethods pyrf_branch_stack__sequence_methods = { + .sq_length = pyrf_branch_stack__length, + .sq_item = pyrf_branch_stack__item, +}; + +static PyTypeObject pyrf_branch_stack__type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "perf.branch_stack", + .tp_basicsize = sizeof(struct pyrf_branch_stack), + .tp_dealloc = (destructor)pyrf_branch_stack__delete, + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_doc = "perf branch stack object.", + .tp_as_sequence = &pyrf_branch_stack__sequence_methods, +}; + +static PyObject *pyrf_sample_event__get_brstack(PyObject *self, void *closure __maybe_unused) +{ + struct pyrf_event *pevent = (void *)self; + + if (!pevent->brstack) + Py_RETURN_NONE; + + Py_INCREF(pevent->brstack); + return pevent->brstack; +} + static PyObject* pyrf_sample_event__getattro(struct pyrf_event *pevent, PyObject *attr_name) { @@ -1017,6 +1169,12 @@ static PyGetSetDef pyrf_sample_event__getset[] = { .set = NULL, .doc = "event callchain.", }, + { + .name = "brstack", + .get = pyrf_sample_event__get_brstack, + .set = NULL, + .doc = "event branch stack.", + }, { .name = "raw_buf", .get = (getter)pyrf_sample_event__get_raw_buf, @@ -1198,6 +1356,12 @@ static int pyrf_event__setup_types(void) err = PyType_Ready(&pyrf_callchain__type); if (err < 0) goto out; + err = PyType_Ready(&pyrf_branch_entry__type); + if (err < 0) + goto out; + err = PyType_Ready(&pyrf_branch_stack__type); + if (err < 0) + goto out; out: return err; } @@ -1264,6 +1428,7 @@ static PyObject *pyrf_event__new(const union perf_event *event, struct evsel *ev perf_sample__init(&pevent->sample, /*all=*/true); pevent->callchain = NULL; + pevent->brstack = NULL; pevent->al_resolved = false; addr_location__init(&pevent->al); @@ -1325,6 +1490,27 @@ static PyObject *pyrf_event__new(const union perf_event *event, struct evsel *ev addr_location__exit(&al); } } + if (sample->branch_stack) { + struct branch_stack *bs = sample->branch_stack; + struct branch_entry *entries = perf_sample__branch_entries(sample); + struct pyrf_branch_stack *pstack; + + pstack = PyObject_New(struct pyrf_branch_stack, &pyrf_branch_stack__type); + if (!pstack) { + Py_DECREF(pevent); + return NULL; + } + pstack->nr = bs->nr; + pstack->entries = calloc(bs->nr, sizeof(struct branch_entry)); + if (!pstack->entries) { + Py_DECREF(pstack); + Py_DECREF(pevent); + return PyErr_NoMemory(); + } + memcpy(pstack->entries, entries, + bs->nr * sizeof(struct branch_entry)); + pevent->brstack = (PyObject *)pstack; + } return (PyObject *)pevent; } @@ -3912,6 +4098,18 @@ PyMODINIT_FUNC PyInit_perf(void) Py_INCREF(&pyrf_session__type); PyModule_AddObject(module, "session", (PyObject *)&pyrf_session__type); + Py_INCREF(&pyrf_branch_entry__type); + if (PyModule_AddObject(module, "branch_entry", (PyObject *)&pyrf_branch_entry__type) < 0) { + Py_DECREF(&pyrf_branch_entry__type); + goto error; + } + + Py_INCREF(&pyrf_branch_stack__type); + if (PyModule_AddObject(module, "branch_stack", (PyObject *)&pyrf_branch_stack__type) < 0) { + Py_DECREF(&pyrf_branch_stack__type); + goto error; + } + dict = PyModule_GetDict(module); if (dict == NULL) goto error; -- cgit v1.2.3 From be64b86ce81fe89145861d812c6659e818422c14 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:38 -0700 Subject: perf python: Add syscall name/id to convert syscall number and name Use perf's syscalltbl support to convert syscall number to name assuming the number is for the host machine. This avoids python libaudit support as tools/perf/scripts/python/syscall-counts.py requires. Assisted-by: Gemini:gemini-3.1-pro-preview Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/Build | 1 - tools/perf/util/python.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 5e2265018826..330311cac550 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -76,7 +76,6 @@ perf-util-y += sample.o perf-util-y += sample-raw.o perf-util-y += s390-sample-raw.o perf-util-y += amd-sample-raw.o - perf-util-y += ordered-events.o perf-util-y += namespaces.o perf-util-y += comm.o diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 05691a513184..c5f567c15cc7 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -21,6 +21,7 @@ #include "data.h" #include "debug.h" #include "dso.h" +#include "dwarf-regs.h" #include "event.h" #include "branch.h" #include "evlist.h" @@ -40,6 +41,7 @@ #include "symbol.h" #include "stat.h" #include "header.h" +#include "trace/beauty/syscalltbl.h" #include "thread.h" #include "thread_map.h" #include "tool.h" @@ -3957,6 +3959,40 @@ static int pyrf_session__setup_types(void) return PyType_Ready(&pyrf_session__type); } +static PyObject *pyrf__syscall_name(PyObject *self, PyObject *args, PyObject *kwargs) +{ + const char *name; + int id; + int elf_machine = EM_HOST; + static char *kwlist[] = { "id", "elf_machine", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|$i", kwlist, &id, &elf_machine)) + return NULL; + + name = syscalltbl__name(elf_machine, id); + if (!name) + Py_RETURN_NONE; + return PyUnicode_FromString(name); +} + +static PyObject *pyrf__syscall_id(PyObject *self, PyObject *args, PyObject *kwargs) +{ + const char *name; + int id; + int elf_machine = EM_HOST; + static char *kwlist[] = { "name", "elf_machine", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|$i", kwlist, &name, &elf_machine)) + return NULL; + + id = syscalltbl__id(elf_machine, name); + if (id < 0) { + PyErr_Format(PyExc_ValueError, "Failed to find syscall %s", name); + return NULL; + } + return PyLong_FromLong(id); +} + static PyMethodDef perf__methods[] = { { .ml_name = "metrics", @@ -3990,6 +4026,18 @@ static PyMethodDef perf__methods[] = { .ml_flags = METH_NOARGS, .ml_doc = PyDoc_STR("Returns a sequence of pmus.") }, + { + .ml_name = "syscall_name", + .ml_meth = (PyCFunction) pyrf__syscall_name, + .ml_flags = METH_VARARGS | METH_KEYWORDS, + .ml_doc = PyDoc_STR("Turns a syscall number to a string.") + }, + { + .ml_name = "syscall_id", + .ml_meth = (PyCFunction) pyrf__syscall_id, + .ml_flags = METH_VARARGS | METH_KEYWORDS, + .ml_doc = PyDoc_STR("Turns a syscall name to a number.") + }, { .ml_name = NULL, } }; -- cgit v1.2.3 From 44a4bf577d51f3d6fd8279a25ec11e542bc23ea5 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:39 -0700 Subject: perf python: Add config file access Add perf.config_get(name) to expose the perf configuration system. Assisted-by: Gemini:gemini-3.1-pro-preview Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/python.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index c5f567c15cc7..3a9f4e35d0bb 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -17,6 +17,7 @@ #include "build-id.h" #include "callchain.h" #include "comm.h" +#include "config.h" #include "counts.h" #include "data.h" #include "debug.h" @@ -3993,7 +3994,26 @@ static PyObject *pyrf__syscall_id(PyObject *self, PyObject *args, PyObject *kwar return PyLong_FromLong(id); } +static PyObject *pyrf__config_get(PyObject *self, PyObject *args) +{ + const char *config_name, *val; + + if (!PyArg_ParseTuple(args, "s", &config_name)) + return NULL; + + val = perf_config_get(config_name); + if (!val) + Py_RETURN_NONE; + return PyUnicode_FromString(val); +} + static PyMethodDef perf__methods[] = { + { + .ml_name = "config_get", + .ml_meth = (PyCFunction) pyrf__config_get, + .ml_flags = METH_VARARGS, + .ml_doc = PyDoc_STR("Get a perf config value.") + }, { .ml_name = "metrics", .ml_meth = (PyCFunction) pyrf__metrics, -- cgit v1.2.3 From 054d1c7717b95d9089cd3b80e9e85fe1f2ea0471 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:40 -0700 Subject: perf python: Handle Py_None for thread and cpu maps The python stubs allow passing None for threads and cpus to the perf.parse_events() and perf.parse_metrics() bindings. However, PyArg_ParseTuple parses None into a Py_None object, which is not a NULL pointer. Because the C code lacked an explicit check for Py_None, it would cast Py_None to a pyrf_thread_map/pyrf_cpu_map struct pointer and dereference it, causing a memory corruption crash. Fix this pre-existing issue by explicitly checking for Py_None alongside NULL in pyrf__parse_events, pyrf__parse_metrics, and pyrf_evsel__open. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/python.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 3a9f4e35d0bb..4ec5a91d45c0 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -2091,10 +2091,10 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, &pcpus, &pthreads, &group, &inherit)) return NULL; - if (pthreads != NULL) + if (pthreads != NULL && pthreads != Py_None) threads = ((struct pyrf_thread_map *)pthreads)->threads; - if (pcpus != NULL) + if (pcpus != NULL && pcpus != Py_None) cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; evsel->core.attr.inherit = inherit; @@ -3341,8 +3341,10 @@ static PyObject *pyrf__parse_events(PyObject *self, PyObject *args) return NULL; } - threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL; - cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL; + threads = (pthreads && pthreads != Py_None) ? + ((struct pyrf_thread_map *)pthreads)->threads : NULL; + cpus = (pcpus && pcpus != Py_None) ? + ((struct pyrf_cpu_map *)pcpus)->cpus : NULL; parse_events_error__init(&err); perf_evlist__set_maps(evlist__core(evlist), cpus, threads); @@ -3375,8 +3377,10 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args) return NULL; } - threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL; - cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL; + threads = (pthreads && pthreads != Py_None) ? + ((struct pyrf_thread_map *)pthreads)->threads : NULL; + cpus = (pcpus && pcpus != Py_None) ? + ((struct pyrf_cpu_map *)pcpus)->cpus : NULL; perf_evlist__set_maps(evlist__core(evlist), cpus, threads); ret = metricgroup__parse_groups(evlist, pmu ?: "all", input, -- cgit v1.2.3 From c52b600dbee982ef0c81becffe228fe3ab6bd8e3 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:41 -0700 Subject: perf python: Add type checking for parse_events/parse_metrics The threads and cpus parameters in parse_events and parse_metrics are parsed with the 'O' format specifier but blindly casted in the C extension. If a user passes an invalid object type, this leads to memory corruption when dereferencing the expected struct. Add runtime PyObject_TypeCheck validations in python.c to safely raise a TypeError if an invalid object is passed. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/python.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 4ec5a91d45c0..11e1f39c1bea 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -3341,6 +3341,20 @@ static PyObject *pyrf__parse_events(PyObject *self, PyObject *args) return NULL; } + if (pthreads && pthreads != Py_None && + !PyObject_TypeCheck(pthreads, &pyrf_thread_map__type)) { + PyErr_SetString(PyExc_TypeError, "threads must be a perf.thread_map or None"); + evlist__put(evlist); + return NULL; + } + + if (pcpus && pcpus != Py_None && + !PyObject_TypeCheck(pcpus, &pyrf_cpu_map__type)) { + PyErr_SetString(PyExc_TypeError, "cpus must be a perf.cpu_map or None"); + evlist__put(evlist); + return NULL; + } + threads = (pthreads && pthreads != Py_None) ? ((struct pyrf_thread_map *)pthreads)->threads : NULL; cpus = (pcpus && pcpus != Py_None) ? @@ -3377,6 +3391,20 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args) return NULL; } + if (pthreads && pthreads != Py_None && + !PyObject_TypeCheck(pthreads, &pyrf_thread_map__type)) { + PyErr_SetString(PyExc_TypeError, "threads must be a perf.thread_map or None"); + evlist__put(evlist); + return NULL; + } + + if (pcpus && pcpus != Py_None && + !PyObject_TypeCheck(pcpus, &pyrf_cpu_map__type)) { + PyErr_SetString(PyExc_TypeError, "cpus must be a perf.cpu_map or None"); + evlist__put(evlist); + return NULL; + } + threads = (pthreads && pthreads != Py_None) ? ((struct pyrf_thread_map *)pthreads)->threads : NULL; cpus = (pcpus && pcpus != Py_None) ? -- cgit v1.2.3 From fed8332b0e0ba9dec1729f0422f0b0d96f7893f2 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:42 -0700 Subject: perf python: Add perf.pyi stubs file Add Python type stubs for the perf module to improve IDE support and static analysis. Includes docstrings for classes, methods, and constants derived from C source and JSON definitions. Assisted-by: Gemini:gemini-3.1-pro-preview Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/Makefile.perf | 7 +- tools/perf/python/perf.pyi | 672 +++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/setup.py | 5 + 3 files changed, 682 insertions(+), 2 deletions(-) create mode 100644 tools/perf/python/perf.pyi diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 476b8dcaef58..3f0544d37a7f 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -517,12 +517,15 @@ all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS) # Create python binding output directory if not already present $(shell [ -d '$(OUTPUT)python' ] || mkdir -p '$(OUTPUT)python') -$(OUTPUT)python/perf$(PYTHON_EXTENSION_SUFFIX): util/python.c util/setup.py $(PERFLIBS_PY) +$(OUTPUT)python/perf$(PYTHON_EXTENSION_SUFFIX): util/python.c util/setup.py python/perf.pyi $(PERFLIBS_PY) $(QUIET_GEN)LDSHARED="$(CC) -pthread -shared" \ CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS) $(LIBS_PY)' \ $(PYTHON_WORD) util/setup.py \ $(python_setup_quiet) build_ext; \ - cp $(PYTHON_EXTBUILD_LIB)perf*.so $(OUTPUT)python/ + cp $(PYTHON_EXTBUILD_LIB)perf*.so $(OUTPUT)python/; \ + if [ "$(abspath python/perf.pyi)" != "$(abspath $(OUTPUT)python/perf.pyi)" ]; then \ + cp python/perf.pyi $(OUTPUT)python/; \ + fi python_perf_target: @echo "Target is: $(OUTPUT)python/perf$(PYTHON_EXTENSION_SUFFIX)" diff --git a/tools/perf/python/perf.pyi b/tools/perf/python/perf.pyi new file mode 100644 index 000000000000..f266c9baffd0 --- /dev/null +++ b/tools/perf/python/perf.pyi @@ -0,0 +1,672 @@ +"""Type stubs for the perf Python module.""" +from typing import Callable, Dict, List, Optional, Any, Iterator + +def config_get(name: str) -> Optional[str]: + """Get a configuration value from perf config. + + Args: + name: The configuration variable name (e.g., 'colors.top'). + + Returns: + The configuration value as a string, or None if not set. + """ + ... + +def metrics() -> List[Dict[str, str]]: + """Get a list of available metrics. + + Returns: + A list of dictionaries, each describing a metric. + """ + ... + +def syscall_name(id: int, *, elf_machine: Optional[int] = None) -> str: + """Convert a syscall number to its name. + + Args: + sc_id: The syscall number. + elf_machine: Optional ELF machine type. + + Returns: + The name of the syscall. + """ + ... + +def syscall_id(name: str, *, elf_machine: Optional[int] = None) -> int: + """Convert a syscall name to its number. + + Args: + name: The syscall name. + elf_machine: Optional ELF machine type. + + Returns: + The number of the syscall. + """ + ... + +def parse_events( + event_string: str, + cpus: Optional[cpu_map] = None, + threads: Optional['thread_map'] = None +) -> 'evlist': + """Parse an event string and return an evlist. + + Args: + event_string: The event string (e.g., 'cycles,instructions'). + cpus: Optional CPU map to bind events to. + threads: Optional thread map to bind events to. + + Returns: + An evlist containing the parsed events. + """ + ... + +def parse_metrics( + metrics_string: str, + pmu: Optional[str] = None, + cpus: Optional[cpu_map] = None, + threads: Optional['thread_map'] = None +) -> 'evlist': + """Parse a string of metrics or metric groups and return an evlist.""" + ... + +def tracepoint(sys: str, name: str) -> int: + """Returns the tracepoint ID for a given system and name.""" + ... + +def pmus() -> Iterator[Any]: + """Returns a sequence of pmus.""" + ... + +class data: + """Represents a perf data file.""" + def __init__(self, path: str = ..., fd: int = ...) -> None: ... + +class thread: + """Represents a thread in the system.""" + def comm(self) -> str: + """Get the command name of the thread.""" + ... + pid: int + tid: int + ppid: int + cpu: int + +class counts_values: + """Raw counter values.""" + id: int + val: int + ena: int + run: int + lost: int + values: List[int] + +class thread_map: + """Map of threads being monitored.""" + def __init__(self, pid: int = -1, tid: int = -1) -> None: + """Initialize a thread map. + + Args: + pid: Process ID to monitor (-1 for all). + tid: Thread ID to monitor (-1 for all). + """ + ... + def __len__(self) -> int: ... + def __getitem__(self, index: int) -> int: ... + def __iter__(self) -> Iterator[int]: ... + +class evsel: + """Event selector, represents a single event being monitored.""" + def __init__( + self, + type: int = ..., + config: int = ..., + sample_freq: int = ..., + sample_period: int = ..., + sample_type: int = ..., + read_format: int = ..., + disabled: bool = ..., + inherit: bool = ..., + pinned: bool = ..., + exclusive: bool = ..., + exclude_user: bool = ..., + exclude_kernel: bool = ..., + exclude_hv: bool = ..., + exclude_idle: bool = ..., + mmap: bool = ..., + context_switch: bool = ..., + comm: bool = ..., + freq: bool = ..., + inherit_stat: bool = ..., + enable_on_exec: bool = ..., + task: bool = ..., + watermark: int = ..., + precise_ip: int = ..., + mmap_data: bool = ..., + sample_id_all: bool = ..., + wakeup_events: int = ..., + bp_type: int = ..., + bp_addr: int = ..., + bp_len: int = ..., + idx: int = ..., + ) -> None: ... + def __str__(self) -> str: + """Return string representation of the event.""" + ... + def open(self) -> None: + """Open the event selector file descriptor table.""" + ... + def read(self, cpu: int, thread: int) -> counts_values: + """Read counter values for a specific CPU and thread.""" + ... + ids: List[int] + def cpus(self) -> cpu_map: + """Get CPU map for this event.""" + ... + def threads(self) -> thread_map: + """Get thread map for this event.""" + ... + tracking: bool + config: int + read_format: int + sample_period: int + sample_type: int + size: int + type: int + wakeup_events: int + + +class _sample_members: + sample_pid: int + sample_tid: int + sample_time: int + sample_id: int + sample_stream_id: int + sample_period: int + sample_cpu: int + +class sample_event(_sample_members): + """Represents a sample event from perf.""" + evsel: evsel + sample_ip: int + sample_addr: int + sample_phys_addr: int + sample_weight: int + sample_data_src: int + sample_insn_count: int + sample_cyc_count: int + type: int + raw_buf: bytes + dso: str + dso_long_name: str + dso_bid: Optional[bytes] + map_start: int + map_end: int + map_pgoff: int + symbol: str + sym_start: int + sym_end: int + brstack: Optional['branch_stack'] + callchain: Optional['callchain'] + def srccode(self) -> str: ... + def insn(self) -> str: ... + def __getattr__(self, name: str) -> Any: ... + +class mmap_event(_sample_members): + """Represents a mmap event from perf.""" + type: int + misc: int + pid: int + tid: int + start: int + len: int + pgoff: int + filename: str + evsel: Optional['evsel'] + +class mmap2_event(_sample_members): + """Represents a mmap2 event from perf.""" + type: int + misc: int + pid: int + tid: int + start: int + len: int + pgoff: int + prot: int + flags: int + filename: str + maj: Optional[int] + min: Optional[int] + ino: Optional[int] + ino_generation: Optional[int] + build_id: Optional[bytes] + evsel: Optional['evsel'] + +class lost_event(_sample_members): + """Represents a lost events record.""" + type: int + id: int + lost: int + evsel: Optional['evsel'] + +class comm_event(_sample_members): + """Represents a COMM record.""" + type: int + pid: int + tid: int + comm: str + evsel: Optional['evsel'] + +class task_event(_sample_members): + """Represents an EXIT or FORK record.""" + type: int + pid: int + ppid: int + tid: int + ptid: int + time: int + evsel: Optional['evsel'] + +class throttle_event(_sample_members): + """Represents a THROTTLE or UNTHROTTLE record.""" + type: int + time: int + id: int + stream_id: int + evsel: Optional['evsel'] + +class read_event(_sample_members): + """Represents a READ record.""" + type: int + pid: int + tid: int + evsel: Optional['evsel'] + +class switch_event(_sample_members): + """Represents a SWITCH or SWITCH_CPU_WIDE record.""" + type: int + next_prev_pid: int + next_prev_tid: int + evsel: Optional['evsel'] + +class branch_entry: + """Represents a branch entry in the branch stack. + + Attributes: + from_ip: Source address of the branch (corresponds to 'from' keyword in C). + to_ip: Destination address of the branch. + mispred: True if the branch was mispredicted. + predicted: True if the branch was predicted. + in_tx: True if the branch was in a transaction. + abort: True if the branch was an abort. + cycles: Number of cycles since the last branch. + type: Type of branch. + """ + from_ip: int + to_ip: int + mispred: bool + predicted: bool + in_tx: bool + abort: bool + cycles: int + type: int + +class branch_stack: + """Sequence of branch entries in the branch stack.""" + def __len__(self) -> int: ... + def __getitem__(self, index: int) -> branch_entry: ... + +class callchain_node: + """Represents a frame in the callchain.""" + ip: int + symbol: Optional[str] + dso: Optional[str] + +class callchain: + """Sequence of callchain frames.""" + def __len__(self) -> int: ... + def __getitem__(self, index: int) -> callchain_node: ... + +class stat_event(_sample_members): + """Represents a stat event from perf.""" + type: int + id: int + cpu: int + thread: int + val: int + ena: int + run: int + evsel: Optional['evsel'] + +class stat_round_event(_sample_members): + """Represents a stat round event from perf.""" + type: int + time: int + stat_round_type: int + evsel: Optional['evsel'] + +class cpu_map: + """Map of CPUs being monitored.""" + def __init__(self, cpustr: Optional[str] = None) -> None: ... + def __len__(self) -> int: ... + def __getitem__(self, index: int) -> int: ... + def __iter__(self) -> Iterator[int]: ... + + +class evlist: + def __init__(self, cpus: cpu_map, threads: thread_map) -> None: ... + def open(self) -> None: + """Open the events in the list.""" + ... + def close(self) -> None: + """Close the events in the list.""" + ... + def mmap(self) -> None: + """Memory map the event buffers.""" + ... + def poll(self, timeout: int) -> int: + """Poll for events. + + Args: + timeout: Timeout in milliseconds. + + Returns: + Number of events ready. + """ + ... + def read_on_cpu(self, cpu: int) -> Optional[Any]: + """Read a sample event from a specific CPU. + + Args: + cpu: The CPU number. + + Returns: + A sample_event or other event type if available, or None. + """ + ... + def all_cpus(self) -> cpu_map: + """Get a cpu_map of all CPUs in the system.""" + ... + def metrics(self) -> List[str]: + """Get a list of metric names within the evlist.""" + ... + def compute_metric(self, metric: str, cpu: int, thread: int) -> float: + """Compute metric for given name, cpu and thread. + + Args: + metric: The metric name. + cpu: The CPU number. + thread: The thread ID. + + Returns: + The computed metric value. + """ + ... + def config(self) -> None: + """Configure the events in the list.""" + ... + def disable(self) -> None: + """Disable all events in the list.""" + ... + def enable(self) -> None: + """Enable all events in the list.""" + ... + def get_pollfd(self) -> List[int]: + """Get a list of file descriptors for polling.""" + ... + def add(self, evsel: evsel) -> int: + """Add an event to the list.""" + ... + def __iter__(self) -> Iterator[evsel]: + """Iterate over the events (evsel) in the list.""" + ... + + +class session: + def __init__( + self, + data: data, + sample: Optional[Callable[[sample_event], None]] = None, + stat: Optional[Callable[[Any, Optional[str]], None]] = None + ) -> None: + """Initialize a perf session. + + Args: + data: The perf data file to read. + sample: Callback for sample events. + stat: Callback for stat events. + """ + ... + def process_events(self) -> None: + """Process all events in the session.""" + ... + def find_thread(self, pid: int) -> thread: + """Returns the thread associated with a pid.""" + ... + +# Event Types +TYPE_HARDWARE: int +"""Hardware event.""" + +TYPE_SOFTWARE: int +"""Software event.""" + +TYPE_TRACEPOINT: int +"""Tracepoint event.""" + +TYPE_HW_CACHE: int +"""Hardware cache event.""" + +TYPE_RAW: int +"""Raw hardware event.""" + +TYPE_BREAKPOINT: int +"""Breakpoint event.""" + + +# Hardware Counters +COUNT_HW_CPU_CYCLES: int +"""Total cycles. Be wary of what happens during CPU frequency scaling.""" + +COUNT_HW_INSTRUCTIONS: int +"""Retired instructions. Be careful, these can be affected by various issues, +most notably hardware interrupt counts.""" + +COUNT_HW_CACHE_REFERENCES: int +"""Cache accesses. Usually this indicates Last Level Cache accesses but this +may vary depending on your CPU.""" + +COUNT_HW_CACHE_MISSES: int +"""Cache misses. Usually this indicates Last Level Cache misses.""" + +COUNT_HW_BRANCH_INSTRUCTIONS: int +"""Retired branch instructions.""" + +COUNT_HW_BRANCH_MISSES: int +"""Mispredicted branch instructions.""" + +COUNT_HW_BUS_CYCLES: int +"""Bus cycles, which can be different from total cycles.""" + +COUNT_HW_STALLED_CYCLES_FRONTEND: int +"""Stalled cycles during issue [This event is an alias of idle-cycles-frontend].""" + +COUNT_HW_STALLED_CYCLES_BACKEND: int +"""Stalled cycles during retirement [This event is an alias of idle-cycles-backend].""" + +COUNT_HW_REF_CPU_CYCLES: int +"""Total cycles; not affected by CPU frequency scaling.""" + + +# Cache Counters +COUNT_HW_CACHE_L1D: int +"""Level 1 data cache.""" + +COUNT_HW_CACHE_L1I: int +"""Level 1 instruction cache.""" + +COUNT_HW_CACHE_LL: int +"""Last Level Cache.""" + +COUNT_HW_CACHE_DTLB: int +"""Data TLB.""" + +COUNT_HW_CACHE_ITLB: int +"""Instruction TLB.""" + +COUNT_HW_CACHE_BPU: int +"""Branch Processing Unit.""" + +COUNT_HW_CACHE_OP_READ: int +"""Read accesses.""" + +COUNT_HW_CACHE_OP_WRITE: int +"""Write accesses.""" + +COUNT_HW_CACHE_OP_PREFETCH: int +"""Prefetch accesses.""" + +COUNT_HW_CACHE_RESULT_ACCESS: int +"""Accesses.""" + +COUNT_HW_CACHE_RESULT_MISS: int +"""Misses.""" + + +# Software Counters +COUNT_SW_CPU_CLOCK: int +"""CPU clock event.""" + +COUNT_SW_TASK_CLOCK: int +"""Task clock event.""" + +COUNT_SW_PAGE_FAULTS: int +"""Page faults.""" + +COUNT_SW_CONTEXT_SWITCHES: int +"""Context switches.""" + +COUNT_SW_CPU_MIGRATIONS: int +"""CPU migrations.""" + +COUNT_SW_PAGE_FAULTS_MIN: int +"""Minor page faults.""" + +COUNT_SW_PAGE_FAULTS_MAJ: int +"""Major page faults.""" + +COUNT_SW_ALIGNMENT_FAULTS: int +"""Alignment faults.""" + +COUNT_SW_EMULATION_FAULTS: int +"""Emulation faults.""" + +COUNT_SW_DUMMY: int +"""Dummy event.""" + + +# Sample Fields +SAMPLE_IP: int +"""Instruction pointer.""" + +SAMPLE_TID: int +"""Process and thread ID.""" + +SAMPLE_TIME: int +"""Timestamp.""" + +SAMPLE_ADDR: int +"""Sampled address.""" + +SAMPLE_READ: int +"""Read barcode.""" + +SAMPLE_CALLCHAIN: int +"""Call chain.""" + +SAMPLE_ID: int +"""Unique ID.""" + +SAMPLE_CPU: int +"""CPU number.""" + +SAMPLE_PERIOD: int +"""Sample period.""" + +SAMPLE_STREAM_ID: int +"""Stream ID.""" + +SAMPLE_RAW: int +"""Raw sample.""" + + +# Format Fields +FORMAT_TOTAL_TIME_ENABLED: int +"""Total time enabled.""" + +FORMAT_TOTAL_TIME_RUNNING: int +"""Total time running.""" + +FORMAT_ID: int +"""Event ID.""" + +FORMAT_GROUP: int +"""Event group.""" + + +# Record Types +RECORD_MMAP: int +"""MMAP record. Contains header, pid, tid, addr, len, pgoff, filename, and sample_id.""" + +RECORD_LOST: int +"""Lost events record. Contains header, id, lost count, and sample_id.""" + +RECORD_COMM: int +"""COMM record. Contains header, pid, tid, comm, and sample_id.""" + +RECORD_EXIT: int +"""EXIT record. Contains header, pid, ppid, tid, ptid, time, and sample_id.""" + +RECORD_THROTTLE: int +"""THROTTLE record. Contains header, time, id, stream_id, and sample_id.""" + +RECORD_UNTHROTTLE: int +"""UNTHROTTLE record. Contains header, time, id, stream_id, and sample_id.""" + +RECORD_FORK: int +"""FORK record. Contains header, pid, ppid, tid, ptid, time, and sample_id.""" + +RECORD_READ: int +"""READ record. Contains header, and read values.""" + +RECORD_SAMPLE: int +"""SAMPLE record. Contains header, and sample data requested by sample_type.""" + +RECORD_MMAP2: int +"""MMAP2 record. Contains header, pid, tid, addr, len, pgoff, maj, min, ino, +ino_generation, prot, flags, filename, and sample_id.""" + +RECORD_AUX: int +"""AUX record. Contains header, aux_offset, aux_size, flags, and sample_id.""" + +RECORD_ITRACE_START: int +"""ITRACE_START record. Contains header, pid, tid, and sample_id.""" + +RECORD_LOST_SAMPLES: int +"""LOST_SAMPLES record. Contains header, lost count, and sample_id.""" + +RECORD_SWITCH: int +"""SWITCH record. Contains header, and sample_id.""" + +RECORD_SWITCH_CPU_WIDE: int +"""SWITCH_CPU_WIDE record. Contains header, and sample_id.""" + +RECORD_STAT: int +"""STAT record.""" + +RECORD_STAT_ROUND: int +"""STAT_ROUND record.""" + +RECORD_MISC_SWITCH_OUT: int +"""MISC_SWITCH_OUT record.""" diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index a0ce76624a23..cb14554454a2 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py @@ -2,6 +2,7 @@ from os import getenv, path from subprocess import Popen, PIPE from re import sub import shlex +import shutil cc = getenv("CC") assert cc, "Environment variable CC not set" @@ -73,6 +74,10 @@ class install_lib(_install_lib): _install_lib.finalize_options(self) self.build_dir = build_lib + def run(self): + _install_lib.run(self) + shutil.copy2(f'{src_perf}/python/perf.pyi', self.install_dir) + # switch off several checks (need to be at the end of cflags list) extra_cflags = ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter', '-Wno-redundant-decls' ] -- cgit v1.2.3 From 270e3f076b509c24d8cf69dde11db12d64706113 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Jun 2026 18:15:43 -0700 Subject: perf python: Add LiveSession helper Add LiveSession class in tools/perf/python/perf_live.py to support live event collection using perf.evlist and perf.parse_events, avoiding the need to fork a separate perf record process. Signed-off-by: Ian Rogers Assisted-by: Gemini:gemini-3.1-pro-preview Cc: Adrian Hunter Cc: Alice Rogers Cc: Dapeng Mi Cc: Ingo Molnar Cc: James Clark Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/python/perf_live.py | 59 ++++++++++++++++++++++++++++++ tools/perf/tests/shell/lib/setup_python.sh | 13 +++++++ 2 files changed, 72 insertions(+) create mode 100755 tools/perf/python/perf_live.py diff --git a/tools/perf/python/perf_live.py b/tools/perf/python/perf_live.py new file mode 100755 index 000000000000..616b5f657463 --- /dev/null +++ b/tools/perf/python/perf_live.py @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-2.0 +""" +Live event session helper using perf.evlist. + +This module provides a LiveSession class that allows running a callback +for each event collected live from the system, similar to perf.session +but without requiring a perf.data file. +""" + +import perf + + +class LiveSession: + """Represents a live event collection session.""" + + def __init__(self, event_string: str, sample_callback): + self.event_string = event_string + self.sample_callback = sample_callback + # Create a cpu map for all online CPUs + self.cpus = perf.cpu_map() + # Parse events and set maps + self.evlist = perf.parse_events(self.event_string, self.cpus) + self.evlist.config() + + def run(self): + """Run the live session.""" + try: + self.evlist.open() + self.evlist.mmap() + self.evlist.enable() + + while True: + # Poll for events with 100ms timeout + try: + self.evlist.poll(100) + except InterruptedError: + continue + for cpu in self.cpus: + for _ in range(1000): # Limit to 1000 events per CPU per poll to prevent starvation + try: + event = self.evlist.read_on_cpu(cpu) + except TypeError as e: + if "Unknown CPU" in str(e): + # CPU might be unmapped or offline, wait for mmap event + break + if "Unexpected header type" in str(e): + # Ignore valid but unsupported event types + continue + raise + + if event is None: + break + + if event.type == perf.RECORD_SAMPLE: + self.sample_callback(event) + except KeyboardInterrupt: + pass + finally: + self.evlist.close() diff --git a/tools/perf/tests/shell/lib/setup_python.sh b/tools/perf/tests/shell/lib/setup_python.sh index a58e5536f2ed..2173215a0517 100644 --- a/tools/perf/tests/shell/lib/setup_python.sh +++ b/tools/perf/tests/shell/lib/setup_python.sh @@ -14,3 +14,16 @@ then echo Skipping test, python not detected please set environment variable PYTHON. exit 2 fi + +# Set PYTHONPATH to find the in-tree built perf.so first, avoiding system-wide perf.so +if [ -n "$PERF_EXEC_PATH" ] && [ -d "$PERF_EXEC_PATH/python" ]; then + PYTHONPATH_DIR="$PERF_EXEC_PATH/python" +elif [ -d "$(dirname "$0")/../../python" ]; then + PYTHONPATH_DIR="$(dirname "$0")/../../python" +elif [ -d "$(dirname "$0")/../python" ]; then + PYTHONPATH_DIR="$(dirname "$0")/../python" +fi + +if [ -n "$PYTHONPATH_DIR" ]; then + export PYTHONPATH="$PYTHONPATH_DIR${PYTHONPATH:+:$PYTHONPATH}" +fi -- cgit v1.2.3 From 2b123a1a09e94e02148157cdafd261f06b534940 Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Sun, 7 Jun 2026 19:32:45 +0530 Subject: tools/perf/sched: Update process names of processes in zombie state for both -s and -S options In redhat perftool testsuite, observed fail for this test: -- [ FAIL ] -- perf_sched :: test_timehist :: --with-summary (output regexp parsing) This led to analysis of "perf sched timehist" summary options. # perf sched record -a -o ./perf.data -- sleep 0.1 This will record using perf sched record perf sched timeliest has two options "-s" and "-S" # perf sched -i ./perf.data timehist -S -S : Captures summary also at the end # perf sched -i ./perf.data timehist -s -s : Captures only summary The test saves -s result which has only summary and compares with summary which comes at the end from -S . Since there is a difference in these two, test fails. Checking the behaviour change in -S and -s results, difference is: rcu_sched[16] 2 4 0.013 0.001 0.003 0.006 33.23 0 migration/11[73] 2 1 0.006 0.006 0.006 0.006 0.00 0 migration/3[33] 2 1 0.006 0.006 0.006 0.006 0.00 0 - :216753[216753] -1 1 0.041 0.041 0.041 0.041 0.00 0 + sleep[216753] -1 1 0.041 0.041 0.041 0.041 0.00 0 migration/8[58] 2 1 0.005 0.005 0.005 0.005 0.00 0 NetworkManager[811] 1 2 0.089 0.028 0.044 0.060 36.06 0 migration/13[83] 2 1 0.005 0.005 0.005 0.005 0.00 0 Here 216753 is pid for sleep which is a zombie process. This is happening in latest kernel due to an update in "-S" result. In -S, the process name appears in the results "sleep[216753]", where as in the -s, only pid is present in the summary result ":216753[216753]". After commit 39f473f6d0b2 ("perf sched timehist: decode process names of processes in zombie state") for -S option, if process name is using pid, it uses different way to set it. So that we get the process name and not just Pid. This change went in only for timehist_print_sample() function. Add this improvement in generic place so that even -s option (which captures summary) also will have meaningful information. Acked-by: Namhyung Kim Tested-by: Venkat Rao Bagalkote Signed-off-by: Athira Rajeev Signed-off-by: Namhyung Kim --- tools/perf/builtin-sched.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index ae033ffd1079..6e0d8f4d270e 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -2270,12 +2270,6 @@ static void timehist_print_sample(struct perf_sched *sched, printf(" "); } - if (!thread__comm_set(thread)) { - const char *prev_comm = perf_sample__strval(sample, "prev_comm"); - - thread__set_comm(thread, prev_comm, sample->time); - } - printf(" %-*s ", comm_width, timehist_get_commstr(thread)); if (sched->show_prio) @@ -2981,6 +2975,16 @@ static int timehist_sched_change_event(const struct perf_tool *tool, thread__zput(itr->last_thread); } + /* + * If the process name is not set for the thread, use "prev_comm" + * to set it. Otherwise the sched summary will have just pid information + */ + if (!thread__comm_set(thread)) { + const char *prev_comm = perf_sample__strval(sample, "prev_comm"); + + thread__set_comm(thread, prev_comm, sample->time); + } + if (!sched->summary_only) timehist_print_sample(sched, sample, &al, thread, t, state); } -- cgit v1.2.3 From be4147c51a65d52b9d92e3a33f35ecb88357d33a Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Tue, 9 Jun 2026 14:50:40 -0700 Subject: perf vendor events intel: Update arrowlake events from 1.17 to 1.19 The updated events were published in: https://github.com/intel/perfmon/commit/b84e75626ae78558b8f526a276e4597c5ca6c429 Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Reviewed-by: Ian Rogers Link: https://github.com/intel/perfmon/commit/b84e75626ae78558b8f526a276e4597c5ca6c429 Signed-off-by: Namhyung Kim --- .../perf/pmu-events/arch/x86/arrowlake/cache.json | 30 ++++- .../arch/x86/arrowlake/floating-point.json | 45 +++++++ .../perf/pmu-events/arch/x86/arrowlake/memory.json | 18 +++ .../pmu-events/arch/x86/arrowlake/pipeline.json | 129 ++++++++++++++++++++- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 5 files changed, 217 insertions(+), 7 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/cache.json b/tools/perf/pmu-events/arch/x86/arrowlake/cache.json index fe6b9ad68f87..142f62c59531 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/cache.json @@ -1,6 +1,6 @@ [ { - "BriefDescription": "Counts the number of request that were not accepted into the L2Q because the L2Q is FULL.", + "BriefDescription": "Counts the number of requests that were not accepted into the L2Q because the L2Q is FULL.", "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x31", "EventName": "CORE_REJECT_L2Q.ANY", @@ -8,6 +8,15 @@ "SampleAfterValue": "1000003", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of requests that were not accepted into the L2Q because the L2Q is FULL.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x31", + "EventName": "CORE_REJECT_L2Q.ANY", + "PublicDescription": "Counts the number of (demand and L1 prefetchers) core requests rejected by the L2Q due to a full or nearly full w condition which likely indicates back pressure from L2Q. It also counts requests that would have gone directly to the XQ, but are rejected due to a full or nearly full condition, indicating back pressure from the IDI link. The L2Q may also reject transactions from a core to insure fairness between cores, or to delay a cores dirty eviction when the address conflicts incoming external snoops. (Note that L2 prefetcher requests that are dropped are not counted by this event.) Counts on a per core basis.", + "SampleAfterValue": "200003", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of L1D cacheline (dirty) evictions caused by load misses, stores, and prefetches.", "Counter": "0,1,2,3,4,5,6,7", @@ -310,6 +319,15 @@ "SampleAfterValue": "1000003", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of demand and prefetch transactions that the External Queue (XQ) rejects due to a full or near full condition.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x30", + "EventName": "L2_REJECT_XQ.ANY", + "PublicDescription": "Counts the number of demand and prefetch transactions that the External Queue (XQ) rejects due to a full or near full condition which likely indicates back pressure from the IDI link. The XQ may reject transactions from the L2Q (non-cacheable requests), BBL (L2 misses) and WOB (L2 write-back victims).", + "SampleAfterValue": "200003", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of L2 Cache Accesses Counts the total number of L2 Cache Accesses - sum of hits, misses, rejects front door requests for CRd/DRd/RFO/ItoM/L2 Prefetches only, per core event", "Counter": "0,1,2,3,4,5,6,7", @@ -1382,6 +1400,16 @@ "UMask": "0x83", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of memory uops retired. A single uop that performs both a load AND a store will be counted as 1, not 2 (e.g. ADD [mem], CONST)", + "Counter": "0,1,2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_UOPS_RETIRED.ALL", + "SampleAfterValue": "200003", + "UMask": "0x83", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of load uops retired.", "Counter": "0,1,2,3,4,5,6,7", diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/floating-point.json b/tools/perf/pmu-events/arch/x86/arrowlake/floating-point.json index c54fc201a6ca..8dc3a11350c5 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/floating-point.json @@ -510,6 +510,15 @@ "UMask": "0x1f", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of uops executed on all floating point ports.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.ALL", + "SampleAfterValue": "1000003", + "UMask": "0xf", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 0.", "Counter": "0,1,2,3,4,5,6,7", @@ -519,6 +528,15 @@ "UMask": "0x2", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 0.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.P0", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 1.", "Counter": "0,1,2,3,4,5,6,7", @@ -528,6 +546,15 @@ "UMask": "0x4", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 1.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.P1", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 2.", "Counter": "0,1,2,3,4,5,6,7", @@ -537,6 +564,15 @@ "UMask": "0x8", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 2.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.P2", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 3.", "Counter": "0,1,2,3,4,5,6,7", @@ -555,6 +591,15 @@ "UMask": "0x1e", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 0, 1, 2.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.PRIMARY", + "SampleAfterValue": "1000003", + "UMask": "0xe", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of uops executed on floating point and vector integer store data port.", "Counter": "0,1,2,3,4,5,6,7", diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/memory.json b/tools/perf/pmu-events/arch/x86/arrowlake/memory.json index 05cc46518232..44922186c2b0 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/memory.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/memory.json @@ -173,6 +173,15 @@ "UMask": "0x2", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to request buffers full or lock in progress.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.WCB_FULL", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to request buffers full or lock in progress.", "Counter": "0,1,2,3,4,5,6,7", @@ -182,6 +191,15 @@ "UMask": "0x82", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to request buffers full or lock in progress.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.WCB_FULL_AT_RET", + "SampleAfterValue": "1000003", + "UMask": "0x82", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of memory ordering machine clears triggered due to a snoop from an external agent. Does not count internally generated machine clears such as those due to disambiguations.", "Counter": "0,1,2,3,4,5,6,7", diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/pipeline.json b/tools/perf/pmu-events/arch/x86/arrowlake/pipeline.json index a0fd63cace22..bdfee0347cc5 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/pipeline.json @@ -209,7 +209,6 @@ "EventName": "BR_INST_RETIRED.COND_TAKEN_FWD", "PublicDescription": "Counts taken forward conditional branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", - "UMask": "0x102", "Unit": "cpu_core" }, { @@ -608,7 +607,7 @@ "EventName": "BR_MISP_RETIRED.COND_TAKEN_BWD_COST", "PublicDescription": "number of branch instructions retired that were mispredicted and taken backward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", - "UMask": "0x8001", + "UMask": "0x41", "Unit": "cpu_core" }, { @@ -637,7 +636,7 @@ "EventName": "BR_MISP_RETIRED.COND_TAKEN_FWD_COST", "PublicDescription": "number of branch instructions retired that were mispredicted and taken forward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", - "UMask": "0x8002", + "UMask": "0x140", "Unit": "cpu_core" }, { @@ -773,11 +772,11 @@ "Unit": "cpu_core" }, { - "BriefDescription": "This event counts the number of mispredicted ret instructions retired. Non PEBS", + "BriefDescription": "This event counts the number of mispredicted ret instructions retired.", "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.RET", - "PublicDescription": "This is a non-precise version (that is, does not use PEBS) of the event that counts mispredicted return instructions retired. Available PDIST counters: 0,1", + "PublicDescription": "This event counts the number of mispredicted ret instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x8", "Unit": "cpu_core" @@ -1326,6 +1325,15 @@ "UMask": "0xff", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of uops executed on all Integer ports.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.ALL", + "SampleAfterValue": "1000003", + "UMask": "0xff", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of uops executed on a load port.", "Counter": "0,1,2,3,4,5,6,7", @@ -1336,6 +1344,16 @@ "UMask": "0x1", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of uops executed on a load port.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.LD", + "PublicDescription": "Counts the number of uops executed on a load port. This event counts for integer uops even if the destination is FP/vector", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of uops executed on integer port 0.", "Counter": "0,1,2,3,4,5,6,7", @@ -1345,6 +1363,15 @@ "UMask": "0x8", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of uops executed on integer port 0.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.P0", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of uops executed on integer port 1.", "Counter": "0,1,2,3,4,5,6,7", @@ -1354,6 +1381,15 @@ "UMask": "0x10", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of uops executed on integer port 1.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.P1", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of uops executed on integer port 2.", "Counter": "0,1,2,3,4,5,6,7", @@ -1363,6 +1399,15 @@ "UMask": "0x20", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of uops executed on integer port 2.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.P2", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of uops executed on integer port 3.", "Counter": "0,1,2,3,4,5,6,7", @@ -1372,6 +1417,15 @@ "UMask": "0x40", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of uops executed on integer port 3.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.P3", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of uops executed on integer port 0,1, 2, 3.", "Counter": "0,1,2,3,4,5,6,7", @@ -1381,6 +1435,15 @@ "UMask": "0x78", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of uops executed on integer port 0,1, 2, 3.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.PRIMARY", + "SampleAfterValue": "1000003", + "UMask": "0x78", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of uops executed on a Store address port.", "Counter": "0,1,2,3,4,5,6,7", @@ -1391,6 +1454,16 @@ "UMask": "0x2", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of uops executed on a Store address port.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.STA", + "PublicDescription": "Counts the number of uops executed on a Store address port. This event counts integer uops even if the data source is FP/vector", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of uops executed on an integer store data and jump port.", "Counter": "0,1,2,3,4,5,6,7", @@ -1400,6 +1473,15 @@ "UMask": "0x4", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of uops executed on an integer store data and jump port.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.STD_JMP", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Number of vector integer instructions retired of 128-bit vector-width.", "Counter": "0,1,2,3,4,5,6,7,8,9", @@ -1691,6 +1773,15 @@ "UMask": "0x88", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of machine clears that flush the pipeline and restart the machine without the use of microcode.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.FAST", + "SampleAfterValue": "20003", + "UMask": "0x10", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts number of virtual trap actually taken (e.g. highest priority event during retirement). It can count virtual trap from FPC port 0 or port 1 (x87/SSE) equally in a single counter.", "Counter": "0,1,2,3,4,5,6,7", @@ -1700,6 +1791,15 @@ "UMask": "0x40", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of virtual traps taken.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.FPC_VIRTUAL_TRAP", + "SampleAfterValue": "20003", + "UMask": "0x40", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of nukes due to memory renaming", "Counter": "0,1,2,3,4,5,6,7", @@ -2015,6 +2115,15 @@ "UMask": "0x8", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of issue slots not consumed due to a color request for an FCW or MXCSR control register when all 4 colors (copies) are already in use.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x75", + "EventName": "SERIALIZATION.COLOR_STALLS", + "SampleAfterValue": "200003", + "UMask": "0x8", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "Counts the number of issue slots where no uop could issue due to an IQ scoreboard that stalls allocation until a specified older uop retires or (in the case of jump scoreboard) executes. Commonly executed instructions with IQ scoreboards include LFENCE and MFENCE.", "Counter": "0,1,2,3,4,5,6,7", @@ -2034,6 +2143,16 @@ "UMask": "0x2", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of issue slots not consumed by the backend due to a micro-sequencer (MS) scoreboard, which stalls the front-end from issuing from the UROM until a specified older uop retires.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x75", + "EventName": "SERIALIZATION.NON_C01_MS_SCB", + "PublicDescription": "Counts the number of issue slots not consumed by the backend due to a micro-sequencer (MS) scoreboard, which stalls the front-end from issuing from the UROM until a specified older uop retires. The most commonly executed instruction with an MS scoreboard is PAUSE.", + "SampleAfterValue": "200003", + "UMask": "0x2", + "Unit": "cpu_lowpower" + }, { "BriefDescription": "This event counts a subset of the Topdown Slots event that were not consumed by the back-end pipeline due to lack of back-end resources, as a result of memory subsystem delays, execution units limitations, or other conditions.", "Counter": "0,1,2,3,4,5,6,7,8,9", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 50a403b429b1..613881d04a9a 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -1,7 +1,7 @@ Family-model,Version,Filename,EventType GenuineIntel-6-(97|9A|B7|BA|BF),v1.39,alderlake,core GenuineIntel-6-BE,v1.39,alderlaken,core -GenuineIntel-6-C[56],v1.17,arrowlake,core +GenuineIntel-6-C[56],v1.19,arrowlake,core GenuineIntel-6-(1C|26|27|35|36),v5,bonnell,core GenuineIntel-6-(3D|47),v30,broadwell,core GenuineIntel-6-56,v12,broadwellde,core -- cgit v1.2.3 From edb496df1675ba555d0038d724ee463c77d46f57 Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Tue, 9 Jun 2026 14:50:41 -0700 Subject: perf vendor events intel: Update emeraldrapids events from 1.23 to 1.24 The updated events were published in: https://github.com/intel/perfmon/commit/3f1d40d1953193e75c6b5a559638cf1f67bacaed Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/pmu-events/arch/x86/emeraldrapids/cache.json | 9 +++++++++ tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/cache.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/cache.json index ff6071d7728e..a44e1f027c1d 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/cache.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/cache.json @@ -368,6 +368,15 @@ "SampleAfterValue": "200003", "UMask": "0x40" }, + { + "BriefDescription": "Cycles when L1D is locked", + "Counter": "0,1,2,3", + "EventCode": "0x42", + "EventName": "LOCK_CYCLES.CACHE_LOCK_DURATION", + "PublicDescription": "This event counts the number of cycles when the L1D is locked. It is a superset of the 0x1 mask (BUS_LOCK_CLOCKS.BUS_LOCK_DURATION).", + "SampleAfterValue": "2000003", + "UMask": "0x2" + }, { "BriefDescription": "Core-originated cacheable requests that missed L3 (Except hardware prefetches to the L3)", "Counter": "0,1,2,3,4,5,6,7", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 613881d04a9a..0f39073805ba 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -9,7 +9,7 @@ GenuineIntel-6-4F,v23,broadwellx,core GenuineIntel-6-55-[56789ABCDEF],v1.25,cascadelakex,core GenuineIntel-6-DD,v1.02,clearwaterforest,core GenuineIntel-6-9[6C],v1.05,elkhartlake,core -GenuineIntel-6-CF,v1.23,emeraldrapids,core +GenuineIntel-6-CF,v1.24,emeraldrapids,core GenuineIntel-6-5[CF],v13,goldmont,core GenuineIntel-6-7A,v1.01,goldmontplus,core GenuineIntel-6-B6,v1.12,grandridge,core -- cgit v1.2.3 From 2bf556fe2da38a5159fdbdd44516928a366d0e06 Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Tue, 9 Jun 2026 14:50:42 -0700 Subject: perf vendor events intel: Update graniterapids events from 1.18 to 1.19 The updated events were published in: https://github.com/intel/perfmon/commit/875354c88686ef50387d9601f52354a6da8f24cc Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim --- .../pmu-events/arch/x86/graniterapids/uncore-interconnect.json | 10 ++++++++++ .../perf/pmu-events/arch/x86/graniterapids/uncore-memory.json | 2 +- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/graniterapids/uncore-interconnect.json index 5eb1145f204f..9f0c4c7198b0 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/uncore-interconnect.json @@ -808,6 +808,16 @@ "PerPkg": "1", "Unit": "IRP" }, + { + "BriefDescription": "Counts Timeouts - Set 0 : Cache Inserts of Write Transactions as Secondary", + "Counter": "0,1,2,3", + "EventCode": "0x1E", + "EventName": "UNC_I_MISC0.2ND_WR_INSERT", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x8", + "Unit": "IRP" + }, { "BriefDescription": "Counts Timeouts - Set 0 : Fastpath Rejects", "Counter": "0,1,2,3", diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/uncore-memory.json b/tools/perf/pmu-events/arch/x86/graniterapids/uncore-memory.json index f559e27e2815..9cd2905726fd 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/uncore-memory.json @@ -539,7 +539,7 @@ "Unit": "IMC" }, { - "BriefDescription": "DRAM Precharge commands. : Precharge due to (?) : Counts the number of DRAM Precharge commands sent on this channel.", + "BriefDescription": "DRAM Precharge commands. : Precharge due to page table : Counts the number of DRAM Precharge commands sent on this channel.", "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "UNC_M_PRE_COUNT.PGT", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 0f39073805ba..b8ea72b99c52 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -13,7 +13,7 @@ GenuineIntel-6-CF,v1.24,emeraldrapids,core GenuineIntel-6-5[CF],v13,goldmont,core GenuineIntel-6-7A,v1.01,goldmontplus,core GenuineIntel-6-B6,v1.12,grandridge,core -GenuineIntel-6-A[DE],v1.18,graniterapids,core +GenuineIntel-6-A[DE],v1.19,graniterapids,core GenuineIntel-6-(3C|45|46),v36,haswell,core GenuineIntel-6-3F,v29,haswellx,core GenuineIntel-6-7[DE],v1.24,icelake,core -- cgit v1.2.3 From cd0361df27509401f729f834468855b8412feb87 Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Tue, 9 Jun 2026 14:50:43 -0700 Subject: perf vendor events intel: Update lunarlake events from 1.22 to 1.25 The updated events were published in: https://github.com/intel/perfmon/commit/5535a3e8cc14ae8ef58013cf3d8e9480018b911a Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim --- .../perf/pmu-events/arch/x86/lunarlake/cache.json | 2 +- .../pmu-events/arch/x86/lunarlake/pipeline.json | 27 ++- .../arch/x86/lunarlake/uncore-memory.json | 208 ++++++++++++++++++++- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 4 files changed, 228 insertions(+), 11 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/cache.json b/tools/perf/pmu-events/arch/x86/lunarlake/cache.json index 92a3667b4520..5b350233a5e1 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/cache.json @@ -1,6 +1,6 @@ [ { - "BriefDescription": "Counts the number of request that were not accepted into the L2Q because the L2Q is FULL.", + "BriefDescription": "Counts the number of requests that were not accepted into the L2Q because the L2Q is FULL.", "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x31", "EventName": "CORE_REJECT_L2Q.ANY", diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json b/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json index d66eafccebbb..a7467b2f291d 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json @@ -190,7 +190,6 @@ "EventName": "BR_INST_RETIRED.COND_TAKEN_FWD", "PublicDescription": "Counts taken forward conditional branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", - "UMask": "0x102", "Unit": "cpu_core" }, { @@ -324,6 +323,15 @@ "UMask": "0xdf", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of taken branch instructions retired", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.TAKEN", + "SampleAfterValue": "200003", + "UMask": "0x80", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts the total number of mispredicted branch instructions retired for all branch types.", "Counter": "0,1,2,3,4,5,6,7", @@ -446,7 +454,7 @@ "EventName": "BR_MISP_RETIRED.COND_TAKEN_BWD_COST", "PublicDescription": "number of branch instructions retired that were mispredicted and taken backward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", - "UMask": "0x8001", + "UMask": "0x41", "Unit": "cpu_core" }, { @@ -475,7 +483,7 @@ "EventName": "BR_MISP_RETIRED.COND_TAKEN_FWD_COST", "PublicDescription": "number of branch instructions retired that were mispredicted and taken forward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", - "UMask": "0x8002", + "UMask": "0x140", "Unit": "cpu_core" }, { @@ -575,11 +583,11 @@ "Unit": "cpu_core" }, { - "BriefDescription": "This event counts the number of mispredicted ret instructions retired. Non PEBS", + "BriefDescription": "This event counts the number of mispredicted ret instructions retired.", "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.RET", - "PublicDescription": "This is a non-precise version (that is, does not use PEBS) of the event that counts mispredicted return instructions retired. Available PDIST counters: 0,1", + "PublicDescription": "This event counts the number of mispredicted ret instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x8", "Unit": "cpu_core" @@ -1373,6 +1381,15 @@ "UMask": "0x88", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts number of virtual trap actually taken (e.g. highest priority event during retirement). It can count virtual trap from FPC port 0 or port 1 (x87/SSE) equally in a single counter.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.FPC_VIRTUAL_TRAP", + "SampleAfterValue": "20003", + "UMask": "0x40", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts the number of nukes due to memory renaming", "Counter": "0,1,2,3,4,5,6,7", diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/uncore-memory.json b/tools/perf/pmu-events/arch/x86/lunarlake/uncore-memory.json index 63c4aa2791e4..a1e79f06645a 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/uncore-memory.json @@ -1,6 +1,30 @@ [ { - "BriefDescription": "Read CAS command sent to DRAM", + "BriefDescription": "ACT command for a read request sent to DRAM.", + "Counter": "0,1,2,3,4", + "EventCode": "0x24", + "EventName": "UNC_M_ACT_COUNT_RD", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "ACT command sent to DRAM.", + "Counter": "0,1,2,3,4", + "EventCode": "0x26", + "EventName": "UNC_M_ACT_COUNT_TOTAL", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "ACT command for a write request sent to DRAM.", + "Counter": "0,1,2,3,4", + "EventCode": "0x25", + "EventName": "UNC_M_ACT_COUNT_WR", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Read CAS command sent to DRAM.", "Counter": "0,1,2,3,4", "EventCode": "0x22", "EventName": "UNC_M_CAS_COUNT_RD", @@ -8,7 +32,7 @@ "Unit": "iMC" }, { - "BriefDescription": "Write CAS command sent to DRAM", + "BriefDescription": "Write CAS command sent to DRAM.", "Counter": "0,1,2,3,4", "EventCode": "0x23", "EventName": "UNC_M_CAS_COUNT_WR", @@ -16,7 +40,94 @@ "Unit": "iMC" }, { - "BriefDescription": "Any Rank at Hot state", + "BriefDescription": "Counting the number of clocks.", + "Counter": "0,1,2,3,4", + "EventCode": "0x01", + "EventName": "UNC_M_CLOCKTICKS", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "CKE in DRAM is low.", + "Counter": "0,1,2,3,4", + "EventCode": "0x29", + "EventName": "UNC_M_DRAM_CKE_OFF_CYCLES", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming read request page status is Page Empty.", + "Counter": "0,1,2,3,4", + "EventCode": "0x1D", + "EventName": "UNC_M_DRAM_PAGE_EMPTY_RD", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "incoming read request page status is Page Empty", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming write request page status is Page Empty.", + "Counter": "0,1,2,3,4", + "EventCode": "0x20", + "EventName": "UNC_M_DRAM_PAGE_EMPTY_WR", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "incoming write request page status is Page Empty", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming read request page status is Page Hit.", + "Counter": "0,1,2,3,4", + "EventCode": "0x1C", + "EventName": "UNC_M_DRAM_PAGE_HIT_RD", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "incoming read request page status is Page Hit", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming write request page status is Page Hit.", + "Counter": "0,1,2,3,4", + "EventCode": "0x1F", + "EventName": "UNC_M_DRAM_PAGE_HIT_WR", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "incoming write request page status is Page Hit", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming read request page status is Page Miss.", + "Counter": "0,1,2,3,4", + "EventCode": "0x1E", + "EventName": "UNC_M_DRAM_PAGE_MISS_RD", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "incoming read request page status is Page Miss", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming write request page status is Page Miss.", + "Counter": "0,1,2,3,4", + "EventCode": "0x21", + "EventName": "UNC_M_DRAM_PAGE_MISS_WR", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "incoming write request page status is Page Miss", + "Unit": "iMC" + }, + { + "BriefDescription": "DRAM in Self-refresh (all channels).", + "Counter": "0,1,2,3,4", + "EventCode": "0x12", + "EventName": "UNC_M_DRAM_SELF_REFRESH", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Any Rank at Hot state.", "Counter": "0,1,2,3,4", "EventCode": "0x19", "EventName": "UNC_M_DRAM_THERMAL_HOT", @@ -25,7 +136,7 @@ "Unit": "iMC" }, { - "BriefDescription": "Any Rank at Warm state", + "BriefDescription": "Any Rank at Warm state.", "Counter": "0,1,2,3,4", "EventCode": "0x1A", "EventName": "UNC_M_DRAM_THERMAL_WARM", @@ -33,6 +144,42 @@ "PerPkg": "1", "Unit": "iMC" }, + { + "BriefDescription": "PRE command sent to DRAM for a read/write request.", + "Counter": "0,1,2,3,4", + "EventCode": "0x27", + "EventName": "UNC_M_PRE_COUNT_PAGE_MISS", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Counts number of bytes read, in 32B chunk, per DDR channel. Counter increments by 1 after receiving 32B chunk data.", + "Counter": "0,1,2,3,4", + "EventCode": "0x3A", + "EventName": "UNC_M_RD_DATA", + "PerPkg": "1", + "PublicDescription": "This counter counts number of bytes read, in 32B chunk, per DDR channel. Counter increments by 1 after receiving 32B chunk data.", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of VC0 read in channel0 - this event can increment by more than 1 (per channel/sub-ch).", + "Counter": "0,1,2,3,4", + "EventCode": "0x13", + "EventName": "UNC_M_RD_OCCUPANCY_CH0", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "Number of VC0 read in channel0 - this event can increment by more than 1 (per channel/sub-ch)", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of VC0 read in channel1 - this event can increment by more than 1 (per channel/sub-ch).", + "Counter": "0,1,2,3,4", + "EventCode": "0x14", + "EventName": "UNC_M_RD_OCCUPANCY_CH1", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, { "BriefDescription": "Total number of read and write byte transfers to/from DRAM, in 32B chunk, per DDR channel. Counter increments by 1 after sending or receiving 32B chunk data.", "Counter": "0,1,2,3,4", @@ -40,5 +187,58 @@ "EventName": "UNC_M_TOTAL_DATA", "PerPkg": "1", "Unit": "iMC" + }, + { + "BriefDescription": "Total number of requests entering MC, this is the sum of all RD + WR requests for all VCs.", + "Counter": "0,1,2,3,4", + "EventCode": "0x39", + "EventName": "UNC_M_TOTAL_REQUESTS", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming VC0 read request.", + "Counter": "0,1,2,3,4", + "EventCode": "0x02", + "EventName": "UNC_M_VC0_REQUESTS_RD", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming VC0 write request.", + "Counter": "0,1,2,3,4", + "EventCode": "0x03", + "EventName": "UNC_M_VC0_REQUESTS_WR", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming VC1 read request.", + "Counter": "0,1,2,3,4", + "EventCode": "0x04", + "EventName": "UNC_M_VC1_REQUESTS_RD", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming VC1 write request.", + "Counter": "0,1,2,3,4", + "EventCode": "0x05", + "EventName": "UNC_M_VC1_REQUESTS_WR", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Counts number of bytes written, in 32B chunk, per DDR channel. Counter increments by 1 after sending 32B chunk data.", + "Counter": "0,1,2,3,4", + "EventCode": "0x3B", + "EventName": "UNC_M_WR_DATA", + "PerPkg": "1", + "Unit": "iMC" } ] diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index b8ea72b99c52..7d19f8fa335a 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -22,7 +22,7 @@ GenuineIntel-6-3A,v24,ivybridge,core GenuineIntel-6-3E,v24,ivytown,core GenuineIntel-6-2D,v24,jaketown,core GenuineIntel-6-(57|85),v16,knightslanding,core -GenuineIntel-6-BD,v1.22,lunarlake,core +GenuineIntel-6-BD,v1.25,lunarlake,core GenuineIntel-6-(AA|AC|B5),v1.21,meteorlake,core GenuineIntel-6-1[AEF],v4,nehalemep,core GenuineIntel-6-2E,v4,nehalemex,core -- cgit v1.2.3 From 174845dc5135073764b65e4c909f1bf8b322418a Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Tue, 9 Jun 2026 14:50:44 -0700 Subject: perf vendor events intel: Update pantherlake events from 1.05 to 1.06 The updated events were published in: https://github.com/intel/perfmon/commit/ffc03fc3b414127c5a36bbb648e500c4afeff134 Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- .../pmu-events/arch/x86/pantherlake/counter.json | 5 + .../pmu-events/arch/x86/pantherlake/pipeline.json | 29 ++- .../arch/x86/pantherlake/uncore-interconnect.json | 10 + .../arch/x86/pantherlake/uncore-memory.json | 221 ++++++++++++++++++++- 5 files changed, 260 insertions(+), 7 deletions(-) create mode 100644 tools/perf/pmu-events/arch/x86/pantherlake/uncore-interconnect.json diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 7d19f8fa335a..6af3cee12c8a 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -26,7 +26,7 @@ GenuineIntel-6-BD,v1.25,lunarlake,core GenuineIntel-6-(AA|AC|B5),v1.21,meteorlake,core GenuineIntel-6-1[AEF],v4,nehalemep,core GenuineIntel-6-2E,v4,nehalemex,core -GenuineIntel-6-(CC|D5),v1.05,pantherlake,core +GenuineIntel-6-(CC|D5),v1.06,pantherlake,core GenuineIntel-6-A7,v1.04,rocketlake,core GenuineIntel-6-2A,v19,sandybridge,core GenuineIntel-6-8F,v1.39,sapphirerapids,core diff --git a/tools/perf/pmu-events/arch/x86/pantherlake/counter.json b/tools/perf/pmu-events/arch/x86/pantherlake/counter.json index 432b6946ccbc..9794b435f650 100644 --- a/tools/perf/pmu-events/arch/x86/pantherlake/counter.json +++ b/tools/perf/pmu-events/arch/x86/pantherlake/counter.json @@ -13,5 +13,10 @@ "Unit": "iMC", "CountersNumFixed": "0", "CountersNumGeneric": "5" + }, + { + "Unit": "SANTA", + "CountersNumFixed": 1, + "CountersNumGeneric": "0" } ] \ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/pantherlake/pipeline.json b/tools/perf/pmu-events/arch/x86/pantherlake/pipeline.json index d476bad5e2a7..5d5303c02954 100644 --- a/tools/perf/pmu-events/arch/x86/pantherlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/pantherlake/pipeline.json @@ -887,11 +887,32 @@ "Unit": "cpu_core" }, { - "BriefDescription": "This event counts the number of mispredicted ret instructions retired. Non PEBS [This event is alias to BR_MISP_RETIRED.RET]", + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_RETURN]", + "Counter": "0,1,2,3,4,5,6,7", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_RET", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_RETURN] Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of mispredicted near RET branch instructions retired. [This event is alias to BR_MISP_RETIRED.NEAR_RET]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_RETURN", + "PublicDescription": "Counts the number of mispredicted near RET branch instructions retired. [This event is alias to BR_MISP_RETIRED.NEAR_RET] Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "This event counts the number of mispredicted ret instructions retired [This event is alias to BR_MISP_RETIRED.RET]", "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.NEAR_RETURN", - "PublicDescription": "This is a non-precise version (that is, does not use PEBS) of the event that counts mispredicted return instructions retired. [This event is alias to BR_MISP_RETIRED.RET] Available PDIST counters: 0,1", + "PublicDescription": "This event counts the number of mispredicted ret instructions retired [This event is alias to BR_MISP_RETIRED.RET] Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x8", "Unit": "cpu_core" @@ -1726,7 +1747,7 @@ "Unit": "cpu_atom" }, { - "BriefDescription": "Counts the number of machines clears due to memory renaming.", + "BriefDescription": "Counts the number of machine clears due to memory renaming.", "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.MRN_NUKE", @@ -1930,7 +1951,7 @@ "Unit": "cpu_atom" }, { - "BriefDescription": "Counts the number issue slots not consumed due to a color request for an FCW or MXCSR control register when all 4 colors (copies) are already in use.", + "BriefDescription": "Counts the number of issue slots not consumed due to a color request for an FCW or MXCSR control register when all 4 colors (copies) are already in use.", "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x75", "EventName": "SERIALIZATION.COLOR_STALLS", diff --git a/tools/perf/pmu-events/arch/x86/pantherlake/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/pantherlake/uncore-interconnect.json new file mode 100644 index 000000000000..69ef928d57f6 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/pantherlake/uncore-interconnect.json @@ -0,0 +1,10 @@ +[ + { + "BriefDescription": "This 48-bit fixed counter counts the UCLK cycles.", + "Counter": "FIXED", + "EventCode": "0xff", + "EventName": "UNC_CLOCK.SOCKET", + "PerPkg": "1", + "Unit": "SANTA" + } +] diff --git a/tools/perf/pmu-events/arch/x86/pantherlake/uncore-memory.json b/tools/perf/pmu-events/arch/x86/pantherlake/uncore-memory.json index a881b99be5f3..8faa03e1c6d0 100644 --- a/tools/perf/pmu-events/arch/x86/pantherlake/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/pantherlake/uncore-memory.json @@ -1,6 +1,30 @@ [ { - "BriefDescription": "Read CAS command sent to DRAM", + "BriefDescription": "ACT command for a read request sent to DRAM.", + "Counter": "0,1,2,3,4", + "EventCode": "0x24", + "EventName": "UNC_M_ACT_COUNT_RD", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "ACT command sent to DRAM.", + "Counter": "0,1,2,3,4", + "EventCode": "0x26", + "EventName": "UNC_M_ACT_COUNT_TOTAL", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "ACT command for a write request sent to DRAM.", + "Counter": "0,1,2,3,4", + "EventCode": "0x25", + "EventName": "UNC_M_ACT_COUNT_WR", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Read CAS command sent to DRAM.", "Counter": "0,1,2,3,4", "EventCode": "0x22", "EventName": "UNC_M_CAS_COUNT_RD", @@ -8,13 +32,153 @@ "Unit": "iMC" }, { - "BriefDescription": "Write CAS command sent to DRAM", + "BriefDescription": "Write CAS command sent to DRAM.", "Counter": "0,1,2,3,4", "EventCode": "0x23", "EventName": "UNC_M_CAS_COUNT_WR", "PerPkg": "1", "Unit": "iMC" }, + { + "BriefDescription": "Counting the number of clocks.", + "Counter": "0,1,2,3,4", + "EventCode": "0x01", + "EventName": "UNC_M_CLOCKTICKS", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "CKE in DRAM is low.", + "Counter": "0,1,2,3,4", + "EventCode": "0x29", + "EventName": "UNC_M_DRAM_CKE_OFF_CYCLES", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming read request page status is Page Empty.", + "Counter": "0,1,2,3,4", + "EventCode": "0x1D", + "EventName": "UNC_M_DRAM_PAGE_EMPTY_RD", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "incoming read request page status is Page Empty", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming write request page status is Page Empty.", + "Counter": "0,1,2,3,4", + "EventCode": "0x20", + "EventName": "UNC_M_DRAM_PAGE_EMPTY_WR", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "incoming write request page status is Page Empty", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming read request page status is Page Hit.", + "Counter": "0,1,2,3,4", + "EventCode": "0x1C", + "EventName": "UNC_M_DRAM_PAGE_HIT_RD", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "incoming read request page status is Page Hit", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming write request page status is Page Hit.", + "Counter": "0,1,2,3,4", + "EventCode": "0x1F", + "EventName": "UNC_M_DRAM_PAGE_HIT_WR", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "incoming write request page status is Page Hit", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming read request page status is Page Miss.", + "Counter": "0,1,2,3,4", + "EventCode": "0x1E", + "EventName": "UNC_M_DRAM_PAGE_MISS_RD", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "incoming read request page status is Page Miss", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming write request page status is Page Miss.", + "Counter": "0,1,2,3,4", + "EventCode": "0x21", + "EventName": "UNC_M_DRAM_PAGE_MISS_WR", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "incoming write request page status is Page Miss", + "Unit": "iMC" + }, + { + "BriefDescription": "DRAM in Self-refresh (all channels).", + "Counter": "0,1,2,3,4", + "EventCode": "0x12", + "EventName": "UNC_M_DRAM_SELF_REFRESH", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Any Rank at Hot state.", + "Counter": "0,1,2,3,4", + "EventCode": "0x19", + "EventName": "UNC_M_DRAM_THERMAL_HOT", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Any Rank at Warm state.", + "Counter": "0,1,2,3,4", + "EventCode": "0x1A", + "EventName": "UNC_M_DRAM_THERMAL_WARM", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "PRE command sent to DRAM for a read/write request.", + "Counter": "0,1,2,3,4", + "EventCode": "0x27", + "EventName": "UNC_M_PRE_COUNT_PAGE_MISS", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Counts number of bytes read, in 32B chunk, per DDR channel. Counter increments by 1 after receiving 32B chunk data.", + "Counter": "0,1,2,3,4", + "EventCode": "0x3A", + "EventName": "UNC_M_RD_DATA", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of VC0 read in channel0 - this event can increment by more than 1 (per channel/sub-ch).", + "Counter": "0,1,2,3,4", + "EventCode": "0x13", + "EventName": "UNC_M_RD_OCCUPANCY_CH0", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "Number of VC0 read in channel0 - this event can increment by more than 1 (per channel/sub-ch)", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of VC0 read in channel1 - this event can increment by more than 1 (per channel/sub-ch).", + "Counter": "0,1,2,3,4", + "EventCode": "0x14", + "EventName": "UNC_M_RD_OCCUPANCY_CH1", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, { "BriefDescription": "Total number of read and write byte transfers to/from DRAM, in 32B chunk, per DDR channel. Counter increments by 1 after sending or receiving 32B chunk data.", "Counter": "0,1,2,3,4", @@ -22,5 +186,58 @@ "EventName": "UNC_M_TOTAL_DATA", "PerPkg": "1", "Unit": "iMC" + }, + { + "BriefDescription": "Total number of requests entering MC, this is the sum of all RD + WR requests for all VCs.", + "Counter": "0,1,2,3,4", + "EventCode": "0x39", + "EventName": "UNC_M_TOTAL_REQUESTS", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming VC0 read request.", + "Counter": "0,1,2,3,4", + "EventCode": "0x02", + "EventName": "UNC_M_VC0_REQUESTS_RD", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming VC0 write request.", + "Counter": "0,1,2,3,4", + "EventCode": "0x03", + "EventName": "UNC_M_VC0_REQUESTS_WR", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming VC1 read request.", + "Counter": "0,1,2,3,4", + "EventCode": "0x04", + "EventName": "UNC_M_VC1_REQUESTS_RD", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Incoming VC1 write request.", + "Counter": "0,1,2,3,4", + "EventCode": "0x05", + "EventName": "UNC_M_VC1_REQUESTS_WR", + "Experimental": "1", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Counts number of bytes written, in 32B chunk, per DDR channel. Counter increments by 1 after sending 32B chunk data.", + "Counter": "0,1,2,3,4", + "EventCode": "0x3B", + "EventName": "UNC_M_WR_DATA", + "PerPkg": "1", + "Unit": "iMC" } ] -- cgit v1.2.3 From eb6356c74ca0d781bfdc0c7e3ba3ddd2c132935e Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Tue, 9 Jun 2026 14:50:45 -0700 Subject: perf vendor events intel: Update tigerlake events from 1.18 to 1.19 The updated events were published in: https://github.com/intel/perfmon/commit/8353ffb63efcad6b6fac1a8c05d76e2d6317ae23 Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 6af3cee12c8a..a7f870669827 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -35,7 +35,7 @@ GenuineIntel-6-(37|4A|4C|4D|5A),v15,silvermont,core GenuineIntel-6-(4E|5E|8E|9E|A5|A6),v59,skylake,core GenuineIntel-6-55-[01234],v1.37,skylakex,core GenuineIntel-6-86,v1.23,snowridgex,core -GenuineIntel-6-8[CD],v1.18,tigerlake,core +GenuineIntel-6-8[CD],v1.19,tigerlake,core GenuineIntel-6-2C,v5,westmereep-dp,core GenuineIntel-6-25,v4,westmereep-sp,core GenuineIntel-6-2F,v4,westmereex,core -- cgit v1.2.3 From 156e027582a6086f5d1668a656d1f5b8f269106e Mon Sep 17 00:00:00 2001 From: Gautam Menghani Date: Tue, 2 Jun 2026 17:26:40 +0530 Subject: perf script powerpc: Update the hcall list with new hcalls Update the hcall list with the newer hcalls in PPC. [1]: github.com/torvalds/linux/blob/master/arch/powerpc/include/asm/hvcall.h Signed-off-by: Gautam Menghani Reviewed-by: Shivani Nittor Signed-off-by: Namhyung Kim --- tools/perf/scripts/python/powerpc-hcalls.py | 89 +++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/tools/perf/scripts/python/powerpc-hcalls.py b/tools/perf/scripts/python/powerpc-hcalls.py index 8b78dc790adb..f897d6a5e051 100644 --- a/tools/perf/scripts/python/powerpc-hcalls.py +++ b/tools/perf/scripts/python/powerpc-hcalls.py @@ -117,10 +117,12 @@ hcall_table = { 440: 'H_GET_HCA_INFO', 444: 'H_GET_PERF_COUNT', 448: 'H_MANAGE_TRACE', + 456: 'H_GET_CPU_CHARACTERISTICS', 468: 'H_FREE_LOGICAL_LAN_BUFFER', 472: 'H_POLL_PENDING', 484: 'H_QUERY_INT_STATE', 580: 'H_ILLAN_ATTRIBUTES', + 584: 'H_ADD_LOGICAL_LAN_BUFFERS', 592: 'H_MODIFY_HEA_QP', 596: 'H_QUERY_HEA_QP', 600: 'H_QUERY_HEA', @@ -135,11 +137,17 @@ hcall_table = { 644: 'H_ADD_CONN', 648: 'H_DEL_CONN', 664: 'H_JOIN', + 672: 'H_VASI_SIGNAL', 676: 'H_VASI_STATE', + 680: 'H_VIOCTL', 688: 'H_ENABLE_CRQ', 696: 'H_GET_EM_PARMS', 720: 'H_SET_MPP', 724: 'H_GET_MPP', + 732: 'H_REG_SUB_CRQ', + 736: 'H_FREE_SUB_CRQ', + 740: 'H_SEND_SUB_CRQ', + 744: 'H_SEND_SUB_CRQ_INDIRECT', 748: 'H_HOME_NODE_ASSOCIATIVITY', 756: 'H_BEST_ENERGY', 764: 'H_XIRR_X', @@ -147,7 +155,88 @@ hcall_table = { 772: 'H_COP', 788: 'H_GET_MPP_X', 796: 'H_SET_MODE', + 808: 'H_BLOCK_REMOVE', + 856: 'H_CLEAR_HPT', + 864: 'H_REQUEST_VMC', + 876: 'H_RESIZE_HPT_PREPARE', + 880: 'H_RESIZE_HPT_COMMIT', + 892: 'H_REGISTER_PROC_TBL', + 896: 'H_SIGNAL_SYS_RESET', + 904: 'H_ALLOCATE_VAS_WINDOW', + 908: 'H_MODIFY_VAS_WINDOW', + 912: 'H_DEALLOCATE_VAS_WINDOW', + 916: 'H_QUERY_VAS_WINDOW', + 920: 'H_QUERY_VAS_CAPABILITIES', + 924: 'H_QUERY_NX_CAPABILITIES', + 928: 'H_GET_NX_FAULT', + 936: 'H_INT_GET_SOURCE_INFO', + 940: 'H_INT_SET_SOURCE_CONFIG', + 944: 'H_INT_GET_SOURCE_CONFIG', + 948: 'H_INT_GET_QUEUE_INFO', + 952: 'H_INT_SET_QUEUE_CONFIG', + 956: 'H_INT_GET_QUEUE_CONFIG', + 960: 'H_INT_SET_OS_REPORTING_LINE', + 964: 'H_INT_GET_OS_REPORTING_LINE', + 968: 'H_INT_ESB', + 972: 'H_INT_SYNC', + 976: 'H_INT_RESET', + 996: 'H_SCM_READ_METADATA', + 1000: 'H_SCM_WRITE_METADATA', + 1004: 'H_SCM_BIND_MEM', + 1008: 'H_SCM_UNBIND_MEM', + 1012: 'H_SCM_QUERY_BLOCK_MEM_BINDING', + 1016: 'H_SCM_QUERY_LOGICAL_MEM_BINDING', + 1020: 'H_SCM_UNBIND_ALL', + 1024: 'H_SCM_HEALTH', + 1048: 'H_SCM_PERFORMANCE_STATS', + 1052: 'H_PKS_GET_CONFIG', + 1056: 'H_PKS_SET_PASSWORD', + 1060: 'H_PKS_GEN_PASSWORD', + 1068: 'H_PKS_WRITE_OBJECT', + 1072: 'H_PKS_GEN_KEY', + 1076: 'H_PKS_READ_OBJECT', + 1080: 'H_PKS_REMOVE_OBJECT', + 1084: 'H_PKS_CONFIRM_OBJECT_FLUSHED', + 1096: 'H_RPT_INVALIDATE', + 1100: 'H_SCM_FLUSH', + 1104: 'H_GET_ENERGY_SCALE_INFO', + 1108: 'H_PKS_SIGNED_UPDATE', + 1112: 'H_HTM', + 1116: 'H_WATCHDOG', + # Platform specific hcalls used by KVM on PowerVM + 1120: 'H_GUEST_GET_CAPABILITIES', + 1124: 'H_GUEST_SET_CAPABILITIES', + 1136: 'H_GUEST_CREATE', + 1140: 'H_GUEST_CREATE_VCPU', + 1144: 'H_GUEST_GET_STATE', + 1148: 'H_GUEST_SET_STATE', + 1152: 'H_GUEST_RUN_VCPU', + 1156: 'H_GUEST_COPY_MEMORY', + 1160: 'H_GUEST_DELETE', + # Key wrapping hcalls + 1168: 'H_PKS_WRAP_OBJECT', + 1172: 'H_PKS_UNWRAP_OBJECT', + # Platform-specific hcalls used by the Ultravisor + 61184: 'H_SVM_PAGE_IN', + 61188: 'H_SVM_PAGE_OUT', + 61192: 'H_SVM_INIT_START', + 61196: 'H_SVM_INIT_DONE', + 61204: 'H_SVM_INIT_ABORT', + # Platform specific hcalls used by KVM 61440: 'H_RTAS', + # Platform specific hcalls used by QEMU/SLOF + 61441: 'H_LOGICAL_MEMOP', + 61442: 'H_CAS', + 61443: 'H_UPDATE_DT', + # Platform specific hcalls provided by PHYP + 61560: 'H_GET_24X7_CATALOG_PAGE', + 61564: 'H_GET_24X7_DATA', + 61568: 'H_GET_PERF_COUNTER_INFO', + # Platform-specific hcalls used for nested HV KVM + 63488: 'H_SET_PARTITION_TABLE', + 63492: 'H_ENTER_NESTED', + 63496: 'H_TLB_INVALIDATE', + 63500: 'H_COPY_TOFROM_GUEST', } def hcall_table_lookup(opcode): -- cgit v1.2.3 From 17f05146714f5d273701ae3cf2ff206e9b86f086 Mon Sep 17 00:00:00 2001 From: Gautam Menghani Date: Tue, 2 Jun 2026 17:26:41 +0530 Subject: perf script powerpc: Fix a typo in the name of H_DISABLE_AND_GET The name of the hcall for opcode 432 is "H_DISABLE_AND_GET". This typo was fixed in the main file [1] in the commit 0f10228c6ff6 ("KVM: PPC: Fix typo on H_DISABLE_AND_GET hcall"). [1]: arch/powerpc/include/asm/hvcall.h Signed-off-by: Gautam Menghani Signed-off-by: Namhyung Kim --- tools/perf/scripts/python/powerpc-hcalls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/scripts/python/powerpc-hcalls.py b/tools/perf/scripts/python/powerpc-hcalls.py index f897d6a5e051..4c14bd05da46 100644 --- a/tools/perf/scripts/python/powerpc-hcalls.py +++ b/tools/perf/scripts/python/powerpc-hcalls.py @@ -112,7 +112,7 @@ hcall_table = { 420: 'H_CREATE_RPT', 424: 'H_REMOVE_RPT', 428: 'H_REGISTER_RPAGES', - 432: 'H_DISABLE_AND_GETC', + 432: 'H_DISABLE_AND_GET', 436: 'H_ERROR_DATA', 440: 'H_GET_HCA_INFO', 444: 'H_GET_PERF_COUNT', -- cgit v1.2.3 From 0cf831b7a40d8e35a966044a79b013611db678ad Mon Sep 17 00:00:00 2001 From: Shivani Nittor Date: Sat, 27 Jun 2026 14:33:33 +0530 Subject: perf scripts: Add configurable sorting option to powerpc-hcalls The powerpc-hcalls.py script currently prints hypercall statistics in a fixed sort order based on the number of hcall occurrences, making it difficult to analyze hcalls from different execution characteristics. Add support for runtime-configurable sorting so users can order hypercall statistics by count, minimum latency, maximum latency, or average latency using a --sort option. Parse arguments through sys.argv to support perf script argument passing semantics. Example: perf record -a -e powerpc* sleep 10 perf script -s ./powerpc-hcalls.py -i ./perf.data -- --sort=max SORT KEY = max hcall count min(ns) max(ns) avg(ns) H_SEND_LOGICAL_LAN 47 7380 40148 8739 H_VIO_SIGNAL 706 880 17454 1911 H_RANDOM 1 15176 15176 15176 H_PUT_TCE_INDIRECT 4 3032 10444 4956 H_ADD_LOGICAL_LAN_BUFFER 363 1250 8716 1534 H_SEND_CRQ 8 2086 6846 3044 H_PUT_TCE 9 1284 4932 2646 H_STUFF_TCE 13 1620 3962 2358 This makes it easier to identify frequently occurring or high-latency hypercalls depending on the analysis being performed. Signed-off-by: Shivani Nittor Signed-off-by: Namhyung Kim --- tools/perf/scripts/python/powerpc-hcalls.py | 46 ++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/tools/perf/scripts/python/powerpc-hcalls.py b/tools/perf/scripts/python/powerpc-hcalls.py index 4c14bd05da46..fedce1b68cad 100644 --- a/tools/perf/scripts/python/powerpc-hcalls.py +++ b/tools/perf/scripts/python/powerpc-hcalls.py @@ -25,6 +25,7 @@ from Util import * # } ... # } output = {} +sort_key = 'count' # d_enter: { # cpu: { @@ -247,10 +248,53 @@ def hcall_table_lookup(opcode): print_ptrn = '%-28s%10s%10s%10s%10s' +def sort_output(opcode): + stats = output[opcode] + + if sort_key == 'min': + return stats['min'] + if sort_key == 'max': + return stats['max'] + if sort_key == 'avg': + return stats['time'] // stats['cnt'] + + return stats['cnt'] + +def trace_begin(): + global sort_key + + valid_sort_keys = ['count', 'min', 'max', 'avg'] + + i = 1 + while i < len(sys.argv): + arg = sys.argv[i] + + if arg == '-s' or arg == '--sort': + if i + 1 >= len(sys.argv): + print("Error: -s/--sort requires a sort key argument") + sys.exit(1) + sort_key = sys.argv[i + 1] + i += 2 + continue + + if arg.startswith('--sort='): + sort_key = arg.split('=', 1)[1] + i += 1 + continue + + i += 1 + + if sort_key not in valid_sort_keys: + print(f"Error: Invalid sort key '{sort_key}'. Valid options are: {', '.join(valid_sort_keys)}") + sys.exit(1) + + print("SORT KEY =", sort_key) + def trace_end(): print(print_ptrn % ('hcall', 'count', 'min(ns)', 'max(ns)', 'avg(ns)')) print('-' * 68) - for opcode in output: + for opcode in sorted(output, key = sort_output, + reverse=True): h_name = hcall_table_lookup(opcode) time = output[opcode]['time'] cnt = output[opcode]['cnt'] -- cgit v1.2.3 From 385db74dc436e4ab6c72e0e59a3fd7524269c58c Mon Sep 17 00:00:00 2001 From: Gautam Menghani Date: Mon, 18 May 2026 18:20:38 +0530 Subject: perf kvm stat: Add missing mappings for PPC kvm exit reasons The macro kvm_trace_symbol_exit is used for providing the mappings for the exit trap vectors and their names. Add mappings for H_FAC_UNAVAIL and H_VIRT so that exit reasons are displayed as string instead of vector numbers when using perf kvm stat. Signed-off-by: Gautam Menghani Signed-off-by: Namhyung Kim --- tools/perf/util/kvm-stat-arch/book3s_hv_exits.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/kvm-stat-arch/book3s_hv_exits.h b/tools/perf/util/kvm-stat-arch/book3s_hv_exits.h index 2011376c7ab5..2688ca7d0399 100644 --- a/tools/perf/util/kvm-stat-arch/book3s_hv_exits.h +++ b/tools/perf/util/kvm-stat-arch/book3s_hv_exits.h @@ -26,8 +26,10 @@ {0xe00, "H_DATA_STORAGE"}, \ {0xe20, "H_INST_STORAGE"}, \ {0xe40, "H_EMUL_ASSIST"}, \ + {0xea0, "H_VIRT"}, \ {0xf00, "PERFMON"}, \ {0xf20, "ALTIVEC"}, \ - {0xf40, "VSX"} + {0xf40, "VSX"}, \ + {0xf80, "H_FAC_UNAVAIL"} #endif -- cgit v1.2.3 From 5786fa53dc7a4ae027ee2dbf321ed2286c4c20b5 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Mon, 29 Jun 2026 13:05:59 +0200 Subject: perf test: Skip failing 'perf test aslr' test case The test case 'perf test aslr' fails on s390. The root cause of the failure is subtest test_callchain_aslr. This test invokes command # ./perf record -g -e task-clock:u -o /tmp/perf-test-aslr \ -- perf test -w noploop 3 to generate a call stack using event task-clock:u. On s390 this defaults to '--call-graph dwarf' whereas on x86_64 this defaults to framepointer (fp) format. The command # ./perf inject --aslr -i /tmp/perf-test-aslr now scans all SAMPLE entries recorded in the perf.data file to convert possible addresses. This is done in aslr_tool__process_sample() looking at sample_type bits PERF_SAMPLE_IP, PERF_SAMPLE_TID, PERF_SAMPLE_TIME, PERF_SAMPLE_PERIOD, PERF_SAMPLE_CALLCHAIN, PERF_SAMPLE_REGS_USER and PERF_SAMPLE_STACK_USER. On s390 the samples do not contain FP entries of type PERF_SAMPLE_CALLCHAIN (the bit is set in sample_type, but the number of FP entries is 0). The processing enters the PERF_SAMPLE_STACK_USER portion where the data is copied to the newly constructed sample and then aborted with this warning: /* TODO: can this be less conservative? */ pr_debug("Dropping stack user sample as possible ASLR leak\n"); With command line option '--call-graph dwarf' the new output file does not contain any samples at all. This leads to a missing $new_addr value in the shell script and a failure. Fix this and skip this subtest. Emit a hint that this subtest is currently unsupported on all platform when option --call-graph dwarf is selected. Since one subtest is skipped, the complete test is reported as skipped. Fixes: 190c45463844 ("perf test: Add inject ASLR test") Signed-off-by: Thomas Richter Reviewed-by: Ian Rogers Suggested-by: Sumanth Korikkar Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/inject_aslr.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/perf/tests/shell/inject_aslr.sh b/tools/perf/tests/shell/inject_aslr.sh index c00461828ea7..d83c2591db8f 100755 --- a/tools/perf/tests/shell/inject_aslr.sh +++ b/tools/perf/tests/shell/inject_aslr.sh @@ -135,8 +135,14 @@ test_callchain_aslr() { echo "Callchain ASLR test [Failed - no noploop samples in original file]" err=1 elif [ -z "$new_addr" ]; then - echo "Callchain ASLR test [Failed - could not find remapped address]" - err=1 + if perf evlist -v -i "${data}" | grep -q 'sample_type:.*STACK_USER'; then + echo "Dropping stack user sample as possible ASLR leak" + echo "Call-graph dwarf not supported with 'perf inject --aslr'" + echo "Callchain ASLR test [Skip]" + else + echo "Callchain ASLR test [Failed - could not find remapped address]" + err=1 + fi elif [ "$orig_addr" = "$new_addr" ]; then echo "Callchain ASLR test [Failed - addresses are not remapped]" err=1 -- cgit v1.2.3 From 4f7442f7e71d6cb3ec9851b5a752b82081ff675b Mon Sep 17 00:00:00 2001 From: "Masami Hiramatsu (Google)" Date: Mon, 29 Jun 2026 15:13:38 +0900 Subject: perf/probe: Ignore comment lines in dynamic_events/kprobe_events file Since dynamic_events/kprobe_events files show the fetcharg debug information as comment lines, its reader needs to ignore it. Signed-off-by: Masami Hiramatsu (Google) Signed-off-by: Namhyung Kim --- tools/perf/util/probe-file.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 4032572cbf55..4d12693a83b3 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -197,6 +197,8 @@ struct strlist *probe_file__get_rawlist(int fd) idx = strlen(p) - 1; if (p[idx] == '\n') p[idx] = '\0'; + if (buf[0] == '#') + continue; ret = strlist__add(sl, buf); if (ret < 0) { pr_debug("strlist__add failed (%d)\n", ret); -- cgit v1.2.3 From dfab3e4b0bf7f772889e8ebc2fd691fc95b596c9 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 11 Jun 2026 18:24:13 -0700 Subject: perf pmu: Recognize default_core as a core PMU in more places MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The python metrics code used in places like ilist.py passes a pmu-filter of "default_core" on non-hybrid x86/ARM/.. systems. As a PMU like "cpu" isn't a literal name match then no PMU matches "default_core" and the events fail to parse for the metric. Fix the name matching and PMU lookup for "default_core" and check that it fixes ilist.py. Fixes: 74e2dbe7be50 ("perf tools: Add --pmu-filter option for filtering PMUs") Signed-off-by: Ian Rogers Reviewed‑by: Qinxin Xia Signed-off-by: Namhyung Kim --- tools/perf/util/pmu.c | 6 +++++- tools/perf/util/pmus.c | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index a550f030b85d..836e3b5615cd 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -2660,8 +2660,12 @@ bool perf_pmu__wildcard_match(const struct perf_pmu *pmu, const char *wildcard_t pmu->name, pmu->alias_name, }; - bool need_fnmatch = strisglob(wildcard_to_match); + bool need_fnmatch; + if (pmu->is_core && !strcmp(wildcard_to_match, "default_core")) + return true; + + need_fnmatch = strisglob(wildcard_to_match); if (!strncmp(wildcard_to_match, "uncore_", 7)) wildcard_to_match += 7; diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c index 5e3f571450fe..e0a4cb2428ca 100644 --- a/tools/perf/util/pmus.c +++ b/tools/perf/util/pmus.c @@ -150,6 +150,8 @@ struct perf_pmu *perf_pmus__find(const char *name) bool core_pmu; unsigned int to_read_pmus = 0; + if (!strcmp(name, "default_core")) + return perf_pmus__find_core_pmu(); /* * Once PMU is loaded it stays in the list, * so we keep us from multiple reading/parsing -- cgit v1.2.3 From 4933d4f45b5ce2a1d0d9c4ab703460997439d6a7 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 24 Jun 2026 13:58:27 -0700 Subject: perf timechart: Don't pass @event to cat_backtrace() The cat_backtrace() is only called from process_sample_event() which means the event type is always PERF_RECORD_SAMPLE. We don't need to pass the event just because to print already known info. Signed-off-by: Namhyung Kim --- tools/perf/builtin-timechart.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 85a9ad0455ae..dafd361ecf9d 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -493,8 +493,7 @@ static void sched_switch(struct timechart *tchart, int cpu, u64 timestamp, * Returns a malloc'd backtrace string built via open_memstream, or NULL * on error. Caller must free() the returned pointer. */ -static char *cat_backtrace(union perf_event *event, - struct perf_sample *sample, +static char *cat_backtrace(struct perf_sample *sample, struct machine *machine) { struct addr_location al; @@ -516,9 +515,8 @@ static char *cat_backtrace(union perf_event *event, goto exit; if (machine__resolve(machine, &al, sample) < 0) { - pr_err("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n", - perf_event__name(event->header.type), event->header.type, - sample->file_offset); + pr_err("problem processing SAMPLE (%u) event at offset %#" PRIx64 ", skipping it.\n", + PERF_RECORD_SAMPLE, sample->file_offset); goto exit; } @@ -578,7 +576,7 @@ typedef int (*tracepoint_handler)(struct timechart *tchart, const char *backtrace); static int process_sample_event(const struct perf_tool *tool, - union perf_event *event, + union perf_event *event __maybe_unused, struct perf_sample *sample, struct machine *machine) { @@ -595,7 +593,7 @@ static int process_sample_event(const struct perf_tool *tool, if (evsel->handler != NULL) { tracepoint_handler f = evsel->handler; - char *backtrace = cat_backtrace(event, sample, machine); + char *backtrace = cat_backtrace(sample, machine); ret = f(tchart, sample, backtrace); free(backtrace); -- cgit v1.2.3 From 445a625a66b15f7f8fbe70dea27269aa85c87bdf Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 24 Jun 2026 13:58:28 -0700 Subject: perf timechart: Generate backtrace only if needed The backtrace was used by sched-switch and sched-wakeup only. No need to call cat_backtrace() in the process_sample_event(). Let's pass NULL backtrace and generate it from the sched events. As it needs a pointer to the 'machine', let's save the session in the timechart struct and use the host machine of the session instead of passing the pointer to all handlers. It should be fine to assume the host machine as timechart command doesn't deal with guest machines and there's no way to get tracepoints from the guest events. Signed-off-by: Namhyung Kim --- tools/perf/builtin-timechart.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index dafd361ecf9d..337ae547d008 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -56,6 +56,7 @@ struct timechart { struct per_pid *all_data; struct power_event *power_events; struct wake_event *wake_events; + struct perf_session *session; int proc_num; unsigned int numcpus; u64 min_freq, /* Lowest CPU frequency seen */ @@ -578,7 +579,7 @@ typedef int (*tracepoint_handler)(struct timechart *tchart, static int process_sample_event(const struct perf_tool *tool, union perf_event *event __maybe_unused, struct perf_sample *sample, - struct machine *machine) + struct machine *machine __maybe_unused) { struct timechart *tchart = container_of(tool, struct timechart, tool); struct evsel *evsel = sample->evsel; @@ -593,10 +594,8 @@ static int process_sample_event(const struct perf_tool *tool, if (evsel->handler != NULL) { tracepoint_handler f = evsel->handler; - char *backtrace = cat_backtrace(sample, machine); - ret = f(tchart, sample, backtrace); - free(backtrace); + ret = f(tchart, sample, NULL); } return ret; @@ -656,7 +655,10 @@ process_sample_sched_wakeup(struct timechart *tchart, sample->file_offset, sample->cpu); return -1; } + + backtrace = cat_backtrace(sample, &tchart->session->machines.host); sched_wakeup(tchart, sample->cpu, sample->time, waker, wakee, flags, backtrace); + free((char *)backtrace); return 0; } @@ -675,8 +677,11 @@ process_sample_sched_switch(struct timechart *tchart, sample->file_offset, sample->cpu); return -1; } + + backtrace = cat_backtrace(sample, &tchart->session->machines.host); sched_switch(tchart, sample->cpu, sample->time, prev_pid, next_pid, prev_state, backtrace); + free((char *)backtrace); return 0; } @@ -1661,6 +1666,7 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name) if (IS_ERR(session)) return PTR_ERR(session); + tchart->session = session; symbol__init(perf_session__env(session)); (void)perf_header__process_sections(&session->header, -- cgit v1.2.3 From 48d698f810fe7e9a3a89ee7907827ab6ba0d3386 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 24 Jun 2026 13:58:29 -0700 Subject: perf timechart: Remove unused backtrace in trace_handler Now the backtrace argument is not used in any handler. Let's get rid of it. Signed-off-by: Namhyung Kim --- tools/perf/builtin-timechart.c | 64 +++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 41 deletions(-) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 337ae547d008..4efac73a714c 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -573,8 +573,7 @@ exit: } typedef int (*tracepoint_handler)(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace); + struct perf_sample *sample); static int process_sample_event(const struct perf_tool *tool, union perf_event *event __maybe_unused, @@ -595,7 +594,7 @@ static int process_sample_event(const struct perf_tool *tool, if (evsel->handler != NULL) { tracepoint_handler f = evsel->handler; - ret = f(tchart, sample, NULL); + ret = f(tchart, sample); } return ret; @@ -603,8 +602,7 @@ static int process_sample_event(const struct perf_tool *tool, static int process_sample_cpu_idle(struct timechart *tchart __maybe_unused, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { u32 state = perf_sample__intval(sample, "state"); u32 cpu_id = perf_sample__intval(sample, "cpu_id"); @@ -624,8 +622,7 @@ process_sample_cpu_idle(struct timechart *tchart __maybe_unused, static int process_sample_cpu_frequency(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { u32 state = perf_sample__intval(sample, "state"); u32 cpu_id = perf_sample__intval(sample, "cpu_id"); @@ -642,12 +639,12 @@ process_sample_cpu_frequency(struct timechart *tchart, static int process_sample_sched_wakeup(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace) + struct perf_sample *sample) { u8 flags = perf_sample__intval(sample, "common_flags"); int waker = perf_sample__intval(sample, "common_pid"); int wakee = perf_sample__intval(sample, "pid"); + char *backtrace; /* perf.data is untrusted input — CPU may be absent or corrupted */ if (sample->cpu >= MAX_CPUS) { @@ -664,12 +661,12 @@ process_sample_sched_wakeup(struct timechart *tchart, static int process_sample_sched_switch(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace) + struct perf_sample *sample) { int prev_pid = perf_sample__intval(sample, "prev_pid"); int next_pid = perf_sample__intval(sample, "next_pid"); u64 prev_state = perf_sample__intval(sample, "prev_state"); + char *backtrace; /* perf.data is untrusted input — CPU may be absent or corrupted */ if (sample->cpu >= MAX_CPUS) { @@ -688,8 +685,7 @@ process_sample_sched_switch(struct timechart *tchart, #ifdef SUPPORT_OLD_POWER_EVENTS static int process_sample_power_start(struct timechart *tchart __maybe_unused, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { u64 cpu_id = perf_sample__intval(sample, "cpu_id"); u64 value = perf_sample__intval(sample, "value"); @@ -706,8 +702,7 @@ process_sample_power_start(struct timechart *tchart __maybe_unused, static int process_sample_power_end(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { /* perf.data is untrusted input — CPU may be absent or corrupted */ if (sample->cpu >= MAX_CPUS) { @@ -721,8 +716,7 @@ process_sample_power_end(struct timechart *tchart, static int process_sample_power_frequency(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { u64 cpu_id = perf_sample__intval(sample, "cpu_id"); u64 value = perf_sample__intval(sample, "value"); @@ -895,8 +889,7 @@ static int pid_end_io_sample(struct timechart *tchart, int pid, int type, static int process_enter_read(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { long fd = perf_sample__intval(sample, "fd"); return pid_begin_io_sample(tchart, sample->tid, IOTYPE_READ, @@ -905,8 +898,7 @@ process_enter_read(struct timechart *tchart, static int process_exit_read(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { long ret = perf_sample__intval(sample, "ret"); return pid_end_io_sample(tchart, sample->tid, IOTYPE_READ, @@ -915,8 +907,7 @@ process_exit_read(struct timechart *tchart, static int process_enter_write(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { long fd = perf_sample__intval(sample, "fd"); return pid_begin_io_sample(tchart, sample->tid, IOTYPE_WRITE, @@ -925,8 +916,7 @@ process_enter_write(struct timechart *tchart, static int process_exit_write(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { long ret = perf_sample__intval(sample, "ret"); return pid_end_io_sample(tchart, sample->tid, IOTYPE_WRITE, @@ -935,8 +925,7 @@ process_exit_write(struct timechart *tchart, static int process_enter_sync(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { long fd = perf_sample__intval(sample, "fd"); return pid_begin_io_sample(tchart, sample->tid, IOTYPE_SYNC, @@ -945,8 +934,7 @@ process_enter_sync(struct timechart *tchart, static int process_exit_sync(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { long ret = perf_sample__intval(sample, "ret"); return pid_end_io_sample(tchart, sample->tid, IOTYPE_SYNC, @@ -955,8 +943,7 @@ process_exit_sync(struct timechart *tchart, static int process_enter_tx(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { long fd = perf_sample__intval(sample, "fd"); return pid_begin_io_sample(tchart, sample->tid, IOTYPE_TX, @@ -965,8 +952,7 @@ process_enter_tx(struct timechart *tchart, static int process_exit_tx(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { long ret = perf_sample__intval(sample, "ret"); return pid_end_io_sample(tchart, sample->tid, IOTYPE_TX, @@ -975,8 +961,7 @@ process_exit_tx(struct timechart *tchart, static int process_enter_rx(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { long fd = perf_sample__intval(sample, "fd"); return pid_begin_io_sample(tchart, sample->tid, IOTYPE_RX, @@ -985,8 +970,7 @@ process_enter_rx(struct timechart *tchart, static int process_exit_rx(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { long ret = perf_sample__intval(sample, "ret"); return pid_end_io_sample(tchart, sample->tid, IOTYPE_RX, @@ -995,8 +979,7 @@ process_exit_rx(struct timechart *tchart, static int process_enter_poll(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { long fd = perf_sample__intval(sample, "fd"); return pid_begin_io_sample(tchart, sample->tid, IOTYPE_POLL, @@ -1005,8 +988,7 @@ process_enter_poll(struct timechart *tchart, static int process_exit_poll(struct timechart *tchart, - struct perf_sample *sample, - const char *backtrace __maybe_unused) + struct perf_sample *sample) { long ret = perf_sample__intval(sample, "ret"); return pid_end_io_sample(tchart, sample->tid, IOTYPE_POLL, -- cgit v1.2.3 From 780368ccd922e58e471afddb5811eec89abeff0a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 24 Jun 2026 13:58:30 -0700 Subject: perf timechart: Remove unnecessary copy of backtrace The pattern of strdup() and free() is found, and I think it just can use the original backtrace directly. Signed-off-by: Namhyung Kim --- tools/perf/builtin-timechart.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 4efac73a714c..04dbb944a427 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -300,7 +300,7 @@ static void pid_put_sample(struct timechart *tchart, int pid, int type, sample->type = type; sample->next = c->samples; sample->cpu = cpu; - sample->backtrace = backtrace ? strdup(backtrace) : NULL; + sample->backtrace = backtrace; c->samples = sample; if (sample->type == TYPE_RUNNING && end > start && start > 0) { @@ -429,12 +429,14 @@ static void sched_wakeup(struct timechart *tchart, int cpu, u64 timestamp, struct per_pid *p; struct wake_event *we = zalloc(sizeof(*we)); - if (!we) + if (!we) { + free((char *)backtrace); return; + } we->time = timestamp; we->waker = waker; - we->backtrace = backtrace ? strdup(backtrace) : NULL; + we->backtrace = backtrace; if ((flags & TRACE_FLAG_HARDIRQ) || (flags & TRACE_FLAG_SOFTIRQ)) we->waker = -1; @@ -461,20 +463,28 @@ static void sched_switch(struct timechart *tchart, int cpu, u64 timestamp, const char *backtrace) { struct per_pid *p = NULL, *prev_p; + bool backtrace_used = false; prev_p = find_create_pid(tchart, prev_pid); p = find_create_pid(tchart, next_pid); - if (prev_p->current && prev_p->current->state != TYPE_NONE) + if (prev_p->current && prev_p->current->state != TYPE_NONE) { pid_put_sample(tchart, prev_pid, TYPE_RUNNING, cpu, prev_p->current->state_since, timestamp, backtrace); + backtrace_used = true; + } if (p && p->current) { - if (p->current->state != TYPE_NONE) + if (p->current->state != TYPE_NONE) { + if (backtrace && backtrace_used) + backtrace = strdup(backtrace); + pid_put_sample(tchart, next_pid, p->current->state, cpu, p->current->state_since, timestamp, backtrace); + backtrace_used = true; + } p->current->state_since = timestamp; p->current->state = TYPE_RUNNING; @@ -488,6 +498,9 @@ static void sched_switch(struct timechart *tchart, int cpu, u64 timestamp, if (prev_state == 0) prev_p->current->state = TYPE_WAITING; } + + if (!backtrace_used) + free((char *)backtrace); } /* @@ -655,7 +668,6 @@ process_sample_sched_wakeup(struct timechart *tchart, backtrace = cat_backtrace(sample, &tchart->session->machines.host); sched_wakeup(tchart, sample->cpu, sample->time, waker, wakee, flags, backtrace); - free((char *)backtrace); return 0; } @@ -678,7 +690,6 @@ process_sample_sched_switch(struct timechart *tchart, backtrace = cat_backtrace(sample, &tchart->session->machines.host); sched_switch(tchart, sample->cpu, sample->time, prev_pid, next_pid, prev_state, backtrace); - free((char *)backtrace); return 0; } -- cgit v1.2.3 From 73aa610f75833123615eebd4b3d6a0b5281c3f73 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 24 Jun 2026 13:58:31 -0700 Subject: perf timechart: Release event samples at the end Add timechart__release() to free all data structures added during the sample processing. Signed-off-by: Namhyung Kim --- tools/perf/builtin-timechart.c | 68 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 04dbb944a427..27d17268395e 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1548,6 +1548,73 @@ static void write_svg_file(struct timechart *tchart, const char *filename) svg_close(); } +static void timechart__release(struct timechart *tchart) +{ + struct per_pid *p = tchart->all_data; + struct power_event *pwr = tchart->power_events; + struct wake_event *we = tchart->wake_events; + + while (p) { + struct per_pid *next_pid = p->next; + struct per_pidcomm *c = p->all; + + while (c) { + struct per_pidcomm *next_comm = c->next; + struct cpu_sample *cs = c->samples; + struct io_sample *ios = c->io_samples; + + while (cs) { + struct cpu_sample *next = cs->next; + + zfree(&cs->backtrace); + cs->next = NULL; + free(cs); + + cs = next; + } + + while (ios) { + struct io_sample *next = ios->next; + + ios->next = NULL; + free(ios); + + ios = next; + } + + zfree(&c->comm); + c->next = NULL; + free(c); + + c = next_comm; + } + + p->next = NULL; + free(p); + + p = next_pid; + } + + while (pwr) { + struct power_event *next = pwr->next; + + pwr->next = NULL; + free(pwr); + + pwr = next; + } + + while (we) { + struct wake_event *next = we->next; + + zfree(&we->backtrace); + we->next = NULL; + free(we); + + we = next; + } +} + static int process_header(struct perf_file_section *section __maybe_unused, struct perf_header *ph, int feat, @@ -2079,6 +2146,7 @@ int cmd_timechart(int argc, const char **argv) ret = __cmd_timechart(&tchart, output_name); out: + timechart__release(&tchart); zfree(&cpus_cstate_start_times); zfree(&cpus_cstate_state); zfree(&cpus_pstate_start_times); -- cgit v1.2.3 From 96a463ee62592b10aa0d96e6bb45de56a981c2d1 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 24 Jun 2026 13:58:32 -0700 Subject: perf timechart: Fix memory leaks during record The command line options can be passed without copy as their lifetime is limited within the same function. Acked-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/builtin-timechart.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 27d17268395e..a73f0ab22fd6 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1834,6 +1834,7 @@ static int timechart__io_record(int argc, const char **argv, const char *output_ "syscalls:sys_exit_select", }; unsigned int poll_events_nr = ARRAY_SIZE(poll_events); + int ret; rec_argc = common_args_nr + disk_events_nr * 4 + @@ -1852,7 +1853,7 @@ static int timechart__io_record(int argc, const char **argv, const char *output_ p = rec_argv; for (i = 0; i < common_args_nr; i++) - *p++ = strdup(common_args[i]); + *p++ = common_args[i]; for (i = 0; i < disk_events_nr; i++) { if (!is_valid_tracepoint(disk_events[i])) { @@ -1861,7 +1862,7 @@ static int timechart__io_record(int argc, const char **argv, const char *output_ } *p++ = "-e"; - *p++ = strdup(disk_events[i]); + *p++ = disk_events[i]; *p++ = "--filter"; *p++ = filter; } @@ -1872,7 +1873,7 @@ static int timechart__io_record(int argc, const char **argv, const char *output_ } *p++ = "-e"; - *p++ = strdup(net_events[i]); + *p++ = net_events[i]; *p++ = "--filter"; *p++ = filter; } @@ -1883,7 +1884,7 @@ static int timechart__io_record(int argc, const char **argv, const char *output_ } *p++ = "-e"; - *p++ = strdup(poll_events[i]); + *p++ = poll_events[i]; *p++ = "--filter"; *p++ = filter; } @@ -1891,7 +1892,11 @@ static int timechart__io_record(int argc, const char **argv, const char *output_ for (i = 0; i < (unsigned int)argc; i++) *p++ = argv[i]; - return cmd_record(rec_argc, rec_argv); + ret = cmd_record(rec_argc, rec_argv); + + free(rec_argv); + free(filter); + return ret; } @@ -1902,6 +1907,7 @@ static int timechart__record(struct timechart *tchart, int argc, const char **ar const char **rec_argv; const char **p; unsigned int record_elems; + int ret; const char * const common_args[] = { "record", "-a", "-R", "-c", "1", "-o", output_data, @@ -1966,24 +1972,27 @@ static int timechart__record(struct timechart *tchart, int argc, const char **ar p = rec_argv; for (i = 0; i < common_args_nr; i++) - *p++ = strdup(common_args[i]); + *p++ = common_args[i]; for (i = 0; i < backtrace_args_no; i++) - *p++ = strdup(backtrace_args[i]); + *p++ = backtrace_args[i]; for (i = 0; i < tasks_args_nr; i++) - *p++ = strdup(tasks_args[i]); + *p++ = tasks_args[i]; for (i = 0; i < power_args_nr; i++) - *p++ = strdup(power_args[i]); + *p++ = power_args[i]; for (i = 0; i < old_power_args_nr; i++) - *p++ = strdup(old_power_args[i]); + *p++ = old_power_args[i]; for (j = 0; j < (unsigned int)argc; j++) *p++ = argv[j]; - return cmd_record(rec_argc, rec_argv); + ret = cmd_record(rec_argc, rec_argv); + + free(rec_argv); + return ret; } static int -- cgit v1.2.3 From fcc9159fc82625bf5f8e8fb5fde48709b631bebe Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 24 Jun 2026 13:58:33 -0700 Subject: perf timechart: Fix memory leaks in draw_wakeups() The second loop for per_pidcommd is meaningful only when it doesn't have from and to tasks. Also make sure c->Y is set before copying the comm string otherwise it will be overwritten by next one. Signed-off-by: Namhyung Kim --- tools/perf/builtin-timechart.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index a73f0ab22fd6..3f9153d5ecfb 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1110,12 +1110,12 @@ static void draw_wakeups(struct timechart *tchart) c = c->next; } c = p->all; - while (c) { - if (p->pid == we->waker && !from) { + while (c && (!from || !to)) { + if (c->Y && p->pid == we->waker && !from) { from = c->Y; task_from = strdup(c->comm); } - if (p->pid == we->wakee && !to) { + if (c->Y && p->pid == we->wakee && !to) { to = c->Y; task_to = strdup(c->comm); } -- cgit v1.2.3 From 5437e98903897246e3f223ab68f1f8bda8b5ed7e Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 24 Jun 2026 13:58:34 -0700 Subject: perf test: Update perf timechart test To include IO-only and backtrace modes to test different code paths. $ sudo perf test -vv timechart 135: perf timechart tests : Running 135: perf timechart tests: ---- start ---- test child forked, pid 2413665 perf timechart Basic test perf timechart Basic test [Success] perf timechart IO-only test perf timechart IO-only test [Success] perf timechart Backtrace test perf timechart Backtrace test [Success] ---- end(0) ---- 135: perf timechart tests : Ok === Test Summary === Passed main tests : 1 Passed subtests : 0 Skipped tests : 0 Failed tests : 0 Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/timechart.sh | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/tools/perf/tests/shell/timechart.sh b/tools/perf/tests/shell/timechart.sh index b14b3472c284..40072b32171a 100755 --- a/tools/perf/tests/shell/timechart.sh +++ b/tools/perf/tests/shell/timechart.sh @@ -9,7 +9,7 @@ perfdata=$(mktemp /tmp/__perf_timechart_test.perf.data.XXXXX) output=$(mktemp /tmp/__perf_timechart_test.output.XXXXX.svg) cleanup() { - rm -f "${perfdata}" + rm -f "${perfdata}"* rm -f "${output}" trap - EXIT TERM INT } @@ -22,38 +22,41 @@ trap_cleanup() { trap trap_cleanup EXIT TERM INT test_timechart() { - echo "Basic perf timechart test" + NAME=$1 + OPTION=$2 + + echo "perf timechart ${NAME} test" # Try to record timechart data. # perf timechart record uses system-wide recording and specific tracepoints. # If it fails (e.g. permissions, missing tracepoints), skip the test. - if ! perf timechart record -o "${perfdata}" true > /dev/null 2>&1; then - echo "Basic perf timechart test [Skipped: perf timechart record failed (permissions/events?)]" + if ! perf timechart record -o "${perfdata}" ${OPTION} true > /dev/null 2>&1; then + echo "perf timechart ${NAME} test [Skipped: perf timechart record failed (permissions/events?)]" return fi # Generate the timechart if ! perf timechart -i "${perfdata}" -o "${output}" > /dev/null 2>&1; then - echo "Basic perf timechart test [Failed: perf timechart command failed]" + echo "perf timechart ${NAME} test [Failed: perf timechart command failed]" err=1 return fi # Check if output file exists and is not empty if [ ! -s "${output}" ]; then - echo "Basic perf timechart test [Failed: output file is empty or missing]" + echo "perf timechart ${NAME} test [Failed: output file is empty or missing]" err=1 return fi # Check if it looks like an SVG if ! grep -q "svg" "${output}"; then - echo "Basic perf timechart test [Failed: output doesn't look like SVG]" + echo "perf timechart ${NAME} test [Failed: output doesn't look like SVG]" err=1 return fi - echo "Basic perf timechart test [Success]" + echo "perf timechart ${NAME} test [Success]" } if ! perf check feature -q libtraceevent ; then @@ -62,6 +65,9 @@ if ! perf check feature -q libtraceevent ; then exit 2 fi -test_timechart +test_timechart "Basic" "" +test_timechart "IO-only" "-I" +test_timechart "Backtrace" "-g" + cleanup exit $err -- cgit v1.2.3 From e6ad1fb3458f9e77f63bcd555baf7a08008ecc2e Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 22 Jun 2026 18:27:46 -0700 Subject: perf parse-events: Restrict core PMU bypass to --cputype option Commit b1c5efbfd92e ("perf parse-events: Remove hard coded legacy hardware and cache parsing") introduced a bypass to PMU filtering to prevent uncore PMUs from being filtered out during event parsing, which was required for resolving `duration_time` and `uncore_freq` when running with `--cputype`. However, this bypass was active whenever `pmu_filter` was set, which also incorrectly bypassed filtering for the `--pmu-filter` option. Introduce a `cputype_filter` boolean flag in `parse_events_state` and `parse_events_option_args` to distinguish filtering initiated by `--cputype` from that initiated by `--pmu-filter`. Restrict the core-only check in `parse_events__filter_pmu()` to when `cputype_filter` is true. Fixes: b1c5efbfd92e ("perf parse-events: Remove hard coded legacy hardware and cache parsing") Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/builtin-script.c | 1 + tools/perf/builtin-stat.c | 20 +++++++++++++++----- tools/perf/tests/expand-cgroup.c | 3 ++- tools/perf/tests/parse-events.c | 11 +++++++---- tools/perf/tests/parse-metric.c | 3 ++- tools/perf/tests/pmu-events.c | 10 +++++++--- tools/perf/util/metricgroup.c | 26 ++++++++++++++++++-------- tools/perf/util/metricgroup.h | 4 +++- tools/perf/util/parse-events.c | 32 +++++++++++++++++++------------- tools/perf/util/parse-events.h | 17 +++++++++++------ tools/perf/util/python.c | 3 ++- 11 files changed, 87 insertions(+), 43 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 47afd8cdc2b7..f91d8b1fbd01 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2174,6 +2174,7 @@ static int script_find_metrics(const struct pmu_metric *pm, struct evsel *metric_evsel; int ret = metricgroup__parse_groups(metric_evlist, /*pmu=*/"all", + /*cputype_filter=*/false, pm->metric_name, /*metric_no_group=*/false, /*metric_no_merge=*/false, diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 3f897b2e8638..92cdb2df7285 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1213,6 +1213,7 @@ static int parse_cputype(const struct option *opt, return -1; } parse_events_option_args.pmu_filter = pmu->name; + parse_events_option_args.cputype_filter = true; return 0; } @@ -1229,6 +1230,7 @@ static int parse_pmu_filter(const struct option *opt, } parse_events_option_args.pmu_filter = str; + parse_events_option_args.cputype_filter = false; return 0; } @@ -2003,7 +2005,9 @@ static int add_default_events(void) ret = -1; goto out; } - ret = metricgroup__parse_groups(evlist, pmu, "transaction", + ret = metricgroup__parse_groups(evlist, pmu, + parse_events_option_args.cputype_filter, + "transaction", stat_config.metric_no_group, stat_config.metric_no_merge, stat_config.metric_no_threshold, @@ -2040,7 +2044,9 @@ static int add_default_events(void) if (!force_metric_only) stat_config.metric_only = true; - ret = metricgroup__parse_groups(evlist, pmu, "smi", + ret = metricgroup__parse_groups(evlist, pmu, + parse_events_option_args.cputype_filter, + "smi", stat_config.metric_no_group, stat_config.metric_no_merge, stat_config.metric_no_threshold, @@ -2077,7 +2083,7 @@ static int add_default_events(void) } str[8] = stat_config.topdown_level + '0'; if (metricgroup__parse_groups(evlist, - pmu, str, + pmu, parse_events_option_args.cputype_filter, str, /*metric_no_group=*/false, /*metric_no_merge=*/false, /*metric_no_threshold=*/true, @@ -2116,7 +2122,9 @@ static int add_default_events(void) ret = -ENOMEM; break; } - if (metricgroup__parse_groups(metric_evlist, pmu, default_metricgroup_names[i], + if (metricgroup__parse_groups(metric_evlist, pmu, + parse_events_option_args.cputype_filter, + default_metricgroup_names[i], /*metric_no_group=*/false, /*metric_no_merge=*/false, /*metric_no_threshold=*/true, @@ -2852,7 +2860,9 @@ int cmd_stat(int argc, const char **argv) */ if (metrics) { const char *pmu = parse_events_option_args.pmu_filter ?: "all"; - int ret = metricgroup__parse_groups(evsel_list, pmu, metrics, + int ret = metricgroup__parse_groups(evsel_list, pmu, + parse_events_option_args.cputype_filter, + metrics, stat_config.metric_no_group, stat_config.metric_no_merge, stat_config.metric_no_threshold, diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c index 549fbd473ab7..04d62611766a 100644 --- a/tools/perf/tests/expand-cgroup.c +++ b/tools/perf/tests/expand-cgroup.c @@ -179,7 +179,8 @@ static int expand_metric_events(void) TEST_ASSERT_VAL("failed to get evlist", evlist); pme_test = find_core_metrics_table("testarch", "testcpu"); - ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str); + ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str, + /*cputype_filter=*/false); if (ret < 0) { pr_debug("failed to parse '%s' metric\n", metric_str); goto out; diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 0ad0273da923..5f6f95c8a5b4 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -2561,8 +2561,10 @@ static int test_event(const struct evlist_test *e) return TEST_FAIL; } parse_events_error__init(&err); - ret = __parse_events(evlist, e->name, /*pmu_filter=*/NULL, &err, /*fake_pmu=*/false, - /*warn_if_reordered=*/true, /*fake_tp=*/true); + ret = __parse_events(evlist, e->name, /*pmu_filter=*/NULL, + /*cputype_filter=*/false, &err, /*fake_pmu=*/false, + /*warn_if_reordered=*/true, + /*fake_tp=*/true); if (ret) { pr_debug("failed to parse event '%s', err %d\n", e->name, ret); parse_events_error__print(&err, e->name); @@ -2589,8 +2591,9 @@ static int test_event_fake_pmu(const char *str) return -ENOMEM; parse_events_error__init(&err); - ret = __parse_events(evlist, str, /*pmu_filter=*/NULL, &err, - /*fake_pmu=*/true, /*warn_if_reordered=*/true, + ret = __parse_events(evlist, str, /*pmu_filter=*/NULL, + /*cputype_filter=*/false, &err, /*fake_pmu=*/true, + /*warn_if_reordered=*/true, /*fake_tp=*/true); if (ret) { pr_debug("failed to parse event '%s', err %d\n", diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c index 8f9211eaf341..872d9a7aa72f 100644 --- a/tools/perf/tests/parse-metric.c +++ b/tools/perf/tests/parse-metric.c @@ -92,7 +92,8 @@ static int __compute_metric(const char *name, struct value *vals, /* Parse the metric into metric_events list. */ pme_test = find_core_metrics_table("testarch", "testcpu"); - err = metricgroup__parse_groups_test(evlist, pme_test, name); + err = metricgroup__parse_groups_test(evlist, pme_test, name, + /*cputype_filter=*/false); if (err) goto out; diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 4c6fc1207b6d..f507ce39439a 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -794,8 +794,10 @@ static int check_parse_id(const char *id, struct parse_events_error *error) for (cur = strchr(dup, '@') ; cur; cur = strchr(++cur, '@')) *cur = '/'; - ret = __parse_events(evlist, dup, /*pmu_filter=*/NULL, error, /*fake_pmu=*/true, - /*warn_if_reordered=*/true, /*fake_tp=*/false); + ret = __parse_events(evlist, dup, /*pmu_filter=*/NULL, + /*cputype_filter=*/false, error, /*fake_pmu=*/true, + /*warn_if_reordered=*/true, + /*fake_tp=*/false); free(dup); evlist__put(evlist); @@ -871,7 +873,9 @@ static int test__parsing_callback(const struct pmu_metric *pm, perf_evlist__set_maps(evlist__core(evlist), cpus, NULL); - err = metricgroup__parse_groups_test(evlist, table, pm->metric_name); + err = metricgroup__parse_groups_test(evlist, table, + pm->metric_name, + /*cputype_filter=*/false); if (err) { if (is_expected_broken_metric(pm)) { (*failures)--; diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 8c7b299a55db..69bfa2a723b2 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -1262,7 +1262,8 @@ static int parse_ids(bool metric_no_merge, bool fake_pmu, struct expr_parse_ctx *ids, const char *modifier, bool group_events, const bool tool_events[TOOL_PMU__EVENT_MAX], struct evlist **out_evlist, - const char *filter_pmu) + const char *filter_pmu, + bool cputype_filter) { struct parse_events_error parse_error; struct evlist *parsed_evlist; @@ -1317,7 +1318,9 @@ static int parse_ids(bool metric_no_merge, bool fake_pmu, pr_debug("Parsing metric events '%s'\n", events.buf); parse_events_error__init(&parse_error); ret = __parse_events(parsed_evlist, events.buf, filter_pmu, - &parse_error, fake_pmu, /*warn_if_reordered=*/false, + cputype_filter, + &parse_error, fake_pmu, + /*warn_if_reordered=*/false, /*fake_tp=*/false); if (ret) { parse_events_error__print(&parse_error, events.buf); @@ -1382,7 +1385,7 @@ static struct evsel *pick_display_evsel(struct list_head *metric_list, } static int parse_groups(struct evlist *perf_evlist, - const char *pmu, const char *str, + const char *pmu, bool cputype_filter, const char *str, bool metric_no_group, bool metric_no_merge, bool metric_no_threshold, @@ -1420,7 +1423,8 @@ static int parse_groups(struct evlist *perf_evlist, /*group_events=*/false, tool_events, &combined_evlist, - (pmu && strcmp(pmu, "all") == 0) ? NULL : pmu); + (pmu && strcmp(pmu, "all") == 0) ? NULL : pmu, + cputype_filter); } if (combined) expr__ctx_free(combined); @@ -1476,7 +1480,8 @@ static int parse_groups(struct evlist *perf_evlist, if (!metric_evlist) { ret = parse_ids(metric_no_merge, fake_pmu, m->pctx, m->modifier, m->group_events, tool_events, &m->evlist, - (pmu && strcmp(pmu, "all") == 0) ? NULL : pmu); + (pmu && strcmp(pmu, "all") == 0) ? NULL : pmu, + cputype_filter); if (ret) goto out; @@ -1543,6 +1548,7 @@ static int parse_groups(struct evlist *perf_evlist, if (combined_evlist) { evlist__splice_list_tail(perf_evlist, &evlist__core(combined_evlist)->entries); evlist__put(combined_evlist); + combined_evlist = NULL; } list_for_each_entry(m, &metric_list, nd) { @@ -1551,12 +1557,15 @@ static int parse_groups(struct evlist *perf_evlist, } out: + if (combined_evlist) + evlist__put(combined_evlist); metricgroup__free_metrics(&metric_list); return ret; } int metricgroup__parse_groups(struct evlist *perf_evlist, const char *pmu, + bool cputype_filter, const char *str, bool metric_no_group, bool metric_no_merge, @@ -1570,16 +1579,17 @@ int metricgroup__parse_groups(struct evlist *perf_evlist, if (hardware_aware_grouping) pr_debug("Use hardware aware grouping instead of traditional metric grouping method\n"); - return parse_groups(perf_evlist, pmu, str, metric_no_group, metric_no_merge, + return parse_groups(perf_evlist, pmu, cputype_filter, str, metric_no_group, metric_no_merge, metric_no_threshold, user_requested_cpu_list, system_wide, /*fake_pmu=*/false, table); } int metricgroup__parse_groups_test(struct evlist *evlist, const struct pmu_metrics_table *table, - const char *str) + const char *str, + bool cputype_filter) { - return parse_groups(evlist, "all", str, + return parse_groups(evlist, "all", cputype_filter, str, /*metric_no_group=*/false, /*metric_no_merge=*/false, /*metric_no_threshold=*/false, diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h index 4be6bfc13c46..6a66f14dd01b 100644 --- a/tools/perf/util/metricgroup.h +++ b/tools/perf/util/metricgroup.h @@ -71,6 +71,7 @@ struct metric_event *metricgroup__lookup(struct rblist *metric_events, bool create); int metricgroup__parse_groups(struct evlist *perf_evlist, const char *pmu, + bool cputype_filter, const char *str, bool metric_no_group, bool metric_no_merge, @@ -80,7 +81,8 @@ int metricgroup__parse_groups(struct evlist *perf_evlist, bool hardware_aware_grouping); int metricgroup__parse_groups_test(struct evlist *evlist, const struct pmu_metrics_table *table, - const char *str); + const char *str, + bool cputype_filter); int metricgroup__for_each_metric(const struct pmu_metrics_table *table, pmu_metric_iter_fn fn, void *data); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 194bc94dfc1e..cc7ad331a49f 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -429,6 +429,9 @@ bool parse_events__filter_pmu(const struct parse_events_state *parse_state, if (parse_state->pmu_filter == NULL) return false; + if (parse_state->cputype_filter && !pmu->is_core) + return false; + return perf_pmu__wildcard_match(pmu, parse_state->pmu_filter) == 0; } @@ -2288,18 +2291,20 @@ static int parse_events__sort_events_and_fix_groups(struct list_head *list) return (idx_changed || num_leaders != orig_num_leaders) ? 1 : 0; } -int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filter, +int __parse_events(struct evlist *evlist, const char *str, + const char *pmu_filter, bool cputype_filter, struct parse_events_error *err, bool fake_pmu, bool warn_if_reordered, bool fake_tp) { struct parse_events_state parse_state = { - .list = LIST_HEAD_INIT(parse_state.list), - .idx = evlist__nr_entries(evlist), - .error = err, - .stoken = PE_START_EVENTS, - .fake_pmu = fake_pmu, - .fake_tp = fake_tp, - .pmu_filter = pmu_filter, + .list = LIST_HEAD_INIT(parse_state.list), + .idx = evlist__nr_entries(evlist), + .error = err, + .stoken = PE_START_EVENTS, + .fake_pmu = fake_pmu, + .fake_tp = fake_tp, + .pmu_filter = pmu_filter, + .cputype_filter = cputype_filter, .match_legacy_cache_terms = true, }; int ret, ret2; @@ -2312,15 +2317,15 @@ int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filte } ret2 = parse_events__sort_events_and_fix_groups(&parse_state.list); - if (ret2 < 0) - return ret; + if (ret2 < 0 && !ret) + ret = ret2; /* * Add list to the evlist even with errors to allow callers to clean up. */ evlist__splice_list_tail(evlist, &parse_state.list); - if (ret2 && warn_if_reordered && !parse_state.wild_card_pmus) { + if (ret2 > 0 && warn_if_reordered && !parse_state.wild_card_pmus) { evlist__uniquify_evsel_names(evlist, &stat_config); pr_warning("WARNING: events were regrouped to match PMUs\n"); @@ -2518,8 +2523,9 @@ int parse_events_option(const struct option *opt, const char *str, int ret; parse_events_error__init(&err); - ret = __parse_events(*args->evlistp, str, args->pmu_filter, &err, - /*fake_pmu=*/false, /*warn_if_reordered=*/true, + ret = __parse_events(*args->evlistp, str, args->pmu_filter, + args->cputype_filter, &err, /*fake_pmu=*/false, + /*warn_if_reordered=*/true, /*fake_tp=*/false); if (ret) { diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 3577ab213730..b14c832b03a1 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -26,20 +26,23 @@ const char *event_type(size_t type); struct parse_events_option_args { struct evlist **evlistp; const char *pmu_filter; + bool cputype_filter; }; int parse_events_option(const struct option *opt, const char *str, int unset); int parse_events_option_new_evlist(const struct option *opt, const char *str, int unset); -__attribute__((nonnull(1, 2, 4))) -int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filter, - struct parse_events_error *error, bool fake_pmu, - bool warn_if_reordered, bool fake_tp); +__attribute__((nonnull(1, 2, 5))) int +__parse_events(struct evlist *evlist, const char *str, const char *pmu_filter, + bool cputype_filter, struct parse_events_error *error, + bool fake_pmu, bool warn_if_reordered, bool fake_tp); __attribute__((nonnull(1, 2, 3))) static inline int parse_events(struct evlist *evlist, const char *str, struct parse_events_error *err) { - return __parse_events(evlist, str, /*pmu_filter=*/NULL, err, /*fake_pmu=*/false, - /*warn_if_reordered=*/true, /*fake_tp=*/false); + return __parse_events(evlist, str, /*pmu_filter=*/NULL, + /*cputype_filter=*/false, err, /*fake_pmu=*/false, + /*warn_if_reordered=*/true, + /*fake_tp=*/false); } int parse_event(struct evlist *evlist, const char *str); @@ -161,6 +164,8 @@ struct parse_events_state { bool fake_tp; /* If non-null, when wildcard matching only match the given PMU. */ const char *pmu_filter; + /* If true, the pmu_filter was set by --cputype option. */ + bool cputype_filter; /* Should PE_LEGACY_NAME tokens be generated for config terms? */ bool match_legacy_cache_terms; /* Were multiple PMUs scanned to find events? */ diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 11e1f39c1bea..af85c0771c44 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -3411,7 +3411,8 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args) ((struct pyrf_cpu_map *)pcpus)->cpus : NULL; perf_evlist__set_maps(evlist__core(evlist), cpus, threads); - ret = metricgroup__parse_groups(evlist, pmu ?: "all", input, + ret = metricgroup__parse_groups(evlist, pmu ?: "all", + /*cputype_filter=*/false, input, /*metric_no_group=*/ false, /*metric_no_merge=*/ false, /*metric_no_threshold=*/ true, -- cgit v1.2.3 From 32e6312f7e397bf0b731b43a6504966398af0788 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 22 Jun 2026 18:27:47 -0700 Subject: perf test: Truncate test description to fit terminal width The parallel test harness uses the carriage return delete escape sequence `PERF_COLOR_DELETE_LINE` ("\033[A\33[2K\r") to erase and update the "Running (X active)" progress lines. However, if a test description is longer than the terminal width, the line wraps around. When this happens, the cursor up escape sequence `\033[A` only moves the cursor to the last wrapped row, leaving the top half of the description printed on the previous line. This leads to name duplication and output corruption spilling over multiple rows on consoles narrower than the maximum description length (e.g., 101 columns wide). Fix this by dynamically querying the terminal width using `get_term_dimensions` and truncating the printed test descriptions using the `%-*.*s` printf format. We reserve 35 characters for prefix, status, and spacing metrics to guarantee the progress line never wraps. Fixes: 0e036dcad4e6 ("perf test: Display number of active running tests") Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/tests/builtin-test.c | 163 ++++++++++++++++++++++------------------ 1 file changed, 89 insertions(+), 74 deletions(-) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 7e75f590f225..8b8f63f706d9 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -10,37 +10,40 @@ #ifdef HAVE_BACKTRACE_SUPPORT #include #endif -#include -#include #include -#include #include -#include +#include + #include -#include +#include "util/term.h" +#include +#include +#include +#include +#include #include #include -#include -#include "util/term.h" +#include +#include +#include + +#include +#include +#include + #include "builtin.h" +#include "color.h" #include "config.h" +#include "debug.h" #include "hist.h" #include "intlist.h" -#include "tests.h" -#include "debug.h" -#include "color.h" -#include -#include #include "string2.h" #include "symbol.h" +#include "tests-scripts.h" +#include "tests.h" #include "util/rlimit.h" #include "util/strbuf.h" -#include -#include -#include -#include - -#include "tests-scripts.h" +#include "util/term.h" static const char *junit_filename; static struct strbuf junit_xml_buf = STRBUF_INIT; @@ -415,73 +418,73 @@ static char *xml_escape(const char *str) return res ? res : strdup(""); } -static const char *format_test_description(const char *desc, int max_desc_width, - char *buf, size_t buf_sz) +static int get_term_width(void) { - int len = strlen(desc); + struct winsize ws; + int cols = 80; + int term_width; /* - * Clamp to buf_sz to prevent GCC format-truncation warnings - * when terminal width is very large. + * If output is redirected to a file or piped, we don't need to wrap + * or truncate at all. Use a massive virtually infinite terminal width + * so descriptions are printed in full. */ - if (max_desc_width >= (int)buf_sz) - max_desc_width = buf_sz - 1; + if (!isatty(fileno(debug_file()))) + return 10000; - if (len > max_desc_width) { - snprintf(buf, buf_sz, "%.*s...", max_desc_width - 3, desc); - return buf; - } - return desc; + get_term_dimensions(&ws); + if (ws.ws_col > 0) + cols = ws.ws_col; + + /* + * Limit description width to fit on a single line. We subtract 35 + * columns of headroom to allocate space for: + * - The suite index prefix: e.g. " 10.100:" (8 characters) plus 1 space separator. + * - The trailing colon (1 character) and space before status (1 character). + * - The longest status results: e.g. "Skip (some metrics failed)" (26 characters) + * or "Running (XX active)" (20 characters). + * + * A minimum description width of 10 is enforced to ensure names are + * legible even on very narrow consoles. + */ + term_width = cols - 35; + if (term_width < 10) + term_width = 10; + + return term_width; +} + +static int get_max_desc_width(int width) +{ + int term_width = get_term_width(); + + return width > term_width ? term_width : width; } static int print_test_result(struct test_suite *t, int curr_suite, int curr_test_case, int result, int width, int running, const char *err_output, double elapsed) { - char desc_buf[256]; - const char *desc = test_description(t, curr_test_case); - struct winsize ws; - int max_desc_area_width; - int target_desc_area_width; - int desc_padding; - - get_term_dimensions(&ws); - /* - * Total terminal columns minus space for status e.g. " Running (12 active)" - * which is 20 chars, plus a margin of 3 chars = 23 chars. - */ - max_desc_area_width = ws.ws_col - 23; - if (max_desc_area_width < 40) - max_desc_area_width = 40; - - /* Standard test has prefix "%3d: " which is 5 chars */ - target_desc_area_width = width + 5; - if (target_desc_area_width > max_desc_area_width) - target_desc_area_width = max_desc_area_width; + int pad_width = get_max_desc_width(width); + int term_width = get_term_width(); if (test_suite__num_test_cases(t) > 1) { char prefix[32]; int len = snprintf(prefix, sizeof(prefix), "%3d.%1d:", curr_suite + 1, curr_test_case + 1); + int pad = len >= 4 ? pad_width + 4 - len : pad_width; + int trunc = len >= 4 ? term_width + 4 - len : term_width; - desc_padding = target_desc_area_width - (len + 1); - if (desc_padding < 20) - desc_padding = 20; - - desc = format_test_description(desc, desc_padding, desc_buf, sizeof(desc_buf)); - pr_info("%s %-*s:", prefix, desc_padding, desc); + pr_info("%s %-*.*s:", prefix, pad, trunc, + test_description(t, curr_test_case)); } else { - desc_padding = target_desc_area_width - 5; - if (desc_padding < 20) - desc_padding = 20; - - desc = format_test_description(desc, desc_padding, desc_buf, sizeof(desc_buf)); - pr_info("%3d: %-*s:", curr_suite + 1, desc_padding, desc); + pr_info("%3d: %-*.*s:", curr_suite + 1, pad_width, term_width, + test_description(t, curr_test_case)); } switch (result) { case TEST_RUNNING: - color_fprintf(stderr, PERF_COLOR_YELLOW, " Running (%d active)\n", running); + color_fprintf(debug_file(), PERF_COLOR_YELLOW, " Running (%d active)\n", running); break; case TEST_OK: if (test_suite__num_test_cases(t) > 1) @@ -495,9 +498,9 @@ static int print_test_result(struct test_suite *t, int curr_suite, int curr_test summary_tests_skipped++; if (reason) - color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (%s)\n", reason); + color_fprintf(debug_file(), PERF_COLOR_YELLOW, " Skip (%s)\n", reason); else - color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n"); + color_fprintf(debug_file(), PERF_COLOR_YELLOW, " Skip\n"); } break; case TEST_FAIL: @@ -511,7 +514,7 @@ static int print_test_result(struct test_suite *t, int curr_suite, int curr_test strbuf_addf_safe(&summary_failed_tests_buf, " %3d: %s\n", curr_suite + 1, test_description(t, curr_test_case)); - color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n"); + color_fprintf(debug_file(), PERF_COLOR_RED, " FAILED!\n"); break; } @@ -747,6 +750,7 @@ static void finish_test(struct child_test **child_tests, int running_test, int c int ret; struct timespec end_time; double elapsed; + width = get_max_desc_width(width); if (child_test == NULL) { /* Test wasn't started. */ @@ -761,7 +765,8 @@ static void finish_test(struct child_test **child_tests, int running_test, int c * sub test names. */ if (test_suite__num_test_cases(t) > 1 && curr_test_case == 0) - pr_info("%3d: %s:\n", curr_suite + 1, test_description(t, -1)); + pr_info("%3d: %-*.*s:\n", curr_suite + 1, width, width, + test_description(t, -1)); /* * Busy loop reading from the child's stdout/stderr that are set to be @@ -969,6 +974,8 @@ static int finish_tests_parallel(struct child_test **child_tests, size_t num_tes int last_suite_printed = -1; sigset_t set, oldset; + width = get_max_desc_width(width); + sigemptyset(&set); sigaddset(&set, SIGINT); sigaddset(&set, SIGTERM); @@ -1037,8 +1044,11 @@ static int finish_tests_parallel(struct child_test **child_tests, size_t num_tes if (next_child) { if (test_suite__num_test_cases(next_child->test) > 1 && last_suite_printed != next_child->suite_num) { - pr_info("%3d: %s:\n", next_child->suite_num + 1, - test_description(next_child->test, -1)); + pr_info("%3d: %-*.*s:\n", + next_child->suite_num + 1, + width, width, + test_description( + next_child->test, -1)); last_suite_printed = next_child->suite_num; } print_test_result(next_child->test, next_child->suite_num, @@ -1101,7 +1111,8 @@ static int finish_tests_parallel(struct child_test **child_tests, size_t num_tes if (test_suite__num_test_cases(child->test) > 1 && last_suite_printed != child->suite_num) { - pr_info("%3d: %s:\n", child->suite_num + 1, + pr_info("%3d: %-*.*s:\n", child->suite_num + 1, + width, width, test_description(child->test, -1)); last_suite_printed = child->suite_num; } @@ -1225,12 +1236,12 @@ static void print_tests_summary(void) pr_info("Passed subtests : %u\n", summary_subtests_passed); pr_info("Skipped tests : %u\n", summary_tests_skipped); if (summary_tests_failed > 0) { - color_fprintf(stderr, PERF_COLOR_RED, "Failed tests : %u\n", + color_fprintf(debug_file(), PERF_COLOR_RED, "Failed tests : %u\n", summary_tests_failed); pr_info("List of failed tests:\n"); pr_info("%s", summary_failed_tests_buf.buf); } else { - color_fprintf(stderr, PERF_COLOR_GREEN, "Failed tests : 0\n"); + color_fprintf(debug_file(), PERF_COLOR_GREEN, "Failed tests : 0\n"); } if (junit_filename) { @@ -1348,9 +1359,13 @@ static int __cmd_test(struct test_suite **suites, int argc, const char *argv[], if (intlist__find(skiplist, curr_suite + 1)) { if (pass == 1) { - pr_info("%3d: %-*s:", curr_suite + 1, width, + int pad_width = get_max_desc_width(width); + int term_width = get_term_width(); + + pr_info("%3d: %-*.*s:", curr_suite + 1, + pad_width, term_width, test_description(*t, -1)); - color_fprintf(stderr, PERF_COLOR_YELLOW, + color_fprintf(debug_file(), PERF_COLOR_YELLOW, " Skip (user override)\n"); summary_tests_skipped++; if (junit_filename) { -- cgit v1.2.3 From 810d0c911796bdc8ec67d5844b070c7f48bd732a Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 22 Jun 2026 18:27:48 -0700 Subject: perf tests workloads: Support sub-second durations in noploop and thloop Currently, the noploop and thloop workloads only support sleep durations in integer seconds because they parse the argument using atoi() and use alarm() for timer signaling. To support much shorter execution times in tests (speeding up test suites and allowing faster retries), change the input parsing to use atof() for double floating-point seconds. Use ualarm() for fractional durations less than 1.0 seconds, and fall back to alarm() for durations of 1.0 second or more. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/tests/workloads/noploop.c | 17 ++++++++++++++--- tools/perf/tests/workloads/thloop.c | 16 +++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/tools/perf/tests/workloads/noploop.c b/tools/perf/tests/workloads/noploop.c index 656e472e6188..ca9f871e136f 100644 --- a/tools/perf/tests/workloads/noploop.c +++ b/tools/perf/tests/workloads/noploop.c @@ -15,15 +15,26 @@ static void sighandler(int sig __maybe_unused) static int noploop(int argc, const char **argv) { - int sec = 1; + double sec = 1.0; pthread_setname_np(pthread_self(), "perf-noploop"); if (argc > 0) - sec = atoi(argv[0]); + sec = atof(argv[0]); + + if (!(sec > 0.0)) { + fprintf(stderr, "Error: seconds (%f) must be > 0\n", sec); + return 1; + } signal(SIGINT, sighandler); signal(SIGALRM, sighandler); - alarm(sec); + + if (sec < 1.0) { + useconds_t usecs = (useconds_t)(sec * 1000000.0); + + ualarm(usecs > 0 ? usecs : 1, 0); + } else + alarm((unsigned int)sec); while (!done) continue; diff --git a/tools/perf/tests/workloads/thloop.c b/tools/perf/tests/workloads/thloop.c index bd8168f883fb..c830d739489f 100644 --- a/tools/perf/tests/workloads/thloop.c +++ b/tools/perf/tests/workloads/thloop.c @@ -31,14 +31,15 @@ static void *thfunc(void *arg) static int thloop(int argc, const char **argv) { - int nt = 2, sec = 1, err = 1; + int nt = 2, err = 1; + double sec = 1.0; pthread_t *thread_list = NULL; if (argc > 0) - sec = atoi(argv[0]); + sec = atof(argv[0]); - if (sec <= 0) { - fprintf(stderr, "Error: seconds (%d) must be >= 1\n", sec); + if (!(sec > 0.0)) { + fprintf(stderr, "Error: seconds (%f) must be > 0\n", sec); return 1; } @@ -67,7 +68,12 @@ static int thloop(int argc, const char **argv) goto out; } } - alarm(sec); + if (sec < 1.0) { + useconds_t usecs = (useconds_t)(sec * 1000000.0); + + ualarm(usecs > 0 ? usecs : 1, 0); + } else + alarm((unsigned int)sec); test_loop(); err = 0; out: -- cgit v1.2.3 From 74dba58222f0d34cf8bd3eba1a6926e9654d4b6b Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 22 Jun 2026 18:27:49 -0700 Subject: perf tests: Add robust record retry helper and use subsecond workloads Introduce `perf_record_with_retry` and `perf_record_cleanup` in a shared library `tests/shell/lib/perf_record.sh` to prevent record test failures caused by transient recording or workload delays. Update `record.sh`, `record_lbr.sh`, `pipe_test.sh`, `kvm.sh`, and `stat_all_pfm.sh` to use this robust record retry logic. These tests now start with very short durations (e.g. 0.01 seconds) and scale up if the initial recording failed to capture samples, significantly improving test execution speed on success while remaining resilient to slow systems. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/kvm.sh | 61 +++++++---- tools/perf/tests/shell/lib/perf_record.sh | 53 +++++++++ tools/perf/tests/shell/pipe_test.sh | 4 +- tools/perf/tests/shell/record.sh | 173 +++++++++++++++--------------- tools/perf/tests/shell/record_lbr.sh | 50 ++++++--- 5 files changed, 214 insertions(+), 127 deletions(-) create mode 100644 tools/perf/tests/shell/lib/perf_record.sh diff --git a/tools/perf/tests/shell/kvm.sh b/tools/perf/tests/shell/kvm.sh index f88e859025c4..a5396f8e6fe5 100755 --- a/tools/perf/tests/shell/kvm.sh +++ b/tools/perf/tests/shell/kvm.sh @@ -39,17 +39,28 @@ skip() { test_kvm_stat() { echo "Testing perf kvm stat" - echo "Recording kvm events for pid ${qemu_pid}..." - if ! perf kvm stat record -p "${qemu_pid}" -o "${perfdata}" sleep 1; then - echo "Failed to record kvm events" - err=1 - return - fi + local duration + local success=false + for duration in 1 2 4 8; do + echo "Recording kvm events for pid ${qemu_pid} (duration ${duration}s)..." + rm -f "${perfdata}" "${perfdata}".old + if ! perf kvm stat record -p "${qemu_pid}" -o "${perfdata}" \ + sleep ${duration} >/dev/null 2>&1; then + echo "perf kvm stat record failed, retrying..." + continue + fi + + if [ -e "${perfdata}" ] && \ + perf kvm -i "${perfdata}" stat report 2>&1 | grep -q "VM-EXIT"; then + success=true + break + fi + echo "No VM-EXIT events found, retrying..." + done - echo "Reporting kvm events..." - if ! perf kvm -i "${perfdata}" stat report 2>&1 | grep -q "VM-EXIT"; then + if [ "$success" = false ]; then echo "Failed to find VM-EXIT in report" - perf kvm -i "${perfdata}" stat report 2>&1 + perf kvm -i "${perfdata}" stat report 2>&1 || true err=1 return fi @@ -60,22 +71,26 @@ test_kvm_stat() { test_kvm_record_report() { echo "Testing perf kvm record/report" - echo "Recording kvm profile for pid ${qemu_pid}..." - # Use --host to avoid needing guest symbols/mounts for this simple test - # We just want to verify the command runs and produces data - # We run in background and kill it because 'perf kvm record' appends options - # after the command, which breaks 'sleep' (e.g. it gets '-e cycles'). - perf kvm --host record -p "${qemu_pid}" -o "${perfdata}" & - rec_pid=$! - sleep 1 - kill -INT "${rec_pid}" - wait "${rec_pid}" || true + local duration + local success=false + for duration in 1 2 4 8; do + echo "Recording kvm profile for pid ${qemu_pid} (duration ${duration}s)..." + rm -f "${perfdata}" "${perfdata}".old + + perf kvm --host record -p "${qemu_pid}" -o "${perfdata}" \ + -e cpu-clock sleep ${duration} + + if [ -e "${perfdata}" ] && \ + perf kvm -i "${perfdata}" report --stdio 2>&1 | grep -q "Event count"; then + success=true + break + fi + echo "No samples or report failed, retrying..." + done - echo "Reporting kvm profile..." - # Check for some standard output from report - if ! perf kvm -i "${perfdata}" report --stdio 2>&1 | grep -q "Event count"; then + if [ "$success" = false ]; then echo "Failed to report kvm profile" - perf kvm -i "${perfdata}" report --stdio 2>&1 + perf kvm -i "${perfdata}" report --stdio 2>&1 || true err=1 return fi diff --git a/tools/perf/tests/shell/lib/perf_record.sh b/tools/perf/tests/shell/lib/perf_record.sh new file mode 100644 index 000000000000..e137fa75370d --- /dev/null +++ b/tools/perf/tests/shell/lib/perf_record.sh @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: GPL-2.0 + +PERF_RECORD_LOGS=() + +perf_record_with_retry() { + local perfdata="$1" + local check_cmd="$2" + local testprog_base="$3" + shift 3 + + local logfile + logfile=$(mktemp /tmp/__perf_record_retry.XXXXXX) + PERF_RECORD_LOGS+=("$logfile") + + # Save the e flag state and disable it + local save_e + if [[ $- == *e* ]]; then + save_e="set -e" + else + save_e="set +e" + fi + set +e + + local duration + local first_run=true + local ret=1 + for duration in 0.01 0.1 0.3 1.0 2.0; do + rm -f "${perfdata}".old + perf record "$@" -o "${perfdata}" ${testprog_base} ${duration} > "$logfile" 2>&1 + local record_exit=$? + + if [ "$first_run" = true ] && [ $record_exit -ne 0 ]; then + ret=2 + break + fi + first_run=false + + if [ -e "${perfdata}" ] && eval "${check_cmd}"; then + ret=0 + break + fi + done + + eval "$save_e" + return $ret +} + +perf_record_cleanup() { + for logfile in "${PERF_RECORD_LOGS[@]}"; do + rm -f "$logfile" + done + PERF_RECORD_LOGS=() +} diff --git a/tools/perf/tests/shell/pipe_test.sh b/tools/perf/tests/shell/pipe_test.sh index e459aa99a951..ce68d850c983 100755 --- a/tools/perf/tests/shell/pipe_test.sh +++ b/tools/perf/tests/shell/pipe_test.sh @@ -12,8 +12,8 @@ skip_test_missing_symbol ${sym} data=$(mktemp /tmp/perf.data.XXXXXX) data2=$(mktemp /tmp/perf.data2.XXXXXX) -prog="perf test -w noploop" -[ "$(uname -m)" = "s390x" ] && prog="$prog 3" +prog="perf test -w noploop 0.1" +[ "$(uname -m)" = "s390x" ] && prog="perf test -w noploop 3" err=0 set -e diff --git a/tools/perf/tests/shell/record.sh b/tools/perf/tests/shell/record.sh index 7cb81cf3444a..dd90fef2088b 100755 --- a/tools/perf/tests/shell/record.sh +++ b/tools/perf/tests/shell/record.sh @@ -1,10 +1,13 @@ #!/bin/bash -# perf record tests (exclusive) # SPDX-License-Identifier: GPL-2.0 +# perf record tests set -e shelldir=$(dirname "$0") +. "${shelldir}"/lib/perf_record.sh + + # shellcheck source=lib/waiting.sh . "${shelldir}"/lib/waiting.sh @@ -39,6 +42,7 @@ cleanup() { rm -f "${perfdata}" rm -f "${perfdata}".old rm -f "${script_output}" + perf_record_cleanup trap - EXIT TERM INT } @@ -50,22 +54,20 @@ trap_cleanup() { } trap trap_cleanup EXIT TERM INT +check_per_thread() { + perf report -i "${perfdata}" -q | grep -q "${testsym}" +} + test_per_thread() { echo "Basic --per-thread mode test" - if ! perf record -o /dev/null --quiet ${testprog} 2> /dev/null - then + local ret=0 + perf_record_with_retry "${perfdata}" "check_per_thread" "perf test -w thloop" \ + --per-thread || ret=$? + if [ $ret -eq 2 ]; then echo "Per-thread record [Skipped event not supported]" return - fi - if ! perf record --per-thread -o "${perfdata}" ${testprog} 2> /dev/null - then - echo "Per-thread record [Failed record]" - err=1 - return - fi - if ! perf report -i "${perfdata}" -q | grep -q "${testsym}" - then - echo "Per-thread record [Failed missing output]" + elif [ $ret -eq 1 ]; then + echo "Per-thread record [Failed record or missing output]" err=1 return fi @@ -96,6 +98,10 @@ test_per_thread() { echo "Basic --per-thread mode test [Success]" } +check_register_capture() { + perf script -F ip,sym,iregs -i "${perfdata}" 2>/dev/null | grep -q "DI:" +} + test_register_capture() { echo "Register capture test" if ! perf list pmu | grep -q 'br_inst_retired.near_call' @@ -108,11 +114,12 @@ test_register_capture() { echo "Register capture test [Skipped missing registers]" return fi - if ! perf record -o - --intr-regs=di,r8,dx,cx -e br_inst_retired.near_call \ - -c 1000 --per-thread ${testprog} 2> /dev/null \ - | perf script -F ip,sym,iregs -i - 2> /dev/null \ - | grep -q "DI:" - then + + local ret=0 + perf_record_with_retry "${perfdata}" "check_register_capture" "perf test -w thloop" \ + --intr-regs=di,r8,dx,cx -e br_inst_retired.near_call -c 1000 --per-thread || ret=$? + + if [ $ret -ne 0 ]; then echo "Register capture test [Failed missing output]" err=1 return @@ -120,65 +127,66 @@ test_register_capture() { echo "Register capture test [Success]" } +check_system_wide() { + perf report -i "${perfdata}" -q | grep -q "${testsym}" +} + test_system_wide() { echo "Basic --system-wide mode test" - if ! perf record -aB --synth=no -o "${perfdata}" ${testprog} 2> /dev/null - then + local ret=0 + perf_record_with_retry "${perfdata}" "check_system_wide" "perf test -w thloop" \ + -aB --synth=no || ret=$? + if [ $ret -eq 2 ]; then echo "System-wide record [Skipped not supported]" return - fi - if ! perf report -i "${perfdata}" -q | grep -q "${testsym}" - then + elif [ $ret -eq 1 ]; then echo "System-wide record [Failed missing output]" err=1 return fi - if ! perf record -aB --synth=no -e cpu-clock,cs --threads=cpu \ - -o "${perfdata}" ${testprog} 2> /dev/null - then - echo "System-wide record [Failed record --threads option]" - err=1 - return - fi - if ! perf report -i "${perfdata}" -q | grep -q "${testsym}" - then - echo "System-wide record [Failed --threads missing output]" + + ret=0 + perf_record_with_retry "${perfdata}" "check_system_wide" "perf test -w thloop" \ + -aB --synth=no -e cpu-clock,cs --threads=cpu || ret=$? + if [ $ret -ne 0 ]; then + echo "System-wide record [Failed record --threads option or missing output]" err=1 return fi echo "Basic --system-wide mode test [Success]" } +check_workload() { + perf report -i "${perfdata}" -q | grep -q "${testsym}" +} + test_workload() { echo "Basic target workload test" - if ! perf record -o "${perfdata}" ${testprog} 2> /dev/null - then - echo "Workload record [Failed record]" + local ret=0 + perf_record_with_retry "${perfdata}" "check_workload" "perf test -w thloop" || ret=$? + if [ $ret -ne 0 ]; then + echo "Workload record [Failed record or missing output]" err=1 return fi - if ! perf report -i "${perfdata}" -q | grep -q "${testsym}" - then - echo "Workload record [Failed missing output]" - err=1 - return - fi - if ! perf record -e cpu-clock,cs --threads=package \ - -o "${perfdata}" ${testprog} 2> /dev/null - then - echo "Workload record [Failed record --threads option]" - err=1 - return - fi - if ! perf report -i "${perfdata}" -q | grep -q "${testsym}" - then - echo "Workload record [Failed --threads missing output]" + + ret=0 + perf_record_with_retry "${perfdata}" "check_workload" "perf test -w thloop" \ + -e cpu-clock,cs --threads=package || ret=$? + if [ $ret -ne 0 ]; then + echo "Workload record [Failed record --threads option or missing output]" err=1 return fi echo "Basic target workload test [Success]" } +check_branch_counter() { + perf report -i "${perfdata}" -D -q 2>/dev/null | grep -q "$br_cntr_output" && \ + perf script -i "${perfdata}" -F +brstackinsn,+brcntr 2>/dev/null | \ + grep -q "$br_cntr_script_output" +} + test_branch_counter() { echo "Branch counter test" # Check if the branch counter feature is supported @@ -190,67 +198,60 @@ test_branch_counter() { return fi done - if ! perf record -o "${perfdata}" -e "{branches:p,instructions}" -j any,counter ${testprog} 2> /dev/null - then - echo "Branch counter record test [Failed record]" - err=1 - return - fi - if ! perf report -i "${perfdata}" -D -q | grep -q "$br_cntr_output" - then - echo "Branch counter report test [Failed missing output]" - err=1 - return - fi - if ! perf script -i "${perfdata}" -F +brstackinsn,+brcntr | grep -q "$br_cntr_script_output" - then - echo " Branch counter script test [Failed missing output]" + local ret=0 + perf_record_with_retry "${perfdata}" "check_branch_counter" "perf test -w thloop" \ + -e "{branches:p,instructions}" -j any,counter || ret=$? + if [ $ret -ne 0 ]; then + echo "Branch counter test [Failed record or missing output]" err=1 return fi echo "Branch counter test [Success]" } +check_cgroup() { + perf report -i "${perfdata}" -D 2>/dev/null | grep -q "CGROUP" && \ + perf script -i "${perfdata}" -F cgroup 2>/dev/null | grep -q -v "unknown" +} + test_cgroup() { echo "Cgroup sampling test" - if ! perf record -aB --synth=cgroup --all-cgroups -o "${perfdata}" ${testprog} 2> /dev/null - then + local ret=0 + perf_record_with_retry "${perfdata}" "check_cgroup" "perf test -w thloop" \ + -aB --synth=cgroup --all-cgroups || ret=$? + if [ $ret -eq 2 ]; then echo "Cgroup sampling [Skipped not supported]" return - fi - if ! perf report -i "${perfdata}" -D | grep -q "CGROUP" - then + elif [ $ret -eq 1 ]; then echo "Cgroup sampling [Failed missing output]" err=1 return fi - if ! perf script -i "${perfdata}" -F cgroup | grep -q -v "unknown" - then - echo "Cgroup sampling [Failed cannot resolve cgroup names]" - err=1 - return - fi echo "Cgroup sampling test [Success]" } +check_uid() { + perf report -i "${perfdata}" -q | grep -q "${testsym}" +} + test_uid() { echo "Uid sampling test" - if ! perf record -aB --synth=no --uid "$(id -u)" -o "${perfdata}" ${testprog} \ - > "${script_output}" 2>&1 - then - if grep -q "libbpf.*EPERM" "${script_output}" + local ret=0 + perf_record_with_retry "${perfdata}" "check_uid" "perf test -w thloop" \ + -aB --synth=no --uid "$(id -u)" || ret=$? + if [ $ret -eq 2 ]; then + local logfile="${PERF_RECORD_LOGS[${#PERF_RECORD_LOGS[@]}-1]}" + if grep -q -E "libbpf.*EPERM|Access to performance monitoring" "$logfile" || \ + grep -q -E "Permission denied|Failure to open any events" "$logfile" then echo "Uid sampling [Skipped permissions]" return else echo "Uid sampling [Failed to record]" err=1 - # cat "${script_output}" return fi - fi - if ! perf report -i "${perfdata}" -q | grep -q "${testsym}" - then + elif [ $ret -eq 1 ]; then echo "Uid sampling [Failed missing output]" err=1 return diff --git a/tools/perf/tests/shell/record_lbr.sh b/tools/perf/tests/shell/record_lbr.sh index 78a02e90ece1..8d51afeb437b 100755 --- a/tools/perf/tests/shell/record_lbr.sh +++ b/tools/perf/tests/shell/record_lbr.sh @@ -1,9 +1,12 @@ #!/bin/bash -# perf record LBR tests (exclusive) # SPDX-License-Identifier: GPL-2.0 +# perf record LBR tests set -e +shelldir=$(dirname "$0") +. "${shelldir}"/lib/perf_record.sh + ParanoidAndNotRoot() { [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] } @@ -22,6 +25,7 @@ cleanup() { rm -rf "${perfdata}" rm -rf "${perfdata}".old rm -rf "${perfdata}".txt + perf_record_cleanup trap - EXIT TERM INT } @@ -34,22 +38,28 @@ trap_cleanup() { trap trap_cleanup EXIT TERM INT +check_lbr_callgraph() { + perf report --stitch-lbr -i "${perfdata}" > "${perfdata}".txt 2>&1 +} + lbr_callgraph_test() { test="LBR callgraph" echo "$test" - if ! perf record -e cycles --call-graph lbr -o "${perfdata}" perf test -w thloop - then + set +e + perf_record_with_retry "${perfdata}" "check_lbr_callgraph" "perf test -w thloop" \ + -e cycles --call-graph lbr + local ret=$? + set -e + + if [ $ret -eq 2 ]; then echo "$test [Failed support missing]" if [ $err -eq 0 ] then err=2 fi return - fi - - if ! perf report --stitch-lbr -i "${perfdata}" > "${perfdata}".txt - then + elif [ $ret -eq 1 ]; then cat "${perfdata}".txt echo "$test [Failed in perf report]" err=1 @@ -59,6 +69,12 @@ lbr_callgraph_test() { echo "$test [Success]" } +check_lbr_samples() { + local out + out=$(perf report -D -i "${perfdata}" 2> /dev/null | grep -A1 'PERF_RECORD_SAMPLE') + [ "$(echo "$out" | grep -c 'PERF_RECORD_SAMPLE' || true)" -gt 0 ] +} + lbr_test() { local branch_flags=$1 local test="LBR $2 test" @@ -70,25 +86,27 @@ lbr_test() { local r echo "$test" - if ! perf record -e cycles $branch_flags -o "${perfdata}" perf test -w thloop - then + set +e + perf_record_with_retry "${perfdata}" "check_lbr_samples" "perf test -w thloop" \ + -e cycles $branch_flags + local ret=$? + set -e + + if [ $ret -eq 2 ]; then echo "$test [Failed support missing]" - perf record -e cycles $branch_flags -o "${perfdata}" perf test -w thloop || true if [ $err -eq 0 ] then err=2 fi return - fi - - out=$(perf report -D -i "${perfdata}" 2> /dev/null | grep -A1 'PERF_RECORD_SAMPLE') - sam_nr=$(echo "$out" | grep -c 'PERF_RECORD_SAMPLE' || true) - if [ $sam_nr -eq 0 ] - then + elif [ $ret -eq 1 ]; then echo "$test [Failed no samples captured]" err=1 return fi + + out=$(perf report -D -i "${perfdata}" 2> /dev/null | grep -A1 'PERF_RECORD_SAMPLE') + sam_nr=$(echo "$out" | grep -c 'PERF_RECORD_SAMPLE' || true) echo "$test: $sam_nr samples" bs_nr=$(echo "$out" | grep -c 'branch stack: nr:' || true) -- cgit v1.2.3 From 8953bfd8820b6525032023fda3a420098c1823ae Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 22 Jun 2026 18:27:50 -0700 Subject: perf tests: Skip metrics validation if system-wide recording lacks permission The metrics value validation test requires system-wide recording (`-a`), which can fail on systems without root permissions or where paranoid levels restrict tracing. Add a check to skip the test if `-a` is not supported. Also fix false negatives during validation by updating parse error string patterns and resolving issues in metric list generation. Fixes: 3ad7092f5145 ("perf test: Add metric value validation test") Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- .../perf/tests/shell/lib/perf_metric_validation.py | 11 ++-- tools/perf/tests/shell/stat_all_metrics.sh | 75 +++++++++++++--------- tools/perf/tests/shell/stat_metrics_values.sh | 7 ++ 3 files changed, 60 insertions(+), 33 deletions(-) diff --git a/tools/perf/tests/shell/lib/perf_metric_validation.py b/tools/perf/tests/shell/lib/perf_metric_validation.py index dea8ef1977bf..3d52f94f22b9 100644 --- a/tools/perf/tests/shell/lib/perf_metric_validation.py +++ b/tools/perf/tests/shell/lib/perf_metric_validation.py @@ -383,10 +383,13 @@ class Validator: wl = workload.split() command.extend(wl) print(" ".join(command)) - cmd = subprocess.run(command, stderr=subprocess.PIPE, encoding='utf-8') - data = [x+'}' for x in cmd.stderr.split('}\n') if x] - if data[0][0] != '{': - data[0] = data[0][data[0].find('{'):] + cmd = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8') + lines = cmd.stderr.splitlines() + cmd.stdout.splitlines() + data = [] + for line in lines: + line = line.strip() + if line.startswith('{') and line.endswith('}'): + data.append(line) return data def collect_perf(self, workload: str): diff --git a/tools/perf/tests/shell/stat_all_metrics.sh b/tools/perf/tests/shell/stat_all_metrics.sh index b582d23f28c9..feeb34c6fa6d 100755 --- a/tools/perf/tests/shell/stat_all_metrics.sh +++ b/tools/perf/tests/shell/stat_all_metrics.sh @@ -12,38 +12,65 @@ system_wide_flag="-a" if ParanoidAndNotRoot 0 then system_wide_flag="" - test_prog="perf test -w noploop" + test_prog="perf test -w noploop 0.01" fi +check_metric() { + local output="$1" + local status="$2" + local metric="$3" + + if [[ $status -ne 0 || ! "$output" =~ ${metric:0:50} ]]; then + return 1 + fi + + if [[ "$output" =~ "" || "$output" =~ "" ]]; then + return 1 + fi + + return 0 +} + skip=0 err=3 for m in $(perf list --raw-dump metrics); do echo "Testing $m" result=$(perf stat -M "$m" $system_wide_flag -- $test_prog 2>&1) result_err=$? - if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]] - then - # No error result and metric shown. + + if check_metric "$result" $result_err "$m"; then if [[ "$err" -ne 1 ]] then err=0 fi continue fi - if [[ "$result" =~ "Cannot resolve IDs for" || "$result" =~ "No supported events found" ]] + + if [[ "$result" =~ "Access to performance monitoring and observability operations is limited" || \ + "$result" =~ "in per-thread mode, enable system wide" || \ + "$result" =~ "" || \ + "$result" =~ "Cannot resolve IDs for" || \ + "$result" =~ "No supported events found" || \ + "$result" =~ "FP_ARITH" || \ + "$result" =~ "AMX" || \ + "$result" =~ "PMM" ]] then - if [[ $(perf list --raw-dump $m) == "Default"* ]] - then - echo "[Ignored $m] failed but as a Default metric this can be expected" - echo $result + true + else + result=$(perf stat -M "$m" $system_wide_flag -- perf test -w noploop 0.1 2>&1) + result_err=$? + + if check_metric "$result" $result_err "$m"; then + if [[ "$err" -ne 1 ]] + then + err=0 + fi continue fi - echo "[Failed $m] Metric contains missing events" - echo $result - err=1 # Fail - continue - elif [[ "$result" =~ \ - "Access to performance monitoring and observability operations is limited" ]] + fi + + # If retry also failed, determine if we skip, ignore, or fail + if [[ "$result" =~ "Access to performance monitoring and observability operations is limited" ]] then echo "[Skipped $m] Permission failure" echo $result @@ -61,7 +88,9 @@ for m in $(perf list --raw-dump metrics); do skip=1 fi continue - elif [[ "$result" =~ "" ]] + elif [[ "$result" =~ "" || \ + "$result" =~ "Cannot resolve IDs for" || \ + "$result" =~ "No supported events found" ]] then if [[ $(perf list --raw-dump $m) == "Default"* ]] then @@ -105,19 +134,7 @@ for m in $(perf list --raw-dump metrics); do continue fi - # Failed, possibly the workload was too small so retry with something longer. - result=$(perf stat -M "$m" $system_wide_flag -- perf bench internals synthesize 2>&1) - result_err=$? - if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]] - then - # No error result and metric shown. - if [[ "$err" -ne 1 ]] - then - err=0 - fi - continue - fi - echo "[Failed $m] has non-zero error '$result_err' or not printed in:" + echo "[Failed $m] has non-zero error '$result_err' or not printed/counted in:" echo "$result" err=1 done diff --git a/tools/perf/tests/shell/stat_metrics_values.sh b/tools/perf/tests/shell/stat_metrics_values.sh index 30566f0b5427..76f1e99d1273 100755 --- a/tools/perf/tests/shell/stat_metrics_values.sh +++ b/tools/perf/tests/shell/stat_metrics_values.sh @@ -8,6 +8,13 @@ shelldir=$(dirname "$0") grep -q GenuineIntel /proc/cpuinfo || { echo Skipping non-Intel; exit 2; } +# Skip if no permission to record system-wide events +if ! perf stat -a -e instructions sleep 0.01 >/dev/null 2>&1; then + echo "Skipping: no permission to record system-wide events (-a)" + exit 2 +fi + + pythonvalidator=$(dirname $0)/lib/perf_metric_validation.py rulefile=$(dirname $0)/lib/perf_metric_validation_rules.json tmpdir=$(mktemp -d /tmp/__perf_test.program.XXXXX) -- cgit v1.2.3 From 07eac17339dab6b143e12cadf19acd61f03011f8 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 22 Jun 2026 18:27:51 -0700 Subject: perf tests: Fix Python JIT dump profiling test failure The `python profiling with jitdump` test failed due to: 1. Target PID extraction resolving to duplicate space-separated values, which broke the buildid-cache loops. 2. The default workload duration being too short to capture JIT stack trampoline samples, resulting in 0 matching JIT symbols. Fix the PID parsing by sorting and retrieving a unique single-line value. Implement a robust retry loop starting at 1M python loop iterations and scaling up to 100M iterations until JIT symbols are successfully captured and verified. Fixes: c9cd0c7e529e ("perf test: Add python JIT dump test") Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/jitdump-python.sh | 79 +++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/tools/perf/tests/shell/jitdump-python.sh b/tools/perf/tests/shell/jitdump-python.sh index ae86203b14a2..05aaa3bd900b 100755 --- a/tools/perf/tests/shell/jitdump-python.sh +++ b/tools/perf/tests/shell/jitdump-python.sh @@ -16,11 +16,15 @@ if [ "${HAS_PERF_JIT}" != "True" ]; then exit 2 fi -PERF_DATA=$(mktemp /tmp/__perf_test.perf.data.XXXXXX) +PERF_DATA_DIR=$(mktemp -d /tmp/__perf_test.perf.data.dir.XXXXXX) +PERF_DATA="${PERF_DATA_DIR}/perf.data" cleanup() { echo "Cleaning up files..." - rm -f ${PERF_DATA} ${PERF_DATA}.jit /tmp/jit-${PID}.dump /tmp/jitted-${PID}-*.so 2> /dev/null + rm -rf ${PERF_DATA_DIR} 2> /dev/null + for p in ${ALL_PIDS}; do + rm -f /tmp/jit-${p}.dump /tmp/jitted-${p}-*.so 2> /dev/null + done trap - EXIT TERM INT } @@ -33,9 +37,16 @@ trap_cleanup() { trap trap_cleanup EXIT TERM INT -echo "Run python with -Xperf_jit" -cat <') - -echo "Found ${NUM} matching lines" - -echo "Remove JIT-ed DSOs from the build-ID cache" -for F in /tmp/jitted-${PID}-*.so; do - perf buildid-cache -r "${F}" + if [ -f "${PERF_DATA}.pid" ]; then + REAL_PID=$(cat "${PERF_DATA}.pid") + ALL_PIDS="${ALL_PIDS} ${REAL_PID}" + fi + + # extract PID of the target process from the data + PID=$(perf report -i "${PERF_DATA}" --stdio -F pid -q -g none | \ + cut -d: -f1 -s | sort -u | head -n 1 | tr -d ' ') + if [ -z "${PID}" ]; then + echo "Failed to get PID, retrying..." + continue + fi + ALL_PIDS="${ALL_PIDS} ${PID}" + + echo "Generate JIT-ed DSOs using perf inject" + DEBUGINFOD_URLS='' perf inject -i "${PERF_DATA}" -j -o "${PERF_DATA}.jit" + + echo "Add JIT-ed DSOs to the build-ID cache" + for F in /tmp/jitted-${PID}-*.so; do + perf buildid-cache -a "${F}" + done + + echo "Check the symbol containing the function/module name" + NUM=$(perf report -i "${PERF_DATA}.jit" -s sym --stdio | grep -cE 'py::(foo|bar|baz):') + + echo "Remove JIT-ed DSOs from the build-ID cache" + for F in /tmp/jitted-${PID}-*.so; do + perf buildid-cache -r "${F}" + done + rm -f /tmp/jitted-${PID}-*.so /tmp/jit-${PID}.dump 2>/dev/null + + if [ "${NUM}" -gt 0 ]; then + echo "Success: found ${NUM} matching lines" + break + fi + echo "No matching lines found, retrying with more iterations..." done cleanup -- cgit v1.2.3 From 509a2b9a6e142697dd5f34cdd802e5b86eababa1 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 22 Jun 2026 18:27:52 -0700 Subject: perf tests: Fix flakiness in trace record and replay test The `perf trace record and replay` test fails intermittently on slow or virtualized hosts because the default recording workload (`sleep 1`) occasionally completes without scheduling the target `nanosleep` or `clock_nanosleep` system calls inside the recorded sample window, resulting in the error: `Failed: cannot find *nanosleep syscall`. Generalize the `perf_record_with_retry` helper in `tests/shell/lib/perf_record.sh` to support a custom record command prefix via the `PERF_RECORD_CMD` environment variable (defaulting to "perf record"). Update `trace_record_replay.sh` to use this robust retry loop running with `PERF_RECORD_CMD="perf trace record"` and a base workload of `sleep`. The test will automatically retry with scaled sleep durations (from 0.01s up to 2.0s) until the required `nanosleep` event is successfully captured. Fixes: 15bcfb96d0dd ("perf test: Add trace record and replay test") Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/lib/perf_record.sh | 7 ++++- tools/perf/tests/shell/trace_record_replay.sh | 38 ++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/tools/perf/tests/shell/lib/perf_record.sh b/tools/perf/tests/shell/lib/perf_record.sh index e137fa75370d..2b9e11b66dc7 100644 --- a/tools/perf/tests/shell/lib/perf_record.sh +++ b/tools/perf/tests/shell/lib/perf_record.sh @@ -24,9 +24,14 @@ perf_record_with_retry() { local duration local first_run=true local ret=1 + local cmd_prefix="perf record" + if [ -n "${PERF_RECORD_CMD}" ]; then + cmd_prefix="${PERF_RECORD_CMD}" + fi + for duration in 0.01 0.1 0.3 1.0 2.0; do rm -f "${perfdata}".old - perf record "$@" -o "${perfdata}" ${testprog_base} ${duration} > "$logfile" 2>&1 + ${cmd_prefix} "$@" -o "${perfdata}" ${testprog_base} ${duration} > "$logfile" 2>&1 local record_exit=$? if [ "$first_run" = true ] && [ $record_exit -ne 0 ]; then diff --git a/tools/perf/tests/shell/trace_record_replay.sh b/tools/perf/tests/shell/trace_record_replay.sh index 88d30a03dcec..38fcafcdfb91 100755 --- a/tools/perf/tests/shell/trace_record_replay.sh +++ b/tools/perf/tests/shell/trace_record_replay.sh @@ -6,16 +6,46 @@ # shellcheck source=lib/probe.sh . "$(dirname $0)"/lib/probe.sh +# shellcheck source=lib/perf_record.sh +. "$(dirname $0)"/lib/perf_record.sh skip_if_no_perf_trace || exit 2 [ "$(id -u)" = 0 ] || exit 2 file=$(mktemp /tmp/temporary_file.XXXXX) +err=0 -perf trace record -o ${file} sleep 1 || exit 1 -if ! perf trace -i ${file} 2>&1 | grep nanosleep; then - echo "Failed: cannot find *nanosleep syscall" +cleanup() { + rm -f ${file} + perf_record_cleanup + trap - EXIT INT TERM +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT INT TERM + +check_nanosleep() { + perf trace -i "${file}" 2>&1 | grep -q nanosleep +} + +PERF_RECORD_CMD="perf trace record" perf_record_with_retry "${file}" "check_nanosleep" "sleep" +err=$? + +if [ $err -ne 0 ]; then + if [ $err -eq 2 ]; then + logfile="${PERF_RECORD_LOGS[${#PERF_RECORD_LOGS[@]}-1]}" + echo "perf trace record failed. Log output:" + cat "$logfile" + else + echo "Failed: cannot find *nanosleep syscall" + fi + cleanup exit 1 fi -rm -f ${file} +cleanup +exit 0 -- cgit v1.2.3 From b02027776ac5bf737f1b76f3759f405e376097e5 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 22 Jun 2026 18:27:53 -0700 Subject: perf tests: Fix flakiness in BPF counters test on hybrid systems The `perf stat --bpf-counters test` fails intermittently on hybrid architectures or systems with dynamic frequency scaling (DVFS). This happens because the test workload (`sqrtloop`) runs for a fixed 1-second duration, and the CPU frequency can scale dynamically between idle and maximum frequency. As the first run runs on a cold CPU and the second run runs on a warmed-up CPU (or vice versa), the number of instructions executed in 1 second differs by up to 2.2x, violating the comparison tolerance. Also, when running as root, BPF tracepoints and scheduling programs trigger frequently. Since standard `perf stat -e instructions` measures both user and kernel space instructions, it counts BPF helper and program execution overheads, whereas the BPF counters themselves do not self- measure. This introduces a large kernel-space instruction count discrepancy between standard and BPF counters. Fix these issues by: 1. Switching the workload to a strictly deterministic, iteration-based workload: `awk 'BEGIN { for (i=0; i<10000000; i++) sum+=i }'`. We pin the workload to a single random allowed CPU using `taskset -c $CPU` via a bash array. 2. Restricting the counted event to user-space only (`instructions:u` or `/u`). 3. Tightening the comparison tolerance from 20% to 15%. These modifications isolate the measurements to user-space instructions of the deterministic loop, which executes a virtually identical number of instructions on both runs (with less than 0.001% variation), eliminating Dynamic Frequency Scaling (DVFS), kernel scheduling noise, and BPF helper self-measurement overheads. Fixes: 2c0cb9f56020 ("perf test: Add a shell test for 'perf stat --bpf-counters' new option") Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/stat_bpf_counters.sh | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/tools/perf/tests/shell/stat_bpf_counters.sh b/tools/perf/tests/shell/stat_bpf_counters.sh index 35463358b273..11de77ee38ad 100755 --- a/tools/perf/tests/shell/stat_bpf_counters.sh +++ b/tools/perf/tests/shell/stat_bpf_counters.sh @@ -4,21 +4,26 @@ set -e -workload="perf test -w sqrtloop" +# Get the first allowed CPU +CPU=$(taskset -c -p $$ | awk -F': ' '{print $2}' | awk -F'[,-]' '{print $1}') +if [ -z "$CPU" ]; then + CPU=0 +fi +workload=(taskset -c "$CPU" awk 'BEGIN { for (i=0; i<10000000; i++) sum+=i }') -# check whether $2 is within +/- 20% of $1 +# check whether $2 is within +/- 15% of $1 compare_number() { first_num=$1 second_num=$2 - # upper bound is first_num * 120% - upper=$(expr $first_num + $first_num / 5 ) - # lower bound is first_num * 80% - lower=$(expr $first_num - $first_num / 5 ) + # upper bound is first_num * 115% + upper=$(expr $first_num + $first_num / 20 \* 3 ) + # lower bound is first_num * 85% + lower=$(expr $first_num - $first_num / 20 \* 3 ) if [ $second_num -gt $upper ] || [ $second_num -lt $lower ]; then - echo "The difference between $first_num and $second_num are greater than 20%." + echo "The difference between $first_num and $second_num are greater than 15%." exit 1 fi } @@ -41,11 +46,12 @@ check_counts() test_bpf_counters() { printf "Testing --bpf-counters " - base_instructions=$(perf stat --no-big-num -e instructions -- $workload 2>&1 | \ + base_instructions=$(perf stat --no-big-num -e instructions:u -- "${workload[@]}" 2>&1 | \ awk -v i=0 -v c=0 '/instructions/ { \ if ($1 != " 0) printf "%.0f", c; else print "&1 | \ + bpf_instructions=$(perf stat --no-big-num --bpf-counters -e instructions:u \ + -- "${workload[@]}" 2>&1 | \ awk -v i=0 -v c=0 '/instructions/ { \ if ($1 != " 0) printf "%.0f", c; else print "&1) + stat_output=$(perf stat --no-big-num \ + -e instructions/name=base_instructions/u,instructions/name=bpf_instructions/bu \ + -- "${workload[@]}" 2>&1) base_instructions=$(echo "$stat_output"| \ awk -v i=0 -v c=0 '/base_instructions/ { \ if ($1 != " Date: Mon, 22 Jun 2026 18:27:54 -0700 Subject: perf tests: Fix flakiness in branch stack sampling tests The branch stack sampling test (test 130) runs short iteration-based workloads to verify syscall, kernel, and trap branch stack sampling. Specifically, `test_syscall()` and `test_kernel_branches()` run `perf bench syscall basic` with loop counts of 8000 and 1000, and `test_trap_eret_branches()` runs `traploop` with 1000 iterations. Because these loop limits are extremely small, the total benchmark runtimes last only a few milliseconds (or less). Under high load, virtualization, or coarse sampling conditions, PMU cycle sampling fails to capture enough samples inside the brief benchmark loops. This leads to false negatives where the script output lacks the expected syscall, kernel, or trap branch entries (e.g. "ERROR: Branches missing getppid[^ ]*/SYSCALL/"). Fix this by increasing the workload loop counts to 100,000 across all three test sections. Running 100,000 loops still finishes virtually instantaneously (less than 0.1 seconds), but generates enough iterations to guarantee robust branch stack capture. Fixes: b55878c90ab9 ("perf test: Add test for branch stack sampling") Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/test_brstack.sh | 107 ++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 41 deletions(-) diff --git a/tools/perf/tests/shell/test_brstack.sh b/tools/perf/tests/shell/test_brstack.sh index eb5837f82e39..71550e0b37ba 100755 --- a/tools/perf/tests/shell/test_brstack.sh +++ b/tools/perf/tests/shell/test_brstack.sh @@ -110,20 +110,29 @@ test_trap_eret_branches() { return fi start_err=$err - err=0 - perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u,k -- \ - perf test -w traploop 1000 > "$TMPDIR/record.txt" 2>&1 - perf script -i $TMPDIR/perf.data --fields brstacksym | \ - tr ' ' '\n' > $TMPDIR/perf.script - - # BRBINF.TYPE == TRAP are mapped to PERF_BR_IRQ by the BRBE driver - check_branches "^trap_bench\+[^ ]+/[^ ]/IRQ/" - check_branches "^[^ ]+/trap_bench\+[^ ]+/ERET/" - if [ $err -eq 0 ]; then + local ret=1 + for loops in 1000 10000 100000; do + err=0 + perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u,k -- \ + perf test -w traploop $loops > "$TMPDIR/record.txt" 2>&1 + perf script -i $TMPDIR/perf.data --fields brstacksym | \ + tr ' ' '\n' > $TMPDIR/perf.script + + # BRBINF.TYPE == TRAP are mapped to PERF_BR_IRQ by the BRBE driver + check_branches "^trap_bench\+[^ ]+/[^ ]/IRQ/" + check_branches "^[^ ]+/trap_bench\+[^ ]+/ERET/" + if [ $err -eq 0 ]; then + ret=0 + break + fi + done + + if [ $ret -eq 0 ]; then echo "Testing trap & eret branches [Passed]" err=$start_err else echo "Testing trap & eret branches [Failed]" + err=1 fi } @@ -135,32 +144,40 @@ test_kernel_branches() { return fi start_err=$err - err=0 - perf record -o $TMPDIR/perf.data --branch-filter any,k -- \ - perf bench syscall basic --loop 1000 > "$TMPDIR/record.txt" 2>&1 - perf script -i $TMPDIR/perf.data --fields brstack | \ - tr ' ' '\n' > $TMPDIR/perf.script - - # Example of branch entries: - # "0xffffffff93bda241/0xffffffff93bda20f/M/-/-/..." - # Source addresses come first in user or kernel code. Next is the target - # address that must be in the kernel. - - # Look for source addresses with top bit set - if ! grep -q -E -m1 "^0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then - echo "Testing kernel branch sampling [Failed kernel branches missing]" - err=1 - fi - # Look for no target addresses without top bit set - if grep -q -E -m1 "^0x[0-9a-f]{0,16}/0x[0-7][0-9a-f]{1,15}/" $TMPDIR/perf.script; then - echo "Testing kernel branch sampling [Failed user branches found]" - err=1 - fi - if [ $err -eq 0 ]; then + local ret=1 + for loops in 1000 10000 100000; do + err=0 + perf record -o $TMPDIR/perf.data --branch-filter any,k -- \ + perf bench syscall basic --loop $loops > "$TMPDIR/record.txt" 2>&1 + perf script -i $TMPDIR/perf.data --fields brstack | \ + tr ' ' '\n' > $TMPDIR/perf.script + + # Example of branch entries: + # "0xffffffff93bda241/0xffffffff93bda20f/M/-/-/..." + # Source addresses come first in user or kernel code. Next is the target + # address that must be in the kernel. + + # Look for source addresses with top bit set + if ! grep -q -E -m1 "^0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then + err=1 + fi + # Look for no target addresses without top bit set + if grep -q -E -m1 "^0x[0-9a-f]{0,16}/0x[0-7][0-9a-f]{1,15}/" \ + $TMPDIR/perf.script; then + err=1 + fi + if [ $err -eq 0 ]; then + ret=0 + break + fi + done + + if [ $ret -eq 0 ]; then echo "Testing kernel branch sampling [Passed]" err=$start_err else echo "Testing kernel branch sampling [Failed]" + err=1 fi } @@ -206,20 +223,28 @@ test_syscall() { return fi start_err=$err - err=0 - perf record -o $TMPDIR/perf.data --branch-filter \ - any_call,save_type,u,k -c 10007 -- \ - perf bench syscall basic --loop 8000 > "$TMPDIR/record.txt" 2>&1 - perf script -i $TMPDIR/perf.data --fields brstacksym | \ - tr ' ' '\n' > $TMPDIR/perf.script - - check_branches "getppid[^ ]*/SYSCALL/" + local ret=1 + for loops in 8000 30000 100000; do + err=0 + perf record -o $TMPDIR/perf.data --branch-filter \ + any_call,save_type,u,k -c 10007 -- \ + perf bench syscall basic --loop $loops > "$TMPDIR/record.txt" 2>&1 + perf script -i $TMPDIR/perf.data --fields brstacksym | \ + tr ' ' '\n' > $TMPDIR/perf.script + + check_branches "getppid[^ ]*/SYSCALL/" + if [ $err -eq 0 ]; then + ret=0 + break + fi + done - if [ $err -eq 0 ]; then + if [ $ret -eq 0 ]; then echo "Testing syscalls [Passed]" err=$start_err else echo "Testing syscalls [Failed]" + err=1 fi } set -e -- cgit v1.2.3 From c10f33fa660ffd10c0254ecd0455c421c59c9f38 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 22 Jun 2026 18:27:55 -0700 Subject: perf tests: Speed up off-cpu profiling tests The off-cpu profiling test suite runs multiple recording commands with a default workload of `sleep 1` to test the off-cpu threshold configurations (specifically, above 999ms and below 1200ms). This adds a mandatory 3.0 seconds of sleep overhead. Optimize this by scaling down the thresholds and workload durations by a factor of 10: - Use `sleep 0.1` as the workload duration. - Change the above-threshold test to use `--off-cpu-thresh 50` and `sleep 0.1`. - Change the below-threshold test to use `--off-cpu-thresh 500` and `sleep 0.1`. - Update the awk period check in the above-threshold test to look for a period greater than 50,000,000 ns (50ms) instead of 999,000,000 ns (999ms). This reduces raw test sleep overhead from 3.0s down to 0.3s, yielding a ~2.7 second speedup for this test. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/record_offcpu.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/perf/tests/shell/record_offcpu.sh b/tools/perf/tests/shell/record_offcpu.sh index 860a2d6f4b75..ee095df47358 100755 --- a/tools/perf/tests/shell/record_offcpu.sh +++ b/tools/perf/tests/shell/record_offcpu.sh @@ -45,7 +45,7 @@ test_offcpu_priv() { test_offcpu_basic() { echo "Basic off-cpu test" - if ! perf record --off-cpu -e dummy -o ${perfdata} sleep 1 2> /dev/null + if ! perf record --off-cpu -e dummy -o ${perfdata} sleep 0.3 2> /dev/null then echo "Basic off-cpu test [Failed record]" err=1 @@ -57,7 +57,7 @@ test_offcpu_basic() { err=1 return fi - if ! perf report -i ${perfdata} -q --percent-limit=90 | grep -E -q sleep + if ! perf report -i ${perfdata} -q --percent-limit=70 | grep -E -q sleep then echo "Basic off-cpu test [Failed missing output]" err=1 @@ -98,8 +98,8 @@ test_offcpu_child() { test_offcpu_above_thresh() { echo "${test_above_thresh}" - # collect direct off-cpu samples for tasks blocked for more than 999ms - if ! perf record -e dummy --off-cpu --off-cpu-thresh 999 -o ${perfdata} -- sleep 1 2> /dev/null + # collect direct off-cpu samples for tasks blocked for more than 50ms + if ! perf record -e dummy --off-cpu --off-cpu-thresh 50 -o ${perfdata} -- sleep 0.1 2> /dev/null then echo "${test_above_thresh} [Failed record]" err=1 @@ -115,7 +115,7 @@ test_offcpu_above_thresh() { fi # there should only be one direct sample, and its period should be higher than off-cpu-thresh if ! perf script --time "0, ${dummy_timestamp}" -i ${perfdata} -F period | \ - awk '{ if (int($1) > 999000000) exit 0; else exit 1; }' + awk '{ if (int($1) > 50000000) exit 0; else exit 1; }' then echo "${test_above_thresh} [Failed off-cpu time too short]" err=1 @@ -128,8 +128,8 @@ test_offcpu_above_thresh() { test_offcpu_below_thresh() { echo "${test_below_thresh}" - # collect direct off-cpu samples for tasks blocked for more than 1.2s - if ! perf record -e dummy --off-cpu --off-cpu-thresh 1200 -o ${perfdata} -- sleep 1 2> /dev/null + # collect direct off-cpu samples for tasks blocked for more than 500ms + if ! perf record -e dummy --off-cpu --off-cpu-thresh 500 -o ${perfdata} -- sleep 0.1 2> /dev/null then echo "${test_below_thresh} [Failed record]" err=1 -- cgit v1.2.3 From ae42a2a2a3aeda1a62527d38d64e3cdfa0e5627c Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 22 Jun 2026 18:27:56 -0700 Subject: perf tests: Speed up lock contention analysis shell test The lock contention analysis test suite (`lock_contention.sh`) performs a series of 13 separate profiling checks to verify various aggregation and filtering parameters of `perf lock contention`. Each of these checks runs the `perf bench sched messaging` messaging benchmark as its workload. By default, `sched messaging` runs 10 groups of 40 processes (400 processes total) generating substantial task scheduling, context switching, and IPC message passing. When traced system-wide for lock events, the tracing overhead (handling millions of lock acquisitions and releases) slows execution down significantly, causing the test suite to take over 80 seconds. Optimize this by introducing a scaled-down messaging benchmark workload: `perf bench sched messaging -g 1 -p`. Running 1 group (40 processes) takes only 0.01 seconds natively (instead of 0.08 seconds), drastically reduces the sheer volume of lock acquire/release trace events, and reduces CPU context switching during tracing while still generating sufficient lock events to fully exercise the BPF/record filters. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/lock_contention.sh | 32 ++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/tools/perf/tests/shell/lock_contention.sh b/tools/perf/tests/shell/lock_contention.sh index 52e8b9db9fbd..ba598370be73 100755 --- a/tools/perf/tests/shell/lock_contention.sh +++ b/tools/perf/tests/shell/lock_contention.sh @@ -9,6 +9,10 @@ perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) result=$(mktemp /tmp/__perf_test.result.XXXXX) errout=$(mktemp /tmp/__perf_test.errout.XXXXX) +# Workload to generate lock contention. +# Using 1 group (-g 1) keeps runtime low while generating sufficient lock events. +msg_workload="perf bench sched messaging -g 1" + cleanup() { rm -f ${perfdata} rm -f ${result} @@ -50,7 +54,7 @@ check() { test_record() { echo "Testing perf lock record and perf lock contention" - perf lock record -o ${perfdata} -- perf bench sched messaging -p > /dev/null 2>&1 + perf lock record -o ${perfdata} -- ${msg_workload} > /dev/null 2>&1 # the output goes to the stderr and we expect only 1 output (-E 1) perf lock contention -i ${perfdata} -E 1 -q 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then @@ -70,7 +74,7 @@ test_bpf() fi # the perf lock contention output goes to the stderr - perf lock con -a -b -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} + perf lock con -a -b -E 1 -q -- ${msg_workload} > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)" err=1 @@ -81,7 +85,7 @@ test_bpf() test_record_concurrent() { echo "Testing perf lock record and perf lock contention at the same time" - perf lock record -o- -- perf bench sched messaging -p 2> ${errout} | \ + perf lock record -o- -- ${msg_workload} 2> ${errout} | \ perf lock contention -i- -E 1 -q 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] Recorded result count is not 1:" "$(cat "${result}" | wc -l)" @@ -107,7 +111,7 @@ test_aggr_task() fi # the perf lock contention output goes to the stderr - perf lock con -a -b -t -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} + perf lock con -a -b -t -E 1 -q -- ${msg_workload} > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)" err=1 @@ -130,7 +134,7 @@ test_aggr_addr() fi # the perf lock contention output goes to the stderr - perf lock con -a -b -l -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} + perf lock con -a -b -l -E 1 -q -- ${msg_workload} > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)" err=1 @@ -148,7 +152,7 @@ test_aggr_cgroup() fi # the perf lock contention output goes to the stderr - perf lock con -a -b --lock-cgroup -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} + perf lock con -a -b --lock-cgroup -E 1 -q -- ${msg_workload} > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)" err=1 @@ -170,7 +174,7 @@ test_type_filter() return fi - perf lock con -a -b -Y spinlock -q -- perf bench sched messaging -p > /dev/null 2> ${result} + perf lock con -a -b -Y spinlock -q -- ${msg_workload} > /dev/null 2> ${result} if [ "$(grep -c -v spinlock "${result}")" != "0" ]; then echo "[Fail] BPF result should not have non-spinlocks:" "$(cat "${result}")" err=1 @@ -202,7 +206,7 @@ test_lock_filter() return fi - perf lock con -a -b -L tasklist_lock -q -- perf bench sched messaging -p > /dev/null 2> ${result} + perf lock con -a -b -L tasklist_lock -q -- ${msg_workload} > /dev/null 2> ${result} if [ "$(grep -c -v "${test_lock_filter_type}" "${result}")" != "0" ]; then echo "[Fail] BPF result should not have non-${test_lock_filter_type} locks:" "$(cat "${result}")" err=1 @@ -241,7 +245,7 @@ test_stack_filter() return fi - perf lock con -a -b -S unix_stream -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} + perf lock con -a -b -S unix_stream -E 1 -q -- ${msg_workload} > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result should have a lock from unix_stream:" "$(cat "${result}")" err=1 @@ -269,7 +273,7 @@ test_aggr_task_stack_filter() return fi - perf lock con -a -b -t -S unix_stream -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} + perf lock con -a -b -t -S unix_stream -E 1 -q -- ${msg_workload} > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result should have a task from unix_stream:" "$(cat "${result}")" err=1 @@ -285,7 +289,8 @@ test_cgroup_filter() return fi - perf lock con -a -b --lock-cgroup -E 1 -F wait_total -q -- perf bench sched messaging -p > /dev/null 2> ${result} + perf lock con -a -b --lock-cgroup -E 1 -F wait_total -q \ + -- ${msg_workload} > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result should have a cgroup result:" "$(cat "${result}")" err=1 @@ -293,7 +298,8 @@ test_cgroup_filter() fi cgroup=$(cat "${result}" | awk '{ print $3 }') - perf lock con -a -b --lock-cgroup -E 1 -G "${cgroup}" -q -- perf bench sched messaging -p > /dev/null 2> ${result} + perf lock con -a -b --lock-cgroup -E 1 -G "${cgroup}" -q \ + -- ${msg_workload} > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result should have a result with cgroup filter:" "$(cat "${cgroup}")" err=1 @@ -328,7 +334,7 @@ test_csv_output() fi # the perf lock contention output goes to the stderr - perf lock con -a -b -E 1 -x , --output ${result} -- perf bench sched messaging -p > /dev/null 2>&1 + perf lock con -a -b -E 1 -x , --output ${result} -- ${msg_workload} > /dev/null 2>&1 output=$(grep -v "^#" ${result} | tr -d -c , | wc -c) if [ "${header}" != "${output}" ]; then echo "[Fail] BPF result does not match the number of commas: ${header} != ${output}" -- cgit v1.2.3 From b02e597450f28c7374afdafd97b15a889a8107da Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 22 Jun 2026 18:27:57 -0700 Subject: perf tests: Speed up metrics checking shell tests Optimize the execution of the metric validation and metric listing shell test suites: 1. `stat_metrics_values.sh`: The Python metric validator runs the `perf bench futex hash` workload for each validated metric relationship. Reduce the benchmark runtime limit from `-r 2` (2 seconds) to `-r 1` (1 second). This cuts the workload duration in half while still generating sufficient PMU events to satisfy non-zero threshold metric validations. 2. `stat_all_metrics.sh`: The metric checking test runs `perf stat` sequentially across all 433+ listed metrics. Change the default workload for system-wide runs from `sleep 0.01` to `true`. This avoids the 10ms sleep delay on each sequential metric invocation, saving over 4 seconds of total wall time during full test suite runs. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/stat_all_metrics.sh | 2 +- tools/perf/tests/shell/stat_metrics_values.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/tests/shell/stat_all_metrics.sh b/tools/perf/tests/shell/stat_all_metrics.sh index feeb34c6fa6d..df5fa27b21ae 100755 --- a/tools/perf/tests/shell/stat_all_metrics.sh +++ b/tools/perf/tests/shell/stat_all_metrics.sh @@ -7,7 +7,7 @@ ParanoidAndNotRoot() [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] } -test_prog="sleep 0.01" +test_prog="true" system_wide_flag="-a" if ParanoidAndNotRoot 0 then diff --git a/tools/perf/tests/shell/stat_metrics_values.sh b/tools/perf/tests/shell/stat_metrics_values.sh index 76f1e99d1273..86c5c7f70933 100755 --- a/tools/perf/tests/shell/stat_metrics_values.sh +++ b/tools/perf/tests/shell/stat_metrics_values.sh @@ -18,7 +18,7 @@ fi pythonvalidator=$(dirname $0)/lib/perf_metric_validation.py rulefile=$(dirname $0)/lib/perf_metric_validation_rules.json tmpdir=$(mktemp -d /tmp/__perf_test.program.XXXXX) -workload="perf bench futex hash -r 2 -s" +workload="perf bench futex hash -r 1 -s" # Add -debug, save data file and full rule file echo "Launch python validation script $pythonvalidator" -- cgit v1.2.3 From f6e5090f63b0a9f4c4c42c82348ade4132495ee7 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 22 Jun 2026 18:27:58 -0700 Subject: perf tests: Include error output for skipped tests in JUnit XML The JUnit XML output correctly captures the stderr/stdout output of failed tests inside the element. However, for skipped tests, the output was completely discarded and the XML only received a self-closing tag. This expands the element to include the test's err_output when available, which is extremely helpful for debugging why a test was skipped (e.g. diagnosing missing prerequisites or unexpected environment states that triggered the skip) directly from CI systems parsing the XML report. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/tests/builtin-test.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 8b8f63f706d9..d115a19e5f0f 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -536,8 +536,14 @@ static int print_test_result(struct test_suite *t, int curr_suite, int curr_test const char *reason = skip_reason(t, curr_test_case); char *escaped_reason = xml_escape(reason ? reason : "Skip"); - strbuf_addf(&junit_xml_buf, " \n", - escaped_reason); + if (err_output && *err_output) { + strbuf_addf(&junit_xml_buf, + " \n%s\n \n", + escaped_reason, escaped_err); + } else { + strbuf_addf(&junit_xml_buf, " \n", + escaped_reason); + } free(escaped_reason); } strbuf_addstr(&junit_xml_buf, " \n"); -- cgit v1.2.3 From e1065ed188cfe1327863e03143db65425b399210 Mon Sep 17 00:00:00 2001 From: Trevor Allison Date: Fri, 26 Jun 2026 14:27:39 -0400 Subject: perf build: Add LDFLAGS to dlfilters .so link Build-time linker flags were not applied when linking dlfilters. Pass LDFLAGS for consistency with the other link rules. Signed-off-by: Trevor Allison Signed-off-by: Namhyung Kim --- tools/perf/Makefile.perf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 3f0544d37a7f..2b53d9e0c73b 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -680,7 +680,7 @@ $(OUTPUT)dlfilters/%.o: dlfilters/%.c include/perf/perf_dlfilter.h .SECONDARY: $(DLFILTERS:.so=.o) $(OUTPUT)dlfilters/%.so: $(OUTPUT)dlfilters/%.o - $(QUIET_LINK)$(CC) $(EXTRA_CFLAGS) -shared -o $@ $< + $(QUIET_LINK)$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -shared -o $@ $< ifndef NO_JVMTI LIBJVMTI_IN := $(OUTPUT)jvmti/jvmti-in.o -- cgit v1.2.3 From 5a9dd835894cffed85d56aaedc1950bf858ff510 Mon Sep 17 00:00:00 2001 From: Joe Lawrence Date: Fri, 26 Jun 2026 17:21:39 -0400 Subject: perf symbols: skip livepatch symbols when loading kallsyms Livepatch modules contain special symbols (prefixed by ".klp.sym.") that act as relocation placeholders. Once resolved, they point to the same addresses as the original kernel symbols they reference. [1] These special symbols confuse the 'vmlinux symtab matches kallsyms' perf test as kallsyms may report multiple symbols sharing a single kernel address. For example: kallsyms (without livepatch) ---------------------------- ffffffff81a41110 T __pfx_arch_release_task_struct > ffffffff81a41120 T arch_release_task_struct ffffffff81a41140 T __pfx_exit_thread ffffffff81a41150 T exit_thread kallsyms (with livepatch loaded) --------------------------------- ffffffff81a41110 T __pfx_arch_release_task_struct > ffffffff81a41120 T arch_release_task_struct ffffffff81a41140 T __pfx_exit_thread ffffffff81a41150 T exit_thread > ffffffff81a41120 w .klp.sym.vmlinux.arch_release_task_struct,0 [kpatch_5_14_0_570_94_1_1_3] When perf loads kallsyms, both symbols are inserted into the symbol table at the same address, corrupting symbol end-address calculations and causing test failures. Filter out symbols prefixed with ".klp.sym." when loading kallsyms, as they alias existing kernel symbols. Link: https://docs.kernel.org/livepatch/module-elf-format.html#livepatch-symbols [1] Reported-and-tested-by: Signed-off-by: Joe Lawrence Acked-by: Petr Mladek Signed-off-by: Namhyung Kim --- tools/perf/util/symbol.c | 4 ++-- tools/perf/util/symbol.h | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index cd379ced19e5..a562702b4841 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -880,8 +880,8 @@ static int map__process_kallsym_symbol(void *arg, const char *name, if (!symbol_type__filter(type)) return 0; - /* Ignore mapping symbols in kallsyms */ - if (is_ignored_kernel_symbol(name)) + /* Ignore mapping and livepatch symbols in kallsyms */ + if (is_ignored_kernel_symbol(name) || is_livepatch_symbol(name)) return 0; /* diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index a71525335703..d0bac824c79c 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -8,7 +8,9 @@ #include #include #include +#include #include +#include #include #include #include "addr_location.h" @@ -45,6 +47,16 @@ static inline bool is_ignored_kernel_symbol(const char *str) return str[0] == '$'; } +/* + * Livepatch symbols (.klp.sym.*) are relocation placeholders whose resolved + * addresses alias existing kernel symbols. They carry a [module] tag which + * confuses module boundary tracking and symbol table lookups. + */ +static inline bool is_livepatch_symbol(const char *str) +{ + return strstarts(str, KLP_SYM_PREFIX); +} + /* * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; * for newer versions we can use mmap to reduce memory usage: -- cgit v1.2.3 From 55caa653014d50a3e10b5dbc282c641cfce5c9f2 Mon Sep 17 00:00:00 2001 From: Joe Lawrence Date: Fri, 26 Jun 2026 17:21:40 -0400 Subject: perf symbols: skip livepatch symbols in kcore_copy kallsyms processing Livepatch symbols (.klp.sym.*) carry a [module] tag but resolve to core kernel text addresses. When kcore_copy__process_kallsyms() encounters these symbols, they are treated as module symbols, pulling the first_module_symbol down to a kernel text address. This corrupts the module memory range used to build the kcore PT_LOAD segments. For example, with a kpatch module containing a ".klp.sym.vmlinux.arch_release_task_struct,0" livepatch symbol loaded: kernel symbols ... ffffffffb4a41120 arch_release_task_struct ... ^ ... | aliased by .klp.sym ... | drags first_module_symbol here | (43M gap) | bloated kcore segment | module symbols | ffffffffc047b000 <-- correct first_module_symbol ... ... This causes the module PT_LOAD segment to start at the .klp.sym address and not the real first module address, bloating the kcore copy: Baseline (no livepatch): VirtAddr ffffffffc047b000, 8.5M Bloated (with livepatch): VirtAddr ffffffffb4a41000, 54M Post-fix (with livepatch): VirtAddr ffffffffc047b000, 8.9M Filter livepatch symbols early in kcore_copy__process_kallsyms() before they can affect module boundary tracking. Reported-by: Sashiko Link: https://sashiko.dev/#/patchset/20260624201254.472576-1-joe.lawrence@redhat.com?part=1 Signed-off-by: Joe Lawrence Acked-by: Petr Mladek Signed-off-by: Namhyung Kim --- tools/perf/util/symbol-elf.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 39562bdec8b9..f6f6b54da131 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -2216,6 +2216,10 @@ static int kcore_copy__process_kallsyms(void *arg, const char *name, char type, if (!kallsyms__is_function(type)) return 0; + /* Ignore livepatch symbols */ + if (is_livepatch_symbol(name)) + return 0; + if (strchr(name, '[')) { if (!kci->first_module_symbol || start < kci->first_module_symbol) kci->first_module_symbol = start; -- cgit v1.2.3 From d12a0135e8e87c04dce78060c9d0899233f7d80e Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 1 Jul 2026 12:41:48 -0700 Subject: perf kvm: Factor out kvm_need_default_arch_event() The kvm_add_default_arch_event() has a similar logic in each arch to check if there's an existing command line option for events. Let's check it in the generic code and remove the duplication. Tested-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/builtin-kvm.c | 17 ++++++---- tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c | 31 +++--------------- tools/perf/util/kvm-stat-arch/kvm-stat-x86.c | 34 +++----------------- tools/perf/util/kvm-stat.c | 41 ++++++++++++++++++++++++ tools/perf/util/kvm-stat.h | 8 +++++ 5 files changed, 70 insertions(+), 61 deletions(-) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 2c6aef1e13a0..2f00cc1fd1c7 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -2014,9 +2015,11 @@ static int __cmd_record(const char *file_name, int argc, const char **argv) BUG_ON(i + 2 != rec_argc); - ret = kvm_add_default_arch_event(EM_HOST, &i, rec_argv); - if (ret) - goto EXIT; + if (kvm_need_default_arch_event(EM_HOST, argc, argv)) { + ret = kvm_add_default_arch_event(EM_HOST, &i, rec_argv); + if (ret) + goto EXIT; + } ret = cmd_record(i, rec_argv); @@ -2101,9 +2104,11 @@ static int __cmd_top(int argc, const char **argv) BUG_ON(i != argc); - ret = kvm_add_default_arch_event(EM_HOST, &i, rec_argv); - if (ret) - goto EXIT; + if (kvm_need_default_arch_event(EM_HOST, argc, argv)) { + ret = kvm_add_default_arch_event(EM_HOST, &i, rec_argv); + if (ret) + goto EXIT; + } ret = cmd_top(i, rec_argv); diff --git a/tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c b/tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c index 96d9c4ae0209..8d4133c35c12 100644 --- a/tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c +++ b/tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c @@ -9,7 +9,6 @@ #include "book3s_hv_exits.h" #include "book3s_hcalls.h" -#include #define NR_TPS 4 @@ -177,35 +176,15 @@ int __cpu_isa_init_powerpc(struct perf_kvm_stat *kvm) */ int __kvm_add_default_arch_event_powerpc(int *argc, const char **argv) { - const char **tmp; - bool event = false; - int i, j = *argc; + int j = *argc; - const struct option event_options[] = { - OPT_BOOLEAN('e', "event", &event, NULL), - OPT_END() - }; - - tmp = calloc(j + 1, sizeof(char *)); - if (!tmp) + if (!perf_pmus__have_event("trace_imc", "trace_cycles")) return -EINVAL; - for (i = 0; i < j; i++) - tmp[i] = argv[i]; - - parse_options(j, tmp, event_options, NULL, PARSE_OPT_KEEP_UNKNOWN); - if (!event) { - if (perf_pmus__have_event("trace_imc", "trace_cycles")) { - argv[j++] = strdup("-e"); - argv[j++] = strdup("trace_imc/trace_cycles/"); - *argc += 2; - } else { - free(tmp); - return -EINVAL; - } - } + argv[j++] = strdup("-e"); + argv[j++] = strdup("trace_imc/trace_cycles/"); + *argc += 2; - free(tmp); return 0; } diff --git a/tools/perf/util/kvm-stat-arch/kvm-stat-x86.c b/tools/perf/util/kvm-stat-arch/kvm-stat-x86.c index 788d216f0852..46f9a0adcb60 100644 --- a/tools/perf/util/kvm-stat-arch/kvm-stat-x86.c +++ b/tools/perf/util/kvm-stat-arch/kvm-stat-x86.c @@ -7,7 +7,6 @@ #include "../../../arch/x86/include/uapi/asm/svm.h" #include "../../../arch/x86/include/uapi/asm/vmx.h" #include "../../../arch/x86/include/uapi/asm/kvm.h" -#include define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS); define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS); @@ -211,38 +210,15 @@ int __cpu_isa_init_x86(struct perf_kvm_stat *kvm, const char *cpuid) */ int __kvm_add_default_arch_event_x86(int *argc, const char **argv) { - const char **tmp; - bool event = false; - int ret = 0, i, j = *argc; - - const struct option event_options[] = { - OPT_BOOLEAN('e', "event", &event, NULL), - OPT_BOOLEAN(0, "pfm-events", &event, NULL), - OPT_END() - }; - - if (!x86__is_intel_cpu()) - return 0; - - tmp = calloc(j + 1, sizeof(char *)); - if (!tmp) - return -ENOMEM; - - for (i = 0; i < j; i++) - tmp[i] = argv[i]; - - parse_options(j, tmp, event_options, NULL, PARSE_OPT_KEEP_UNKNOWN); - if (!event) { - argv[j++] = STRDUP_FAIL_EXIT("-e"); - argv[j++] = STRDUP_FAIL_EXIT("cycles"); - *argc += 2; - } + int ret = 0, j = *argc; + + argv[j++] = STRDUP_FAIL_EXIT("-e"); + argv[j++] = STRDUP_FAIL_EXIT("cycles"); + *argc += 2; - free(tmp); return 0; EXIT: - free(tmp); return ret; } diff --git a/tools/perf/util/kvm-stat.c b/tools/perf/util/kvm-stat.c index 755ab659a05c..c571d2ed711a 100644 --- a/tools/perf/util/kvm-stat.c +++ b/tools/perf/util/kvm-stat.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 #include "debug.h" +#include "env.h" #include "evsel.h" #include "kvm-stat.h" #include +#include bool kvm_exit_event(struct evsel *evsel) { @@ -268,3 +270,42 @@ int kvm_add_default_arch_event(uint16_t e_machine, int *argc, const char **argv) return 0; } } + +bool kvm_need_default_arch_event(uint16_t e_machine, int argc, const char **argv) +{ + const char **tmp_argv; + bool event = false; + int i; + + const struct option event_options[] = { + OPT_BOOLEAN('e', "event", &event, NULL), + OPT_BOOLEAN(0, "pfm-events", &event, NULL), + OPT_END() + }; + + switch (e_machine) { + case EM_PPC: + case EM_PPC64: + break; + case EM_X86_64: + case EM_386: + if (!x86__is_intel_cpu()) + return false; + break; + default: + return false; + } + + /* parse_options() may change the argv, let's make a copy */ + tmp_argv = calloc(argc + 1, sizeof(char *)); + if (!tmp_argv) + return false; + + for (i = 0; i < argc; i++) + tmp_argv[i] = argv[i]; + + parse_options(argc, tmp_argv, event_options, NULL, PARSE_OPT_KEEP_UNKNOWN); + free(tmp_argv); + + return !event; +} diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h index cdbd921a555f..04f9f3193555 100644 --- a/tools/perf/util/kvm-stat.h +++ b/tools/perf/util/kvm-stat.h @@ -174,12 +174,20 @@ const char * const *__kvm_skip_events_riscv(void); const char * const *__kvm_skip_events_s390(void); const char * const *__kvm_skip_events_x86(void); +bool kvm_need_default_arch_event(uint16_t e_machine, int argc, const char **argv); int kvm_add_default_arch_event(uint16_t e_machine, int *argc, const char **argv); int __kvm_add_default_arch_event_powerpc(int *argc, const char **argv); int __kvm_add_default_arch_event_x86(int *argc, const char **argv); #else /* !HAVE_LIBTRACEEVENT */ +static inline bool kvm_need_default_arch_event(uint16_t e_machine __maybe_unused, + int argc __maybe_unused, + const char **argv __maybe_unused) +{ + return false; +} + static inline int kvm_add_default_arch_event(uint16_t e_machine __maybe_unused, int *argc __maybe_unused, const char **argv __maybe_unused) -- cgit v1.2.3 From 95e63238386524e231fcd100b9e6db22053fd4ff Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 1 Jul 2026 12:41:49 -0700 Subject: perf kvm: Check kvm_need_default_arch_event() early There's a subtle issue with option parsing in perf record. It calls the function with PARSE_OPT_STOP_AT_NON_OPTION so that it can pass later options to the external command it runs. But perf kvm record passes the default arch events after the argv. So if user calls it with command, then it passes the event to the external command and fails it like below: $ sudo perf kvm --host record sleep 1 sleep: invalid option -- 'e' Try 'sleep --help' for more information. [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.046 MB perf.data.kvm (5 samples) ] We can check if the default options are needed before passing the extra command line to make sure it's passed to perf record. Tested-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/builtin-kvm.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 2f00cc1fd1c7..24576e4ebb02 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1996,13 +1996,14 @@ static int __cmd_record(const char *file_name, int argc, const char **argv) { int rec_argc, i = 0, j, ret; const char **rec_argv; + int need_arch_event = !!kvm_need_default_arch_event(EM_HOST, argc, argv); /* * Besides the 2 more options "-o" and "filename", * kvm_add_default_arch_event() may add 2 extra options, - * so allocate 4 more items. + * so allocate more items conditionally. */ - rec_argc = argc + 2 + 2; + rec_argc = argc + 2 + (2 * need_arch_event); rec_argv = calloc(rec_argc + 1, sizeof(char *)); if (!rec_argv) return -ENOMEM; @@ -2010,22 +2011,22 @@ static int __cmd_record(const char *file_name, int argc, const char **argv) rec_argv[i++] = STRDUP_FAIL_EXIT("record"); rec_argv[i++] = STRDUP_FAIL_EXIT("-o"); rec_argv[i++] = STRDUP_FAIL_EXIT(file_name); - for (j = 1; j < argc; j++, i++) - rec_argv[i] = STRDUP_FAIL_EXIT(argv[j]); - - BUG_ON(i + 2 != rec_argc); - - if (kvm_need_default_arch_event(EM_HOST, argc, argv)) { + if (need_arch_event) { ret = kvm_add_default_arch_event(EM_HOST, &i, rec_argv); if (ret) goto EXIT; } + for (j = 1; j < argc; j++, i++) + rec_argv[i] = STRDUP_FAIL_EXIT(argv[j]); + + BUG_ON(i != rec_argc); + ret = cmd_record(i, rec_argv); EXIT: - for (i = 0; i < rec_argc; i++) - free((void *)rec_argv[i]); + for (j = 0; j < i; j++) + free((void *)rec_argv[j]); free(rec_argv); return ret; } -- cgit v1.2.3 From cd589eba99f4578a6cf495fa23d02c28fc129ec1 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 1 Jul 2026 12:41:50 -0700 Subject: perf kvm: Kill STRDUP_FAIL_EXIT() It's used to pass command line options to a copied argv. But there's no reason to make the copies as it's all used in the same function. It can simply use stack variables. In fact, it fixes a subtle double free issue. As parse_options() can move contents in argv[], some entries may point to the same item. So freeing all items in the argv could trigger a double free. With stack variables, we don't need to allocate and free them. Tested-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/builtin-kvm.c | 54 +++++++++--------------- tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c | 4 +- tools/perf/util/kvm-stat-arch/kvm-stat-x86.c | 9 ++-- tools/perf/util/kvm-stat.h | 10 ----- 4 files changed, 24 insertions(+), 53 deletions(-) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 24576e4ebb02..eaf9297cc34d 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1682,18 +1682,18 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(record_args); i++) - rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); + rec_argv[i] = record_args[i]; for (j = 0; j < events_tp_size; j++) { - rec_argv[i++] = STRDUP_FAIL_EXIT("-e"); - rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp(e_machine)[j]); + rec_argv[i++] = "-e"; + rec_argv[i++] = kvm_events_tp(e_machine)[j]; } - rec_argv[i++] = STRDUP_FAIL_EXIT("-o"); - rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name); + rec_argv[i++] = "-o"; + rec_argv[i++] = kvm->file_name; for (j = 1; j < (unsigned int)argc; j++, i++) - rec_argv[i] = STRDUP_FAIL_EXIT(argv[j]); + rec_argv[i] = argv[j]; set_option_flag(record_options, 'e', "event", PARSE_OPT_HIDDEN); set_option_flag(record_options, 0, "filter", PARSE_OPT_HIDDEN); @@ -1717,10 +1717,6 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) record_usage = kvm_stat_record_usage; ret = cmd_record(i, rec_argv); - -EXIT: - for (i = 0; i < rec_argc; i++) - free((void *)rec_argv[i]); free(rec_argv); return ret; } @@ -2008,9 +2004,9 @@ static int __cmd_record(const char *file_name, int argc, const char **argv) if (!rec_argv) return -ENOMEM; - rec_argv[i++] = STRDUP_FAIL_EXIT("record"); - rec_argv[i++] = STRDUP_FAIL_EXIT("-o"); - rec_argv[i++] = STRDUP_FAIL_EXIT(file_name); + rec_argv[i++] = "record"; + rec_argv[i++] = "-o"; + rec_argv[i++] = file_name; if (need_arch_event) { ret = kvm_add_default_arch_event(EM_HOST, &i, rec_argv); if (ret) @@ -2018,15 +2014,13 @@ static int __cmd_record(const char *file_name, int argc, const char **argv) } for (j = 1; j < argc; j++, i++) - rec_argv[i] = STRDUP_FAIL_EXIT(argv[j]); + rec_argv[i] = argv[j]; BUG_ON(i != rec_argc); ret = cmd_record(i, rec_argv); EXIT: - for (j = 0; j < i; j++) - free((void *)rec_argv[j]); free(rec_argv); return ret; } @@ -2041,19 +2035,15 @@ static int __cmd_report(const char *file_name, int argc, const char **argv) if (!rec_argv) return -ENOMEM; - rec_argv[i++] = STRDUP_FAIL_EXIT("report"); - rec_argv[i++] = STRDUP_FAIL_EXIT("-i"); - rec_argv[i++] = STRDUP_FAIL_EXIT(file_name); + rec_argv[i++] = "report"; + rec_argv[i++] = "-i"; + rec_argv[i++] = file_name; for (j = 1; j < argc; j++, i++) - rec_argv[i] = STRDUP_FAIL_EXIT(argv[j]); + rec_argv[i] = argv[j]; BUG_ON(i != rec_argc); ret = cmd_report(i, rec_argv); - -EXIT: - for (i = 0; i < rec_argc; i++) - free((void *)rec_argv[i]); free(rec_argv); return ret; } @@ -2069,19 +2059,15 @@ __cmd_buildid_list(const char *file_name, int argc, const char **argv) if (!rec_argv) return -ENOMEM; - rec_argv[i++] = STRDUP_FAIL_EXIT("buildid-list"); - rec_argv[i++] = STRDUP_FAIL_EXIT("-i"); - rec_argv[i++] = STRDUP_FAIL_EXIT(file_name); + rec_argv[i++] = "buildid-list"; + rec_argv[i++] = "-i"; + rec_argv[i++] = file_name; for (j = 1; j < argc; j++, i++) - rec_argv[i] = STRDUP_FAIL_EXIT(argv[j]); + rec_argv[i] = argv[j]; BUG_ON(i != rec_argc); ret = cmd_buildid_list(i, rec_argv); - -EXIT: - for (i = 0; i < rec_argc; i++) - free((void *)rec_argv[i]); free(rec_argv); return ret; } @@ -2101,7 +2087,7 @@ static int __cmd_top(int argc, const char **argv) return -ENOMEM; for (i = 0; i < argc; i++) - rec_argv[i] = STRDUP_FAIL_EXIT(argv[i]); + rec_argv[i] = argv[i]; BUG_ON(i != argc); @@ -2114,8 +2100,6 @@ static int __cmd_top(int argc, const char **argv) ret = cmd_top(i, rec_argv); EXIT: - for (i = 0; i < rec_argc; i++) - free((void *)rec_argv[i]); free(rec_argv); return ret; } diff --git a/tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c b/tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c index 8d4133c35c12..315b24f9a592 100644 --- a/tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c +++ b/tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c @@ -181,8 +181,8 @@ int __kvm_add_default_arch_event_powerpc(int *argc, const char **argv) if (!perf_pmus__have_event("trace_imc", "trace_cycles")) return -EINVAL; - argv[j++] = strdup("-e"); - argv[j++] = strdup("trace_imc/trace_cycles/"); + argv[j++] = "-e"; + argv[j++] = "trace_imc/trace_cycles/"; *argc += 2; return 0; diff --git a/tools/perf/util/kvm-stat-arch/kvm-stat-x86.c b/tools/perf/util/kvm-stat-arch/kvm-stat-x86.c index 46f9a0adcb60..97041f5100fc 100644 --- a/tools/perf/util/kvm-stat-arch/kvm-stat-x86.c +++ b/tools/perf/util/kvm-stat-arch/kvm-stat-x86.c @@ -210,16 +210,13 @@ int __cpu_isa_init_x86(struct perf_kvm_stat *kvm, const char *cpuid) */ int __kvm_add_default_arch_event_x86(int *argc, const char **argv) { - int ret = 0, j = *argc; + int j = *argc; - argv[j++] = STRDUP_FAIL_EXIT("-e"); - argv[j++] = STRDUP_FAIL_EXIT("cycles"); + argv[j++] = "-e"; + argv[j++] = "cycles"; *argc += 2; return 0; - -EXIT: - return ret; } const char * const *__kvm_events_tp_x86(void) diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h index 04f9f3193555..1db31c075187 100644 --- a/tools/perf/util/kvm-stat.h +++ b/tools/perf/util/kvm-stat.h @@ -229,14 +229,4 @@ static inline struct kvm_info *kvm_info__new(void) return ki; } -#define STRDUP_FAIL_EXIT(s) \ - ({ char *_p; \ - _p = strdup(s); \ - if (!_p) { \ - ret = -ENOMEM; \ - goto EXIT; \ - } \ - _p; \ - }) - #endif /* __PERF_KVM_STAT_H */ -- cgit v1.2.3 From 5169bd7647e612a0c93c8f52140565a0388856b1 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 1 Jul 2026 12:41:51 -0700 Subject: perf kvm: Do not copy filename string As it removed STRDUP_FAIL_EXIT(), it no longer calls free() for elements in the copied argv. Thus, the filename should not be allocated as well. In fact, it's a pointer to string literals and should be fine to pass the pointer. Tested-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/builtin-kvm.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index eaf9297cc34d..20ea59e59a4b 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -607,11 +607,11 @@ static const char *get_filename_for_perf_kvm(void) const char *filename; if (perf_host && !perf_guest) - filename = strdup("perf.data.host"); + filename = "perf.data.host"; else if (!perf_host && perf_guest) - filename = strdup("perf.data.guest"); + filename = "perf.data.guest"; else - filename = strdup("perf.data.kvm"); + filename = "perf.data.kvm"; return filename; } @@ -2148,15 +2148,9 @@ int cmd_kvm(int argc, const char **argv) if (!perf_host) perf_guest = 1; - if (!file_name) { + if (!file_name) file_name = get_filename_for_perf_kvm(); - if (!file_name) { - pr_err("Failed to allocate memory for filename\n"); - return -ENOMEM; - } - } - if (strlen(argv[0]) > 2 && strstarts("record", argv[0])) return __cmd_record(file_name, argc, argv); else if (strlen(argv[0]) > 2 && strstarts("report", argv[0])) -- cgit v1.2.3 From ab42c7b94339bb913be467cef61e6fb8f36f24a2 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 1 Jul 2026 12:41:52 -0700 Subject: perf kvm: Fix a memory leak in the usage string The first element of the kvm_usage string is allocated dynamically by parse_options_subcommand() if it's NULL. Callers should free it after use. Tested-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/builtin-kvm.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 20ea59e59a4b..00baafb05603 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -2135,6 +2135,7 @@ int cmd_kvm(int argc, const char **argv) const char *const kvm_subcommands[] = { "top", "record", "report", "diff", "buildid-list", "stat", NULL }; const char *kvm_usage[] = { NULL, NULL }; + int ret; exclude_GH_default = true; perf_host = 0; @@ -2152,18 +2153,18 @@ int cmd_kvm(int argc, const char **argv) file_name = get_filename_for_perf_kvm(); if (strlen(argv[0]) > 2 && strstarts("record", argv[0])) - return __cmd_record(file_name, argc, argv); + ret = __cmd_record(file_name, argc, argv); else if (strlen(argv[0]) > 2 && strstarts("report", argv[0])) - return __cmd_report(file_name, argc, argv); + ret = __cmd_report(file_name, argc, argv); else if (strlen(argv[0]) > 2 && strstarts("diff", argv[0])) - return cmd_diff(argc, argv); + ret = cmd_diff(argc, argv); else if (!strcmp(argv[0], "top")) - return __cmd_top(argc, argv); + ret = __cmd_top(argc, argv); else if (strlen(argv[0]) > 2 && strstarts("buildid-list", argv[0])) - return __cmd_buildid_list(file_name, argc, argv); + ret = __cmd_buildid_list(file_name, argc, argv); #if defined(HAVE_LIBTRACEEVENT) else if (strlen(argv[0]) > 2 && strstarts("stat", argv[0])) - return kvm_cmd_stat(file_name, argc, argv); + ret = kvm_cmd_stat(file_name, argc, argv); #endif else usage_with_options(kvm_usage, kvm_options); @@ -2171,5 +2172,5 @@ int cmd_kvm(int argc, const char **argv) /* free usage string allocated by parse_options_subcommand */ free((void *)kvm_usage[0]); - return 0; + return ret; } -- cgit v1.2.3 From 3ec1248747e40261264ce0afe4b7bd0ff6822115 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 1 Jul 2026 12:41:53 -0700 Subject: perf test: Extend perf kvm tests to check default event It can now pass command line arguments to perf kvm record. Let's pass 'sleep 1' directly and see it doesn't fail. $ sudo perf test -vv kvm 96: perf kvm tests: ---- start ---- test child forked, pid 3686726 Starting qemu-system-x86_64... Testing perf kvm stat Recording kvm events for pid 3686746 (duration 1s)... perf kvm stat test [Success] Testing perf kvm record/report Recording kvm profile for pid 3686746 (duration 1s)... [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.576 MB /tmp/__perf_kvm_test.perf.data.0HgX6 (4009 samples) ] perf kvm record/report test [Success] Testing perf kvm buildid-list perf kvm buildid-list test [Success] Testing perf kvm stat live perf kvm stat live test [Success] Testing perf kvm record default event with command line [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.000 MB /dev/null ] perf kvm record default event [Success] ---- end(0) ---- 96: perf kvm tests : Ok === Test Summary === Passed main tests : 1 Passed subtests : 0 Skipped tests : 0 Failed tests : 0 Tested-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/kvm.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/perf/tests/shell/kvm.sh b/tools/perf/tests/shell/kvm.sh index a5396f8e6fe5..7b26368051ff 100755 --- a/tools/perf/tests/shell/kvm.sh +++ b/tools/perf/tests/shell/kvm.sh @@ -138,6 +138,15 @@ test_kvm_stat_live() { echo "perf kvm stat live test [Success]" } +test_kvm_default_event() { + echo "Testing perf kvm record default event with command line" + + # Check if kvm record with default events handle command line arguments + perf kvm record -p "${qemu_pid}" -o /dev/null sleep 1 + + echo "perf kvm record default event [Success]" +} + setup_qemu() { # Find qemu if [ "$(uname -m)" = "x86_64" ]; then @@ -191,6 +200,7 @@ if [ $err -eq 0 ]; then test_kvm_record_report test_kvm_buildid_list test_kvm_stat_live + test_kvm_default_event fi cleanup -- cgit v1.2.3 From 50cd0d54f1f6dd9b3de7c0ad101bd41d06206ace Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 2 Jul 2026 20:51:36 +0100 Subject: perf cs-etm: Fix thread leaks on trace queue init failure cs_etm__init_traceid_queue() allocates the frontend and decode threads, if a later allocation fails, the error path does not drop thread reference that was already acquired. Release both thread pointers with thread__zput() on the error path, so does not leak thread references or leave stale pointers behind. Fixes: 951ccccdc715 ("perf cs-etm: Only track threads instead of PID and TIDs") Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Namhyung Kim --- tools/perf/util/cs-etm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 2284cda78abe..deca07d57282 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -645,6 +645,8 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq, queue->tid); tidq->decode_thread = machine__findnew_thread(&etm->session->machines.host, -1, queue->tid); + if (!tidq->frontend_thread || !tidq->decode_thread) + goto out; tidq->packet = zalloc(sizeof(struct cs_etm_packet)); if (!tidq->packet) @@ -679,6 +681,8 @@ out_free: zfree(&tidq->prev_packet); zfree(&tidq->packet); out: + thread__zput(tidq->frontend_thread); + thread__zput(tidq->decode_thread); return rc; } -- cgit v1.2.3 From a9e99b860fb6dfdc9a17d7c63b84fd5647f1f44c Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 2 Jul 2026 20:51:37 +0100 Subject: perf cs-etm: Filter synthesized branch samples The itrace 'c' and 'r' options request synthesized branch events for calls and returns only. For perf script the default itrace options are "--itrace=ce", so CS ETM should emit call branches and error events by default. CS ETM currently synthesizes a branch sample for every decoded taken branch whenever branch synthesis is enabled. This produces redundant jump and conditional branch samples. Add a branch filter derived from the itrace calls and returns options. When neither option is set, keep the existing behavior and synthesize all branch samples. When calls or returns are requested, emit only branch samples whose flags match the selected branch type, while preserving trace begin/end markers. Also update test_arm_coresight_disasm.sh and arm-cs-trace-disasm.py to use the --itrace=b option for generating branch samples. Before: perf script -F,+flags callchain_test 6114 [005] 331519.825214: 1 branches: tr strt jmp 0 [unknown] ([unknown]) => ffff8000803a3a68 perf_report_aux_output_id+0x50 ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: call ffff8000803a3a74 perf_report_aux_output_id+0x5c ([kernel.kallsyms]) => ffff8000817f4d88 memset+0x0 ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: jmp ffff8000817f4d8c memset+0x4 ([kernel.kallsyms]) => ffff8000817f4c00 __pi_memset_generic+0x0 ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000817f4c1c __pi_memset_generic+0x1c ([kernel.kallsyms]) => ffff8000817f4c44 __pi_memset_generic+0x44 ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000817f4c4c __pi_memset_generic+0x4c ([kernel.kallsyms]) => ffff8000817f4c5c __pi_memset_generic+0x5c ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000817f4c5c __pi_memset_generic+0x5c ([kernel.kallsyms]) => ffff8000817f4cf0 __pi_memset_generic+0xf0 ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000817f4d30 __pi_memset_generic+0x130 ([kernel.kallsyms]) => ffff8000817f4d68 __pi_memset_generic+0x168 ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000817f4d78 __pi_memset_generic+0x178 ([kernel.kallsyms]) => ffff8000817f4d6c __pi_memset_generic+0x16c ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000817f4d78 __pi_memset_generic+0x178 ([kernel.kallsyms]) => ffff8000817f4d6c __pi_memset_generic+0x16c ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000817f4d78 __pi_memset_generic+0x178 ([kernel.kallsyms]) => ffff8000817f4d6c __pi_memset_generic+0x16c ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: return ffff8000817f4d84 __pi_memset_generic+0x184 ([kernel.kallsyms]) => ffff8000803a3a78 perf_report_aux_output_id+0x60 ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000803a3a98 perf_report_aux_output_id+0x80 ([kernel.kallsyms]) => ffff8000803a3b04 perf_report_aux_output_id+0xec ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: call ffff8000803a3b1c perf_report_aux_output_id+0x104 ([kernel.kallsyms]) => ffff8000803a38f8 __perf_event_header__init_id+0x0 ([kernel.kallsyms]) After: callchain_test 6114 [005] 331519.825214: 1 branches: tr strt jmp 0 [unknown] ([unknown]) => ffff8000803a3a68 perf_report_aux_output_id+0x50 ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: call ffff8000803a3a74 perf_report_aux_output_id+0x5c ([kernel.kallsyms]) => ffff8000817f4d88 memset+0x0 ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: call ffff8000803a3b1c perf_report_aux_output_id+0x104 ([kernel.kallsyms]) => ffff8000803a38f8 __perf_event_header__init_id+0x0 ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: call ffff8000803a39c0 __perf_event_header__init_id+0xc8 ([kernel.kallsyms]) => ffff800080105258 __task_pid_nr_ns+0x0 ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: call ffff80008010528c __task_pid_nr_ns+0x34 ([kernel.kallsyms]) => ffff8000801d5610 __rcu_read_lock+0x0 ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: call ffff8000801052b0 __task_pid_nr_ns+0x58 ([kernel.kallsyms]) => ffff800080192078 lock_acquire+0x0 ([kernel.kallsyms]) callchain_test 6114 [005] 331519.825214: 1 branches: call ffff8000801923f4 lock_acquire+0x37c ([kernel.kallsyms]) => ffff8000801d6da0 rcu_is_watching+0x0 ([kernel.kallsyms]) Fixes: b12235b113cf ("perf tools: Add mechanic to synthesise CoreSight trace packets") Signed-off-by: Leo Yan Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Namhyung Kim --- tools/perf/scripts/python/arm-cs-trace-disasm.py | 9 +++++---- .../tests/shell/coresight/test_arm_coresight_disasm.sh | 4 ++-- tools/perf/util/cs-etm.c | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/tools/perf/scripts/python/arm-cs-trace-disasm.py b/tools/perf/scripts/python/arm-cs-trace-disasm.py index 8f6fa4a007b4..42579f858684 100755 --- a/tools/perf/scripts/python/arm-cs-trace-disasm.py +++ b/tools/perf/scripts/python/arm-cs-trace-disasm.py @@ -31,18 +31,19 @@ from perf_trace_context import perf_sample_srccode, perf_config_get # # Output disassembly with objdump and auto detect vmlinux # (when running on same machine.): -# perf script -s scripts/python/arm-cs-trace-disasm.py -d +# perf script --itrace=b -s scripts/python/arm-cs-trace-disasm.py \ +# -- -d # # Output disassembly with llvm-objdump: -# perf script -s scripts/python/arm-cs-trace-disasm.py \ +# perf script --itrace=b -s scripts/python/arm-cs-trace-disasm.py \ # -- -d llvm-objdump-11 -k path/to/vmlinux # # Output accurate disassembly by passing kcore to script: -# perf script -s scripts/python/arm-cs-trace-disasm.py \ +# perf script --itrace=b -s scripts/python/arm-cs-trace-disasm.py \ # -- -d -k perf.data/kcore_dir/kcore # # Output only source line and symbols: -# perf script -s scripts/python/arm-cs-trace-disasm.py +# perf script --itrace=b -s scripts/python/arm-cs-trace-disasm.py def default_objdump(): config = perf_config_get("annotate.objdump") diff --git a/tools/perf/tests/shell/coresight/test_arm_coresight_disasm.sh b/tools/perf/tests/shell/coresight/test_arm_coresight_disasm.sh index ccb90dda2475..f3ebad596378 100755 --- a/tools/perf/tests/shell/coresight/test_arm_coresight_disasm.sh +++ b/tools/perf/tests/shell/coresight/test_arm_coresight_disasm.sh @@ -44,7 +44,7 @@ branch_search='[[:space:]](bl|b(\.(eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al) if [ "$(id -u)" == 0 ] && [ -e /proc/kcore ]; then echo "Testing kernel disassembly" perf record -o ${perfdata} -e cs_etm//k --kcore -Se -m,64K -- touch $file > /dev/null 2>&1 - perf script -i ${perfdata} -s python:${script_path} -- \ + perf script -i ${perfdata} --itrace=b -s python:${script_path} -- \ -d --stop-sample=2 -k ${perfdata}/kcore_dir/kcore 2> /dev/null > ${file} grep -q -E ${branch_search} ${file} echo "Found kernel branches" @@ -56,7 +56,7 @@ fi ## Test user ## echo "Testing userspace disassembly" perf record -o ${perfdata} -e cs_etm//u -Se -m,64K -- touch $file > /dev/null 2>&1 -perf script -i ${perfdata} -s python:${script_path} -- \ +perf script -i ${perfdata} --itrace=b -s python:${script_path} -- \ -d --stop-sample=2 2> /dev/null > ${file} grep -q -E ${branch_search} ${file} echo "Found userspace branches" diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index deca07d57282..95530e10e010 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -71,6 +71,7 @@ struct cs_etm_auxtrace { int num_cpu; u64 latest_kernel_timestamp; u32 auxtrace_type; + u32 branches_filter; u64 branches_sample_type; u64 branches_id; u64 instructions_sample_type; @@ -1705,6 +1706,10 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq, } dummy_bs; u64 ip; + if (etm->branches_filter && + !(etm->branches_filter & tidq->prev_packet->flags)) + return 0; + perf_sample__init(&sample, /*all=*/true); ip = cs_etm__last_executed_instr(tidq->prev_packet); @@ -3564,6 +3569,16 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event, etm->synth_opts.callchain = false; } + if (etm->synth_opts.calls) + etm->branches_filter |= PERF_IP_FLAG_CALL | + PERF_IP_FLAG_TRACE_BEGIN | + PERF_IP_FLAG_TRACE_END; + + if (etm->synth_opts.returns) + etm->branches_filter |= PERF_IP_FLAG_RETURN | + PERF_IP_FLAG_TRACE_BEGIN | + PERF_IP_FLAG_TRACE_END; + etm->session = session; etm->num_cpu = num_cpu; -- cgit v1.2.3 From 5cf3ea0f2616fea7d91e4b45b6bca872e09205c3 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 2 Jul 2026 20:51:38 +0100 Subject: perf cs-etm: Decode ETE exception packets ETE shares the same packet format as ETMv4, but exception decoding handled ETMv4 packets only. As a result, ETE exception packets were not classified. Recognize the ETE magic for exception number decoding. Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Namhyung Kim --- tools/perf/util/cs-etm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 95530e10e010..0ad6cccc292d 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -2202,7 +2202,7 @@ static bool cs_etm__is_syscall(struct cs_etm_queue *etmq, * HVC cases; need to check if it's SVC instruction based on * packet address. */ - if (magic == __perf_cs_etmv4_magic) { + if (magic == __perf_cs_etmv4_magic || magic == __perf_cs_ete_magic) { if (packet->exception_number == CS_ETMV4_EXC_CALL && cs_etm__is_svc_instr(etmq, tidq, prev_packet, prev_packet->end_addr)) @@ -2225,7 +2225,7 @@ static bool cs_etm__is_async_exception(struct cs_etm_traceid_queue *tidq, packet->exception_number == CS_ETMV3_EXC_FIQ) return true; - if (magic == __perf_cs_etmv4_magic) + if (magic == __perf_cs_etmv4_magic || magic == __perf_cs_ete_magic) if (packet->exception_number == CS_ETMV4_EXC_RESET || packet->exception_number == CS_ETMV4_EXC_DEBUG_HALT || packet->exception_number == CS_ETMV4_EXC_SYSTEM_ERROR || @@ -2255,7 +2255,7 @@ static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq, packet->exception_number == CS_ETMV3_EXC_GENERIC) return true; - if (magic == __perf_cs_etmv4_magic) { + if (magic == __perf_cs_etmv4_magic || magic == __perf_cs_ete_magic) { if (packet->exception_number == CS_ETMV4_EXC_TRAP || packet->exception_number == CS_ETMV4_EXC_ALIGNMENT || packet->exception_number == CS_ETMV4_EXC_INST_FAULT || -- cgit v1.2.3 From 9bb1423295d1f84d3a557bc690fbb791d8a773ac Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 2 Jul 2026 20:51:39 +0100 Subject: perf cs-etm: Refactor instruction size handling This patch introduces a new function cs_etm__instr_size() to calculate the instruction size based on ISA type and instruction address. Given the trace data can be MB and most likely that will be A64/A32 on a lot of platforms, cs_etm__instr_addr() keeps a single ISA type check for A64/A32 and executes an optimized calculation (addr + offset * 4). Signed-off-by: Leo Yan Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Namhyung Kim --- tools/perf/util/cs-etm.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 0ad6cccc292d..838c2d004713 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -1389,6 +1389,18 @@ static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq, return ((instrBytes[1] & 0xF8) >= 0xE8) ? 4 : 2; } +static inline int cs_etm__instr_size(struct cs_etm_queue *etmq, + struct cs_etm_traceid_queue *tidq, + struct cs_etm_packet *packet, + u64 addr) +{ + if (packet->isa == CS_ETM_ISA_T32) + return cs_etm__t32_instr_size(etmq, tidq, packet, addr); + + /* Otherwise, 4-byte instruction size for A32/A64 */ + return 4; +} + static inline u64 cs_etm__first_executed_instr(struct cs_etm_packet *packet) { /* @@ -1417,19 +1429,17 @@ static inline u64 cs_etm__instr_addr(struct cs_etm_queue *etmq, struct cs_etm_packet *packet, u64 offset) { - if (packet->isa == CS_ETM_ISA_T32) { - u64 addr = packet->start_addr; + u64 addr = packet->start_addr; - while (offset) { - addr += cs_etm__t32_instr_size(etmq, tidq, packet, - addr); - offset--; - } - return addr; - } + /* 4-byte instruction size for A32/A64 */ + if (packet->isa == CS_ETM_ISA_A64 || packet->isa == CS_ETM_ISA_A32) + return addr + offset * 4; - /* Assume a 4 byte instruction size (A32/A64) */ - return packet->start_addr + offset * 4; + while (offset) { + addr += cs_etm__instr_size(etmq, tidq, packet, addr); + offset--; + } + return addr; } static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq, @@ -1599,16 +1609,7 @@ static void cs_etm__copy_insn(struct cs_etm_queue *etmq, return; } - /* - * T32 instruction size might be 32-bit or 16-bit, decide by calling - * cs_etm__t32_instr_size(). - */ - if (packet->isa == CS_ETM_ISA_T32) - sample->insn_len = cs_etm__t32_instr_size(etmq, tidq, packet, - sample->ip); - /* Otherwise, A64 and A32 instruction size are always 32-bit. */ - else - sample->insn_len = 4; + sample->insn_len = cs_etm__instr_size(etmq, tidq, packet, sample->ip); cs_etm__frontend_mem_access(etmq, tidq, packet, sample->ip, sample->insn_len, (void *)sample->insn); -- cgit v1.2.3 From 3ea91599b7b6e05cd21dfa1214f251dfe7770468 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 2 Jul 2026 20:51:40 +0100 Subject: perf cs-etm: Use thread-stack for last branch entries CS ETM maintains its own circular array for last branch entries, with local helpers to update, copy and reset the branch stack. This duplicates logic already provided by the common code. Record taken branches with thread_stack__event() and synthesize PERF_SAMPLE_BRANCH_STACK data with thread_stack__br_sample(). This removes the private last_branch_rb buffer and its position tracking. This also makes the branch history state belong to the thread rather than the trace queue. That is a better fit for CoreSight traces where a trace queue can effectively be CPU scoped, while call/return history is per thread. Keep the buffer number updated via thread_stack__set_trace_nr(), which is used when exporting samples to Python scripts. Pass callstack=false for now; synthesized callchains are added by a later patch. The output should remain same, except that be->flags.predicted is no longer set. Since CoreSight trace does not provide branch prediction information, clearing the flag avoids confusion. Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Namhyung Kim --- tools/perf/util/cs-etm.c | 173 ++++++++++++++++------------------------------- 1 file changed, 58 insertions(+), 115 deletions(-) diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 838c2d004713..ba9ffb7bdb4b 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -85,10 +85,9 @@ struct cs_etm_auxtrace { struct cs_etm_traceid_queue { u8 trace_chan_id; u64 period_instructions; - size_t last_branch_pos; union perf_event *event_buf; + unsigned int br_stack_sz; struct branch_stack *last_branch; - struct branch_stack *last_branch_rb; struct cs_etm_packet *prev_packet; struct cs_etm_packet *packet; struct cs_etm_packet_queue packet_queue; @@ -665,9 +664,8 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq, tidq->last_branch = zalloc(sz); if (!tidq->last_branch) goto out_free; - tidq->last_branch_rb = zalloc(sz); - if (!tidq->last_branch_rb) - goto out_free; + + tidq->br_stack_sz = etm->synth_opts.last_branch_sz; } tidq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE); @@ -677,7 +675,6 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq, return 0; out_free: - zfree(&tidq->last_branch_rb); zfree(&tidq->last_branch); zfree(&tidq->prev_packet); zfree(&tidq->packet); @@ -962,7 +959,6 @@ static void cs_etm__free_traceid_queues(struct cs_etm_queue *etmq) thread__zput(tidq->decode_thread); zfree(&tidq->event_buf); zfree(&tidq->last_branch); - zfree(&tidq->last_branch_rb); zfree(&tidq->prev_packet); zfree(&tidq->packet); zfree(&tidq); @@ -1322,57 +1318,6 @@ out: return ret; } -static inline -void cs_etm__copy_last_branch_rb(struct cs_etm_queue *etmq, - struct cs_etm_traceid_queue *tidq) -{ - struct branch_stack *bs_src = tidq->last_branch_rb; - struct branch_stack *bs_dst = tidq->last_branch; - size_t nr = 0; - - /* - * Set the number of records before early exit: ->nr is used to - * determine how many branches to copy from ->entries. - */ - bs_dst->nr = bs_src->nr; - - /* - * Early exit when there is nothing to copy. - */ - if (!bs_src->nr) - return; - - /* - * As bs_src->entries is a circular buffer, we need to copy from it in - * two steps. First, copy the branches from the most recently inserted - * branch ->last_branch_pos until the end of bs_src->entries buffer. - */ - nr = etmq->etm->synth_opts.last_branch_sz - tidq->last_branch_pos; - memcpy(&bs_dst->entries[0], - &bs_src->entries[tidq->last_branch_pos], - sizeof(struct branch_entry) * nr); - - /* - * If we wrapped around at least once, the branches from the beginning - * of the bs_src->entries buffer and until the ->last_branch_pos element - * are older valid branches: copy them over. The total number of - * branches copied over will be equal to the number of branches asked by - * the user in last_branch_sz. - */ - if (bs_src->nr >= etmq->etm->synth_opts.last_branch_sz) { - memcpy(&bs_dst->entries[nr], - &bs_src->entries[0], - sizeof(struct branch_entry) * tidq->last_branch_pos); - } -} - -static inline -void cs_etm__reset_last_branch_rb(struct cs_etm_traceid_queue *tidq) -{ - tidq->last_branch_pos = 0; - tidq->last_branch_rb->nr = 0; -} - static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq, struct cs_etm_traceid_queue *tidq, struct cs_etm_packet *packet, u64 addr) @@ -1442,38 +1387,6 @@ static inline u64 cs_etm__instr_addr(struct cs_etm_queue *etmq, return addr; } -static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq, - struct cs_etm_traceid_queue *tidq) -{ - struct branch_stack *bs = tidq->last_branch_rb; - struct branch_entry *be; - - /* - * The branches are recorded in a circular buffer in reverse - * chronological order: we start recording from the last element of the - * buffer down. After writing the first element of the stack, move the - * insert position back to the end of the buffer. - */ - if (!tidq->last_branch_pos) - tidq->last_branch_pos = etmq->etm->synth_opts.last_branch_sz; - - tidq->last_branch_pos -= 1; - - be = &bs->entries[tidq->last_branch_pos]; - be->from = cs_etm__last_executed_instr(tidq->prev_packet); - be->to = cs_etm__first_executed_instr(tidq->packet); - /* No support for mispredict */ - be->flags.mispred = 0; - be->flags.predicted = 1; - - /* - * Increment bs->nr until reaching the number of last branches asked by - * the user on the command line. - */ - if (bs->nr < etmq->etm->synth_opts.last_branch_sz) - bs->nr += 1; -} - static int cs_etm__inject_event(struct cs_etm_auxtrace *etm, union perf_event *event, struct perf_sample *sample, u64 type) { @@ -1637,6 +1550,57 @@ static inline u64 cs_etm__resolve_sample_time(struct cs_etm_queue *etmq, return etm->latest_kernel_timestamp; } +static bool cs_etm__packet_has_taken_branch(struct cs_etm_packet *packet) +{ + if (packet->sample_type == CS_ETM_RANGE && + packet->last_instr_taken_branch) + return true; + + return false; +} + +static void cs_etm__add_stack_event(struct cs_etm_queue *etmq, + struct cs_etm_traceid_queue *tidq) +{ + struct cs_etm_auxtrace *etm = etmq->etm; + u64 from, to; + int size; + + if (!etm->synth_opts.branches && !etm->synth_opts.instructions) + return; + + if (!cs_etm__packet_has_taken_branch(tidq->prev_packet)) + return; + + if (etmq->etm->synth_opts.last_branch) { + from = cs_etm__last_executed_instr(tidq->prev_packet); + to = cs_etm__first_executed_instr(tidq->packet); + + size = cs_etm__instr_size(etmq, tidq, tidq->prev_packet, from); + + /* Enable callchain so thread stack entry can be allocated */ + thread_stack__event(tidq->frontend_thread, tidq->prev_packet->cpu, + tidq->prev_packet->flags, from, to, size, + etmq->buffer->buffer_nr + 1, false, + tidq->br_stack_sz, 0); + } else { + thread_stack__set_trace_nr(tidq->frontend_thread, + tidq->prev_packet->cpu, + etmq->buffer->buffer_nr + 1); + } +} + +static void cs_etm__sample_branch_stack(struct cs_etm_auxtrace *etm, + struct cs_etm_traceid_queue *tidq, + struct perf_sample *sample) +{ + if (etm->synth_opts.last_branch) { + thread_stack__br_sample(tidq->frontend_thread, tidq->packet->cpu, + tidq->last_branch, tidq->br_stack_sz); + sample->branch_stack = tidq->last_branch; + } +} + static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, struct cs_etm_traceid_queue *tidq, struct cs_etm_packet *packet, @@ -1666,9 +1630,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, sample.cpumode = event->sample.header.misc; cs_etm__copy_insn(etmq, tidq, packet, &sample); - - if (etm->synth_opts.last_branch) - sample.branch_stack = tidq->last_branch; + cs_etm__sample_branch_stack(etm, tidq, &sample); if (etm->synth_opts.inject) { ret = cs_etm__inject_event(etm, event, &sample, @@ -1862,14 +1824,7 @@ static int cs_etm__sample(struct cs_etm_queue *etmq, tidq->period_instructions += tidq->packet->instr_count; - /* - * Record a branch when the last instruction in - * PREV_PACKET is a branch. - */ - if (etm->synth_opts.last_branch && - tidq->prev_packet->sample_type == CS_ETM_RANGE && - tidq->prev_packet->last_instr_taken_branch) - cs_etm__update_last_branch_rb(etmq, tidq); + cs_etm__add_stack_event(etmq, tidq); if (etm->synth_opts.instructions && tidq->period_instructions >= etm->instructions_sample_period) { @@ -1928,10 +1883,6 @@ static int cs_etm__sample(struct cs_etm_queue *etmq, u64 offset = etm->instructions_sample_period - instrs_prev; u64 addr; - /* Prepare last branches for instruction sample */ - if (etm->synth_opts.last_branch) - cs_etm__copy_last_branch_rb(etmq, tidq); - while (tidq->period_instructions >= etm->instructions_sample_period) { /* @@ -1962,8 +1913,7 @@ static int cs_etm__sample(struct cs_etm_queue *etmq, generate_sample = true; /* Generate sample for branch taken packet */ - if (tidq->prev_packet->sample_type == CS_ETM_RANGE && - tidq->prev_packet->last_instr_taken_branch) + if (cs_etm__packet_has_taken_branch(tidq->prev_packet)) generate_sample = true; if (generate_sample) { @@ -2011,10 +1961,6 @@ static int cs_etm__flush(struct cs_etm_queue *etmq, etmq->etm->synth_opts.instructions && tidq->prev_packet->sample_type == CS_ETM_RANGE) { u64 addr; - - /* Prepare last branches for instruction sample */ - cs_etm__copy_last_branch_rb(etmq, tidq); - /* * Generate a last branch event for the branches left in the * circular buffer at the end of the trace. @@ -2046,7 +1992,7 @@ swap_packet: /* Reset last branches after flush the trace */ if (etm->synth_opts.last_branch) - cs_etm__reset_last_branch_rb(tidq); + thread_stack__flush(tidq->frontend_thread); return err; } @@ -2070,9 +2016,6 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq, tidq->prev_packet->sample_type == CS_ETM_RANGE) { u64 addr; - /* Prepare last branches for instruction sample */ - cs_etm__copy_last_branch_rb(etmq, tidq); - /* * Use the address of the end of the last reported execution * range. -- cgit v1.2.3 From ea5075e3776846d4941dddf1549426ebd3feb81f Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 2 Jul 2026 20:51:41 +0100 Subject: perf cs-etm: Flush thread stacks after decoder reset Perf resets the CoreSight decoder when moving to a new AUX trace buffer, this causes trace discontinunity globally. For callchain synthesis, keeping thread-stack state after decoder reset can leave stale call/return history attached to threads that are decoded later, producing incorrect synthesized callchains. Flush all host thread stacks after a decoder reset. When virtualization is present, flush the guest thread stacks as well. Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Namhyung Kim --- tools/perf/util/cs-etm.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index ba9ffb7bdb4b..996317687ce7 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -2033,6 +2033,45 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq, return 0; } + +static int cs_etm__flush_stack_cb(struct thread *thread, + void *data __maybe_unused) +{ + thread_stack__flush(thread); + return 0; +} + +static void cs_etm__flush_machine_stack(struct cs_etm_queue *etmq, pid_t pid) +{ + struct machine *machine; + + machine = machines__find(&etmq->etm->session->machines, pid); + if (machine) + machine__for_each_thread(machine, cs_etm__flush_stack_cb, NULL); +} + +static void cs_etm__flush_all_stack(struct cs_etm_queue *etmq) +{ + enum cs_etm_pid_fmt pid_fmt = cs_etm__get_pid_fmt(etmq); + + if (!etmq->etm->synth_opts.last_branch) + return; + + switch (pid_fmt) { + case CS_ETM_PIDFMT_CTXTID2: + /* Clear the guest stack if virtualization is supported */ + cs_etm__flush_machine_stack(etmq, DEFAULT_GUEST_KERNEL_ID); + fallthrough; + case CS_ETM_PIDFMT_CTXTID: + cs_etm__flush_machine_stack(etmq, HOST_KERNEL_ID); + break; + case CS_ETM_PIDFMT_NONE: + default: + break; + + } +} + /* * cs_etm__get_data_block: Fetch a block from the auxtrace_buffer queue * if need be. @@ -2055,6 +2094,12 @@ static int cs_etm__get_data_block(struct cs_etm_queue *etmq) ret = cs_etm_decoder__reset(etmq->decoder); if (ret) return ret; + + /* + * Since the decoder is reset, this causes a global trace + * discontinuity. Flush all thread stacks. + */ + cs_etm__flush_all_stack(etmq); } return etmq->buf_len; -- cgit v1.2.3 From e3fbd5d1a13a82906222c924014f1a48e2427932 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 2 Jul 2026 20:51:42 +0100 Subject: perf cs-etm: Support call indentation The perf script callindent is derived from call stack in thread context, CS ETM ignores the requirement for callindent without pushing and poping call stack. Enable thread-stack when either itrace thread-stack support or last branch entries are requested, allocate the branch stack storage accordingly, and feed taken branches to thread_stack__event() whenever thread-stack state is needed. When callindent is requested, pass callstack=true to thread_stack__event() so the common thread-stack code maintains call depth for branch samples. Before: perf script -F +callindent callchain_test 6543 [002] 1 branches: main ffff93252258 __libc_start_call_main+0x78 (/usr/lib/aarch64-linux-gnu/libc.so.6) callchain_test 6543 [002] 1 branches: foo aaaad6b607c4 main+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test) callchain_test 6543 [002] 1 branches: print aaaad6b607ac foo+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test) callchain_test 6543 [002] 1 branches: do_svc aaaad6b60794 print+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test) callchain_test 6543 [002] 1 branches: vectors aaaad6b60780 do_svc+0x18 (/home/kernel/leoy/test_cs_callchain/callchain_test) callchain_test 6543 [002] 1 branches: el0t_64_sync_handler ffff80008001159c el0t_64_sync+0x194 ([kernel.kallsyms]) callchain_test 6543 [002] 1 branches: el0_svc ffff800081829194 el0t_64_sync_handler+0x9c ([kernel.kallsyms]) callchain_test 6543 [002] 1 branches: lockdep_hardirqs_off ffff800081828794 el0_svc+0x24 ([kernel.kallsyms]) callchain_test 6543 [002] 1 branches: __this_cpu_preempt_check ffff80008182b348 lockdep_hardirqs_off+0xf0 ([kernel.kallsyms]) After: callchain_test 6543 [002] 1 branches: main ffff93252258 __libc_start_call_main+0x78 (/usr/lib/aarch64-linux-gnu/libc.so.6) callchain_test 6543 [002] 1 branches: foo aaaad6b607c4 main+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test) callchain_test 6543 [002] 1 branches: print aaaad6b607ac foo+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test) callchain_test 6543 [002] 1 branches: do_svc aaaad6b60794 print+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test) callchain_test 6543 [002] 1 branches: vectors aaaad6b60780 do_svc+0x18 (/home/kernel/leoy/test_cs_callchain/callchain_test) callchain_test 6543 [002] 1 branches: el0t_64_sync_handler ffff80008001159c el0t_64_sync+0x194 ([kernel.kallsyms]) callchain_test 6543 [002] 1 branches: el0_svc ffff800081829194 el0t_64_sync_handler+0x9c ([kernel.kallsyms]) callchain_test 6543 [002] 1 branches: lockdep_hardirqs_off ffff800081828794 el0_svc+0x24 ([kernel.kallsyms]) callchain_test 6543 [002] 1 branches: __this_cpu_preempt_check ffff80008182b348 lockdep_hardirqs_off+0xf0 ([kernel.kallsyms]) Signed-off-by: Leo Yan Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Namhyung Kim --- tools/perf/util/cs-etm.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 996317687ce7..f76648fa6768 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -67,6 +67,8 @@ struct cs_etm_auxtrace { bool snapshot_mode; bool data_queued; bool has_virtual_ts; /* Virtual/Kernel timestamps in the trace. */ + bool use_thread_stack; + bool use_callchain; int num_cpu; u64 latest_kernel_timestamp; @@ -656,7 +658,7 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq, if (!tidq->prev_packet) goto out_free; - if (etm->synth_opts.last_branch) { + if (etm->use_thread_stack) { size_t sz = sizeof(struct branch_stack); sz += etm->synth_opts.last_branch_sz * @@ -1572,7 +1574,7 @@ static void cs_etm__add_stack_event(struct cs_etm_queue *etmq, if (!cs_etm__packet_has_taken_branch(tidq->prev_packet)) return; - if (etmq->etm->synth_opts.last_branch) { + if (etmq->etm->use_thread_stack) { from = cs_etm__last_executed_instr(tidq->prev_packet); to = cs_etm__first_executed_instr(tidq->packet); @@ -1581,7 +1583,8 @@ static void cs_etm__add_stack_event(struct cs_etm_queue *etmq, /* Enable callchain so thread stack entry can be allocated */ thread_stack__event(tidq->frontend_thread, tidq->prev_packet->cpu, tidq->prev_packet->flags, from, to, size, - etmq->buffer->buffer_nr + 1, false, + etmq->buffer->buffer_nr + 1, + etmq->etm->use_callchain, tidq->br_stack_sz, 0); } else { thread_stack__set_trace_nr(tidq->frontend_thread, @@ -1991,7 +1994,7 @@ swap_packet: cs_etm__packet_swap(etm, tidq); /* Reset last branches after flush the trace */ - if (etm->synth_opts.last_branch) + if (etm->use_thread_stack) thread_stack__flush(tidq->frontend_thread); return err; @@ -2054,7 +2057,7 @@ static void cs_etm__flush_all_stack(struct cs_etm_queue *etmq) { enum cs_etm_pid_fmt pid_fmt = cs_etm__get_pid_fmt(etmq); - if (!etmq->etm->synth_opts.last_branch) + if (!etmq->etm->use_thread_stack) return; switch (pid_fmt) { @@ -3556,6 +3559,7 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event, itrace_synth_opts__set_default(&etm->synth_opts, session->itrace_synth_opts->default_no_sample); etm->synth_opts.callchain = false; + etm->synth_opts.thread_stack = session->itrace_synth_opts->thread_stack; } if (etm->synth_opts.calls) @@ -3617,6 +3621,12 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event, etm->tc.cap_user_time_zero = tc->cap_user_time_zero; etm->tc.cap_user_time_short = tc->cap_user_time_short; } + + etm->use_thread_stack = etm->synth_opts.thread_stack || + etm->synth_opts.last_branch; + + etm->use_callchain = etm->synth_opts.thread_stack; + err = cs_etm__synth_events(etm, session); if (err) goto err_free_queues; -- cgit v1.2.3 From 41a7388d0734961e36136b2c16b2423c2f385569 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 2 Jul 2026 20:51:43 +0100 Subject: perf cs-etm: Synthesize callchains for instruction samples CS ETM already records branches into the thread stack, but instruction samples do not carry synthesized callchains. It misses to support the callchain and no output with the itrace option 'g'. Allocate a callchain buffer per queue and use thread_stack__sample() when synthesizing instruction samples. Advertise PERF_SAMPLE_CALLCHAIN on the synthetic instruction event. Allocate one extra callchain entry than requested, as the first entry is reserved for storing context information. cs_etm__context() is introduced for handling context packet and update the thread info and start kernel address for frontend decoding. After: perf script --itrace=g16l64i1i callchain_test 6543 [002] 1 instructions: ffff800080010c14 vectors+0x414 ([kernel.kallsyms]) aaaad6b60784 do_svc+0x1c (/home/kernel/leoy/test_cs_callchain/callchain_test) aaaad6b60798 print+0xc (/home/kernel/leoy/test_cs_callchain/callchain_test) aaaad6b607b0 foo+0xc (/home/kernel/leoy/test_cs_callchain/callchain_test) aaaad6b607c8 main+0xc (/home/kernel/leoy/test_cs_callchain/callchain_test) ffff9325225c __libc_start_call_main+0x7c (/usr/lib/aarch64-linux-gnu/libc.so.6) ffff9325233c call_init+0x9c (inlined) ffff9325233c __libc_start_main_impl+0x9c (inlined) aaaad6b60670 _start+0x30 (/home/kernel/leoy/test_cs_callchain/callchain_test) ffff800080012290 ret_to_user+0x120 ([kernel.kallsyms]) Signed-off-by: Leo Yan Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Namhyung Kim --- tools/perf/util/cs-etm.c | 83 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index f76648fa6768..95e3ec1171ac 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -18,6 +18,7 @@ #include #include "auxtrace.h" +#include "callchain.h" #include "color.h" #include "cs-etm.h" #include "cs-etm-decoder/cs-etm-decoder.h" @@ -87,9 +88,11 @@ struct cs_etm_auxtrace { struct cs_etm_traceid_queue { u8 trace_chan_id; u64 period_instructions; + u64 kernel_start; union perf_event *event_buf; unsigned int br_stack_sz; struct branch_stack *last_branch; + struct ip_callchain *callchain; struct cs_etm_packet *prev_packet; struct cs_etm_packet *packet; struct cs_etm_packet_queue packet_queue; @@ -670,6 +673,15 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq, tidq->br_stack_sz = etm->synth_opts.last_branch_sz; } + if (etm->synth_opts.callchain) { + /* Add 1 to callchain_sz for callchain context */ + tidq->callchain = + zalloc(struct_size(tidq->callchain, ips, + etm->synth_opts.callchain_sz + 1)); + if (!tidq->callchain) + goto out_free; + } + tidq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE); if (!tidq->event_buf) goto out_free; @@ -677,6 +689,7 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq, return 0; out_free: + zfree(&tidq->callchain); zfree(&tidq->last_branch); zfree(&tidq->prev_packet); zfree(&tidq->packet); @@ -960,6 +973,7 @@ static void cs_etm__free_traceid_queues(struct cs_etm_queue *etmq) thread__zput(tidq->frontend_thread); thread__zput(tidq->decode_thread); zfree(&tidq->event_buf); + zfree(&tidq->callchain); zfree(&tidq->last_branch); zfree(&tidq->prev_packet); zfree(&tidq->packet); @@ -1602,6 +1616,26 @@ static void cs_etm__sample_branch_stack(struct cs_etm_auxtrace *etm, tidq->last_branch, tidq->br_stack_sz); sample->branch_stack = tidq->last_branch; } + + if (etm->synth_opts.callchain) { + if (tidq->kernel_start) + thread_stack__sample(tidq->frontend_thread, + tidq->packet->cpu, + tidq->callchain, + etm->synth_opts.callchain_sz + 1, + sample->ip, tidq->kernel_start); + else + /* + * Clear the callchain when the kernel start address is + * not available yet. The empty callchain can then be + * consumed by cs_etm__inject_event(). + */ + memset(tidq->callchain, 0, + struct_size(tidq->callchain, ips, + etm->synth_opts.callchain_sz + 1)); + + sample->callchain = tidq->callchain; + } } static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, @@ -1800,6 +1834,9 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm, attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX; } + if (etm->synth_opts.callchain) + attr.sample_type |= PERF_SAMPLE_CALLCHAIN; + if (etm->synth_opts.instructions) { attr.config = PERF_COUNT_HW_INSTRUCTIONS; attr.sample_period = etm->synth_opts.period; @@ -1931,6 +1968,34 @@ static int cs_etm__sample(struct cs_etm_queue *etmq, return 0; } +static int cs_etm__context(struct cs_etm_queue *etmq, + struct cs_etm_traceid_queue *tidq) +{ + ocsd_ex_level el = tidq->packet->el; + struct machine *machine; + int ret; + + machine = cs_etm__get_machine(etmq, el); + if (!machine) { + ret = -EINVAL; + goto err; + } + + tidq->kernel_start = machine__kernel_start(machine); + + ret = cs_etm__etmq_update_thread(etmq, el, tidq->packet->tid, + &tidq->frontend_thread); + if (ret) + goto err; + + return 0; + +err: + thread__zput(tidq->frontend_thread); + tidq->kernel_start = 0; + return ret; +} + static int cs_etm__exception(struct cs_etm_traceid_queue *tidq) { /* @@ -2531,9 +2596,7 @@ static int cs_etm__process_traceid_queue(struct cs_etm_queue *etmq, * tracing the kernel the context packet will be emitted * between two ranges. */ - ret = cs_etm__etmq_update_thread(etmq, tidq->packet->el, - tidq->packet->tid, - &tidq->frontend_thread); + ret = cs_etm__context(etmq, tidq); if (ret) goto out; break; @@ -3572,6 +3635,14 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event, PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END; + if (etm->synth_opts.callchain && !symbol_conf.use_callchain) { + symbol_conf.use_callchain = true; + if (callchain_register_param(&callchain_param) < 0) { + symbol_conf.use_callchain = false; + etm->synth_opts.callchain = false; + } + } + etm->session = session; etm->num_cpu = num_cpu; @@ -3623,9 +3694,11 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event, } etm->use_thread_stack = etm->synth_opts.thread_stack || - etm->synth_opts.last_branch; + etm->synth_opts.last_branch || + etm->synth_opts.callchain; - etm->use_callchain = etm->synth_opts.thread_stack; + etm->use_callchain = etm->synth_opts.thread_stack || + etm->synth_opts.callchain; err = cs_etm__synth_events(etm, session); if (err) -- cgit v1.2.3 From ca0e19074bd6afcb9c7b23aa474ca17238cdb241 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 2 Jul 2026 20:51:44 +0100 Subject: perf test: Add Arm CoreSight callchain test Add a CoreSight shell test for synthesized callchains. The test uses the new callchain workload to generate trace and decodes it with synthesis callchain. It then verifies that the instruction samples show the expected callchain push and pop. Use control FIFOs so tracing starts only around the workload, which keeps the trace data small. The test is limited to with the cs_etm event available and root permission. After: perf test 138 -vvv 138: CoreSight synthesized callchain: ---- start ---- test child forked, pid 35581 Callchain flow matched: l1=4642868 l2=4642880 l3=4642895 l4=4642919 l5=4670494 l6=4670500 l7=4670520 ---- end(0) ---- 138: CoreSight synthesized callchain : Ok Assisted-by: Codex:GPT-5.5 Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Namhyung Kim --- tools/perf/Documentation/perf-test.txt | 6 +- tools/perf/tests/builtin-test.c | 1 + tools/perf/tests/shell/coresight/callchain.sh | 172 ++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + tools/perf/tests/workloads/Build | 2 + tools/perf/tests/workloads/callchain.c | 33 +++++ 6 files changed, 213 insertions(+), 2 deletions(-) create mode 100755 tools/perf/tests/shell/coresight/callchain.sh create mode 100644 tools/perf/tests/workloads/callchain.c diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt index 81c8525f5946..859df74e62ef 100644 --- a/tools/perf/Documentation/perf-test.txt +++ b/tools/perf/Documentation/perf-test.txt @@ -57,7 +57,8 @@ OPTIONS --workload=:: Run a built-in workload, to list them use '--list-workloads', current ones include: noploop, thloop, leafloop, sqrtloop, brstack, datasym, - context_switch_loop, deterministic, named_threads and landlock. + context_switch_loop, deterministic, named_threads, landlock and + callchain. Used with the shell script regression tests. @@ -69,7 +70,8 @@ OPTIONS 'named_threads' accepts the number of threads and the number of loops to do in each thread. - The datasym, landlock and deterministic workloads don't accept any. + The datasym, landlock, deterministic and callchain workloads don't accept + any. --list-workloads:: List the available workloads to use with -w/--workload. diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index d115a19e5f0f..7d18cb6021d3 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -171,6 +171,7 @@ static struct test_workload *workloads[] = { &workload__jitdump, &workload__context_switch_loop, &workload__deterministic, + &workload__callchain, #ifdef HAVE_RUST_SUPPORT &workload__code_with_type, diff --git a/tools/perf/tests/shell/coresight/callchain.sh b/tools/perf/tests/shell/coresight/callchain.sh new file mode 100755 index 000000000000..13cca7dc1118 --- /dev/null +++ b/tools/perf/tests/shell/coresight/callchain.sh @@ -0,0 +1,172 @@ +#!/bin/bash +# CoreSight synthesized callchain (exclusive) +# SPDX-License-Identifier: GPL-2.0 + +glb_err=1 + +if ! tmpdir=$(mktemp -d /tmp/perf-cs-callchain-test.XXXXXX); then + echo "mktemp failed" + exit 1 +fi + +cleanup_files() +{ + rm -rf "$tmpdir" +} + +trap cleanup_files EXIT +trap 'cleanup_files; exit $glb_err' TERM INT + +skip_if_system_is_not_ready() +{ + perf list | grep -Pzq 'cs_etm//' || { + echo "[Skip] cs_etm event is not available" >&2 + return 2 + } + + # Requires root for trace in kernel + [ "$(id -u)" = 0 ] || { + echo "[Skip] No root permission" >&2 + return 2 + } + + return 0 +} + +record_trace() +{ + local data=$1 + local script=$2 + + local cf="$tmpdir/ctl" + local af="$tmpdir/ack" + + mkfifo "$cf" "$af" + + perf record -o "$data" -e cs_etm// --per-thread -D -1 --control fifo:"$cf","$af" -- \ + perf test --record-ctl fifo:"$cf","$af" -w callchain >/dev/null 2>&1 && + + # It is safe to use 'i3i' with a three-instruction interval, since the + # workload is compiled with -O0. + perf script --itrace=g16i3il64 -i "$data" > "$script" +} + +callchain_regex_1() +{ + printf '%s' \ +'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\ +'[[:space:]]+[[:xdigit:]]+ callchain_foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\ +'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\ +'([[:space:]]+[[:xdigit:]]+ .*\n)*' +} + +callchain_regex_2() +{ + printf '%s' \ +'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\ +'[[:space:]]+[[:xdigit:]]+ callchain_do_syscall\+0x[[:xdigit:]]+ \(.*/perf\)\n'\ +'[[:space:]]+[[:xdigit:]]+ callchain_foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\ +'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\ +'([[:space:]]+[[:xdigit:]]+ .*\n)*' +} + +callchain_regex_3() +{ + printf '%s' \ +'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\ +'[[:space:]]+[[:xdigit:]]+ syscall(@plt)?\+0x[[:xdigit:]]+ \(.*\)\n'\ +'[[:space:]]+[[:xdigit:]]+ callchain_do_syscall\+0x[[:xdigit:]]+ \(.*/perf\)\n'\ +'[[:space:]]+[[:xdigit:]]+ callchain_foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\ +'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\ +'([[:space:]]+[[:xdigit:]]+ .*\n)*' +} + +callchain_regex_4() +{ + printf '%s' \ +'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\ +'[[:space:]]+[[:xdigit:]]+ .*\+0x[[:xdigit:]]+ \(\[kernel\.kallsyms\]\)\n'\ +'[[:space:]]+[[:xdigit:]]+ syscall(@plt)?\+0x[[:xdigit:]]+ \(.*\)\n'\ +'[[:space:]]+[[:xdigit:]]+ callchain_do_syscall\+0x[[:xdigit:]]+ \(.*/perf\)\n'\ +'[[:space:]]+[[:xdigit:]]+ callchain_foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\ +'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\ +'([[:space:]]+[[:xdigit:]]+ .*\n)*' +} + +find_after_line() +{ + local regex="$1" + local file="$2" + local start="$3" + local offset + local line + + # Search in byte offset + offset=$( + tail -n +"$start" "$file" | + grep -Pzob -m1 "$regex" | + tr '\0' '\n' | + sed -n 's/^\([0-9][0-9]*\):.*/\1/p;q' + ) + + if [ -z "$offset" ]; then + echo "Failed to match regex after line $start" >&2 + echo "Regex:" >&2 + printf '%s\n' "$regex" >&2 + echo "Context from line $start:" >&2 + sed -n "${start},$((start + 100))p" "$file" >&2 + return 1 + fi + + # Convert from offset to line + line=$( + tail -n +"$start" "$file" | + head -c "$offset" | + wc -l + ) + + echo "$((start + line))" +} + +check_callchain_flow() +{ + local file="$1" + local l1 l2 l3 l4 l5 l6 l7 + + # Callchain push + l1=$(find_after_line "$(callchain_regex_1)" "$file" 1) || return 1 + l2=$(find_after_line "$(callchain_regex_2)" "$file" "$((l1 + 1))") || return 1 + l3=$(find_after_line "$(callchain_regex_3)" "$file" "$((l2 + 1))") || return 1 + l4=$(find_after_line "$(callchain_regex_4)" "$file" "$((l3 + 1))") || return 1 + + # Callchain pop + l5=$(find_after_line "$(callchain_regex_3)" "$file" "$((l4 + 1))") || return 1 + l6=$(find_after_line "$(callchain_regex_2)" "$file" "$((l5 + 1))") || return 1 + l7=$(find_after_line "$(callchain_regex_1)" "$file" "$((l6 + 1))") || return 1 + + echo "Callchain flow matched:" + echo " l1=$l1 l2=$l2 l3=$l3 l4=$l4 l5=$l5 l6=$l6 l7=$l7" + + return 0 +} + +run_test() +{ + local data=$tmpdir/perf.data + local script=$tmpdir/perf.script + + if ! record_trace "$data" "$script"; then + echo "perf record/script failed" + return + fi + + check_callchain_flow "$script" || return + + glb_err=0 +} + +skip_if_system_is_not_ready || exit 2 + +run_test + +exit $glb_err diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 7cedf05be544..cee9e6b62dcc 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -248,6 +248,7 @@ DECLARE_WORKLOAD(inlineloop); DECLARE_WORKLOAD(jitdump); DECLARE_WORKLOAD(context_switch_loop); DECLARE_WORKLOAD(deterministic); +DECLARE_WORKLOAD(callchain); #ifdef HAVE_RUST_SUPPORT DECLARE_WORKLOAD(code_with_type); diff --git a/tools/perf/tests/workloads/Build b/tools/perf/tests/workloads/Build index 7bb4b9829ba2..048e371eb63e 100644 --- a/tools/perf/tests/workloads/Build +++ b/tools/perf/tests/workloads/Build @@ -13,6 +13,7 @@ perf-test-y += inlineloop.o perf-test-y += jitdump.o perf-test-y += context_switch_loop.o perf-test-y += deterministic.o +perf-test-y += callchain.o ifeq ($(CONFIG_RUST_SUPPORT),y) perf-test-y += code_with_type.o @@ -27,3 +28,4 @@ CFLAGS_traploop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE CFLAGS_inlineloop.o = -g -O2 CFLAGS_deterministic.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE CFLAGS_named_threads.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE +CFLAGS_callchain.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE diff --git a/tools/perf/tests/workloads/callchain.c b/tools/perf/tests/workloads/callchain.c new file mode 100644 index 000000000000..abbb406ba90b --- /dev/null +++ b/tools/perf/tests/workloads/callchain.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include "../tests.h" + +/* + * Mark as noinline to establish the call chain, and avoid the static + * annotation to prevent LTO from renaming the functions. + */ +noinline void callchain_do_syscall(void); +noinline void callchain_foo(void); +noinline int callchain(int argc, const char **argv); + +noinline void callchain_do_syscall(void) +{ + syscall(SYS_gettid); +} + +noinline void callchain_foo(void) +{ + callchain_do_syscall(); +} + +noinline int callchain(int argc __maybe_unused, + const char **argv __maybe_unused) +{ + callchain_foo(); + + return 0; +} + +DEFINE_WORKLOAD(callchain); -- cgit v1.2.3 From e34006e7435fdd2c8d15e89d2137a4bf22c16401 Mon Sep 17 00:00:00 2001 From: Ondrej Mosnacek Date: Wed, 1 Jul 2026 08:23:21 +0200 Subject: perf test amd ibs: avoid using executable heap Making [parts of] the heap executable is dangerous and is blocked by SELinux on Fedora/RHEL even for an unconfined user. Replace the malloc() + mprotect() combo with just mmap(), creating a private anonymous rwx mapping, which only requires the more commonly allowed "execmem" permission under SELinux (things like JIT or regex compilation need it as well). mmap() with MAP_ANONYMOUS will give us a zeroed mapping that begins on a page boundary, so the result is equivalent to the original code even without a memset() or the page-alignment dance. Verified that the test still passes on a machine with an AMD CPU that has the "ibs" CPU flag. Fixes: 35db59fa8ea2 ("perf test amd ibs: Add sample period unit test") Signed-off-by: Ondrej Mosnacek Reviewed-by: Ravi Bangoria Acked-by: Peter Zijlstra (Intel) Signed-off-by: Namhyung Kim --- tools/perf/arch/x86/tests/amd-ibs-period.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/tools/perf/arch/x86/tests/amd-ibs-period.c b/tools/perf/arch/x86/tests/amd-ibs-period.c index 6a92b3a23ed7..32713f8fcd5c 100644 --- a/tools/perf/arch/x86/tests/amd-ibs-period.c +++ b/tools/perf/arch/x86/tests/amd-ibs-period.c @@ -46,7 +46,6 @@ static int dummy_workload_1(unsigned long count) { int (*func)(void); int ret = 0; - char *p; char insn1[] = { 0xb8, 0x01, 0x00, 0x00, 0x00, /* mov 1,%eax */ 0xc3, /* ret */ @@ -59,18 +58,11 @@ static int dummy_workload_1(unsigned long count) 0xcc, /* int 3 */ }; - p = calloc(2, page_size); - if (!p) { - printf("malloc() failed. %m"); - return 1; - } - - func = (void *)((unsigned long)(p + page_size - 1) & ~(page_size - 1)); - - ret = mprotect(func, page_size, PROT_READ | PROT_WRITE | PROT_EXEC); - if (ret) { - printf("mprotect() failed. %m"); - goto out; + func = mmap(NULL, page_size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (func == MAP_FAILED) { + pr_debug("mmap() failed. %m\n"); + return -1; } if (count < 100000) @@ -93,7 +85,7 @@ static int dummy_workload_1(unsigned long count) } out: - free(p); + munmap(func, page_size); return ret; } -- cgit v1.2.3 From 047979af3bf6a118066c81099162d518de63abb1 Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Tue, 23 Jun 2026 10:58:31 +0530 Subject: perf vendor events amd: Update Zen 5 core events Update definitions for the following events. * PMCx00A - Add missing unit masks * PMCx00B - Add missing unit masks and fix descriptions * PMCx00C - Add missing unit masks * PMCx00D - Add missing unit masks * PMCx025 - Add missing unit masks and fix descriptions Fixes: 45c072f2537a ("perf vendor events amd: Add Zen 5 core events") Signed-off-by: Sandipan Das Signed-off-by: Namhyung Kim --- .../arch/x86/amdzen5/floating-point.json | 130 ++++++++++++++++++--- .../pmu-events/arch/x86/amdzen5/load-store.json | 8 +- 2 files changed, 120 insertions(+), 18 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json b/tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json index 9204bfb1d69e..569975b53cc3 100644 --- a/tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json @@ -179,6 +179,30 @@ "BriefDescription": "Retired scalar floating-point blend ops.", "UMask": "0x09" }, + { + "EventName": "fp_ops_retired_by_type.scalar_mov", + "EventCode": "0x0a", + "BriefDescription": "Retired scalar floating-point MOV ops.", + "UMask": "0x0a" + }, + { + "EventName": "fp_ops_retired_by_type.scalar_shuffle", + "EventCode": "0x0a", + "BriefDescription": "Retired scalar floating-point shuffle ops (may include instructions not necessarily thought of as including shuffles e.g. horizontal add, dot product, and certain MOV instructions).", + "UMask": "0x0b" + }, + { + "EventName": "fp_ops_retired_by_type.scalar_bfloat", + "EventCode": "0x0a", + "BriefDescription": "Retired scalar floating-point bfloat ops.", + "UMask": "0x0c" + }, + { + "EventName": "fp_ops_retired_by_type.scalar_logical", + "EventCode": "0x0a", + "BriefDescription": "Retired scalar floating-point logical ops.", + "UMask": "0x0d" + }, { "EventName": "fp_ops_retired_by_type.scalar_other", "EventCode": "0x0a", @@ -245,12 +269,24 @@ "BriefDescription": "Retired vector floating-point blend ops.", "UMask": "0x90" }, + { + "EventName": "fp_ops_retired_by_type.vector_mov", + "EventCode": "0x0a", + "BriefDescription": "Retired vector floating-point MOV ops.", + "UMask": "0xa0" + }, { "EventName": "fp_ops_retired_by_type.vector_shuffle", "EventCode": "0x0a", "BriefDescription": "Retired vector floating-point shuffle ops (may include instructions not necessarily thought of as including shuffles e.g. horizontal add, dot product, and certain MOV instructions).", "UMask": "0xb0" }, + { + "EventName": "fp_ops_retired_by_type.vector_bfloat", + "EventCode": "0x0a", + "BriefDescription": "Retired vector floating-point bfloat ops.", + "UMask": "0xc0" + }, { "EventName": "fp_ops_retired_by_type.vector_logical", "EventCode": "0x0a", @@ -278,7 +314,7 @@ { "EventName": "sse_avx_ops_retired.mmx_add", "EventCode": "0x0b", - "BriefDescription": "Retired MMX integer add.", + "BriefDescription": "Retired MMX integer add ops.", "UMask": "0x01" }, { @@ -299,16 +335,34 @@ "BriefDescription": "Retired MMX integer multiply-accumulate ops.", "UMask": "0x04" }, + { + "EventName": "sse_avx_ops_retired.mmx_aes", + "EventCode": "0x0b", + "BriefDescription": "Retired MMX integer AES ops.", + "UMask": "0x05" + }, + { + "EventName": "sse_avx_ops_retired.mmx_sha", + "EventCode": "0x0b", + "BriefDescription": "Retired MMX integer SHA ops.", + "UMask": "0x06" + }, { "EventName": "sse_avx_ops_retired.mmx_cmp", "EventCode": "0x0b", "BriefDescription": "Retired MMX integer compare ops.", "UMask": "0x07" }, + { + "EventName": "sse_avx_ops_retired.mmx_cvt", + "EventCode": "0x0b", + "BriefDescription": "Retired MMX integer convert or pack ops.", + "UMask": "0x08" + }, { "EventName": "sse_avx_ops_retired.mmx_shift", "EventCode": "0x0b", - "BriefDescription": "Retired MMX integer shift ops.", + "BriefDescription": "Retired MMX integer shift or rotate ops.", "UMask": "0x09" }, { @@ -324,9 +378,9 @@ "UMask": "0x0b" }, { - "EventName": "sse_avx_ops_retired.mmx_pack", + "EventName": "sse_avx_ops_retired.mmx_vnni", "EventCode": "0x0b", - "BriefDescription": "Retired MMX integer pack ops.", + "BriefDescription": "Retired MMX integer VNNI ops.", "UMask": "0x0c" }, { @@ -390,15 +444,15 @@ "UMask": "0x70" }, { - "EventName": "sse_avx_ops_retired.sse_avx_clm", + "EventName": "sse_avx_ops_retired.sse_avx_cvt", "EventCode": "0x0b", - "BriefDescription": "Retired SSE and AVX integer CLM ops.", + "BriefDescription": "Retired SSE and AVX integer convert or pack ops.", "UMask": "0x80" }, { "EventName": "sse_avx_ops_retired.sse_avx_shift", "EventCode": "0x0b", - "BriefDescription": "Retired SSE and AVX integer shift ops.", + "BriefDescription": "Retired SSE and AVX integer shift or rotate ops.", "UMask": "0x90" }, { @@ -414,9 +468,9 @@ "UMask": "0xb0" }, { - "EventName": "sse_avx_ops_retired.sse_avx_pack", + "EventName": "sse_avx_ops_retired.sse_avx_vnni", "EventCode": "0x0b", - "BriefDescription": "Retired SSE and AVX integer pack ops.", + "BriefDescription": "Retired SSE and AVX integer VNNI ops.", "UMask": "0xc0" }, { @@ -497,12 +551,24 @@ "BriefDescription": "Retired 128-bit packed floating-point blend ops.", "UMask": "0x09" }, + { + "EventName": "fp_pack_ops_retired.fp128_mov", + "EventCode": "0x0c", + "BriefDescription": "Retired 128-bit packed floating-point MOV ops.", + "UMask": "0x0a" + }, { "EventName": "fp_pack_ops_retired.fp128_shuffle", "EventCode": "0x0c", "BriefDescription": "Retired 128-bit packed floating-point shuffle ops (may include instructions not necessarily thought of as including shuffles e.g. horizontal add, dot product, and certain MOV instructions).", "UMask": "0x0b" }, + { + "EventName": "fp_pack_ops_retired.fp128_bfloat", + "EventCode": "0x0c", + "BriefDescription": "Retired 128-bit packed floating-point bfloat ops.", + "UMask": "0x0c" + }, { "EventName": "fp_pack_ops_retired.fp128_logical", "EventCode": "0x0c", @@ -575,12 +641,24 @@ "BriefDescription": "Retired 256-bit packed floating-point blend ops.", "UMask": "0x90" }, + { + "EventName": "fp_pack_ops_retired.fp256_mov", + "EventCode": "0x0c", + "BriefDescription": "Retired 256-bit packed floating-point MOV ops.", + "UMask": "0xa0" + }, { "EventName": "fp_pack_ops_retired.fp256_shuffle", "EventCode": "0x0c", "BriefDescription": "Retired 256-bit packed floating-point shuffle ops (may include instructions not necessarily thought of as including shuffles e.g. horizontal add, dot product, and certain MOV instructions).", "UMask": "0xb0" }, + { + "EventName": "fp_pack_ops_retired.fp256_bfloat", + "EventCode": "0x0c", + "BriefDescription": "Retired 256-bit packed floating-point bfloat ops.", + "UMask": "0xc0" + }, { "EventName": "fp_pack_ops_retired.fp256_logical", "EventCode": "0x0c", @@ -648,15 +726,15 @@ "UMask": "0x07" }, { - "EventName": "packed_int_op_type.int128_clm", + "EventName": "packed_int_op_type.int128_cvt", "EventCode": "0x0d", - "BriefDescription": "Retired 128-bit packed integer CLM ops.", + "BriefDescription": "Retired 128-bit packed integer convert or pack ops.", "UMask": "0x08" }, { "EventName": "packed_int_op_type.int128_shift", "EventCode": "0x0d", - "BriefDescription": "Retired 128-bit packed integer shift ops.", + "BriefDescription": "Retired 128-bit packed integer shift or rotate ops.", "UMask": "0x09" }, { @@ -672,9 +750,9 @@ "UMask": "0x0b" }, { - "EventName": "packed_int_op_type.int128_pack", + "EventName": "packed_int_op_type.int128_vnni", "EventCode": "0x0d", - "BriefDescription": "Retired 128-bit packed integer pack ops.", + "BriefDescription": "Retired 128-bit packed integer VNNI ops.", "UMask": "0x0c" }, { @@ -719,16 +797,34 @@ "BriefDescription": "Retired 256-bit packed integer multiply-accumulate ops.", "UMask": "0x40" }, + { + "EventName": "packed_int_op_type.int256_aes", + "EventCode": "0x0d", + "BriefDescription": "Retired 256-bit packed integer AES ops.", + "UMask": "0x50" + }, + { + "EventName": "packed_int_op_type.int256_sha", + "EventCode": "0x0d", + "BriefDescription": "Retired 256-bit packed integer SHA ops.", + "UMask": "0x60" + }, { "EventName": "packed_int_op_type.int256_cmp", "EventCode": "0x0d", "BriefDescription": "Retired 256-bit packed integer compare ops.", "UMask": "0x70" }, + { + "EventName": "packed_int_op_type.int256_cvt", + "EventCode": "0x0d", + "BriefDescription": "Retired 256-bit packed integer convert or pack ops.", + "UMask": "0x80" + }, { "EventName": "packed_int_op_type.int256_shift", "EventCode": "0x0d", - "BriefDescription": "Retired 256-bit packed integer shift ops.", + "BriefDescription": "Retired 256-bit packed integer shift or rotate ops.", "UMask": "0x90" }, { @@ -744,9 +840,9 @@ "UMask": "0xb0" }, { - "EventName": "packed_int_op_type.int256_pack", + "EventName": "packed_int_op_type.int256_vnni", "EventCode": "0x0d", - "BriefDescription": "Retired 256-bit packed integer pack ops.", + "BriefDescription": "Retired 256-bit packed integer VNNI ops.", "UMask": "0xc0" }, { diff --git a/tools/perf/pmu-events/arch/x86/amdzen5/load-store.json b/tools/perf/pmu-events/arch/x86/amdzen5/load-store.json index 06bbaea15925..b1994539ece8 100644 --- a/tools/perf/pmu-events/arch/x86/amdzen5/load-store.json +++ b/tools/perf/pmu-events/arch/x86/amdzen5/load-store.json @@ -8,9 +8,15 @@ { "EventName": "ls_locks.bus_lock", "EventCode": "0x25", - "BriefDescription": "Retired Lock instructions which caused a bus lock.", + "BriefDescription": "Retired lock instructions which caused a bus lock.", "UMask": "0x01" }, + { + "EventName": "ls_locks.all", + "EventCode": "0x25", + "BriefDescription": "Retired lock instructions of all types.", + "UMask": "0x1f" + }, { "EventName": "ls_ret_cl_flush", "EventCode": "0x26", -- cgit v1.2.3 From 6744430f106b0e46d6318d44a99cb27b0ee937ae Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Tue, 23 Jun 2026 10:58:32 +0530 Subject: perf vendor events amd: Update Zen 6 core events Update definitions for the following events. * PMCx00A - Fix descriptions * PMCx00C - Add missing unit masks * PMCx00D - Add missing unit masks and fix descriptions * PMCx013 - Fix incorrect unit masks Fixes: 2f42fb0661d9 ("perf vendor events amd: Add Zen 6 core events") Signed-off-by: Sandipan Das Signed-off-by: Namhyung Kim --- .../arch/x86/amdzen6/floating-point.json | 34 ++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/amdzen6/floating-point.json b/tools/perf/pmu-events/arch/x86/amdzen6/floating-point.json index 03cb039434de..71b883776f37 100644 --- a/tools/perf/pmu-events/arch/x86/amdzen6/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/amdzen6/floating-point.json @@ -212,7 +212,7 @@ { "EventName": "fp_ops_ret_by_type.scalar_logical", "EventCode": "0x0a", - "BriefDescription": "Retired scalar floating-point move uops.", + "BriefDescription": "Retired scalar floating-point logical uops.", "UMask": "0x0d" }, { @@ -665,6 +665,12 @@ "BriefDescription": "Retired 256-bit packed floating-point shuffle uops (may include instructions not necessarily thought of as including shuffles e.g. horizontal add, dot product, and certain MOV instructions).", "UMask": "0xb0" }, + { + "EventName": "fp_pack_ops_ret.fp256_bfloat", + "EventCode": "0x0c", + "BriefDescription": "Retired 256-bit packed floating-point bfloat uops.", + "UMask": "0xc0" + }, { "EventName": "fp_pack_ops_ret.fp256_logical", "EventCode": "0x0c", @@ -758,7 +764,7 @@ { "EventName": "fp_pack_int_ops_ret.int128_vnni", "EventCode": "0x0d", - "BriefDescription": "Retired 128-bit packed integer VNNI ops.", + "BriefDescription": "Retired 128-bit packed integer VNNI uops.", "UMask": "0x0c" }, { @@ -803,12 +809,30 @@ "BriefDescription": "Retired 256-bit packed integer multiply-accumulate uops.", "UMask": "0x40" }, + { + "EventName": "fp_pack_int_ops_ret.int256_aes", + "EventCode": "0x0d", + "BriefDescription": "Retired 256-bit packed integer AES uops.", + "UMask": "0x50" + }, + { + "EventName": "fp_pack_int_ops_ret.int256_sha", + "EventCode": "0x0d", + "BriefDescription": "Retired 256-bit packed integer SHA uops.", + "UMask": "0x60" + }, { "EventName": "fp_pack_int_ops_ret.int256_cmp", "EventCode": "0x0d", "BriefDescription": "Retired 256-bit packed integer compare uops.", "UMask": "0x70" }, + { + "EventName": "fp_pack_int_ops_ret.int256_cvt", + "EventCode": "0x0d", + "BriefDescription": "Retired 256-bit packed integer convert or pack uops.", + "UMask": "0x80" + }, { "EventName": "fp_pack_int_ops_ret.int256_shift", "EventCode": "0x0d", @@ -1083,19 +1107,19 @@ "EventName": "fp_nsq_read_stalls.fp_prf", "EventCode": "0x13", "BriefDescription": "Cycles when reads of the NSQ and writes to the floating-point or SIMD schedulers are stalled due to insufficient free physical register file (FP-PRF) entries.", - "UMask": "0x0e" + "UMask": "0x02" }, { "EventName": "fp_nsq_read_stalls.k_prf", "EventCode": "0x13", "BriefDescription": "Cycles when reads of the NSQ and writes to the floating-point or SIMD schedulers are stalled due to insufficient free mask physical register file (K-PRF) entries.", - "UMask": "0x0e" + "UMask": "0x04" }, { "EventName": "fp_nsq_read_stalls.fp_sq", "EventCode": "0x13", "BriefDescription": "Cycles when reads of the NSQ and writes to the floating-point or SIMD schedulers are stalled due to insufficient free scheduler entries.", - "UMask": "0x0e" + "UMask": "0x08" }, { "EventName": "fp_nsq_read_stalls.all", -- cgit v1.2.3 From b3665131e7a63b3ed2d91015a6db97c5f65a5328 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Wed, 24 Jun 2026 17:33:16 +0800 Subject: perf tests: Add auto counter reload (ACR) sampling test Add auto counter reload sampling test to verify that the intended event records can be captured and the self-reloaded events won't generate any records. Signed-off-by: Dapeng Mi Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/record.sh | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tools/perf/tests/shell/record.sh b/tools/perf/tests/shell/record.sh index dd90fef2088b..625240809fce 100755 --- a/tools/perf/tests/shell/record.sh +++ b/tools/perf/tests/shell/record.sh @@ -403,6 +403,48 @@ test_callgraph() { echo "Callgraph test [Success]" } +test_acr_sampling() { + events="{instructions/period=40000,acr_mask=0x2/u,cycles/period=20000,acr_mask=0x3/u}" + pebs_events="{instructions/period=40000,acr_mask=0x2/pu,cycles/period=20000,acr_mask=0x3/u}" + echo "Auto counter reload (ACR) sampling test" + if ! perf record -o "${perfdata}" -e "${events}" ${testprog} 2> /dev/null + then + echo "Auto counter reload sampling [Skipped not supported]" + return + fi + if ! perf script -i "${perfdata}" -F event | grep -q "instructions" + then + echo "Auto counter reload sampling [Failed missing instructions event]" + err=1 + return + fi + if perf script -i "${perfdata}" -F event | grep -q "cycles" + then + echo "Auto counter reload sampling [Failed cycles event shouldn't be sampled]" + err=1 + return + fi + if ! perf record -o "${perfdata}" -e "${pebs_events}" ${testprog} 2> /dev/null + then + echo "Auto counter reload PEBS sampling [Skipped not supported]" + echo "Auto counter reload sampling [Success]" + return + fi + if ! perf script -i "${perfdata}" -F event | grep -q "instructions" + then + echo "Auto counter reload PEBS sampling [Failed missing instructions event]" + err=1 + return + fi + if perf script -i "${perfdata}" -F event | grep -q "cycles" + then + echo "Auto counter reload PEBS sampling [Failed cycles event shouldn't be sampled]" + err=1 + return + fi + echo "Auto counter reload sampling [Success]" +} + test_ratio_to_prev() { echo "ratio-to-prev test" if ! perf record -o /dev/null -e "{instructions, cycles/period=100000,ratio-to-prev=0.5/}" \ @@ -458,6 +500,7 @@ test_leader_sampling test_topdown_leader_sampling test_precise_max test_callgraph +test_acr_sampling test_ratio_to_prev # restore the default value -- cgit v1.2.3 From f94563fac26912ef5a51fd16ae1d83f17b24b19d Mon Sep 17 00:00:00 2001 From: Jiawei Sun Date: Tue, 7 Jul 2026 23:38:00 +0800 Subject: perf record: fix poll storm when monitored threads exit When `perf record` samples a multi-threaded process and one of the target threads exits during the session, perf itself may start burning 100% CPU (up to 200% across two cores) until the session ends. A single dead fd is sufficient to trigger this; it can be reproduced with 15 pthreads in a compute loop where one thread exits halfway through. The root cause is two independent instances of the same defect: dead perf_event ring-buffer fds are left in a pollfd array. When a monitored thread exits, the kernel closes its ring-buffer fd, which then returns POLLHUP. POSIX specifies that poll() always reports POLLHUP and POLLERR regardless of the events mask, so any dead fd left in the array makes poll() return immediately every time, spinning in a tight loop: 3 seconds: 256,600 poll() calls, 0 context switches, only 21 write() Woken up count goes from ~0 to 1,300,000+ There are two affected poll paths, fixed together here: 1. Record main loop, via fdarray__filter() (tools/lib/api/fd/array.c). Since commit 59b4412f27f1 ("libperf: Avoid internal moving of fdarray fds") it only zeroes events/revents without setting fd to -1, so poll() keeps reporting POLLHUP for the entry. Setting fd = -1 makes poll() skip it, matching the pattern already used in the control-fd path at tools/perf/builtin-record.c:1673. 2. BPF sideband thread, perf_evlist__poll_thread() (tools/perf/util/sideband_evlist.c). This thread polls for PERF_RECORD_BPF_EVENT but, unlike the main record loop, never calls fdarray__filter() at all, so dead fds accumulate forever and it spins at 100% CPU: Before fix: dJiffies=101, wchan=0 (running) After fix: dJiffies=0, wchan=do_sys_poll (blocking) Fixed by calling the existing evlist__filter_pollfd() helper after evlist__poll(), mirroring the main record loop. is included for the POLLERR/POLLHUP macros (previously unused there). The two fixes compose: fix 1 makes poll() ignore dead fds (fd=-1); fix 2 ensures the sideband thread actually performs the filtering. Both paths are affected in all kernels from v5.1/v5.9 to the current master (7.2-rc1); the source of both functions is byte-identical across them. BPF event recording is preserved: after the fix, perf.data still contains PERF_RECORD_BPF_EVENT records and bpf_prog_info entries. Verified on perf 6.1.76, 6.6.143 and 7.2-rc1 with a minimal reproducer (Woken up 1,300,000 -> 3, CPU 100% -> 0%) and an A/B orthogonal test: keeping the unpatched binary but preventing the target thread from exiting also makes the storm disappear, confirming the trigger. Fixes: 59b4412f27f1 ("libperf: Avoid internal moving of fdarray fds") Fixes: 657ee5531903 ("perf evlist: Introduce side band thread") Signed-off-by: Jiawei Sun Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/lib/api/fd/array.c | 6 ++++++ tools/perf/util/sideband_evlist.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/tools/lib/api/fd/array.c b/tools/lib/api/fd/array.c index f0f195207fca..ffe8272af59b 100644 --- a/tools/lib/api/fd/array.c +++ b/tools/lib/api/fd/array.c @@ -122,6 +122,12 @@ int fdarray__filter(struct fdarray *fda, short revents, if (entry_destructor) entry_destructor(fda, fd, arg); + /* + * Set fd to -1 so poll() ignores this entry; otherwise + * POLLHUP/POLLERR are still reported for events=0 fds + * (POSIX: always checked), causing a poll storm. + */ + fda->entries[fd].fd = -1; fda->entries[fd].revents = fda->entries[fd].events = 0; continue; } diff --git a/tools/perf/util/sideband_evlist.c b/tools/perf/util/sideband_evlist.c index c07dacf3c54c..ba043db6cedc 100644 --- a/tools/perf/util/sideband_evlist.c +++ b/tools/perf/util/sideband_evlist.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,19 @@ static void *perf_evlist__poll_thread(void *arg) if (!draining) evlist__poll(evlist, 1000); + /* + * When a thread of the monitored target exits, its per-cpu + * ring-buffer fd is closed and starts returning POLLHUP. Such + * dead fds are never requested for POLLIN, but poll() reports + * POLLHUP/POLLERR unconditionally, so leaving them in the + * pollfd array makes the following evlist__poll() return + * immediately forever, spinning this thread at 100% CPU. + * + * Filter them out here, mirroring what the 'perf record' main + * loop does after fdarray__poll(). + */ + evlist__filter_pollfd(evlist, POLLERR | POLLHUP); + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { struct mmap *map = &evlist__mmap(evlist)[i]; union perf_event *event; -- cgit v1.2.3 From dcb87c88952046ef43cb5ba3a5b95eb29c362a16 Mon Sep 17 00:00:00 2001 From: Tanushree Shah Date: Thu, 4 Jun 2026 12:25:19 +0530 Subject: perf data convert json: Fix trace_seq memory leak in process_sample_event() Unlike the in-kernel trace_seq which uses a statically allocated buffer, the userspace traceevent library's trace_seq uses a dynamically allocated one. Therefore, every trace_seq_init() call must be paired with a trace_seq_destroy(), otherwise it produces a memory leak. In process_sample_event(), a trace_seq is initialized for each field when formatting tracepoint raw_data, but the matching trace_seq_destroy() is never called, leaking memory for every field of every sample processed. Add the missing trace_seq_destroy() after using the trace_seq buffer to properly free the allocated memory. Detected with Valgrind on a perf.data file with 2,729 tracepoint samples: Before: definitely lost: 55,537,664 bytes in 13,559 blocks After: definitely lost: 0 bytes in 0 blocks Fixes: 9d895e468429 ("perf data: Add tracepoint fields when converting to JSON") Signed-off-by: Tanushree Shah Signed-off-by: Namhyung Kim --- tools/perf/util/data-convert-json.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/data-convert-json.c b/tools/perf/util/data-convert-json.c index 40412c3dbdb2..40888b7c4467 100644 --- a/tools/perf/util/data-convert-json.c +++ b/tools/perf/util/data-convert-json.c @@ -258,6 +258,7 @@ static int process_sample_event(const struct perf_tool *tool, trace_seq_init(&s); tep_print_field(&s, sample->raw_data, fields[i]); output_json_key_string(out, true, 3, fields[i]->name, s.buffer); + trace_seq_destroy(&s); i++; } -- cgit v1.2.3 From eda39f98bbc5ce8b7b0be10193d2de38ed59da6c Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Wed, 8 Jul 2026 00:34:01 +0530 Subject: perf vendor events amd: Reintroduce deprecated Zen 5 core events Maintain backward compatibility by reintroducing the events that were previously removed by commit 047979af3bf6 ("perf vendor events amd: Update Zen 5 core events"). Also set the deprecated flag and update the descriptions to point users to the correct alternative. Reported-by: Ian Rogers Closes: https://lore.kernel.org/all/CAP-5=fV_czvd-z4N7K+_SabxuOm9UUHRyBxNuchrtAgJL3OqOw@mail.gmail.com/ Fixes: 047979af3bf6 ("perf vendor events amd: Update Zen 5 core events") Signed-off-by: Sandipan Das Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim --- .../arch/x86/amdzen5/floating-point.json | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json b/tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json index 569975b53cc3..50d38434f8d3 100644 --- a/tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json @@ -383,6 +383,13 @@ "BriefDescription": "Retired MMX integer VNNI ops.", "UMask": "0x0c" }, + { + "EventName": "sse_avx_ops_retired.mmx_pack", + "EventCode": "0x0b", + "BriefDescription": "This event is deprecated. Refer to new event sse_avx_ops_retired.mmx_vnni", + "Deprecated": "1", + "UMask": "0x0c" + }, { "EventName": "sse_avx_ops_retired.mmx_logical", "EventCode": "0x0b", @@ -449,6 +456,13 @@ "BriefDescription": "Retired SSE and AVX integer convert or pack ops.", "UMask": "0x80" }, + { + "EventName": "sse_avx_ops_retired.sse_avx_clm", + "EventCode": "0x0b", + "BriefDescription": "This event is deprecated. Refer to new event sse_avx_ops_retired.sse_avx_cvt", + "Deprecated": "1", + "UMask": "0x80" + }, { "EventName": "sse_avx_ops_retired.sse_avx_shift", "EventCode": "0x0b", @@ -473,6 +487,13 @@ "BriefDescription": "Retired SSE and AVX integer VNNI ops.", "UMask": "0xc0" }, + { + "EventName": "sse_avx_ops_retired.sse_avx_pack", + "EventCode": "0x0b", + "BriefDescription": "This event is deprecated. Refer to new event sse_avx_ops_retired.sse_avx_vnni", + "Deprecated": "1", + "UMask": "0xc0" + }, { "EventName": "sse_avx_ops_retired.sse_avx_logical", "EventCode": "0x0b", @@ -731,6 +752,13 @@ "BriefDescription": "Retired 128-bit packed integer convert or pack ops.", "UMask": "0x08" }, + { + "EventName": "packed_int_op_type.int128_clm", + "EventCode": "0x0d", + "BriefDescription": "This event is deprecated. Refer to new event packed_int_op_type.int128_cvt", + "Deprecated": "1", + "UMask": "0x08" + }, { "EventName": "packed_int_op_type.int128_shift", "EventCode": "0x0d", @@ -755,6 +783,13 @@ "BriefDescription": "Retired 128-bit packed integer VNNI ops.", "UMask": "0x0c" }, + { + "EventName": "packed_int_op_type.int128_pack", + "EventCode": "0x0d", + "BriefDescription": "This event is deprecated. Refer to new event packed_int_op_type.int128_vnni", + "Deprecated": "1", + "UMask": "0x0c" + }, { "EventName": "packed_int_op_type.int128_logical", "EventCode": "0x0d", @@ -845,6 +880,13 @@ "BriefDescription": "Retired 256-bit packed integer VNNI ops.", "UMask": "0xc0" }, + { + "EventName": "packed_int_op_type.int256_pack", + "EventCode": "0x0d", + "BriefDescription": "This event is deprecated. Refer to new event packed_int_op_type.int256_vnni", + "Deprecated": "1", + "UMask": "0xc0" + }, { "EventName": "packed_int_op_type.int256_logical", "EventCode": "0x0d", -- cgit v1.2.3 From 261210854462ef5e587eb1b740aa06dbab3b3a40 Mon Sep 17 00:00:00 2001 From: Ivan Lazaric Date: Wed, 8 Jul 2026 15:14:01 +0200 Subject: perf stat: reject --field-separator and --json-output combination Specifying --field-separator option is stating you want CSV output. Passing both --field-separator and --json-output is then stating you want output to be in CSV and JSON format at same time. Currently this combination is not rejected, and the outcome is a malformed combination of CSV and JSON output. This is because of inconsistencies in various printing functions, some of them have if-else chains that start with "Should I print JSON?", and some start with "Should I print CSV?". Example of current output: $ tools/perf/perf stat -x , -j -e cpu-migrations true {"counter-value" : "0.000000", "unit" : "", "event" : "cpu-migrations", "event-runtime" : 474817, "pcnt-running" : 100.00,, Instead reject the option combination, with a helpful error message and non-zero exit code. Example of new output: $ tools/perf/perf stat -x , -j true cannot use both --field-separator and --json-output Usage: perf stat [] [] -x, --field-separator print counts with custom separator -j, --json-output print counts in JSON format Signed-off-by: Ivan Lazaric Signed-off-by: Namhyung Kim --- tools/perf/builtin-stat.c | 7 +++++++ tools/perf/tests/shell/stat.sh | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 92cdb2df7285..3f685beba384 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -2655,6 +2655,13 @@ int cmd_stat(int argc, const char **argv) stat_config.aggr_mode = opt_aggr_mode_to_aggr_mode(&opt_mode); + if (stat_config.csv_sep && stat_config.json_output) { + fprintf(stderr, "cannot use both --field-separator and --json-output\n"); + parse_options_usage(stat_usage, stat_options, "x", 1); + parse_options_usage(NULL, stat_options, "j", 1); + goto out; + } + if (stat_config.csv_sep) { stat_config.csv_output = true; if (!strcmp(stat_config.csv_sep, "\\t")) diff --git a/tools/perf/tests/shell/stat.sh b/tools/perf/tests/shell/stat.sh index 1e17bee026bd..649de1166fed 100755 --- a/tools/perf/tests/shell/stat.sh +++ b/tools/perf/tests/shell/stat.sh @@ -535,6 +535,17 @@ test_stat_delay() { echo "stat -D test [Success]" } +test_csv_json_fail() { + echo "stat -x -j test" + if perf stat -x , -j true > /dev/null 2>&1 + then + echo "stat -x -j test [Failed - command should have errored]" + err=1 + else + echo "stat -x -j test [Success]" + fi +} + test_default_stat test_null_stat test_offline_cpu_stat @@ -551,6 +562,7 @@ test_stat_detailed test_stat_repeat test_stat_pid test_stat_delay +test_csv_json_fail cleanup exit $err -- cgit v1.2.3 From 8c5f60344b07f839267c0c835962e2206143be85 Mon Sep 17 00:00:00 2001 From: Tanushree Shah Date: Wed, 8 Jul 2026 16:56:08 +0530 Subject: perf dso: Fix kallsyms DSO detection with fallback logic The current kallsyms detection in dso__is_kallsyms() uses the dso_binary_type enum which fixes the issue of kallsyms being cached in the build-id cache for out-of-tree modules. However, during build-id injection in perf record/inject, dso_binary_type has not been explicitly set yet,so dso__binary_type() returns DSO_BINARY_TYPE__NOT_FOUND instead of DSO_BINARY_TYPE__KALLSYMS for the kernel DSO. The current check then fails to identify it as kallsyms, causing build-id symlinks to not be created in ~/.debug/.build-id/ and perf archive to fail with "Cannot stat" errors. Steps to reproduce the issue: 1. rm -rf ~/.debug/.build-id 2. perf record sleep 1 3. perf archive Fix by falling back to matching long_name against the known kallsyms strings explicitly when binary_type is not yet set (== DSO_BINARY_TYPE__NOT_FOUND). Use strcmp() for exact matching of fixed names and strict validation for guest kallsyms with embedded PID to prevent path traversal attacks. Fixes: ebf0b332732d ("perf dso: fix dso__is_kallsyms() check") Signed-off-by: Tanushree Shah Signed-off-by: Namhyung Kim --- tools/perf/util/dso.h | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 2916b954a804..55c4aaa53c38 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "build-id.h" #include "debuginfo.h" #include "mutex.h" @@ -20,6 +21,40 @@ struct perf_env; #define DSO__NAME_KALLSYMS "[kernel.kallsyms]" #define DSO__NAME_KCORE "[kernel.kcore]" +#define DSO__NAME_GUEST_KALLSYMS "[guest.kernel.kallsyms]" +#define DSO__NAME_GUEST_KALLSYMS_PID_PREFIX "[guest.kernel.kallsyms." + +/* + * Validate names of the form "[guest.kernel.kallsyms.]", where + * is the PID of the guest VM and varies per guest, so it + * cannot be matched with strcmp() against a fixed string. + * + * Every character after the fixed prefix must be a decimal digit, + * with ']' immediately terminating the digit run and nothing + * following it. This rules out '/', "..", or any other character + * being smuggled into the name. + */ +static inline bool is_guest_kallsyms_pid_name(const char *name) +{ + const size_t prefix_len = sizeof(DSO__NAME_GUEST_KALLSYMS_PID_PREFIX) - 1; + size_t digits; + + if (strncmp(name, DSO__NAME_GUEST_KALLSYMS_PID_PREFIX, prefix_len) != 0) + return false; + + digits = strspn(name + prefix_len, "0123456789"); + if (digits == 0) + return false; + + /* ']' must terminate the digit run, with nothing trailing it */ + if (name[prefix_len + digits] != ']') + return false; + + if (name[prefix_len + digits + 1] != '\0') + return false; + + return true; +} /** * enum dso_binary_type - The kind of DSO generally associated with a memory @@ -924,8 +959,28 @@ static inline bool dso__is_kcore(const struct dso *dso) static inline bool dso__is_kallsyms(const struct dso *dso) { enum dso_binary_type bt = dso__binary_type(dso); + const char *name; + + if (bt == DSO_BINARY_TYPE__KALLSYMS || bt == DSO_BINARY_TYPE__GUEST_KALLSYMS) + return true; + + if (bt != DSO_BINARY_TYPE__NOT_FOUND) + return false; + + if (!dso__kernel(dso)) + return false; + + name = dso__long_name(dso); + if (!name) + return false; + + if (!strcmp(name, DSO__NAME_KALLSYMS)) + return true; + + if (!strcmp(name, DSO__NAME_GUEST_KALLSYMS)) + return true; - return bt == DSO_BINARY_TYPE__KALLSYMS || bt == DSO_BINARY_TYPE__GUEST_KALLSYMS; + return is_guest_kallsyms_pid_name(name); } bool dso__is_object_file(const struct dso *dso); -- cgit v1.2.3 From 831068eed9202ece884ddace8fbb262d900fa1b7 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 8 Jul 2026 10:53:11 -0700 Subject: perf tests: Restore -p flag to lock contention test Commit ae42a2a2a3ae ("perf tests: Speed up lock contention analysis shell test") in linux-next heavily optimized the test runtimes by switching the workload from the default of 10 process groups down to 1 (`perf bench sched messaging -g 1`). However, this change inadvertently dropped the original `-p` flag, causing the benchmark to default to `socketpair()` instead of `pipe()`. While `socketpair()` still generates some lock events on x86, it fails to trigger enough samples on architectures like s390, causing the test suite to fail due to lack of captured data. Restore the omitted `-p` pipe flag. The test retains the massive speedups achieved through the `-g 1` scaling, while producing a massive density of lock events across all architectures to fully satisfy the BPF trace filtering logic. Fixes: ae42a2a2a3ae ("perf tests: Speed up lock contention analysis shell test") Signed-off-by: Ian Rogers Tested-by: Thomas Richter Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/lock_contention.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/lock_contention.sh b/tools/perf/tests/shell/lock_contention.sh index ba598370be73..5df9a0cd48a3 100755 --- a/tools/perf/tests/shell/lock_contention.sh +++ b/tools/perf/tests/shell/lock_contention.sh @@ -11,7 +11,8 @@ errout=$(mktemp /tmp/__perf_test.errout.XXXXX) # Workload to generate lock contention. # Using 1 group (-g 1) keeps runtime low while generating sufficient lock events. -msg_workload="perf bench sched messaging -g 1" +# We include -p (pipes) because socketpairs don't generate enough lock events on s390. +msg_workload="perf bench sched messaging -g 1 -p" cleanup() { rm -f ${perfdata} -- cgit v1.2.3 From d3c9fca531e2465f3a8f585965f3d10e1a6595ff Mon Sep 17 00:00:00 2001 From: Tengda Wu Date: Wed, 1 Jul 2026 03:53:35 +0000 Subject: perf capstone: Fix kernel map reference count leak In print_capstone_detail(), maps__find() is used to locate the kernel map. This function increments the reference count of the found map object. However, the current implementation fails to call map__put() after the map is no longer needed, leading to a reference count leak. Fix this by adding a map__put(map) call to properly release the reference after use. Fixes: 92dfc59463d5 ("perf annotate: Add symbol name when using capstone") Signed-off-by: Tengda Wu Signed-off-by: Namhyung Kim --- tools/perf/util/capstone.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c index 5ad537fea436..9bba78ee0c5a 100644 --- a/tools/perf/util/capstone.c +++ b/tools/perf/util/capstone.c @@ -302,6 +302,7 @@ static void print_capstone_detail(struct cs_insn *insn, char *buf, size_t len, for (i = 0; i < insn->detail->x86.op_count; i++) { struct cs_x86_op *op = &insn->detail->x86.operands[i]; u64 orig_addr; + struct map *found_map = NULL; if (op->type != X86_OP_MEM) continue; @@ -317,19 +318,22 @@ static void print_capstone_detail(struct cs_insn *insn, char *buf, size_t len, if (dso__kernel(map__dso(map))) { /* * The kernel maps can be split into sections, let's - * find the map first and the search the symbol. + * find the map first and then search the symbol. */ - map = maps__find(map__kmaps(map), addr); - if (map == NULL) + found_map = maps__find(map__kmaps(map), addr); + if (found_map == NULL) continue; + map = found_map; } /* convert it to map-relative address for search */ addr = map__map_ip(map, addr); sym = map__find_symbol(map, addr); - if (sym == NULL) + if (sym == NULL) { + map__put(found_map); continue; + } if (addr == sym->start) { scnprintf(buf, len, "\t# %"PRIx64" <%s>", @@ -338,6 +342,7 @@ static void print_capstone_detail(struct cs_insn *insn, char *buf, size_t len, scnprintf(buf, len, "\t# %"PRIx64" <%s+%#"PRIx64">", orig_addr, sym->name, addr - sym->start); } + map__put(found_map); break; } } -- cgit v1.2.3 From fb4751e79c45cb48cff1c1d86b10a9cc6f6612fe Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 9 Jul 2026 22:39:06 -0700 Subject: perf record: Fix teardown hang on system-wide multi-threaded sessions Under system-wide (-a) parallel streaming mode (--threads=cpu), background recording threads can be inundated by a continuous firehose of hardware samples generated by the OS. In this state, a background thread's local hit count remains unequal to its sample count, causing it to bypass the blocking fdarray__poll() call entirely on each iteration of its recording loop. Because the termination check relies on the POLLHUP event status populated specifically by fdarray__poll(), bypassing it prevents the background thread from ever recognizing that its control pipe was closed by the main thread. This traps the background thread in an infinite recording loop, hanging the main thread indefinitely as it awaits a termination acknowledgment that never arrives. Ensure teardown completion by adding explicit evlist__disable() calls in the main thread's cleanup paths at out_child: and out_child_no_flush:. Additionally, patch fdarray__filter() to respect the fdarray_flag__nonfilterable flag, preventing it from incorrectly setting the background thread's control pipe file descriptor to -1 and clearing its revents mask upon processing termination POLLHUP signals. Fixes: f94563fac269 ("perf record: fix poll storm when monitored threads exit") Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/lib/api/fd/array.c | 6 ++++-- tools/perf/builtin-record.c | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/lib/api/fd/array.c b/tools/lib/api/fd/array.c index ffe8272af59b..16a047f1906e 100644 --- a/tools/lib/api/fd/array.c +++ b/tools/lib/api/fd/array.c @@ -115,6 +115,9 @@ int fdarray__filter(struct fdarray *fda, short revents, return 0; for (fd = 0; fd < fda->nr; ++fd) { + if (fda->priv[fd].flags & fdarray_flag__nonfilterable) + continue; + if (!fda->entries[fd].events) continue; @@ -132,8 +135,7 @@ int fdarray__filter(struct fdarray *fda, short revents, continue; } - if (!(fda->priv[fd].flags & fdarray_flag__nonfilterable)) - ++nr; + ++nr; } return nr; diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ebd3ed0c9b3e..d1276382b77a 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -2890,11 +2890,13 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) record__synthesize_workload(rec, true); out_child: + evlist__disable(rec->evlist); record__stop_threads(rec); record__mmap_read_all(rec, true); goto out_free_threads; out_child_no_flush: /* mmap read already failed — retrying would just fail again */ + evlist__disable(rec->evlist); record__stop_threads(rec); out_free_threads: record__free_thread_data(rec); -- cgit v1.2.3 From c25a46dc6304000fffa9960cfb1f8fc296aa69a3 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 4 Jun 2026 23:24:18 -0700 Subject: perf clang-format: Prioritize Python.h and expand other categories This commit updates the .clang-format rules for the perf tools. It prioritizes Python.h sorting and expands the regex lists for C standard library and OS specific headers. - Prioritize Python.h by sorting it first (Priority -1), ensuring it is sorted before even the main header (Priority 0). - Keep other header priorities (1 and 2) to maintain their relative order. - Sanity check and complete "C Standard Library Headers" up to C23 (added stdbit.h, stdckdint.h). - Sanity check and complete "OS/System-Specific Headers" based on actual usage in tools/perf (added asm-generic, uapi, and various flat POSIX/system headers). Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/.clang-format | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/perf/.clang-format b/tools/perf/.clang-format index 902b2f7456f6..e4cff363a603 100644 --- a/tools/perf/.clang-format +++ b/tools/perf/.clang-format @@ -2,15 +2,18 @@ BasedOnStyle: InheritParentConfig SortIncludes: true IncludeBlocks: Regroup IncludeCategories: + # Python.h must be first + - Regex: '^' + Priority: -1 # Implicitly the corresponding header for the C file has Priority 0 # C Standard Library Headers - - Regex: '^<(assert|complex|ctype|errno|fenv|float|inttypes|iso646|limits|locale|math|setjmp|signal|stdalign|stdarg|stdatomic|stdbool|stddef|stdint|stdio|stdlib|stdnoreturn|string|tgmath|threads|time|uchar|wchar|wctype)\.h>' + - Regex: '^<(assert|complex|ctype|errno|fenv|float|inttypes|iso646|limits|locale|math|setjmp|signal|stdalign|stdarg|stdatomic|stdbit|stdbool|stdckdint|stddef|stdint|stdio|stdlib|stdnoreturn|string|tgmath|threads|time|uchar|wchar|wctype)\.h>' Priority: 1 # OS/System-Specific Headers (directories) - - Regex: '^<(sys|linux|asm|arpa|net|netinet|x86_64|machine)/.*>' + - Regex: '^<(arpa|asm|asm-generic|linux|machine|net|netinet|sys|uapi|x86_64)/.*>' Priority: 2 # OS/System-Specific Headers (POSIX/System flat headers) - - Regex: '^<(unistd|pthread|fcntl|dirent|dlfcn|poll|sched|semaphore|spawn|syslog|termios|pwd|grp|netdb|sysexits|err|paths|pty|utmp|resolv|ifaddrs|elf|libelf|gelf)\.h>' + - Regex: '^<(aio|byteswap|dirent|dlfcn|elf|endian|err|execinfo|fcntl|features|fnmatch|ftw|gelf|getopt|grp|ifaddrs|libelf|libgen|malloc|memory|mntent|netdb|numa|numaif|paths|poll|pthread|pty|pwd|regex|resolv|sched|semaphore|spawn|strings|syscall|sysexits|syslog|termios|unistd|utmp|x86intrin)\.h>' Priority: 2 # Third-Party Library Headers - Regex: '^<.*>' -- cgit v1.2.3 From ef3af1df4f3372bd8ad47619452a283048b3bc8d Mon Sep 17 00:00:00 2001 From: Yu Peng Date: Tue, 2 Jun 2026 16:11:04 +0800 Subject: perf metricgroup: Fix metric expression copy leaks metricgroup__copy_metric_events() allocates a new metric expression and duplicates metric_name before linking the expression into the destination metric event. Free new_expr when strdup() fails, and free the duplicated metric_name on the later error paths. Fixes: b85a4d61d302 ("perf metric: Allow modifiers on metrics") Signed-off-by: Yu Peng Signed-off-by: Namhyung Kim --- tools/perf/util/metricgroup.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 69bfa2a723b2..5a60cb95e31c 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -1693,8 +1693,10 @@ int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp, new_expr->metric_expr = old_expr->metric_expr; new_expr->metric_threshold = old_expr->metric_threshold; new_expr->metric_name = strdup(old_expr->metric_name); - if (!new_expr->metric_name) + if (!new_expr->metric_name) { + free(new_expr); return -ENOMEM; + } new_expr->metric_unit = old_expr->metric_unit; new_expr->runtime = old_expr->runtime; @@ -1707,6 +1709,7 @@ int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp, alloc_size = sizeof(*new_expr->metric_refs); new_expr->metric_refs = calloc(nr + 1, alloc_size); if (!new_expr->metric_refs) { + zfree(&new_expr->metric_name); free(new_expr); return -ENOMEM; } @@ -1723,6 +1726,7 @@ int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp, alloc_size = sizeof(*new_expr->metric_events); new_expr->metric_events = calloc(nr + 1, alloc_size); if (!new_expr->metric_events) { + zfree(&new_expr->metric_name); zfree(&new_expr->metric_refs); free(new_expr); return -ENOMEM; @@ -1733,6 +1737,7 @@ int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp, evsel = old_expr->metric_events[idx]; evsel = evlist__find_evsel(evlist, evsel->core.idx); if (evsel == NULL) { + zfree(&new_expr->metric_name); zfree(&new_expr->metric_events); zfree(&new_expr->metric_refs); free(new_expr); -- cgit v1.2.3 From e83fd0f637c46d4abb0b0cb9d057268a018122b0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 6 Jul 2026 17:03:57 -0700 Subject: perf build: Do not pass -static to dlfilters The recent commit caused a failure in make build-test for static builds. Let's not pass -static the option to dlfilters which is dynamically loaded as it's hard-coded with -shared even for static builds. Tested-by: Leo Yan Cc: Trevor Allison Fixes: e1065ed188cf ("perf build: Add LDFLAGS to dlfilters .so link") Signed-off-by: Namhyung Kim --- tools/perf/Makefile.perf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 2b53d9e0c73b..0031112c036e 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -680,7 +680,7 @@ $(OUTPUT)dlfilters/%.o: dlfilters/%.c include/perf/perf_dlfilter.h .SECONDARY: $(DLFILTERS:.so=.o) $(OUTPUT)dlfilters/%.so: $(OUTPUT)dlfilters/%.o - $(QUIET_LINK)$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -shared -o $@ $< + $(QUIET_LINK)$(CC) $(filter-out -static,$(LDFLAGS)) $(EXTRA_CFLAGS) -shared -o $@ $< ifndef NO_JVMTI LIBJVMTI_IN := $(OUTPUT)jvmti/jvmti-in.o -- cgit v1.2.3 From 757155c142f2bc9793e888ab101a5eea2d53f8f8 Mon Sep 17 00:00:00 2001 From: Dmitry Ilvokhin Date: Wed, 8 Jul 2026 13:38:33 +0000 Subject: perf record: Return the written size from process_comp_header() process_comp_header() is called from zstd_compress_stream_to_records() twice per record: once with data_size == 0 to write the record header, and once with the payload size to finalize it. It returns the increment it was passed, and the loop separately decides whether a record still fits by comparing the remaining 'dst_size' against the header size. With the fit check split from the code that writes the record, process_comp_header() cannot reject a record on its own, so any bytes it writes into 'dst' have to be bounds-checked by the caller instead of where they are produced. Pass the space left in 'dst' to process_comp_header(), let it return the number of bytes written or -1 when the header does not fit, and account the compressed payload in the loop. No functional change intended. Signed-off-by: Dmitry Ilvokhin Signed-off-by: Namhyung Kim --- tools/perf/builtin-record.c | 17 +++++++++++++---- tools/perf/util/compress.h | 6 ++++-- tools/perf/util/zstd.c | 25 ++++++++++++++----------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d1276382b77a..294bdd4b8d00 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1592,16 +1592,25 @@ static void record__adjust_affinity(struct record *rec, struct mmap *map) } } -static size_t process_comp_header(void *record, size_t increment) +/* + * Called once with data_size == 0 to start a record, then once with + * data_size == compressed payload size to finalize. + * Returns the bytes written, or -1 if it won't fit. + */ +static ssize_t process_comp_header(void *record, size_t dst_size, + size_t data_size) { struct perf_record_compressed2 *event = record; size_t size = sizeof(*event); - if (increment) { - event->header.size += increment; - return increment; + if (data_size) { + event->header.size += data_size; + return 0; } + if (size > dst_size) + return -1; + event->header.type = PERF_RECORD_COMPRESSED2; event->header.size = size; diff --git a/tools/perf/util/compress.h b/tools/perf/util/compress.h index 6cfecfca16f2..ec6c38129e24 100644 --- a/tools/perf/util/compress.h +++ b/tools/perf/util/compress.h @@ -54,7 +54,8 @@ int zstd_fini(struct zstd_data *data); ssize_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size, void *src, size_t src_size, size_t max_record_size, - size_t process_header(void *record, size_t increment)); + ssize_t process_header(void *record, size_t dst_size, + size_t data_size)); size_t zstd_decompress_stream(struct zstd_data *data, void *src, size_t src_size, void *dst, size_t dst_size); @@ -75,7 +76,8 @@ ssize_t zstd_compress_stream_to_records(struct zstd_data *data __maybe_unused, void *dst __maybe_unused, size_t dst_size __maybe_unused, void *src __maybe_unused, size_t src_size __maybe_unused, size_t max_record_size __maybe_unused, - size_t process_header(void *record, size_t increment) __maybe_unused) + ssize_t process_header(void *record, size_t dst_size, + size_t data_size) __maybe_unused) { return 0; } diff --git a/tools/perf/util/zstd.c b/tools/perf/util/zstd.c index 21a0eb58597c..d98014902f01 100644 --- a/tools/perf/util/zstd.c +++ b/tools/perf/util/zstd.c @@ -31,9 +31,11 @@ int zstd_fini(struct zstd_data *data) ssize_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size, void *src, size_t src_size, size_t max_record_size, - size_t process_header(void *record, size_t increment)) + ssize_t process_header(void *record, size_t dst_size, + size_t data_size)) { - size_t ret, size, compressed = 0; + size_t ret, compressed = 0; + ssize_t size; ZSTD_inBuffer input = { src, src_size, 0 }; ZSTD_outBuffer output; void *record; @@ -55,12 +57,9 @@ ssize_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_ while (input.pos < input.size) { record = dst; - /* process_header writes the event header into record */ - if (dst_size < sizeof(struct perf_event_header)) - goto reset; - size = process_header(record, 0); + size = process_header(record, dst_size, 0); /* Output buffer full — cannot fit even the record header */ - if (size > dst_size) + if (size < 0) goto reset; compressed += size; dst += size; @@ -74,17 +73,21 @@ ssize_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_ (long)src_size, ZSTD_getErrorName(ret)); goto reset; } - size = output.pos; + compressed += output.pos; + dst += output.pos; + dst_size -= output.pos; /* * No progress: ZSTD couldn't emit any bytes into the * remaining output buffer. Calling process_header - * with size=0 would re-trigger header initialization, + * with output.pos=0 would re-trigger header initialization, * double-subtracting the header size from dst_size and * underflowing the unsigned counter. */ - if (size == 0) + if (output.pos == 0) + goto reset; + size = process_header(record, dst_size, output.pos); + if (size < 0) goto reset; - size = process_header(record, size); compressed += size; dst += size; dst_size -= size; -- cgit v1.2.3 From ad40a000ea598f316ddc0e81e5acc77cc3b1fae0 Mon Sep 17 00:00:00 2001 From: Dmitry Ilvokhin Date: Wed, 8 Jul 2026 13:38:34 +0000 Subject: perf record: Fix multiple PERF_RECORD_COMPRESSED2 records per push With Zstd compression enabled ('perf record -z'), a single mmap push whose compressed output exceeds the maximum record size makes zstd_compress_stream_to_records() emit several PERF_RECORD_COMPRESSED2 records back to back. record__pushfn() however rewrote only the first record's header to describe the whole blob as one record: event->data_size = compressed - sizeof(struct perf_record_compressed2); event->header.size = PERF_ALIGN(compressed, sizeof(u64)); padding = event->header.size - compressed; ... record__write(rec, map, &pad, padding); perf_event_header::size is a __u16, so once the compressed blob no longer fits in it the header.size assignment truncates and 'padding' (size_t) underflows. write() is then handed that bogus length and fails with EFAULT, aborting the recording: failed to write perf data, error: Bad address The bytes that did reach the file are mis-framed, so reading it back cannot be decompressed. This is easy to hit with a high event rate and a large buffer, e.g.: perf record -z -F max -m 32M --per-thread -- perf test -w thloop 5 1 The single-record fixup is wrong by construction: because header.size is 16 bits a compressed record cannot exceed 64KB, so the compressor must split a push into a chain of records, and the session reader already consumes them as such. Frame each record where it is produced instead: make process_comp_header() set the per-record data_size, 8-byte-align header.size and zero the trailing padding, and let record__pushfn() write the resulting blob, as the AIO path already does. Reduce max_record_size by sizeof(u64) so the per-record alignment padding cannot push header.size past its u16 field. process_comp_header() returns -1 when that padding would not fit the space left in 'dst', so the compressor stops instead of overrunning the output buffer. There is no on-disk format change; a perf.data written by the fixed tool is still read by existing perf. Fixes: 208c0e168344 ("perf record: Add 8-byte aligned event type PERF_RECORD_COMPRESSED2") Reported-by: Farid Zakaria Signed-off-by: Dmitry Ilvokhin Signed-off-by: Namhyung Kim --- tools/perf/builtin-record.c | 38 ++++++------- .../shell/record+zstd_comp_decomp_multi_record.sh | 63 ++++++++++++++++++++++ 2 files changed, 83 insertions(+), 18 deletions(-) create mode 100755 tools/perf/tests/shell/record+zstd_comp_decomp_multi_record.sh diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 294bdd4b8d00..f58d7e3c7879 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -64,6 +64,7 @@ #include #include #include +#include #ifndef HAVE_GETTID #include #endif @@ -653,27 +654,14 @@ static int record__pushfn(struct mmap *map, void *to, void *bf, size_t size) struct record *rec = to; if (record__comp_enabled(rec)) { - struct perf_record_compressed2 *event = map->data; - size_t padding = 0; - u8 pad[8] = {0}; ssize_t compressed = zstd_compress(rec->session, map, map->data, mmap__mmap_len(map), bf, size); if (compressed < 0) return (int)compressed; - bf = event; thread->samples++; - - /* - * The record from `zstd_compress` is not 8 bytes aligned, which would cause asan - * error. We make it aligned here. - */ - event->data_size = compressed - sizeof(struct perf_record_compressed2); - event->header.size = PERF_ALIGN(compressed, sizeof(u64)); - padding = event->header.size - compressed; - return record__write(rec, map, bf, compressed) || - record__write(rec, map, &pad, padding); + return record__write(rec, map, map->data, compressed); } thread->samples++; @@ -1594,7 +1582,8 @@ static void record__adjust_affinity(struct record *rec, struct mmap *map) /* * Called once with data_size == 0 to start a record, then once with - * data_size == compressed payload size to finalize. + * data_size == compressed payload size to finalize and 8-byte-pad it + * (unaligned records trip ASan in the reader). * Returns the bytes written, or -1 if it won't fit. */ static ssize_t process_comp_header(void *record, size_t dst_size, @@ -1604,8 +1593,15 @@ static ssize_t process_comp_header(void *record, size_t dst_size, size_t size = sizeof(*event); if (data_size) { - event->header.size += data_size; - return 0; + size_t padding; + + event->data_size = data_size; + event->header.size = PERF_ALIGN(size + data_size, sizeof(u64)); + padding = event->header.size - size - data_size; + if (padding > dst_size) + return -1; + memset(record + size + data_size, 0, padding); + return padding; } if (size > dst_size) @@ -1613,6 +1609,7 @@ static ssize_t process_comp_header(void *record, size_t dst_size, event->header.type = PERF_RECORD_COMPRESSED2; event->header.size = size; + event->data_size = 0; return size; } @@ -1621,7 +1618,12 @@ static ssize_t zstd_compress(struct perf_session *session, struct mmap *map, void *dst, size_t dst_size, void *src, size_t src_size) { ssize_t compressed; - size_t max_record_size = PERF_SAMPLE_MAX_SIZE - sizeof(struct perf_record_compressed2) - 1; + /* + * Reserve space so per-record PERF_ALIGN() padding keeps header.size + * within u16. + */ + size_t max_record_size = PERF_SAMPLE_MAX_SIZE + - sizeof(struct perf_record_compressed2) - sizeof(u64); struct zstd_data *zstd_data = &session->zstd_data; if (map && map->file) diff --git a/tools/perf/tests/shell/record+zstd_comp_decomp_multi_record.sh b/tools/perf/tests/shell/record+zstd_comp_decomp_multi_record.sh new file mode 100755 index 000000000000..c05ace8214ca --- /dev/null +++ b/tools/perf/tests/shell/record+zstd_comp_decomp_multi_record.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# Zstd perf.data compression/decompression of multi-record data +# SPDX-License-Identifier: GPL-2.0 + +perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) +recout=$(mktemp /tmp/__perf_test.zstd.rec.XXXXX) +injout=$(mktemp /tmp/__perf_test.zstd.inj.XXXXX) +perf_tool=perf + +cleanup() { + rm -f "${perfdata}" "${perfdata}".old "${perfdata}".decomp "${recout}" "${injout}" +} +trap cleanup EXIT TERM INT + +skip_if_no_z_record() { + $perf_tool record -h 2>&1 | grep -q -- '-z, --compression-level' +} + +collect_z_record() { + echo "Collecting compressed record file:" + [ "$(uname -m)" != s390x ] && gflag='-g' + $perf_tool record -o "${perfdata}" $gflag -z -F max -m 32M --per-thread -- \ + $perf_tool test -w thloop 5 1 \ + >/dev/null 2>"${recout}" +} + +check_record() { + echo "Checking record did not fail to write data:" + if grep -q "failed to write perf data" "${recout}"; then + cat "${recout}" + return 1 + fi +} + +check_decompress() { + echo "Checking compressed file decompresses cleanly:" + if ! $perf_tool inject -i "${perfdata}" -o "${perfdata}".decomp 2>"${injout}"; then + cat "${injout}" + return 1 + fi + if grep -Eqi "decompress|corrupt|failed to process type" "${injout}"; then + cat "${injout}" + return 1 + fi +} + +skip_if_no_z_record || exit 2 +collect_z_record +check_record || exit 1 + +# Need >1 record, else the multi-record path wasn't exercised. +# Skip rather than pass/fail spuriously. +nr=$($perf_tool report -i "${perfdata}" --stats 2>/dev/null | + awk '/COMPRESSED2 events:/ { print $3 }') +if [ -z "${nr}" ] || [ "${nr}" -lt 2 ]; then + echo "less than two compressed records (${nr:-0}), skipping" + exit 2 +fi +echo "Produced ${nr} compressed records" + +check_decompress +err=$? +exit $err -- cgit v1.2.3 From 17e3978f3ad1c6c4c9aca009a5081c6b0ebb5491 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Tue, 14 Jul 2026 16:28:10 +0800 Subject: perf test: Remove duplicate include of util/term.h Remove duplicate inclusion of util/term.h in builtin-test.c to clean up redundant code. Signed-off-by: Chen Ni Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/tests/builtin-test.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 7d18cb6021d3..41dcfbf874f0 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -15,7 +15,6 @@ #include #include -#include "util/term.h" #include #include #include -- cgit v1.2.3 From ea46211d7e9a2210b62c40e56b2d6540c0b4b083 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Wed, 8 Jul 2026 13:32:26 +0800 Subject: perf jevents: Add Intel OMR MSR mappings New OMR MSRs are introduced for OMR events on DMR and NVL. Perf continues to reuse the existing offcore_rsp attribute to encode the MSR value, similar to existing OCR event handling. Add the corresponding OMR MSR mappings in lookup_msr() so jevents can translate these events and generate the correct offcore_rsp attribute. Link: https://lore.kernel.org/all/20260114011750.350569-2-dapeng1.mi@linux.intel.com/ Signed-off-by: Dapeng Mi Signed-off-by: Namhyung Kim --- tools/perf/pmu-events/jevents.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py index 376dc2d24162..2bb51cc621b5 100755 --- a/tools/perf/pmu-events/jevents.py +++ b/tools/perf/pmu-events/jevents.py @@ -249,6 +249,10 @@ class JsonEvent: 0x3F6: 'ldlat=', 0x1A6: 'offcore_rsp=', 0x1A7: 'offcore_rsp=', + 0x3E0: 'offcore_rsp=', + 0x3E1: 'offcore_rsp=', + 0x3E2: 'offcore_rsp=', + 0x3E3: 'offcore_rsp=', 0x3F7: 'frontend=', } return msrmap[int(num.split(',', 1)[0], 0)] -- cgit v1.2.3 From d30f2d869b6a2e985351867424037eb7bcb57386 Mon Sep 17 00:00:00 2001 From: Hongfu Li Date: Mon, 13 Jul 2026 17:36:26 +0800 Subject: perf doc: Fix mmap failure checks in topdown example Use MAP_FAILED instead of NULL to detect mmap errors, and fix the slots_p variable name typo in the sample code. Signed-off-by: Hongfu Li Signed-off-by: Namhyung Kim --- tools/perf/Documentation/topdown.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/topdown.txt b/tools/perf/Documentation/topdown.txt index 5c17fff694ee..fd4214f9a7b0 100644 --- a/tools/perf/Documentation/topdown.txt +++ b/tools/perf/Documentation/topdown.txt @@ -87,7 +87,7 @@ if (slots_fd < 0) /* Memory mapping the fd permits _rdpmc calls from userspace */ void *slots_p = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, slots_fd, 0); -if (!slot_p) +if (slots_p == MAP_FAILED) .... error ... /* @@ -107,7 +107,7 @@ if (metrics_fd < 0) /* Memory mapping the fd permits _rdpmc calls from userspace */ void *metrics_p = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, metrics_fd, 0); -if (!metrics_p) +if (metrics_p == MAP_FAILED) ... error ... Note: the file descriptors returned by the perf_event_open calls must be memory -- cgit v1.2.3 From 4968708beaad53940b67e4952e34a97d8768091d Mon Sep 17 00:00:00 2001 From: Hongling Zeng Date: Fri, 10 Jul 2026 16:01:40 +0800 Subject: perf: evsel: Fix error handling in tp_format lookup In evsel__tp_format(), when trace_event__tp_format*() returns an error, IS_ERR() checks the local variable 'tp_format', but PTR_ERR() incorrectly uses 'evsel->tp_format' which hasn't been assigned yet. Fix this by using PTR_ERR(tp_format) to extract the error code from the correct variable. Fixes: 6c8310e8380d ("perf evsel: Allow evsel__newtp without libtraceevent") Signed-off-by: Hongling Zeng Signed-off-by: Namhyung Kim --- tools/perf/util/evsel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index d0484e4ee679..3404c40dee34 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -711,7 +711,7 @@ struct tep_event *evsel__tp_format(struct evsel *evsel) tp_format = trace_event__tp_format(evsel->tp_sys, evsel->tp_name); if (IS_ERR(tp_format)) { - int err = -PTR_ERR(evsel->tp_format); + int err = -PTR_ERR(tp_format); errno = err; pr_err("Error getting tracepoint format '%s': %m\n", -- cgit v1.2.3 From 12038480d7e76c38d8ab2031c36cf8c96f3e0485 Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Mon, 13 Jul 2026 11:17:46 -0700 Subject: perf vendor events intel: Update alderlake events from 1.39 to 1.40 The updated events were published in: https://github.com/intel/perfmon/commit/7a14cc8feaf86772deb6708e96c8e9fee6d5b1ca Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Signed-off-by: Namhyung Kim --- .../pmu-events/arch/x86/alderlake/adl-metrics.json | 80 +++++++++++----------- .../perf/pmu-events/arch/x86/alderlake/cache.json | 36 ++++++++++ .../arch/x86/alderlake/metricgroups.json | 2 +- .../pmu-events/arch/x86/alderlake/pipeline.json | 6 +- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 5 files changed, 82 insertions(+), 44 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json b/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json index cae7c0cf02f2..e76d679a784b 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json @@ -800,16 +800,16 @@ }, { "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_miss_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_uc_bound", "Unit": "cpu_core" }, { "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_miss_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", "MetricName": "tma_bottleneck_data_cache_memory_latency", "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", @@ -835,7 +835,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", "MetricThreshold": "tma_bottleneck_memory_data_tlbs > 20", @@ -844,7 +844,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", "MetricThreshold": "tma_bottleneck_memory_synchronization > 10", @@ -1012,13 +1012,13 @@ "Unit": "cpu_core" }, { - "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses", + "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to L3 data-sharing accesses", "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "24 * tma_info_system_core_frequency * (cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD@ + cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD@ * (1 - cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM@ / (cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM@ + cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD@))) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "BvMS;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_data_sharing", "MetricThreshold": "tma_data_sharing > 0.05 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses. Data shared by multiple Logical Processors (even just read shared) may cause increased access latency due to cache coherency. Excessive data sharing can drastically harm multithreaded performance. Sample with: MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_false_sharing, tma_machine_clears, tma_remote_cache", + "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to L3 data-sharing accesses. Data shared by multiple Logical Processors (even just read shared) may cause increased access latency due to cache coherency. Excessive data sharing can drastically harm multithreaded performance. Sample with: MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_false_sharing, tma_machine_clears, tma_remote_cache", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -1042,16 +1042,6 @@ "ScaleUnit": "100%", "Unit": "cpu_core" }, - { - "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", - "MetricExpr": "cpu_core@MEMORY_ACTIVITY.STALLS_L3_MISS@ / tma_info_thread_clks", - "MetricGroup": "MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", - "MetricName": "tma_dram_bound", - "MetricThreshold": "tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", - "PublicDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads. Better caching can improve the latency and increase performance. Sample with: MEM_LOAD_RETIRED.L3_MISS", - "ScaleUnit": "100%", - "Unit": "cpu_core" - }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to DSB (decoded uop cache) fetch pipeline", "MetricExpr": "(cpu_core@IDQ.DSB_CYCLES_ANY@ - cpu_core@IDQ.DSB_CYCLES_OK@) / tma_info_core_core_clks / 2", @@ -1108,7 +1098,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores, tma_uc_bound", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -1426,7 +1416,7 @@ }, { "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded ICache; or Uop Cache)", - "MetricExpr": "cpu_core@IDQ.DSB_UOPS@ / cpu_core@UOPS_ISSUED.ANY@", + "MetricExpr": "cpu_core@IDQ.DSB_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@LSD.UOPS@ + cpu_core@IDQ.MITE_UOPS@ + cpu_core@IDQ.MS_UOPS@)", "MetricGroup": "DSB;Fed;FetchBW;tma_issueFB", "MetricName": "tma_info_frontend_dsb_coverage", "MetricThreshold": "tma_info_frontend_dsb_coverage < 0.7 & tma_info_thread_ipc / 6 > 0.35", @@ -1485,7 +1475,7 @@ }, { "BriefDescription": "Fraction of Uops delivered by the LSD (Loop Stream Detector; aka Loop Cache)", - "MetricExpr": "cpu_core@LSD.UOPS@ / cpu_core@UOPS_ISSUED.ANY@", + "MetricExpr": "cpu_core@LSD.UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@LSD.UOPS@ + cpu_core@IDQ.MITE_UOPS@ + cpu_core@IDQ.MS_UOPS@)", "MetricGroup": "Fed;LSD", "MetricName": "tma_info_frontend_lsd_coverage", "Unit": "cpu_core" @@ -1629,6 +1619,15 @@ "PublicDescription": "Instructions per taken branch. Related metrics: tma_dsb_switches, tma_fetch_bandwidth, tma_info_botlnk_l2_dsb_bandwidth, tma_info_botlnk_l2_dsb_misses, tma_info_frontend_dsb_coverage, tma_lcp", "Unit": "cpu_core" }, + { + "BriefDescription": "AVX preserve/restore assists per kilo instruction", + "MetricExpr": "1e3 * cpu_core@ASSISTS.SSE_AVX_MIX@ / cpu_core@INST_RETIRED.ANY@", + "MetricGroup": "tma_issueMV", + "MetricName": "tma_info_inst_mix_vectormixpki", + "MetricThreshold": "tma_info_inst_mix_vectormixpki > 0.05", + "PublicDescription": "AVX preserve/restore assists per kilo instruction. Related metrics: tma_mixing_vectors, tma_ms_switches", + "Unit": "cpu_core" + }, { "BriefDescription": "Average per-core data fill bandwidth to the L1 data cache [GB / sec]", "MetricExpr": "tma_info_memory_l1d_cache_fill_bw", @@ -1850,7 +1849,7 @@ "Unit": "cpu_core" }, { - "BriefDescription": "Mem;Backend;CacheHits", + "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is execution) per physical core", "MetricExpr": "cpu_core@UOPS_EXECUTED.THREAD@ / (cpu_core@UOPS_EXECUTED.CORE_CYCLES_GE_1@ / 2 if #SMT_on else cpu_core@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute", @@ -1935,7 +1934,7 @@ "MetricExpr": "64 * (UNC_ARB_TRK_REQUESTS.ALL + UNC_ARB_COH_TRK_REQUESTS.ALL) / 1e6 / tma_info_system_time / 1e3", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full", + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full, tma_uc_bound", "Unit": "cpu_core" }, { @@ -2029,13 +2028,6 @@ "MetricName": "tma_info_system_turbo_utilization", "Unit": "cpu_core" }, - { - "BriefDescription": "Measured Average Uncore Frequency for the SoC [GHz]", - "MetricExpr": "tma_info_system_socket_clks / 1e9 / tma_info_system_time", - "MetricGroup": "SoC", - "MetricName": "tma_info_system_uncore_frequency", - "Unit": "cpu_core" - }, { "BriefDescription": "Per-Logical Processor actual clocks when the Logical Processor is active.", "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.THREAD@", @@ -2204,6 +2196,16 @@ "ScaleUnit": "100%", "Unit": "cpu_core" }, + { + "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", + "MetricExpr": "cpu_core@MEMORY_ACTIVITY.STALLS_L3_MISS@ / tma_info_thread_clks", + "MetricGroup": "MemoryBound;Offcore;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", + "MetricName": "tma_l3_miss_bound", + "MetricThreshold": "tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", + "PublicDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads. Better caching can improve the latency and increase performance. Sample with: MEM_LOAD_RETIRED.L3_MISS", + "ScaleUnit": "100%", + "Unit": "cpu_core" + }, { "BriefDescription": "This metric represents fraction of cycles CPU was stalled due to Length Changing Prefixes (LCPs)", "MetricExpr": "cpu_core@DECODE.LCP@ / tma_info_thread_clks", @@ -2283,7 +2285,7 @@ { "BriefDescription": "This metric represents fraction of cycles the CPU spent handling cache misses due to lock operations", "MetricConstraint": "NO_GROUP_EVENTS", - "MetricExpr": "(16 * max(0, cpu_core@MEM_INST_RETIRED.LOCK_LOADS@ - cpu_core@L2_RQSTS.ALL_RFO@) + cpu_core@MEM_INST_RETIRED.LOCK_LOADS@ / cpu_core@MEM_INST_RETIRED.ALL_STORES@ * (10 * cpu_core@L2_RQSTS.RFO_HIT@ + min(cpu_core@CPU_CLK_UNHALTED.THREAD@, cpu_core@OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO@))) / tma_info_thread_clks", + "MetricExpr": "cpu_core@LOCK_CYCLES.CACHE_LOCK_DURATION@ / tma_info_thread_clks", "MetricGroup": "LockCont;Offcore;TopdownL4;tma_L4_group;tma_issueRFO;tma_l1_bound_group", "MetricName": "tma_lock_latency", "MetricThreshold": "tma_lock_latency > 0.2 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", @@ -2315,19 +2317,19 @@ { "BriefDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM)", "MetricExpr": "min(cpu_core@CPU_CLK_UNHALTED.THREAD@, cpu_core@OFFCORE_REQUESTS_OUTSTANDING.ALL_DATA_RD\\,cmask\\=4@) / tma_info_thread_clks", - "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", + "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_miss_bound_group", "MetricName": "tma_mem_bandwidth", - "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full, tma_uc_bound", "ScaleUnit": "100%", "Unit": "cpu_core" }, { "BriefDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM)", "MetricExpr": "min(cpu_core@CPU_CLK_UNHALTED.THREAD@, cpu_core@OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD@) / tma_info_thread_clks - tma_mem_bandwidth", - "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", + "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_miss_bound_group", "MetricName": "tma_mem_latency", - "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", + "MetricThreshold": "tma_mem_latency > 0.1 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%", "Unit": "cpu_core" @@ -2397,7 +2399,7 @@ "MetricGroup": "TopdownL5;tma_L5_group;tma_issueMV;tma_ports_utilized_0_group", "MetricName": "tma_mixing_vectors", "MetricThreshold": "tma_mixing_vectors > 0.05", - "PublicDescription": "This metric estimates penalty in terms of percentage of([SKL+] injected blend uops out of all Uops Issued -- the Count Domain; [ADL+] cycles). Usually a Mixing_Vectors over 5% is worth investigating. Read more in Appendix B1 of the Optimizations Guide for this topic. Related metrics: tma_ms_switches", + "PublicDescription": "This metric estimates penalty in terms of percentage of([SKL+] injected blend uops out of all Uops Issued -- the Count Domain; [ADL+] cycles). Usually a Mixing_Vectors over 5% is worth investigating. Read more in Appendix B1 of the Optimizations Guide for this topic. Related metrics: tma_info_inst_mix_vectormixpki, tma_ms_switches", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2416,7 +2418,7 @@ "MetricGroup": "FetchLat;MicroSeq;TopdownL3;tma_L3_group;tma_fetch_latency_group;tma_issueMC;tma_issueMS;tma_issueMV;tma_issueSO", "MetricName": "tma_ms_switches", "MetricThreshold": "tma_ms_switches > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", - "PublicDescription": "This metric estimates the fraction of cycles when the CPU was stalled due to switches of uop delivery to the Microcode Sequencer (MS). Commonly used instructions are optimized for delivery by the DSB (decoded i-cache) or MITE (legacy instruction decode) pipelines. Certain operations cannot be handled natively by the execution pipeline; and must be performed by microcode (small programs injected into the execution stream). Switching to the MS too often can negatively impact performance. The MS is designated to deliver long uop flows required by CISC instructions like CPUID; or uncommon conditions like Floating Point Assists when dealing with Denormals. Sample with: FRONTEND_RETIRED.MS_FLOWS. Related metrics: tma_bottleneck_irregular_overhead, tma_clears_resteers, tma_l1_bound, tma_machine_clears, tma_microcode_sequencer, tma_mixing_vectors, tma_serializing_operation", + "PublicDescription": "This metric estimates the fraction of cycles when the CPU was stalled due to switches of uop delivery to the Microcode Sequencer (MS). Commonly used instructions are optimized for delivery by the DSB (decoded i-cache) or MITE (legacy instruction decode) pipelines. Certain operations cannot be handled natively by the execution pipeline; and must be performed by microcode (small programs injected into the execution stream). Switching to the MS too often can negatively impact performance. The MS is designated to deliver long uop flows required by CISC instructions like CPUID; or uncommon conditions like Floating Point Assists when dealing with Denormals. Sample with: FRONTEND_RETIRED.MS_FLOWS. Related metrics: tma_bottleneck_irregular_overhead, tma_clears_resteers, tma_info_inst_mix_vectormixpki, tma_l1_bound, tma_machine_clears, tma_microcode_sequencer, tma_mixing_vectors, tma_serializing_operation", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2606,7 +2608,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles handling memory load split accesses - load that cross 64-byte cache line boundary", - "MetricExpr": "tma_info_memory_load_miss_real_latency * cpu_core@LD_BLOCKS.NO_SR@ / tma_info_thread_clks", + "MetricExpr": "cpu_core@MEM_INST_RETIRED.SPLIT_LOADS@ * tma_info_memory_load_miss_real_latency / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_split_loads", "MetricThreshold": "tma_split_loads > 0.3", @@ -2630,7 +2632,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_uc_bound", "ScaleUnit": "100%", "Unit": "cpu_core" }, diff --git a/tools/perf/pmu-events/arch/x86/alderlake/cache.json b/tools/perf/pmu-events/arch/x86/alderlake/cache.json index e44e6b651d55..6c09da7b69e8 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/cache.json @@ -1,4 +1,13 @@ [ + { + "BriefDescription": "Counts the number of core requests (demand and L1 prefetchers) rejected by the L2 queue (L2Q) due to a full condition.", + "Counter": "0,1,2,3,4,5", + "EventCode": "0x31", + "EventName": "CORE_REJECT_L2Q.ANY", + "PublicDescription": "Counts the number of (demand and L1 prefetchers) core requests rejected by the L2 queue (L2Q) due to a full or nearly full condition, which likely indicates back pressure from L2Q. It also counts requests that would have gone directly to the External Queue (XQ), but are rejected due to a full or nearly full condition, indicating back pressure from the IDI link. The L2Q may also reject transactions from a core to ensure fairness between cores, or to delay a cores dirty eviction when the address conflicts incoming external snoops. (Note that L2 prefetcher requests that are dropped are not counted by this event). Counts on a per core basis.", + "SampleAfterValue": "200003", + "Unit": "cpu_atom" + }, { "BriefDescription": "L1D.HWPF_MISS", "Counter": "0,1,2,3", @@ -121,6 +130,15 @@ "UMask": "0x4", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts the number of demand and prefetch transactions that the External Queue (XQ) rejects due to a full or near full condition.", + "Counter": "0,1,2,3,4,5", + "EventCode": "0x30", + "EventName": "L2_REJECT_XQ.ANY", + "PublicDescription": "Counts the number of demand and prefetch transactions that the External Queue (XQ) rejects due to a full or near full condition which likely indicates back pressure from the IDI link. The XQ may reject transactions from the L2Q (non-cacheable requests), BBL (L2 misses) and WOB (L2 write-back victims).", + "SampleAfterValue": "200003", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts the total number of L2 Cache accesses. Counts on a per core basis.", "Counter": "0,1,2,3,4,5", @@ -438,6 +456,15 @@ "UMask": "0x8", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of cycles the core is stalled due to an instruction cache or TLB miss which missed in the L2 cache.", + "Counter": "0,1,2,3,4,5", + "EventCode": "0x34", + "EventName": "MEM_BOUND_STALLS.IFETCH_L2_MISS", + "SampleAfterValue": "1000003", + "UMask": "0x30", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts the number of cycles the core is stalled due to an instruction cache or TLB miss which hit in the LLC or other core with HITE/F/M.", "Counter": "0,1,2,3,4,5", @@ -475,6 +502,15 @@ "UMask": "0x1", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of cycles the core is stalled due to a demand load which missed in the L2 cache.", + "Counter": "0,1,2,3,4,5", + "EventCode": "0x34", + "EventName": "MEM_BOUND_STALLS.LOAD_L2_MISS", + "SampleAfterValue": "1000003", + "UMask": "0x6", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts the number of cycles the core is stalled due to a demand load which hit in the LLC or other core with HITE/F/M.", "Counter": "0,1,2,3,4,5", diff --git a/tools/perf/pmu-events/arch/x86/alderlake/metricgroups.json b/tools/perf/pmu-events/arch/x86/alderlake/metricgroups.json index 855585fe6fae..9acbda612c25 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/metricgroups.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/metricgroups.json @@ -93,7 +93,6 @@ "tma_code_stlb_miss_group": "Metrics contributing to tma_code_stlb_miss category", "tma_core_bound_group": "Metrics contributing to tma_core_bound category", "tma_divider_group": "Metrics contributing to tma_divider category", - "tma_dram_bound_group": "Metrics contributing to tma_dram_bound category", "tma_dtlb_load_group": "Metrics contributing to tma_dtlb_load category", "tma_dtlb_store_group": "Metrics contributing to tma_dtlb_store category", "tma_fetch_bandwidth_group": "Metrics contributing to tma_fetch_bandwidth category", @@ -129,6 +128,7 @@ "tma_l1_bound_group": "Metrics contributing to tma_l1_bound category", "tma_l2_bound_group": "Metrics contributing to tma_l2_bound category", "tma_l3_bound_group": "Metrics contributing to tma_l3_bound category", + "tma_l3_miss_bound_group": "Metrics contributing to tma_l3_miss_bound category", "tma_light_operations_group": "Metrics contributing to tma_light_operations category", "tma_load_op_utilization_group": "Metrics contributing to tma_load_op_utilization category", "tma_load_stlb_miss_group": "Metrics contributing to tma_load_stlb_miss category", diff --git a/tools/perf/pmu-events/arch/x86/alderlake/pipeline.json b/tools/perf/pmu-events/arch/x86/alderlake/pipeline.json index 1c292f29b0aa..eb840066a5a7 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/pipeline.json @@ -550,11 +550,11 @@ "Unit": "cpu_atom" }, { - "BriefDescription": "This event counts the number of mispredicted ret instructions retired. Non PEBS", + "BriefDescription": "This event counts the number of mispredicted ret instructions retired.", "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.RET", - "PublicDescription": "This is a non-precise version (that is, does not use PEBS) of the event that counts mispredicted return instructions retired. Available PDIST counters: 0", + "PublicDescription": "This event counts the number of mispredicted ret instructions retired. Available PDIST counters: 0", "SampleAfterValue": "100007", "UMask": "0x8", "Unit": "cpu_core" @@ -988,7 +988,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", - "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent.", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note: Since the number of iterations within a REP instruction can be significantly affected by fast strings, this event may vary run to run and not match the architectural number of iterations (specified by RCX)", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index a7f870669827..414744811c00 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -1,5 +1,5 @@ Family-model,Version,Filename,EventType -GenuineIntel-6-(97|9A|B7|BA|BF),v1.39,alderlake,core +GenuineIntel-6-(97|9A|B7|BA|BF),v1.40,alderlake,core GenuineIntel-6-BE,v1.39,alderlaken,core GenuineIntel-6-C[56],v1.19,arrowlake,core GenuineIntel-6-(1C|26|27|35|36),v5,bonnell,core -- cgit v1.2.3 From 6281354894d9a144216aef2a27712cd9b7b52dce Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Mon, 13 Jul 2026 11:17:47 -0700 Subject: perf vendor events intel: Update alderlaken events from 1.39 to 1.40 The updated events were published in: https://github.com/intel/perfmon/commit/7a14cc8feaf86772deb6708e96c8e9fee6d5b1ca Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Signed-off-by: Namhyung Kim --- .../perf/pmu-events/arch/x86/alderlaken/cache.json | 32 ++++++++++++++++++++++ tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/tools/perf/pmu-events/arch/x86/alderlaken/cache.json b/tools/perf/pmu-events/arch/x86/alderlaken/cache.json index 0ffad953e752..b39c73614b86 100644 --- a/tools/perf/pmu-events/arch/x86/alderlaken/cache.json +++ b/tools/perf/pmu-events/arch/x86/alderlaken/cache.json @@ -1,4 +1,20 @@ [ + { + "BriefDescription": "Counts the number of core requests (demand and L1 prefetchers) rejected by the L2 queue (L2Q) due to a full condition.", + "Counter": "0,1,2,3,4,5", + "EventCode": "0x31", + "EventName": "CORE_REJECT_L2Q.ANY", + "PublicDescription": "Counts the number of (demand and L1 prefetchers) core requests rejected by the L2 queue (L2Q) due to a full or nearly full condition, which likely indicates back pressure from L2Q. It also counts requests that would have gone directly to the External Queue (XQ), but are rejected due to a full or nearly full condition, indicating back pressure from the IDI link. The L2Q may also reject transactions from a core to ensure fairness between cores, or to delay a cores dirty eviction when the address conflicts incoming external snoops. (Note that L2 prefetcher requests that are dropped are not counted by this event). Counts on a per core basis.", + "SampleAfterValue": "200003" + }, + { + "BriefDescription": "Counts the number of demand and prefetch transactions that the External Queue (XQ) rejects due to a full or near full condition.", + "Counter": "0,1,2,3,4,5", + "EventCode": "0x30", + "EventName": "L2_REJECT_XQ.ANY", + "PublicDescription": "Counts the number of demand and prefetch transactions that the External Queue (XQ) rejects due to a full or near full condition which likely indicates back pressure from the IDI link. The XQ may reject transactions from the L2Q (non-cacheable requests), BBL (L2 misses) and WOB (L2 write-back victims).", + "SampleAfterValue": "200003" + }, { "BriefDescription": "Counts the total number of L2 Cache accesses. Counts on a per core basis.", "Counter": "0,1,2,3,4,5", @@ -70,6 +86,14 @@ "SampleAfterValue": "200003", "UMask": "0x8" }, + { + "BriefDescription": "Counts the number of cycles the core is stalled due to an instruction cache or TLB miss which missed in the L2 cache.", + "Counter": "0,1,2,3,4,5", + "EventCode": "0x34", + "EventName": "MEM_BOUND_STALLS.IFETCH_L2_MISS", + "SampleAfterValue": "1000003", + "UMask": "0x30" + }, { "BriefDescription": "Counts the number of cycles the core is stalled due to an instruction cache or TLB miss which hit in the LLC or other core with HITE/F/M.", "Counter": "0,1,2,3,4,5", @@ -103,6 +127,14 @@ "SampleAfterValue": "200003", "UMask": "0x1" }, + { + "BriefDescription": "Counts the number of cycles the core is stalled due to a demand load which missed in the L2 cache.", + "Counter": "0,1,2,3,4,5", + "EventCode": "0x34", + "EventName": "MEM_BOUND_STALLS.LOAD_L2_MISS", + "SampleAfterValue": "1000003", + "UMask": "0x6" + }, { "BriefDescription": "Counts the number of cycles the core is stalled due to a demand load which hit in the LLC or other core with HITE/F/M.", "Counter": "0,1,2,3,4,5", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 414744811c00..d82f6b3d5b68 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -1,6 +1,6 @@ Family-model,Version,Filename,EventType GenuineIntel-6-(97|9A|B7|BA|BF),v1.40,alderlake,core -GenuineIntel-6-BE,v1.39,alderlaken,core +GenuineIntel-6-BE,v1.40,alderlaken,core GenuineIntel-6-C[56],v1.19,arrowlake,core GenuineIntel-6-(1C|26|27|35|36),v5,bonnell,core GenuineIntel-6-(3D|47),v30,broadwell,core -- cgit v1.2.3 From d4aba8c1503f7ddc0c76b38cb9bbf91053fa6569 Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Mon, 13 Jul 2026 11:17:48 -0700 Subject: perf vendor events intel: Update arrowlake events from 1.19 to 1.20 The updated events were published in: https://github.com/intel/perfmon/commit/b23ebe7bc25add0c835565e4bc87e063cb620a02 Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Signed-off-by: Namhyung Kim --- .../pmu-events/arch/x86/arrowlake/arl-metrics.json | 152 ++++++++++++--------- .../arch/x86/arrowlake/metricgroups.json | 2 +- .../pmu-events/arch/x86/arrowlake/pipeline.json | 2 +- .../arch/x86/arrowlake/uncore-memory.json | 84 ++++++++++-- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 5 files changed, 160 insertions(+), 82 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/arl-metrics.json b/tools/perf/pmu-events/arch/x86/arrowlake/arl-metrics.json index 4f1f77404943..52db2caafc0a 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/arl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/arl-metrics.json @@ -823,16 +823,16 @@ }, { "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_miss_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency + tma_uc_bound)) + tma_memory_bound * (tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)))", "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_uc_bound", "Unit": "cpu_core" }, { "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_capacity / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_miss_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency + tma_uc_bound)) + tma_memory_bound * (tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_l1_latency_capacity / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", "MetricName": "tma_bottleneck_data_cache_memory_latency", "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", @@ -858,7 +858,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_dtlb_load / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", "MetricThreshold": "tma_bottleneck_memory_data_tlbs > 20", @@ -867,7 +867,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", "MetricThreshold": "tma_bottleneck_memory_synchronization > 10", @@ -1015,7 +1015,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by non-taken conditional branches.", - "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_NTAKEN_COST@ * cpu_core@BR_MISP_RETIRED.COND_NTAKEN_COST@R / tma_info_thread_clks", + "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_NTAKEN@ / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_cond_nt_mispredicts", "MetricThreshold": "tma_cond_nt_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -1024,7 +1024,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to misprediction by backward-taken conditional branches.", - "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_TAKEN_BWD_COST@ * cpu_core@BR_MISP_RETIRED.COND_TAKEN_BWD_COST@R / tma_info_thread_clks", + "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_TAKEN_BWD@ / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_cond_tk_bwd_mispredicts", "MetricThreshold": "tma_cond_tk_bwd_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -1033,7 +1033,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to misprediction by forward-taken conditional branches.", - "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_TAKEN_FWD_COST@ * cpu_core@BR_MISP_RETIRED.COND_TAKEN_FWD_COST@R / tma_info_thread_clks", + "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_TAKEN_FWD@ / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_cond_tk_fwd_mispredicts", "MetricThreshold": "tma_cond_tk_fwd_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -1046,7 +1046,7 @@ "MetricGroup": "BvMS;DataSharing;LockCont;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_contested_accesses", "MetricThreshold": "tma_contested_accesses > 0.05 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to contested accesses. Contested accesses occur when data written by one Logical Processor are read by another Logical Processor on a different Physical Core. Examples of contested accesses include synchronizations such as locks; true data sharing such as modified locked variables; and false sharing. Sample with: MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD;MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS. Related metrics: tma_bottleneck_memory_synchronization, tma_data_sharing, tma_false_sharing, tma_machine_clears, tma_remote_cache", + "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to contested accesses. Contested accesses occur when data written by one Logical Processor are read by another Logical Processor on a different Physical Core. Examples of contested accesses include synchronizations such as locks; true data sharing such as modified locked variables; and false sharing. Sample with: MEM_LOAD_L2_MISS_RETIRED.L3.SAME_CBB.HIT_ESF.SNP_MISS;MEM_LOAD_L2_MISS_RETIRED.OTHER_MODULE_L2.SAME_CBB.HIT_M.SNP_FWD. Related metrics: tma_bottleneck_memory_synchronization, tma_data_sharing, tma_false_sharing, tma_machine_clears, tma_remote_cache", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -1062,13 +1062,13 @@ "Unit": "cpu_core" }, { - "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses", + "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to L3 data-sharing accesses", "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD@ * min(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD@R, 24 * tma_info_system_core_frequency) + cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD@ * min(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD@R, 25 * tma_info_system_core_frequency)) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "BvMS;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_data_sharing", "MetricThreshold": "tma_data_sharing > 0.05 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses. Data shared by multiple Logical Processors (even just read shared) may cause increased access latency due to cache coherency. Excessive data sharing can drastically harm multithreaded performance. Sample with: MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_false_sharing, tma_machine_clears, tma_remote_cache", + "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to L3 data-sharing accesses. Data shared by multiple Logical Processors (even just read shared) may cause increased access latency due to cache coherency. Excessive data sharing can drastically harm multithreaded performance. Sample with: MEM_LOAD_L2_MISS_RETIRED.L3.SAME_CBB.HIT_ESF.SNP_HIT_NO_FWD. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_false_sharing, tma_machine_clears, tma_remote_cache", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -1082,19 +1082,9 @@ "ScaleUnit": "100%", "Unit": "cpu_core" }, - { - "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", - "MetricExpr": "cpu_core@MEMORY_STALLS.MEM@ / tma_info_thread_clks", - "MetricGroup": "MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", - "MetricName": "tma_dram_bound", - "MetricThreshold": "tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", - "PublicDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads. Better caching can improve the latency and increase performance. Sample with: MEM_LOAD_RETIRED.L3_MISS", - "ScaleUnit": "100%", - "Unit": "cpu_core" - }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to DSB (decoded uop cache) fetch pipeline", - "MetricExpr": "(cpu_core@IDQ.DSB_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / 2 + cpu_core@IDQ.DSB_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.STARVATION_CYCLES@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", + "MetricExpr": "(cpu_core@IDQ.DSB_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ * max(0, 8 - tma_info_pipeline_fetch_dsb) / 8 + cpu_core@IDQ.DSB_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.STARVATION_CYCLES@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", "MetricGroup": "DSB;FetchBW;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_dsb", "MetricThreshold": "tma_dsb > 0.15 & tma_fetch_bandwidth > 0.2", @@ -1138,7 +1128,7 @@ "MetricGroup": "BvMS;DataSharing;LockCont;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_store_bound_group", "MetricName": "tma_false_sharing", "MetricThreshold": "tma_false_sharing > 0.05 & (tma_store_bound > 0.2 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric roughly estimates how often CPU was handling synchronizations due to False Sharing. False Sharing is a multithreading hiccup; where multiple Logical Processors contend on different data-elements mapped into the same cache line. Sample with: OCR.DEMAND_RFO.L3_HIT.SNOOP_HITM. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_data_sharing, tma_machine_clears, tma_remote_cache", + "PublicDescription": "This metric roughly estimates how often CPU was handling synchronizations due to False Sharing. False Sharing is a multithreading hiccup; where multiple Logical Processors contend on different data-elements mapped into the same cache line. Sample with: L2_REQUEST.RFO_HIT_XSNP_HIT_FWD. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_data_sharing, tma_machine_clears, tma_remote_cache", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -1148,7 +1138,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores, tma_uc_bound", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -1245,7 +1235,7 @@ }, { "BriefDescription": "This metric approximates arithmetic FP vector uops fraction the CPU has retired for 256-bit wide vectors", - "MetricExpr": "cpu_core@FP_ARITH_OPS_RETIRED.VECTOR\\,umask\\=0x30@ / (tma_retiring * tma_info_thread_slots)", + "MetricExpr": "cpu_core@FP_ARITH_OPS_RETIRED.VECTOR_256B@ / (tma_retiring * tma_info_thread_slots)", "MetricGroup": "Compute;Flops;TopdownL5;tma_L5_group;tma_fp_vector_group;tma_issue2P", "MetricName": "tma_fp_vector_256b", "MetricThreshold": "tma_fp_vector_256b > 0.1 & (tma_fp_vector > 0.1 & (tma_fp_arith > 0.2 & tma_light_operations > 0.6))", @@ -1288,7 +1278,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to instruction cache misses", - "MetricExpr": "cpu_core@ICACHE_DATA.STALLS@ / tma_info_thread_clks", + "MetricExpr": "cpu_core@ICACHE_DATA.STALLS@ / tma_info_thread_clks + tma_isb_full", "MetricGroup": "BigFootprint;BvBC;FetchLat;IcMiss;TopdownL3;tma_L3_group;tma_fetch_latency_group", "MetricName": "tma_icache_misses", "MetricThreshold": "tma_icache_misses > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", @@ -1298,7 +1288,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by indirect CALL instructions.", - "MetricExpr": "cpu_core@BR_MISP_RETIRED.INDIRECT_CALL_COST@ * cpu_core@BR_MISP_RETIRED.INDIRECT_CALL_COST@R / tma_info_thread_clks", + "MetricExpr": "cpu_core@BR_MISP_RETIRED.INDIRECT_CALL@ / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_ind_call_mispredicts", "MetricThreshold": "tma_ind_call_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -1307,7 +1297,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by indirect JMP instructions.", - "MetricExpr": "max((cpu_core@BR_MISP_RETIRED.INDIRECT_COST@ * cpu_core@BR_MISP_RETIRED.INDIRECT_COST@R - cpu_core@BR_MISP_RETIRED.INDIRECT_CALL_COST@ * cpu_core@BR_MISP_RETIRED.INDIRECT_CALL_COST@R) / tma_info_thread_clks, 0)", + "MetricExpr": "max((cpu_core@BR_MISP_RETIRED.INDIRECT@ - cpu_core@BR_MISP_RETIRED.INDIRECT_CALL@) / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts, 0)", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_ind_jump_mispredicts", "MetricThreshold": "tma_ind_jump_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -1477,7 +1467,7 @@ }, { "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded ICache; or Uop Cache)", - "MetricExpr": "cpu_core@IDQ.DSB_UOPS@ / cpu_core@UOPS_ISSUED.ANY@", + "MetricExpr": "cpu_core@IDQ.DSB_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@LSD.UOPS@ + cpu_core@IDQ.MITE_UOPS@ + cpu_core@IDQ.MS_UOPS@)", "MetricGroup": "DSB;Fed;FetchBW;tma_issueFB", "MetricName": "tma_info_frontend_dsb_coverage", "MetricThreshold": "tma_info_frontend_dsb_coverage < 0.7 & tma_info_thread_ipc / 8 > 0.35", @@ -1544,7 +1534,7 @@ }, { "BriefDescription": "Fraction of Uops delivered by the LSD (Loop Stream Detector; aka Loop Cache)", - "MetricExpr": "cpu_core@LSD.UOPS@ / cpu_core@UOPS_ISSUED.ANY@", + "MetricExpr": "cpu_core@LSD.UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@LSD.UOPS@ + cpu_core@IDQ.MITE_UOPS@ + cpu_core@IDQ.MS_UOPS@)", "MetricGroup": "Fed;LSD", "MetricName": "tma_info_frontend_lsd_coverage", "Unit": "cpu_core" @@ -1703,6 +1693,15 @@ "PublicDescription": "Instructions per taken branch. Related metrics: tma_dsb_switches, tma_fetch_bandwidth, tma_info_botlnk_l2_dsb_bandwidth, tma_info_botlnk_l2_dsb_misses, tma_info_frontend_dsb_coverage, tma_lcp", "Unit": "cpu_core" }, + { + "BriefDescription": "AVX preserve/restore assists per kilo instruction", + "MetricExpr": "1e3 * cpu_core@ASSISTS.SSE_AVX_MIX@ / cpu_core@INST_RETIRED.ANY@", + "MetricGroup": "tma_issueMV", + "MetricName": "tma_info_inst_mix_vectormixpki", + "MetricThreshold": "tma_info_inst_mix_vectormixpki > 0.05", + "PublicDescription": "AVX preserve/restore assists per kilo instruction. Related metrics: tma_mixing_vectors, tma_ms_switches", + "Unit": "cpu_core" + }, { "BriefDescription": "Fill Buffer (FB) hits per kilo instructions for retired demand loads (L1D misses that merge into ongoing miss-handling entries)", "MetricExpr": "1e3 * cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@INST_RETIRED.ANY@", @@ -1969,6 +1968,13 @@ "MetricName": "tma_info_pipeline_retire", "Unit": "cpu_core" }, + { + "BriefDescription": "Total percent of cycles without actually retired uops", + "MetricExpr": "cpu_core@UOPS_RETIRED.STALLS@ / tma_info_thread_clks", + "MetricGroup": "Pipeline;Ret", + "MetricName": "tma_info_pipeline_retire_stall", + "Unit": "cpu_core" + }, { "BriefDescription": "Estimated fraction of retirement-cycles dealing with repeat instructions", "MetricExpr": "cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.SLOTS\\,cmask\\=1@", @@ -2011,7 +2017,7 @@ "MetricExpr": "32 * UNC_M_TOTAL_DATA / 1e9 / tma_info_system_time", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full", + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full, tma_uc_bound", "Unit": "cpu_core" }, { @@ -2082,13 +2088,6 @@ "MetricName": "tma_info_system_turbo_utilization", "Unit": "cpu_core" }, - { - "BriefDescription": "Measured Average Uncore Frequency for the SoC [GHz]", - "MetricExpr": "tma_info_system_socket_clks / 1e9 / tma_info_system_time", - "MetricGroup": "SoC", - "MetricName": "tma_info_system_uncore_frequency", - "Unit": "cpu_core" - }, { "BriefDescription": "Per-Logical Processor actual clocks when the Logical Processor is active.", "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.THREAD@", @@ -2180,9 +2179,18 @@ "ScaleUnit": "100%", "Unit": "cpu_core" }, + { + "BriefDescription": "This metric represents fraction of cycles Icache tag lookup was stalled due to Instruction Stream Buffer (ISB) being full", + "MetricExpr": "(cpu_core@ICACHE_TAG.STALLS_ISB@ + cpu_core@ICACHE_TAG.STALLS_INUSE@) / tma_info_thread_clks", + "MetricGroup": "TopdownL4;tma_L4_group;tma_icache_misses_group", + "MetricName": "tma_isb_full", + "MetricThreshold": "tma_isb_full > 0.05 & (tma_icache_misses > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15))", + "ScaleUnit": "100%", + "Unit": "cpu_core" + }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to Instruction TLB (ITLB) misses", - "MetricExpr": "cpu_core@ICACHE_TAG.STALLS@ / tma_info_thread_clks", + "MetricExpr": "cpu_core@ICACHE_TAG.STALLS@ / tma_info_thread_clks - tma_isb_full", "MetricGroup": "BigFootprint;BvBC;FetchLat;MemoryTLB;TopdownL3;tma_L3_group;tma_fetch_latency_group", "MetricName": "tma_itlb_misses", "MetricThreshold": "tma_itlb_misses > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", @@ -2209,19 +2217,9 @@ "ScaleUnit": "100%", "Unit": "cpu_core" }, - { - "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", - "MetricExpr": "4 * cpu_core@DEPENDENT_LOADS.ANY\\,cmask\\=1@ / tma_info_thread_clks", - "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", - "MetricName": "tma_l1_latency_dependency", - "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", - "ScaleUnit": "100%", - "Unit": "cpu_core" - }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to L2 cache accesses by loads", - "MetricExpr": "cpu_core@MEMORY_STALLS.L2@ / tma_info_thread_clks", + "MetricExpr": "cpu_core@MEM_LOAD_RETIRED.L2_HIT@ / (cpu_core@MEM_LOAD_RETIRED.L2_HIT@ + cpu_core@MEM_LOAD_MISC_RETIRED.UC@) * cpu_core@MEMORY_STALLS.L2@ / tma_info_thread_clks", "MetricGroup": "BvML;CacheHits;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l2_bound", "MetricThreshold": "tma_l2_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", @@ -2245,7 +2243,7 @@ "MetricGroup": "CacheHits;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", "MetricThreshold": "tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", - "PublicDescription": "This metric estimates how often the CPU was stalled due to loads accesses to L3 cache or contended with a sibling Core. Avoiding cache misses (i.e. L2 misses/L3 hits) can improve the latency and increase performance. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS", + "PublicDescription": "This metric estimates how often the CPU was stalled due to loads accesses to L3 cache or contended with a sibling Core. Avoiding cache misses (i.e. L2 misses/L3 hits) can improve the latency and increase performance. Sample with: MEM_LOAD_L2_MISS_RETIRED.L3_HIT_SAME_CBB", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2255,7 +2253,17 @@ "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_L2_MISS_RETIRED.L3_HIT_SAME_CBB. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", + "ScaleUnit": "100%", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", + "MetricExpr": "cpu_core@MEMORY_STALLS.MEM@ / tma_info_thread_clks", + "MetricGroup": "MemoryBound;Offcore;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", + "MetricName": "tma_l3_miss_bound", + "MetricThreshold": "tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", + "PublicDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads. Better caching can improve the latency and increase performance. Sample with: MEM_LOAD_L2_MISS_RETIRED.L3_MISS", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2348,7 +2356,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to LSD (Loop Stream Detector) unit", - "MetricExpr": "cpu_core@LSD.UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / tma_info_thread_clks / 2", + "MetricExpr": "cpu_core@LSD.UOPS\\,cmask\\=0x8\\,inv\\=0x1@ * max(0, 8 - tma_info_pipeline_fetch_lsd) / 8 / tma_info_thread_clks", "MetricGroup": "FetchBW;LSD;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_lsd", "MetricThreshold": "tma_lsd > 0.15 & tma_fetch_bandwidth > 0.2", @@ -2370,19 +2378,19 @@ { "BriefDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM)", "MetricExpr": "min(cpu_core@CPU_CLK_UNHALTED.THREAD@, cpu_core@OFFCORE_REQUESTS_OUTSTANDING.DATA_RD\\,cmask\\=4@) / tma_info_thread_clks", - "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", + "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_miss_bound_group", "MetricName": "tma_mem_bandwidth", - "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full, tma_uc_bound", "ScaleUnit": "100%", "Unit": "cpu_core" }, { "BriefDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM)", "MetricExpr": "min(cpu_core@CPU_CLK_UNHALTED.THREAD@, cpu_core@OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD@) / tma_info_thread_clks - tma_mem_bandwidth", - "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", + "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_miss_bound_group", "MetricName": "tma_mem_latency", - "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", + "MetricThreshold": "tma_mem_latency > 0.1 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%", "Unit": "cpu_core" @@ -2438,7 +2446,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the MITE pipeline (the legacy decode pipeline)", - "MetricExpr": "(cpu_core@IDQ.MITE_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / 2 + cpu_core@IDQ.MITE_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.STARVATION_CYCLES@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", + "MetricExpr": "(cpu_core@IDQ.MITE_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ * max(0, 8 - tma_info_pipeline_fetch_mite) / 8 + cpu_core@IDQ.MITE_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.STARVATION_CYCLES@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", "MetricGroup": "DSBmiss;FetchBW;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_mite", "MetricThreshold": "tma_mite > 0.1 & tma_fetch_bandwidth > 0.2", @@ -2452,13 +2460,13 @@ "MetricGroup": "TopdownL5;tma_L5_group;tma_issueMV;tma_ports_utilized_0_group", "MetricName": "tma_mixing_vectors", "MetricThreshold": "tma_mixing_vectors > 0.05", - "PublicDescription": "This metric estimates penalty in terms of percentage of([SKL+] injected blend uops out of all Uops Issued -- the Count Domain; [ADL+] cycles). Usually a Mixing_Vectors over 5% is worth investigating. Read more in Appendix B1 of the Optimizations Guide for this topic. Related metrics: tma_ms_switches", + "PublicDescription": "This metric estimates penalty in terms of percentage of([SKL+] injected blend uops out of all Uops Issued -- the Count Domain; [ADL+] cycles). Usually a Mixing_Vectors over 5% is worth investigating. Read more in Appendix B1 of the Optimizations Guide for this topic. Related metrics: tma_info_inst_mix_vectormixpki, tma_ms_switches", "ScaleUnit": "100%", "Unit": "cpu_core" }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the Microcode Sequencer (MS) unit - see Microcode_Sequencer node for details.", - "MetricExpr": "cpu_core@IDQ.MS_CYCLES_ANY@ / tma_info_thread_clks / 1.8", + "MetricExpr": "cpu_core@IDQ.MS_CYCLES_ANY@ * (8 - cpu_core@IDQ.MS_UOPS@ / cpu_core@IDQ.MS_CYCLES_ANY@) / tma_info_thread_slots", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_ms", "MetricThreshold": "tma_ms > 0.05 & tma_fetch_bandwidth > 0.2", @@ -2471,7 +2479,7 @@ "MetricGroup": "FetchLat;MicroSeq;TopdownL3;tma_L3_group;tma_fetch_latency_group;tma_issueMC;tma_issueMS;tma_issueMV;tma_issueSO", "MetricName": "tma_ms_switches", "MetricThreshold": "tma_ms_switches > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", - "PublicDescription": "This metric estimates the fraction of cycles when the CPU was stalled due to switches of uop delivery to the Microcode Sequencer (MS). Commonly used instructions are optimized for delivery by the DSB (decoded i-cache) or MITE (legacy instruction decode) pipelines. Certain operations cannot be handled natively by the execution pipeline; and must be performed by microcode (small programs injected into the execution stream). Switching to the MS too often can negatively impact performance. The MS is designated to deliver long uop flows required by CISC instructions like CPUID; or uncommon conditions like Floating Point Assists when dealing with Denormals. Sample with: IDQ.MS_SWITCHES. Related metrics: tma_bottleneck_irregular_overhead, tma_clears_resteers, tma_l1_bound, tma_machine_clears, tma_microcode_sequencer, tma_mixing_vectors, tma_serializing_operation", + "PublicDescription": "This metric estimates the fraction of cycles when the CPU was stalled due to switches of uop delivery to the Microcode Sequencer (MS). Commonly used instructions are optimized for delivery by the DSB (decoded i-cache) or MITE (legacy instruction decode) pipelines. Certain operations cannot be handled natively by the execution pipeline; and must be performed by microcode (small programs injected into the execution stream). Switching to the MS too often can negatively impact performance. The MS is designated to deliver long uop flows required by CISC instructions like CPUID; or uncommon conditions like Floating Point Assists when dealing with Denormals. Sample with: IDQ.MS_SWITCHES. Related metrics: tma_bottleneck_irregular_overhead, tma_clears_resteers, tma_info_inst_mix_vectormixpki, tma_l1_bound, tma_machine_clears, tma_microcode_sequencer, tma_mixing_vectors, tma_serializing_operation", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2589,7 +2597,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by (indirect) RET instructions.", - "MetricExpr": "cpu_core@BR_MISP_RETIRED.RET_COST@ * cpu_core@BR_MISP_RETIRED.RET_COST@R / tma_info_thread_clks", + "MetricExpr": "cpu_core@BR_MISP_RETIRED.RET@ / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_ret_mispredicts", "MetricThreshold": "tma_ret_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -2664,7 +2672,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_uc_bound", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2679,8 +2687,8 @@ "Unit": "cpu_core" }, { - "BriefDescription": "This metric estimates clocks wasted due to loads blocked due to unknown store address (did not do memory disambiguation) or due to unknown store data", - "MetricExpr": "7 * cpu_core@LD_BLOCKS.STORE_EARLY\\,cmask\\=1@ / tma_info_thread_clks", + "BriefDescription": "This metric roughly estimates clocks wasted due to loads blocked due to unknown store address (did not do memory disambiguation) or due to unknown store data", + "MetricExpr": "cpu_core@LD_BLOCKS.STORE_EARLY\\,cmask\\=1@ / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_early_blk", "MetricThreshold": "tma_store_early_blk > 0.2", @@ -2768,7 +2776,17 @@ "MetricGroup": "MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueSmSt;tma_store_bound_group", "MetricName": "tma_streaming_stores", "MetricThreshold": "tma_streaming_stores > 0.2 & (tma_store_bound > 0.2 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates how often CPU was stalled due to Streaming store memory accesses; Streaming store optimize out a read request required by RFO stores. Even though store accesses do not typically stall out-of-order CPUs; there are few cases where stores can lead to actual stalls. This metric will be flagged should Streaming stores be a bottleneck. Sample with: OCR.STREAMING_WR.ANY_RESPONSE. Related metrics: tma_fb_full", + "PublicDescription": "This metric estimates how often CPU was stalled due to Streaming store memory accesses; Streaming store optimize out a read request required by RFO stores. Even though store accesses do not typically stall out-of-order CPUs; there are few cases where stores can lead to actual stalls. This metric will be flagged should Streaming stores be a bottleneck. Sample with: OMR.STREAMING_WR.ANY_RESPONSE. Related metrics: tma_fb_full", + "ScaleUnit": "100%", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This metric roughly estimates fraction of cycles where the core's performance was likely hurt due to un-chacheable memory", + "MetricExpr": "cpu_core@MEM_LOAD_MISC_RETIRED.UC@ / (cpu_core@MEM_LOAD_RETIRED.L2_HIT@ + cpu_core@MEM_LOAD_MISC_RETIRED.UC@) * cpu_core@MEMORY_STALLS.L2@ / tma_info_thread_clks", + "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_miss_bound_group", + "MetricName": "tma_uc_bound", + "MetricThreshold": "tma_uc_bound > 0.2 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", + "PublicDescription": "This metric roughly estimates fraction of cycles where the core's performance was likely hurt due to un-chacheable memory. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full", "ScaleUnit": "100%", "Unit": "cpu_core" }, diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/metricgroups.json b/tools/perf/pmu-events/arch/x86/arrowlake/metricgroups.json index 855585fe6fae..9acbda612c25 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/metricgroups.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/metricgroups.json @@ -93,7 +93,6 @@ "tma_code_stlb_miss_group": "Metrics contributing to tma_code_stlb_miss category", "tma_core_bound_group": "Metrics contributing to tma_core_bound category", "tma_divider_group": "Metrics contributing to tma_divider category", - "tma_dram_bound_group": "Metrics contributing to tma_dram_bound category", "tma_dtlb_load_group": "Metrics contributing to tma_dtlb_load category", "tma_dtlb_store_group": "Metrics contributing to tma_dtlb_store category", "tma_fetch_bandwidth_group": "Metrics contributing to tma_fetch_bandwidth category", @@ -129,6 +128,7 @@ "tma_l1_bound_group": "Metrics contributing to tma_l1_bound category", "tma_l2_bound_group": "Metrics contributing to tma_l2_bound category", "tma_l3_bound_group": "Metrics contributing to tma_l3_bound category", + "tma_l3_miss_bound_group": "Metrics contributing to tma_l3_miss_bound category", "tma_light_operations_group": "Metrics contributing to tma_light_operations category", "tma_load_op_utilization_group": "Metrics contributing to tma_load_op_utilization category", "tma_load_stlb_miss_group": "Metrics contributing to tma_load_stlb_miss category", diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/pipeline.json b/tools/perf/pmu-events/arch/x86/arrowlake/pipeline.json index bdfee0347cc5..1f1b5a88216a 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/pipeline.json @@ -1238,7 +1238,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", - "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent. Available PDIST counters: 0,1", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note: Since the number of iterations within a REP instruction can be significantly affected by fast strings, this event may vary run to run and not match the architectural number of iterations (specified by RCX) Available PDIST counters: 0,1", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/uncore-memory.json b/tools/perf/pmu-events/arch/x86/arrowlake/uncore-memory.json index ceb8839f0767..60bf390198d6 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/uncore-memory.json @@ -1,61 +1,61 @@ [ { - "BriefDescription": "Counts every CAS read command sent from the Memory Controller 0 to DRAM (sum of all channels).", + "BriefDescription": "This event is deprecated. [This event is alias to UNC_M_MC0_RDCAS_COUNT_FREERUN]", "Counter": "0", + "Deprecated": "1", "EventCode": "0xff", "EventName": "UNC_MC0_RDCAS_COUNT_FREERUN", "PerPkg": "1", - "PublicDescription": "Counts every CAS read command sent from the Memory Controller 0 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data.", "UMask": "0x20", "Unit": "imc_free_running_0" }, { - "BriefDescription": "Counts every read and write request entering the Memory Controller 0.", + "BriefDescription": "This event is deprecated. [This event is alias to UNC_M_MC0_TOTAL_REQCOUNT_FREERUN]", "Counter": "2", + "Deprecated": "1", "EventCode": "0xff", "EventName": "UNC_MC0_TOTAL_REQCOUNT_FREERUN", "PerPkg": "1", - "PublicDescription": "Counts every read and write request entering the Memory Controller 0 (sum of all channels). All requests are counted as one, whether they are 32B or 64B Read/Write or partial/full line writes. Some write requests to the same address may merge to a single write command to DRAM. Therefore, the total request count may be higher than total DRAM BW.", "UMask": "0x10", "Unit": "imc_free_running_0" }, { - "BriefDescription": "Counts every CAS write command sent from the Memory Controller 0 to DRAM (sum of all channels).", + "BriefDescription": "This event is deprecated. [This event is alias to UNC_M_MC0_WRCAS_COUNT_FREERUN]", "Counter": "1", + "Deprecated": "1", "EventCode": "0xff", "EventName": "UNC_MC0_WRCAS_COUNT_FREERUN", "PerPkg": "1", - "PublicDescription": "Counts every CAS write command sent from the Memory Controller 0 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data.", "UMask": "0x30", "Unit": "imc_free_running_0" }, { - "BriefDescription": "Counts every CAS read command sent from the Memory Controller 1 to DRAM (sum of all channels).", + "BriefDescription": "This event is deprecated. [This event is alias to UNC_M_MC1_RDCAS_COUNT_FREERUN]", "Counter": "3", + "Deprecated": "1", "EventCode": "0xff", "EventName": "UNC_MC1_RDCAS_COUNT_FREERUN", "PerPkg": "1", - "PublicDescription": "Counts every CAS read command sent from the Memory Controller 1 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data.", "UMask": "0x20", "Unit": "imc_free_running_1" }, { - "BriefDescription": "Counts every read and write request entering the Memory Controller 1.", + "BriefDescription": "This event is deprecated. [This event is alias to UNC_M_MC1_TOTAL_REQCOUNT_FREERUN]", "Counter": "5", + "Deprecated": "1", "EventCode": "0xff", "EventName": "UNC_MC1_TOTAL_REQCOUNT_FREERUN", "PerPkg": "1", - "PublicDescription": "Counts every read and write request entering the Memory Controller 1 (sum of all channels). All requests are counted as one, whether they are 32B or 64B Read/Write or partial/full line writes. Some write requests to the same address may merge to a single write command to DRAM. Therefore, the total request count may be higher than total DRAM BW.", "UMask": "0x10", "Unit": "imc_free_running_1" }, { - "BriefDescription": "Counts every CAS write command sent from the Memory Controller 1 to DRAM (sum of all channels).", + "BriefDescription": "This event is deprecated. [This event is alias to UNC_M_MC1_WRCAS_COUNT_FREERUN]", "Counter": "4", + "Deprecated": "1", "EventCode": "0xff", "EventName": "UNC_MC1_WRCAS_COUNT_FREERUN", "PerPkg": "1", - "PublicDescription": "Counts every CAS write command sent from the Memory Controller 1 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data.", "UMask": "0x30", "Unit": "imc_free_running_1" }, @@ -117,6 +117,66 @@ "PerPkg": "1", "Unit": "iMC" }, + { + "BriefDescription": "Counts every CAS read command sent from the Memory Controller 0 to DRAM (sum of all channels). [This event is alias to UNC_MC0_RDCAS_COUNT_FREERUN]", + "Counter": "0", + "EventCode": "0xff", + "EventName": "UNC_M_MC0_RDCAS_COUNT_FREERUN", + "PerPkg": "1", + "PublicDescription": "Counts every CAS read command sent from the Memory Controller 0 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data. [This event is alias to UNC_MC0_RDCAS_COUNT_FREERUN]", + "UMask": "0x20", + "Unit": "imc_free_running_0" + }, + { + "BriefDescription": "Counts every read and write request entering the Memory Controller 0. [This event is alias to UNC_MC0_TOTAL_REQCOUNT_FREERUN]", + "Counter": "2", + "EventCode": "0xff", + "EventName": "UNC_M_MC0_TOTAL_REQCOUNT_FREERUN", + "PerPkg": "1", + "PublicDescription": "Counts every read and write request entering the Memory Controller 0 (sum of all channels). All requests are counted as one, whether they are 32B or 64B Read/Write or partial/full line writes. Some write requests to the same address may merge to a single write command to DRAM. Therefore, the total request count may be higher than total DRAM BW. [This event is alias to UNC_MC0_TOTAL_REQCOUNT_FREERUN]", + "UMask": "0x10", + "Unit": "imc_free_running_0" + }, + { + "BriefDescription": "Counts every CAS write command sent from the Memory Controller 0 to DRAM (sum of all channels). [This event is alias to UNC_MC0_WRCAS_COUNT_FREERUN]", + "Counter": "1", + "EventCode": "0xff", + "EventName": "UNC_M_MC0_WRCAS_COUNT_FREERUN", + "PerPkg": "1", + "PublicDescription": "Counts every CAS write command sent from the Memory Controller 0 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data. [This event is alias to UNC_MC0_WRCAS_COUNT_FREERUN]", + "UMask": "0x30", + "Unit": "imc_free_running_0" + }, + { + "BriefDescription": "Counts every CAS read command sent from the Memory Controller 1 to DRAM (sum of all channels). [This event is alias to UNC_MC1_RDCAS_COUNT_FREERUN]", + "Counter": "3", + "EventCode": "0xff", + "EventName": "UNC_M_MC1_RDCAS_COUNT_FREERUN", + "PerPkg": "1", + "PublicDescription": "Counts every CAS read command sent from the Memory Controller 1 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data. [This event is alias to UNC_MC1_RDCAS_COUNT_FREERUN]", + "UMask": "0x20", + "Unit": "imc_free_running_1" + }, + { + "BriefDescription": "Counts every read and write request entering the Memory Controller 1. [This event is alias to UNC_MC1_TOTAL_REQCOUNT_FREERUN]", + "Counter": "5", + "EventCode": "0xff", + "EventName": "UNC_M_MC1_TOTAL_REQCOUNT_FREERUN", + "PerPkg": "1", + "PublicDescription": "Counts every read and write request entering the Memory Controller 1 (sum of all channels). All requests are counted as one, whether they are 32B or 64B Read/Write or partial/full line writes. Some write requests to the same address may merge to a single write command to DRAM. Therefore, the total request count may be higher than total DRAM BW. [This event is alias to UNC_MC1_TOTAL_REQCOUNT_FREERUN]", + "UMask": "0x10", + "Unit": "imc_free_running_1" + }, + { + "BriefDescription": "Counts every CAS write command sent from the Memory Controller 1 to DRAM (sum of all channels). [This event is alias to UNC_MC1_WRCAS_COUNT_FREERUN]", + "Counter": "4", + "EventCode": "0xff", + "EventName": "UNC_M_MC1_WRCAS_COUNT_FREERUN", + "PerPkg": "1", + "PublicDescription": "Counts every CAS write command sent from the Memory Controller 1 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data. [This event is alias to UNC_MC1_WRCAS_COUNT_FREERUN]", + "UMask": "0x30", + "Unit": "imc_free_running_1" + }, { "BriefDescription": "PRE command sent to DRAM due to page table idle timer expiration", "Counter": "0,1,2,3,4", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index d82f6b3d5b68..7160ff89dac4 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -1,7 +1,7 @@ Family-model,Version,Filename,EventType GenuineIntel-6-(97|9A|B7|BA|BF),v1.40,alderlake,core GenuineIntel-6-BE,v1.40,alderlaken,core -GenuineIntel-6-C[56],v1.19,arrowlake,core +GenuineIntel-6-C[56],v1.20,arrowlake,core GenuineIntel-6-(1C|26|27|35|36),v5,bonnell,core GenuineIntel-6-(3D|47),v30,broadwell,core GenuineIntel-6-56,v12,broadwellde,core -- cgit v1.2.3 From 07b647ec983028436c9afdc195a054891f216ae2 Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Mon, 13 Jul 2026 11:17:49 -0700 Subject: perf vendor events intel: Update clearwaterforest events from 1.02 to 1.04 The updated events were published in: https://github.com/intel/perfmon/commit/13983cd535d18b2bfd86a3b9daa374039f78a836 Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Signed-off-by: Namhyung Kim --- .../arch/x86/clearwaterforest/memory.json | 33 ++++++++++++++++++++++ .../arch/x86/clearwaterforest/pipeline.json | 19 +++++++++++++ .../x86/clearwaterforest/uncore-interconnect.json | 10 +++++++ .../arch/x86/clearwaterforest/uncore-memory.json | 2 +- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 5 files changed, 64 insertions(+), 2 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/clearwaterforest/memory.json b/tools/perf/pmu-events/arch/x86/clearwaterforest/memory.json index ae9095a090e5..477c06a561bb 100644 --- a/tools/perf/pmu-events/arch/x86/clearwaterforest/memory.json +++ b/tools/perf/pmu-events/arch/x86/clearwaterforest/memory.json @@ -91,6 +91,17 @@ "SampleAfterValue": "1000003", "UMask": "0x4" }, + { + "BriefDescription": "Counts demand data reads that were supplied by DRAM.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xB7", + "EventName": "OCR.DEMAND_DATA_RD.DRAM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x7BC000001", + "PublicDescription": "Counts demand data reads that were supplied by DRAM. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, { "BriefDescription": "Counts demand data reads that were not supplied by the L3 cache.", "Counter": "0,1,2,3,4,5,6,7", @@ -102,6 +113,28 @@ "SampleAfterValue": "100003", "UMask": "0x1" }, + { + "BriefDescription": "Counts demand data reads that were supplied by DRAM attached to this socket.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xB7", + "EventName": "OCR.DEMAND_DATA_RD.LOCAL_DRAM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x784000001", + "PublicDescription": "Counts demand data reads that were supplied by DRAM attached to this socket. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, + { + "BriefDescription": "Counts demand data reads that were supplied by DRAM attached to another socket.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xB7", + "EventName": "OCR.DEMAND_DATA_RD.REMOTE_DRAM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x730000001", + "PublicDescription": "Counts demand data reads that were supplied by DRAM attached to another socket. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, { "BriefDescription": "Counts demand read for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were not supplied by the L3 cache.", "Counter": "0,1,2,3,4,5,6,7", diff --git a/tools/perf/pmu-events/arch/x86/clearwaterforest/pipeline.json b/tools/perf/pmu-events/arch/x86/clearwaterforest/pipeline.json index 3d10dcffb8fc..f73686174af9 100644 --- a/tools/perf/pmu-events/arch/x86/clearwaterforest/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/clearwaterforest/pipeline.json @@ -291,6 +291,25 @@ "SampleAfterValue": "1000003", "UMask": "0x50" }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_RETURN]", + "Counter": "0,1,2,3,4,5,6,7", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_RET", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_RETURN] Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x8" + }, + { + "BriefDescription": "Counts the number of mispredicted near RET branch instructions retired. [This event is alias to BR_MISP_RETIRED.NEAR_RET]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_RETURN", + "PublicDescription": "Counts the number of mispredicted near RET branch instructions retired. [This event is alias to BR_MISP_RETIRED.NEAR_RET] Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x8" + }, { "BriefDescription": "Fixed Counter: Counts the number of unhalted core clock cycles. [This event is alias to CPU_CLK_UNHALTED.THREAD]", "Counter": "Fixed counter 1", diff --git a/tools/perf/pmu-events/arch/x86/clearwaterforest/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/clearwaterforest/uncore-interconnect.json index 251e5d20fefe..1f6e0970141a 100644 --- a/tools/perf/pmu-events/arch/x86/clearwaterforest/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/clearwaterforest/uncore-interconnect.json @@ -814,6 +814,16 @@ "PerPkg": "1", "Unit": "IRP" }, + { + "BriefDescription": "Counts Timeouts - Set 0 : Cache Inserts of Write Transactions as Secondary", + "Counter": "0,1,2,3", + "EventCode": "0x1E", + "EventName": "UNC_I_MISC0.2ND_WR_INSERT", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x8", + "Unit": "IRP" + }, { "BriefDescription": "Counts Timeouts - Set 0 : Fastpath Rejects", "Counter": "0,1,2,3", diff --git a/tools/perf/pmu-events/arch/x86/clearwaterforest/uncore-memory.json b/tools/perf/pmu-events/arch/x86/clearwaterforest/uncore-memory.json index 8184c2b6b861..cae7d0f6c34d 100644 --- a/tools/perf/pmu-events/arch/x86/clearwaterforest/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/clearwaterforest/uncore-memory.json @@ -520,7 +520,7 @@ "Unit": "IMC" }, { - "BriefDescription": "DRAM Precharge commands. : Precharge due to (?) : Counts the number of DRAM Precharge commands sent on this channel.", + "BriefDescription": "DRAM Precharge commands. : Precharge due to page table : Counts the number of DRAM Precharge commands sent on this channel.", "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "UNC_M_PRE_COUNT.PGT", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 7160ff89dac4..554ce716d402 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -7,7 +7,7 @@ GenuineIntel-6-(3D|47),v30,broadwell,core GenuineIntel-6-56,v12,broadwellde,core GenuineIntel-6-4F,v23,broadwellx,core GenuineIntel-6-55-[56789ABCDEF],v1.25,cascadelakex,core -GenuineIntel-6-DD,v1.02,clearwaterforest,core +GenuineIntel-6-DD,v1.04,clearwaterforest,core GenuineIntel-6-9[6C],v1.05,elkhartlake,core GenuineIntel-6-CF,v1.24,emeraldrapids,core GenuineIntel-6-5[CF],v13,goldmont,core -- cgit v1.2.3 From 79d8a962de781d771ecabe54bca058e526e0c733 Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Mon, 13 Jul 2026 11:17:50 -0700 Subject: perf vendor events intel: Update grandridge events from 1.12 to 1.13 The updated events were published in: https://github.com/intel/perfmon/commit/e479bd676826824110a49505b51a92952de91200 Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Signed-off-by: Namhyung Kim --- .../perf/pmu-events/arch/x86/grandridge/cache.json | 25 ++++ .../pmu-events/arch/x86/grandridge/counter.json | 42 ------- .../arch/x86/grandridge/floating-point.json | 56 +++++++++ .../pmu-events/arch/x86/grandridge/memory.json | 57 +++++++++ .../pmu-events/arch/x86/grandridge/pipeline.json | 140 +++++++++++++++++++++ .../arch/x86/grandridge/uncore-memory.json | 2 +- .../arch/x86/grandridge/virtual-memory.json | 8 ++ tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 8 files changed, 288 insertions(+), 44 deletions(-) delete mode 100644 tools/perf/pmu-events/arch/x86/grandridge/counter.json diff --git a/tools/perf/pmu-events/arch/x86/grandridge/cache.json b/tools/perf/pmu-events/arch/x86/grandridge/cache.json index 393ce9421c12..4c7727df33e4 100644 --- a/tools/perf/pmu-events/arch/x86/grandridge/cache.json +++ b/tools/perf/pmu-events/arch/x86/grandridge/cache.json @@ -1,4 +1,12 @@ [ + { + "BriefDescription": "Counts the number of requests that were not accepted into the L2Q because the L2Q is FULL.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x31", + "EventName": "CORE_REJECT_L2Q.ANY", + "PublicDescription": "Counts the number of (demand and L1 prefetchers) core requests rejected by the L2Q due to a full or nearly full w condition which likely indicates back pressure from L2Q. It also counts requests that would have gone directly to the XQ, but are rejected due to a full or nearly full condition, indicating back pressure from the IDI link. The L2Q may also reject transactions from a core to insure fairness between cores, or to delay a cores dirty eviction when the address conflicts incoming external snoops. (Note that L2 prefetcher requests that are dropped are not counted by this event.) Counts on a per core basis.", + "SampleAfterValue": "200003" + }, { "BriefDescription": "Counts the number of L1D cacheline (dirty) evictions caused by load misses, stores, and prefetches.", "Counter": "0,1,2,3,4,5,6,7", @@ -62,6 +70,14 @@ "SampleAfterValue": "1000003", "UMask": "0x1" }, + { + "BriefDescription": "Counts the number of demand and prefetch transactions that the External Queue (XQ) rejects due to a full or near full condition.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x30", + "EventName": "L2_REJECT_XQ.ANY", + "PublicDescription": "Counts the number of demand and prefetch transactions that the External Queue (XQ) rejects due to a full or near full condition which likely indicates back pressure from the IDI link. The XQ may reject transactions from the L2Q (non-cacheable requests), BBL (L2 misses) and WOB (L2 write-back victims).", + "SampleAfterValue": "200003" + }, { "BriefDescription": "Counts the number of L2 Cache Accesses that resulted in a Hit from a front door request only (does not include rejects or recycles), per core event", "Counter": "0,1,2,3,4,5,6,7", @@ -322,6 +338,15 @@ "SampleAfterValue": "20003", "UMask": "0x1" }, + { + "BriefDescription": "Counts the number of memory uops retired. A single uop that performs both a load AND a store will be counted as 1, not 2 (e.g. ADD [mem], CONST)", + "Counter": "0,1,2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_UOPS_RETIRED.ALL", + "SampleAfterValue": "200003", + "UMask": "0x83" + }, { "BriefDescription": "Counts the number of load ops retired.", "Counter": "0,1,2,3,4,5,6,7", diff --git a/tools/perf/pmu-events/arch/x86/grandridge/counter.json b/tools/perf/pmu-events/arch/x86/grandridge/counter.json deleted file mode 100644 index d9ac3aca5bd5..000000000000 --- a/tools/perf/pmu-events/arch/x86/grandridge/counter.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { - "Unit": "core", - "CountersNumFixed": "3", - "CountersNumGeneric": "8" - }, - { - "Unit": "B2CMI", - "CountersNumFixed": "0", - "CountersNumGeneric": "4" - }, - { - "Unit": "CHA", - "CountersNumFixed": "0", - "CountersNumGeneric": "4" - }, - { - "Unit": "IMC", - "CountersNumFixed": "0", - "CountersNumGeneric": "4" - }, - { - "Unit": "IIO", - "CountersNumFixed": "0", - "CountersNumGeneric": "4" - }, - { - "Unit": "IRP", - "CountersNumFixed": "0", - "CountersNumGeneric": "4" - }, - { - "Unit": "PCU", - "CountersNumFixed": "0", - "CountersNumGeneric": 4 - }, - { - "Unit": "CHACMS", - "CountersNumFixed": "0", - "CountersNumGeneric": "4" - } -] \ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/grandridge/floating-point.json b/tools/perf/pmu-events/arch/x86/grandridge/floating-point.json index c567f073713c..67d52477aad6 100644 --- a/tools/perf/pmu-events/arch/x86/grandridge/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/grandridge/floating-point.json @@ -8,6 +8,22 @@ "SampleAfterValue": "1000003", "UMask": "0x2" }, + { + "BriefDescription": "Counts the number of active floating point dividers per cycle in the loop stage.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcd", + "EventName": "ARITH.FPDIV_OCCUPANCY", + "SampleAfterValue": "1000003", + "UMask": "0x2" + }, + { + "BriefDescription": "Counts the number of floating point divider uops executed per cycle.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcd", + "EventName": "ARITH.FPDIV_UOPS", + "SampleAfterValue": "1000003", + "UMask": "0x8" + }, { "BriefDescription": "Counts the number of all types of floating point operations per uop with all default weighting", "Counter": "0,1,2,3,4,5,6,7", @@ -90,6 +106,46 @@ "SampleAfterValue": "1000003", "UMask": "0x2" }, + { + "BriefDescription": "Counts the number of uops executed on all floating point ports.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.ALL", + "SampleAfterValue": "1000003", + "UMask": "0xf" + }, + { + "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 0.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.P0", + "SampleAfterValue": "1000003", + "UMask": "0x2" + }, + { + "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 1.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.P1", + "SampleAfterValue": "1000003", + "UMask": "0x4" + }, + { + "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 2.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.P2", + "SampleAfterValue": "1000003", + "UMask": "0x8" + }, + { + "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 0, 1, 2.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.PRIMARY", + "SampleAfterValue": "1000003", + "UMask": "0xe" + }, { "BriefDescription": "Counts the number of uops executed on floating point and vector integer store data port.", "Counter": "0,1,2,3,4,5,6,7", diff --git a/tools/perf/pmu-events/arch/x86/grandridge/memory.json b/tools/perf/pmu-events/arch/x86/grandridge/memory.json index 48b6301e7696..3cbd86976e51 100644 --- a/tools/perf/pmu-events/arch/x86/grandridge/memory.json +++ b/tools/perf/pmu-events/arch/x86/grandridge/memory.json @@ -1,4 +1,12 @@ [ + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to any number of reasons, including an L1 miss, WCB full, pagewalk, store address block or store data block.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.ANY", + "SampleAfterValue": "1000003", + "UMask": "0x7f" + }, { "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to any number of reasons, including an L1 miss, WCB full, pagewalk, store address block or store data block, on a load that retires.", "Counter": "0,1,2,3,4,5,6,7", @@ -15,6 +23,14 @@ "SampleAfterValue": "1000003", "UMask": "0xf4" }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to a DL1 miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.L1_MISS", + "SampleAfterValue": "1000003", + "UMask": "0x1" + }, { "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to a DL1 miss.", "Counter": "0,1,2,3,4,5,6,7", @@ -23,6 +39,15 @@ "SampleAfterValue": "1000003", "UMask": "0x81" }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to other block cases.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.OTHER", + "PublicDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to other block cases such as pipeline conflicts, fences, etc.", + "SampleAfterValue": "1000003", + "UMask": "0x40" + }, { "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to other block cases.", "Counter": "0,1,2,3,4,5,6,7", @@ -32,6 +57,14 @@ "SampleAfterValue": "1000003", "UMask": "0xc0" }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to a pagewalk.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.PGWALK", + "SampleAfterValue": "1000003", + "UMask": "0x20" + }, { "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to a pagewalk.", "Counter": "0,1,2,3,4,5,6,7", @@ -40,6 +73,14 @@ "SampleAfterValue": "1000003", "UMask": "0xa0" }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to a store address match.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.ST_ADDR", + "SampleAfterValue": "1000003", + "UMask": "0x4" + }, { "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to a store address match.", "Counter": "0,1,2,3,4,5,6,7", @@ -48,6 +89,22 @@ "SampleAfterValue": "1000003", "UMask": "0x84" }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to request buffers full or lock in progress.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.WCB_FULL", + "SampleAfterValue": "1000003", + "UMask": "0x2" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to request buffers full or lock in progress.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.WCB_FULL_AT_RET", + "SampleAfterValue": "1000003", + "UMask": "0x82" + }, { "BriefDescription": "Counts the number of machine clears due to memory ordering caused by a snoop from an external agent. Does not count internally generated machine clears such as those due to memory disambiguation.", "Counter": "0,1,2,3,4,5,6,7", diff --git a/tools/perf/pmu-events/arch/x86/grandridge/pipeline.json b/tools/perf/pmu-events/arch/x86/grandridge/pipeline.json index 0a8f7d327150..01cf2d81757f 100644 --- a/tools/perf/pmu-events/arch/x86/grandridge/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/grandridge/pipeline.json @@ -8,6 +8,31 @@ "SampleAfterValue": "1000003", "UMask": "0x3" }, + { + "BriefDescription": "Counts the number of cycles when any of the integer dividers are active.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0xcd", + "EventName": "ARITH.IDIV_ACTIVE", + "SampleAfterValue": "1000003", + "UMask": "0x1" + }, + { + "BriefDescription": "Counts the number of active integer dividers per cycle.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcd", + "EventName": "ARITH.IDIV_OCCUPANCY", + "SampleAfterValue": "1000003", + "UMask": "0x1" + }, + { + "BriefDescription": "Counts the number of integer divider uops executed per cycle.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcd", + "EventName": "ARITH.IDIV_UOPS", + "SampleAfterValue": "1000003", + "UMask": "0x4" + }, { "BriefDescription": "Counts the total number of branch instructions retired for all branch types.", "Counter": "0,1,2,3,4,5,6,7", @@ -113,6 +138,14 @@ "SampleAfterValue": "200003", "UMask": "0xdf" }, + { + "BriefDescription": "Counts the number of taken branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.TAKEN", + "SampleAfterValue": "200003", + "UMask": "0x80" + }, { "BriefDescription": "Counts the total number of mispredicted branch instructions retired for all branch types.", "Counter": "0,1,2,3,4,5,6,7", @@ -236,6 +269,80 @@ "EventName": "INST_RETIRED.ANY_P", "SampleAfterValue": "2000003" }, + { + "BriefDescription": "Counts the number of uops executed on all Integer ports.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.ALL", + "SampleAfterValue": "1000003", + "UMask": "0xff" + }, + { + "BriefDescription": "Counts the number of uops executed on a load port.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.LD", + "PublicDescription": "Counts the number of uops executed on a load port. This event counts for integer uops even if the destination is FP/vector", + "SampleAfterValue": "1000003", + "UMask": "0x1" + }, + { + "BriefDescription": "Counts the number of uops executed on integer port 0.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.P0", + "SampleAfterValue": "1000003", + "UMask": "0x8" + }, + { + "BriefDescription": "Counts the number of uops executed on integer port 1.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.P1", + "SampleAfterValue": "1000003", + "UMask": "0x10" + }, + { + "BriefDescription": "Counts the number of uops executed on integer port 2.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.P2", + "SampleAfterValue": "1000003", + "UMask": "0x20" + }, + { + "BriefDescription": "Counts the number of uops executed on integer port 3.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.P3", + "SampleAfterValue": "1000003", + "UMask": "0x40" + }, + { + "BriefDescription": "Counts the number of uops executed on integer port 0,1, 2, 3.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.PRIMARY", + "SampleAfterValue": "1000003", + "UMask": "0x78" + }, + { + "BriefDescription": "Counts the number of uops executed on a Store address port.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.STA", + "PublicDescription": "Counts the number of uops executed on a Store address port. This event counts integer uops even if the data source is FP/vector", + "SampleAfterValue": "1000003", + "UMask": "0x2" + }, + { + "BriefDescription": "Counts the number of uops executed on an integer store data and jump port.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.STD_JMP", + "SampleAfterValue": "1000003", + "UMask": "0x4" + }, { "BriefDescription": "Counts the number of retired loads that are blocked because it initially appears to be store forward blocked, but subsequently is shown not to be blocked based on 4K alias check.", "Counter": "0,1,2,3,4,5,6,7", @@ -275,6 +382,22 @@ "SampleAfterValue": "20003", "UMask": "0x8" }, + { + "BriefDescription": "Counts the number of machine clears that flush the pipeline and restart the machine without the use of microcode.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.FAST", + "SampleAfterValue": "20003", + "UMask": "0x10" + }, + { + "BriefDescription": "Counts the number of virtual traps taken.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.FPC_VIRTUAL_TRAP", + "SampleAfterValue": "20003", + "UMask": "0x40" + }, { "BriefDescription": "Counts the number of machines clears due to memory renaming.", "Counter": "0,1,2,3,4,5,6,7", @@ -356,6 +479,23 @@ "SampleAfterValue": "200003", "UMask": "0x4" }, + { + "BriefDescription": "Counts the number of issue slots not consumed due to a color request for an FCW or MXCSR control register when all 4 colors (copies) are already in use.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x75", + "EventName": "SERIALIZATION.COLOR_STALLS", + "SampleAfterValue": "200003", + "UMask": "0x8" + }, + { + "BriefDescription": "Counts the number of issue slots not consumed by the backend due to a micro-sequencer (MS) scoreboard, which stalls the front-end from issuing from the UROM until a specified older uop retires.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x75", + "EventName": "SERIALIZATION.NON_C01_MS_SCB", + "PublicDescription": "Counts the number of issue slots not consumed by the backend due to a micro-sequencer (MS) scoreboard, which stalls the front-end from issuing from the UROM until a specified older uop retires. The most commonly executed instruction with an MS scoreboard is PAUSE.", + "SampleAfterValue": "200003", + "UMask": "0x2" + }, { "BriefDescription": "Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL_P]", "Counter": "0,1,2,3,4,5,6,7", diff --git a/tools/perf/pmu-events/arch/x86/grandridge/uncore-memory.json b/tools/perf/pmu-events/arch/x86/grandridge/uncore-memory.json index 8413391d752c..cec6e0a3147a 100644 --- a/tools/perf/pmu-events/arch/x86/grandridge/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/grandridge/uncore-memory.json @@ -448,7 +448,7 @@ "Unit": "IMC" }, { - "BriefDescription": "DRAM Precharge commands. : Precharge due to (?) : Counts the number of DRAM Precharge commands sent on this channel.", + "BriefDescription": "DRAM Precharge commands. : Precharge due to page table : Counts the number of DRAM Precharge commands sent on this channel.", "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "UNC_M_PRE_COUNT.PGT", diff --git a/tools/perf/pmu-events/arch/x86/grandridge/virtual-memory.json b/tools/perf/pmu-events/arch/x86/grandridge/virtual-memory.json index 35cc5b6d41f2..88996fdac15f 100644 --- a/tools/perf/pmu-events/arch/x86/grandridge/virtual-memory.json +++ b/tools/perf/pmu-events/arch/x86/grandridge/virtual-memory.json @@ -137,6 +137,14 @@ "SampleAfterValue": "200003", "UMask": "0x10" }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to a DTLB miss", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.DTLB_MISS", + "SampleAfterValue": "1000003", + "UMask": "0x10" + }, { "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to a DTLB miss.", "Counter": "0,1,2,3,4,5,6,7", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 554ce716d402..d9f45cc906c7 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -12,7 +12,7 @@ GenuineIntel-6-9[6C],v1.05,elkhartlake,core GenuineIntel-6-CF,v1.24,emeraldrapids,core GenuineIntel-6-5[CF],v13,goldmont,core GenuineIntel-6-7A,v1.01,goldmontplus,core -GenuineIntel-6-B6,v1.12,grandridge,core +GenuineIntel-6-B6,v1.13,grandridge,core GenuineIntel-6-A[DE],v1.19,graniterapids,core GenuineIntel-6-(3C|45|46),v36,haswell,core GenuineIntel-6-3F,v29,haswellx,core -- cgit v1.2.3 From 51291e81bb64b2a2d6451e11b09133efcf67abe6 Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Mon, 13 Jul 2026 11:17:51 -0700 Subject: perf vendor events intel: Update graniterapids events from 1.19 to 1.20 The updated events were published in: https://github.com/intel/perfmon/commit/084ecb869d75f9e5383354d3fe68a93aa25be112 Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Signed-off-by: Namhyung Kim --- .../arch/x86/graniterapids/gnr-metrics.json | 102 +++++++++++---------- .../arch/x86/graniterapids/metricgroups.json | 2 +- .../arch/x86/graniterapids/pipeline.json | 2 +- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 4 files changed, 55 insertions(+), 53 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/gnr-metrics.json b/tools/perf/pmu-events/arch/x86/graniterapids/gnr-metrics.json index 299631fb8d53..95e05812eb3b 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/gnr-metrics.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/gnr-metrics.json @@ -452,15 +452,15 @@ }, { "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_miss_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_uc_bound" }, { "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + 0 / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency) + tma_memory_bound * (tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_miss_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", "MetricName": "tma_bottleneck_data_cache_memory_latency", "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", @@ -483,7 +483,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_dtlb_load / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", "MetricThreshold": "tma_bottleneck_memory_data_tlbs > 20", @@ -491,7 +491,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) * tma_remote_cache / (tma_local_mem + tma_remote_cache + tma_remote_mem) + tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_miss_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) * tma_remote_cache / (tma_local_mem + tma_remote_cache + tma_remote_mem) + tma_l3_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_cxl_mem_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", "MetricThreshold": "tma_bottleneck_memory_synchronization > 10", @@ -624,7 +624,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by non-taken conditional branches.", - "MetricExpr": "BR_MISP_RETIRED.COND_NTAKEN_COST * BR_MISP_RETIRED.COND_NTAKEN_COST:R / tma_info_thread_clks", + "MetricExpr": "BR_MISP_RETIRED.COND_NTAKEN / BR_MISP_RETIRED.ALL_BRANCHES * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_cond_nt_mispredicts", "MetricThreshold": "tma_cond_nt_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -632,7 +632,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to misprediction by taken conditional branches.", - "MetricExpr": "BR_MISP_RETIRED.COND_TAKEN_COST * BR_MISP_RETIRED.COND_TAKEN_COST:R / tma_info_thread_clks", + "MetricExpr": "BR_MISP_RETIRED.COND_TAKEN / BR_MISP_RETIRED.ALL_BRANCHES * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_cond_tk_mispredicts", "MetricThreshold": "tma_cond_tk_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -668,13 +668,13 @@ "ScaleUnit": "100%" }, { - "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses", + "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to L3 data-sharing accesses", "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD * min(MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD:R, 74.6 * tma_info_system_core_frequency) + MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD * min(MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD:R, 74.6 * tma_info_system_core_frequency) * (1 - OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM / (OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM + OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD))) * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "BvMS;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_data_sharing", "MetricThreshold": "tma_data_sharing > 0.05 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses. Data shared by multiple Logical Processors (even just read shared) may cause increased access latency due to cache coherency. Excessive data sharing can drastically harm multithreaded performance. Sample with: MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_false_sharing, tma_machine_clears, tma_remote_cache", + "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to L3 data-sharing accesses. Data shared by multiple Logical Processors (even just read shared) may cause increased access latency due to cache coherency. Excessive data sharing can drastically harm multithreaded performance. Sample with: MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_false_sharing, tma_machine_clears, tma_remote_cache", "ScaleUnit": "100%" }, { @@ -695,15 +695,6 @@ "PublicDescription": "This metric represents fraction of cycles where the Divider unit was active. Divide and square root instructions are performed by the Divider unit and can take considerably longer latency than integer or Floating Point addition; subtraction; or multiplication. Sample with: ARITH.DIV_ACTIVE", "ScaleUnit": "100%" }, - { - "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", - "MetricExpr": "(MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks - tma_cxl_mem_bound if #has_pmem > 0 else MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks)", - "MetricGroup": "MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", - "MetricName": "tma_dram_bound", - "MetricThreshold": "tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", - "PublicDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads. Better caching can improve the latency and increase performance. Sample with: MEM_LOAD_RETIRED.L3_MISS", - "ScaleUnit": "100%" - }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to DSB (decoded uop cache) fetch pipeline", "MetricExpr": "(IDQ.DSB_CYCLES_ANY - IDQ.DSB_CYCLES_OK) / tma_info_core_core_clks / 2", @@ -755,7 +746,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores, tma_uc_bound", "ScaleUnit": "100%" }, { @@ -902,7 +893,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by indirect CALL instructions.", - "MetricExpr": "BR_MISP_RETIRED.INDIRECT_CALL_COST * BR_MISP_RETIRED.INDIRECT_CALL_COST:R / tma_info_thread_clks", + "MetricExpr": "BR_MISP_RETIRED.INDIRECT_CALL / BR_MISP_RETIRED.ALL_BRANCHES * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_ind_call_mispredicts", "MetricThreshold": "tma_ind_call_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -910,7 +901,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by indirect JMP instructions.", - "MetricExpr": "max((BR_MISP_RETIRED.INDIRECT_COST * BR_MISP_RETIRED.INDIRECT_COST:R - BR_MISP_RETIRED.INDIRECT_CALL_COST * BR_MISP_RETIRED.INDIRECT_CALL_COST:R) / tma_info_thread_clks, 0)", + "MetricExpr": "max((BR_MISP_RETIRED.INDIRECT - BR_MISP_RETIRED.INDIRECT_CALL) / BR_MISP_RETIRED.ALL_BRANCHES * tma_branch_mispredicts, 0)", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_ind_jump_mispredicts", "MetricThreshold": "tma_ind_jump_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -1045,7 +1036,7 @@ }, { "BriefDescription": "Floating Point Operations Per Cycle", - "MetricExpr": "(cpu@FP_ARITH_INST_RETIRED.SCALAR_SINGLE\\,umask\\=0x03@ + 2 * FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4 * cpu@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE\\,umask\\=0x18@ + 8 * cpu@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE\\,umask\\=0x60@ + 16 * FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE) / tma_info_core_core_clks", + "MetricExpr": "(FP_ARITH_INST_RETIRED.SCALAR + 2 * FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4 * FP_ARITH_INST_RETIRED.4_FLOPS + 8 * FP_ARITH_INST_RETIRED.8_FLOPS + 16 * FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE) / tma_info_core_core_clks", "MetricGroup": "Flops;Ret", "MetricName": "tma_info_core_flopc" }, @@ -1064,7 +1055,7 @@ }, { "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded ICache; or Uop Cache)", - "MetricExpr": "IDQ.DSB_UOPS / UOPS_ISSUED.ANY", + "MetricExpr": "IDQ.DSB_UOPS / (IDQ.DSB_UOPS + IDQ.MITE_UOPS + IDQ.MS_UOPS)", "MetricGroup": "DSB;Fed;FetchBW;tma_issueFB", "MetricName": "tma_info_frontend_dsb_coverage", "MetricThreshold": "tma_info_frontend_dsb_coverage < 0.7 & tma_info_thread_ipc / 6 > 0.35", @@ -1202,7 +1193,7 @@ { "BriefDescription": "Instructions per FP Arithmetic Scalar Half-Precision instruction (lower number means higher occurrence rate)", "MetricExpr": "INST_RETIRED.ANY / FP_ARITH_INST_RETIRED2.SCALAR", - "MetricGroup": "Flops;FpScalar;InsType;Server", + "MetricGroup": "Flops;FpScalar;InsType", "MetricName": "tma_info_inst_mix_iparith_scalar_hp", "MetricThreshold": "tma_info_inst_mix_iparith_scalar_hp < 10", "PublicDescription": "Instructions per FP Arithmetic Scalar Half-Precision instruction (lower number means higher occurrence rate). Values < 1 are possible due to intentional FMA double counting." @@ -1231,7 +1222,7 @@ }, { "BriefDescription": "Instructions per Floating Point (FP) Operation (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / (cpu@FP_ARITH_INST_RETIRED.SCALAR_SINGLE\\,umask\\=0x03@ + 2 * FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4 * cpu@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE\\,umask\\=0x18@ + 8 * cpu@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE\\,umask\\=0x60@ + 16 * FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE)", + "MetricExpr": "INST_RETIRED.ANY / (FP_ARITH_INST_RETIRED.SCALAR + 2 * FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4 * FP_ARITH_INST_RETIRED.4_FLOPS + 8 * FP_ARITH_INST_RETIRED.8_FLOPS + 16 * FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE)", "MetricGroup": "Flops;InsType", "MetricName": "tma_info_inst_mix_ipflop", "MetricThreshold": "tma_info_inst_mix_ipflop < 10" @@ -1271,6 +1262,14 @@ "MetricThreshold": "tma_info_inst_mix_iptb < 13", "PublicDescription": "Instructions per taken branch. Related metrics: tma_dsb_switches, tma_fetch_bandwidth, tma_info_botlnk_l2_dsb_bandwidth, tma_info_botlnk_l2_dsb_misses, tma_info_frontend_dsb_coverage, tma_lcp" }, + { + "BriefDescription": "AVX preserve/restore assists per kilo instruction", + "MetricExpr": "1e3 * ASSISTS.SSE_AVX_MIX / INST_RETIRED.ANY", + "MetricGroup": "tma_issueMV", + "MetricName": "tma_info_inst_mix_vectormixpki", + "MetricThreshold": "tma_info_inst_mix_vectormixpki > 0.05", + "PublicDescription": "AVX preserve/restore assists per kilo instruction. Related metrics: tma_mixing_vectors, tma_ms_switches" + }, { "BriefDescription": "Average per-core data fill bandwidth to the L1 data cache [GB / sec]", "MetricExpr": "tma_info_memory_l1d_cache_fill_bw", @@ -1526,7 +1525,7 @@ "MetricName": "tma_info_memory_tlb_store_stlb_mpki" }, { - "BriefDescription": "Mem;Backend;CacheHits", + "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is execution) per physical core", "MetricExpr": "UOPS_EXECUTED.THREAD / (UOPS_EXECUTED.CORE_CYCLES_GE_1 / 2 if #SMT_on else cpu@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -1606,11 +1605,11 @@ "MetricExpr": "64 * (UNC_M_CAS_COUNT_SCH0.RD + UNC_M_CAS_COUNT_SCH1.RD + UNC_M_CAS_COUNT_SCH0.WR + UNC_M_CAS_COUNT_SCH1.WR) / 1e9 / tma_info_system_time", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full, tma_uc_bound" }, { "BriefDescription": "Giga Floating Point Operations Per Second", - "MetricExpr": "(cpu@FP_ARITH_INST_RETIRED.SCALAR_SINGLE\\,umask\\=0x03@ + 2 * FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4 * cpu@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE\\,umask\\=0x18@ + 8 * cpu@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE\\,umask\\=0x60@ + 16 * FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE) / 1e9 / tma_info_system_time", + "MetricExpr": "(FP_ARITH_INST_RETIRED.SCALAR + 2 * FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4 * FP_ARITH_INST_RETIRED.4_FLOPS + 8 * FP_ARITH_INST_RETIRED.8_FLOPS + 16 * FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE) / 1e9 / tma_info_system_time", "MetricGroup": "Cor;Flops;HPC", "MetricName": "tma_info_system_gflops", "PublicDescription": "Giga Floating Point Operations Per Second. Aggregate across all supported options of: FP precisions, scalar and vector instructions, vector-width" @@ -1701,12 +1700,6 @@ "MetricGroup": "Power", "MetricName": "tma_info_system_turbo_utilization" }, - { - "BriefDescription": "Measured Average Uncore Frequency for the SoC [GHz]", - "MetricExpr": "tma_info_system_socket_clks / 1e9 / tma_info_system_time", - "MetricGroup": "SoC", - "MetricName": "tma_info_system_uncore_frequency" - }, { "BriefDescription": "Cross-socket Ultra Path Interconnect (UPI) data transmit bandwidth for data only [MB / sec]", "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 64 / 9 / 1e6", @@ -1862,6 +1855,15 @@ "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%" }, + { + "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", + "MetricExpr": "(MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks - tma_cxl_mem_bound if #has_pmem > 0 else MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks)", + "MetricGroup": "MemoryBound;Offcore;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", + "MetricName": "tma_l3_miss_bound", + "MetricThreshold": "tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", + "PublicDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads. Better caching can improve the latency and increase performance. Sample with: MEM_LOAD_RETIRED.L3_MISS", + "ScaleUnit": "100%" + }, { "BriefDescription": "This metric represents fraction of cycles CPU was stalled due to Length Changing Prefixes (LCPs)", "MetricExpr": "DECODE.LCP / tma_info_thread_clks", @@ -1936,7 +1938,7 @@ "MetricExpr": "MEM_LOAD_L3_MISS_RETIRED.LOCAL_DRAM * MEM_LOAD_L3_MISS_RETIRED.LOCAL_DRAM:R * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "Server;TopdownL5;tma_L5_group;tma_mem_latency_group", "MetricName": "tma_local_mem", - "MetricThreshold": "tma_local_mem > 0.1 & (tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", + "MetricThreshold": "tma_local_mem > 0.1 & (tma_mem_latency > 0.1 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from local memory. Caching will improve the latency and increase performance. Sample with: MEM_LOAD_L3_MISS_RETIRED.LOCAL_DRAM", "ScaleUnit": "100%" }, @@ -1966,24 +1968,24 @@ "MetricExpr": "INT_MISC.MBA_STALLS / tma_info_thread_clks", "MetricGroup": "MemoryBW;Offcore;Server;TopdownL5;tma_L5_group;tma_mem_bandwidth_group", "MetricName": "tma_mba_stalls", - "MetricThreshold": "tma_mba_stalls > 0.1 & (tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", + "MetricThreshold": "tma_mba_stalls > 0.1 & (tma_mem_bandwidth > 0.2 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", "ScaleUnit": "100%" }, { "BriefDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM)", - "MetricExpr": "min(CPU_CLK_UNHALTED.THREAD, cpu@OFFCORE_REQUESTS_OUTSTANDING.DATA_RD\\,cmask\\=4@) / tma_info_thread_clks", - "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", + "MetricExpr": "min(CPU_CLK_UNHALTED.THREAD, cpu@OFFCORE_REQUESTS_OUTSTANDING.DATA_RD\\,cmask\\=12@) / tma_info_thread_clks", + "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_miss_bound_group", "MetricName": "tma_mem_bandwidth", - "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full, tma_uc_bound", "ScaleUnit": "100%" }, { "BriefDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM)", "MetricExpr": "min(CPU_CLK_UNHALTED.THREAD, OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD) / tma_info_thread_clks - tma_mem_bandwidth", - "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", + "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_miss_bound_group", "MetricName": "tma_mem_latency", - "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", + "MetricThreshold": "tma_mem_latency > 0.1 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%" }, @@ -2047,7 +2049,7 @@ "MetricGroup": "TopdownL5;tma_L5_group;tma_issueMV;tma_ports_utilized_0_group", "MetricName": "tma_mixing_vectors", "MetricThreshold": "tma_mixing_vectors > 0.05", - "PublicDescription": "This metric estimates penalty in terms of percentage of([SKL+] injected blend uops out of all Uops Issued -- the Count Domain; [ADL+] cycles). Usually a Mixing_Vectors over 5% is worth investigating. Read more in Appendix B1 of the Optimizations Guide for this topic. Related metrics: tma_ms_switches", + "PublicDescription": "This metric estimates penalty in terms of percentage of([SKL+] injected blend uops out of all Uops Issued -- the Count Domain; [ADL+] cycles). Usually a Mixing_Vectors over 5% is worth investigating. Read more in Appendix B1 of the Optimizations Guide for this topic. Related metrics: tma_info_inst_mix_vectormixpki, tma_ms_switches", "ScaleUnit": "100%" }, { @@ -2064,7 +2066,7 @@ "MetricGroup": "FetchLat;MicroSeq;TopdownL3;tma_L3_group;tma_fetch_latency_group;tma_issueMC;tma_issueMS;tma_issueMV;tma_issueSO", "MetricName": "tma_ms_switches", "MetricThreshold": "tma_ms_switches > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", - "PublicDescription": "This metric estimates the fraction of cycles when the CPU was stalled due to switches of uop delivery to the Microcode Sequencer (MS). Commonly used instructions are optimized for delivery by the DSB (decoded i-cache) or MITE (legacy instruction decode) pipelines. Certain operations cannot be handled natively by the execution pipeline; and must be performed by microcode (small programs injected into the execution stream). Switching to the MS too often can negatively impact performance. The MS is designated to deliver long uop flows required by CISC instructions like CPUID; or uncommon conditions like Floating Point Assists when dealing with Denormals. Sample with: IDQ.MS_SWITCHES. Related metrics: tma_bottleneck_irregular_overhead, tma_clears_resteers, tma_l1_bound, tma_machine_clears, tma_microcode_sequencer, tma_mixing_vectors, tma_serializing_operation", + "PublicDescription": "This metric estimates the fraction of cycles when the CPU was stalled due to switches of uop delivery to the Microcode Sequencer (MS). Commonly used instructions are optimized for delivery by the DSB (decoded i-cache) or MITE (legacy instruction decode) pipelines. Certain operations cannot be handled natively by the execution pipeline; and must be performed by microcode (small programs injected into the execution stream). Switching to the MS too often can negatively impact performance. The MS is designated to deliver long uop flows required by CISC instructions like CPUID; or uncommon conditions like Floating Point Assists when dealing with Denormals. Sample with: IDQ.MS_SWITCHES. Related metrics: tma_bottleneck_irregular_overhead, tma_clears_resteers, tma_info_inst_mix_vectormixpki, tma_l1_bound, tma_machine_clears, tma_microcode_sequencer, tma_mixing_vectors, tma_serializing_operation", "ScaleUnit": "100%" }, { @@ -2197,25 +2199,25 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from remote cache in other sockets including synchronizations issues", - "MetricExpr": "(MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM * PEBS + MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD * PEBS) * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", + "MetricExpr": "(MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM * MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM:R + MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD * MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD:R) * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "Offcore;Server;Snoop;TopdownL5;tma_L5_group;tma_issueSyncxn;tma_mem_latency_group", "MetricName": "tma_remote_cache", - "MetricThreshold": "tma_remote_cache > 0.05 & (tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", + "MetricThreshold": "tma_remote_cache > 0.05 & (tma_mem_latency > 0.1 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from remote cache in other sockets including synchronizations issues. This is caused often due to non-optimal NUMA allocations. #link to NUMA article. Sample with: MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM_PS;MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD_PS. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_data_sharing, tma_false_sharing, tma_machine_clears", "ScaleUnit": "100%" }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from remote memory", - "MetricExpr": "MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM * PEBS * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", + "MetricExpr": "MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM * MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM:R * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "Server;Snoop;TopdownL5;tma_L5_group;tma_mem_latency_group", "MetricName": "tma_remote_mem", - "MetricThreshold": "tma_remote_mem > 0.1 & (tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", + "MetricThreshold": "tma_remote_mem > 0.1 & (tma_mem_latency > 0.1 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from remote memory. This is caused often due to non-optimal NUMA allocations. #link to NUMA article. Sample with: MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM_PS", "ScaleUnit": "100%" }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by (indirect) RET instructions.", - "MetricExpr": "BR_MISP_RETIRED.RET_COST * BR_MISP_RETIRED.RET_COST:R / tma_info_thread_clks", + "MetricExpr": "BR_MISP_RETIRED.RET / BR_MISP_RETIRED.ALL_BRANCHES * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_ret_mispredicts", "MetricThreshold": "tma_ret_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -2283,7 +2285,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_uc_bound", "ScaleUnit": "100%" }, { diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/metricgroups.json b/tools/perf/pmu-events/arch/x86/graniterapids/metricgroups.json index 9129fb7b7ce4..b5f601991e9d 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/metricgroups.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/metricgroups.json @@ -90,7 +90,6 @@ "tma_code_stlb_miss_group": "Metrics contributing to tma_code_stlb_miss category", "tma_core_bound_group": "Metrics contributing to tma_core_bound category", "tma_divider_group": "Metrics contributing to tma_divider category", - "tma_dram_bound_group": "Metrics contributing to tma_dram_bound category", "tma_dtlb_load_group": "Metrics contributing to tma_dtlb_load category", "tma_dtlb_store_group": "Metrics contributing to tma_dtlb_store category", "tma_fetch_bandwidth_group": "Metrics contributing to tma_fetch_bandwidth category", @@ -124,6 +123,7 @@ "tma_l1_bound_group": "Metrics contributing to tma_l1_bound category", "tma_l2_bound_group": "Metrics contributing to tma_l2_bound category", "tma_l3_bound_group": "Metrics contributing to tma_l3_bound category", + "tma_l3_miss_bound_group": "Metrics contributing to tma_l3_miss_bound category", "tma_light_operations_group": "Metrics contributing to tma_light_operations category", "tma_load_op_utilization_group": "Metrics contributing to tma_load_op_utilization category", "tma_load_stlb_miss_group": "Metrics contributing to tma_load_stlb_miss category", diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/pipeline.json b/tools/perf/pmu-events/arch/x86/graniterapids/pipeline.json index 0fef8fd61974..afc77bdeb600 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/pipeline.json @@ -559,7 +559,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", - "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent.", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note: Since the number of iterations within a REP instruction can be significantly affected by fast strings, this event may vary run to run and not match the architectural number of iterations (specified by RCX)", "SampleAfterValue": "2000003", "UMask": "0x8" }, diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index d9f45cc906c7..21f624e20cf3 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -13,7 +13,7 @@ GenuineIntel-6-CF,v1.24,emeraldrapids,core GenuineIntel-6-5[CF],v13,goldmont,core GenuineIntel-6-7A,v1.01,goldmontplus,core GenuineIntel-6-B6,v1.13,grandridge,core -GenuineIntel-6-A[DE],v1.19,graniterapids,core +GenuineIntel-6-A[DE],v1.20,graniterapids,core GenuineIntel-6-(3C|45|46),v36,haswell,core GenuineIntel-6-3F,v29,haswellx,core GenuineIntel-6-7[DE],v1.24,icelake,core -- cgit v1.2.3 From 98ebd9d679db5199665e3f895b0625146a9b89a0 Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Mon, 13 Jul 2026 11:17:52 -0700 Subject: perf vendor events intel: Update lunarlake events from 1.25 to 1.26 The updated events were published in: https://github.com/intel/perfmon/commit/2ba9dec72a771ed3ce7114d6a16797131871fd61 Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Signed-off-by: Namhyung Kim --- .../pmu-events/arch/x86/lunarlake/lnl-metrics.json | 142 ++++++++++++--------- .../arch/x86/lunarlake/metricgroups.json | 2 +- .../pmu-events/arch/x86/lunarlake/pipeline.json | 2 +- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 4 files changed, 83 insertions(+), 65 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/lnl-metrics.json b/tools/perf/pmu-events/arch/x86/lunarlake/lnl-metrics.json index 06390a72110d..6bc62297ca6c 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/lnl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/lnl-metrics.json @@ -783,16 +783,16 @@ }, { "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_miss_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency + tma_uc_bound)) + tma_memory_bound * (tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)))", "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_uc_bound", "Unit": "cpu_core" }, { "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_capacity / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_miss_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency + tma_uc_bound)) + tma_memory_bound * (tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_l1_latency_capacity / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", "MetricName": "tma_bottleneck_data_cache_memory_latency", "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", @@ -818,7 +818,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_dtlb_load / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", "MetricThreshold": "tma_bottleneck_memory_data_tlbs > 20", @@ -827,7 +827,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", "MetricThreshold": "tma_bottleneck_memory_synchronization > 10", @@ -975,7 +975,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by non-taken conditional branches.", - "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_NTAKEN_COST@ * cpu_core@BR_MISP_RETIRED.COND_NTAKEN_COST@R / tma_info_thread_clks", + "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_NTAKEN@ / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_cond_nt_mispredicts", "MetricThreshold": "tma_cond_nt_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -984,7 +984,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to misprediction by backward-taken conditional branches.", - "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_TAKEN_BWD_COST@ * cpu_core@BR_MISP_RETIRED.COND_TAKEN_BWD_COST@R / tma_info_thread_clks", + "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_TAKEN_BWD@ / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_cond_tk_bwd_mispredicts", "MetricThreshold": "tma_cond_tk_bwd_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -993,7 +993,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to misprediction by forward-taken conditional branches.", - "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_TAKEN_FWD_COST@ * cpu_core@BR_MISP_RETIRED.COND_TAKEN_FWD_COST@R / tma_info_thread_clks", + "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_TAKEN_FWD@ / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_cond_tk_fwd_mispredicts", "MetricThreshold": "tma_cond_tk_fwd_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -1022,13 +1022,13 @@ "Unit": "cpu_core" }, { - "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses", + "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to L3 data-sharing accesses", "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD@ * min(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD@R, 24 * tma_info_system_core_frequency) + cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD@ * min(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD@R, 25 * tma_info_system_core_frequency)) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "BvMS;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_data_sharing", "MetricThreshold": "tma_data_sharing > 0.05 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses. Data shared by multiple Logical Processors (even just read shared) may cause increased access latency due to cache coherency. Excessive data sharing can drastically harm multithreaded performance. Sample with: MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_false_sharing, tma_machine_clears, tma_remote_cache", + "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to L3 data-sharing accesses. Data shared by multiple Logical Processors (even just read shared) may cause increased access latency due to cache coherency. Excessive data sharing can drastically harm multithreaded performance. Sample with: MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_false_sharing, tma_machine_clears, tma_remote_cache", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -1042,19 +1042,9 @@ "ScaleUnit": "100%", "Unit": "cpu_core" }, - { - "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", - "MetricExpr": "cpu_core@MEMORY_STALLS.MEM@ / tma_info_thread_clks", - "MetricGroup": "MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", - "MetricName": "tma_dram_bound", - "MetricThreshold": "tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", - "PublicDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads. Better caching can improve the latency and increase performance. Sample with: MEM_LOAD_RETIRED.L3_MISS", - "ScaleUnit": "100%", - "Unit": "cpu_core" - }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to DSB (decoded uop cache) fetch pipeline", - "MetricExpr": "(cpu_core@IDQ.DSB_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / 2 + cpu_core@IDQ.DSB_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.STARVATION_CYCLES@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", + "MetricExpr": "(cpu_core@IDQ.DSB_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ * max(0, 8 - tma_info_pipeline_fetch_dsb) / 8 + cpu_core@IDQ.DSB_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.STARVATION_CYCLES@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", "MetricGroup": "DSB;FetchBW;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_dsb", "MetricThreshold": "tma_dsb > 0.15 & tma_fetch_bandwidth > 0.2", @@ -1108,7 +1098,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores, tma_uc_bound", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -1205,7 +1195,7 @@ }, { "BriefDescription": "This metric approximates arithmetic FP vector uops fraction the CPU has retired for 256-bit wide vectors", - "MetricExpr": "cpu_core@FP_ARITH_OPS_RETIRED.VECTOR\\,umask\\=0x30@ / (tma_retiring * tma_info_thread_slots)", + "MetricExpr": "cpu_core@FP_ARITH_OPS_RETIRED.VECTOR_256B@ / (tma_retiring * tma_info_thread_slots)", "MetricGroup": "Compute;Flops;TopdownL5;tma_L5_group;tma_fp_vector_group;tma_issue2P", "MetricName": "tma_fp_vector_256b", "MetricThreshold": "tma_fp_vector_256b > 0.1 & (tma_fp_vector > 0.1 & (tma_fp_arith > 0.2 & tma_light_operations > 0.6))", @@ -1248,7 +1238,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to instruction cache misses", - "MetricExpr": "cpu_core@ICACHE_DATA.STALLS@ / tma_info_thread_clks", + "MetricExpr": "cpu_core@ICACHE_DATA.STALLS@ / tma_info_thread_clks + tma_isb_full", "MetricGroup": "BigFootprint;BvBC;FetchLat;IcMiss;TopdownL3;tma_L3_group;tma_fetch_latency_group", "MetricName": "tma_icache_misses", "MetricThreshold": "tma_icache_misses > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", @@ -1258,7 +1248,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by indirect CALL instructions.", - "MetricExpr": "cpu_core@BR_MISP_RETIRED.INDIRECT_CALL_COST@ * cpu_core@BR_MISP_RETIRED.INDIRECT_CALL_COST@R / tma_info_thread_clks", + "MetricExpr": "cpu_core@BR_MISP_RETIRED.INDIRECT_CALL@ / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_ind_call_mispredicts", "MetricThreshold": "tma_ind_call_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -1267,7 +1257,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by indirect JMP instructions.", - "MetricExpr": "max((cpu_core@BR_MISP_RETIRED.INDIRECT_COST@ * cpu_core@BR_MISP_RETIRED.INDIRECT_COST@R - cpu_core@BR_MISP_RETIRED.INDIRECT_CALL_COST@ * cpu_core@BR_MISP_RETIRED.INDIRECT_CALL_COST@R) / tma_info_thread_clks, 0)", + "MetricExpr": "max((cpu_core@BR_MISP_RETIRED.INDIRECT@ - cpu_core@BR_MISP_RETIRED.INDIRECT_CALL@) / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts, 0)", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_ind_jump_mispredicts", "MetricThreshold": "tma_ind_jump_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -1437,7 +1427,7 @@ }, { "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded ICache; or Uop Cache)", - "MetricExpr": "cpu_core@IDQ.DSB_UOPS@ / cpu_core@UOPS_ISSUED.ANY@", + "MetricExpr": "cpu_core@IDQ.DSB_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@LSD.UOPS@ + cpu_core@IDQ.MITE_UOPS@ + cpu_core@IDQ.MS_UOPS@)", "MetricGroup": "DSB;Fed;FetchBW;tma_issueFB", "MetricName": "tma_info_frontend_dsb_coverage", "MetricThreshold": "tma_info_frontend_dsb_coverage < 0.7 & tma_info_thread_ipc / 8 > 0.35", @@ -1504,7 +1494,7 @@ }, { "BriefDescription": "Fraction of Uops delivered by the LSD (Loop Stream Detector; aka Loop Cache)", - "MetricExpr": "cpu_core@LSD.UOPS@ / cpu_core@UOPS_ISSUED.ANY@", + "MetricExpr": "cpu_core@LSD.UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@LSD.UOPS@ + cpu_core@IDQ.MITE_UOPS@ + cpu_core@IDQ.MS_UOPS@)", "MetricGroup": "Fed;LSD", "MetricName": "tma_info_frontend_lsd_coverage", "Unit": "cpu_core" @@ -1663,6 +1653,15 @@ "PublicDescription": "Instructions per taken branch. Related metrics: tma_dsb_switches, tma_fetch_bandwidth, tma_info_botlnk_l2_dsb_bandwidth, tma_info_botlnk_l2_dsb_misses, tma_info_frontend_dsb_coverage, tma_lcp", "Unit": "cpu_core" }, + { + "BriefDescription": "AVX preserve/restore assists per kilo instruction", + "MetricExpr": "1e3 * cpu_core@ASSISTS.SSE_AVX_MIX@ / cpu_core@INST_RETIRED.ANY@", + "MetricGroup": "tma_issueMV", + "MetricName": "tma_info_inst_mix_vectormixpki", + "MetricThreshold": "tma_info_inst_mix_vectormixpki > 0.05", + "PublicDescription": "AVX preserve/restore assists per kilo instruction. Related metrics: tma_mixing_vectors, tma_ms_switches", + "Unit": "cpu_core" + }, { "BriefDescription": "Fill Buffer (FB) hits per kilo instructions for retired demand loads (L1D misses that merge into ongoing miss-handling entries)", "MetricExpr": "1e3 * cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@INST_RETIRED.ANY@", @@ -1929,6 +1928,13 @@ "MetricName": "tma_info_pipeline_retire", "Unit": "cpu_core" }, + { + "BriefDescription": "Total percent of cycles without actually retired uops", + "MetricExpr": "cpu_core@UOPS_RETIRED.STALLS@ / tma_info_thread_clks", + "MetricGroup": "Pipeline;Ret", + "MetricName": "tma_info_pipeline_retire_stall", + "Unit": "cpu_core" + }, { "BriefDescription": "Estimated fraction of retirement-cycles dealing with repeat instructions", "MetricExpr": "cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.SLOTS\\,cmask\\=1@", @@ -1971,7 +1977,7 @@ "MetricExpr": "32 * UNC_M_TOTAL_DATA / 1e9 / tma_info_system_time", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full", + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full, tma_uc_bound", "Unit": "cpu_core" }, { @@ -2042,13 +2048,6 @@ "MetricName": "tma_info_system_turbo_utilization", "Unit": "cpu_core" }, - { - "BriefDescription": "Measured Average Uncore Frequency for the SoC [GHz]", - "MetricExpr": "tma_info_system_socket_clks / 1e9 / tma_info_system_time", - "MetricGroup": "SoC", - "MetricName": "tma_info_system_uncore_frequency", - "Unit": "cpu_core" - }, { "BriefDescription": "Per-Logical Processor actual clocks when the Logical Processor is active.", "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.THREAD@", @@ -2140,9 +2139,18 @@ "ScaleUnit": "100%", "Unit": "cpu_core" }, + { + "BriefDescription": "This metric represents fraction of cycles Icache tag lookup was stalled due to Instruction Stream Buffer (ISB) being full", + "MetricExpr": "(cpu_core@ICACHE_TAG.STALLS_ISB@ + cpu_core@ICACHE_TAG.STALLS_INUSE@) / tma_info_thread_clks", + "MetricGroup": "TopdownL4;tma_L4_group;tma_icache_misses_group", + "MetricName": "tma_isb_full", + "MetricThreshold": "tma_isb_full > 0.05 & (tma_icache_misses > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15))", + "ScaleUnit": "100%", + "Unit": "cpu_core" + }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to Instruction TLB (ITLB) misses", - "MetricExpr": "cpu_core@ICACHE_TAG.STALLS@ / tma_info_thread_clks", + "MetricExpr": "cpu_core@ICACHE_TAG.STALLS@ / tma_info_thread_clks - tma_isb_full", "MetricGroup": "BigFootprint;BvBC;FetchLat;MemoryTLB;TopdownL3;tma_L3_group;tma_fetch_latency_group", "MetricName": "tma_itlb_misses", "MetricThreshold": "tma_itlb_misses > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", @@ -2169,19 +2177,9 @@ "ScaleUnit": "100%", "Unit": "cpu_core" }, - { - "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", - "MetricExpr": "4 * cpu_core@DEPENDENT_LOADS.ANY\\,cmask\\=1@ / tma_info_thread_clks", - "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", - "MetricName": "tma_l1_latency_dependency", - "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_UOPS_RETIRED.L1_HIT_PS", - "ScaleUnit": "100%", - "Unit": "cpu_core" - }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to L2 cache accesses by loads", - "MetricExpr": "cpu_core@MEMORY_STALLS.L2@ / tma_info_thread_clks", + "MetricExpr": "cpu_core@MEM_LOAD_RETIRED.L2_HIT@ / (cpu_core@MEM_LOAD_RETIRED.L2_HIT@ + cpu_core@MEM_LOAD_MISC_RETIRED.UC@) * cpu_core@MEMORY_STALLS.L2@ / tma_info_thread_clks", "MetricGroup": "BvML;CacheHits;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l2_bound", "MetricThreshold": "tma_l2_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", @@ -2219,6 +2217,16 @@ "ScaleUnit": "100%", "Unit": "cpu_core" }, + { + "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", + "MetricExpr": "cpu_core@MEMORY_STALLS.MEM@ / tma_info_thread_clks", + "MetricGroup": "MemoryBound;Offcore;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", + "MetricName": "tma_l3_miss_bound", + "MetricThreshold": "tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", + "PublicDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads. Better caching can improve the latency and increase performance. Sample with: MEM_LOAD_RETIRED.L3_MISS", + "ScaleUnit": "100%", + "Unit": "cpu_core" + }, { "BriefDescription": "This metric represents fraction of cycles CPU was stalled due to Length Changing Prefixes (LCPs)", "MetricExpr": "cpu_core@DECODE.LCP@ / tma_info_thread_clks", @@ -2308,7 +2316,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to LSD (Loop Stream Detector) unit", - "MetricExpr": "cpu_core@LSD.UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / tma_info_thread_clks / 2", + "MetricExpr": "cpu_core@LSD.UOPS\\,cmask\\=0x8\\,inv\\=0x1@ * max(0, 8 - tma_info_pipeline_fetch_lsd) / 8 / tma_info_thread_clks", "MetricGroup": "FetchBW;LSD;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_lsd", "MetricThreshold": "tma_lsd > 0.15 & tma_fetch_bandwidth > 0.2", @@ -2330,19 +2338,19 @@ { "BriefDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM)", "MetricExpr": "min(cpu_core@CPU_CLK_UNHALTED.THREAD@, cpu_core@OFFCORE_REQUESTS_OUTSTANDING.DATA_RD\\,cmask\\=4@) / tma_info_thread_clks", - "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", + "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_miss_bound_group", "MetricName": "tma_mem_bandwidth", - "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full, tma_uc_bound", "ScaleUnit": "100%", "Unit": "cpu_core" }, { "BriefDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM)", "MetricExpr": "min(cpu_core@CPU_CLK_UNHALTED.THREAD@, cpu_core@OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD@) / tma_info_thread_clks - tma_mem_bandwidth", - "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", + "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_miss_bound_group", "MetricName": "tma_mem_latency", - "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", + "MetricThreshold": "tma_mem_latency > 0.1 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%", "Unit": "cpu_core" @@ -2398,7 +2406,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the MITE pipeline (the legacy decode pipeline)", - "MetricExpr": "(cpu_core@IDQ.MITE_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / 2 + cpu_core@IDQ.MITE_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.STARVATION_CYCLES@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", + "MetricExpr": "(cpu_core@IDQ.MITE_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ * max(0, 8 - tma_info_pipeline_fetch_mite) / 8 + cpu_core@IDQ.MITE_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.STARVATION_CYCLES@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", "MetricGroup": "DSBmiss;FetchBW;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_mite", "MetricThreshold": "tma_mite > 0.1 & tma_fetch_bandwidth > 0.2", @@ -2412,13 +2420,13 @@ "MetricGroup": "TopdownL5;tma_L5_group;tma_issueMV;tma_ports_utilized_0_group", "MetricName": "tma_mixing_vectors", "MetricThreshold": "tma_mixing_vectors > 0.05", - "PublicDescription": "This metric estimates penalty in terms of percentage of([SKL+] injected blend uops out of all Uops Issued -- the Count Domain; [ADL+] cycles). Usually a Mixing_Vectors over 5% is worth investigating. Read more in Appendix B1 of the Optimizations Guide for this topic. Related metrics: tma_ms_switches", + "PublicDescription": "This metric estimates penalty in terms of percentage of([SKL+] injected blend uops out of all Uops Issued -- the Count Domain; [ADL+] cycles). Usually a Mixing_Vectors over 5% is worth investigating. Read more in Appendix B1 of the Optimizations Guide for this topic. Related metrics: tma_info_inst_mix_vectormixpki, tma_ms_switches", "ScaleUnit": "100%", "Unit": "cpu_core" }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the Microcode Sequencer (MS) unit - see Microcode_Sequencer node for details.", - "MetricExpr": "cpu_core@IDQ.MS_CYCLES_ANY@ / tma_info_thread_clks / 1.8", + "MetricExpr": "cpu_core@IDQ.MS_CYCLES_ANY@ * (8 - cpu_core@IDQ.MS_UOPS@ / cpu_core@IDQ.MS_CYCLES_ANY@) / tma_info_thread_slots", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_ms", "MetricThreshold": "tma_ms > 0.05 & tma_fetch_bandwidth > 0.2", @@ -2431,7 +2439,7 @@ "MetricGroup": "FetchLat;MicroSeq;TopdownL3;tma_L3_group;tma_fetch_latency_group;tma_issueMC;tma_issueMS;tma_issueMV;tma_issueSO", "MetricName": "tma_ms_switches", "MetricThreshold": "tma_ms_switches > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", - "PublicDescription": "This metric estimates the fraction of cycles when the CPU was stalled due to switches of uop delivery to the Microcode Sequencer (MS). Commonly used instructions are optimized for delivery by the DSB (decoded i-cache) or MITE (legacy instruction decode) pipelines. Certain operations cannot be handled natively by the execution pipeline; and must be performed by microcode (small programs injected into the execution stream). Switching to the MS too often can negatively impact performance. The MS is designated to deliver long uop flows required by CISC instructions like CPUID; or uncommon conditions like Floating Point Assists when dealing with Denormals. Sample with: IDQ.MS_SWITCHES. Related metrics: tma_bottleneck_irregular_overhead, tma_clears_resteers, tma_l1_bound, tma_machine_clears, tma_microcode_sequencer, tma_mixing_vectors, tma_serializing_operation", + "PublicDescription": "This metric estimates the fraction of cycles when the CPU was stalled due to switches of uop delivery to the Microcode Sequencer (MS). Commonly used instructions are optimized for delivery by the DSB (decoded i-cache) or MITE (legacy instruction decode) pipelines. Certain operations cannot be handled natively by the execution pipeline; and must be performed by microcode (small programs injected into the execution stream). Switching to the MS too often can negatively impact performance. The MS is designated to deliver long uop flows required by CISC instructions like CPUID; or uncommon conditions like Floating Point Assists when dealing with Denormals. Sample with: IDQ.MS_SWITCHES. Related metrics: tma_bottleneck_irregular_overhead, tma_clears_resteers, tma_info_inst_mix_vectormixpki, tma_l1_bound, tma_machine_clears, tma_microcode_sequencer, tma_mixing_vectors, tma_serializing_operation", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2549,7 +2557,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by (indirect) RET instructions.", - "MetricExpr": "cpu_core@BR_MISP_RETIRED.RET_COST@ * cpu_core@BR_MISP_RETIRED.RET_COST@R / tma_info_thread_clks", + "MetricExpr": "cpu_core@BR_MISP_RETIRED.RET@ / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_ret_mispredicts", "MetricThreshold": "tma_ret_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -2624,7 +2632,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_uc_bound", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2639,8 +2647,8 @@ "Unit": "cpu_core" }, { - "BriefDescription": "This metric estimates clocks wasted due to loads blocked due to unknown store address (did not do memory disambiguation) or due to unknown store data", - "MetricExpr": "7 * cpu_core@LD_BLOCKS.STORE_EARLY\\,cmask\\=1@ / tma_info_thread_clks", + "BriefDescription": "This metric roughly estimates clocks wasted due to loads blocked due to unknown store address (did not do memory disambiguation) or due to unknown store data", + "MetricExpr": "cpu_core@LD_BLOCKS.STORE_EARLY\\,cmask\\=1@ / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_early_blk", "MetricThreshold": "tma_store_early_blk > 0.2", @@ -2731,6 +2739,16 @@ "ScaleUnit": "100%", "Unit": "cpu_core" }, + { + "BriefDescription": "This metric roughly estimates fraction of cycles where the core's performance was likely hurt due to un-chacheable memory", + "MetricExpr": "cpu_core@MEM_LOAD_MISC_RETIRED.UC@ / (cpu_core@MEM_LOAD_RETIRED.L2_HIT@ + cpu_core@MEM_LOAD_MISC_RETIRED.UC@) * cpu_core@MEMORY_STALLS.L2@ / tma_info_thread_clks", + "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_miss_bound_group", + "MetricName": "tma_uc_bound", + "MetricThreshold": "tma_uc_bound > 0.2 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", + "PublicDescription": "This metric roughly estimates fraction of cycles where the core's performance was likely hurt due to un-chacheable memory. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full", + "ScaleUnit": "100%", + "Unit": "cpu_core" + }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to new branch address clears", "MetricExpr": "cpu_core@INT_MISC.UNKNOWN_BRANCH_CYCLES@ / tma_info_thread_clks", diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/metricgroups.json b/tools/perf/pmu-events/arch/x86/lunarlake/metricgroups.json index 855585fe6fae..9acbda612c25 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/metricgroups.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/metricgroups.json @@ -93,7 +93,6 @@ "tma_code_stlb_miss_group": "Metrics contributing to tma_code_stlb_miss category", "tma_core_bound_group": "Metrics contributing to tma_core_bound category", "tma_divider_group": "Metrics contributing to tma_divider category", - "tma_dram_bound_group": "Metrics contributing to tma_dram_bound category", "tma_dtlb_load_group": "Metrics contributing to tma_dtlb_load category", "tma_dtlb_store_group": "Metrics contributing to tma_dtlb_store category", "tma_fetch_bandwidth_group": "Metrics contributing to tma_fetch_bandwidth category", @@ -129,6 +128,7 @@ "tma_l1_bound_group": "Metrics contributing to tma_l1_bound category", "tma_l2_bound_group": "Metrics contributing to tma_l2_bound category", "tma_l3_bound_group": "Metrics contributing to tma_l3_bound category", + "tma_l3_miss_bound_group": "Metrics contributing to tma_l3_miss_bound category", "tma_light_operations_group": "Metrics contributing to tma_light_operations category", "tma_load_op_utilization_group": "Metrics contributing to tma_load_op_utilization category", "tma_load_stlb_miss_group": "Metrics contributing to tma_load_stlb_miss category", diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json b/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json index a7467b2f291d..8be3ea336bb8 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json @@ -973,7 +973,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", - "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent. Available PDIST counters: 0,1", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note: Since the number of iterations within a REP instruction can be significantly affected by fast strings, this event may vary run to run and not match the architectural number of iterations (specified by RCX) Available PDIST counters: 0,1", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 21f624e20cf3..68f1ae4c0aae 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -22,7 +22,7 @@ GenuineIntel-6-3A,v24,ivybridge,core GenuineIntel-6-3E,v24,ivytown,core GenuineIntel-6-2D,v24,jaketown,core GenuineIntel-6-(57|85),v16,knightslanding,core -GenuineIntel-6-BD,v1.25,lunarlake,core +GenuineIntel-6-BD,v1.26,lunarlake,core GenuineIntel-6-(AA|AC|B5),v1.21,meteorlake,core GenuineIntel-6-1[AEF],v4,nehalemep,core GenuineIntel-6-2E,v4,nehalemex,core -- cgit v1.2.3 From 982079cbd91414de2d3e92df3453b4ce83db5800 Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Mon, 13 Jul 2026 11:17:53 -0700 Subject: perf vendor events intel: Update meteorlake events from 1.21 to 1.22 The updated events were published in: https://github.com/intel/perfmon/commit/704ef43e4c0738065a0575622cf7d31867b8d48b Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Signed-off-by: Namhyung Kim --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- .../perf/pmu-events/arch/x86/meteorlake/cache.json | 11 ++- .../arch/x86/meteorlake/metricgroups.json | 2 +- .../arch/x86/meteorlake/mtl-metrics.json | 88 +++++++++++----------- .../pmu-events/arch/x86/meteorlake/pipeline.json | 4 +- .../arch/x86/meteorlake/uncore-memory.json | 84 ++++++++++++++++++--- 6 files changed, 131 insertions(+), 60 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 68f1ae4c0aae..a15cd3280993 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -23,7 +23,7 @@ GenuineIntel-6-3E,v24,ivytown,core GenuineIntel-6-2D,v24,jaketown,core GenuineIntel-6-(57|85),v16,knightslanding,core GenuineIntel-6-BD,v1.26,lunarlake,core -GenuineIntel-6-(AA|AC|B5),v1.21,meteorlake,core +GenuineIntel-6-(AA|AC|B5),v1.22,meteorlake,core GenuineIntel-6-1[AEF],v4,nehalemep,core GenuineIntel-6-2E,v4,nehalemex,core GenuineIntel-6-(CC|D5),v1.06,pantherlake,core diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/cache.json b/tools/perf/pmu-events/arch/x86/meteorlake/cache.json index 6419bc36f249..c2d351efa9d6 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/cache.json @@ -1,6 +1,6 @@ [ { - "BriefDescription": "Counts the number of request that were not accepted into the L2Q because the L2Q is FULL.", + "BriefDescription": "Counts the number of requests that were not accepted into the L2Q because the L2Q is FULL.", "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x31", "EventName": "CORE_REJECT_L2Q.ANY", @@ -631,6 +631,15 @@ "UMask": "0x50", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of unhalted cycles when the core is stalled due to a demand load miss which missed all the caches, a snoop was required, and hits in other core or module on the same die. Another core provides the data with a FWD, NO_FWD, or HITM. If the core has access to an L3 cache, an LLC miss refers to an L3 cache miss, otherwise it is an L2 cache miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x34", + "EventName": "MEM_BOUND_STALLS_LOAD.LLC_MISS_OTHERMOD", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts the number of unhalted cycles when the core is stalled to a store buffer full condition", "Counter": "0,1,2,3,4,5,6,7", diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/metricgroups.json b/tools/perf/pmu-events/arch/x86/meteorlake/metricgroups.json index 855585fe6fae..9acbda612c25 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/metricgroups.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/metricgroups.json @@ -93,7 +93,6 @@ "tma_code_stlb_miss_group": "Metrics contributing to tma_code_stlb_miss category", "tma_core_bound_group": "Metrics contributing to tma_core_bound category", "tma_divider_group": "Metrics contributing to tma_divider category", - "tma_dram_bound_group": "Metrics contributing to tma_dram_bound category", "tma_dtlb_load_group": "Metrics contributing to tma_dtlb_load category", "tma_dtlb_store_group": "Metrics contributing to tma_dtlb_store category", "tma_fetch_bandwidth_group": "Metrics contributing to tma_fetch_bandwidth category", @@ -129,6 +128,7 @@ "tma_l1_bound_group": "Metrics contributing to tma_l1_bound category", "tma_l2_bound_group": "Metrics contributing to tma_l2_bound category", "tma_l3_bound_group": "Metrics contributing to tma_l3_bound category", + "tma_l3_miss_bound_group": "Metrics contributing to tma_l3_miss_bound category", "tma_light_operations_group": "Metrics contributing to tma_light_operations category", "tma_load_op_utilization_group": "Metrics contributing to tma_load_op_utilization category", "tma_load_stlb_miss_group": "Metrics contributing to tma_load_stlb_miss category", diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/mtl-metrics.json b/tools/perf/pmu-events/arch/x86/meteorlake/mtl-metrics.json index 948c16a1f95b..a23691052237 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/mtl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/mtl-metrics.json @@ -797,16 +797,16 @@ }, { "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_miss_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_uc_bound", "Unit": "cpu_core" }, { "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_miss_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", "MetricName": "tma_bottleneck_data_cache_memory_latency", "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", @@ -832,7 +832,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_dtlb_load / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", "MetricThreshold": "tma_bottleneck_memory_data_tlbs > 20", @@ -841,7 +841,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", "MetricThreshold": "tma_bottleneck_memory_synchronization > 10", @@ -989,7 +989,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by non-taken conditional branches.", - "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_NTAKEN_COST@ * cpu_core@BR_MISP_RETIRED.COND_NTAKEN_COST@R / tma_info_thread_clks", + "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_NTAKEN@ / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_cond_nt_mispredicts", "MetricThreshold": "tma_cond_nt_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -998,7 +998,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to misprediction by taken conditional branches.", - "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_TAKEN_COST@ * cpu_core@BR_MISP_RETIRED.COND_TAKEN_COST@R / tma_info_thread_clks", + "MetricExpr": "cpu_core@BR_MISP_RETIRED.COND_TAKEN@ / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_cond_tk_mispredicts", "MetricThreshold": "tma_cond_tk_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -1027,13 +1027,13 @@ "Unit": "cpu_core" }, { - "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses", + "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to L3 data-sharing accesses", "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD@ * min(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD@R, 24 * tma_info_system_core_frequency) + cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD@ * min(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD@R, 24 * tma_info_system_core_frequency) * (1 - cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM@ / (cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM@ + cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD@))) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "BvMS;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_data_sharing", "MetricThreshold": "tma_data_sharing > 0.05 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses. Data shared by multiple Logical Processors (even just read shared) may cause increased access latency due to cache coherency. Excessive data sharing can drastically harm multithreaded performance. Sample with: MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_false_sharing, tma_machine_clears, tma_remote_cache", + "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to L3 data-sharing accesses. Data shared by multiple Logical Processors (even just read shared) may cause increased access latency due to cache coherency. Excessive data sharing can drastically harm multithreaded performance. Sample with: MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_false_sharing, tma_machine_clears, tma_remote_cache", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -1057,16 +1057,6 @@ "ScaleUnit": "100%", "Unit": "cpu_core" }, - { - "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", - "MetricExpr": "cpu_core@MEMORY_ACTIVITY.STALLS_L3_MISS@ / tma_info_thread_clks", - "MetricGroup": "MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", - "MetricName": "tma_dram_bound", - "MetricThreshold": "tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", - "PublicDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads. Better caching can improve the latency and increase performance. Sample with: MEM_LOAD_RETIRED.L3_MISS", - "ScaleUnit": "100%", - "Unit": "cpu_core" - }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to DSB (decoded uop cache) fetch pipeline", "MetricExpr": "(cpu_core@IDQ.DSB_CYCLES_ANY@ - cpu_core@IDQ.DSB_CYCLES_OK@) / tma_info_core_core_clks / 2", @@ -1123,7 +1113,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores, tma_uc_bound", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -1273,7 +1263,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by indirect CALL instructions.", - "MetricExpr": "cpu_core@BR_MISP_RETIRED.INDIRECT_CALL_COST@ * cpu_core@BR_MISP_RETIRED.INDIRECT_CALL_COST@R / tma_info_thread_clks", + "MetricExpr": "cpu_core@BR_MISP_RETIRED.INDIRECT_CALL@ / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_ind_call_mispredicts", "MetricThreshold": "tma_ind_call_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -1282,7 +1272,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by indirect JMP instructions.", - "MetricExpr": "max((cpu_core@BR_MISP_RETIRED.INDIRECT_COST@ * cpu_core@BR_MISP_RETIRED.INDIRECT_COST@R - cpu_core@BR_MISP_RETIRED.INDIRECT_CALL_COST@ * cpu_core@BR_MISP_RETIRED.INDIRECT_CALL_COST@R) / tma_info_thread_clks, 0)", + "MetricExpr": "max((cpu_core@BR_MISP_RETIRED.INDIRECT@ - cpu_core@BR_MISP_RETIRED.INDIRECT_CALL@) / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts, 0)", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_ind_jump_mispredicts", "MetricThreshold": "tma_ind_jump_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -1459,7 +1449,7 @@ }, { "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded ICache; or Uop Cache)", - "MetricExpr": "cpu_core@IDQ.DSB_UOPS@ / cpu_core@UOPS_ISSUED.ANY@", + "MetricExpr": "cpu_core@IDQ.DSB_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@LSD.UOPS@ + cpu_core@IDQ.MITE_UOPS@ + cpu_core@IDQ.MS_UOPS@)", "MetricGroup": "DSB;Fed;FetchBW;tma_issueFB", "MetricName": "tma_info_frontend_dsb_coverage", "MetricThreshold": "tma_info_frontend_dsb_coverage < 0.7 & tma_info_thread_ipc / 6 > 0.35", @@ -1526,7 +1516,7 @@ }, { "BriefDescription": "Fraction of Uops delivered by the LSD (Loop Stream Detector; aka Loop Cache)", - "MetricExpr": "cpu_core@LSD.UOPS@ / cpu_core@UOPS_ISSUED.ANY@", + "MetricExpr": "cpu_core@LSD.UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@LSD.UOPS@ + cpu_core@IDQ.MITE_UOPS@ + cpu_core@IDQ.MS_UOPS@)", "MetricGroup": "Fed;LSD", "MetricName": "tma_info_frontend_lsd_coverage", "Unit": "cpu_core" @@ -1685,6 +1675,15 @@ "PublicDescription": "Instructions per taken branch. Related metrics: tma_dsb_switches, tma_fetch_bandwidth, tma_info_botlnk_l2_dsb_bandwidth, tma_info_botlnk_l2_dsb_misses, tma_info_frontend_dsb_coverage, tma_lcp", "Unit": "cpu_core" }, + { + "BriefDescription": "AVX preserve/restore assists per kilo instruction", + "MetricExpr": "1e3 * cpu_core@ASSISTS.SSE_AVX_MIX@ / cpu_core@INST_RETIRED.ANY@", + "MetricGroup": "tma_issueMV", + "MetricName": "tma_info_inst_mix_vectormixpki", + "MetricThreshold": "tma_info_inst_mix_vectormixpki > 0.05", + "PublicDescription": "AVX preserve/restore assists per kilo instruction. Related metrics: tma_mixing_vectors, tma_ms_switches", + "Unit": "cpu_core" + }, { "BriefDescription": "Average per-core data fill bandwidth to the L1 data cache [GB / sec]", "MetricExpr": "tma_info_memory_l1d_cache_fill_bw", @@ -1922,7 +1921,7 @@ "Unit": "cpu_core" }, { - "BriefDescription": "Mem;Backend;CacheHits", + "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is execution) per physical core", "MetricExpr": "cpu_core@UOPS_EXECUTED.THREAD@ / (cpu_core@UOPS_EXECUTED.CORE_CYCLES_GE_1@ / 2 if #SMT_on else cpu_core@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute", @@ -2004,10 +2003,10 @@ }, { "BriefDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]", - "MetricExpr": "64 * (UNC_HAC_ARB_TRK_REQUESTS.ALL + UNC_HAC_ARB_COH_TRK_REQUESTS.ALL) / 1e9 / tma_info_system_time", + "MetricExpr": "32 * UNC_M_TOTAL_DATA / 1e9 / tma_info_system_time", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full", + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full, tma_uc_bound", "Unit": "cpu_core" }, { @@ -2093,13 +2092,6 @@ "MetricName": "tma_info_system_turbo_utilization", "Unit": "cpu_core" }, - { - "BriefDescription": "Measured Average Uncore Frequency for the SoC [GHz]", - "MetricExpr": "tma_info_system_socket_clks / 1e9 / tma_info_system_time", - "MetricGroup": "SoC", - "MetricName": "tma_info_system_uncore_frequency", - "Unit": "cpu_core" - }, { "BriefDescription": "Per-Logical Processor actual clocks when the Logical Processor is active.", "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.THREAD@", @@ -2268,6 +2260,16 @@ "ScaleUnit": "100%", "Unit": "cpu_core" }, + { + "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", + "MetricExpr": "cpu_core@MEMORY_ACTIVITY.STALLS_L3_MISS@ / tma_info_thread_clks", + "MetricGroup": "MemoryBound;Offcore;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", + "MetricName": "tma_l3_miss_bound", + "MetricThreshold": "tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", + "PublicDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads. Better caching can improve the latency and increase performance. Sample with: MEM_LOAD_RETIRED.L3_MISS", + "ScaleUnit": "100%", + "Unit": "cpu_core" + }, { "BriefDescription": "This metric represents fraction of cycles CPU was stalled due to Length Changing Prefixes (LCPs)", "MetricExpr": "cpu_core@DECODE.LCP@ / tma_info_thread_clks", @@ -2379,19 +2381,19 @@ { "BriefDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM)", "MetricExpr": "min(cpu_core@CPU_CLK_UNHALTED.THREAD@, cpu_core@OFFCORE_REQUESTS_OUTSTANDING.DATA_RD\\,cmask\\=4@) / tma_info_thread_clks", - "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", + "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_miss_bound_group", "MetricName": "tma_mem_bandwidth", - "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full, tma_uc_bound", "ScaleUnit": "100%", "Unit": "cpu_core" }, { "BriefDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM)", "MetricExpr": "min(cpu_core@CPU_CLK_UNHALTED.THREAD@, cpu_core@OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD@) / tma_info_thread_clks - tma_mem_bandwidth", - "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", + "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_miss_bound_group", "MetricName": "tma_mem_latency", - "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", + "MetricThreshold": "tma_mem_latency > 0.1 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%", "Unit": "cpu_core" @@ -2461,7 +2463,7 @@ "MetricGroup": "TopdownL5;tma_L5_group;tma_issueMV;tma_ports_utilized_0_group", "MetricName": "tma_mixing_vectors", "MetricThreshold": "tma_mixing_vectors > 0.05", - "PublicDescription": "This metric estimates penalty in terms of percentage of([SKL+] injected blend uops out of all Uops Issued -- the Count Domain; [ADL+] cycles). Usually a Mixing_Vectors over 5% is worth investigating. Read more in Appendix B1 of the Optimizations Guide for this topic. Related metrics: tma_ms_switches", + "PublicDescription": "This metric estimates penalty in terms of percentage of([SKL+] injected blend uops out of all Uops Issued -- the Count Domain; [ADL+] cycles). Usually a Mixing_Vectors over 5% is worth investigating. Read more in Appendix B1 of the Optimizations Guide for this topic. Related metrics: tma_info_inst_mix_vectormixpki, tma_ms_switches", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2480,7 +2482,7 @@ "MetricGroup": "FetchLat;MicroSeq;TopdownL3;tma_L3_group;tma_fetch_latency_group;tma_issueMC;tma_issueMS;tma_issueMV;tma_issueSO", "MetricName": "tma_ms_switches", "MetricThreshold": "tma_ms_switches > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", - "PublicDescription": "This metric estimates the fraction of cycles when the CPU was stalled due to switches of uop delivery to the Microcode Sequencer (MS). Commonly used instructions are optimized for delivery by the DSB (decoded i-cache) or MITE (legacy instruction decode) pipelines. Certain operations cannot be handled natively by the execution pipeline; and must be performed by microcode (small programs injected into the execution stream). Switching to the MS too often can negatively impact performance. The MS is designated to deliver long uop flows required by CISC instructions like CPUID; or uncommon conditions like Floating Point Assists when dealing with Denormals. Sample with: FRONTEND_RETIRED.MS_FLOWS. Related metrics: tma_bottleneck_irregular_overhead, tma_clears_resteers, tma_l1_bound, tma_machine_clears, tma_microcode_sequencer, tma_mixing_vectors, tma_serializing_operation", + "PublicDescription": "This metric estimates the fraction of cycles when the CPU was stalled due to switches of uop delivery to the Microcode Sequencer (MS). Commonly used instructions are optimized for delivery by the DSB (decoded i-cache) or MITE (legacy instruction decode) pipelines. Certain operations cannot be handled natively by the execution pipeline; and must be performed by microcode (small programs injected into the execution stream). Switching to the MS too often can negatively impact performance. The MS is designated to deliver long uop flows required by CISC instructions like CPUID; or uncommon conditions like Floating Point Assists when dealing with Denormals. Sample with: FRONTEND_RETIRED.MS_FLOWS. Related metrics: tma_bottleneck_irregular_overhead, tma_clears_resteers, tma_info_inst_mix_vectormixpki, tma_l1_bound, tma_machine_clears, tma_microcode_sequencer, tma_mixing_vectors, tma_serializing_operation", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2628,7 +2630,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to retired misprediction by (indirect) RET instructions.", - "MetricExpr": "cpu_core@BR_MISP_RETIRED.RET_COST@ * cpu_core@BR_MISP_RETIRED.RET_COST@R / tma_info_thread_clks", + "MetricExpr": "cpu_core@BR_MISP_RETIRED.RET@ / cpu_core@BR_MISP_RETIRED.ALL_BRANCHES@ * tma_branch_mispredicts", "MetricGroup": "BrMispredicts;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_ret_mispredicts", "MetricThreshold": "tma_ret_mispredicts > 0.05 & (tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15)", @@ -2703,7 +2705,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_uc_bound", "ScaleUnit": "100%", "Unit": "cpu_core" }, diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json b/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json index 09e1147c4733..6cd1b1659ec7 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json @@ -909,7 +909,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", - "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent.", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note: Since the number of iterations within a REP instruction can be significantly affected by fast strings, this event may vary run to run and not match the architectural number of iterations (specified by RCX)", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -1443,7 +1443,7 @@ "Unit": "cpu_atom" }, { - "BriefDescription": "Counts the number issue slots not consumed due to a color request for an FCW or MXCSR control register when all 4 colors (copies) are already in use.", + "BriefDescription": "Counts the number of issue slots not consumed due to a color request for an FCW or MXCSR control register when all 4 colors (copies) are already in use.", "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x75", "EventName": "SERIALIZATION.COLOR_STALLS", diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/uncore-memory.json b/tools/perf/pmu-events/arch/x86/meteorlake/uncore-memory.json index ceb8839f0767..60bf390198d6 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/uncore-memory.json @@ -1,61 +1,61 @@ [ { - "BriefDescription": "Counts every CAS read command sent from the Memory Controller 0 to DRAM (sum of all channels).", + "BriefDescription": "This event is deprecated. [This event is alias to UNC_M_MC0_RDCAS_COUNT_FREERUN]", "Counter": "0", + "Deprecated": "1", "EventCode": "0xff", "EventName": "UNC_MC0_RDCAS_COUNT_FREERUN", "PerPkg": "1", - "PublicDescription": "Counts every CAS read command sent from the Memory Controller 0 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data.", "UMask": "0x20", "Unit": "imc_free_running_0" }, { - "BriefDescription": "Counts every read and write request entering the Memory Controller 0.", + "BriefDescription": "This event is deprecated. [This event is alias to UNC_M_MC0_TOTAL_REQCOUNT_FREERUN]", "Counter": "2", + "Deprecated": "1", "EventCode": "0xff", "EventName": "UNC_MC0_TOTAL_REQCOUNT_FREERUN", "PerPkg": "1", - "PublicDescription": "Counts every read and write request entering the Memory Controller 0 (sum of all channels). All requests are counted as one, whether they are 32B or 64B Read/Write or partial/full line writes. Some write requests to the same address may merge to a single write command to DRAM. Therefore, the total request count may be higher than total DRAM BW.", "UMask": "0x10", "Unit": "imc_free_running_0" }, { - "BriefDescription": "Counts every CAS write command sent from the Memory Controller 0 to DRAM (sum of all channels).", + "BriefDescription": "This event is deprecated. [This event is alias to UNC_M_MC0_WRCAS_COUNT_FREERUN]", "Counter": "1", + "Deprecated": "1", "EventCode": "0xff", "EventName": "UNC_MC0_WRCAS_COUNT_FREERUN", "PerPkg": "1", - "PublicDescription": "Counts every CAS write command sent from the Memory Controller 0 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data.", "UMask": "0x30", "Unit": "imc_free_running_0" }, { - "BriefDescription": "Counts every CAS read command sent from the Memory Controller 1 to DRAM (sum of all channels).", + "BriefDescription": "This event is deprecated. [This event is alias to UNC_M_MC1_RDCAS_COUNT_FREERUN]", "Counter": "3", + "Deprecated": "1", "EventCode": "0xff", "EventName": "UNC_MC1_RDCAS_COUNT_FREERUN", "PerPkg": "1", - "PublicDescription": "Counts every CAS read command sent from the Memory Controller 1 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data.", "UMask": "0x20", "Unit": "imc_free_running_1" }, { - "BriefDescription": "Counts every read and write request entering the Memory Controller 1.", + "BriefDescription": "This event is deprecated. [This event is alias to UNC_M_MC1_TOTAL_REQCOUNT_FREERUN]", "Counter": "5", + "Deprecated": "1", "EventCode": "0xff", "EventName": "UNC_MC1_TOTAL_REQCOUNT_FREERUN", "PerPkg": "1", - "PublicDescription": "Counts every read and write request entering the Memory Controller 1 (sum of all channels). All requests are counted as one, whether they are 32B or 64B Read/Write or partial/full line writes. Some write requests to the same address may merge to a single write command to DRAM. Therefore, the total request count may be higher than total DRAM BW.", "UMask": "0x10", "Unit": "imc_free_running_1" }, { - "BriefDescription": "Counts every CAS write command sent from the Memory Controller 1 to DRAM (sum of all channels).", + "BriefDescription": "This event is deprecated. [This event is alias to UNC_M_MC1_WRCAS_COUNT_FREERUN]", "Counter": "4", + "Deprecated": "1", "EventCode": "0xff", "EventName": "UNC_MC1_WRCAS_COUNT_FREERUN", "PerPkg": "1", - "PublicDescription": "Counts every CAS write command sent from the Memory Controller 1 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data.", "UMask": "0x30", "Unit": "imc_free_running_1" }, @@ -117,6 +117,66 @@ "PerPkg": "1", "Unit": "iMC" }, + { + "BriefDescription": "Counts every CAS read command sent from the Memory Controller 0 to DRAM (sum of all channels). [This event is alias to UNC_MC0_RDCAS_COUNT_FREERUN]", + "Counter": "0", + "EventCode": "0xff", + "EventName": "UNC_M_MC0_RDCAS_COUNT_FREERUN", + "PerPkg": "1", + "PublicDescription": "Counts every CAS read command sent from the Memory Controller 0 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data. [This event is alias to UNC_MC0_RDCAS_COUNT_FREERUN]", + "UMask": "0x20", + "Unit": "imc_free_running_0" + }, + { + "BriefDescription": "Counts every read and write request entering the Memory Controller 0. [This event is alias to UNC_MC0_TOTAL_REQCOUNT_FREERUN]", + "Counter": "2", + "EventCode": "0xff", + "EventName": "UNC_M_MC0_TOTAL_REQCOUNT_FREERUN", + "PerPkg": "1", + "PublicDescription": "Counts every read and write request entering the Memory Controller 0 (sum of all channels). All requests are counted as one, whether they are 32B or 64B Read/Write or partial/full line writes. Some write requests to the same address may merge to a single write command to DRAM. Therefore, the total request count may be higher than total DRAM BW. [This event is alias to UNC_MC0_TOTAL_REQCOUNT_FREERUN]", + "UMask": "0x10", + "Unit": "imc_free_running_0" + }, + { + "BriefDescription": "Counts every CAS write command sent from the Memory Controller 0 to DRAM (sum of all channels). [This event is alias to UNC_MC0_WRCAS_COUNT_FREERUN]", + "Counter": "1", + "EventCode": "0xff", + "EventName": "UNC_M_MC0_WRCAS_COUNT_FREERUN", + "PerPkg": "1", + "PublicDescription": "Counts every CAS write command sent from the Memory Controller 0 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data. [This event is alias to UNC_MC0_WRCAS_COUNT_FREERUN]", + "UMask": "0x30", + "Unit": "imc_free_running_0" + }, + { + "BriefDescription": "Counts every CAS read command sent from the Memory Controller 1 to DRAM (sum of all channels). [This event is alias to UNC_MC1_RDCAS_COUNT_FREERUN]", + "Counter": "3", + "EventCode": "0xff", + "EventName": "UNC_M_MC1_RDCAS_COUNT_FREERUN", + "PerPkg": "1", + "PublicDescription": "Counts every CAS read command sent from the Memory Controller 1 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data. [This event is alias to UNC_MC1_RDCAS_COUNT_FREERUN]", + "UMask": "0x20", + "Unit": "imc_free_running_1" + }, + { + "BriefDescription": "Counts every read and write request entering the Memory Controller 1. [This event is alias to UNC_MC1_TOTAL_REQCOUNT_FREERUN]", + "Counter": "5", + "EventCode": "0xff", + "EventName": "UNC_M_MC1_TOTAL_REQCOUNT_FREERUN", + "PerPkg": "1", + "PublicDescription": "Counts every read and write request entering the Memory Controller 1 (sum of all channels). All requests are counted as one, whether they are 32B or 64B Read/Write or partial/full line writes. Some write requests to the same address may merge to a single write command to DRAM. Therefore, the total request count may be higher than total DRAM BW. [This event is alias to UNC_MC1_TOTAL_REQCOUNT_FREERUN]", + "UMask": "0x10", + "Unit": "imc_free_running_1" + }, + { + "BriefDescription": "Counts every CAS write command sent from the Memory Controller 1 to DRAM (sum of all channels). [This event is alias to UNC_MC1_WRCAS_COUNT_FREERUN]", + "Counter": "4", + "EventCode": "0xff", + "EventName": "UNC_M_MC1_WRCAS_COUNT_FREERUN", + "PerPkg": "1", + "PublicDescription": "Counts every CAS write command sent from the Memory Controller 1 to DRAM (sum of all channels). Each CAS commands can be for 32B or 64B of data. [This event is alias to UNC_MC1_WRCAS_COUNT_FREERUN]", + "UMask": "0x30", + "Unit": "imc_free_running_1" + }, { "BriefDescription": "PRE command sent to DRAM due to page table idle timer expiration", "Counter": "0,1,2,3,4", -- cgit v1.2.3 From 42a93c514e049e0e632c158b02305e1bbb313bcf Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Mon, 13 Jul 2026 11:17:54 -0700 Subject: perf vendor events intel: Add novalake v1.00 events The updated events were published in: https://github.com/intel/perfmon/commit/3aa49b06346e3a3ff40c7beabe63585591200c58 Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Signed-off-by: Namhyung Kim --- tools/perf/pmu-events/arch/x86/mapfile.csv | 1 + tools/perf/pmu-events/arch/x86/novalake/cache.json | 749 ++++++++ .../perf/pmu-events/arch/x86/novalake/counter.json | 17 + .../arch/x86/novalake/floating-point.json | 452 +++++ .../pmu-events/arch/x86/novalake/frontend.json | 600 ++++++ .../perf/pmu-events/arch/x86/novalake/memory.json | 299 +++ tools/perf/pmu-events/arch/x86/novalake/other.json | 144 ++ .../pmu-events/arch/x86/novalake/pipeline.json | 1976 ++++++++++++++++++++ .../arch/x86/novalake/uncore-memory.json | 42 + .../arch/x86/novalake/virtual-memory.json | 338 ++++ 10 files changed, 4618 insertions(+) create mode 100644 tools/perf/pmu-events/arch/x86/novalake/cache.json create mode 100644 tools/perf/pmu-events/arch/x86/novalake/counter.json create mode 100644 tools/perf/pmu-events/arch/x86/novalake/floating-point.json create mode 100644 tools/perf/pmu-events/arch/x86/novalake/frontend.json create mode 100644 tools/perf/pmu-events/arch/x86/novalake/memory.json create mode 100644 tools/perf/pmu-events/arch/x86/novalake/other.json create mode 100644 tools/perf/pmu-events/arch/x86/novalake/pipeline.json create mode 100644 tools/perf/pmu-events/arch/x86/novalake/uncore-memory.json create mode 100644 tools/perf/pmu-events/arch/x86/novalake/virtual-memory.json diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index a15cd3280993..d88a22d9de72 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -39,6 +39,7 @@ GenuineIntel-6-8[CD],v1.19,tigerlake,core GenuineIntel-6-2C,v5,westmereep-dp,core GenuineIntel-6-25,v4,westmereep-sp,core GenuineIntel-6-2F,v4,westmereex,core +GenuineIntel-18-0[13],v1.00,novalake,core AuthenticAMD-23-([12][0-9A-F]|[0-9A-F]),v2,amdzen1,core AuthenticAMD-23-[[:xdigit:]]+,v1,amdzen2,core AuthenticAMD-25-([245][[:xdigit:]]|[[:xdigit:]]),v1,amdzen3,core diff --git a/tools/perf/pmu-events/arch/x86/novalake/cache.json b/tools/perf/pmu-events/arch/x86/novalake/cache.json new file mode 100644 index 000000000000..106c50fa6eb4 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/novalake/cache.json @@ -0,0 +1,749 @@ +[ + { + "BriefDescription": "Counts the number of requests that were not accepted into the L2Q because the L2Q is FULL.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x31", + "EventName": "CORE_REJECT_L2Q.ANY", + "PublicDescription": "Counts the number of (demand and L1 prefetchers) core requests rejected by the L2Q due to a full or nearly full w condition which likely indicates back pressure from L2Q. It also counts requests that would have gone directly to the XQ, but are rejected due to a full or nearly full condition, indicating back pressure from the IDI link. The L2Q may also reject transactions from a core to insure fairness between cores, or to delay a core?s dirty eviction when the address conflicts incoming external snoops. (Note that L2 prefetcher requests that are dropped are not counted by this event.) Counts on a per core basis.", + "SampleAfterValue": "1000003", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cache lines replaced in L0 data cache.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x51", + "EventName": "L1D.L0_REPLACEMENT", + "PublicDescription": "Counts L0 data line replacements including opportunistic replacements, and replacements that require stall-for-replace or block-for-replace.", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cachelines replaced into the L1 d-cache. Successful replacements only (not blocked) and exclude WB-miss case", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x51", + "EventName": "L1D.L1_REPLACEMENT", + "PublicDescription": "Counts cachelines replaced into the L1 d-cache.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cachelines replaced into the L0 and L1 d-cache. Successful replacements only (not blocked) and exclude WB-miss case", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x51", + "EventName": "L1D.REPLACEMENT", + "PublicDescription": "Counts cachelines replaced into the L0 and L1 d-cache.", + "SampleAfterValue": "1000003", + "UMask": "0x5", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailability.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x49", + "EventName": "L1D_MISS.FB_FULL", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of cycles a demand request has waited due to L1D due to lack of L2 resources.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x49", + "EventName": "L1D_MISS.L2_STALLS", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D due to lack of L2 resources. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of demand requests that missed L1D cache", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x49", + "EventName": "L1D_MISS.LOAD", + "PublicDescription": "Count occurrences (rising-edge) of DCACHE_PENDING sub-event0. Impl. sends per-port binary inc-bit the occupancy increases* (at FB alloc or promotion).", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of L1D misses that are outstanding", + "Counter": "0,1,2,3", + "EventCode": "0x48", + "EventName": "L1D_PENDING.LOAD", + "PublicDescription": "Counts number of L1D misses that are outstanding in each cycle, that is each cycle the number of Fill Buffers (FB) outstanding required by Demand Reads. FB either is held by demand loads, or it is held by non-demand loads and gets hit at least once by demand. The valid outstanding interval is defined until the FB deallocation by one of the following ways: from FB allocation, if FB is allocated by demand from the demand Hit FB, if it is allocated by hardware or software prefetch. Note: In the L1D, a Demand Read contains cacheable or noncacheable demand loads, including ones causing cache-line splits and reads due to page walks resulted from any request type.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles with L1D load Misses outstanding.", + "Counter": "0,1,2,3", + "CounterMask": "1", + "EventCode": "0x48", + "EventName": "L1D_PENDING.LOAD_CYCLES", + "PublicDescription": "Counts duration of L1D miss outstanding in cycles.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "L2 cache lines filling L2", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x25", + "EventName": "L2_LINES_IN.ALL", + "PublicDescription": "Counts the number of L2 cache lines filling the L2. Counting does not cover rejects.", + "SampleAfterValue": "100003", + "UMask": "0x3f", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Modified cache lines that are evicted by L2 cache when triggered by an L2 cache fill.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x26", + "EventName": "L2_LINES_OUT.NON_SILENT", + "PublicDescription": "Counts the number of lines that are evicted by L2 cache when triggered by an L2 cache fill. Those lines are in Modified state. Modified lines are written back to L3", + "SampleAfterValue": "200003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Non-modified cache lines that are silently dropped by L2 cache.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x26", + "EventName": "L2_LINES_OUT.SILENT", + "PublicDescription": "Counts the number of lines that are silently dropped by L2 cache. These lines are typically in Shared or Exclusive state. A non-threaded event.", + "SampleAfterValue": "200003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of L2 cache lines that have been L2 hardware prefetched but not used by demand accesses.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x26", + "EventName": "L2_LINES_OUT.USELESS_HWPF", + "PublicDescription": "Counts the number of L2 cache lines that have been L2 hardware prefetched but not used by demand accesses. Increments on the core that brought the line in originally.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Cache lines that have been L2 hardware prefetched but not used by demand accesses", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x26", + "EventName": "L2_LINES_OUT.USELESS_HWPF", + "PublicDescription": "Counts the number of cache lines that have been prefetched by the L2 hardware prefetcher but not used by demand access when evicted from the L2 cache", + "SampleAfterValue": "200003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "All accesses to L2 cache [This event is alias to L2_RQSTS.REFERENCES, L2_RQSTS.ANY]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_REQUEST.ALL", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.REFERENCES, L2_RQSTS.ANY]", + "SampleAfterValue": "200003", + "UMask": "0xff", + "Unit": "cpu_core" + }, + { + "BriefDescription": "L2 code requests [This event is alias to L2_RQSTS.ALL_CODE_RD]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_REQUEST.ALL_CODE_RD", + "PublicDescription": "Counts the total number of L2 code requests. [This event is alias to L2_RQSTS.ALL_CODE_RD]", + "SampleAfterValue": "200003", + "UMask": "0xe4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Demand Data Read access L2 cache [This event is alias to L2_RQSTS.ALL_DEMAND_DATA_RD]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_REQUEST.ALL_DEMAND_DATA_RD", + "PublicDescription": "Counts Demand Data Read requests accessing the L2 cache. These requests may hit or miss L2 cache. True-miss exclude misses that were merged with ongoing L2 misses. An access is counted once. [This event is alias to L2_RQSTS.ALL_DEMAND_DATA_RD]", + "SampleAfterValue": "200003", + "UMask": "0xe1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "L2 cache hits when fetching instructions, code reads. [This event is alias to L2_RQSTS.CODE_RD_HIT]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_REQUEST.CODE_RD_HIT", + "PublicDescription": "Counts L2 cache hits when fetching instructions, code reads. [This event is alias to L2_RQSTS.CODE_RD_HIT]", + "SampleAfterValue": "200003", + "UMask": "0x44", + "Unit": "cpu_core" + }, + { + "BriefDescription": "L2 cache misses when fetching instructions [This event is alias to L2_RQSTS.CODE_RD_MISS]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_REQUEST.CODE_RD_MISS", + "PublicDescription": "Counts L2 cache misses when fetching instructions. [This event is alias to L2_RQSTS.CODE_RD_MISS]", + "SampleAfterValue": "200003", + "UMask": "0x24", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Demand Data Read requests that hit L2 cache [This event is alias to L2_RQSTS.DEMAND_DATA_RD_HIT]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_REQUEST.DEMAND_DATA_RD_HIT", + "PublicDescription": "Counts the number of demand Data Read requests initiated by load instructions that hit L2 cache. [This event is alias to L2_RQSTS.DEMAND_DATA_RD_HIT]", + "SampleAfterValue": "200003", + "UMask": "0x41", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Demand Data Read miss L2 cache [This event is alias to L2_RQSTS.DEMAND_DATA_RD_MISS]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_REQUEST.DEMAND_DATA_RD_MISS", + "PublicDescription": "Counts demand Data Read requests with true-miss in the L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. An access is counted once. [This event is alias to L2_RQSTS.DEMAND_DATA_RD_MISS]", + "SampleAfterValue": "200003", + "UMask": "0x21", + "Unit": "cpu_core" + }, + { + "BriefDescription": "All requests that hit L2 cache. [This event is alias to L2_RQSTS.HIT]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_REQUEST.HIT", + "PublicDescription": "Counts all requests that hit L2 cache. [This event is alias to L2_RQSTS.HIT]", + "SampleAfterValue": "200003", + "UMask": "0x5f", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Read requests with true-miss in L2 cache [This event is alias to L2_RQSTS.MISS]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_REQUEST.MISS", + "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.MISS]", + "SampleAfterValue": "200003", + "UMask": "0x3f", + "Unit": "cpu_core" + }, + { + "BriefDescription": "RFO requests that hit L2 cache [This event is alias to L2_RQSTS.RFO_HIT]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_REQUEST.RFO_HIT", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that hit L2 cache. [This event is alias to L2_RQSTS.RFO_HIT]", + "SampleAfterValue": "200003", + "UMask": "0x42", + "Unit": "cpu_core" + }, + { + "BriefDescription": "RFO requests that miss L2 cache [This event is alias to L2_RQSTS.RFO_MISS]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_REQUEST.RFO_MISS", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that miss L2 cache. [This event is alias to L2_RQSTS.RFO_MISS]", + "SampleAfterValue": "200003", + "UMask": "0x22", + "Unit": "cpu_core" + }, + { + "BriefDescription": "L2 code requests [This event is alias to L2_REQUEST.ALL_CODE_RD]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_RQSTS.ALL_CODE_RD", + "PublicDescription": "Counts the total number of L2 code requests. [This event is alias to L2_REQUEST.ALL_CODE_RD]", + "SampleAfterValue": "200003", + "UMask": "0xe4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Demand Data Read access L2 cache [This event is alias to L2_REQUEST.ALL_DEMAND_DATA_RD]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_RQSTS.ALL_DEMAND_DATA_RD", + "PublicDescription": "Counts Demand Data Read requests accessing the L2 cache. These requests may hit or miss L2 cache. True-miss exclude misses that were merged with ongoing L2 misses. An access is counted once. [This event is alias to L2_REQUEST.ALL_DEMAND_DATA_RD]", + "SampleAfterValue": "200003", + "UMask": "0xe1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "All accesses to L2 cache [This event is alias to L2_RQSTS.REFERENCES, L2_REQUEST.ALL]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_RQSTS.ANY", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.REFERENCES, L2_REQUEST.ALL]", + "SampleAfterValue": "200003", + "UMask": "0xff", + "Unit": "cpu_core" + }, + { + "BriefDescription": "L2 cache hits when fetching instructions, code reads. [This event is alias to L2_REQUEST.CODE_RD_HIT]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_RQSTS.CODE_RD_HIT", + "PublicDescription": "Counts L2 cache hits when fetching instructions, code reads. [This event is alias to L2_REQUEST.CODE_RD_HIT]", + "SampleAfterValue": "200003", + "UMask": "0x44", + "Unit": "cpu_core" + }, + { + "BriefDescription": "L2 cache misses when fetching instructions [This event is alias to L2_REQUEST.CODE_RD_MISS]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_RQSTS.CODE_RD_MISS", + "PublicDescription": "Counts L2 cache misses when fetching instructions. [This event is alias to L2_REQUEST.CODE_RD_MISS]", + "SampleAfterValue": "200003", + "UMask": "0x24", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Demand Data Read requests that hit L2 cache [This event is alias to L2_REQUEST.DEMAND_DATA_RD_HIT]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_RQSTS.DEMAND_DATA_RD_HIT", + "PublicDescription": "Counts the number of demand Data Read requests initiated by load instructions that hit L2 cache. [This event is alias to L2_REQUEST.DEMAND_DATA_RD_HIT]", + "SampleAfterValue": "200003", + "UMask": "0x41", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Demand Data Read miss L2 cache [This event is alias to L2_REQUEST.DEMAND_DATA_RD_MISS]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS", + "PublicDescription": "Counts demand Data Read requests with true-miss in the L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. An access is counted once. [This event is alias to L2_REQUEST.DEMAND_DATA_RD_MISS]", + "SampleAfterValue": "200003", + "UMask": "0x21", + "Unit": "cpu_core" + }, + { + "BriefDescription": "All requests that hit L2 cache. [This event is alias to L2_REQUEST.HIT]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_RQSTS.HIT", + "PublicDescription": "Counts all requests that hit L2 cache. [This event is alias to L2_REQUEST.HIT]", + "SampleAfterValue": "200003", + "UMask": "0x5f", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Read requests with true-miss in L2 cache [This event is alias to L2_REQUEST.MISS]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_RQSTS.MISS", + "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.MISS]", + "SampleAfterValue": "200003", + "UMask": "0x3f", + "Unit": "cpu_core" + }, + { + "BriefDescription": "All accesses to L2 cache [This event is alias to L2_REQUEST.ALL,L2_RQSTS.ANY]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_RQSTS.REFERENCES", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.ALL,L2_RQSTS.ANY]", + "SampleAfterValue": "200003", + "UMask": "0xff", + "Unit": "cpu_core" + }, + { + "BriefDescription": "RFO requests that hit L2 cache [This event is alias to L2_REQUEST.RFO_HIT]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_RQSTS.RFO_HIT", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that hit L2 cache. [This event is alias to L2_REQUEST.RFO_HIT]", + "SampleAfterValue": "200003", + "UMask": "0x42", + "Unit": "cpu_core" + }, + { + "BriefDescription": "RFO requests that miss L2 cache [This event is alias to L2_REQUEST.RFO_MISS]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_RQSTS.RFO_MISS", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that miss L2 cache. [This event is alias to L2_REQUEST.RFO_MISS]", + "SampleAfterValue": "200003", + "UMask": "0x22", + "Unit": "cpu_core" + }, + { + "BriefDescription": "L1D writebacks that access L2 cache", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x23", + "EventName": "L2_TRANS.L1D_WB", + "PublicDescription": "This event counts L1D writebacks that access L2 cache.", + "SampleAfterValue": "200003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of cacheable memory requests that miss in the LLC. Counts on a per core basis.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x2e", + "EventName": "LONGEST_LAT_CACHE.MISS", + "PublicDescription": "Counts the number of cacheable memory requests that miss in the Last Level Cache (LLC). Requests include demand loads, reads for ownership (RFO), instruction fetches and L1 HW prefetches. If the core has access to an L3 cache, the LLC is the L3 cache, otherwise it is the L2 cache. Counts on a per core basis.", + "SampleAfterValue": "1000003", + "UMask": "0x41", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Core-originated cacheable requests that missed L3 (Except hardware prefetches to the L3)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x2e", + "EventName": "LONGEST_LAT_CACHE.MISS", + "PublicDescription": "Counts core-originated cacheable requests that miss the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3.", + "SampleAfterValue": "100003", + "UMask": "0x41", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of cacheable memory requests that access the LLC. Counts on a per core basis.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x2e", + "EventName": "LONGEST_LAT_CACHE.REFERENCE", + "PublicDescription": "Counts the number of cacheable memory requests that access the Last Level Cache (LLC). Requests include demand loads, reads for ownership (RFO), instruction fetches and L1 HW prefetches. If the core has access to an L3 cache, the LLC is the L3 cache, otherwise it is the L2 cache. Counts on a per core basis.", + "SampleAfterValue": "1000003", + "UMask": "0x4f", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts all retired load instructions.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.ALL_LOADS", + "PublicDescription": "Counts Instructions with at least one architecturally visible load retired. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x81", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired store instructions.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.ALL_STORES", + "PublicDescription": "Counts all retired store instructions. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x82", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired software prefetch instructions.", + "Counter": "0,1,2,3", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.ALL_SWPF", + "PublicDescription": "Counts all retired software prefetch instructions. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x84", + "Unit": "cpu_core" + }, + { + "BriefDescription": "All retired memory instructions.", + "Counter": "0,1,2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.ANY", + "PublicDescription": "Counts all retired memory instructions - loads and stores. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x87", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions with locked access.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.LOCK_LOADS", + "PublicDescription": "Counts retired load instructions with locked access. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x21", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions that split across a cacheline boundary.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.SPLIT_LOADS", + "PublicDescription": "Counts retired load instructions that split across a cacheline boundary. Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x41", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired store instructions that split across a cacheline boundary.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.SPLIT_STORES", + "PublicDescription": "Counts retired store instructions that split across a cacheline boundary. Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x42", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions that hit the STLB.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_HIT_LOADS", + "PublicDescription": "Number of retired load instructions with a clean hit in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x9", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired store instructions that hit the STLB.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_HIT_STORES", + "PublicDescription": "Number of retired store instructions that hit in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0xa", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions that miss the STLB.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_MISS_LOADS", + "PublicDescription": "Number of retired load instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x11", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired store instructions that miss the STLB.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_MISS_STORES", + "PublicDescription": "Number of retired store instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x12", + "Unit": "cpu_core" + }, + { + "BriefDescription": "MEM_LOAD_L2_MISS_RETIRED.L3_HIT_SAME_CBB", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xD6", + "EventName": "MEM_LOAD_L2_MISS_RETIRED.L3_HIT_SAME_CBB", + "MSRIndex": "0x3E0,0x3E1,0x3E2,0x3E3", + "MSRValue": "0xED000400000001", + "PublicDescription": "MEM_LOAD_L2_MISS_RETIRED.L3_HIT_SAME_CBB Available PDIST counters: 0,1", + "SampleAfterValue": "100021", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "MEM_LOAD_L2_MISS_RETIRED.L3_HIT_SAME_CBB_SNP_HIT_NO_FWD", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xD6", + "EventName": "MEM_LOAD_L2_MISS_RETIRED.L3_HIT_SAME_CBB_SNP_HIT_NO_FWD", + "MSRIndex": "0x3E0,0x3E1,0x3E2,0x3E3", + "MSRValue": "0x4D000400000001", + "PublicDescription": "MEM_LOAD_L2_MISS_RETIRED.L3_HIT_SAME_CBB_SNP_HIT_NO_FWD Available PDIST counters: 0,1", + "SampleAfterValue": "100021", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "MEM_LOAD_L2_MISS_RETIRED.L3_MISS", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xD6", + "EventName": "MEM_LOAD_L2_MISS_RETIRED.L3_MISS", + "MSRIndex": "0x3E0,0x3E1,0x3E2,0x3E3", + "MSRValue": "0xFF03F000000001", + "PublicDescription": "MEM_LOAD_L2_MISS_RETIRED.L3_MISS Available PDIST counters: 0,1", + "SampleAfterValue": "100021", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "MEM_LOAD_L2_MISS_RETIRED.MEM_REGION_1", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xD6", + "EventName": "MEM_LOAD_L2_MISS_RETIRED.MEM_REGION_1", + "MSRIndex": "0x3E0,0x3E1,0x3E2,0x3E3", + "MSRValue": "0xF5020000000001", + "PublicDescription": "MEM_LOAD_L2_MISS_RETIRED.MEM_REGION_1 Available PDIST counters: 0,1", + "SampleAfterValue": "100021", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions with at least 1 uncacheable load or lock.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd4", + "EventName": "MEM_LOAD_MISC_RETIRED.UC", + "PublicDescription": "Retired instructions with at least one load to uncacheable memory-type, or at least one cache-line split locked access (Bus Lock). Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of completed demand load requests that missed the L1, but hit the FB(fill buffer), because a preceding miss to the same cacheline initiated the line to be brought into L1, but data is not yet ready in L1.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.FB_HIT", + "PublicDescription": "Counts retired load instructions with at least one uop was load missed in L1 but hit FB (Fill Buffers) due to preceding miss to the same cache line with data not ready. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions with L1 cache hits as data sources", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x6", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts retired load instructions with at least one uop that hit in the Level 0 of the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.L1_HIT_L0", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the Level 0 of the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts retired load instructions with at least one uop that hit in the Level 1 of the L1 data cache.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.L1_HIT_L1", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the Level 1 of the L1 data cache. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions missed L1 cache as data sources", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.L1_MISS", + "PublicDescription": "Counts retired load instructions with at least one uop that missed in the L1 cache. Available PDIST counters: 0,1", + "SampleAfterValue": "200003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instruction with at least 1 load uop whose Data Source was: Hit in L2 cache in a local slice of MLC of DCM.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.L2_HIT_LOCAL", + "PublicDescription": "Retired instruction with at least 1 load uop whose Data Source was: Hit in L2 cache in a local slice of MLC of DCM. Available PDIST counters: 0,1", + "SampleAfterValue": "50021", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions missed L2 cache as data sources", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.L2_MISS", + "PublicDescription": "Counts retired load instructions missed L2 cache as data sources. Available PDIST counters: 0,1", + "SampleAfterValue": "100021", + "Unit": "cpu_core" + }, + { + "BriefDescription": "MEM_STORE_RETIRED.L2_HIT_LOCAL", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x44", + "EventName": "MEM_STORE_RETIRED.L2_HIT_LOCAL", + "SampleAfterValue": "200003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired memory uops for any access", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe5", + "EventName": "MEM_UOP_RETIRED.ANY", + "PublicDescription": "Number of retired micro-operations (uops) for load or store memory accesses", + "SampleAfterValue": "1000003", + "UMask": "0xf", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts bus locks, accounts for cache line split locks and UC locks.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x2c", + "EventName": "SQ_MISC.BUS_LOCK", + "PublicDescription": "Counts the more expensive bus lock needed to enforce cache coherency for certain memory accesses that need to be done atomically. Can be created by issuing an atomic instruction (via the LOCK prefix) which causes a cache line split or accesses uncacheable memory.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of PREFETCHNTA, PREFETCHW, PREFETCHT0, PREFETCHT1 or PREFETCHT2 instructions executed.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x40", + "EventName": "SW_PREFETCH_ACCESS.ANY", + "SampleAfterValue": "100003", + "UMask": "0xf", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of PREFETCHNTA instructions executed.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x40", + "EventName": "SW_PREFETCH_ACCESS.NTA", + "PublicDescription": "Counts the number of PREFETCHNTA instructions executed.", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of PREFETCHW instructions executed.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x40", + "EventName": "SW_PREFETCH_ACCESS.PREFETCHW", + "PublicDescription": "Counts the number of PREFETCHW instructions executed.", + "SampleAfterValue": "100003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of PREFETCHT0 instructions executed.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x40", + "EventName": "SW_PREFETCH_ACCESS.T0", + "PublicDescription": "Counts the number of PREFETCHT0 instructions executed.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of PREFETCHT1 or PREFETCHT2 instructions executed.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x40", + "EventName": "SW_PREFETCH_ACCESS.T1_T2", + "PublicDescription": "Counts the number of PREFETCHT1 or PREFETCHT2 instructions executed.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + } +] diff --git a/tools/perf/pmu-events/arch/x86/novalake/counter.json b/tools/perf/pmu-events/arch/x86/novalake/counter.json new file mode 100644 index 000000000000..6cdc63552c67 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/novalake/counter.json @@ -0,0 +1,17 @@ +[ + { + "Unit": "cpu_atom", + "CountersNumFixed": "7", + "CountersNumGeneric": "8" + }, + { + "Unit": "cpu_core", + "CountersNumFixed": "4", + "CountersNumGeneric": "8" + }, + { + "Unit": "iMC", + "CountersNumFixed": "0", + "CountersNumGeneric": "5" + } +] \ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/novalake/floating-point.json b/tools/perf/pmu-events/arch/x86/novalake/floating-point.json new file mode 100644 index 000000000000..471a90f3670c --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/novalake/floating-point.json @@ -0,0 +1,452 @@ +[ + { + "BriefDescription": "Counts the number of cycles when any of the floating point dividers are active.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0xcd", + "EventName": "ARITH.FPDIV_ACTIVE", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Cycles when floating-point divide unit is busy executing divide or square root operations.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0xb0", + "EventName": "ARITH.FPDIV_ACTIVE", + "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for floating-point operations only.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of active floating point dividers per cycle in the loop stage.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcd", + "EventName": "ARITH.FPDIV_OCCUPANCY", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of floating point divider uops executed per cycle.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcd", + "EventName": "ARITH.FPDIV_UOPS", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts all microcode FP assists.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc1", + "EventName": "ASSISTS.FP", + "PublicDescription": "Counts all microcode Floating Point assists.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "ASSISTS.SSE_AVX_MIX", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc1", + "EventName": "ASSISTS.SSE_AVX_MIX", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "FP_ARITH_DISPATCHED.V0", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V0", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "FP_ARITH_DISPATCHED.V1", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V1", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "FP_ARITH_DISPATCHED.V2", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V2", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "FP_ARITH_DISPATCHED.V3", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V3", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "FP_ARITH_DISPATCHED.V4", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V4", + "SampleAfterValue": "2000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "FP_ARITH_DISPATCHED.V5", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V5", + "SampleAfterValue": "2000003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc8", + "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc8", + "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc8", + "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc8", + "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc8", + "EventName": "FP_ARITH_INST_RETIRED.512B_PACKED_DOUBLE", + "PublicDescription": "Number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational 512-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 16 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc8", + "EventName": "FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE", + "PublicDescription": "Number of SSE/AVX computational 512-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 16 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x80", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc8", + "EventName": "FP_ARITH_INST_RETIRED.SCALAR_DOUBLE", + "PublicDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc8", + "EventName": "FP_ARITH_INST_RETIRED.SCALAR_SINGLE", + "PublicDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "FP_ARITH_INST_RETIRED.VECTOR_128B", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc8", + "EventName": "FP_ARITH_INST_RETIRED.VECTOR_128B", + "SampleAfterValue": "100003", + "UMask": "0x40c", + "Unit": "cpu_core" + }, + { + "BriefDescription": "FP_ARITH_INST_RETIRED.VECTOR_256B", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc8", + "EventName": "FP_ARITH_INST_RETIRED.VECTOR_256B", + "SampleAfterValue": "100003", + "UMask": "0x830", + "Unit": "cpu_core" + }, + { + "BriefDescription": "FP_ARITH_INST_RETIRED.VECTOR_512B", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc8", + "EventName": "FP_ARITH_INST_RETIRED.VECTOR_512B", + "SampleAfterValue": "100003", + "UMask": "0x10c0", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.128B_PACKED_DOUBLE", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.128B_PACKED_SINGLE", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.256B_PACKED_DOUBLE", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.256B_PACKED_SINGLE", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of SSE/AVX computational 128-bit packed single and 256-bit packed double precision FP instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, 1 for each element. Applies to SSE* and AVX* packed single precision and packed double precision FP instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.4_FLOPS", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision and 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point and packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x18", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.512B_PACKED_DOUBLE", + "PublicDescription": "Number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational 512-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 16 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.512B_PACKED_SINGLE", + "PublicDescription": "Number of SSE/AVX computational 512-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 16 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x80", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of SSE/AVX computational 256-bit packed single precision and 512-bit packed double precision FP instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, 1 for each element. Applies to SSE* and AVX* packed single precision and double precision FP instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RSQRT14 RCP RCP14 DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.8_FLOPS", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision and 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision and double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RSQRT14 RCP RCP14 DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x460", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of SSE/AVX computational scalar floating-point instructions retired; some instructions will count twice as noted below. Applies to SSE* and AVX* scalar, double and single precision floating-point: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 RANGE SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform multiple calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.SCALAR", + "PublicDescription": "Number of SSE/AVX computational scalar single precision and double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "1000003", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.SCALAR_DOUBLE", + "PublicDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.SCALAR_SINGLE", + "PublicDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of any Vector retired FP arithmetic instructions", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.VECTOR", + "PublicDescription": "Number of any Vector retired FP arithmetic instructions. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "1000003", + "UMask": "0x3c", + "Unit": "cpu_core" + }, + { + "BriefDescription": "FP_ARITH_OPS_RETIRED.VECTOR_128B", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.VECTOR_128B", + "SampleAfterValue": "100003", + "UMask": "0x40c", + "Unit": "cpu_core" + }, + { + "BriefDescription": "FP_ARITH_OPS_RETIRED.VECTOR_256B", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.VECTOR_256B", + "SampleAfterValue": "100003", + "UMask": "0x830", + "Unit": "cpu_core" + }, + { + "BriefDescription": "FP_ARITH_OPS_RETIRED.VECTOR_512B", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.VECTOR_512B", + "SampleAfterValue": "100003", + "UMask": "0x10c0", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of uops executed on all floating point ports.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.ALL", + "SampleAfterValue": "1000003", + "UMask": "0x1f", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 0.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.P0", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 1.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.P1", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 2.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.P2", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 3.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.P3", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on floating point and vector integer port 0, 1, 2, 3.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.PRIMARY", + "SampleAfterValue": "1000003", + "UMask": "0x1e", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on floating point and vector integer store data port.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "FP_VINT_UOPS_EXECUTED.STD", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of floating point operations retired that required microcode assist.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.FP_ASSIST", + "PublicDescription": "Counts the number of floating point operations retired that required microcode assist, which is not a reflection of the number of FP operations, instructions or uops.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of floating point divide uops retired (x87 and sse, including x87 sqrt).", + "Counter": "0,1,2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.FPDIV", + "PublicDescription": "Counts the number of floating point divide uops retired (x87 and sse, including x87 sqrt). Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_atom" + } +] diff --git a/tools/perf/pmu-events/arch/x86/novalake/frontend.json b/tools/perf/pmu-events/arch/x86/novalake/frontend.json new file mode 100644 index 000000000000..7d1e62bb8803 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/novalake/frontend.json @@ -0,0 +1,600 @@ +[ + { + "BriefDescription": "Counts the total number of BACLEARS due to all branch types including conditional and unconditional jumps, returns, and indirect branches.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe6", + "EventName": "BACLEARS.ANY", + "PublicDescription": "Counts the total number of BACLEARS, which occur when the Branch Target Buffer (BTB) prediction or lack thereof, was corrected by a later branch predictor in the frontend. Includes BACLEARS due to all branch types including conditional and unconditional jumps, returns, and indirect branches.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Clears due to Unknown Branches.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x60", + "EventName": "BACLEARS.ANY", + "PublicDescription": "Number of times the front-end is resteered when it finds a branch instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore.", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of BACLEARS due to a conditional jump.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe6", + "EventName": "BACLEARS.COND", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of BACLEARS due to an indirect branch.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe6", + "EventName": "BACLEARS.INDIRECT", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of BACLEARS due to a return branch.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe6", + "EventName": "BACLEARS.RETURN", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of BACLEARS due to a direct, unconditional jump.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe6", + "EventName": "BACLEARS.UNCOND", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Stalls caused by changing prefix length of the instruction.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x87", + "EventName": "DECODE.LCP", + "PublicDescription": "Counts cycles that the Instruction Length decoder (ILD) stalls occurred due to dynamically changing prefix length of the decoded instruction (by operand size prefix instruction 0x66, address size prefix instruction 0x67 or REX.W for Intel64). Count is proportional to the number of prefixes in a 16B-line. This may result in a three-cycle penalty for each LCP (Length changing prefix) in a 16-byte chunk.", + "SampleAfterValue": "500009", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles the Microcode Sequencer is busy.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x87", + "EventName": "DECODE.MS_BUSY", + "SampleAfterValue": "500009", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "DSB-to-MITE switch true penalty cycles.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x61", + "EventName": "DSB2MITE_SWITCHES.PENALTY_CYCLES", + "PublicDescription": "Decode Stream Buffer (DSB) is a Uop-cache that holds translations of previously fetched instructions that were decoded by the legacy x86 decode pipeline (MITE). This event counts fetch penalty cycles when a transition occurs from DSB to MITE.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired ANT branches", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.ANY_ANT", + "MSRIndex": "0x3F7", + "MSRValue": "0x9", + "PublicDescription": "Always Not Taken (ANT) conditional retired branches (no BTB entry and not mispredicted) Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired Instructions who experienced DSB miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.ANY_DSB_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x1", + "PublicDescription": "Counts retired Instructions that experienced DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired Instructions who experienced a critical DSB miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.DSB_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x11", + "PublicDescription": "Number of retired Instructions that experienced a critical DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Critical means stalls were exposed to the back-end as a result of the DSB miss. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of instructions retired that were tagged because empty issue slots were seen before the uop due to icache miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.ICACHE", + "PublicDescription": "Counts the number of instructions retired that were tagged because empty issue slots were seen before the uop due to icache miss Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of instructions retired that were tagged because empty issue slots were seen before the uop due to ITLB miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.ITLB_MISS", + "PublicDescription": "Counts the number of instructions retired that were tagged because empty issue slots were seen before the uop due to ITLB miss Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Retired Instructions who experienced iTLB true miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.ITLB_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x14", + "PublicDescription": "Counts retired Instructions that experienced iTLB (Instruction TLB) true miss. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired Instructions who experienced Instruction L1 Cache true miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.L1I_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x12", + "PublicDescription": "Counts retired Instructions who experienced Instruction L1 Cache true miss. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired Instructions who experienced Instruction L2 Cache true miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.L2_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x13", + "PublicDescription": "Counts retired Instructions who experienced Instruction L2 Cache true miss. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 128 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_128", + "MSRIndex": "0x3F7", + "MSRValue": "0x608006", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 128 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 16 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_16", + "MSRIndex": "0x3F7", + "MSRValue": "0x601006", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 16 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions after front-end starvation of at least 2 cycles", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_2", + "MSRIndex": "0x3F7", + "MSRValue": "0x600206", + "PublicDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of at least 2 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 256 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_256", + "MSRIndex": "0x3F7", + "MSRValue": "0x610006", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 256 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end had at least 1 bubble-slot for a period of 2 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_2_BUBBLES_GE_1", + "MSRIndex": "0x3F7", + "MSRValue": "0x100206", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after the front-end had at least 1 bubble-slot for a period of 2 cycles. A bubble-slot is an empty issue-pipeline slot while there was no RAT stall. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 32 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_32", + "MSRIndex": "0x3F7", + "MSRValue": "0x602006", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 32 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 4 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_4", + "MSRIndex": "0x3F7", + "MSRValue": "0x600406", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 4 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 512 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_512", + "MSRIndex": "0x3F7", + "MSRValue": "0x620006", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 512 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 64 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_64", + "MSRIndex": "0x3F7", + "MSRValue": "0x604006", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 64 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 8 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_8", + "MSRIndex": "0x3F7", + "MSRValue": "0x600806", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 8 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted Retired ANT branches", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.MISP_ANT", + "MSRIndex": "0x3F7", + "MSRValue": "0x9", + "PublicDescription": "ANT retired branches that got just mispredicted Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts flows delivered by the Microcode Sequencer", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.MS_FLOWS", + "MSRIndex": "0x3F7", + "MSRValue": "0x8", + "PublicDescription": "Counts flows delivered by the Microcode Sequencer Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired Instructions who experienced STLB (2nd level TLB) true miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.STLB_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x15", + "PublicDescription": "Counts retired Instructions that experienced STLB (2nd level TLB) true miss. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that caused clears due to being Unknown Branches.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.UNKNOWN_BRANCH", + "MSRIndex": "0x3F7", + "MSRValue": "0x17", + "PublicDescription": "Number retired branch instructions that caused the front-end to be resteered when it finds the instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts every time the code stream enters into a new cache line by walking sequential from the previous line or being redirected by a jump.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x80", + "EventName": "ICACHE.ACCESSES", + "SampleAfterValue": "1000003", + "UMask": "0x3", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts every time the code stream enters into a new cache line by walking sequential from the previous line or being redirected by a jump and the instruction cache registers bytes are present.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x80", + "EventName": "ICACHE.HIT", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts every time the code stream enters into a new cache line by walking sequential from the previous line or being redirected by a jump and the instruction cache registers bytes are not present.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x80", + "EventName": "ICACHE.MISSES", + "PublicDescription": "Counts every time the code stream enters into a new cache line by walking sequential from the previous line or being redirected by a jump and the instruction cache registers bytes are not present. -", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Cycles where a code fetch is stalled due to L1 instruction cache miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x80", + "EventName": "ICACHE_DATA.STALLS", + "PublicDescription": "Counts cycles where a code line fetch is stalled due to an L1 instruction cache miss. The decode pipeline works at a 32 Byte granularity.", + "SampleAfterValue": "500009", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "ICACHE_DATA.STALL_PERIODS", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0x80", + "EventName": "ICACHE_DATA.STALL_PERIODS", + "SampleAfterValue": "500009", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where a code fetch is stalled due to L1 instruction cache tag miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x83", + "EventName": "ICACHE_TAG.STALLS", + "PublicDescription": "Counts cycles where a code fetch is stalled due to L1 instruction cache tag miss.", + "SampleAfterValue": "200003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where a code fetch is stalled due to L1 instruction cache In use-full", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x83", + "EventName": "ICACHE_TAG.STALLS_INUSE", + "SampleAfterValue": "200003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where a code fetch is stalled due to L1 instruction cache ISB-full", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x83", + "EventName": "ICACHE_TAG.STALLS_ISB", + "SampleAfterValue": "200003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering any Uop", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0x79", + "EventName": "IDQ.DSB_CYCLES_ANY", + "PublicDescription": "Counts the number of cycles uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles DSB is delivering optimal number of Uops", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "8", + "EventCode": "0x79", + "EventName": "IDQ.DSB_CYCLES_OK", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ.", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x79", + "EventName": "IDQ.DSB_UOPS", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles MITE is delivering any Uop", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0x79", + "EventName": "IDQ.MITE_CYCLES_ANY", + "PublicDescription": "Counts the number of cycles uops were delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles MITE is delivering optimal number of Uops", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "8", + "EventCode": "0x79", + "EventName": "IDQ.MITE_CYCLES_OK", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops delivered to Instruction Decode Queue (IDQ) from MITE path", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x79", + "EventName": "IDQ.MITE_UOPS", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the MITE path. This also means that uops are not being delivered from the Decode Stream Buffer (DSB).", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when uops are being delivered to IDQ while MS is busy", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0x79", + "EventName": "IDQ.MS_CYCLES_ANY", + "PublicDescription": "Counts cycles during which uops are being delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Uops maybe initiated by Decode Stream Buffer (DSB) or MITE.", + "SampleAfterValue": "2000003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of switches from DSB or MITE to the MS", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0x79", + "EventName": "IDQ.MS_SWITCHES", + "PublicDescription": "Number of switches from DSB (Decode Stream Buffer) or MITE (legacy decode pipeline) to the Microcode Sequencer.", + "SampleAfterValue": "100003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops initiated by MITE or Decode Stream Buffer (DSB) and delivered to Instruction Decode Queue (IDQ) while Microcode Sequencer (MS) is busy", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x79", + "EventName": "IDQ.MS_UOPS", + "PublicDescription": "Counts the number of uops initiated by MITE or Decode Stream Buffer (DSB) and delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Counting includes uops that may 'bypass' the IDQ.", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "count cycles when IDQ didn't deliver any uop for 1 cycle, counts 1-cycle starvation windows.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x9c", + "EventName": "IDQ_BUBBLES.BW_STARVATION", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event counts a subset of the Topdown Slots event that when no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x9c", + "EventName": "IDQ_BUBBLES.CORE", + "PublicDescription": "This event counts a subset of the Topdown Slots event that when no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations. Software can use this event as the numerator for the Frontend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when optimal number of uops was delivered to the back-end when the back-end is not stalled", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0x9c", + "EventName": "IDQ_BUBBLES.CYCLES_FE_WAS_OK", + "Invert": "1", + "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when no uops are delivered by the IDQ for 2 or more cycles when backend of the machine is not stalled - normally indicating a Fetch Latency issue", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x9c", + "EventName": "IDQ_BUBBLES.FETCH_LATENCY", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls for 2 or more cycles - normally indicating a Fetch Latency issue.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when no uops are not delivered by the IDQ when backend of the machine is not stalled", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "8", + "EventCode": "0x9c", + "EventName": "IDQ_BUBBLES.STARVATION_CYCLES", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of cycles that the MS is busy.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe7", + "EventName": "MS_DECODED.MS_BUSY", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of times entered into a ucode flow in the FEC. Includes inserted flows due to front-end detected faults or assists.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe7", + "EventName": "MS_DECODED.MS_ENTRY", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of times nanocode flow is executed.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe7", + "EventName": "MS_DECODED.NANO_CODE", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + } +] diff --git a/tools/perf/pmu-events/arch/x86/novalake/memory.json b/tools/perf/pmu-events/arch/x86/novalake/memory.json new file mode 100644 index 000000000000..459f0b7a026f --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/novalake/memory.json @@ -0,0 +1,299 @@ +[ + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to any number of reasons, including an L1 miss, WCB full, pagewalk, store address block or store data block.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.ANY", + "SampleAfterValue": "1000003", + "UMask": "0x7f", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to any number of reasons, including an L1 miss, WCB full, pagewalk, store address block or store data block, on a load that retires.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.ANY_AT_RET", + "SampleAfterValue": "1000003", + "UMask": "0xff", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to a core bound stall including a store address match, a DTLB miss or a page walk that detains the load from retiring.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.L1_BOUND_AT_RET", + "SampleAfterValue": "1000003", + "UMask": "0xf4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to a DL1 miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.L1_MISS", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to a DL1 miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.L1_MISS_AT_RET", + "SampleAfterValue": "1000003", + "UMask": "0x81", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to other block cases.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.OTHER", + "PublicDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to other block cases such as pipeline conflicts, fences, etc.", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to other block cases.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.OTHER_AT_RET", + "PublicDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to other block cases such as pipeline conflicts, fences, etc.", + "SampleAfterValue": "1000003", + "UMask": "0xc0", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to a pagewalk.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.PGWALK", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to a pagewalk.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.PGWALK_AT_RET", + "SampleAfterValue": "1000003", + "UMask": "0xa0", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to a store address match.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.ST_ADDR", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to a store address match.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.ST_ADDR_AT_RET", + "SampleAfterValue": "1000003", + "UMask": "0x84", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to request buffers full or lock in progress.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.WCB_FULL", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to request buffers full or lock in progress.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.WCB_FULL_AT_RET", + "SampleAfterValue": "1000003", + "UMask": "0x82", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of machine clears due to memory ordering caused by a snoop from an external agent. Does not count internally generated machine clears such as those due to memory disambiguation.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.MEMORY_ORDERING", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Number of machine clears due to memory ordering conflicts.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.MEMORY_ORDERING", + "PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of machine clears that flush the pipeline and restart the machine without the use of microcode.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.MEMORY_ORDERING_FAST", + "SampleAfterValue": "1000003", + "UMask": "0x8002", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Execution stalls while L3 cache miss demand load is outstanding.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x47", + "EventName": "MEMORY_ACTIVITY.STALLS_L3_MISS", + "SampleAfterValue": "1000003", + "UMask": "0x48", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 1024 cycles.", + "Counter": "2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xcd", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_1024", + "MSRIndex": "0x3F6", + "MSRValue": "0x400", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 1024 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", + "SampleAfterValue": "53", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 128 cycles.", + "Counter": "2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xcd", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_128", + "MSRIndex": "0x3F6", + "MSRValue": "0x80", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 128 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", + "SampleAfterValue": "1009", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 16 cycles.", + "Counter": "2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xcd", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_16", + "MSRIndex": "0x3F6", + "MSRValue": "0x10", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 16 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", + "SampleAfterValue": "20011", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 2048 cycles.", + "Counter": "2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xcd", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_2048", + "MSRIndex": "0x3F6", + "MSRValue": "0x800", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 2048 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", + "SampleAfterValue": "23", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 256 cycles.", + "Counter": "2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xcd", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_256", + "MSRIndex": "0x3F6", + "MSRValue": "0x100", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 256 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", + "SampleAfterValue": "503", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 32 cycles.", + "Counter": "2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xcd", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_32", + "MSRIndex": "0x3F6", + "MSRValue": "0x20", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 32 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 4 cycles.", + "Counter": "2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xcd", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_4", + "MSRIndex": "0x3F6", + "MSRValue": "0x4", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 4 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 512 cycles.", + "Counter": "2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xcd", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_512", + "MSRIndex": "0x3F6", + "MSRValue": "0x200", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 512 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", + "SampleAfterValue": "101", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 64 cycles.", + "Counter": "2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xcd", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_64", + "MSRIndex": "0x3F6", + "MSRValue": "0x40", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 64 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", + "SampleAfterValue": "2003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 8 cycles.", + "Counter": "2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xcd", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_8", + "MSRIndex": "0x3F6", + "MSRValue": "0x8", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 8 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", + "SampleAfterValue": "50021", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired memory store access operations. A PDist event for PEBS Store Latency Facility.", + "Counter": "0,1", + "Data_LA": "1", + "EventCode": "0xcd", + "EventName": "MEM_TRANS_RETIRED.STORE_SAMPLE", + "PublicDescription": "Counts Retired memory accesses with at least 1 store operation. This PEBS event is the precisely-distributed (PDist) trigger covering all stores uops for sampling by the PEBS Store Latency Facility. The facility is described in Intel SDM Volume 3 section 19.9.8 Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + } +] diff --git a/tools/perf/pmu-events/arch/x86/novalake/other.json b/tools/perf/pmu-events/arch/x86/novalake/other.json new file mode 100644 index 000000000000..1c6ae1c9d4ff --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/novalake/other.json @@ -0,0 +1,144 @@ +[ + { + "BriefDescription": "Count all other hardware assists or traps that are not necessarily architecturally exposed (through a software handler) beyond FP; SSE-AVX mix and A/D assists who are counted by dedicated sub-events.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc1", + "EventName": "ASSISTS.HARDWARE", + "PublicDescription": "Count all other hardware assists or traps that are not necessarily architecturally exposed (through a software handler) beyond FP; SSE-AVX mix and A/D assists who are counted by dedicated sub-events. This includes, but not limited to, assists at EXE or MEM uop writeback like AVX* load/store/gather/scatter (non-FP GSSE-assist ) , assists generated by ROB like PEBS and RTIT, Uncore trap, RAR (Remote Action Request) and CET (Control flow Enforcement Technology) assists.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "ASSISTS.PAGE_FAULT", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc1", + "EventName": "ASSISTS.PAGE_FAULT", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Core cycles during which interrupts are masked.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcb", + "EventName": "HW_INTERRUPTS.MASKED", + "PublicDescription": "Core cycles during which interrupts are masked (disabled, when RFLAGS.IF is clear) while thread is Unhalted.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Core cycles during which there are pending interrupts but interrupts are masked.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcb", + "EventName": "HW_INTERRUPTS.PENDING_AND_MASKED", + "PublicDescription": "Core cycles during which there are pending interrupts but interrupts are masked (disabled, when RFLAGS.IF is clear and there is pending interrupt from PIC) while thread is Unhalted.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of hardware interrupts received by the processor.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcb", + "EventName": "HW_INTERRUPTS.RECEIVED", + "PublicDescription": "Counts the number of hardware interruptions received by the processor.", + "SampleAfterValue": "203", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of LBR entries recorded. Requires LBRs to be enabled in IA32_LBR_CTL. [This event is alias to MISC_RETIRED.LBR_INSERTS]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe4", + "EventName": "LBR_INSERTS.ANY", + "PublicDescription": "Counts the number of LBR entries recorded. Requires LBRs to be enabled in IA32_LBR_CTL. [This event is alias to MISC_RETIRED.LBR_INSERTS] Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "number of port pushouts of integer ports (ready uop was delayed due to port being used by another uop) including integer STD.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xab", + "EventName": "PORT_PUSHOUT.INTEGER", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "number of port pushouts of vector ports (ready uop was delayed due to port being used by another uop)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xab", + "EventName": "PORT_PUSHOUT.VECTOR", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of vector uops scheduled for execution (no cancel) including vec/fp STD uops- ports with ready uops", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xaa", + "EventName": "PORT_READY.VECTOR", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Alloc Stall cycles when stall is due to general shared resource (e.g. ROB) and is not MEMORY_BOUND stall", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa9", + "EventName": "STALL_CORE_BOUND.GENERAL", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Alloc Stall cycles when stall is due to MEM RS resource and is not MEMORY_BOUND stall", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa9", + "EventName": "STALL_CORE_BOUND.MEM_ADDRESS", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Alloc Stall cycles when the stall is due to MEM RS resource or other memory resource and is not MEMORY_BOUND", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa9", + "EventName": "STALL_CORE_BOUND.MEM_RESOURCE", + "SampleAfterValue": "1000003", + "UMask": "0x14", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Alloc Stall cycles when stall is due to serialization and is not MEMORY_BOUND stall", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa9", + "EventName": "STALL_CORE_BOUND.SERIALIZATION", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Alloc Stall cycles when stall is due to vector stack resource and is not MEMORY_BOUND stall", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa9", + "EventName": "STALL_CORE_BOUND.VECTOR", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles the uncore cannot take further requests", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0x2d", + "EventName": "XQ.FULL", + "PublicDescription": "number of cycles when the thread is active and the uncore cannot take any further requests (for example prefetches, loads or stores initiated by the Core that miss the L2 cache).", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + } +] diff --git a/tools/perf/pmu-events/arch/x86/novalake/pipeline.json b/tools/perf/pmu-events/arch/x86/novalake/pipeline.json new file mode 100644 index 000000000000..998dd4cbc66a --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/novalake/pipeline.json @@ -0,0 +1,1976 @@ +[ + { + "BriefDescription": "Cycles when divide unit is busy executing divide or square root operations.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0xb0", + "EventName": "ARITH.DIV_ACTIVE", + "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer and floating-point operations.", + "SampleAfterValue": "1000003", + "UMask": "0x9", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when integer divide unit is busy executing divide or square root operations.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0xb0", + "EventName": "ARITH.IDIV_ACTIVE", + "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer operations only.", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of active integer dividers per cycle.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcd", + "EventName": "ARITH.IDIV_OCCUPANCY", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of integer divider uops executed per cycle.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcd", + "EventName": "ARITH.IDIV_UOPS", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Number of occurrences where a microcode assist is invoked by hardware.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc1", + "EventName": "ASSISTS.ANY", + "PublicDescription": "Counts the number of occurrences where a microcode assist is invoked by hardware. Examples include AD (page Access Dirty), FP and AVX related assists.", + "SampleAfterValue": "100003", + "UMask": "0x1f", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles there was microcode scoreboard stall", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa2", + "EventName": "BE_STALLS.SCOREBOARD", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the total number of branch instructions retired for all branch types.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.ALL_BRANCHES", + "PublicDescription": "Counts the total number of instructions in which the instruction pointer (IP) of the processor is resteered due to a branch instruction and the branch instruction successfully retires. All branch type instructions are accounted for. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "All branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.ALL_BRANCHES", + "PublicDescription": "Counts all branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.COND", + "PublicDescription": "Counts conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x7", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of not taken conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.COND_NTAKEN", + "PublicDescription": "Counts the number of not taken conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Not taken branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.COND_NTAKEN", + "PublicDescription": "Counts not taken branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of taken conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.COND_TAKEN", + "PublicDescription": "Counts the number of taken conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x3", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Taken conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.COND_TAKEN", + "PublicDescription": "Counts taken conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Taken backward conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.COND_TAKEN_BWD", + "PublicDescription": "Counts taken backward conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Taken forward conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.COND_TAKEN_FWD", + "PublicDescription": "Counts taken forward conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Far branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.FAR_BRANCH", + "PublicDescription": "Counts far branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Direct and indirect near call instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_CALL", + "PublicDescription": "Counts both direct and indirect near call instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x30", + "Unit": "cpu_core" + }, + { + "BriefDescription": "near direct call instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_DIRECT_CALL", + "PublicDescription": "Counts near direct call instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "near direct jump instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_DIRECT_JMP", + "PublicDescription": "Counts near direct jump instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x80", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Indirect near branch instructions retired (excluding returns)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_INDIRECT", + "PublicDescription": "Counts near indirect branch instructions retired excluding returns. TSX abort is an indirect branch. Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x50", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Indirect near call instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_INDIRECT_CALL", + "PublicDescription": "Counts indirect near call instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Indirect near jump instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_INDIRECT_JMP", + "PublicDescription": "Counts indirect near jump instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Indirect and Direct Relative near jump instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_JMP", + "PublicDescription": "Counts near jump instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0xc0", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Return instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_RETURN", + "PublicDescription": "Counts return instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Taken branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_TAKEN", + "PublicDescription": "Counts taken branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0xfb", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the total number of mispredicted branch instructions retired for all branch types.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.ALL_BRANCHES", + "PublicDescription": "Counts the total number of mispredicted branch instructions retired. All branch type instructions are accounted for. Prediction of the branch target address enables the processor to begin executing instructions before the non-speculative execution path is known. The branch prediction unit (BPU) predicts the target address based on the instruction pointer (IP) of the branch and on the execution path through which execution reached this IP. A branch misprediction occurs when the prediction is wrong, and results in discarding all instructions executed in the speculative path and re-fetching from the correct path. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "All mispredicted branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.ALL_BRANCHES", + "PublicDescription": "Counts all the retired branch instructions that were mispredicted by the processor. A branch misprediction occurs when the processor incorrectly predicts the destination of the branch. When the misprediction is discovered at execution, all the instructions executed in the wrong (speculative) path must be discarded, and the processor must start fetching from the correct path. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "Unit": "cpu_core" + }, + { + "BriefDescription": "All mispredicted branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.ALL_BRANCHES_TPEBS", + "PublicDescription": "All mispredicted branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND", + "PublicDescription": "Counts mispredicted conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x7", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted non-taken conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_NTAKEN", + "PublicDescription": "Counts the number of conditional branch instructions retired that were mispredicted and the branch direction was not taken. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted non-taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_NTAKEN_TPEBS", + "PublicDescription": "Mispredicted non-taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8004", + "Unit": "cpu_core" + }, + { + "BriefDescription": "number of branch instructions retired that were mispredicted and taken.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TAKEN", + "PublicDescription": "Counts taken conditional mispredicted branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "number of branch instructions retired that were mispredicted and taken forward.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TAKEN_FWD", + "PublicDescription": "Counts taken forward conditional mispredicted branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "number of branch instructions retired that were mispredicted and taken forward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TAKEN_FWD_TPEBS", + "PublicDescription": "number of branch instructions retired that were mispredicted and taken forward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8002", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TAKEN_TPEBS", + "PublicDescription": "Mispredicted taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8003", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TPEBS", + "PublicDescription": "Mispredicted conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8007", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Miss-predicted near indirect branch instructions retired (excluding returns)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_INDIRECT", + "PublicDescription": "Counts miss-predicted near indirect branch instructions retired excluding returns. TSX abort is an indirect branch. Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x50", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted indirect CALL retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_INDIRECT_CALL", + "PublicDescription": "Counts retired mispredicted indirect (near taken) CALL instructions, including both register and memory indirect. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted indirect CALL retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_INDIRECT_CALL_TPEBS", + "PublicDescription": "Mispredicted indirect CALL retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8010", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Miss-predicted near indirect jump instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_INDIRECT_JMP", + "PublicDescription": "Miss-predicted near indirect jump instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Miss-predicted near indirect jump instructions retired. Precise cost.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_INDIRECT_JMP_TPEBS", + "PublicDescription": "Miss-predicted near indirect jump instructions retired. Precise cost. Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x8040", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Miss-predicted near indirect branch instructions retired (excluding returns)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_INDIRECT_TPEBS", + "PublicDescription": "Counts miss-predicted near indirect branch instructions retired excluding returns. TSX abort is an indirect branch. Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x8050", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event counts the number of mispredicted ret instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_RETURN", + "PublicDescription": "This event counts the number of mispredicted ret instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted ret instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_RETURN_TPEBS", + "PublicDescription": "Mispredicted ret instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x8008", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of near branch instructions retired that were mispredicted and taken.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_TAKEN", + "PublicDescription": "Counts number of near branch instructions retired that were mispredicted and taken. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0xfb", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted taken near branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_TAKEN_TPEBS", + "PublicDescription": "Mispredicted taken near branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x80fb", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.C01", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", + "SampleAfterValue": "2000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.C02", + "PublicDescription": "Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", + "SampleAfterValue": "2000003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Core clocks when the thread is in the C0.1 or C0.2 or running a PAUSE in C0 ACPI state.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.C0_WAIT", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction.", + "SampleAfterValue": "2000003", + "UMask": "0x70", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Fixed Counter: Counts the number of unhalted core clock cycles. [This event is alias to CPU_CLK_UNHALTED.THREAD]", + "Counter": "Fixed counter 1", + "EventName": "CPU_CLK_UNHALTED.CORE", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Core cycles when the core is not in a halt state.", + "Counter": "Fixed counter 1", + "EventName": "CPU_CLK_UNHALTED.CORE", + "PublicDescription": "Counts the number of core cycles while the core is not in a halt state. The core enters the halt state when it is running the HLT instruction. This event is a component in many key event ratios. The core frequency may change from time to time due to transitions associated with Enhanced Intel SpeedStep Technology or TM2. For this reason this event may have a changing ratio with regards to time. When the core frequency is constant, this event can approximate elapsed time while the core was not in the halt state. It is counted on a dedicated fixed counter, leaving the programmable counters available for other events.", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of unhalted core clock cycles. [This event is alias to CPU_CLK_UNHALTED.THREAD_P]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x3c", + "EventName": "CPU_CLK_UNHALTED.CORE_P", + "PublicDescription": "Counts the number of unhalted core clock cycles [This event is alias to CPU_CLK_UNHALTED.THREAD_P]", + "SampleAfterValue": "2000003", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Thread cycles when thread is not in halt state [This event is alias to CPU_CLK_UNHALTED.THREAD_P]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x3c", + "EventName": "CPU_CLK_UNHALTED.CORE_P", + "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time. [This event is alias to CPU_CLK_UNHALTED.THREAD_P]", + "SampleAfterValue": "2000003", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Core clocks when a PAUSE is pending.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.PAUSE", + "SampleAfterValue": "2000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of Pause instructions", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.PAUSE_INST", + "SampleAfterValue": "2000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Fixed Counter: Counts the number of unhalted reference clock cycles.", + "Counter": "Fixed counter 2", + "EventName": "CPU_CLK_UNHALTED.REF_TSC", + "SampleAfterValue": "2000003", + "UMask": "0x3", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Reference cycles when the core is not in halt state.", + "Counter": "Fixed counter 2", + "EventName": "CPU_CLK_UNHALTED.REF_TSC", + "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case.", + "SampleAfterValue": "2000003", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of unhalted reference clock cycles at TSC frequency.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x3c", + "EventName": "CPU_CLK_UNHALTED.REF_TSC_P", + "PublicDescription": "Counts the number of reference cycles that the core is not in a halt state. The core enters the halt state when it is running the HLT instruction. This event is not affected by core frequency changes and increments at a fixed frequency that is also used for the Time Stamp Counter (TSC). This event uses a programmable general purpose performance counter.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Reference cycles when the core is not in halt state.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x3c", + "EventName": "CPU_CLK_UNHALTED.REF_TSC_P", + "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Fixed Counter: Counts the number of unhalted core clock cycles. [This event is alias to CPU_CLK_UNHALTED.CORE]", + "Counter": "Fixed counter 1", + "EventName": "CPU_CLK_UNHALTED.THREAD", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Core cycles when the thread is not in a halt state.", + "Counter": "Fixed counter 1", + "EventName": "CPU_CLK_UNHALTED.THREAD", + "PublicDescription": "Counts the number of core cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. This event is a component in many key event ratios. The core frequency may change from time to time due to transitions associated with Enhanced Intel SpeedStep Technology or TM2. For this reason this event may have a changing ratio with regards to time. When the core frequency is constant, this event can approximate elapsed time while the core was not in the halt state. It is counted on a dedicated fixed counter, leaving the programmable counters available for other events.", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of unhalted core clock cycles. [This event is alias to CPU_CLK_UNHALTED.CORE_P]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x3c", + "EventName": "CPU_CLK_UNHALTED.THREAD_P", + "PublicDescription": "Counts the number of unhalted core clock cycles [This event is alias to CPU_CLK_UNHALTED.CORE_P]", + "SampleAfterValue": "2000003", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Thread cycles when thread is not in halt state [This event is alias to CPU_CLK_UNHALTED.CORE_P]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x3c", + "EventName": "CPU_CLK_UNHALTED.THREAD_P", + "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time. [This event is alias to CPU_CLK_UNHALTED.CORE_P]", + "SampleAfterValue": "2000003", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Total execution stalls.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "4", + "EventCode": "0xa3", + "EventName": "CYCLE_ACTIVITY.STALLS_TOTAL", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Count number of times a load is depending on another load that had just write back its data or in previous or 2 cycles back. This event supports in-direct dependency through a single uop.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x02", + "EventName": "DEPENDENT_LOADS.ANY", + "SampleAfterValue": "1000003", + "UMask": "0x7", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles total of 1 uop is executed on all ports and Reservation Station was not empty.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.1_PORTS_UTIL", + "PublicDescription": "Counts cycles during which a total of 1 uop was executed on all ports and Reservation Station (RS) was not empty.", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles total of 2 or 3 uops are executed on all ports and Reservation Station (RS) was not empty.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.2_3_PORTS_UTIL", + "SampleAfterValue": "2000003", + "UMask": "0xc", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles total of 2 uops are executed on all ports and Reservation Station was not empty.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.2_PORTS_UTIL", + "PublicDescription": "Counts cycles during which a total of 2 uops were executed on all ports and Reservation Station (RS) was not empty.", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles total of 3 uops are executed on all ports and Reservation Station was not empty.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.3_PORTS_UTIL", + "PublicDescription": "Cycles total of 3 uops are executed on all ports and Reservation Station (RS) was not empty.", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles total of 4 uops are executed on all ports and Reservation Station was not empty.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.4_PORTS_UTIL", + "PublicDescription": "Cycles total of 4 uops are executed on all ports and Reservation Station (RS) was not empty.", + "SampleAfterValue": "2000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Execution stalls while memory subsystem has an outstanding load.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "5", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.BOUND_ON_LOADS", + "SampleAfterValue": "2000003", + "UMask": "0x21", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where the Store Buffer was full and no loads caused an execution stall.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "2", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.BOUND_ON_STORES", + "PublicDescription": "Counts cycles where the Store Buffer was full and no loads caused an execution stall.", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles no uop executed while RS was not empty, the SB was not full and there was no outstanding load.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.EXE_BOUND_0_PORTS", + "PublicDescription": "Number of cycles total of 0 uops executed on all ports, Reservation Station (RS) was not empty, the Store Buffer (SB) was not full and there was no outstanding load.", + "SampleAfterValue": "1000003", + "UMask": "0x80", + "Unit": "cpu_core" + }, + { + "BriefDescription": "EXE_RETIRED.ANY", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xdf", + "EventName": "EXE_RETIRED.ANY", + "SampleAfterValue": "2000003", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired conditional instructions (e.g. CMOV) where condition was false", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xdf", + "EventName": "EXE_RETIRED.CMOV_NTAKEN", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired conditional instructions (e.g. CMOV) where condition was true", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xdf", + "EventName": "EXE_RETIRED.CMOV_TAKEN", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "INST_DECODED.DEC_BW_3MU", + "Counter": "0,1,2,3", + "EventCode": "0x75", + "EventName": "INST_DECODED.DEC_BW_3MU", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Fixed Counter: Counts the number of instructions retired.", + "Counter": "Fixed counter 0", + "EventName": "INST_RETIRED.ANY", + "PublicDescription": "Fixed Counter: Counts the number of instructions retired Available PDIST counters: 32", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Number of instructions retired. Fixed Counter - architectural event", + "Counter": "Fixed counter 0", + "EventName": "INST_RETIRED.ANY", + "PublicDescription": "Counts the number of X86 instructions retired - an Architectural PerfMon event. Counting continues during hardware interrupts, traps, and inside interrupt handlers. Notes: INST_RETIRED.ANY is counted by a designated fixed counter freeing up programmable counters to count other events. INST_RETIRED.ANY_P is counted by a programmable counter. Available PDIST counters: 32", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc0", + "EventName": "INST_RETIRED.ANY_P", + "PublicDescription": "Counts the number of instructions retired Available PDIST counters: 0,1", + "SampleAfterValue": "2000003", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Number of instructions retired. General Counter - architectural event", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc0", + "EventName": "INST_RETIRED.ANY_P", + "PublicDescription": "Counts the number of X86 instructions retired - an Architectural PerfMon event. Counting continues during hardware interrupts, traps, and inside interrupt handlers. Notes: INST_RETIRED.ANY is counted by a designated fixed counter freeing up programmable counters to count other events. INST_RETIRED.ANY_P is counted by a programmable counter. Available PDIST counters: 0,1", + "SampleAfterValue": "2000003", + "Unit": "cpu_core" + }, + { + "BriefDescription": "retired macro-fused uops when there is a branch in the macro-fused pair (the two instructions that got macro-fused count once in this pmon)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc0", + "EventName": "INST_RETIRED.BR_FUSED", + "PublicDescription": "retired macro-fused uops when there is a branch in the macro-fused pair (the two instructions that got macro-fused count once in this pmon) Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "INST_RETIRED.MACRO_FUSED", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc0", + "EventName": "INST_RETIRED.MACRO_FUSED", + "PublicDescription": "INST_RETIRED.MACRO_FUSED Available PDIST counters: 0,1", + "SampleAfterValue": "2000003", + "UMask": "0x30", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired NOP instructions.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc0", + "EventName": "INST_RETIRED.NOP", + "PublicDescription": "Counts all retired NOP or ENDBR32/64 or PREFETCHIT0/1 instructions Available PDIST counters: 0,1", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Precise instruction retired with PEBS precise-distribution", + "Counter": "Fixed counter 0", + "EventName": "INST_RETIRED.PREC_DIST", + "PublicDescription": "A version of INST_RETIRED that allows for a precise distribution of samples across instructions retired. It utilizes the Precise Distribution of Instructions Retired (PDIR++) feature to fix bias in how retired instructions get sampled. Use on Fixed Counter 0. Available PDIST counters: 32", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Iterations of Repeat string retired instructions.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc0", + "EventName": "INST_RETIRED.REP_ITERATION", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note: Since the number of iterations within a REP instruction can be significantly affected by fast strings, this event may vary run to run and not match the architectural number of iterations (specified by RCX) Available PDIST counters: 0,1", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Bubble cycles of BPClear. [This event is alias to INT_MISC.BPCLEAR_CYCLES]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xad", + "EventName": "INT_MISC.BPCLEAR_BUBBLES", + "MSRIndex": "0x3F7", + "MSRValue": "0xB", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Bubble cycles of BPClear. [This event is alias to INT_MISC.BPCLEAR_BUBBLES]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xad", + "EventName": "INT_MISC.BPCLEAR_CYCLES", + "MSRIndex": "0x3F7", + "MSRValue": "0xB", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Clears speculative count", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0xad", + "EventName": "INT_MISC.CLEARS_COUNT", + "PublicDescription": "Counts the number of speculative clears due to any type of branch misprediction or machine clears", + "SampleAfterValue": "500009", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xad", + "EventName": "INT_MISC.CLEAR_RESTEER_CYCLES", + "PublicDescription": "Cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path.", + "SampleAfterValue": "500009", + "UMask": "0x80", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Core cycles the allocator was stalled due to recovery from earlier clear event for this thread", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xad", + "EventName": "INT_MISC.RECOVERY_CYCLES", + "PublicDescription": "Counts core cycles when the Resource allocator was stalled due to recovery from an earlier branch misprediction or machine clear event.", + "SampleAfterValue": "500009", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "INT_MISC.UNKNOWN_BRANCH", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0xad", + "EventName": "INT_MISC.UNKNOWN_BRANCH", + "MSRIndex": "0x3F7", + "MSRValue": "0x7", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Bubble cycles of BAClear (Unknown Branch). [This event is alias to INT_MISC.UNKNOWN_BRANCH_CYCLES]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xad", + "EventName": "INT_MISC.UNKNOWN_BRANCH_BUBBLES", + "MSRIndex": "0x3F7", + "MSRValue": "0x7", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Bubble cycles of BAClear (Unknown Branch). [This event is alias to INT_MISC.UNKNOWN_BRANCH_BUBBLES]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xad", + "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES", + "MSRIndex": "0x3F7", + "MSRValue": "0x7", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "TMA slots where uops got dropped", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xad", + "EventName": "INT_MISC.UOP_DROPPING", + "PublicDescription": "Estimated number of Top-down Microarchitecture Analysis slots that got dropped due to non front-end reasons", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of uops executed on secondary integer ports 0,1,2,3.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.2ND", + "SampleAfterValue": "1000003", + "UMask": "0x80", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on all Integer ports.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.ALL", + "SampleAfterValue": "1000003", + "UMask": "0xff", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on a load port.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.LD", + "PublicDescription": "Counts the number of uops executed on a load port. This event counts for integer uops even if the destination is FP/vector", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on integer port 0.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.P0", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on integer port 1.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.P1", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on integer port 2.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.P2", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on integer port 3.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.P3", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on integer port 0,1, 2, 3.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.PRIMARY", + "SampleAfterValue": "1000003", + "UMask": "0x78", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on a Store address port.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.STA", + "PublicDescription": "Counts the number of uops executed on a Store address port. This event counts integer uops even if the data source is FP/vector", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops executed on an integer store data and jump port.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.STD_JMP", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Number of vector integer instructions retired of 128-bit vector-width.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.128BIT", + "SampleAfterValue": "1000003", + "UMask": "0x13", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of vector integer instructions retired of 256-bit vector-width.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.256BIT", + "SampleAfterValue": "1000003", + "UMask": "0xac", + "Unit": "cpu_core" + }, + { + "BriefDescription": "integer ADD, SUB, SAD 128-bit vector instructions.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.ADD_128", + "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 128-bit vector instructions.", + "SampleAfterValue": "1000003", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "integer ADD, SUB, SAD 256-bit vector instructions.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.ADD_256", + "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 256-bit vector instructions.", + "SampleAfterValue": "1000003", + "UMask": "0xc", + "Unit": "cpu_core" + }, + { + "BriefDescription": "INT_VEC_RETIRED.MUL_256", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.MUL_256", + "SampleAfterValue": "1000003", + "UMask": "0x80", + "Unit": "cpu_core" + }, + { + "BriefDescription": "INT_VEC_RETIRED.SHUFFLES", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.SHUFFLES", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "INT_VEC_RETIRED.VNNI_128", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.VNNI_128", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "INT_VEC_RETIRED.VNNI_256", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.VNNI_256", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of retired loads that are blocked because it initially appears to be store forward blocked, but subsequently is shown not to be blocked based on 4K alias check.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.ADDRESS_ALIAS", + "PublicDescription": "Counts the number of retired loads that are blocked because it initially appears to be store forward blocked, but subsequently is shown not to be blocked based on 4K alias check. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "False dependencies in MOB due to partial compare on address.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.ADDRESS_ALIAS", + "PublicDescription": "Counts the number of times a load got blocked due to false dependencies in MOB due to partial compare on address.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of retired loads that are blocked for any of the following reasons: DTLB miss, address alias, store forward or data unknown (includes memory disambiguation blocks and ESP consuming load blocks), and others.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.ALL", + "PublicDescription": "Counts the number of retired loads that are blocked for any of the following reasons: DTLB miss, address alias, store forward or data unknown (includes memory disambiguation blocks and ESP consuming load blocks), and others. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x1f", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Bank conflicts in DCU due to limited lookup ports.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.BANK_CONFLICT", + "PublicDescription": "Counts the number of times a load got blocked due to bank conflicts in DCU", + "SampleAfterValue": "100003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of retired loads that are blocked because its address exactly matches an older store whose data is not ready.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.DATA_UNKNOWN", + "PublicDescription": "Counts the number of retired loads that are blocked because its address exactly matches an older store whose data is not ready. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "The number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.NO_SR", + "PublicDescription": "Counts the number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use.", + "SampleAfterValue": "100003", + "UMask": "0x88", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of times a load got early blocked due to preceding store operation with unknown address or unknown data. Excluding in-line (immediate) wakeups", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.STORE_EARLY", + "SampleAfterValue": "100003", + "UMask": "0xa1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of retired loads that are blocked because its address partially overlapped with an older store.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.STORE_FORWARD", + "PublicDescription": "Counts the number of retired loads that are blocked because its address partially overlapped with an older store. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Loads blocked due to overlapping with a preceding store that cannot be forwarded.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.STORE_FORWARD", + "PublicDescription": "Counts the number of times where store forwarding was prevented for a load operation. The most common case is a load blocked due to the address of memory access (partially) overlapping with a preceding uncompleted store. Note: See the table of not supported store forwards in the Optimization Guide.", + "SampleAfterValue": "100003", + "UMask": "0x82", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles Uops delivered by the LSD, but didn't come from the decoder.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0xa8", + "EventName": "LSD.CYCLES_ACTIVE", + "PublicDescription": "Counts the cycles when at least one uop is delivered by the LSD (Loop-stream detector).", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles optimal number of Uops delivered by the LSD, but did not come from the decoder.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "8", + "EventCode": "0xa8", + "EventName": "LSD.CYCLES_OK", + "PublicDescription": "Counts the cycles when optimal number of uops is delivered by the LSD (Loop-stream detector).", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of Uops delivered by the LSD.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa8", + "EventName": "LSD.UOPS", + "PublicDescription": "Counts the number of uops delivered to the back-end by the LSD(Loop Stream Detector).", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the total number of machine clears for any reason including, but not limited to, memory ordering, memory disambiguation, SMC, and FP assist.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.ANY", + "SampleAfterValue": "1000003", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of machine clears that flush the pipeline and restart the machine without the use of microcode.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.ANY_FAST", + "SampleAfterValue": "1000003", + "UMask": "0x80ff", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Number of machine clears (nukes) of any type.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.COUNT", + "PublicDescription": "Counts the number of machine clears (nukes) of any type.", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of machine clears due to memory ordering in which an internal load passes an older store within the same CPU.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.DISAMBIGUATION", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of machine clears that flush the pipeline and restart the machine without the use of microcode.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.DISAMBIGUATION_FAST", + "SampleAfterValue": "1000003", + "UMask": "0x8008", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of virtual traps taken.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.FPC_VIRTUAL_TRAP", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of machines clears due to memory renaming.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.MRN_NUKE", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of machine clears that flush the pipeline and restart the machine without the use of microcode.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.MRN_NUKE_FAST", + "SampleAfterValue": "1000003", + "UMask": "0x8010", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of machine clears due to a page fault. Counts both I-Side and D-Side (Loads/Stores) page faults. A page fault occurs when either the page is not present, or an access violation occurs.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.PAGE_FAULT", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of machine clears due to program modifying data (self modifying code) within 1K of a recently fetched code page.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.SMC", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Self-modifying code (SMC) detected.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.SMC", + "PublicDescription": "Counts self-modifying code (SMC) detected, which causes a machine clear.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of machine clears due to program modifying data (cross-core modifying code) within 1K of a recently fetched code page.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.XMC", + "SampleAfterValue": "1000003", + "UMask": "0x80", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts cycles where no execution is happening due to loads waiting for L1 cache (that is: no execution & load in flight & no load missed L1 cache)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x46", + "EventName": "MEMORY_STALLS.L1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts cycles where no execution is happening due to loads waiting for L2 cache (that is: no execution & load in flight & load missed L1 & no load missed L2 cache)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x46", + "EventName": "MEMORY_STALLS.L2", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts cycles where no execution is happening due to loads waiting for L3 cache (that is: no execution & load in flight & load missed L1 & load missed L2 cache & no load missed L3 Cache)", + "Counter": "0,1,2,3", + "EventCode": "0x46", + "EventName": "MEMORY_STALLS.L3", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts cycles where no execution is happening due to loads waiting for Memory (that is: no execution & load in flight & a load missed L3 cache)", + "Counter": "0,1,2,3", + "EventCode": "0x46", + "EventName": "MEMORY_STALLS.MEM", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of CLFLUSH, CLWB, and CLDEMOTE instructions retired. [This event is alias to MISC_RETIRED1.CL_INST]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe0", + "EventName": "MICROCODE_RETIRED.CL_INST", + "PublicDescription": "Counts the number of CLFLUSH, CLWB, and CLDEMOTE instructions retired. [This event is alias to MISC_RETIRED1.CL_INST] Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0xff", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of LFENCE instructions retired. [This event is alias to MISC_RETIRED1.LFENCE]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe0", + "EventName": "MICROCODE_RETIRED.LFENCE", + "PublicDescription": "Counts the number of LFENCE instructions retired. [This event is alias to MISC_RETIRED1.LFENCE] Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Count the number of WRMSR instructions retired. [This event is alias to MISC_RETIRED1.WRMSR]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe0", + "EventName": "MICROCODE_RETIRED.WRMSR", + "PublicDescription": "Count the number of WRMSR instructions retired. [This event is alias to MISC_RETIRED1.WRMSR] Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "LFENCE instructions retired", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe0", + "EventName": "MISC2_RETIRED.LFENCE", + "PublicDescription": "number of LFENCE retired instructions", + "SampleAfterValue": "400009", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to LBR_INSERTS.ANY]", + "Counter": "0,1,2,3,4,5,6,7", + "Deprecated": "1", + "EventCode": "0xe4", + "EventName": "MISC_RETIRED.LBR_INSERTS", + "PublicDescription": "This event is deprecated. [This event is alias to LBR_INSERTS.ANY] Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "LBR record is inserted", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe4", + "EventName": "MISC_RETIRED.LBR_INSERTS", + "PublicDescription": "LBR record is inserted Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of CLFLUSH, CLWB, and CLDEMOTE instructions retired. [This event is alias to MICROCODE_RETIRED.CL_INST]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe0", + "EventName": "MISC_RETIRED1.CL_INST", + "PublicDescription": "Counts the number of CLFLUSH, CLWB, and CLDEMOTE instructions retired. [This event is alias to MICROCODE_RETIRED.CL_INST] Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0xff", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of LFENCE instructions retired. [This event is alias to MICROCODE_RETIRED.LFENCE]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe0", + "EventName": "MISC_RETIRED1.LFENCE", + "PublicDescription": "Counts the number of LFENCE instructions retired. [This event is alias to MICROCODE_RETIRED.LFENCE] Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Count the number of WRMSR instructions retired. [This event is alias to MICROCODE_RETIRED.WRMSR]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe0", + "EventName": "MISC_RETIRED1.WRMSR", + "PublicDescription": "Count the number of WRMSR instructions retired. [This event is alias to MICROCODE_RETIRED.WRMSR] Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Cycles when Reservation Station (RS) is empty for the thread.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa5", + "EventName": "RS.EMPTY", + "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into starvation periods (e.g. branch mispredictions or i-cache misses)", + "SampleAfterValue": "1000003", + "UMask": "0x7", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts end of periods where the Reservation Station (RS) was empty.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0xa5", + "EventName": "RS.EMPTY_COUNT", + "Invert": "1", + "PublicDescription": "Counts end of periods where the Reservation Station (RS) was empty. Could be useful to closely sample on front-end latency issues (see the FRONTEND_RETIRED event of designated precise events)", + "SampleAfterValue": "100003", + "UMask": "0x7", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when RS was empty and a resource allocation stall is asserted", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa5", + "EventName": "RS.EMPTY_RESOURCE", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of issue slots in a UMWAIT or TPAUSE instruction where no uop issues due to the instruction putting the CPU into the C0.1 activity state. For Tremont, UMWAIT and TPAUSE will only put the CPU into C0.1 activity state (not C0.2 activity state).", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x75", + "EventName": "SERIALIZATION.C01_MS_SCB", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number issue slots not consumed due to a color request for an FCW or MXCSR control register when all 4 colors (copies) are already in use.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x75", + "EventName": "SERIALIZATION.COLOR_STALLS", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of issue slots where no uop could issue due to an IQ scoreboard that stalls allocation until a specified older uop retires or (in the case of jump scoreboard) executes. Commonly executed instructions with IQ scoreboards include LFENCE and MFENCE.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x75", + "EventName": "SERIALIZATION.IQ_JEU_SCB", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of issue slots not consumed by the backend due to a micro-sequencer (MS) scoreboard, which stalls the front-end from issuing from the UROM until a specified older uop retires.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x75", + "EventName": "SERIALIZATION.NON_C01_MS_SCB", + "PublicDescription": "Counts the number of issue slots not consumed by the backend due to a micro-sequencer (MS) scoreboard, which stalls the front-end from issuing from the UROM until a specified older uop retires. The most commonly executed instruction with an MS scoreboard is PAUSE.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "This event counts a subset of the Topdown Slots event that were not consumed by the back-end pipeline due to lack of back-end resources, as a result of memory subsystem delays, execution units limitations, or other conditions.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa4", + "EventName": "TOPDOWN.BACKEND_BOUND_SLOTS", + "PublicDescription": "This event counts a subset of the Topdown Slots event that were not consumed by the back-end pipeline due to lack of back-end resources, as a result of memory subsystem delays, execution units limitations, or other conditions. Software can use this event as the numerator for the Backend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.", + "SampleAfterValue": "10000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "TMA slots wasted due to incorrect speculations.", + "Counter": "0", + "EventCode": "0xa4", + "EventName": "TOPDOWN.BAD_SPEC_SLOTS", + "PublicDescription": "Number of slots of TMA method that were wasted due to incorrect speculation. It covers all types of control-flow or data-related mis-speculations.", + "SampleAfterValue": "10000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "TMA slots wasted due to incorrect speculation by branch mispredictions", + "Counter": "0", + "EventCode": "0xa4", + "EventName": "TOPDOWN.BR_MISPREDICT_SLOTS", + "PublicDescription": "Number of TMA slots that were wasted due to incorrect speculation by (any type of) branch mispredictions. This event estimates number of speculative operations that were issued but not retired as well as the out-of-order engine recovery past a branch misprediction.", + "SampleAfterValue": "10000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "TOPDOWN.MEMORY_BOUND_SLOTS", + "Counter": "3", + "EventCode": "0xa4", + "EventName": "TOPDOWN.MEMORY_BOUND_SLOTS", + "SampleAfterValue": "10000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "TMA slots available for an unhalted logical processor. Fixed counter - architectural event", + "Counter": "Fixed counter 3", + "EventName": "TOPDOWN.SLOTS", + "PublicDescription": "Number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method (TMA). Software can use this event as the denominator for the top-level metrics of the TMA method. This architectural event is counted on a designated fixed counter (Fixed Counter 3).", + "SampleAfterValue": "10000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "TMA slots available for an unhalted logical processor. General counter - architectural event", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa4", + "EventName": "TOPDOWN.SLOTS_P", + "PublicDescription": "Counts the number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method.", + "SampleAfterValue": "10000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Fixed Counter: Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear.", + "Counter": "Fixed counter 4", + "EventName": "TOPDOWN_BAD_SPECULATION.ALL", + "SampleAfterValue": "1000003", + "UMask": "0x5", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x73", + "EventName": "TOPDOWN_BAD_SPECULATION.ALL_P", + "PublicDescription": "Counts the total number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. Only issue slots wasted due to fast nukes such as memory ordering nukes are counted. Other nukes are not accounted for. Counts all issue slots blocked during this recovery window, including relevant microcode flows, and while uops are not yet available in the instruction queue (IQ) or until an FE_BOUND event occurs besides OTHER and CISC. Also includes the issue slots that were consumed by the backend but were thrown away because they were younger than the mispredict or machine clear.", + "SampleAfterValue": "1000003", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of retirement slots not consumed due to backend stalls. [This event is alias to TOPDOWN_BE_BOUND.ALL_P]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa4", + "EventName": "TOPDOWN_BE_BOUND.ALL", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of retirement slots not consumed due to backend stalls. [This event is alias to TOPDOWN_BE_BOUND.ALL]", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xa4", + "EventName": "TOPDOWN_BE_BOUND.ALL_P", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Fixed Counter: Counts the number of retirement slots not consumed due to front end stalls.", + "Counter": "Fixed counter 5", + "EventName": "TOPDOWN_FE_BOUND.ALL", + "SampleAfterValue": "1000003", + "UMask": "0x6", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of retirement slots not consumed due to front end stalls.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x9c", + "EventName": "TOPDOWN_FE_BOUND.ALL_P", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Fixed Counter: Counts the number of consumed retirement slots.", + "Counter": "Fixed counter 6", + "EventName": "TOPDOWN_RETIRING.ALL", + "SampleAfterValue": "1000003", + "UMask": "0x7", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of consumed retirement slots.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc2", + "EventName": "TOPDOWN_RETIRING.ALL_P", + "PublicDescription": "Counts the number of consumed retirement slots. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "This event counts the number of not dec-by-all uops decoded (any non dec-by-all uops) e.g. when a 2 uop instruction is decoded this events counts 2.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x76", + "EventName": "UOPS_DECODED.HEAVY_INST_UOPS", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops executed on INT EU ALU ports.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.ALU", + "PublicDescription": "Number of ALU integer uops dispatch to execution.", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops executed on any INT EU ports", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.INT_EU_ALL", + "PublicDescription": "Number of integer uops dispatched to execution.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of Uops dispatched/executed by any of the 3 JEUs (all ups that hold the JEU including macro; micro jumps; fetch-from-eip)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.JMP", + "PublicDescription": "Number of jump uops dispatch to execution", + "SampleAfterValue": "2000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops executed on Load ports", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.LOAD", + "PublicDescription": "Number of Load uops dispatched to execution.", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of (shift) 1-cycle Uops dispatched/executed by any of the Shift Eus", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.SHIFT", + "PublicDescription": "Number of SHIFT integer uops dispatch to execution", + "SampleAfterValue": "2000003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of Uops dispatched/executed by Slow EU (e.g. 3+ cycles LEA, >1 cycles shift, iDIVs, CR; *H operation)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.SLOW", + "PublicDescription": "Number of Slow integer uops dispatch to execution.", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of Uops dispatched on STA ports", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.STA", + "PublicDescription": "Number of STA (Store Address) uops dispatch to execution", + "SampleAfterValue": "2000003", + "UMask": "0x80", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops executed on STD ports", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.STD", + "PublicDescription": "Number of STD (Store Data) uops dispatch to execution", + "SampleAfterValue": "2000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where at least 1 uop was executed per-thread", + "Counter": "3", + "CounterMask": "1", + "EventCode": "0xb1", + "EventName": "UOPS_EXECUTED.CYCLES_GE_1", + "PublicDescription": "Cycles where at least 1 uop was executed per-thread.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where at least 2 uops were executed per-thread", + "Counter": "3", + "CounterMask": "2", + "EventCode": "0xb1", + "EventName": "UOPS_EXECUTED.CYCLES_GE_2", + "PublicDescription": "Cycles where at least 2 uops were executed per-thread.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where at least 3 uops were executed per-thread", + "Counter": "3", + "CounterMask": "3", + "EventCode": "0xb1", + "EventName": "UOPS_EXECUTED.CYCLES_GE_3", + "PublicDescription": "Cycles where at least 3 uops were executed per-thread.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where at least 4 uops were executed per-thread", + "Counter": "3", + "CounterMask": "4", + "EventCode": "0xb1", + "EventName": "UOPS_EXECUTED.CYCLES_GE_4", + "PublicDescription": "Cycles where at least 4 uops were executed per-thread.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of cycles no uops were dispatched to be executed on this thread.", + "Counter": "3", + "CounterMask": "1", + "EventCode": "0xb1", + "EventName": "UOPS_EXECUTED.STALLS", + "Invert": "1", + "PublicDescription": "Counts cycles during which no uops were dispatched from the Reservation Station (RS) per thread.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of uops to be executed per-thread each cycle.", + "Counter": "3", + "EventCode": "0xb1", + "EventName": "UOPS_EXECUTED.THREAD", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of x87 uops dispatched.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb1", + "EventName": "UOPS_EXECUTED.X87", + "PublicDescription": "Counts the number of x87 uops executed.", + "SampleAfterValue": "2000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of uops issued by the front end every cycle.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x0e", + "EventName": "UOPS_ISSUED.ANY", + "PublicDescription": "Counts the number of uops issued by the front end every cycle. When 4-uops are requested and only 2-uops are delivered, the event counts 2. Uops_issued correlates to the number of ROB entries. If uop takes 2 ROB slots it counts as 2 uops_issued.", + "SampleAfterValue": "1000003", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Uops that RAT issues to RS", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xae", + "EventName": "UOPS_ISSUED.ANY", + "PublicDescription": "Counts the number of uops that the Resource Allocation Table (RAT) issues to the Reservation Station (RS).", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "UOPS_ISSUED.CYCLES", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0xae", + "EventName": "UOPS_ISSUED.CYCLES", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles with retired uop(s).", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.CYCLES", + "PublicDescription": "Counts cycles where at least one uop has retired.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of uops retired that were dual destination.", + "Counter": "0,1,2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.DUAL_DEST", + "PublicDescription": "Counts the number of uops retired that were dual destination. Dual destination (dual dest) micro-operations require writing to two separate destination registers or memory addresses upon execution. These uops consume two entries in the ROB and tracked separately because they involve more complex operations that necessitate multiple results. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops retired that are the last uop of a macro-instruction.", + "Counter": "0,1,2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.EOM", + "PublicDescription": "Counts the number of uops retired that are the last uop of a macro-instruction. EOM uops indicate the 'end of a macro-instruction' and play a crucial role in the processor's control flow and recovery mechanisms. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Retired uops except the last uop of each instruction.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.HEAVY", + "PublicDescription": "Counts the number of retired micro-operations (uops) except the last uop of each instruction. An instruction that is decoded into less than two uops does not contribute to the count.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of integer divide uops retired.", + "Counter": "0,1,2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.IDIV", + "PublicDescription": "Counts the number of integer divide uops retired. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x80", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops retired that originated from a loop stream detector.", + "Counter": "0,1,2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.LSD", + "PublicDescription": "Counts the number of uops retired that originated from a loop stream detector. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of uops that are from the complex flows issued by the micro-sequencer (MS). This includes uops from flows due to complex instructions, faults, assists, and inserted flows.", + "Counter": "0,1,2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.MS", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "UOPS_RETIRED.MS", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.MS", + "MSRIndex": "0x3F7", + "MSRValue": "0x8", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of non-speculative switches to the Microcode Sequencer (MS)", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.MS_SWITCHES", + "MSRIndex": "0x3F7", + "MSRValue": "0x8", + "PublicDescription": "Switches to the Microcode Sequencer", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event counts a subset of the Topdown Slots event that are utilized by operations that eventually get retired (committed) by the processor pipeline. Usually, this event positively correlates with higher performance for example, as measured by the instructions-per-cycle metric.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.SLOTS", + "PublicDescription": "This event counts a subset of the Topdown Slots event that are utilized by operations that eventually get retired (committed) by the processor pipeline. Usually, this event positively correlates with higher performance for example, as measured by the instructions-per-cycle metric. Software can use this event as the numerator for the Retiring metric (or top-level category) of the Top-down Microarchitecture Analysis method.", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles without actually retired uops.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.STALLS", + "Invert": "1", + "PublicDescription": "This event counts cycles without actually retired uops.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of x87 uops retired, includes those in MS flows.", + "Counter": "0,1,2,3,4,5,6,7", + "Data_LA": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.X87", + "PublicDescription": "Counts the number of x87 uops retired, includes those in ms flows Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "Unit": "cpu_atom" + } +] diff --git a/tools/perf/pmu-events/arch/x86/novalake/uncore-memory.json b/tools/perf/pmu-events/arch/x86/novalake/uncore-memory.json new file mode 100644 index 000000000000..6f809cc34966 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/novalake/uncore-memory.json @@ -0,0 +1,42 @@ +[ + { + "BriefDescription": "Read CAS command sent to DRAM (including Read CAS with auto precharge)", + "Counter": "0,1,2,3,4", + "EventCode": "0x22", + "EventName": "UNC_M_CAS_COUNT_RD", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Write CAS command sent to DRAM (including Write CAS with auto precharge)", + "Counter": "0,1,2,3,4", + "EventCode": "0x23", + "EventName": "UNC_M_CAS_COUNT_WR", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "This counter counts number of bytes read, in 32B chunk, per DDR channel. Counter increments by 1 after receiving 32B chunk data. Note this includes data from mode register accesses", + "Counter": "0,1,2,3,4", + "EventCode": "0x3A", + "EventName": "UNC_M_RD_DATA", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Total number of read and write byte transfers to/from DRAM, in 32B chunk, per DDR channel. Counter increments by 1 after sending or receiving 32B chunk data. Note this includes data from mode register accesses. Does not support channel masking", + "Counter": "0,1,2,3,4", + "EventCode": "0x3C", + "EventName": "UNC_M_TOTAL_DATA", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "This counter counts number of bytes written, in 32B chunk, per DDR channel. Counter increments by 1 after sending 32B chunk data.", + "Counter": "0,1,2,3,4", + "EventCode": "0x3B", + "EventName": "UNC_M_WR_DATA", + "PerPkg": "1", + "Unit": "iMC" + } +] diff --git a/tools/perf/pmu-events/arch/x86/novalake/virtual-memory.json b/tools/perf/pmu-events/arch/x86/novalake/virtual-memory.json new file mode 100644 index 000000000000..356a74434288 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/novalake/virtual-memory.json @@ -0,0 +1,338 @@ +[ + { + "BriefDescription": "Counts the number of page walks initiated by a demand load that missed the first and second level TLBs.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x08", + "EventName": "DTLB_LOAD_MISSES.MISS_CAUSED_WALK", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of first level TLB misses but second level hits due to a demand load that did not start a page walk. Accounts for all page sizes. Will result in a DTLB write from STLB.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x08", + "EventName": "DTLB_LOAD_MISSES.STLB_HIT", + "SampleAfterValue": "1000003", + "UMask": "0x60", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Loads that miss the DTLB and hit the STLB.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x12", + "EventName": "DTLB_LOAD_MISSES.STLB_HIT", + "PublicDescription": "Counts loads that miss the DTLB (Data TLB) and hit the STLB (Second level TLB).", + "SampleAfterValue": "100003", + "UMask": "0x320", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when at least one PMH is busy with a page walk for a demand load.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0x12", + "EventName": "DTLB_LOAD_MISSES.WALK_ACTIVE", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a demand load.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Load miss in all TLB levels causes a page walk that completes. (All page sizes)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x12", + "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED", + "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data loads. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0xe", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Page walks completed due to a demand data load to a 1G page.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x12", + "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_1G", + "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Page walks completed due to a demand data load to a 2M/4M page.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x12", + "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M", + "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of page walks completed due to load DTLB misses to a 4K page.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x08", + "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_4K", + "PublicDescription": "Counts the number of page walks completed due to loads (including SW prefetches) whose address translations missed in all Translation Lookaside Buffer (TLB) levels and were mapped to 4K pages. Includes page walks that page fault.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Page walks completed due to a demand data load to a 4K page.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x12", + "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_4K", + "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of page walks outstanding for Loads (demand or SW prefetch) in PMH every cycle.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x08", + "EventName": "DTLB_LOAD_MISSES.WALK_PENDING", + "PublicDescription": "Counts the number of page walks outstanding for Loads (demand or SW prefetch) in PMH every cycle. A PMH page walk is outstanding from page walk start till PMH becomes idle again (ready to serve next walk). Includes EPT-walk intervals.", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Number of page walks outstanding for a demand load in the PMH each cycle.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x12", + "EventName": "DTLB_LOAD_MISSES.WALK_PENDING", + "PublicDescription": "Counts the number of page walks outstanding for a demand load in the PMH (Page Miss Handler) each cycle.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of page walks initiated by a store that missed the first and second level TLBs.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x49", + "EventName": "DTLB_STORE_MISSES.MISS_CAUSED_WALK", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of first level TLB misses but second level hits due to stores that did not start a page walk. Accounts for all page sizes. Will result in a DTLB write from STLB.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x49", + "EventName": "DTLB_STORE_MISSES.STLB_HIT", + "PublicDescription": "Counts the number of first level TLB misses but second level hits due to a demand load that did not start a page walk. Accounts for all page sizes. Will result in a DTLB write from STLB.", + "SampleAfterValue": "1000003", + "UMask": "0x60", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Stores that miss the DTLB and hit the STLB.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x13", + "EventName": "DTLB_STORE_MISSES.STLB_HIT", + "PublicDescription": "Counts stores that miss the DTLB (Data TLB) and hit the STLB (2nd Level TLB).", + "SampleAfterValue": "100003", + "UMask": "0x320", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when at least one PMH is busy with a page walk for a store.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0x13", + "EventName": "DTLB_STORE_MISSES.WALK_ACTIVE", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a store.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Store misses in all TLB levels causes a page walk that completes. (All page sizes)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x13", + "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED", + "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data stores. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0xe", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Page walks completed due to a demand data store to a 1G page.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x13", + "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_1G", + "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Page walks completed due to a demand data store to a 2M/4M page.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x13", + "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M", + "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of page walks completed due to store DTLB misses to a 4K page.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x49", + "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_4K", + "PublicDescription": "Counts the number of page walks completed due to stores whose address translations missed in all Translation Lookaside Buffer (TLB) levels and were mapped to 4K pages. Includes page walks that page fault.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Page walks completed due to a demand data store to a 4K page.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x13", + "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_4K", + "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of page walks outstanding in the page miss handler (PMH) for stores every cycle.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x49", + "EventName": "DTLB_STORE_MISSES.WALK_PENDING", + "PublicDescription": "Counts the number of page walks outstanding in the page miss handler (PMH) for stores every cycle. A PMH page walk is outstanding from page walk start till PMH becomes idle again (ready to serve next walk). Includes EPT-walk intervals.", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Number of page walks outstanding for a store in the PMH each cycle.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x13", + "EventName": "DTLB_STORE_MISSES.WALK_PENDING", + "PublicDescription": "Counts the number of page walks outstanding for a store in the PMH (Page Miss Handler) each cycle.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of page walks initiated by a instruction fetch that missed the first and second level TLBs.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x85", + "EventName": "ITLB_MISSES.MISS_CAUSED_WALK", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of first level TLB misses but second level hits due to an instruction fetch that did not start a page walk. Account for all pages sizes. Will result in an ITLB write from STLB.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x85", + "EventName": "ITLB_MISSES.STLB_HIT", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Instruction fetch requests that miss the ITLB and hit the STLB.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x11", + "EventName": "ITLB_MISSES.STLB_HIT", + "PublicDescription": "Counts instruction fetch requests that miss the ITLB (Instruction TLB) and hit the STLB (Second-level TLB).", + "SampleAfterValue": "100003", + "UMask": "0x120", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when at least one PMH is busy with a page walk for code (instruction fetch) request.", + "Counter": "0,1,2,3,4,5,6,7", + "CounterMask": "1", + "EventCode": "0x11", + "EventName": "ITLB_MISSES.WALK_ACTIVE", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a code (instruction fetch) request.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Code miss in all TLB levels causes a page walk that completes. (All page sizes)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x11", + "EventName": "ITLB_MISSES.WALK_COMPLETED", + "PublicDescription": "Counts completed page walks (all page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0xe", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Code miss in all TLB levels causes a page walk that completes. (2M/4M)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x11", + "EventName": "ITLB_MISSES.WALK_COMPLETED_2M_4M", + "PublicDescription": "Counts completed page walks (2M/4M page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of page walks completed due to instruction fetch misses to a 4K page.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x85", + "EventName": "ITLB_MISSES.WALK_COMPLETED_4K", + "PublicDescription": "Counts the number of page walks completed due to instruction fetches whose address translations missed in all Translation Lookaside Buffer (TLB) levels and were mapped to 4K pages. Includes page walks that page fault.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Code miss in all TLB levels causes a page walk that completes. (4K)", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x11", + "EventName": "ITLB_MISSES.WALK_COMPLETED_4K", + "PublicDescription": "Counts completed page walks (4K page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of page walks outstanding for an outstanding code request in the PMH each cycle.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x11", + "EventName": "ITLB_MISSES.WALK_PENDING", + "PublicDescription": "Counts the number of page walks outstanding for an outstanding code (instruction fetch) request in the PMH (Page Miss Handler) each cycle.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of retired loads that are blocked due to a first level TLB miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.DTLB_MISS", + "PublicDescription": "Counts the number of retired loads that are blocked due to a first level TLB miss. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to a DTLB miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.DTLB_MISS", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer and retirement are both stalled due to a DTLB miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.DTLB_MISS_AT_RET", + "SampleAfterValue": "1000003", + "UMask": "0x90", + "Unit": "cpu_atom" + } +] -- cgit v1.2.3 From 27780f9b3b7bfcec7e1d0776887863513454aef1 Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Mon, 13 Jul 2026 11:17:55 -0700 Subject: perf vendor events intel: Update pantherlake events from 1.06 to 1.07 The updated events were published in: https://github.com/intel/perfmon/commit/ce70546e9ccca4181d142057171c5bd820c8756d Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Signed-off-by: Namhyung Kim --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- tools/perf/pmu-events/arch/x86/pantherlake/pipeline.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index d88a22d9de72..e4cc479a040d 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -26,7 +26,7 @@ GenuineIntel-6-BD,v1.26,lunarlake,core GenuineIntel-6-(AA|AC|B5),v1.22,meteorlake,core GenuineIntel-6-1[AEF],v4,nehalemep,core GenuineIntel-6-2E,v4,nehalemex,core -GenuineIntel-6-(CC|D5),v1.06,pantherlake,core +GenuineIntel-6-(CC|D5|E5),v1.07,pantherlake,core GenuineIntel-6-A7,v1.04,rocketlake,core GenuineIntel-6-2A,v19,sandybridge,core GenuineIntel-6-8F,v1.39,sapphirerapids,core diff --git a/tools/perf/pmu-events/arch/x86/pantherlake/pipeline.json b/tools/perf/pmu-events/arch/x86/pantherlake/pipeline.json index 5d5303c02954..74209da5bc27 100644 --- a/tools/perf/pmu-events/arch/x86/pantherlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/pantherlake/pipeline.json @@ -1334,7 +1334,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", - "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent. Available PDIST counters: 0,1", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note: Since the number of iterations within a REP instruction can be significantly affected by fast strings, this event may vary run to run and not match the architectural number of iterations (specified by RCX) Available PDIST counters: 0,1", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" -- cgit v1.2.3 From c0f049a1f63ac57da77a6f895043c0a0e3f9129d Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Mon, 13 Jul 2026 11:17:56 -0700 Subject: perf vendor events intel: Update sierraforest events from 1.17 to 1.18 The updated events were published in: https://github.com/intel/perfmon/commit/d1bc6c1e8b32e7a75c70cc939295c11ba9aabc96 Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Signed-off-by: Namhyung Kim --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- .../pmu-events/arch/x86/sierraforest/counter.json | 77 ---------------------- .../arch/x86/sierraforest/uncore-interconnect.json | 10 +++ .../arch/x86/sierraforest/uncore-memory.json | 2 +- 4 files changed, 12 insertions(+), 79 deletions(-) delete mode 100644 tools/perf/pmu-events/arch/x86/sierraforest/counter.json diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index e4cc479a040d..8e4ee898942c 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -30,7 +30,7 @@ GenuineIntel-6-(CC|D5|E5),v1.07,pantherlake,core GenuineIntel-6-A7,v1.04,rocketlake,core GenuineIntel-6-2A,v19,sandybridge,core GenuineIntel-6-8F,v1.39,sapphirerapids,core -GenuineIntel-6-AF,v1.17,sierraforest,core +GenuineIntel-6-AF,v1.18,sierraforest,core GenuineIntel-6-(37|4A|4C|4D|5A),v15,silvermont,core GenuineIntel-6-(4E|5E|8E|9E|A5|A6),v59,skylake,core GenuineIntel-6-55-[01234],v1.37,skylakex,core diff --git a/tools/perf/pmu-events/arch/x86/sierraforest/counter.json b/tools/perf/pmu-events/arch/x86/sierraforest/counter.json deleted file mode 100644 index a92c75109e6a..000000000000 --- a/tools/perf/pmu-events/arch/x86/sierraforest/counter.json +++ /dev/null @@ -1,77 +0,0 @@ -[ - { - "Unit": "core", - "CountersNumFixed": "3", - "CountersNumGeneric": "8" - }, - { - "Unit": "B2CMI", - "CountersNumFixed": "0", - "CountersNumGeneric": "4" - }, - { - "Unit": "CHA", - "CountersNumFixed": "0", - "CountersNumGeneric": "4" - }, - { - "Unit": "IMC", - "CountersNumFixed": "0", - "CountersNumGeneric": "4" - }, - { - "Unit": "CXLCM", - "CountersNumFixed": "0", - "CountersNumGeneric": 8 - }, - { - "Unit": "CXLDP", - "CountersNumFixed": "0", - "CountersNumGeneric": 4 - }, - { - "Unit": "B2HOT", - "CountersNumFixed": "0", - "CountersNumGeneric": 4 - }, - { - "Unit": "IIO", - "CountersNumFixed": "0", - "CountersNumGeneric": "4" - }, - { - "Unit": "IRP", - "CountersNumFixed": "0", - "CountersNumGeneric": "4" - }, - { - "Unit": "UPI", - "CountersNumFixed": "0", - "CountersNumGeneric": "4" - }, - { - "Unit": "B2UPI", - "CountersNumFixed": "0", - "CountersNumGeneric": 4 - }, - { - "Unit": "B2CXL", - "CountersNumFixed": "0", - "CountersNumGeneric": 4 - }, - { - "Unit": "PCU", - "CountersNumFixed": "0", - "CountersNumGeneric": "4" - }, - { - "Unit": "CHACMS", - "CountersNumFixed": "0", - "CountersNumGeneric": "4" - }, - { - "Unit": "MDF", - "CountersNumFixed": "0", - "CountersNumGeneric": 4 - } -] \ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/sierraforest/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/sierraforest/uncore-interconnect.json index 251e5d20fefe..1f6e0970141a 100644 --- a/tools/perf/pmu-events/arch/x86/sierraforest/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/sierraforest/uncore-interconnect.json @@ -814,6 +814,16 @@ "PerPkg": "1", "Unit": "IRP" }, + { + "BriefDescription": "Counts Timeouts - Set 0 : Cache Inserts of Write Transactions as Secondary", + "Counter": "0,1,2,3", + "EventCode": "0x1E", + "EventName": "UNC_I_MISC0.2ND_WR_INSERT", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x8", + "Unit": "IRP" + }, { "BriefDescription": "Counts Timeouts - Set 0 : Fastpath Rejects", "Counter": "0,1,2,3", diff --git a/tools/perf/pmu-events/arch/x86/sierraforest/uncore-memory.json b/tools/perf/pmu-events/arch/x86/sierraforest/uncore-memory.json index a9fd7a34b24b..8b7222a3708b 100644 --- a/tools/perf/pmu-events/arch/x86/sierraforest/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/sierraforest/uncore-memory.json @@ -499,7 +499,7 @@ "Unit": "IMC" }, { - "BriefDescription": "DRAM Precharge commands. : Precharge due to (?) : Counts the number of DRAM Precharge commands sent on this channel.", + "BriefDescription": "DRAM Precharge commands. : Precharge due to page table : Counts the number of DRAM Precharge commands sent on this channel.", "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "UNC_M_PRE_COUNT.PGT", -- cgit v1.2.3 From 604062ad51c75cf6ecd6a5823dc42b48e8d47838 Mon Sep 17 00:00:00 2001 From: Chun-Tse Shao Date: Mon, 13 Jul 2026 11:17:57 -0700 Subject: perf vendor events intel: Update emeraldrapids metrics The updated events were published in: https://github.com/intel/perfmon/commit/240735b7d8e0b50fe8f4a64e08399df13cb87ae6 Signed-off-by: Chun-Tse Shao Reviewed-by: Dapeng Mi Signed-off-by: Namhyung Kim --- .../arch/x86/emeraldrapids/emr-metrics.json | 135 +++++++++++++-------- .../arch/x86/emeraldrapids/metricgroups.json | 2 +- 2 files changed, 87 insertions(+), 50 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/emr-metrics.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/emr-metrics.json index 433ae5f50704..e00e32e71691 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/emr-metrics.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/emr-metrics.json @@ -84,6 +84,18 @@ "PublicDescription": "Ratio of number of completed page walks (for all page sizes) caused by demand data stores to the total number of completed instructions. This implies it missed in the DTLB and further levels of TLB", "ScaleUnit": "1per_instr" }, + { + "BriefDescription": "Bandwidth observed by the integrated I/O traffic controller (IIO) of IO reads that are initiated by end device controllers that are requesting memory from the CPU", + "MetricExpr": "UNC_IIO_DATA_REQ_OF_CPU.MEM_READ.ALL_PARTS * 4 / 1e6 / duration_time", + "MetricName": "iio_bandwidth_read", + "ScaleUnit": "1MB/s" + }, + { + "BriefDescription": "Bandwidth observed by the integrated I/O traffic controller (IIO) of IO writes that are initiated by end device controllers that are writing memory to the CPU", + "MetricExpr": "UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.ALL_PARTS * 4 / 1e6 / duration_time", + "MetricName": "iio_bandwidth_write", + "ScaleUnit": "1MB/s" + }, { "BriefDescription": "Bandwidth of IO reads that are initiated by end device controllers that are requesting memory from the CPU", "MetricExpr": "UNC_CHA_TOR_INSERTS.IO_PCIRDCUR * 64 / 1e6 / duration_time", @@ -242,6 +254,30 @@ "MetricName": "llc_demand_data_read_miss_to_dram_latency", "ScaleUnit": "1ns" }, + { + "BriefDescription": "Bandwidth (MB/sec) of read requests that miss the last level cache (LLC) and go to local memory", + "MetricExpr": "UNC_CHA_REQUESTS.READS_LOCAL * 64 / 1e6 / duration_time", + "MetricName": "llc_miss_local_memory_bandwidth_read", + "ScaleUnit": "1MB/s" + }, + { + "BriefDescription": "Bandwidth (MB/sec) of write requests that miss the last level cache (LLC) and go to local memory", + "MetricExpr": "UNC_CHA_REQUESTS.WRITES_LOCAL * 64 / 1e6 / duration_time", + "MetricName": "llc_miss_local_memory_bandwidth_write", + "ScaleUnit": "1MB/s" + }, + { + "BriefDescription": "Bandwidth (MB/sec) of read requests that miss the last level cache (LLC) and go to remote memory", + "MetricExpr": "UNC_CHA_REQUESTS.READS_REMOTE * 64 / 1e6 / duration_time", + "MetricName": "llc_miss_remote_memory_bandwidth_read", + "ScaleUnit": "1MB/s" + }, + { + "BriefDescription": "Bandwidth (MB/sec) of write requests that miss the last level cache (LLC) and go to remote memory", + "MetricExpr": "UNC_CHA_REQUESTS.WRITES_REMOTE * 64 / 1e6 / duration_time", + "MetricName": "llc_miss_remote_memory_bandwidth_write", + "ScaleUnit": "1MB/s" + }, { "BriefDescription": "The ratio of number of completed memory load instructions to the total number completed instructions", "MetricExpr": "MEM_INST_RETIRED.ALL_LOADS / INST_RETIRED.ANY", @@ -403,15 +439,15 @@ }, { "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + 0 / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_miss_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + 0 / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency) + tma_memory_bound * (tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_uc_bound" }, { "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + 0 / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_miss_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + 0 / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency) + tma_memory_bound * (tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", "MetricName": "tma_bottleneck_data_cache_memory_latency", "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", @@ -434,7 +470,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", "MetricThreshold": "tma_bottleneck_memory_data_tlbs > 20", @@ -442,7 +478,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) * tma_remote_cache / (tma_local_mem + tma_remote_cache + tma_remote_mem) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l3_miss_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) * tma_remote_cache / (tma_local_mem + tma_remote_cache + tma_remote_mem) + tma_l3_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_l3_miss_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", "MetricThreshold": "tma_bottleneck_memory_synchronization > 10", @@ -594,13 +630,13 @@ "ScaleUnit": "100%" }, { - "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses", + "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to L3 data-sharing accesses", "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "74.6 * tma_info_system_core_frequency * (MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD + MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD * (1 - OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM / (OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM + OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD))) * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "BvMS;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_data_sharing", "MetricThreshold": "tma_data_sharing > 0.05 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses. Data shared by multiple Logical Processors (even just read shared) may cause increased access latency due to cache coherency. Excessive data sharing can drastically harm multithreaded performance. Sample with: MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_false_sharing, tma_machine_clears, tma_remote_cache", + "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to L3 data-sharing accesses. Data shared by multiple Logical Processors (even just read shared) may cause increased access latency due to cache coherency. Excessive data sharing can drastically harm multithreaded performance. Sample with: MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_false_sharing, tma_machine_clears, tma_remote_cache", "ScaleUnit": "100%" }, { @@ -621,15 +657,6 @@ "PublicDescription": "This metric represents fraction of cycles where the Divider unit was active. Divide and square root instructions are performed by the Divider unit and can take considerably longer latency than integer or Floating Point addition; subtraction; or multiplication. Sample with: ARITH.DIV_ACTIVE", "ScaleUnit": "100%" }, - { - "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", - "MetricExpr": "MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks", - "MetricGroup": "MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", - "MetricName": "tma_dram_bound", - "MetricThreshold": "tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", - "PublicDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads. Better caching can improve the latency and increase performance. Sample with: MEM_LOAD_RETIRED.L3_MISS", - "ScaleUnit": "100%" - }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to DSB (decoded uop cache) fetch pipeline", "MetricExpr": "(IDQ.DSB_CYCLES_ANY - IDQ.DSB_CYCLES_OK) / tma_info_core_core_clks / 2", @@ -681,7 +708,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores, tma_uc_bound", "ScaleUnit": "100%" }, { @@ -974,7 +1001,7 @@ }, { "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded ICache; or Uop Cache)", - "MetricExpr": "IDQ.DSB_UOPS / UOPS_ISSUED.ANY", + "MetricExpr": "IDQ.DSB_UOPS / (IDQ.DSB_UOPS + IDQ.MITE_UOPS + IDQ.MS_UOPS)", "MetricGroup": "DSB;Fed;FetchBW;tma_issueFB", "MetricName": "tma_info_frontend_dsb_coverage", "MetricThreshold": "tma_info_frontend_dsb_coverage < 0.7 & tma_info_thread_ipc / 6 > 0.35", @@ -1092,7 +1119,7 @@ { "BriefDescription": "Instructions per FP Arithmetic Scalar Half-Precision instruction (lower number means higher occurrence rate)", "MetricExpr": "INST_RETIRED.ANY / FP_ARITH_INST_RETIRED2.SCALAR", - "MetricGroup": "Flops;FpScalar;InsType;Server", + "MetricGroup": "Flops;FpScalar;InsType", "MetricName": "tma_info_inst_mix_iparith_scalar_hp", "MetricThreshold": "tma_info_inst_mix_iparith_scalar_hp < 10", "PublicDescription": "Instructions per FP Arithmetic Scalar Half-Precision instruction (lower number means higher occurrence rate). Values < 1 are possible due to intentional FMA double counting." @@ -1161,6 +1188,14 @@ "MetricThreshold": "tma_info_inst_mix_iptb < 13", "PublicDescription": "Instructions per taken branch. Related metrics: tma_dsb_switches, tma_fetch_bandwidth, tma_info_botlnk_l2_dsb_bandwidth, tma_info_botlnk_l2_dsb_misses, tma_info_frontend_dsb_coverage, tma_lcp" }, + { + "BriefDescription": "AVX preserve/restore assists per kilo instruction", + "MetricExpr": "1e3 * ASSISTS.SSE_AVX_MIX / INST_RETIRED.ANY", + "MetricGroup": "tma_issueMV", + "MetricName": "tma_info_inst_mix_vectormixpki", + "MetricThreshold": "tma_info_inst_mix_vectormixpki > 0.05", + "PublicDescription": "AVX preserve/restore assists per kilo instruction. Related metrics: tma_mixing_vectors, tma_ms_switches" + }, { "BriefDescription": "Average per-core data fill bandwidth to the L1 data cache [GB / sec]", "MetricExpr": "tma_info_memory_l1d_cache_fill_bw", @@ -1402,7 +1437,7 @@ "MetricName": "tma_info_memory_tlb_store_stlb_mpki" }, { - "BriefDescription": "Mem;Backend;CacheHits", + "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is execution) per physical core", "MetricExpr": "UOPS_EXECUTED.THREAD / (UOPS_EXECUTED.CORE_CYCLES_GE_1 / 2 if #SMT_on else cpu@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -1482,7 +1517,7 @@ "MetricExpr": "64 * (UNC_M_CAS_COUNT.RD + UNC_M_CAS_COUNT.WR) / 1e9 / tma_info_system_time", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full, tma_uc_bound" }, { "BriefDescription": "Giga Floating Point Operations Per Second", @@ -1532,13 +1567,6 @@ "MetricName": "tma_info_system_mem_dram_read_latency", "PublicDescription": "Average latency of data read request to external DRAM memory [in nanoseconds]. Accounts for demand loads and L1/L2 data-read prefetches" }, - { - "BriefDescription": "Fraction of Uncore cycles where requests got rejected due to duplicate address already in IRQ ingress queue in the cache homing agent", - "MetricExpr": "UNC_CHA_RxC_IRQ1_REJECT.PA_MATCH / UNC_CHA_CLOCKTICKS", - "MetricGroup": "LockCont;MemOffcore;Server;SoC", - "MetricName": "tma_info_system_mem_irq_duplicate_address", - "MetricThreshold": "tma_info_system_mem_irq_duplicate_address > 0.1" - }, { "BriefDescription": "Average number of parallel data read requests to external memory", "MetricExpr": "UNC_CHA_TOR_OCCUPANCY.IA_MISS_DRD / UNC_CHA_TOR_OCCUPANCY.IA_MISS_DRD@thresh\\=1@", @@ -1591,12 +1619,6 @@ "MetricGroup": "Power", "MetricName": "tma_info_system_turbo_utilization" }, - { - "BriefDescription": "Measured Average Uncore Frequency for the SoC [GHz]", - "MetricExpr": "tma_info_system_socket_clks / 1e9 / tma_info_system_time", - "MetricGroup": "SoC", - "MetricName": "tma_info_system_uncore_frequency" - }, { "BriefDescription": "Cross-socket Ultra Path Interconnect (UPI) data transmit bandwidth for data only [MB / sec]", "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 64 / 9 / 1e6", @@ -1752,6 +1774,15 @@ "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%" }, + { + "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", + "MetricExpr": "MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks", + "MetricGroup": "MemoryBound;Offcore;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", + "MetricName": "tma_l3_miss_bound", + "MetricThreshold": "tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", + "PublicDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads. Better caching can improve the latency and increase performance. Sample with: MEM_LOAD_RETIRED.L3_MISS", + "ScaleUnit": "100%" + }, { "BriefDescription": "This metric represents fraction of cycles CPU was stalled due to Length Changing Prefixes (LCPs)", "MetricExpr": "DECODE.LCP / tma_info_thread_clks", @@ -1826,14 +1857,14 @@ "MetricExpr": "72 * tma_info_system_core_frequency * MEM_LOAD_L3_MISS_RETIRED.LOCAL_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "Server;TopdownL5;tma_L5_group;tma_mem_latency_group", "MetricName": "tma_local_mem", - "MetricThreshold": "tma_local_mem > 0.1 & (tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", + "MetricThreshold": "tma_local_mem > 0.1 & (tma_mem_latency > 0.1 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from local memory. Caching will improve the latency and increase performance. Sample with: MEM_LOAD_L3_MISS_RETIRED.LOCAL_DRAM", "ScaleUnit": "100%" }, { "BriefDescription": "This metric represents fraction of cycles the CPU spent handling cache misses due to lock operations", "MetricConstraint": "NO_GROUP_EVENTS", - "MetricExpr": "(16 * max(0, MEM_INST_RETIRED.LOCK_LOADS - L2_RQSTS.ALL_RFO) + MEM_INST_RETIRED.LOCK_LOADS / MEM_INST_RETIRED.ALL_STORES * (10 * L2_RQSTS.RFO_HIT + min(CPU_CLK_UNHALTED.THREAD, OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO))) / tma_info_thread_clks", + "MetricExpr": "LOCK_CYCLES.CACHE_LOCK_DURATION / tma_info_thread_clks", "MetricGroup": "LockCont;Offcore;TopdownL4;tma_L4_group;tma_issueRFO;tma_l1_bound_group", "MetricName": "tma_lock_latency", "MetricThreshold": "tma_lock_latency > 0.2 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", @@ -1856,24 +1887,24 @@ "MetricExpr": "INT_MISC.MBA_STALLS / tma_info_thread_clks", "MetricGroup": "MemoryBW;Offcore;Server;TopdownL5;tma_L5_group;tma_mem_bandwidth_group", "MetricName": "tma_mba_stalls", - "MetricThreshold": "tma_mba_stalls > 0.1 & (tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", + "MetricThreshold": "tma_mba_stalls > 0.1 & (tma_mem_bandwidth > 0.2 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", "ScaleUnit": "100%" }, { "BriefDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM)", - "MetricExpr": "min(CPU_CLK_UNHALTED.THREAD, cpu@OFFCORE_REQUESTS_OUTSTANDING.ALL_DATA_RD\\,cmask\\=4@) / tma_info_thread_clks", - "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", + "MetricExpr": "min(CPU_CLK_UNHALTED.THREAD, cpu@OFFCORE_REQUESTS_OUTSTANDING.ALL_DATA_RD\\,cmask\\=12@) / tma_info_thread_clks", + "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_miss_bound_group", "MetricName": "tma_mem_bandwidth", - "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full, tma_uc_bound", "ScaleUnit": "100%" }, { "BriefDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM)", "MetricExpr": "min(CPU_CLK_UNHALTED.THREAD, OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD) / tma_info_thread_clks - tma_mem_bandwidth", - "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", + "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_miss_bound_group", "MetricName": "tma_mem_latency", - "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", + "MetricThreshold": "tma_mem_latency > 0.1 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%" }, @@ -1937,7 +1968,7 @@ "MetricGroup": "TopdownL5;tma_L5_group;tma_issueMV;tma_ports_utilized_0_group", "MetricName": "tma_mixing_vectors", "MetricThreshold": "tma_mixing_vectors > 0.05", - "PublicDescription": "This metric estimates penalty in terms of percentage of([SKL+] injected blend uops out of all Uops Issued -- the Count Domain; [ADL+] cycles). Usually a Mixing_Vectors over 5% is worth investigating. Read more in Appendix B1 of the Optimizations Guide for this topic. Related metrics: tma_ms_switches", + "PublicDescription": "This metric estimates penalty in terms of percentage of([SKL+] injected blend uops out of all Uops Issued -- the Count Domain; [ADL+] cycles). Usually a Mixing_Vectors over 5% is worth investigating. Read more in Appendix B1 of the Optimizations Guide for this topic. Related metrics: tma_info_inst_mix_vectormixpki, tma_ms_switches", "ScaleUnit": "100%" }, { @@ -1954,7 +1985,7 @@ "MetricGroup": "FetchLat;MicroSeq;TopdownL3;tma_L3_group;tma_fetch_latency_group;tma_issueMC;tma_issueMS;tma_issueMV;tma_issueSO", "MetricName": "tma_ms_switches", "MetricThreshold": "tma_ms_switches > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", - "PublicDescription": "This metric estimates the fraction of cycles when the CPU was stalled due to switches of uop delivery to the Microcode Sequencer (MS). Commonly used instructions are optimized for delivery by the DSB (decoded i-cache) or MITE (legacy instruction decode) pipelines. Certain operations cannot be handled natively by the execution pipeline; and must be performed by microcode (small programs injected into the execution stream). Switching to the MS too often can negatively impact performance. The MS is designated to deliver long uop flows required by CISC instructions like CPUID; or uncommon conditions like Floating Point Assists when dealing with Denormals. Sample with: IDQ.MS_SWITCHES. Related metrics: tma_bottleneck_irregular_overhead, tma_clears_resteers, tma_l1_bound, tma_machine_clears, tma_microcode_sequencer, tma_mixing_vectors, tma_serializing_operation", + "PublicDescription": "This metric estimates the fraction of cycles when the CPU was stalled due to switches of uop delivery to the Microcode Sequencer (MS). Commonly used instructions are optimized for delivery by the DSB (decoded i-cache) or MITE (legacy instruction decode) pipelines. Certain operations cannot be handled natively by the execution pipeline; and must be performed by microcode (small programs injected into the execution stream). Switching to the MS too often can negatively impact performance. The MS is designated to deliver long uop flows required by CISC instructions like CPUID; or uncommon conditions like Floating Point Assists when dealing with Denormals. Sample with: IDQ.MS_SWITCHES. Related metrics: tma_bottleneck_irregular_overhead, tma_clears_resteers, tma_info_inst_mix_vectormixpki, tma_l1_bound, tma_machine_clears, tma_microcode_sequencer, tma_mixing_vectors, tma_serializing_operation", "ScaleUnit": "100%" }, { @@ -2090,7 +2121,7 @@ "MetricExpr": "(133 * tma_info_system_core_frequency * MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM + 133 * tma_info_system_core_frequency * MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD) * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "Offcore;Server;Snoop;TopdownL5;tma_L5_group;tma_issueSyncxn;tma_mem_latency_group", "MetricName": "tma_remote_cache", - "MetricThreshold": "tma_remote_cache > 0.05 & (tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", + "MetricThreshold": "tma_remote_cache > 0.05 & (tma_mem_latency > 0.1 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from remote cache in other sockets including synchronizations issues. This is caused often due to non-optimal NUMA allocations. #link to NUMA article. Sample with: MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM_PS;MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD_PS. Related metrics: tma_bottleneck_memory_synchronization, tma_contested_accesses, tma_data_sharing, tma_false_sharing, tma_machine_clears", "ScaleUnit": "100%" }, @@ -2099,7 +2130,7 @@ "MetricExpr": "153 * tma_info_system_core_frequency * MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "Server;Snoop;TopdownL5;tma_L5_group;tma_mem_latency_group", "MetricName": "tma_remote_mem", - "MetricThreshold": "tma_remote_mem > 0.1 & (tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", + "MetricThreshold": "tma_remote_mem > 0.1 & (tma_mem_latency > 0.1 & (tma_l3_miss_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", "PublicDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from remote memory. This is caused often due to non-optimal NUMA allocations. #link to NUMA article. Sample with: MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM_PS", "ScaleUnit": "100%" }, @@ -2143,7 +2174,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles handling memory load split accesses - load that cross 64-byte cache line boundary", - "MetricExpr": "tma_info_memory_load_miss_real_latency * LD_BLOCKS.NO_SR / tma_info_thread_clks", + "MetricExpr": "MEM_INST_RETIRED.SPLIT_LOADS * tma_info_memory_load_miss_real_latency / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_split_loads", "MetricThreshold": "tma_split_loads > 0.3", @@ -2165,7 +2196,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_uc_bound", "ScaleUnit": "100%" }, { @@ -2277,6 +2308,12 @@ "MetricName": "uncore_frequency", "ScaleUnit": "1GHz" }, + { + "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data receive bandwidth (MB/sec)", + "MetricExpr": "UNC_UPI_RxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time", + "MetricName": "upi_data_receive_bw", + "ScaleUnit": "1MB/s" + }, { "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)", "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time", diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/metricgroups.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/metricgroups.json index 9129fb7b7ce4..b5f601991e9d 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/metricgroups.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/metricgroups.json @@ -90,7 +90,6 @@ "tma_code_stlb_miss_group": "Metrics contributing to tma_code_stlb_miss category", "tma_core_bound_group": "Metrics contributing to tma_core_bound category", "tma_divider_group": "Metrics contributing to tma_divider category", - "tma_dram_bound_group": "Metrics contributing to tma_dram_bound category", "tma_dtlb_load_group": "Metrics contributing to tma_dtlb_load category", "tma_dtlb_store_group": "Metrics contributing to tma_dtlb_store category", "tma_fetch_bandwidth_group": "Metrics contributing to tma_fetch_bandwidth category", @@ -124,6 +123,7 @@ "tma_l1_bound_group": "Metrics contributing to tma_l1_bound category", "tma_l2_bound_group": "Metrics contributing to tma_l2_bound category", "tma_l3_bound_group": "Metrics contributing to tma_l3_bound category", + "tma_l3_miss_bound_group": "Metrics contributing to tma_l3_miss_bound category", "tma_light_operations_group": "Metrics contributing to tma_light_operations category", "tma_load_op_utilization_group": "Metrics contributing to tma_load_op_utilization category", "tma_load_stlb_miss_group": "Metrics contributing to tma_load_stlb_miss category", -- cgit v1.2.3 From 2bd4ad6914ed73189ccc2fb2740e94dafd1a9a8f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 13 Jul 2026 16:45:34 -0700 Subject: perf sched: Add missing perf_session__delete() The perf sched stats record missed to release the session and ASAN reported a leak. Fixes: c3030995f23b ("perf sched stats: Add record and rawdump support") Reviewed-and-tested-by: Swapnil Sapkal Signed-off-by: Namhyung Kim --- tools/perf/builtin-sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 6e0d8f4d270e..c5728f3aa46f 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -4027,8 +4027,8 @@ out: else fprintf(stderr, "[ perf sched stats: Failed !! ]\n"); + perf_session__delete(session); evlist__put(evlist); - close(fd); return err; } -- cgit v1.2.3 From 60de2c6561ae57b5f2c50efecc1fa1f0081f731a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 13 Jul 2026 16:45:35 -0700 Subject: perf sched: Fix memory leaks in perf sched stats report The second pass data is not saved in the list and only used to calculate delta from the first pass. Let's free the data after use. Fixes: 5a357ae6ad63 ("perf sched stats: Add support for report subcommand") Reviewed-and-tested-by: Swapnil Sapkal Signed-off-by: Namhyung Kim --- tools/perf/builtin-sched.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index c5728f3aa46f..ab9590c4d838 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -4631,6 +4631,8 @@ static int perf_sched__process_schedstat(const struct perf_tool *tool __maybe_un domain_second_pass = list_first_entry(&cpu_second_pass->domain_head, struct schedstat_domain, domain_list); store_schedstat_cpu_diff(temp); + free(temp->cpu_data); + free(temp); } } else if (event->header.type == PERF_RECORD_SCHEDSTAT_DOMAIN) { struct schedstat_cpu *cpu_tail; @@ -4651,6 +4653,8 @@ static int perf_sched__process_schedstat(const struct perf_tool *tool __maybe_un } else { store_schedstat_domain_diff(temp); domain_second_pass = list_next_entry(domain_second_pass, domain_list); + free(temp->domain_data); + free(temp); } } -- cgit v1.2.3 From e1f522ac439f94d56cf0d9a3c82d1953646d377a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 13 Jul 2026 16:45:36 -0700 Subject: perf sched: Free subcommand string after perf sched stats The first entry of the sched_usage is dynamically allocated in parse_options_subcommand() so it should be released at the end. Do not return from a subcommand directly. Fixes: 064790a3d4a8 ("perf sched stats: Add support for diff subcommand") Reviewed-and-tested-by: Swapnil Sapkal Signed-off-by: Namhyung Kim --- tools/perf/builtin-sched.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index ab9590c4d838..acc8d81a20d3 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -5259,19 +5259,20 @@ int cmd_sched(int argc, const char **argv) if (argc) argc = parse_options(argc, argv, stats_options, stats_usage, 0); - return perf_sched__schedstat_record(&sched, argc, argv); + ret = perf_sched__schedstat_record(&sched, argc, argv); } else if (argv[0] && !strcmp(argv[0], "report")) { if (argc) argc = parse_options(argc, argv, stats_options, stats_usage, 0); - return perf_sched__schedstat_report(&sched); + ret = perf_sched__schedstat_report(&sched); } else if (argv[0] && !strcmp(argv[0], "diff")) { if (argc) argc = parse_options(argc, argv, stats_options, stats_usage, 0); - return perf_sched__schedstat_diff(&sched, argc, argv); + ret = perf_sched__schedstat_diff(&sched, argc, argv); + } else { + ret = perf_sched__schedstat_live(&sched, argc, argv); } - return perf_sched__schedstat_live(&sched, argc, argv); } else { usage_with_options(sched_usage, sched_options); } -- cgit v1.2.3 From 557f8b3ca8c8e58d5bc3084734bc7a470b043922 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 6 Jul 2026 20:40:17 -0700 Subject: perf jevents: Add more components to the metric sorting order Nazar Kazakov reported non-deterministic builds due to the metrics being reordered in the jevents.py output. The metrics were largely only being sorted by name, add in the expressions and descriptions. Reported-by: Nazar Kazakov Closes: https://lore.kernel.org/linux-perf-users/20260706175624.692736-1-nazar.kazakov@codethink.co.uk/ Fixes: 40769665b63d ("perf jevents: Parse metrics during conversion") Tested-by: Nazar Kazakov Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/pmu-events/jevents.py | 5 +++-- tools/perf/pmu-events/metric.py | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py index 2bb51cc621b5..e86989c1389d 100755 --- a/tools/perf/pmu-events/jevents.py +++ b/tools/perf/pmu-events/jevents.py @@ -574,13 +574,14 @@ static const struct pmu_table_entry {_pending_events_tblname}[] = {{ def print_pending_metrics() -> None: """Optionally close metrics table.""" - def metric_cmp_key(j: JsonEvent) -> Tuple[bool, str, str]: + def metric_cmp_key(j: JsonEvent) -> Tuple[str, str, str, str]: def fix_none(s: Optional[str]) -> str: if s is None: return '' return s - return (j.desc is not None, fix_none(j.pmu), fix_none(j.metric_name)) + return (fix_none(j.pmu), fix_none(j.metric_name), j.metric_expr.ToPerfJson(), + fix_none(j.desc)) global _pending_metrics if not _pending_metrics: diff --git a/tools/perf/pmu-events/metric.py b/tools/perf/pmu-events/metric.py index a91ccb5977f0..11c7162825f4 100644 --- a/tools/perf/pmu-events/metric.py +++ b/tools/perf/pmu-events/metric.py @@ -623,7 +623,11 @@ class Metric: def __lt__(self, other): """Sort order.""" - return self.name < other.name + if self.name != other.name: + return self.name < other.name + if not self.expr.Equals(other.expr): + return self.expr.ToPerfJson() < other.expr.ToPerfJson() + return self.description < other.description def AddToMetricGroup(self, group): """Callback used when being added to a MetricGroup.""" -- cgit v1.2.3 From eadce0f46a1d066b812c7e5aa46a33711c78a755 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 10 Jul 2026 17:32:35 -0700 Subject: tools/lib/api: Fix potential double-free from fdarray__grow() If the realloc for fda->entries succeeds but the realloc for fda->priv fails, the error path frees the newly allocated entries. However, fda->entries is neither updated to point to the new entries block nor cleared to NULL. If realloc moved the allocation to a new block, the old fda->entries pointer is now freed memory. When fdarray__exit() is later called to clean up, it executes free(fda->entries), which would trigger a double-free on that old pointer. Reported-by: Sashiko Review Closes: https://lore.kernel.org/linux-perf-users/20260710200150.11FE71F00A3A@smtp.kernel.org Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/lib/api/fd/array.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/lib/api/fd/array.c b/tools/lib/api/fd/array.c index 16a047f1906e..67b73481df27 100644 --- a/tools/lib/api/fd/array.c +++ b/tools/lib/api/fd/array.c @@ -31,7 +31,8 @@ int fdarray__grow(struct fdarray *fda, int nr) priv = realloc(fda->priv, psize); if (priv == NULL) { - free(entries); + /* this will be freed by fdarray__exit() */ + fda->entries = entries; return -ENOMEM; } @@ -50,7 +51,7 @@ struct fdarray *fdarray__new(int nr_alloc, int nr_autogrow) if (fda != NULL) { if (fdarray__grow(fda, nr_alloc)) { - free(fda); + fdarray__delete(fda); fda = NULL; } else { fda->nr_autogrow = nr_autogrow; -- cgit v1.2.3 From 3f7909fa921e38b7aba8566b03ca5e0754a8fa8b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 8 Jul 2026 13:04:07 -0700 Subject: perf stat: Do not open cgroups for BPF counters The --bpf-counters and --for-each-cgroup options use a set of shared events among the given cgroups rather than adding events for each cgroup respectively. It only uses cgroup-ID to compare and calculate the result. So no need to open and keep FDs for cgroups in BPF mode. Signed-off-by: Namhyung Kim --- tools/perf/builtin-stat.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 3f685beba384..a85a4f30221a 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -2895,7 +2895,8 @@ int cmd_stat(int argc, const char **argv) goto out; } - if (evlist__expand_cgroup(evsel_list, stat_config.cgroup_list, true) < 0) { + if (evlist__expand_cgroup(evsel_list, stat_config.cgroup_list, + !target.use_bpf) < 0) { parse_options_usage(stat_usage, stat_options, "for-each-cgroup", 0); goto out; -- cgit v1.2.3 From c16af17927e0b9105f2964338f9341e0faf7edaa Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 10 Jul 2026 17:04:16 -0700 Subject: perf stat: Fix duplicate output with --for-each-cgroup Currently it produces following output with duplicate events when --for-each-cgroup option is used. It seems perf stat adds them when it handles default events but didn't copy some fields in evsel__clone(). $ sudo perf stat -a --for-each-cgroup / true Performance counter stats for 'system wide': 8,440,165 duration_time / 8,439,895 duration_time / 8,440,015 duration_time / 8,440,024 duration_time / 8,440,075 duration_time / 8,440,095 duration_time / 330 context-switches / # 679.4 cs/sec cs_per_second 485.69 msec cpu-clock / # 57.5 CPUs CPUs_utilized 70 cpu-migrations / # 144.1 migrations/sec migrations_per_second 71 page-faults / # 146.2 faults/sec page_faults_per_second 12,183,711 branch-misses / # 10.9 % branch_miss_rate (5.15%) 111,981,297 branches / (5.15%) 95,844,809 branches / # 197.3 M/sec branch_frequency (35.49%) 65,611,429 cpu-cycles / # 0.1 GHz cycles_frequency (98.32%) 24,170,987 cpu-cycles / (95.12%) 18,552,509 instructions / # 0.8 instructions insn_per_cycle (95.12%) 22,405,293 cpu-cycles / (64.78%) 6,840,383 stalled-cycles-frontend / # 0.31 frontend_cycles_idle (64.78%) cpu-cycles / stalled-cycles-backend / # nan backend_cycles_idle stalled-cycles-backend / # nan stalled_cycles_per_instruction instructions / stalled-cycles-frontend / 0.006546057 seconds time elapsed Some events weren't counted. Try disabling the NMI watchdog: echo 0 > /proc/sys/kernel/nmi_watchdog perf stat ... echo 1 > /proc/sys/kernel/nmi_watchdog But I'm worrying about opening same events multiple times. Probably due to grouping, but I'm not sure if it's beneficial in the end. Without duplication, it seems it won't cause multiplexing (assuming no other users at the same time). Fixes: a3248b5b5427d ("perf jevents: Add metric DefaultShowEvents") Signed-off-by: Namhyung Kim --- tools/perf/util/evsel.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 3404c40dee34..32cbacfae475 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -617,7 +617,13 @@ struct evsel *evsel__clone(struct evsel *orig) evsel->sample_read = orig->sample_read; evsel->collect_stat = orig->collect_stat; evsel->weak_group = orig->weak_group; + evsel->bpf_counter = orig->bpf_counter; evsel->use_config_name = orig->use_config_name; + evsel->skippable = orig->skippable; + evsel->dont_regroup = orig->dont_regroup; + evsel->default_metricgroup = orig->default_metricgroup; + evsel->default_show_events = orig->default_show_events; + evsel->pmu = orig->pmu; evsel->first_wildcard_match = orig->first_wildcard_match; @@ -626,6 +632,10 @@ struct evsel *evsel__clone(struct evsel *orig) evsel->alternate_hw_config = orig->alternate_hw_config; + evsel->retire_lat = orig->retire_lat; + if (evsel->retire_lat) + evsel->retirement_latency = orig->retirement_latency; + return evsel; out_err: -- cgit v1.2.3 From 8f216bc1f73c40fa6c993233dce4840ec0b363be Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 10 Jul 2026 17:04:17 -0700 Subject: perf evsel: Remove unused BPF related fields IIUC bpf_fd and bpf_obj fields are not used anymore. It seems like leftover from 3d6dfae889174340 ("perf parse-events: Remove BPF event support"). Signed-off-by: Namhyung Kim --- tools/perf/util/evsel.c | 21 --------------------- tools/perf/util/evsel.h | 2 -- 2 files changed, 23 deletions(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 32cbacfae475..a5b0687a3a79 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -455,8 +455,6 @@ static void evsel__init(struct evsel *evsel, evsel->scale = 1.0; evsel->max_events = ULONG_MAX; evsel->evlist = NULL; - evsel->bpf_obj = NULL; - evsel->bpf_fd = -1; INIT_LIST_HEAD(&evsel->config_terms); INIT_LIST_HEAD(&evsel->bpf_counter_list); INIT_LIST_HEAD(&evsel->bpf_filters); @@ -540,10 +538,6 @@ struct evsel *evsel__clone(struct evsel *orig) BUG_ON(orig->priv); BUG_ON(orig->per_pkg_mask); - /* cannot handle BPF objects for now */ - if (orig->bpf_obj) - return NULL; - evsel = evsel__new(&orig->core.attr); if (evsel == NULL) return NULL; @@ -3079,21 +3073,6 @@ retry_open: /* Debug message used by test scripts */ pr_debug2_peo(" = %d\n", fd); - if (evsel->bpf_fd >= 0) { - int evt_fd = fd; - int bpf_fd = evsel->bpf_fd; - - err = ioctl(evt_fd, - PERF_EVENT_IOC_SET_BPF, - bpf_fd); - if (err && errno != EEXIST) { - pr_err("failed to attach bpf fd %d: %m\n", - bpf_fd); - err = -EINVAL; - goto out_close; - } - } - set_rlimit = NO_CHANGE; /* diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 6b0c08958616..27af0c4f294e 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -94,8 +94,6 @@ struct evsel { bool skippable; bool retire_lat; bool dont_regroup; - int bpf_fd; - struct bpf_object *bpf_obj; struct list_head config_terms; u64 alternate_hw_config; }; -- cgit v1.2.3 From cf37bb44cd8817039ba5e790413f69de0a96fe55 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 10 Jul 2026 17:04:18 -0700 Subject: perf evsel: Arrange some fields that should be cloned In the evsel, there's an internal struct to put fields need copy when the evsel is cloned. This is purely to make it easier track those fields even if it sometimes failed to do so. :) Signed-off-by: Namhyung Kim --- tools/perf/util/evsel.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 27af0c4f294e..42b95933632a 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -74,6 +74,10 @@ struct evsel { const char *unit; struct cgroup *cgrp; const char *metric_id; + + /* The PMU the event is from. Used for missing_features, PMU name, etc. */ + struct perf_pmu *pmu; + /* * This point to the first evsel with the same name, intended to store the * aggregated counts in aggregation mode. @@ -94,6 +98,8 @@ struct evsel { bool skippable; bool retire_lat; bool dont_regroup; + bool default_metricgroup; /* A member of the Default metricgroup */ + bool default_show_events; /* If a default group member, show the event */ struct list_head config_terms; u64 alternate_hw_config; }; @@ -123,8 +129,6 @@ struct evsel { bool cmdline_group_boundary; bool reset_group; bool needs_auxtrace_mmap; - bool default_metricgroup; /* A member of the Default metricgroup */ - bool default_show_events; /* If a default group member, show the event */ bool needs_uniquify; bool fallenback_eacces; bool fallenback_eopnotsupp; @@ -180,9 +184,6 @@ struct evsel { unsigned long open_flags; int precise_ip_original; - /* The PMU the event is from. Used for missing_features, PMU name, etc. */ - struct perf_pmu *pmu; - /* For tool events */ /* Beginning time subtracted when the counter is read. */ union { -- cgit v1.2.3 From c341749d6abca2b81946f92e55567b5765b2b610 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 10 Jul 2026 17:04:19 -0700 Subject: perf test: Update test for --for-each-cgroup option To simply check the number of output lines with and without the option. Before this series, it failed like below: $ perf test -v 125 125: perf stat --bpf-counters --for-each-cgroup test: ---- start ---- test child forked, pid 1941516 Normal output has 22 lines, but it now has 54 ---- end(-1) ---- 125: perf stat --bpf-counters --for-each-cgroup test : FAILED! Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/stat_bpf_counters_cgrp.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh b/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh index ff2e06c408bc..febe3af06441 100755 --- a/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh +++ b/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh @@ -58,9 +58,24 @@ check_system_wide_counted() fi } +# Missing flags in evlist__clone() resulted in different output. +# Just check the number of output lines for simple verification. +check_evlist_expand() +{ + normal_output=$(perf stat -a -x, true 2>&1 | wc -l) + expand_output=$(perf stat -a -x, --bpf-counters --for-each-cgroup / true 2>&1 | wc -l) + if [ "${normal_output}" != "${expand_output}" ]; then + if [ "${verbose}" = "1" ]; then + echo "Normal output has ${normal_output} lines, but it now has ${expand_output}" + fi + exit 1 + fi +} + check_bpf_counter find_cgroups check_system_wide_counted +check_evlist_expand exit 0 -- cgit v1.2.3 From acff3e1a9cc29a6a039b76b81a438c56016bc0e3 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 7 Jul 2026 08:52:46 +0200 Subject: perf trace: Factor out BPF loop body The BPF program in augmented_raw_syscalls uses a for loop to iterate all syscall arguments. The loop body is quite complex and often poses problems for the BPF verifier. As a preparation step for addressing this issue, factor out the loop body into a separate function. Signed-off-by: Viktor Malik Cc: stable@vger.kernel.org Signed-off-by: Namhyung Kim --- .../util/bpf_skel/augmented_raw_syscalls.bpf.c | 128 ++++++++++++--------- 1 file changed, 73 insertions(+), 55 deletions(-) diff --git a/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c index 2a6e61864ee0..bc036a348079 100644 --- a/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c +++ b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c @@ -429,15 +429,80 @@ static bool pid_filter__has(struct pids_filtered *pids, pid_t pid) return bpf_map_lookup_elem(pids, &pid) != NULL; } +/* + * Determine what type of argument and how many bytes to read from user space, using the + * value in the beauty_map. This is the relation of parameter type and its corresponding + * value in the beauty map, and how many bytes we read eventually: + * + * string: 1 -> size of string + * struct: size of struct -> size of struct + * buffer: -1 * (index of paired len) -> value of paired len (maximum: TRACE_AUG_MAX_BUF) + */ +static inline int augment_arg(struct syscall_enter_args *args, int i, + unsigned int *beauty_map, + struct augmented_arg *payload_offset) +{ + int index, value_size = sizeof(struct augmented_arg) - offsetof(struct augmented_arg, value); + s64 aug_size, size; + bool augmented; + void *arg; + + arg = (void *)args->args[i]; + augmented = false; + size = beauty_map[i]; + aug_size = size; /* size of the augmented data read from user space */ + + if (size == 0 || arg == NULL) + return 0; + + if (size == 1) { /* string */ + aug_size = bpf_probe_read_user_str(payload_offset->value, value_size, arg); + /* minimum of 0 to pass the verifier */ + if (aug_size < 0) + aug_size = 0; + + augmented = true; + } else if (size > 0 && size <= value_size) { /* struct */ + if (!bpf_probe_read_user(payload_offset->value, size, arg)) + augmented = true; + } else if ((int)size < 0 && size >= -6) { /* buffer */ + index = -(size + 1); + barrier_var(index); // Prevent clang (noticed with v18) from removing the &= 7 trick. + index &= 7; // Satisfy the bounds checking with the verifier in some kernels. + aug_size = args->args[index] > TRACE_AUG_MAX_BUF ? TRACE_AUG_MAX_BUF : args->args[index]; + + if (aug_size > 0) { + if (!bpf_probe_read_user(payload_offset->value, aug_size, arg)) + augmented = true; + } + } + + /* Augmented data size is limited to sizeof(augmented_arg->unnamed union with value field) */ + if (aug_size > value_size) + aug_size = value_size; + + /* write data to payload */ + if (augmented) { + int written = offsetof(struct augmented_arg, value) + aug_size; + + if (written < 0 || written > sizeof(struct augmented_arg)) + return -1; + + payload_offset->size = aug_size; + return written; + } + + return 0; +} + static int augment_sys_enter(void *ctx, struct syscall_enter_args *args) { - bool augmented, do_output = false; - int zero = 0, index, value_size = sizeof(struct augmented_arg) - offsetof(struct augmented_arg, value); + bool do_output = false; + int zero = 0, written; u64 output = 0; /* has to be u64, otherwise it won't pass the verifier */ - s64 aug_size, size; unsigned int nr, *beauty_map; struct beauty_payload_enter *payload; - void *arg, *payload_offset; + void *payload_offset; /* fall back to do predefined tail call */ if (args == NULL) @@ -457,58 +522,11 @@ static int augment_sys_enter(void *ctx, struct syscall_enter_args *args) /* copy the sys_enter header, which has the syscall_nr */ __builtin_memcpy(&payload->args, args, sizeof(struct syscall_enter_args)); - /* - * Determine what type of argument and how many bytes to read from user space, using the - * value in the beauty_map. This is the relation of parameter type and its corresponding - * value in the beauty map, and how many bytes we read eventually: - * - * string: 1 -> size of string - * struct: size of struct -> size of struct - * buffer: -1 * (index of paired len) -> value of paired len (maximum: TRACE_AUG_MAX_BUF) - */ for (int i = 0; i < 6; i++) { - arg = (void *)args->args[i]; - augmented = false; - size = beauty_map[i]; - aug_size = size; /* size of the augmented data read from user space */ - - if (size == 0 || arg == NULL) - continue; - - if (size == 1) { /* string */ - aug_size = bpf_probe_read_user_str(((struct augmented_arg *)payload_offset)->value, value_size, arg); - /* minimum of 0 to pass the verifier */ - if (aug_size < 0) - aug_size = 0; - - augmented = true; - } else if (size > 0 && size <= value_size) { /* struct */ - if (!bpf_probe_read_user(((struct augmented_arg *)payload_offset)->value, size, arg)) - augmented = true; - } else if ((int)size < 0 && size >= -6) { /* buffer */ - index = -(size + 1); - barrier_var(index); // Prevent clang (noticed with v18) from removing the &= 7 trick. - index &= 7; // Satisfy the bounds checking with the verifier in some kernels. - aug_size = args->args[index] > TRACE_AUG_MAX_BUF ? TRACE_AUG_MAX_BUF : args->args[index]; - - if (aug_size > 0) { - if (!bpf_probe_read_user(((struct augmented_arg *)payload_offset)->value, aug_size, arg)) - augmented = true; - } - } - - /* Augmented data size is limited to sizeof(augmented_arg->unnamed union with value field) */ - if (aug_size > value_size) - aug_size = value_size; - - /* write data to payload */ - if (augmented) { - int written = offsetof(struct augmented_arg, value) + aug_size; - - if (written < 0 || written > sizeof(struct augmented_arg)) - return 1; - - ((struct augmented_arg *)payload_offset)->size = aug_size; + written = augment_arg(args, i, beauty_map, (struct augmented_arg *)payload_offset); + if (written < 0) + return 1; + if (written > 0) { output += written; payload_offset += written; do_output = true; -- cgit v1.2.3 From ea6992784d65ef2c01f3525217dbf3a44afa9917 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 7 Jul 2026 08:52:47 +0200 Subject: perf trace: Refactor augmented_raw_syscalls using bpf_for The loop for processing syscall args in augment_raw_syscalls has a history of breaking with Clang updates, see e.g. commit 013eb043f37b ("perf trace: Fix BPF loading failure (-E2BIG)") from Clang 15 to 16. Now, a similar thing happened between Clang 21 and 22. While the issue is mitigated on the main line by a recent verifier update, it remains broken on the 6.12 and 6.18 stable branches: [linux-6.18.y]# sudo perf trace true libbpf: prog 'sys_enter': BPF program load failed: -E2BIG libbpf: prog 'sys_enter': -- BEGIN PROG LOAD LOG -- [...] BPF program is too large. Processed 1000001 insn processed 1000001 insns (limit 1000000) max_states_per_insn 40 total_states 37941 peak_states 232 mark_read 0 -- END PROG LOAD LOG -- libbpf: prog 'sys_enter': failed to load: -E2BIG libbpf: failed to load object 'augmented_raw_syscalls_bpf' libbpf: failed to load BPF skeleton 'augmented_raw_syscalls_bpf': -E2BIG Error: failed to get syscall or beauty map fd [...] The reason is that the loop is quite complex and the BPF verifier often struggles to prove that it terminates. Fix the issue by replacing the standard for loop with the bpf_for macro, which uses a numeric BPF iterator. This should prevent future breakages of this kind since the verifier has a much easier job proving that the loop terminates. Small adjustments were necessary for the loop to make it work. The main problem is that the verifier sometimes has problems with bpf_for loops that use a carry-over state, such as the `payload_offset` and `output` vars here, since the verifier tries to track their values too precisely and cannot prove loop convergence. To resolve the issue, we (1) explicitly recompute `payload_offset` in every iteration and (2) use a trick with adding a global zero to `output` to help the verifier forget its precise state and use a range instead. Finally, to keep backwards compatibility with older kernel versions that don't have bpf_for (i.e. numeric iterators), fall back to standard loop. Signed-off-by: Viktor Malik Cc: stable@vger.kernel.org Suggested-by: Andrii Nakryiko Fixes: a68fd6a6cdd3 ("perf trace: Collect augmented data using BPF") Signed-off-by: Namhyung Kim --- .../util/bpf_skel/augmented_raw_syscalls.bpf.c | 47 ++++++++++++++++------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c index bc036a348079..3bc9e28a9b8a 100644 --- a/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c +++ b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c @@ -429,6 +429,8 @@ static bool pid_filter__has(struct pids_filtered *pids, pid_t pid) return bpf_map_lookup_elem(pids, &pid) != NULL; } +u64 ZERO = 0; + /* * Determine what type of argument and how many bytes to read from user space, using the * value in the beauty_map. This is the relation of parameter type and its corresponding @@ -440,9 +442,10 @@ static bool pid_filter__has(struct pids_filtered *pids, pid_t pid) */ static inline int augment_arg(struct syscall_enter_args *args, int i, unsigned int *beauty_map, - struct augmented_arg *payload_offset) + struct beauty_payload_enter *payload, u64 offset) { int index, value_size = sizeof(struct augmented_arg) - offsetof(struct augmented_arg, value); + struct augmented_arg *payload_offset; s64 aug_size, size; bool augmented; void *arg; @@ -455,6 +458,12 @@ static inline int augment_arg(struct syscall_enter_args *args, int i, if (size == 0 || arg == NULL) return 0; + /* bounds check for the verifier */ + if (offset > sizeof(payload->aug_args) - sizeof(payload->aug_args[0])) + return -1; + barrier_var(offset); + payload_offset = (struct augmented_arg *)((void *)&payload->aug_args + offset); + if (size == 1) { /* string */ aug_size = bpf_probe_read_user_str(payload_offset->value, value_size, arg); /* minimum of 0 to pass the verifier */ @@ -498,11 +507,10 @@ static inline int augment_arg(struct syscall_enter_args *args, int i, static int augment_sys_enter(void *ctx, struct syscall_enter_args *args) { bool do_output = false; - int zero = 0, written; + int i, zero = 0, written; u64 output = 0; /* has to be u64, otherwise it won't pass the verifier */ unsigned int nr, *beauty_map; struct beauty_payload_enter *payload; - void *payload_offset; /* fall back to do predefined tail call */ if (args == NULL) @@ -514,7 +522,6 @@ static int augment_sys_enter(void *ctx, struct syscall_enter_args *args) /* set up payload for output */ payload = bpf_map_lookup_elem(&beauty_payload_enter_map, &zero); - payload_offset = (void *)&payload->aug_args; if (beauty_map == NULL || payload == NULL) return 1; @@ -522,14 +529,30 @@ static int augment_sys_enter(void *ctx, struct syscall_enter_args *args) /* copy the sys_enter header, which has the syscall_nr */ __builtin_memcpy(&payload->args, args, sizeof(struct syscall_enter_args)); - for (int i = 0; i < 6; i++) { - written = augment_arg(args, i, beauty_map, (struct augmented_arg *)payload_offset); - if (written < 0) - return 1; - if (written > 0) { - output += written; - payload_offset += written; - do_output = true; + if (bpf_ksym_exists(bpf_iter_num_new)) { + bpf_for(i, 0, 6) { + written = augment_arg(args, i, beauty_map, payload, output); + if (written < 0) + return 1; + if (written > 0) { + output += written; + /* + * guide the verifier to forget range of `output`, which + * helps to prove convergence of the loop + */ + output += ZERO; + do_output = true; + } + } + } else { + for (i = 0; i < 6; i++) { + written = augment_arg(args, i, beauty_map, payload, output); + if (written < 0) + return 1; + if (written > 0) { + output += written; + do_output = true; + } } } -- cgit v1.2.3 From e68dc36f8b1f893f2791cb1436d982fde5c2329f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 15 Jul 2026 17:43:36 -0700 Subject: perf build: Fix a compiler error in util/libbfd.c The bfd_boolean type was gone and converted to the standard bool type but we have some old code that uses the type. It caused a failure in the build test. util/libbfd.c: In function 'slurp_symtab': util/libbfd.c:94:9: error: unknown type name 'bfd_boolean' 94 | bfd_boolean dynamic = FALSE; | ^~~~~~~~~~~ util/libbfd.c:94:31: error: 'FALSE' undeclared (first use in this function) 94 | bfd_boolean dynamic = FALSE; | ^~~~~ util/libbfd.c:94:31: note: each undeclared identifier is reported only once for each function it appears in util/libbfd.c:102:27: error: 'TRUE' undeclared (first use in this function) 102 | dynamic = TRUE; | ^~~~ Fix it with standard bool type and constants. Reviewed-by: Ian Rogers Link: https://sourceware.org/pipermail/binutils-cvs/2021-March/056231.html Signed-off-by: Namhyung Kim --- tools/perf/util/libbfd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/libbfd.c b/tools/perf/util/libbfd.c index c1c12308cc12..d8241c7caac5 100644 --- a/tools/perf/util/libbfd.c +++ b/tools/perf/util/libbfd.c @@ -91,7 +91,7 @@ static int slurp_symtab(bfd *abfd, struct a2l_data *a2l) long storage; long symcount; asymbol **syms; - bfd_boolean dynamic = FALSE; + bool dynamic = false; if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0) return bfd_error(bfd_get_filename(abfd)); @@ -99,7 +99,7 @@ static int slurp_symtab(bfd *abfd, struct a2l_data *a2l) storage = bfd_get_symtab_upper_bound(abfd); if (storage == 0L) { storage = bfd_get_dynamic_symtab_upper_bound(abfd); - dynamic = TRUE; + dynamic = true; } if (storage < 0L) return bfd_error(bfd_get_filename(abfd)); -- cgit v1.2.3 From cda907c2c3f992baf0501b2e83845d8a8c9ac02f Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 6 Jul 2026 20:40:18 -0700 Subject: perf jevents: Add python type annotations Make mypy clean. Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/pmu-events/jevents.py | 77 +++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py index e86989c1389d..5c15485d695a 100755 --- a/tools/perf/pmu-events/jevents.py +++ b/tools/perf/pmu-events/jevents.py @@ -14,27 +14,27 @@ import collections # Global command line arguments. _args = None # List of regular event tables. -_event_tables = [] +_event_tables: list[str] = [] # List of event tables generated from "/sys" directories. -_sys_event_tables = [] +_sys_event_tables: list[str] = [] # List of regular metric tables. -_metric_tables = [] +_metric_tables: list[str] = [] # List of metric tables generated from "/sys" directories. -_sys_metric_tables = [] +_sys_metric_tables: list[str] = [] # Mapping between sys event table names and sys metric table names. _sys_event_table_to_metric_table_mapping = {} # Map from an event name to an architecture standard # JsonEvent. Architecture standard events are in json files in the top # f'{_args.starting_dir}/{_args.arch}' directory. -_arch_std_events = {} +_arch_std_events: Dict[str, "JsonEvent"] = {} # Events to write out when the table is closed -_pending_events = [] +_pending_events: list["JsonEvent"] = [] # Name of events table to be written out -_pending_events_tblname = None +_pending_events_tblname: Optional[str] = None # Metrics to write out when the table is closed -_pending_metrics = [] +_pending_metrics: list["JsonEvent"] = [] # Name of metrics table to be written out -_pending_metrics_tblname = None +_pending_metrics_tblname: Optional[str] = None # Global BigCString shared by all structures. _bcs = None # Map from the name of a metric group to a description of the group. @@ -210,7 +210,7 @@ class JsonEvent: """Convert an int to a string similar to a printf modifier of %#llx.""" return str(x) if x >= 0 and x < 10 else hex(x) - def fixdesc(s: str) -> str: + def fixdesc(s: Optional[str]) -> Optional[str]: """Fix formatting issue for the desc string.""" if s is None: return None @@ -218,7 +218,7 @@ class JsonEvent: '. '), '.').replace('\n', '\\n').replace( '\"', '\\"').replace('\r', '\\r') - def convert_aggr_mode(aggr_mode: str) -> Optional[str]: + def convert_aggr_mode(aggr_mode: Optional[str]) -> Optional[str]: """Returns the aggr_mode_class enum value associated with the JSON string.""" if not aggr_mode: return None @@ -228,7 +228,7 @@ class JsonEvent: } return aggr_mode_to_enum[aggr_mode] - def convert_metric_constraint(metric_constraint: str) -> Optional[str]: + def convert_metric_constraint(metric_constraint: Optional[str]) -> Optional[str]: """Returns the metric_event_groups enum value associated with the JSON string.""" if not metric_constraint: return None @@ -241,7 +241,7 @@ class JsonEvent: } return metric_constraint_to_enum[metric_constraint] - def lookup_msr(num: str) -> Optional[str]: + def lookup_msr(num: Optional[str]) -> Optional[str]: """Converts the msr number, or first in a list to the appropriate event field.""" if not num: return None @@ -257,7 +257,7 @@ class JsonEvent: } return msrmap[int(num.split(',', 1)[0], 0)] - def real_event(name: str, event: str) -> Optional[str]: + def real_event(name: Optional[str], event: Optional[str]) -> Optional[str]: """Convert well known event names to an event string otherwise use the event argument.""" fixed = { 'inst_retired.any': 'event=0xc0,period=2000003', @@ -273,7 +273,7 @@ class JsonEvent: return fixed[name.lower()] return event - def unit_to_pmu(unit: str) -> Optional[str]: + def unit_to_pmu(unit: Optional[str]) -> Optional[str]: """Convert a JSON Unit to Linux PMU name.""" if not unit: return 'default_core' @@ -308,21 +308,21 @@ class JsonEvent: return table[unit] if unit in table else f'uncore_{unit.lower()}' def is_zero(val: str) -> bool: - try: - if val.startswith('0x'): - return int(val, 16) == 0 - else: - return int(val) == 0 - except e: - return False + try: + if val.startswith('0x'): + return int(val, 16) == 0 + else: + return int(val) == 0 + except: + return False def canonicalize_value(val: str) -> str: - try: - if val.startswith('0x'): - return llx(int(val, 16)) - return str(int(val)) - except e: - return val + try: + if val.startswith('0x'): + return llx(int(val, 16)) + return str(int(val)) + except: + return val eventcode = 0 if 'EventCode' in jd: @@ -374,7 +374,8 @@ class JsonEvent: if precise and self.desc and '(Precise Event)' not in self.desc: extra_desc += ' (Must be precise)' if precise == '2' else (' (Precise ' 'event)') - event = None + self.event: Optional[str] = None + event: Optional[str] = None if configcode is not None: event = f'config={llx(configcode)}' elif eventidcode is not None: @@ -459,6 +460,7 @@ class JsonEvent: return f'\t/* {s} */\n' if len(s) < 80 else f'\t/* {s[0:80]}... */\n' s = self.build_c_string(metric) + assert _bcs is not None return f'{make_comment(s)}\t{{ { _bcs.offsets[s] } }},\n' @@ -528,6 +530,7 @@ def print_pending_events() -> None: return global _pending_events_tblname + assert _pending_events_tblname is not None if _pending_events_tblname.endswith('_sys'): global _sys_event_tables _sys_event_tables.append(_pending_events_tblname) @@ -538,7 +541,8 @@ def print_pending_events() -> None: first = True last_pmu = None last_name = None - pmus = set() + pmus: Set[Tuple[str, str]] = set() + assert _args is not None for event in sorted(_pending_events, key=event_cmp_key): if last_pmu and last_pmu == event.pmu: assert event.name != last_name, f"Duplicate event: {last_pmu}/{last_name}/ in {_pending_events_tblname}" @@ -580,6 +584,7 @@ def print_pending_metrics() -> None: return '' return s + assert j.metric_expr is not None return (fix_none(j.pmu), fix_none(j.metric_name), j.metric_expr.ToPerfJson(), fix_none(j.desc)) @@ -588,6 +593,7 @@ def print_pending_metrics() -> None: return global _pending_metrics_tblname + assert _pending_metrics_tblname is not None if _pending_metrics_tblname.endswith('_sys'): global _sys_metric_tables _sys_metric_tables.append(_pending_metrics_tblname) @@ -597,7 +603,8 @@ def print_pending_metrics() -> None: first = True last_pmu = None - pmus = set() + pmus: Set[Tuple[str, str]] = set() + assert _args is not None for metric in sorted(_pending_metrics, key=metric_cmp_key): if metric.pmu != last_pmu: if not first: @@ -633,7 +640,6 @@ def get_topic(topic: str) -> str: return removesuffix(topic, '.json').replace('-', ' ') def preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None: - if item.is_dir(): return @@ -647,6 +653,7 @@ def preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None: if not item.is_file() or not item.name.endswith('.json'): return + assert _bcs is not None if item.name.endswith('metricgroups.json'): metricgroup_descriptions = json.load(open(item.path)) for mgroup in metricgroup_descriptions: @@ -708,6 +715,7 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None: def print_mapping_table(archs: Sequence[str]) -> None: """Read the mapfile and generate the struct from cpuid string to event table.""" + assert _args is not None _args.output_file.write(""" /* Struct used to make the PMU event table implementation opaque to callers. */ struct pmu_events_table { @@ -825,6 +833,7 @@ static const struct pmu_events_map pmu_events_map[] = { def print_metric_table_functions() -> None: + assert _args is not None _args.output_file.write(""" const char *pmu_metrics_table__name(const struct pmu_metrics_table *table) { @@ -868,6 +877,7 @@ int pmu_metrics_table__iterate_tables(pmu_metrics_table_iter_t fn, void *data) def print_system_mapping_table() -> None: + assert _args is not None """C struct mapping table array for tables from /sys directories.""" _args.output_file.write(""" struct pmu_sys_events { @@ -1404,6 +1414,7 @@ int pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data) """) def print_metricgroups() -> None: + assert _args is not None _args.output_file.write(""" static const int metricgroups[][2] = { """) @@ -1447,6 +1458,7 @@ def main() -> None: def ftw(path: str, parents: Sequence[str], action: Callable[[Sequence[str], os.DirEntry], None]) -> None: """Replicate the directory/file walking behavior of C's file tree walk.""" + assert _args is not None for item in sorted(os.scandir(path), key=lambda e: e.name): if _args.model != 'all' and item.is_dir(): # Check if the model matches one in _args.model. @@ -1517,6 +1529,7 @@ struct pmu_table_entry { preprocess_arch_std_files(arch_path) ftw(arch_path, [], preprocess_one_file) + assert _bcs is not None _bcs.compute() _args.output_file.write('/* clang-format off */\n') if not _args.output_string_file: -- cgit v1.2.3 From 59355235f29e02eb4d88aa2d0c0d68aca901c929 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 6 Jul 2026 20:40:19 -0700 Subject: perf jevents metric: Add python type annotations Make mypy clean. Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/pmu-events/metric.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tools/perf/pmu-events/metric.py b/tools/perf/pmu-events/metric.py index 11c7162825f4..ce025675898c 100644 --- a/tools/perf/pmu-events/metric.py +++ b/tools/perf/pmu-events/metric.py @@ -276,7 +276,7 @@ class Operator(Expression): lhs = self.lhs.Simplify() rhs = self.rhs.Simplify() if isinstance(lhs, Constant) and isinstance(rhs, Constant): - return Constant(ast.literal_eval(lhs + self.operator + rhs)) + return Constant(ast.literal_eval(lhs.value + self.operator + rhs.value)) if isinstance(self.lhs, Constant): if self.operator in ('+', '|') and lhs.value == '0': @@ -298,7 +298,7 @@ class Operator(Expression): if self.operator == '*' and rhs.value == '0': return Constant(0) - if self.operator == '*' and self.rhs.value == '1': + if self.operator == '*' and rhs.value == '1': return lhs return Operator(self.operator, lhs, rhs) @@ -316,9 +316,7 @@ class Operator(Expression): if self.Equals(expression): return Event(name) lhs = self.lhs.Substitute(name, expression) - rhs = None - if self.rhs: - rhs = self.rhs.Substitute(name, expression) + rhs = self.rhs.Substitute(name, expression) return Operator(self.operator, lhs, rhs) @@ -382,7 +380,9 @@ class Function(Expression): rhs: Optional[Union[int, float, Expression]] = None): self.fn = fn self.lhs = _Constify(lhs) - self.rhs = _Constify(rhs) + self.rhs = None + if rhs is not None: + self.rhs = _Constify(rhs) def ToPerfJson(self): if self.rhs: @@ -407,7 +407,8 @@ class Function(Expression): return Function(self.fn, lhs, rhs) def HasExperimentalEvents(self) -> bool: - return self.lhs.HasExperimentalEvents() or (self.rhs and self.rhs.HasExperimentalEvents()) + return (self.lhs.HasExperimentalEvents() or + (self.rhs is not None and self.rhs.HasExperimentalEvents())) def Equals(self, other: Expression) -> bool: if isinstance(other, Function): @@ -683,7 +684,7 @@ class MetricGroup: def Flatten(self) -> Set[Metric]: """Returns a set of all leaf metrics.""" - result = set() + result: Set[Metric] = set() for x in self.metric_list: result = result.union(x.Flatten()) -- cgit v1.2.3 From 2ec3b985872594031cc1000b830344de5c26633d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 16 Jul 2026 00:23:42 -0700 Subject: perf hists browser: Increase MAX_OPTIONS to prevent stack buffer overflow In evsel__hists_browse(), the 'options' and 'actions' arrays are statically allocated on the stack with a size of MAX_OPTIONS (16). Further down, the function sequentially calls several add_*_opt() functions, which increment nr_options without bounds checking. Depending on the context (e.g., branch mode, scripting, annotations), the sum of added options can theoretically exceed 16 (potentially reaching up to ~19). This could lead to a stack buffer overflow. Increase MAX_OPTIONS to 32 to safely accommodate the maximum possible number of options without risking an overflow. Closes: https://lore.kernel.org/linux-perf-users/20260708235834.3FB771F00A3A@smtp.kernel.org/ Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Ian Rogers Link: https://lore.kernel.org/linux-perf-users/20260708235834.3FB771F00A3A@smtp.kernel.org/ Signed-off-by: Namhyung Kim --- tools/perf/ui/browsers/hists.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index da7cc195b9f4..6163cc3ace27 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -3003,7 +3003,7 @@ static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *h struct hists *hists = evsel__hists(evsel); struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env); struct branch_info *bi = NULL; -#define MAX_OPTIONS 16 +#define MAX_OPTIONS 32 char *options[MAX_OPTIONS]; struct popup_action actions[MAX_OPTIONS]; int nr_options = 0; -- cgit v1.2.3 From d5fdde1c426922efabe86a515f0782b3eba40577 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 16 Jul 2026 00:23:43 -0700 Subject: perf ui hists: Fix uninitialized stack memory free on pstack allocation failure Fixes heap corruption by initializing the options and actions arrays before the pstack allocation check, preventing an uninitialized stack pointer from being passed to free_popup_options() if the allocation fails. Reported-by: sashiko-bot Closes: https://lore.kernel.org/linux-perf-users/20260709035230.6DBEE1F000E9@smtp.kernel.org/ Fixes: f2b487db45f2 ("perf hists browser: Fix possible memory leak") Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Ian Rogers Link: https://lore.kernel.org/linux-perf-users/20260709035230.6DBEE1F000E9@smtp.kernel.org/ Signed-off-by: Namhyung Kim --- tools/perf/ui/browsers/hists.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 6163cc3ace27..319c3d6c0375 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -3064,15 +3064,15 @@ static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *h browser->min_pcnt = min_pcnt; hist_browser__update_nr_entries(browser); + memset(options, 0, sizeof(options)); + memset(actions, 0, sizeof(actions)); + browser->pstack = pstack__new(3); if (browser->pstack == NULL) goto out; ui_helpline__push(helpline); - memset(options, 0, sizeof(options)); - memset(actions, 0, sizeof(actions)); - if (symbol_conf.col_width_list_str) perf_hpp__set_user_width(symbol_conf.col_width_list_str); -- cgit v1.2.3 From c6275783931ddb9d82a2d52e932d4e85bff5f588 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 16 Jul 2026 00:23:44 -0700 Subject: perf ui hists: Include limits.h for PATH_MAX definition Looking at switch_data_file(), it uses the POSIX constant PATH_MAX. Omitting the explicit inclusion of limits.h can cause build failures on musl libc systems, which do not implicitly include headers in the same way glibc does. Fix this by explicitly including at the top of tools/perf/ui/browsers/hists.c. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/ui/browsers/hists.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 319c3d6c0375..9a3844dc3246 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 1243a5e741a4f93312a2da16929bb66edb5d5b25 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 16 Jul 2026 00:23:46 -0700 Subject: perf disasm: Fix potential NULL pointer dereference and use-after-free in arch__find() In arch__find(), if the architecture's arch_new_fn[e_machine]() returns NULL, the error handling path attempts to read result->name, dereferencing a NULL pointer and crashing. At the same time, it invokes free(tmp) BEFORE updating the static global archs pointer to tmp. If the reallocarray() call moved the allocated block, the original archs pointer remained active but was freed. A subsequent call to arch__find() would then pass this dangling pointer into bsearch(), causing a use-after-free. Fix both by printing the numeric e_machine ID instead of result->name, and updating the static global archs pointer to tmp immediately after the successful reallocarray() invocation to safely retain the valid prior architectures. Closes: https://lore.kernel.org/linux-perf-users/20260709035721.9EE901F000E9@smtp.kernel.org/ Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/util/disasm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index 0a1a7e9cf3ef..6cfdbabbb8c7 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -180,14 +180,14 @@ const struct arch *arch__find(uint16_t e_machine, uint32_t e_flags, const char * if (!tmp) return NULL; + archs = tmp; + result = arch_new_fn[e_machine](&key, cpuid); if (!result) { - pr_err("%s: failed to initialize %s (%u) arch priv area\n", - __func__, result->name, e_machine); - free(tmp); + pr_err("%s: failed to initialize %u arch priv area\n", + __func__, e_machine); return NULL; } - archs = tmp; archs[num_archs++] = result; qsort(archs, num_archs, sizeof(*archs), arch__cmp); return result; -- cgit v1.2.3 From 5bc1647216b68c17d03665739ea18bba8447f3ce Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 16 Jul 2026 00:23:47 -0700 Subject: perf ui hists: Fix NULL pointer array gap in add_script_opt() In add_script_opt(), the function unconditionally increments the optstr and act pointers for a second optional 'time' popup action before attempting to invoke add_script_opt_2(). If the first add_script_opt_2() call failed (for example, due to an asprintf allocation failure), this leaves a NULL pointer gap in the options array at the prior index. When ui__popup_menu() is later displayed, it dereferences this gap and crashes. Fix it by avoiding unconditional pointer increments. Only advance the optstr and act pointers if the first script addition actually succeeded, and safely attach the time parameter to the correct assigned action. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/ui/browsers/hists.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 9a3844dc3246..b6002724bc3a 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2811,7 +2811,7 @@ add_script_opt(struct hist_browser *browser, struct popup_action *act, char **optstr, struct thread *thread, struct symbol *sym) { - int n, j; + int n, j, ret; struct hist_entry *he; n = add_script_opt_2(act, optstr, thread, sym, ""); @@ -2819,17 +2819,24 @@ add_script_opt(struct hist_browser *browser, he = hist_browser__selected_entry(browser); if (sort_order && strstr(sort_order, "time")) { char tstr[128]; + struct popup_action *time_act = act; + char **time_optstr = optstr; - optstr++; - act++; + if (n > 0) { + time_optstr++; + time_act++; + } j = sprintf(tstr, " in "); j += timestamp__scnprintf_usec(he->time, tstr + j, sizeof tstr - j); j += sprintf(tstr + j, "-"); timestamp__scnprintf_usec(he->time + symbol_conf.time_quantum, tstr + j, sizeof tstr - j); - n += add_script_opt_2(act, optstr, thread, sym, tstr); - act->time = he->time; + ret = add_script_opt_2(time_act, time_optstr, thread, sym, tstr); + if (ret > 0) { + time_act->time = he->time; + n += ret; + } } return n; } -- cgit v1.2.3 From e01c7bd5b1eece254bcbf282db066b12c4815d21 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 6 Jul 2026 16:48:35 -0700 Subject: perf build: Fix compiler errors with old capstone It seems RISCV was added in capstone version 5 (released Jul 2023). Unfortunately they are enum constants so cannot check with #ifdef but anyway we can define the symbols. Let's do it using the version number to avoid build errors. It'll fail at runtime though. util/capstone.c: In function 'e_machine_to_capstone': util/capstone.c:186:25: error: 'CS_ARCH_RISCV' undeclared (first use in this function); did you mean 'CS_ARCH_SYSZ'? 186 | *arch = CS_ARCH_RISCV; | ^~~~~~~~~~~~~ | CS_ARCH_SYSZ util/capstone.c:186:25: note: each undeclared identifier is reported only once for each function it appears in util/capstone.c:187:34: error: 'CS_MODE_RISCV64' undeclared (first use in this function); did you mean 'CS_MODE_MIPS64'? 187 | *mode |= (is64 ? CS_MODE_RISCV64 : CS_MODE_RISCV32) | CS_MODE_RISCVC; | ^~~~~~~~~~~~~~~ | CS_MODE_MIPS64 Also note that capstone renamed CS_MODE_RISCVC to CS_MODE_RISCV_C which would cause a different build failure on latest versions. It's reported in https://github.com/capstone-engine/capstone/issues/2977 so I think they will add compatibility layer to prevent the error. Fixes: 12c4737f55f2 ("perf capstone: Determine architecture from e_machine") Signed-off-by: Namhyung Kim --- tools/perf/util/capstone.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c index 9bba78ee0c5a..00e0141cae8d 100644 --- a/tools/perf/util/capstone.c +++ b/tools/perf/util/capstone.c @@ -24,6 +24,13 @@ #include "symbol.h" #include "thread.h" +#if CS_VERSION_MAJOR < 5 +#define CS_ARCH_RISCV 15 +#define CS_MODE_RISCV32 1 +#define CS_MODE_RISCV64 2 +#define CS_MODE_RISCVC 4 +#endif + #ifdef LIBCAPSTONE_DLOPEN static void *perf_cs_dll_handle(void) { -- cgit v1.2.3 From 64724095a33fbee805657415a4eb374bef5161c9 Mon Sep 17 00:00:00 2001 From: Aaron Tomlin Date: Sat, 18 Jul 2026 21:38:00 -0400 Subject: perf stat: Add --hide-zero-events option to suppress zero-count events When monitoring a large number of events (e.g., with wildcards such as --event 'syscalls:sys_enter_*'), many matched events will return a count of zero. This clutters the output, making it difficult to spot the active events. Add a new option --hide-zero-events to suppress printing events that have a count of zero. To prevent formatting and diagnostic issues, the zero-skipping logic implements the following rules: 1. In metric-only mode (i.e., --metric-only), columns must remain aligned in the output grid. We evaluate config->metric_only first to avoid skipping zero-valued columns, preventing values from shifting left and aligning under incorrect headers 2. For explicitly requested events, we ensure they are not silently hidden if they are unsupported. We only hide a zero-count event if counter->supported is true, ensuring that unsupported explicit events still report "" Signed-off-by: Aaron Tomlin Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/Documentation/perf-stat.txt | 3 +++ tools/perf/builtin-stat.c | 2 ++ tools/perf/tests/shell/stat.sh | 46 ++++++++++++++++++++++++++++++++++ tools/perf/util/stat-display.c | 3 +++ tools/perf/util/stat.h | 1 + 5 files changed, 55 insertions(+) diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index b72a29c9223c..f334aabdc809 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -162,6 +162,9 @@ null run - Don't start any counters. This can be useful to measure just elapsed wall-clock time - or to assess the raw overhead of perf stat itself, without running any counters. +--hide-zero-events:: +Do not show events with a zero count. + -v:: --verbose:: be more verbose (show counter open errors, etc) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a85a4f30221a..d68a2617a920 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -2505,6 +2505,8 @@ int cmd_stat(int argc, const char **argv) "display details about each run (only with -r option)"), OPT_BOOLEAN('n', "null", &stat_config.null_run, "null run - dont start any counters"), + OPT_BOOLEAN(0, "hide-zero-events", &stat_config.hide_zero, + "Do not show events with a zero count"), OPT_INCR('d', "detailed", &detailed_run, "detailed run - start a lot of events"), OPT_BOOLEAN('S', "sync", &sync_run, diff --git a/tools/perf/tests/shell/stat.sh b/tools/perf/tests/shell/stat.sh index 649de1166fed..298ce454b45a 100755 --- a/tools/perf/tests/shell/stat.sh +++ b/tools/perf/tests/shell/stat.sh @@ -546,6 +546,51 @@ test_csv_json_fail() { fi } +test_hide_zero_events_stat() { + echo "Hide zero events stat test" + if ! perf stat -e context-switches,cpu-migrations true > "${stat_output}" 2>&1 + then + echo "Hide zero events stat test [Skipped event parsing failed]" + return + fi + + zero_event="" + if grep -q -E "[[:space:]]+0[[:space:]]+context-switches" "${stat_output}"; then + zero_event="context-switches" + elif grep -q -E "[[:space:]]+0[[:space:]]+cpu-migrations" "${stat_output}"; then + zero_event="cpu-migrations" + fi + + if [ -z "$zero_event" ]; then + echo "Hide zero events stat test [Skipped - no zero count event found]" + return + fi + + if ! perf stat --hide-zero-events -e context-switches,cpu-migrations true > "${stat_output}" 2>&1 + then + echo "Hide zero events stat test [Failed - command failed]" + err=1 + return + fi + + if grep -q -E "$zero_event" "${stat_output}" + then + echo "Hide zero events stat test [Failed - zero event $zero_event was not hidden]" + err=1 + return + fi + + # Check that --metric-only works with --hide-zero-events + if ! perf stat --hide-zero-events --metric-only -e instructions,cycles true > "${stat_output}" 2>&1 + then + echo "Hide zero events stat test [Failed - metric-only command failed]" + err=1 + return + fi + + echo "Hide zero events stat test [Success]" +} + test_default_stat test_null_stat test_offline_cpu_stat @@ -563,6 +608,7 @@ test_stat_repeat test_stat_pid test_stat_delay test_csv_json_fail +test_hide_zero_events_stat cleanup exit $err diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c index f94f1324d24a..b337cc23f413 100644 --- a/tools/perf/util/stat-display.c +++ b/tools/perf/util/stat-display.c @@ -907,6 +907,9 @@ static bool should_skip_zero_counter(struct perf_stat_config *config, /* Metric only counts won't be displayed but the metric wants to be computed. */ if (config->metric_only) return false; + + if (config->hide_zero && counter->supported) + return true; /* * Skip value 0 when enabling --per-thread globally, * otherwise it will have too many 0 output. diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 4bced233d2fc..e3598037a6aa 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -69,6 +69,7 @@ struct perf_stat_config { bool interval_clear; bool metric_only; bool null_run; + bool hide_zero; bool ru_display; bool big_num; bool hybrid_merge; -- cgit v1.2.3 From ec99be8a31db999a4f866be74ea7db61dbb19f24 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Mon, 20 Jul 2026 11:01:21 +0100 Subject: perf cs-etm: Avoid truncating AUX buffer sizes to int cs_etm__get_trace() returns an int, but it used to return etmq->buf_len on success. That value comes from auxtrace_buffer::size, which is a size_t. For a large AUX trace block, returning the byte count through an int can overflow and make a valid buffer look like a negative error. The callers do not need the actual byte count from cs_etm__get_trace(). The buffer length is already stored in the etmq->buf_len. The callers only need to distinguish three states: < 0: error = 0: no more AUX buffers > 0: data is available Make cs_etm__get_trace() return 0 for all non-error cases and use etmq->buf_len to indicate whether a new buffer was found. Then make cs_etm__get_data_block() return 1 whenever data is available, instead of returning the buffer length. Also refactor cs_etm__get_data_block() to make its return value semantics clearer. Reported-by: Suyash Mahar Fixes: 8224531cf5a1 ("perf cs-etm: Modularize auxtrace_buffer fetch function") Signed-off-by: Leo Yan Reviewed-by: James Clark Signed-off-by: Namhyung Kim --- tools/perf/util/cs-etm.c | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 95e3ec1171ac..114b3cd2da49 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -1467,8 +1467,7 @@ cs_etm__get_trace(struct cs_etm_queue *etmq) etmq->buf_used = 0; etmq->buf_len = aux_buffer->size; etmq->buf = aux_buffer->data; - - return etmq->buf_len; + return 0; } /* @@ -2151,26 +2150,33 @@ static int cs_etm__get_data_block(struct cs_etm_queue *etmq) { int ret; - if (!etmq->buf_len) { - ret = cs_etm__get_trace(etmq); - if (ret <= 0) - return ret; - /* - * We cannot assume consecutive blocks in the data file - * are contiguous, reset the decoder to force re-sync. - */ - ret = cs_etm_decoder__reset(etmq->decoder); - if (ret) - return ret; + /* The current block is not finished */ + if (etmq->buf_len) + return 1; - /* - * Since the decoder is reset, this causes a global trace - * discontinuity. Flush all thread stacks. - */ - cs_etm__flush_all_stack(etmq); - } + ret = cs_etm__get_trace(etmq); + if (ret < 0) + return ret; + + /* No more buffer to read */ + if (!etmq->buf_len) + return 0; + + /* + * We cannot assume consecutive blocks in the data file + * are contiguous, reset the decoder to force re-sync. + */ + ret = cs_etm_decoder__reset(etmq->decoder); + if (ret) + return ret; + + /* + * Since the decoder is reset, this causes a global trace + * discontinuity. Flush all thread stacks. + */ + cs_etm__flush_all_stack(etmq); - return etmq->buf_len; + return 1; } static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, -- cgit v1.2.3 From 87ec3437f37b9fe44c524ba967cb12e78de06f15 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 22 Jul 2026 22:06:40 -0700 Subject: perf cap: Remove used_root parameter and simplify capability checks Refactor perf_cap__capable() to completely remove the used_root out-parameter as requested by the maintainer. Relying on an explicit used_root boolean poisoned sequential capability checks (e.g. failing CAP_SYS_ADMIN checks poisoning the flag for subsequent CAP_PERFMON evaluations for unprivileged users) and created redundant complexity across check_ftrace_capable(), symbol__read_kptr_restrict(), and perf_event_paranoid_check(). Streamline the capability API to perform a pure true/false boolean evaluation. The function checks the Effective set using SYS_capget; if the syscall is missing or fails on legacy kernels, it cleanly falls back to checking EUID == 0. This perfectly preserves modern capability-aware host sessions, guarantees transparent fallback for older kernels, and correctly rejects privileged operations for containerized root processes that have explicitly dropped their capability bounding and permitted sets. Fixes: e25ebda78e23 ("perf cap: Tidy up and improve capability testing") Suggested-by: Namhyung Kim Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/builtin-ftrace.c | 13 +++---------- tools/perf/util/bpf-filter.c | 22 +++++++++------------- tools/perf/util/cap.c | 4 +--- tools/perf/util/cap.h | 3 +-- tools/perf/util/symbol.c | 3 +-- tools/perf/util/util.c | 12 +++--------- 6 files changed, 18 insertions(+), 39 deletions(-) diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index 9e4c5220d43c..f7126196b092 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -72,18 +72,11 @@ static void ftrace__workload_exec_failed_signal(int signo __maybe_unused, static bool check_ftrace_capable(void) { - bool used_root; - - if (perf_cap__capable(CAP_PERFMON, &used_root)) - return true; - - if (!used_root && perf_cap__capable(CAP_SYS_ADMIN, &used_root)) + if (perf_cap__capable(CAP_PERFMON) || + perf_cap__capable(CAP_SYS_ADMIN)) return true; - pr_err("ftrace only works for %s!\n", - used_root ? "root" - : "users with the CAP_PERFMON or CAP_SYS_ADMIN capability" - ); + pr_err("ftrace only works for users with the CAP_PERFMON or CAP_SYS_ADMIN capability!\n"); return false; } diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c index 1a2e7b388d57..bcd81084e342 100644 --- a/tools/perf/util/bpf-filter.c +++ b/tools/perf/util/bpf-filter.c @@ -629,24 +629,20 @@ struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(enum perf_bpf_filter_term static bool check_bpf_filter_capable(void) { - bool used_root; + int fd; - if (perf_cap__capable(CAP_BPF, &used_root)) + if (perf_cap__capable(CAP_BPF)) return true; - if (!used_root) { - /* Check if root already pinned the filter programs and maps */ - int fd = get_pinned_fd("filters"); - - if (fd >= 0) { - close(fd); - return true; - } + /* Check if root already pinned the filter programs and maps */ + fd = get_pinned_fd("filters"); + if (fd >= 0) { + close(fd); + return true; } - pr_err("Error: BPF filter only works for %s!\n" - "\tPlease run 'perf record --setup-filter pin' as root first.\n", - used_root ? "root" : "users with the CAP_BPF capability"); + pr_err("Error: BPF filter only works for users with the CAP_BPF capability!\n" + "\tPlease run 'perf record --setup-filter pin' as root first.\n"); return false; } diff --git a/tools/perf/util/cap.c b/tools/perf/util/cap.c index ac6d1d9a523d..272bd8255ff1 100644 --- a/tools/perf/util/cap.c +++ b/tools/perf/util/cap.c @@ -12,7 +12,7 @@ #define MAX_LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_3 -bool perf_cap__capable(int cap, bool *used_root) +bool perf_cap__capable(int cap) { struct __user_cap_header_struct header = { .version = _LINUX_CAPABILITY_VERSION_3, @@ -21,7 +21,6 @@ bool perf_cap__capable(int cap, bool *used_root) struct __user_cap_data_struct data[MAX_LINUX_CAPABILITY_U32S] = {}; __u32 cap_val; - *used_root = false; while (syscall(SYS_capget, &header, &data[0]) == -1) { /* Retry, first attempt has set the header.version correctly. */ if (errno == EINVAL && header.version != _LINUX_CAPABILITY_VERSION_3 && @@ -29,7 +28,6 @@ bool perf_cap__capable(int cap, bool *used_root) continue; pr_debug2("capget syscall failed (%m) fall back on root check\n"); - *used_root = true; return geteuid() == 0; } diff --git a/tools/perf/util/cap.h b/tools/perf/util/cap.h index c1b8ac033ccc..bf09fb20c779 100644 --- a/tools/perf/util/cap.h +++ b/tools/perf/util/cap.h @@ -18,7 +18,6 @@ #define CAP_BPF 39 #endif -/* Query if a capability is supported, used_root is set if the fallback root check was used. */ -bool perf_cap__capable(int cap, bool *used_root); +bool perf_cap__capable(int cap); #endif /* __PERF_CAP_H */ diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index a562702b4841..94f9c8faedda 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -2452,8 +2452,7 @@ static bool symbol__read_kptr_restrict(void) { bool value = false; FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); - bool used_root; - bool cap_syslog = perf_cap__capable(CAP_SYSLOG, &used_root); + bool cap_syslog = perf_cap__capable(CAP_SYSLOG); if (fp != NULL) { char line[8]; diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 2c2a5c449ffd..8f7cd32f524d 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -378,15 +378,9 @@ int perf_event_paranoid(void) bool perf_event_paranoid_check(int max_level) { - bool used_root; - - if (perf_cap__capable(CAP_SYS_ADMIN, &used_root)) - return true; - - if (!used_root && perf_cap__capable(CAP_PERFMON, &used_root)) - return true; - - return perf_event_paranoid() <= max_level; + return perf_cap__capable(CAP_SYS_ADMIN) || + perf_cap__capable(CAP_PERFMON) || + perf_event_paranoid() <= max_level; } int perf_tip(char **strp, const char *dirpath) -- cgit v1.2.3 From 1fa8d81be1ebaf0393a5141c48916f335e26f2f2 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 23 Jul 2026 10:27:09 -0700 Subject: perf python: Clean up and restructure setup.py Clean up and restructure the python setup script to resolve pylint warnings, improve code quality, and increase robustness and readability, targeting Python 3.9+ (the Linux kernel build minimum Python version). Changes: - Restructure the script to use a `main()` function as the entry point, leaving only imports, classes, and pure functions at module level. - Eliminate all global/module-level variables, making them local to `main()` or the respective classes/functions. - Make `clang_has_option` a pure function by passing all necessary parameters explicitly. - Extract clang compiler flag filtering into a new `filter_clang_options` helper function. This function uses a loop over a tuple of options, replacing ~30 lines of repetitive blocks and reducing branch/statement complexity in the main flow. - Cleanly define attributes in `__init__` for `BuildExt` and `InstallLib` and read environment variables dynamically within the methods (including `srctree` in `InstallLib.run`), removing their dependency on global variables. - Replace legacy Popen with subprocess.run for safer process handling. - Use quote-aware flag filtering (`shlex.split`, filter, `shlex.join`) on sysconfig CFLAGS and OPT instead of regex `re.sub` substitutions. This avoids boundary bugs and safely handles quoted arguments and options with values. - Rely on setuptools to handle user CFLAGS from the environment directly rather than manually prepending them to extra_compile_args. - Safely parse `CC` env var using `shlex.split` to handle quotes and pass compiler arguments as `list[str]` lists to helper functions, avoiding redundant string formatting and parsing. - Remove unused `import re`. - Rename setuptools command subclasses to PascalCase (BuildExt, InstallLib). - Add type annotations to functions and methods. - Add missing docstrings for module, functions, and classes. - Split long lines to adhere to standard limits. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/util/setup.py | 256 +++++++++++++++++++++++++++++++---------------- 1 file changed, 169 insertions(+), 87 deletions(-) diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index cb14554454a2..8380980ade4c 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py @@ -1,112 +1,194 @@ -from os import getenv, path -from subprocess import Popen, PIPE -from re import sub +# SPDX-License-Identifier: GPL-2.0 +"""Setup script for perf python extension. + +This script is used to build and install the perf python binding. +It handles compiler-specific flags, especially for clang, and configures +the setuptools Extension. +""" + +import os import shlex import shutil +import subprocess +import sysconfig -cc = getenv("CC") -assert cc, "Environment variable CC not set" +from setuptools import setup, Extension +from setuptools.command.build_ext import build_ext as _build_ext +from setuptools.command.install_lib import install_lib as _install_lib -# Check if CC has options, as is the case in yocto, where it uses CC="cc --sysroot..." -cc_tokens = cc.split() -if len(cc_tokens) > 1: - cc = cc_tokens[0] - cc_options = " ".join([str(e) for e in cc_tokens[1:]]) + " " -else: - cc_options = "" -# ignore optional stderr could be None as it is set to PIPE to avoid that. -# mypy: disable-error-code="union-attr" -cc_is_clang = b"clang version" in Popen([cc, "-v"], stderr=PIPE).stderr.readline() +def clang_has_option(cc: str, cc_args: list[str], src_feature_tests: str, option: str) -> bool: + """Check if clang supports a specific option. -srctree = getenv('srctree') -assert srctree, "Environment variable srctree, for the Linux sources, not set" -src_feature_tests = f'{srctree}/tools/build/feature' + Args: + cc: The compiler executable. + cc_args: Compiler arguments from CC environment variable. + src_feature_tests: Path to the feature tests directory. + option: The compiler option to check (e.g., "-mcet"). -def clang_has_option(option): + Returns: + True if the option is supported, False otherwise. + """ error_substrings = ( b"unknown argument", b"is not supported", b"unknown warning option" ) - cmd = shlex.split(f"{cc} {cc_options} {option}") + [ + cmd = [cc] + cc_args + [ + option, "-o", "/dev/null", - path.join(src_feature_tests, "test-hello.c") + os.path.join(src_feature_tests, "test-hello.c") ] - cc_output = Popen(cmd, stderr=PIPE).stderr.readlines() + try: + res = subprocess.run(cmd, stderr=subprocess.PIPE, stdout=subprocess.DEVNULL, check=False) + cc_output = res.stderr.splitlines() + except OSError: + return False return not any(any(error in line for error in error_substrings) for line in cc_output) -if cc_is_clang: - from sysconfig import get_config_vars - vars = get_config_vars() + +def filter_clang_options(cc: str, cc_args: list[str], src_feature_tests: str) -> None: + """Filter out unsupported clang options from sysconfig CFLAGS and OPT. + + Args: + cc: The compiler executable. + cc_args: Compiler arguments from CC environment variable. + src_feature_tests: Path to the feature tests directory. + """ + config_vars = sysconfig.get_config_vars() for var in ('CFLAGS', 'OPT'): - vars[var] = sub("-specs=[^ ]+", "", vars[var]) - if not clang_has_option("-mcet"): - vars[var] = sub("-mcet", "", vars[var]) - if not clang_has_option("-fcf-protection"): - vars[var] = sub("-fcf-protection", "", vars[var]) - if not clang_has_option("-fstack-clash-protection"): - vars[var] = sub("-fstack-clash-protection", "", vars[var]) - if not clang_has_option("-fstack-protector-strong"): - vars[var] = sub("-fstack-protector-strong", "", vars[var]) - if not clang_has_option("-fno-semantic-interposition"): - vars[var] = sub("-fno-semantic-interposition", "", vars[var]) - if not clang_has_option("-ffat-lto-objects"): - vars[var] = sub("-ffat-lto-objects", "", vars[var]) - if not clang_has_option("-ftree-loop-distribute-patterns"): - vars[var] = sub("-ftree-loop-distribute-patterns", "", vars[var]) - if not clang_has_option("-gno-variable-location-views"): - vars[var] = sub("-gno-variable-location-views", "", vars[var]) + if var not in config_vars: + continue + + # Split into individual flags using shlex to preserve quoted arguments + flags = shlex.split(config_vars[var]) + + # Remove -specs=... + flags = [f for f in flags if not f.startswith("-specs=")] + + options = ( + "-mcet", + "-fcf-protection", + "-fstack-clash-protection", + "-fstack-protector-strong", + "-fno-semantic-interposition", + "-ffat-lto-objects", + "-ftree-loop-distribute-patterns", + "-gno-variable-location-views" + ) + for option in options: + if not clang_has_option(cc, cc_args, src_feature_tests, option): + # Remove the option and any variant (e.g. -option=...) + flags = [f for f in flags if not f.startswith(option)] + + # Re-join flags preserving quoting + config_vars[var] = shlex.join(flags) + + +class BuildExt(_build_ext): + """Custom build_ext command to set output directories.""" + + def __init__(self, *args, **kwargs): + self.build_lib = None + self.build_temp = None + super().__init__(*args, **kwargs) + + def finalize_options(self) -> None: + _build_ext.finalize_options(self) + build_lib = os.getenv('PYTHON_EXTBUILD_LIB') + build_tmp = os.getenv('PYTHON_EXTBUILD_TMP') + if build_lib: + self.build_lib = build_lib + if build_tmp: + self.build_temp = build_tmp -from setuptools import setup, Extension -from setuptools.command.build_ext import build_ext as _build_ext -from setuptools.command.install_lib import install_lib as _install_lib +class InstallLib(_install_lib): + """Custom install_lib command to set output directory.""" -class build_ext(_build_ext): - def finalize_options(self): - _build_ext.finalize_options(self) - self.build_lib = build_lib - self.build_temp = build_tmp + def __init__(self, *args, **kwargs): + self.build_dir = None + super().__init__(*args, **kwargs) -class install_lib(_install_lib): - def finalize_options(self): + def finalize_options(self) -> None: _install_lib.finalize_options(self) - self.build_dir = build_lib + build_lib = os.getenv('PYTHON_EXTBUILD_LIB') + if build_lib: + self.build_dir = build_lib def run(self): _install_lib.run(self) - shutil.copy2(f'{src_perf}/python/perf.pyi', self.install_dir) - - -# switch off several checks (need to be at the end of cflags list) -extra_cflags = ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter', '-Wno-redundant-decls' ] -if cc_is_clang: - extra_cflags += ["-Wno-unused-command-line-argument" ] - if clang_has_option("-Wno-cast-function-type-mismatch"): - extra_cflags += ["-Wno-cast-function-type-mismatch" ] -else: - extra_cflags += ['-Wno-cast-function-type' ] - -# The python headers have mixed code with declarations (decls after asserts, for instance) -extra_cflags += [ "-Wno-declaration-after-statement" ] - -src_perf = f'{srctree}/tools/perf' -build_lib = getenv('PYTHON_EXTBUILD_LIB') -build_tmp = getenv('PYTHON_EXTBUILD_TMP') - -perf = Extension('perf', - sources = [ src_perf + '/util/python.c' ], - include_dirs = ['util/include'], - extra_compile_args = extra_cflags, - ) - -setup(name='perf', - version='0.1', - description='Interface with the Linux profiling infrastructure', - author='Arnaldo Carvalho de Melo', - author_email='acme@redhat.com', - license='GPLv2', - url='http://perf.wiki.kernel.org', - ext_modules=[perf], - cmdclass={'build_ext': build_ext, 'install_lib': install_lib}) + srctree = os.getenv('srctree', '.') + src_perf = os.path.join(srctree, 'tools/perf') + shutil.copy2(os.path.join(src_perf, 'python/perf.pyi'), self.install_dir) + + +def main() -> None: + """Main entry point for the setup script.""" + cc_env = os.getenv("CC") + assert cc_env, "Environment variable CC not set" + + # Safe parsing of CC environment variable which might contain options/quotes + cc_tokens = shlex.split(cc_env) + cc = cc_tokens[0] + cc_args = cc_tokens[1:] + + # Run CC -v to check if it is clang. + try: + cc_info = subprocess.run( + [cc, "-v"], stderr=subprocess.PIPE, stdout=subprocess.DEVNULL, check=False + ) + cc_is_clang = b"clang version" in cc_info.stderr + except OSError as e: + raise RuntimeError(f"Failed to execute compiler '{cc}': {e}") from e + + srctree = os.getenv('srctree') + assert srctree, "Environment variable srctree, for the Linux sources, not set" + src_feature_tests = f'{srctree}/tools/build/feature' + + if cc_is_clang: + filter_clang_options(cc, cc_args, src_feature_tests) + + # switch off several checks (need to be at the end of cflags list) + cflags = [ + '-fno-strict-aliasing', + '-Wno-write-strings', + '-Wno-unused-parameter', + '-Wno-redundant-decls' + ] + if cc_is_clang: + cflags += ["-Wno-unused-command-line-argument"] + if clang_has_option( + cc, cc_args, src_feature_tests, "-Wno-cast-function-type-mismatch" + ): + cflags += ["-Wno-cast-function-type-mismatch"] + else: + cflags += ['-Wno-cast-function-type'] + + # The python headers have mixed code with declarations (decls after asserts, for instance) + cflags += ["-Wno-declaration-after-statement"] + + src_perf = f'{srctree}/tools/perf' + + perf = Extension( + 'perf', + sources=[os.path.join(src_perf, 'util/python.c')], + include_dirs=['util/include'], + extra_compile_args=cflags, + ) + + setup( + name='perf', + version='0.1', + description='Interface with the Linux profiling infrastructure', + author='Arnaldo Carvalho de Melo', + author_email='acme@redhat.com', + license='GPLv2', + url='http://perf.wiki.kernel.org', + ext_modules=[perf], + cmdclass={'build_ext': BuildExt, 'install_lib': InstallLib}, + ) + + +if __name__ == '__main__': + main() -- cgit v1.2.3 From eaab2eb09dc2f86f41e8fa55243c31a274978233 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 22 Jul 2026 10:31:38 -0700 Subject: perf pmu-events: Parallelize JSON and metric pre-computation in jevents.py Currently, jevents.py parses hundreds of JSON event and metric files sequentially across all CPU architectures during Kbuild startup, taking ~3.5 seconds of single-core execution time. Refactor jevents.py to pre-populate its internal JSON AST cache in parallel across all available CPU cores using ProcessPoolExecutor. First gather all the paths with ftw and collect_json, then spawn _parallel_read_json_events that starts workers to just read the json events. Define the worker process initializer _init_worker so that _arch_std_events is available under spawn multiprocessing semantics. This accelerates the JSON parsing phase by over 10x (from ~3.0s down to ~290ms), reducing overall jevents.py execution time by 3.5x (from ~3.56s down to ~1.03s). Tested-by: James Clark Assisted-by: Gemini:gemini-3.1-pro-preview Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/pmu-events/jevents.py | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py index 5c15485d695a..860027bb71b2 100755 --- a/tools/perf/pmu-events/jevents.py +++ b/tools/perf/pmu-events/jevents.py @@ -464,8 +464,8 @@ class JsonEvent: return f'{make_comment(s)}\t{{ { _bcs.offsets[s] } }},\n' -@lru_cache(maxsize=None) -def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]: +_json_cache = {} +def _read_json_events_impl(path: str, topic: str) -> Sequence[JsonEvent]: """Read json events from the specified file.""" try: events = json.load(open(path), object_hook=JsonEvent) @@ -481,12 +481,16 @@ def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]: if updates: for event in events: if event.metric_name in updates: - # print(f'Updated {event.metric_name} from\n"{event.metric_expr}"\n' - # f'to\n"{updates[event.metric_name]}"') event.metric_expr = updates[event.metric_name] return events +def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]: + key = (path, topic) + if key not in _json_cache: + _json_cache[key] = _read_json_events_impl(path, topic) + return _json_cache[key] + def preprocess_arch_std_files(archpath: str) -> None: """Read in all architecture standard events.""" global _arch_std_events @@ -1446,6 +1450,14 @@ const char *describe_metricgroup(const char *group) } """) +def _parallel_read_json_events(task: Tuple[str, str]) -> Tuple[str, str, Sequence[JsonEvent]]: + path, topic = task + return path, topic, _read_json_events_impl(path, topic) + +def _init_worker(std_events: dict) -> None: + global _arch_std_events + _arch_std_events = std_events + def main() -> None: global _args @@ -1524,9 +1536,25 @@ struct pmu_table_entry { raise IOError(f'Missing architecture directory \'{_args.arch}\'') archs.sort() + import concurrent.futures + tasks = [] + def collect_json(parents: Sequence[str], item: os.DirEntry) -> None: + if len(parents) == 0: + return + if item.is_file() and item.name.endswith('.json') and not item.name.endswith('metricgroups.json'): + tasks.append((item.path, get_topic(item.name))) + for arch in archs: arch_path = f'{_args.starting_dir}/{arch}' preprocess_arch_std_files(arch_path) + ftw(arch_path, [], collect_json) + + with concurrent.futures.ProcessPoolExecutor(initializer=_init_worker, initargs=(_arch_std_events,)) as executor: + for path, topic, events in executor.map(_parallel_read_json_events, tasks): + _json_cache[(path, topic)] = events + + for arch in archs: + arch_path = f'{_args.starting_dir}/{arch}' ftw(arch_path, [], preprocess_one_file) assert _bcs is not None -- cgit v1.2.3 From 89493fe58c81db19efc16ec220e6fce512ec1cf7 Mon Sep 17 00:00:00 2001 From: Aaron Tomlin Date: Wed, 22 Jul 2026 11:50:48 -0400 Subject: perf trace: Correct default cpumask formatting to hexadecimal Currently, dynamic non-array fields such as 'cpumask_t' are mishandled in 'perf trace', causing the raw length and offset descriptors to be interpreted and displayed as a literal integer (e.g., "cpumask: 524320" instead of the actual mask data). Correct the parsing of dynamic fields that do not have the TEP_FIELD_IS_ARRAY flag set by introducing helper functions format_field__get_raw_data() and format_field__get_cpumask(). Using these helpers, resolve the pointer to the raw bits within the payload and format the cpumask as a zero-padded hexadecimal string by default. Fixes: c5e006cdbd27 ("perf trace: Support tracepoint dynamic char arrays") Signed-off-by: Aaron Tomlin Signed-off-by: Namhyung Kim --- tools/perf/builtin-trace.c | 71 +++++++++++++++++++++++++++++++----- tools/perf/util/evsel.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/evsel.h | 6 +++ 3 files changed, 159 insertions(+), 9 deletions(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 845a9fe47f0b..186978cafab9 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -3207,6 +3207,22 @@ static void bpf_output__fprintf(struct trace *trace, ++trace->nr_events_printed; } +static unsigned char bitmap_byte(const unsigned long *mask, int byte_idx) +{ + unsigned char b_val = 0; + int bit_in_byte; + + for (bit_in_byte = 0; bit_in_byte < 8; bit_in_byte++) { + int b_idx = byte_idx * 8 + bit_in_byte; + int host_w_idx = b_idx / BITS_PER_LONG; + int host_bit_in_word = b_idx % BITS_PER_LONG; + + if (mask[host_w_idx] & (1UL << host_bit_in_word)) + b_val |= (1 << bit_in_byte); + } + return b_val; +} + static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample *sample, struct thread *thread, void *augmented_args, int augmented_args_size) { @@ -3238,17 +3254,54 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample * syscall_arg.len = 0; syscall_arg.fmt = arg; if (field->flags & TEP_FIELD_IS_ARRAY) { - int offset = field->offset; - - if (field->flags & TEP_FIELD_IS_DYNAMIC) { - offset = format_field__intval(field, sample, evsel->needs_swap); - syscall_arg.len = offset >> 16; - offset &= 0xffff; - if (tep_field_is_relative(field->flags)) - offset += field->offset + field->size; + void *ptr = format_field__get_raw_data(field, sample, + evsel->needs_swap, + &syscall_arg.len); + + if (!ptr) { + pr_err("Problem processing %s field, skipping...\n", field->name); + continue; + } + val = (uintptr_t)ptr; + } else if ((field->flags & TEP_FIELD_IS_DYNAMIC) && + strstr(field->type, "cpumask")) { + unsigned long *mask = format_field__get_cpumask(field, sample, + evsel->needs_swap, + &syscall_arg.len); + + if (!mask) { + pr_err("Problem processing %s field, skipping...\n", field->name); + continue; } - val = (uintptr_t)(sample->raw_data + offset); + printed += scnprintf(bf + printed, size - printed, "%s", printed ? ", " : ""); + if (trace->show_arg_names) + printed += scnprintf(bf + printed, size - printed, "%s: ", field->name); + + if (syscall_arg.len == 0) { + printed += scnprintf(bf + printed, size - printed, "0"); + } else { + int i; + bool skip_zero = true; + + printed += scnprintf(bf + printed, size - printed, "0x"); + /* Print bytes from most significant to least significant */ + for (i = syscall_arg.len - 1; i >= 0; i--) { + unsigned char b_val = bitmap_byte(mask, i); + + if (skip_zero && b_val == 0 && i > 0) + continue; + + if (skip_zero) { + printed += scnprintf(bf + printed, size - printed, "%x", b_val); + skip_zero = false; + } else { + printed += scnprintf(bf + printed, size - printed, "%02x", b_val); + } + } + } + free(mask); + continue; } else val = format_field__intval(field, sample, evsel->needs_swap); /* diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index a5b0687a3a79..d4cb455f4a7d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -16,9 +16,11 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -3933,6 +3935,95 @@ void *perf_sample__rawptr(struct perf_sample *sample, const char *name) return sample->raw_data + offset; } +void *format_field__get_raw_data(struct tep_format_field *field, struct + perf_sample *sample, bool needs_swap, + u16 *len_out) +{ + int offset = field->offset; + int size = field->size; + + if (field->flags & TEP_FIELD_IS_DYNAMIC) { + unsigned int dynamic_data; + + if (out_of_bounds(field, field->offset, field->size, sample->raw_size)) + return NULL; + + dynamic_data = format_field__intval(field, sample, needs_swap); + + offset = dynamic_data & 0xffff; + size = (dynamic_data >> 16) & 0xffff; + + if (tep_field_is_relative(field->flags)) + offset += field->offset + field->size; + } + + if (out_of_bounds(field, offset, size, sample->raw_size)) + return NULL; + + *len_out = size; + return sample->raw_data + offset; +} + +unsigned long *format_field__get_cpumask(struct tep_format_field *field, + struct perf_sample *sample, + bool needs_swap, u16 *len_out) +{ + u16 len; + void *ptr = format_field__get_raw_data(field, sample, needs_swap, &len); + unsigned long *mask; + struct perf_env *env; + bool target_is_64; + int target_word_size; + int nr_words; + int bit_idx; + int nbits; + + if (!ptr) + return NULL; + + nbits = len * 8; + mask = bitmap_zalloc(nbits ?: 1); + if (!mask) + return NULL; + + env = evsel__env(sample->evsel); + target_is_64 = env ? perf_env__kernel_is_64_bit(env) : (sizeof(void *) == 8); + target_word_size = target_is_64 ? 8 : 4; + nr_words = len / target_word_size; + + for (bit_idx = 0; bit_idx < nbits; bit_idx++) { + int w_idx = bit_idx / (target_word_size * 8); + int bit_in_word = bit_idx % (target_word_size * 8); + bool set = false; + + if (w_idx >= nr_words) + break; + + if (target_is_64) { + u64 word; + memcpy(&word, (unsigned char *)ptr + w_idx * 8, 8); + if (needs_swap) + word = bswap_64(word); + set = (word & (1ULL << bit_in_word)) != 0; + } else { + u32 word32; + memcpy(&word32, (unsigned char *)ptr + w_idx * 4, 4); + if (needs_swap) + word32 = bswap_32(word32); + set = (word32 & (1U << bit_in_word)) != 0; + } + + if (set) { + int host_w_idx = bit_idx / BITS_PER_LONG; + int host_bit_in_word = bit_idx % BITS_PER_LONG; + mask[host_w_idx] |= (1UL << host_bit_in_word); + } + } + + *len_out = len; + return mask; +} + u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sample, bool needs_swap) { diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 42b95933632a..d9ecc6628217 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -398,6 +398,12 @@ static inline char *perf_sample__strval(struct perf_sample *sample, const char * struct tep_format_field; +void *format_field__get_raw_data(struct tep_format_field *field, + struct perf_sample *sample, + bool needs_swap, u16 *len_out); +unsigned long *format_field__get_cpumask(struct tep_format_field *field, + struct perf_sample *sample, + bool needs_swap, u16 *len_out); u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sample, bool needs_swap); #ifdef HAVE_LIBTRACEEVENT -- cgit v1.2.3 From ab74d1fbe0618940f0d8100e36f7383d903afe5f Mon Sep 17 00:00:00 2001 From: Aaron Tomlin Date: Wed, 22 Jul 2026 11:50:49 -0400 Subject: perf trace: Add --bitmask-list command-line option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a new '--bitmask-list' command-line option for 'perf trace'. When this option is specified, the formatting of cpumasks is delegated to bitmap_scnprintf(), enabling cpumasks to be displayed as a condensed, human-readable list (e.g., "0,2-5,7") instead of the default hexadecimal representation. An example is provided below: ❯ sudo ./perf trace --show-cpu --bitmask-list --event ipi:ipi_send_cpumask --max-event 5 0.000 [000] Xorg/1434 ipi:ipi_send_cpumask(cpumask: 2-3,6, callsite: 0xffffffff9994f8e4, callback: 0xffffffff9994fdd0) 694.527 [002] chrome/2894 ipi:ipi_send_cpumask(cpumask: 1,3-5, callsite: 0xffffffff9994f8e4, callback: 0xffffffff9994fdd0) 2666.608 [003] Chrome_ChildIO/2948 ipi:ipi_send_cpumask(cpumask: 4,7, callsite: 0xffffffff9994f8e4, callback: 0xffffffff9994fdd0) 2673.638 [000] Chrome_IOThrea/2920 ipi:ipi_send_cpumask(cpumask: 2-5, callsite: 0xffffffff9994f8e4, callback: 0xffffffff9994fdd0) 2714.228 [005] chrome/3375 ipi:ipi_send_cpumask(cpumask: 0-4,6-7, callsite: 0xffffffff9994f8e4, callback: 0xffffffff9994fdd0) Signed-off-by: Aaron Tomlin Signed-off-by: Namhyung Kim --- tools/perf/Documentation/perf-trace.txt | 4 ++++ tools/perf/builtin-trace.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index d0b6c771a1b9..d20b43ea3d37 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt @@ -247,6 +247,10 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. pretty-printing serves as a fallback to hand-crafted pretty printers, as the latter can better pretty-print integer flags and struct pointers. +--bitmask-list:: + Show bitmasks as a human-readable, condensed list (e.g. "0,2-5,7") + instead of the default hexadecimal representation. + --bpf-summary:: Collect system call statistics in BPF. This is only for live mode and works well with -s/--summary option where no argument information is diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 186978cafab9..e47b5ae4e82a 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -226,6 +226,7 @@ struct trace { bool force; bool vfs_getname; bool force_btf; + bool bitmask_list; bool summary_bpf; int trace_pgfaults; char *perfconfig_events; @@ -3280,6 +3281,9 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample * if (syscall_arg.len == 0) { printed += scnprintf(bf + printed, size - printed, "0"); + } else if (trace->bitmask_list) { + printed += bitmap_scnprintf(mask, syscall_arg.len * 8, + bf + printed, size - printed); } else { int i; bool skip_zero = true; @@ -5593,6 +5597,7 @@ int cmd_trace(int argc, const char **argv) "start"), OPT_BOOLEAN(0, "force-btf", &trace.force_btf, "Prefer btf_dump general pretty printer" "to customized ones"), + OPT_BOOLEAN(0, "bitmask-list", &trace.bitmask_list, "Show bitmask as a human-readable list"), OPT_BOOLEAN(0, "bpf-summary", &trace.summary_bpf, "Summary syscall stats in BPF"), OPT_INTEGER(0, "max-summary", &trace.max_summary, "Max number of entries in the summary."), -- cgit v1.2.3 From da85966dfd23a3b03e00ee3bce6ad301f0a2b229 Mon Sep 17 00:00:00 2001 From: Aaron Tomlin Date: Sun, 19 Jul 2026 15:10:00 -0400 Subject: perf trace: Format instruction pointer fields as hexadecimal Provide a helper function trace__field_is_ip() in trace__fprintf_tp_fields() to ensure that tracepoint fields representing instruction pointers such as "__probe_ip", "caller_ip", and "call_site" are always formatted as hexadecimal memory addresses rather than signed integers. For example, when running a kmem:kfree tracepoint: # perf trace --show-cpu --event kmem:kfree --max-event 1 Before this change, "call_site" was represented as a signed integer: 0.000 [003] xfce4-terminal/2201 kmem:kfree(call_site: -1714572588, ptr: 0xffff8afee0303000) After this change, "call_site" is correctly represented in hexadecimal: 0.000 [003] xfce4-terminal/2201 kmem:kfree(call_site: 0xffffffff99cf1194, ptr: 0xffff8afee0303000) This improves the readability of perf trace output by making code addresses straightforward to parse and map to kernel symbols. Signed-off-by: Aaron Tomlin Signed-off-by: Namhyung Kim --- tools/perf/builtin-trace.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index e47b5ae4e82a..310ee8df33eb 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -3224,6 +3224,13 @@ static unsigned char bitmap_byte(const unsigned long *mask, int byte_idx) return b_val; } +static bool trace__field_is_ip(const char *name) +{ + return !strcmp(name, "__probe_ip") || + !strcmp(name, "caller_ip") || + !strcmp(name, "call_site"); +} + static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample *sample, struct thread *thread, void *augmented_args, int augmented_args_size) { @@ -3236,6 +3243,7 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample * size_t printed = 0, btf_printed; unsigned long val; u8 bit = 1; + bool is_probe_ip; struct syscall_arg syscall_arg = { .augmented = { .size = augmented_args_size, @@ -3323,9 +3331,14 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample * * Suppress it by default to avoid cluttering the output. * If verbose mode is enabled, ensure it is formatted as a * hexadecimal memory address rather than a signed integer. + * + * caller_ip and call_site are also expected to be instruction + * pointers and should always be represented in hexadecimal. */ - if (evsel__is_probe(evsel) && !strcmp(field->name, "__probe_ip")) { - if (!verbose) + is_probe_ip = evsel__is_probe(evsel) && !strcmp(field->name, "__probe_ip"); + + if (is_probe_ip || trace__field_is_ip(field->name)) { + if (is_probe_ip && !verbose) continue; printed += scnprintf(bf + printed, size - printed, -- cgit v1.2.3