Re: [PATCH v6 13/13] alpha/perf: honor exclude_user and exclude_kernel for ProfileMe events
From: Magnus Lindholm
Date: Thu Nov 05 2026 - 14:21:24 EST
Hi Matt,
On Wed, Nov 4, 2026 at 7:49 PM Matt Turner <mattst88@xxxxxxxxx> wrote:
>
> The PMU sets PERF_PMU_CAP_NO_EXCLUDE, as the counters count in every
> mode. perf record then fails for unprivileged users: at the default
> perf_event_paranoid of 2, the tool sets exclude_kernel for them.
>
> A ProfileMe sample says which mode the profiled instruction ran in, so
> the excluded samples can be dropped, as AMD IBS does with swfilt. Do
> that for ProfileMe events, counting PALmode as kernel, and ignore
> exclude_hv, as there is no hypervisor. A sample that falls back to the
> interrupted PC is dropped if either its PC or the profiled instruction
> is in an excluded mode. Aggregate events cannot tell, so event_init
> now rejects their exclude bits itself, along with exclude_idle,
> exclude_guest and exclude_host for all events.
>
> The event count, and what PCTR1 counted during a window, still include
> the excluded modes, as they do for IBS.
>
> Suggested-by: Ian Rogers <irogers@xxxxxxxxxx>
> Assisted-by: Claude:claude-opus-5-5
> Signed-off-by: Matt Turner <mattst88@xxxxxxxxx>
> ---
> arch/alpha/kernel/perf_event.c | 47 ++++++++++++++++++++++++++++++++++--------
> 1 file changed, 38 insertions(+), 9 deletions(-)
>
> diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c
> index 7e34eac0ea47..c75d204076fa 100644
> --- a/arch/alpha/kernel/perf_event.c
> +++ b/arch/alpha/kernel/perf_event.c
> @@ -832,6 +832,18 @@ static int __hw_perf_event_init(struct perf_event *event)
> return -EINVAL;
> hwc->flags = profileme ? ALPHA_PERF_FLAG_PROFILEME : 0;
>
> + /*
> + * The counters count in every mode, but ProfileMe samples say which
> + * mode the profiled instruction ran in, so those that are excluded can
> + * be dropped. PALmode counts as kernel, and exclude_hv is ignored, as
> + * there is no hypervisor.
> + */
> + if (attr->exclude_idle || attr->exclude_guest || attr->exclude_host)
> + return -EINVAL;
> + if (!profileme &&
> + (attr->exclude_user || attr->exclude_kernel || attr->exclude_hv))
> + return -EINVAL;
> +
> if (attr->config1 & ~ALPHA_PERF_CONFIG1_FILTERS)
> return -EINVAL;
> if (attr->config1 && !profileme)
> @@ -983,7 +995,6 @@ static struct pmu pmu = {
> .stop = alpha_pmu_stop,
> .read = alpha_pmu_read,
> .attr_groups = ev67_attr_groups,
> - .capabilities = PERF_PMU_CAP_NO_EXCLUDE,
> };
>
>
> @@ -1140,6 +1151,24 @@ static u64 alpha_profileme_status(unsigned long i_stat,
> return status;
> }
>
> +/*
> + * Whether exclude_user or exclude_kernel rules out a sample of the profiled
> + * instruction at pmpc, reported at pc. A PALmode PMPC counts as kernel. The
> + * two differ only when the sample falls back to the interrupted PC, and
> + * such a sample is then dropped if either mode is excluded.
> + */
> +static bool alpha_profileme_excluded(struct perf_event *event,
> + unsigned long pmpc, unsigned long pc)
> +{
> + bool pm_user = !(pmpc & EV67_PMPC_PAL) &&
> + (pmpc & EV67_PMPC_PC_MASK) < TASK_SIZE;
> + bool user = pc < TASK_SIZE;
> +
> + if (event->attr.exclude_user && (pm_user || user))
> + return true;
> + return event->attr.exclude_kernel && !(pm_user && user);
> +}
> +
> /* What the memory instruction at pc does, or PERF_MEM_OP_NA. */
> static u64 alpha_profileme_mem_op(unsigned long pc)
> {
> @@ -1250,14 +1279,6 @@ static void alpha_perf_event_profileme(struct perf_event *event,
> local64_add(ovr, &hwc->period_left);
> }
>
> - /* A dropped sample still counts, for throttling and frequency mode. */
> - if ((alpha_profileme_status(i_stat, pctr_ctl, pmpc) & hwc->config) !=
> - hwc->config) {
> - if (alpha_perf_event_set_period(event, hwc, 0))
> - perf_event_account_interrupt(event);
> - return;
> - }
> -
> /*
> * Attribute the sample to the profiled instruction rather than to
> * wherever the interrupt landed. perf takes the sample's mode,
> @@ -1303,6 +1324,14 @@ static void alpha_perf_event_profileme(struct perf_event *event,
> memset(pm_regs, 0, sizeof(*pm_regs));
> }
>
> + /* A dropped sample still counts, for throttling and frequency mode. */
> + if ((alpha_profileme_status(i_stat, pctr_ctl, pmpc) & hwc->config) !=
> + hwc->config || alpha_profileme_excluded(event, pmpc, pc)) {
> + if (alpha_perf_event_set_period(event, hwc, 0))
> + perf_event_account_interrupt(event);
> + return;
> + }
> +
> perf_sample_data_init(&data, 0, hwc->last_period);
> if (pc_only)
> alpha_profileme_drop_regs(event, &data, PERF_SAMPLE_REGS_USER |
>
> --
> 2.55.0
>
Tested user-only and kernel-only recordings on all three CPUs of my
ES40. I checked both the raw PMPC and the reported sample mode.
With perf_event_paranoid=2, an unprivileged process also recorded
203 user-only samples. Every sample had a user PMPC matching its IP.
Reviewed-by: Magnus Lindholm <linmag7@xxxxxxxxx>
Tested-by: Magnus Lindholm <linmag7@xxxxxxxxx>