[PATCH 1/7] perf tools: Track all user changed config bits

James Clark
2025-12-01T16:41:53Z

Currently we only track which bits were set by the user in attr->config.
But all configN fields should be treated equally as they can all have
default and user overridden values.

Track them all by making get_config_chgs() generic and calling it once
for each config value.

Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/util/evsel.c | 6 ++-
tools/perf/util/evsel_config.h | 6 ++-
tools/perf/util/parse-events.c | 89 +++++++++++++++++-------------------------
tools/perf/util/pmu.c | 2 +-
4 files changed, 47 insertions(+), 56 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index aee42666e882..40d68f346007 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1238,7 +1238,11 @@ static void evsel__apply_config_terms(struct evsel *evsel,
case EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE:
/* Already applied by auxtrace */
break;
- case EVSEL__CONFIG_TERM_CFG_CHG:
+ case EVSEL__CONFIG_TERM_USR_CHG_CONFIG:
+ case EVSEL__CONFIG_TERM_USR_CHG_CONFIG1:
+ case EVSEL__CONFIG_TERM_USR_CHG_CONFIG2:
+ case EVSEL__CONFIG_TERM_USR_CHG_CONFIG3:
+ case EVSEL__CONFIG_TERM_USR_CHG_CONFIG4:
break;
case EVSEL__CONFIG_TERM_RATIO_TO_PREV:
rtp_buf = term->val.str;
diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h
index bcd3a978f0c4..b38190dc5a40 100644
--- a/tools/perf/util/evsel_config.h
+++ b/tools/perf/util/evsel_config.h
@@ -27,7 +27,11 @@ enum evsel_term_type {
EVSEL__CONFIG_TERM_AUX_OUTPUT,
EVSEL__CONFIG_TERM_AUX_ACTION,
EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE,
- EVSEL__CONFIG_TERM_CFG_CHG,
+ EVSEL__CONFIG_TERM_USR_CHG_CONFIG,
+ EVSEL__CONFIG_TERM_USR_CHG_CONFIG1,
+ EVSEL__CONFIG_TERM_USR_CHG_CONFIG2,
+ EVSEL__CONFIG_TERM_USR_CHG_CONFIG3,
+ EVSEL__CONFIG_TERM_USR_CHG_CONFIG4,
EVSEL__CONFIG_TERM_RATIO_TO_PREV,
};

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 17c1c36a7bf9..f1cc6e96a371 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1235,63 +1235,46 @@ do { \
return 0;
}

+#define ADD_CONFIG_CHG(format_type, term_type, new_term) \
+{ \
+ struct parse_events_term *term; \
+ u64 bits = 0; \
+ int type; \
+ \
+ list_for_each_entry(term, &head_config->terms, list) { \
+ if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) { \
+ type = perf_pmu__format_type(pmu, term->config);\
+ if (type != format_type) \
+ continue; \
+ bits |= perf_pmu__format_bits(pmu, term->config); \
+ } else if (term->type_term == term_type) { \
+ bits = ~(u64)0; \
+ } \
+ } \
+ \
+ if (bits) \
+ ADD_CONFIG_TERM_VAL(new_term, cfg_chg, bits, false); \
+ return 0; \
+}
+
/*
- * Add EVSEL__CONFIG_TERM_CFG_CHG where cfg_chg will have a bit set for
- * each bit of attr->config that the user has changed.
+ * Add EVSEL__CONFIG_TERM_USR_CFG_CONFIGn where cfg_chg will have a bit set for
+ * each bit of attr->configN that the user has changed.
*/
-static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head_config,
+static int get_config_chgs(struct perf_pmu *pmu,
+ struct parse_events_terms *head_config,
struct list_head *head_terms)
{
- struct parse_events_term *term;
- u64 bits = 0;
- int type;
-
- list_for_each_entry(term, &head_config->terms, list) {
- switch (term->type_term) {
- case PARSE_EVENTS__TERM_TYPE_USER:
- type = perf_pmu__format_type(pmu, term->config);
- if (type != PERF_PMU_FORMAT_VALUE_CONFIG)
- continue;
- bits |= perf_pmu__format_bits(pmu, term->config);
- break;
- case PARSE_EVENTS__TERM_TYPE_CONFIG:
- bits = ~(u64)0;
- break;
- case PARSE_EVENTS__TERM_TYPE_CONFIG1:
- case PARSE_EVENTS__TERM_TYPE_CONFIG2:
- case PARSE_EVENTS__TERM_TYPE_CONFIG3:
- case PARSE_EVENTS__TERM_TYPE_CONFIG4:
- case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
- case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG:
- case PARSE_EVENTS__TERM_TYPE_NAME:
- case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
- case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
- case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
- case PARSE_EVENTS__TERM_TYPE_TIME:
- case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
- case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
- case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
- case PARSE_EVENTS__TERM_TYPE_INHERIT:
- case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
- case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
- case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
- case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
- case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
- case PARSE_EVENTS__TERM_TYPE_PERCORE:
- case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
- case PARSE_EVENTS__TERM_TYPE_AUX_ACTION:
- case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
- case PARSE_EVENTS__TERM_TYPE_METRIC_ID:
- case PARSE_EVENTS__TERM_TYPE_RAW:
- case PARSE_EVENTS__TERM_TYPE_CPU:
- case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
- default:
- break;
- }
- }
-
- if (bits)
- ADD_CONFIG_TERM_VAL(CFG_CHG, cfg_chg, bits, false);
+ ADD_CONFIG_CHG(PERF_PMU_FORMAT_VALUE_CONFIG,
+ PARSE_EVENTS__TERM_TYPE_CONFIG, USR_CHG_CONFIG);
+ ADD_CONFIG_CHG(PERF_PMU_FORMAT_VALUE_CONFIG1,
+ PARSE_EVENTS__TERM_TYPE_CONFIG1, USR_CHG_CONFIG1);
+ ADD_CONFIG_CHG(PERF_PMU_FORMAT_VALUE_CONFIG2,
+ PARSE_EVENTS__TERM_TYPE_CONFIG2, USR_CHG_CONFIG2);
+ ADD_CONFIG_CHG(PERF_PMU_FORMAT_VALUE_CONFIG3,
+ PARSE_EVENTS__TERM_TYPE_CONFIG3, USR_CHG_CONFIG3);
+ ADD_CONFIG_CHG(PERF_PMU_FORMAT_VALUE_CONFIG4,
+ PARSE_EVENTS__TERM_TYPE_CONFIG4, USR_CHG_CONFIG4);

#undef ADD_CONFIG_TERM
return 0;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 1b7c712d8f99..7a7db31be70d 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1384,7 +1384,7 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
const char *config_name, u64 val)
{
u64 user_bits = 0, bits;
- struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG);
+ struct evsel_config_term *term = evsel__get_config_term(evsel, USR_CHG_CONFIG);

if (term)
user_bits = term->val.cfg_chg;

--
2.34.1