[tip: perf/core] perf/x86/amd/uncore: Remove redundant event slot scan
From: tip-bot2 for Usama Arif
Date: Fri Sep 25 2026 - 06:48:35 EST
The following commit has been merged into the perf/core branch of tip:
Commit-ID: 4a8557a4e5d2d5f96a989a428e38569451e74405
Gitweb: https://git.kernel.org/tip/4a8557a4e5d2d5f96a989a428e38569451e74405
Author: Usama Arif <usama.arif@xxxxxxxxx>
AuthorDate: Mon, 21 Sep 2026 08:30:14 -07:00
Committer: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
CommitterDate: Fri, 25 Sep 2026 12:45:54 +02:00
perf/x86/amd/uncore: Remove redundant event slot scan
amd_uncore_add() first checks the slot recorded in event->hw.idx. If
that misses, it scans ctx->events[] for the event before looking for a
free slot.
Perf serializes ->add() and ->del() for an event. Initialization sets
idx to -1. A successful ->add() claims a slot and records its index
before returning, while ->del() clears the slot before resetting idx.
CPU context migration follows the same delete/add sequence.
Thus an installed event can only reside at the recorded index. If the
direct check misses, the event is not present in ctx->events[].
Remove the redundant scan. This avoids walking all counters before each
new slot search after multiplexing has scheduled an event out.
On a host running a production workload in the Meta fleet, amd_uncore_add()
was called 56,575 times per second from mux rotation. Its 16-counter DF PMU
makes each failed search scan 16 pointers across two cache lines.
Signed-off-by: Usama Arif <usama.arif@xxxxxxxxx>
Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
Reviewed-by: Sandipan Das <sandipan.das@xxxxxxx>
Link: https://patch.msgid.link/20260921153108.2713179-2-usama.arif@xxxxxxxxx
---
arch/x86/events/amd/uncore.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/arch/x86/events/amd/uncore.c b/arch/x86/events/amd/uncore.c
index 74b9c92..c1158f3 100644
--- a/arch/x86/events/amd/uncore.c
+++ b/arch/x86/events/amd/uncore.c
@@ -206,17 +206,15 @@ static int amd_uncore_add(struct perf_event *event, int flags)
struct amd_uncore_ctx *ctx = *per_cpu_ptr(pmu->ctx, event->cpu);
struct hw_perf_event *hwc = &event->hw;
- /* are we already assigned? */
+ /*
+ * Perf serializes ->add() and ->del() for an event. A successful
+ * ->add() records the claimed slot in hwc->idx before returning, and
+ * ->del() clears that slot before resetting hwc->idx. Therefore, an
+ * existing assignment must be at hwc->idx.
+ */
if (hwc->idx != -1 && ctx->events[hwc->idx] == event)
goto out;
- for (i = 0; i < pmu->num_counters; i++) {
- if (ctx->events[i] == event) {
- hwc->idx = i;
- goto out;
- }
- }
-
/* if not, take the first available counter */
hwc->idx = -1;
for (i = 0; i < pmu->num_counters; i++) {