[PATCH v5 07/14] perf evsel: Add a helper to get the value of a config field
From: James Clark <james.clark@linaro.org>
Date: 2026-01-14 15:57:47
Also in:
linux-perf-users, lkml
Subsystem:
performance events subsystem, the rest · Maintainers:
Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim, Linus Torvalds
This will be used by aux PMUs to read an already written value for configuring their events and for also testing. Its helper perf_pmu__format_unpack() does the opposite of the existing pmu_format_value() so rename that one to perf_pmu__format_pack() so it's clear how they are related. Reviewed-by: Ian Rogers <irogers@google.com> Signed-off-by: James Clark <james.clark@linaro.org> --- tools/perf/util/evsel.c | 42 +++++++++++++++++++++++++++++++++++++++++- tools/perf/util/evsel.h | 2 ++ tools/perf/util/pmu.c | 35 ++++++++++++++++++++++++++++------- tools/perf/util/pmu.h | 4 +++- 4 files changed, 74 insertions(+), 9 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 3162bfc0ccfe..ec74dce3211c 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c@@ -1378,7 +1378,47 @@ void evsel__set_config_if_unset(struct evsel *evsel, const char *config_name, return; /* Otherwise replace it */ - pmu_format_value(format->bits, val, vp, /*zero=*/true); + perf_pmu__format_pack(format->bits, val, vp, /*zero=*/true); +} + + +int evsel__get_config_val(const struct evsel *evsel, const char *config_name, + u64 *val) +{ + struct perf_pmu_format *format = pmu_find_format(&evsel->pmu->format, config_name); + + if (!format || bitmap_empty(format->bits, PERF_PMU_FORMAT_BITS)) { + pr_err("Unknown/empty format name: %s\n", config_name); + *val = 0; + return -EINVAL; + } + + switch (format->value) { + case PERF_PMU_FORMAT_VALUE_CONFIG: + *val = perf_pmu__format_unpack(format->bits, + evsel->core.attr.config); + return 0; + case PERF_PMU_FORMAT_VALUE_CONFIG1: + *val = perf_pmu__format_unpack(format->bits, + evsel->core.attr.config1); + return 0; + case PERF_PMU_FORMAT_VALUE_CONFIG2: + *val = perf_pmu__format_unpack(format->bits, + evsel->core.attr.config2); + return 0; + case PERF_PMU_FORMAT_VALUE_CONFIG3: + *val = perf_pmu__format_unpack(format->bits, + evsel->core.attr.config3); + return 0; + case PERF_PMU_FORMAT_VALUE_CONFIG4: + *val = perf_pmu__format_unpack(format->bits, + evsel->core.attr.config4); + return 0; + default: + pr_err("Unknown format value: %d\n", format->value); + *val = 0; + return -EINVAL; + } } void __weak arch_evsel__set_sample_weight(struct evsel *evsel)
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 2cf87bc67df7..95c4bd0f0f2e 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h@@ -575,6 +575,8 @@ void evsel__uniquify_counter(struct evsel *counter); ((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1))) u64 evsel__bitfield_swap_branch_flags(u64 value); +int evsel__get_config_val(const struct evsel *evsel, const char *config_name, + u64 *val); void evsel__set_config_if_unset(struct evsel *evsel, const char *config_name, u64 val);
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index dc5dab69151f..bb399a47d2b4 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c@@ -1337,6 +1337,26 @@ void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu) } } +/* + * Unpacks a raw config[n] value using the sparse bitfield that defines a + * format attr. For example "config1:1,6-7,44" defines a 4 bit value across non + * contiguous bits and this function returns those 4 bits as a value. + */ +u64 perf_pmu__format_unpack(unsigned long *format, u64 config_val) +{ + int val_bit = 0; + u64 res = 0; + int fmt_bit; + + for_each_set_bit(fmt_bit, format, PERF_PMU_FORMAT_BITS) { + if (config_val & (1ULL << fmt_bit)) + res |= BIT_ULL(val_bit); + + val_bit++; + } + return res; +} + struct perf_pmu_format *pmu_find_format(const struct list_head *formats, const char *name) {
@@ -1379,7 +1399,8 @@ int perf_pmu__format_type(const struct perf_pmu *pmu, const char *name) * Sets value based on the format definition (format parameter) * and unformatted value (value parameter). */ -void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, bool zero) +void perf_pmu__format_pack(unsigned long *format, __u64 value, __u64 *v, + bool zero) { unsigned long fbit, vbit;
@@ -1496,23 +1517,23 @@ static int pmu_config_term(const struct perf_pmu *pmu, switch (term->type_term) { case PARSE_EVENTS__TERM_TYPE_CONFIG: assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); - pmu_format_value(bits, term->val.num, &attr->config, zero); + perf_pmu__format_pack(bits, term->val.num, &attr->config, zero); break; case PARSE_EVENTS__TERM_TYPE_CONFIG1: assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); - pmu_format_value(bits, term->val.num, &attr->config1, zero); + perf_pmu__format_pack(bits, term->val.num, &attr->config1, zero); break; case PARSE_EVENTS__TERM_TYPE_CONFIG2: assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); - pmu_format_value(bits, term->val.num, &attr->config2, zero); + perf_pmu__format_pack(bits, term->val.num, &attr->config2, zero); break; case PARSE_EVENTS__TERM_TYPE_CONFIG3: assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); - pmu_format_value(bits, term->val.num, &attr->config3, zero); + perf_pmu__format_pack(bits, term->val.num, &attr->config3, zero); break; case PARSE_EVENTS__TERM_TYPE_CONFIG4: assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); - pmu_format_value(bits, term->val.num, &attr->config4, zero); + perf_pmu__format_pack(bits, term->val.num, &attr->config4, zero); break; case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG: assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
@@ -1650,7 +1671,7 @@ static int pmu_config_term(const struct perf_pmu *pmu, */ } - pmu_format_value(format->bits, val, vp, zero); + perf_pmu__format_pack(format->bits, val, vp, zero); return 0; }
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 7655d996090a..7ef90b54a149 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h@@ -279,12 +279,14 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_ u64 *alternate_hw_config, struct parse_events_error *err); int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, pmu_event_callback cb); -void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, bool zero); +void perf_pmu__format_pack(unsigned long *format, __u64 value, __u64 *v, + bool zero); struct perf_pmu_format *pmu_find_format(const struct list_head *formats, const char *name); void perf_pmu_format__set_value(void *format, int config, unsigned long *bits); bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name); int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_callback cb); +u64 perf_pmu__format_unpack(unsigned long *format, u64 config_val); bool is_pmu_core(const char *name); bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu);
--
2.34.1