Re: [PATCH v6 11/13] alpha/perf: add ProfileMe sample filters
From: Magnus Lindholm
Date: Thu Nov 05 2026 - 14:40:34 EST
Hi Matt,
On Wed, Nov 4, 2026 at 7:49 PM Matt Turner <mattst88@xxxxxxxxx> wrote:
>
> ProfileMe samples any fetched instruction, including those killed on a
> wrong path, and what happened to it is only in the PERF_SAMPLE_RAW data.
>
> Add three config1 bits that keep only the samples of instructions that:
>
> retired retired. VAL says so for an instruction that did not trap,
> and the trap type for one that did.
> mispredict were mispredicted conditional branches.
> trapped trapped, mispredicts included, or caused an ITB miss,
> Istream access violation or interrupt redirect.
>
> A sample must match every bit that is set, as with Arm SPE's
> event_filter. The driver drops the samples that do not, and they still
> count as interrupts for throttling and frequency mode.
>
> Suggested-by: Ian Rogers <irogers@xxxxxxxxxx>
> Assisted-by: Claude:claude-opus-5-5
> Signed-off-by: Matt Turner <mattst88@xxxxxxxxx>
> ---
> arch/alpha/include/asm/wrperfmon.h | 10 +++++
> arch/alpha/kernel/perf_event.c | 83 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 93 insertions(+)
>
> diff --git a/arch/alpha/include/asm/wrperfmon.h b/arch/alpha/include/asm/wrperfmon.h
> index dc24c7cb45db..6526438e73ee 100644
> --- a/arch/alpha/include/asm/wrperfmon.h
> +++ b/arch/alpha/include/asm/wrperfmon.h
> @@ -106,9 +106,14 @@
> #define EV67_I_STAT_MIS (1UL<<40)
>
> /* I_STAT[TRAP_TYPE] values */
> +#define EV67_TRAP_REPLAY 0
> #define EV67_TRAP_DTB_DOUBLE_3 2
> #define EV67_TRAP_DTB_DOUBLE_4 3
> +#define EV67_TRAP_FEN 4
> +#define EV67_TRAP_UNALIGNED 5
> #define EV67_TRAP_DTB_SINGLE 6
> +#define EV67_TRAP_DFAULT 7
> +#define EV67_TRAP_OPCDEC 8
>
> #define EV67_PCTR_VAL (1UL<<1)
> #define EV67_PCTR_PM_KILLED_BM (1UL<<26)
> @@ -116,5 +121,10 @@
> /* PMPC bits 63:2 hold the profiled PC. Bit 0 set means a PALmode address. */
> #define EV67_PMPC_PAL (1UL<<0)
> #define EV67_PMPC_PC_MASK (~3UL)
> +/* PMPC[14:0] of the redirect traps, which do not set I_STAT[TRP] */
> +#define EV67_PMPC_PAL_OFFSET_MASK 0x7fffUL
> +#define EV67_PMPC_IACV 0x0481
> +#define EV67_PMPC_ITB_MISS 0x0581
> +#define EV67_PMPC_INTERRUPT 0x0681
>
> #endif
> diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c
> index 0723e1042145..32a8b5c98381 100644
> --- a/arch/alpha/kernel/perf_event.c
> +++ b/arch/alpha/kernel/perf_event.c
> @@ -39,6 +39,13 @@
> #define ALPHA_PERF_CONFIG_EVENT 0xffULL
> #define ALPHA_PERF_CONFIG_PROFILEME BIT_ULL(8)
> #define ALPHA_PERF_CONFIG_RANDOMIZE BIT_ULL(9)
> +/* attr.config1 of a ProfileMe event: keep only samples of these insns. */
> +#define ALPHA_PERF_CONFIG1_RETIRED BIT_ULL(0)
> +#define ALPHA_PERF_CONFIG1_MISPREDICT BIT_ULL(1)
> +#define ALPHA_PERF_CONFIG1_TRAPPED BIT_ULL(2)
> +#define ALPHA_PERF_CONFIG1_FILTERS (ALPHA_PERF_CONFIG1_RETIRED | \
> + ALPHA_PERF_CONFIG1_MISPREDICT | \
> + ALPHA_PERF_CONFIG1_TRAPPED)
>
> /* hw_perf_event.flags */
> #define ALPHA_PERF_FLAG_WRAPPED 0x1
> @@ -258,11 +265,17 @@ 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");
> +PMU_FORMAT_ATTR(retired, "config1:0");
> +PMU_FORMAT_ATTR(mispredict, "config1:1");
> +PMU_FORMAT_ATTR(trapped, "config1:2");
>
> static struct attribute *ev67_format_attrs[] = {
> &format_attr_event.attr,
> &format_attr_profileme.attr,
> &format_attr_randomize.attr,
> + &format_attr_retired.attr,
> + &format_attr_mispredict.attr,
> + &format_attr_trapped.attr,
> NULL,
> };
>
> @@ -819,6 +832,12 @@ static int __hw_perf_event_init(struct perf_event *event)
> return -EINVAL;
> hwc->flags = profileme ? ALPHA_PERF_FLAG_PROFILEME : 0;
>
> + if (attr->config1 & ~ALPHA_PERF_CONFIG1_FILTERS)
> + return -EINVAL;
> + if (attr->config1 && !profileme)
> + return -EINVAL;
> + hwc->config = attr->config1;
> +
> if (attr->type == PERF_TYPE_RAW &&
> (attr->config & ALPHA_PERF_CONFIG_RANDOMIZE)) {
> if (!profileme)
> @@ -1060,6 +1079,62 @@ static bool alpha_profileme_trp(unsigned long i_stat, unsigned long pctr_ctl)
> return !(pctr_ctl & EV67_PCTR_PM_KILLED_BM) && (i_stat & EV67_I_STAT_TRP);
> }
>
> +/*
> + * VAL says whether an instruction that did not trap retired. For one that
> + * did, the trap type decides: these faults abort it, to be replayed,
> + * refetched after a fill, or emulated. Other traps, mispredicts among
> + * them, are counted as retired.
> + */
> +static bool alpha_profileme_retired(unsigned long i_stat,
> + unsigned long pctr_ctl)
> +{
> + if (pctr_ctl & EV67_PCTR_PM_KILLED_BM)
> + return false;
> + if (!(i_stat & EV67_I_STAT_TRP))
> + return pctr_ctl & EV67_PCTR_VAL;
> + if (i_stat & EV67_I_STAT_MIS)
> + return true;
> +
> + switch ((i_stat >> EV67_I_STAT_TRAP_TYPE_SHIFT) &
> + EV67_I_STAT_TRAP_TYPE_MASK) {
> + case EV67_TRAP_REPLAY:
> + case EV67_TRAP_DTB_DOUBLE_3:
> + case EV67_TRAP_DTB_DOUBLE_4:
> + case EV67_TRAP_FEN:
> + case EV67_TRAP_UNALIGNED:
> + case EV67_TRAP_DTB_SINGLE:
> + case EV67_TRAP_DFAULT:
> + case EV67_TRAP_OPCDEC:
> + rTested on all three CPUs of my ES40. I checked the trapped and
mispredict recordings against the raw ProfileMe status. Every
sample matched the requested filter.
Reviewed-by: Magnus Lindholm <linmag7@xxxxxxxxx>
Tested-by: Magnus Lindholm <linmag7@xxxxxxxxx>eturn false;
> + default:
> + return true;
> + }
> +}
> +
> +/* What the profiled instruction did, as config1 filter bits. */
> +static u64 alpha_profileme_status(unsigned long i_stat,
> + unsigned long pctr_ctl, unsigned long pmpc)
> +{
> + u64 status = 0;
> +
> + if (alpha_profileme_retired(i_stat, pctr_ctl))
> + status |= ALPHA_PERF_CONFIG1_RETIRED;
> + if (alpha_profileme_trp(i_stat, pctr_ctl)) {
> + status |= ALPHA_PERF_CONFIG1_TRAPPED;
> + if (i_stat & EV67_I_STAT_MIS)
> + status |= ALPHA_PERF_CONFIG1_MISPREDICT;
> + } else if (pmpc & EV67_PMPC_PAL) {
> + switch (pmpc & EV67_PMPC_PAL_OFFSET_MASK) {
> + case EV67_PMPC_IACV:
> + case EV67_PMPC_ITB_MISS:
> + case EV67_PMPC_INTERRUPT:
> + status |= ALPHA_PERF_CONFIG1_TRAPPED;
> + break;
> + }
> + }
> + return status;
> +}
> +
> /* What the memory instruction at pc does, or PERF_MEM_OP_NA. */
> static u64 alpha_profileme_mem_op(unsigned long pc)
> {
> @@ -1170,6 +1245,14 @@ 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,
>
> --
> 2.55.0
>
Tested on all three CPUs of my ES40. I checked the trapped and
mispredict recordings against the raw ProfileMe status. Every
sample matched the requested filter.
Reviewed-by: Magnus Lindholm <linmag7@xxxxxxxxx>
Tested-by: Magnus Lindholm <linmag7@xxxxxxxxx>