[PATCH v2 5/5] alpha/perf: optionally randomize the ProfileMe sampling interval
From: Matt Turner
Date: Fri Oct 30 2026 - 00:04:24 EST
A fixed sampling interval can phase-lock with a loop whose length divides
it, so that the same few instructions are profiled over and over while
the rest of the loop is never seen. DCPI avoided this by randomizing the
interval.
Add a randomize config bit that varies each interval by up to 1/16 of
the period in either direction. Only ProfileMe events accept it, since
Aggregate mode samples already land a variable distance from the
instruction that overflowed. Counts are unaffected, because prev_count
already records the value actually written to the counter. The jitter
is computed with mul_u64_u32_shr() and the sum saturates, so that a
period beyond 32 bits cannot overflow.
The jitter comes from a per-CPU prandom state rather than
get_random_u32_below(), which takes the batched entropy local lock and
triggers an invalid wait context report from lockdep in the PMI.
Signed-off-by: Matt Turner <mattst88@xxxxxxxxx>
---
arch/alpha/kernel/perf_event.c | 37 ++++++++++++++++++++++++++++++++++++-
1 file changed, 36 insertions(+), 1 deletion(-)
diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c
index c9d4b13817bc..c553cbd6c7a3 100644
--- a/arch/alpha/kernel/perf_event.c
+++ b/arch/alpha/kernel/perf_event.c
@@ -16,6 +16,9 @@
#include <linux/kdebug.h>
#include <linux/mutex.h>
#include <linux/init.h>
+#include <linux/math64.h>
+#include <linux/overflow.h>
+#include <linux/prandom.h>
#include <asm/hwrpb.h>
#include <linux/atomic.h>
@@ -33,9 +36,11 @@
/* Layout of attr.config for PERF_TYPE_RAW events; see format/ in sysfs. */
#define ALPHA_PERF_CONFIG_EVENT 0xffULL
#define ALPHA_PERF_CONFIG_PROFILEME BIT_ULL(8)
+#define ALPHA_PERF_CONFIG_RANDOMIZE BIT_ULL(9)
/* hw_perf_event.flags */
#define ALPHA_PERF_FLAG_PROFILEME 0x1
+#define ALPHA_PERF_FLAG_RANDOMIZE 0x2
/* For tracking PMCs and the hw events they monitor on each CPU. */
struct cpu_hw_events {
@@ -59,6 +64,9 @@ struct cpu_hw_events {
};
DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+/* For randomizing sample intervals from the PMI, where locks are not allowed. */
+static DEFINE_PER_CPU(struct rnd_state, alpha_perf_rnd);
+
/*
@@ -246,10 +254,12 @@ static int ev67_raw_event_valid(u64 config)
PMU_FORMAT_ATTR(event, "config:0-7");
PMU_FORMAT_ATTR(profileme, "config:8");
+PMU_FORMAT_ATTR(randomize, "config:9");
static struct attribute *ev67_format_attrs[] = {
&format_attr_event.attr,
&format_attr_profileme.attr,
+ &format_attr_randomize.attr,
NULL,
};
@@ -367,6 +377,22 @@ static int alpha_perf_event_set_period(struct perf_event *event,
ret = 1;
}
+ /*
+ * Vary each new interval by up to 1/16 of the period either way, so
+ * the samples cannot phase-lock with a loop whose length divides the
+ * period. The count stays exact because prev_count records the value
+ * actually written.
+ */
+ if (ret && (hwc->flags & ALPHA_PERF_FLAG_RANDOMIZE) && period >= 8) {
+ long jitter = period / 8;
+ u32 r = prandom_u32_state(this_cpu_ptr(&alpha_perf_rnd));
+ long offset = mul_u64_u32_shr(jitter, r, 32) - jitter / 2;
+
+ if (check_add_overflow(left, offset, &left))
+ left = LONG_MAX;
+ local64_set(&hwc->period_left, left);
+ }
+
/*
* Hardware restrictions require that the counters must not be
* written with values that are too close to the maximum period.
@@ -738,7 +764,8 @@ static int __hw_perf_event_init(struct perf_event *event)
return -EOPNOTSUPP;
} else if (attr->type == PERF_TYPE_RAW) {
if (attr->config & ~(ALPHA_PERF_CONFIG_EVENT |
- ALPHA_PERF_CONFIG_PROFILEME))
+ ALPHA_PERF_CONFIG_PROFILEME |
+ ALPHA_PERF_CONFIG_RANDOMIZE))
return -EINVAL;
ev = attr->config & ALPHA_PERF_CONFIG_EVENT;
if (!alpha_pmu->raw_event_valid(ev))
@@ -763,6 +790,14 @@ static int __hw_perf_event_init(struct perf_event *event)
return -EINVAL;
hwc->flags = profileme ? ALPHA_PERF_FLAG_PROFILEME : 0;
+ if (attr->type == PERF_TYPE_RAW &&
+ (attr->config & ALPHA_PERF_CONFIG_RANDOMIZE)) {
+ if (!profileme)
+ return -EINVAL;
+ prandom_init_once(&alpha_perf_rnd);
+ hwc->flags |= ALPHA_PERF_FLAG_RANDOMIZE;
+ }
+
/*
* We place the event type in event_base here and leave calculation
* of the codes to programme the PMU for alpha_pmu_enable() because
--
2.55.0