Re: [PATCH v2 5/5] alpha/perf: optionally randomize the ProfileMe sampling interval
From: Magnus Lindholm
Date: Sat Oct 31 2026 - 12:57:02 EST
Hi Matt,
On Fri, Oct 30, 2026 at 5:04 AM Matt Turner <mattst88@xxxxxxxxx> wrote:
>
> 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(randoThe v2 arithmetic handles the large-period overflow case. I tested
randomized instruction sampling with a period of 10000 on all three
CPUs of my ES40. Repeated runs completed without hangs or kernel
warnings.
Reviewed-by: Magnus Lindholm <linmag7@xxxxxxxxx>
Tested-by: Magnus Lindholm <linmag7@xxxxxxxxx>mize, "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
>
The v2 arithmetic handles the large-period overflow case. I tested
randomized instruction sampling with a period of 10000 on all three
CPUs of my ES40. Repeated runs completed without hangs or kernel
warnings.
Reviewed-by: Magnus Lindholm <linmag7@xxxxxxxxx>
Tested-by: Magnus Lindholm <linmag7@xxxxxxxxx>