[PATCH 15/15] perf/x86/intel: Allow Topdown metrics with a non-leader slots event
From: Dapeng Mi
Date: Mon Sep 28 2026 - 03:53:14 EST
Topdown metric events currently require the slots event to be the group
leader. That is unnecessarily strict. For metric counting, it is
sufficient that a valid slots event exists in the same group, regardless
of whether it is the leader.
Relax the validation in intel_pmu_hw_config() to accept a slots sibling
and validate metric constraints against that slots event. This enables
leader sampling for groups such as:
-e '{cycles:p,slots,topdown-retiring}:S'
Keep the existing ordering rule: the slots event must appear before all
metric events. Group validation is incremental, and intel_pmu_hw_config()
cannot determine whether the current event is the last event in the
group.
Also set the slots event with PERF_EV_CAP_RELIED_ON and metric events
with PERF_EV_CAP_RELIANT so that detaching the slots event will place
the dependent metric events into the ERROR state if slots event is not
the group leader.
Signed-off-by: Dapeng Mi <dapeng1.mi@xxxxxxxxxxxxxxx>
---
arch/x86/events/intel/core.c | 37 +++++++++++++++++++++++++++++-------
1 file changed, 30 insertions(+), 7 deletions(-)
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 6cc1462c9c82..9025f29f625d 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -5300,30 +5300,53 @@ static int intel_pmu_hw_config(struct perf_event *event)
if (is_available_metric_event(event)) {
struct perf_event *leader = event->group_leader;
+ struct perf_event *slots = NULL;
+ struct perf_event *sibling;
/* The metric events don't support sampling. */
if (is_sampling_event(event))
return -EINVAL;
- /* The metric events require a slots group leader. */
- if (!is_slots_event(leader))
+ /*
+ * intel_pmu_hw_config() cannot tell whether the current
+ * event is the last one in the group. Require the slots
+ * event to appear before all metric events.
+ */
+ if (is_slots_event(leader)) {
+ slots = leader;
+ } else if (leader->nr_siblings) {
+ for_each_sibling_event(sibling, leader) {
+ if (is_slots_event(sibling)) {
+ slots = sibling;
+ break;
+ }
+ }
+ }
+
+ /* The metric events require a slots event. */
+ if (!slots)
return -EINVAL;
/*
- * The leader/SLOTS must not be a sampling event for
+ * The slots event must not be a sampling event for
* metric use; hardware requires it starts at 0 when used
* in conjunction with MSR_PERF_METRICS.
*/
- if (is_sampling_event(leader))
+ if (is_sampling_event(slots))
return -EINVAL;
- event->event_caps |= PERF_EV_CAP_SIBLING;
+ if (slots == leader) {
+ event->event_caps |= PERF_EV_CAP_SIBLING;
+ } else {
+ slots->event_caps |= PERF_EV_CAP_RELIED_ON;
+ event->event_caps |= PERF_EV_CAP_RELIANT;
+ }
/*
* Only once we have a METRICs sibling do we
* need TopDown magic.
*/
- leader->hw.flags |= PERF_X86_EVENT_TOPDOWN;
- event->hw.flags |= PERF_X86_EVENT_TOPDOWN;
+ slots->hw.flags |= PERF_X86_EVENT_TOPDOWN;
+ event->hw.flags |= PERF_X86_EVENT_TOPDOWN;
}
}
--
2.34.1