Re: [PATCH v2 4/5] alpha/perf: attach ProfileMe status as PERF_SAMPLE_RAW data

From: Magnus Lindholm

Date: Sat Oct 31 2026 - 12:55:43 EST


Hi Matt,

On Fri, Oct 30, 2026 at 5:04 AM Matt Turner <mattst88@xxxxxxxxx> wrote:
>
> A ProfileMe sample's PC alone does not say what happened to the profiled
> instruction. I_STAT and PCTR_CTL do: whether it trapped and why, was
> mispredicted, stalled, or was killed on a wrong path, and what PCTR1
> counted during the window.
>
> With PERF_SAMPLE_RAW, attach PMPC, I_STAT and PCTR_CTL to each ProfileMe
> sample in a versioned struct alpha_profileme_sample. PMPC is included
> because a PALmode PMPC is not the sample's IP. Killed instructions can be
> told apart by PM_KILLED_BM and VAL. The 64-bit fields are packed after
> the 32-bit version, since the payload follows the 32-bit raw size in the
> sample record: they are then 8-byte aligned in the record, which needs
> no padding.
>
> Signed-off-by: Matt Turner <mattst88@xxxxxxxxx>
> ---
> arch/alpha/include/asm/perf_event.h | 2 ++
> arch/alpha/include/uapi/asm/perf_event.h | 31 +++++++++++++++++++++++++++++++
> arch/alpha/kernel/perf_event.c | 22 +++++++++++++++++++---
> 3 files changed, 52 insertions(+), 3 deletions(-)
>
> diff --git a/arch/alpha/include/asm/perf_event.h b/arch/alpha/include/asm/perf_event.h
> index 72536566014a..f498c1d47c07 100644
> --- a/arch/alpha/include/asm/perf_event.h
> +++ b/arch/alpha/include/asm/perf_event.h
> @@ -1,6 +1,8 @@
> #ifndef __ASM_ALPHA_PERF_EVENT_H
> #define __ASM_ALPHA_PERF_EVENT_H
>
> +#include <uapi/asm/perf_event.h>
> +
> /*
> * Software events have no trap frame, so perf_fetch_caller_regs() fills
> * in a zeroed pt_regs. A zero ps already means kernel mode; only pc is
> diff --git a/arch/alpha/include/uapi/asm/perf_event.h b/arch/alpha/include/uapi/asm/perf_event.h
> new file mode 100644
> index 000000000000..aa0eff5a917c
> --- /dev/null
> +++ b/arch/alpha/include/uapi/asm/perf_event.h
> @@ -0,0 +1,31 @@
> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +#ifndef _UAPI_ASM_ALPHA_PERF_EVENT_H
> +#define _UAPI_ASM_ALPHA_PERF_EVENT_H
> +
> +#include <linux/types.h>
> +
> +/*
> + * PERF_SAMPLE_RAW payload of a ProfileMe sample from the cpu PMU.
> + *
> + * pmpc, i_stat and pctr_ctl are the values of the PMPC, I_STAT and
> + * PCTR_CTL registers when the ProfileMe window closed. i_stat holds only
> + * bits 40:30 and pctr_ctl only bits 47:0. See the EV67/EV68 Hardware
> + * Reference Manuals for the field layout.
> + *
> + * In the sample record the payload follows the 32-bit PERF_SAMPLE_RAW
> + * size, so it starts 4 bytes past an 8-byte boundary. The 64-bit fields
> + * are packed after the 32-bit version so that they are 8-byte aligned in
> + * the record and no padding follows the payload.
> + *
> + * Fields may be added to the end in later versions.
> + */
> +#define ALPHA_PROFILEME_SAMPLE_VERSION 1
> +
> +struct alpha_profileme_sample {
> + __u32 version;
> + __u64 pmpc __attribute__((packed));
> + __u64 i_stat __attribute__((packed));
> + __u64 pctr_ctl __attribute__((packed));
> +};
> +
> +#endif /* _UAPI_ASM_ALPHA_PERF_EVENT_H */
> diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c
> index c7f0ccf8ec80..c9d4b13817bc 100644
> --- a/arch/alpha/kernel/perf_event.c
> +++ b/arch/alpha/kernel/perf_event.c
> @@ -944,10 +944,13 @@ static void alpha_perf_event_profileme(struct perf_event *event,
> struct hw_perf_event *hwc,
> struct pt_regs *regs)
> {
> + struct alpha_profileme_sample pm;
> + struct perf_raw_record raw;
> struct perf_sample_data data;
> struct pt_regs *pm_regs;
> - unsigned long i_stat, pmpc, ovr, pc, saved_pc, saved_ps;
> + unsigned long pctr_ctl, i_stat, pmpc, ovr, pc, saved_pc, saved_ps;
>
> + pctr_ctl = wrperfmon(PERFMON_CMD_READ, 0);
> i_stat = wrperfmon(PERFMON_CMD_I_STAT, 0);
> pmpc = wrperfmon(PERFMON_CMD_PMPC, 0);
>
> @@ -982,8 +985,8 @@ static void alpha_perf_event_profileme(struct perf_event *event,
> * happens for ITB miss, Istream access violation and interrupt
> * redirects, and for instructions inside PALcode. Keep the
> * interrupted PC, which for redirects is the instruction that
> - * trapped. Do the same for a user PMPC in a kernel thread, which has
> - * no user frame.
> + * trapped, and report the real PMPC in the raw data. Do the same
> + * for a user PMPC in a kernel thread, which has no user frame.
> */
> pm_regs = regs;
> pc = pmpc & EV67_PMPC_PC_MASK;
> @@ -1001,6 +1004,19 @@ static void alpha_perf_event_profileme(struct perf_event *event,
>
> perf_sample_data_init(&data, 0, hwc->last_period);
>
> + pm.version = ALPHA_PROFILEME_SAMPLE_VERSION;
> + pm.pmpc = pmpc;
> + pm.i_stat = i_stat;
> + /* PALcode sign-extends bit 47 of PCTR_CTL. */
> + pm.pctr_ctl = pctr_ctl & GENMASK(47, 0);
> + raw = (struct perf_raw_record) {
> + .frag = {
> + .size = sizeof(pm),
> + .data = &pm,
> + },
> + };
> + perf_sample_save_raw_data(&data, event, &raw);
> +
> if (!alpha_perf_event_set_period(event, hwc, 0))
> return;
>
>
> --
> 2.55.0
>

I checked the raw samples from all four ProfileMe modes on my ES40.
The selectors matched the configured events, and I saw the VAL, TAK,
killed and stalled bits set in the recordings.

Reviewed-by: Magnus Lindholm <linmag7@xxxxxxxxx>
Tested-by: Magnus Lindholm <linmag7@xxxxxxxxx>