[PATCH 1/1] alpha/perf: Account for time spent handling PMU interrupts
From: Magnus Lindholm
Date: Sat Nov 07 2026 - 04:20:23 EST
Alpha does not report PMU interrupt duration to perf, preventing its
adaptive throttling from reducing an excessively costly sampling rate.
Measure handler time with RPCC and report it to perf_sample_event_took().
Convert cycles using the calibrated frequency selected by time_init();
Alpha's tick-based sched_clock() is too coarse for this measurement.
Wrap the existing handler so all return paths are accounted for, without
changing counter programming or event handling.
Signed-off-by: Magnus Lindholm <linmag7@xxxxxxxxx>
---
arch/alpha/kernel/perf_event.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c
index a3eaab094ece..dd3bc70b71d7 100644
--- a/arch/alpha/kernel/perf_event.c
+++ b/arch/alpha/kernel/perf_event.c
@@ -16,8 +16,10 @@
#include <linux/kdebug.h>
#include <linux/mutex.h>
#include <linux/init.h>
+#include <linux/math64.h>
#include <asm/hwrpb.h>
+#include <asm/timex.h>
#include <linux/atomic.h>
#include <asm/irq.h>
#include <asm/irq_regs.h>
@@ -26,6 +28,9 @@
#include <asm/hw_irq.h>
+extern unsigned long est_cycle_freq;
+static unsigned long pmu_cycle_freq __read_mostly;
+
/* The maximum number of PMCs on any Alpha CPU whatsoever. */
#define MAX_HWEVENTS 3
#define PMC_NO_INDEX -1
@@ -797,8 +802,8 @@ void perf_event_print_debug(void)
* Performance Monitoring Interrupt Service Routine called when a PMC
* overflows. The PMC that overflowed is passed in la_ptr.
*/
-static void alpha_perf_event_irq_handler(unsigned long la_ptr,
- struct pt_regs *regs)
+static void alpha_perf_event_irq_inner(unsigned long la_ptr,
+ struct pt_regs *regs)
{
struct cpu_hw_events *cpuc;
struct perf_sample_data data;
@@ -862,6 +867,21 @@ static void alpha_perf_event_irq_handler(unsigned long la_ptr,
+/* sched_clock() is tick-based on Alpha; measure a short same-CPU interval. */
+static void alpha_perf_event_irq_handler(unsigned long la_ptr,
+ struct pt_regs *regs)
+{
+ u32 start = get_cycles();
+ u32 cycles;
+
+ alpha_perf_event_irq_inner(la_ptr, regs);
+ /* Unsigned subtraction handles a wrap of the low 32-bit counter. */
+ cycles = (u32)get_cycles() - start;
+ if (likely(pmu_cycle_freq))
+ perf_sample_event_took(div64_u64((u64)cycles * NSEC_PER_SEC,
+ pmu_cycle_freq));
+}
+
/*
* Init call to initialise performance events at kernel startup.
*/
@@ -878,6 +898,8 @@ static int __init init_hw_perf_events(void)
/* Override performance counter IRQ vector */
+ /* Match the calibrated frequency selected by time_init(). */
+ pmu_cycle_freq = est_cycle_freq ? est_cycle_freq : hwrpb->cycle_freq;
perf_irq = alpha_perf_event_irq_handler;
/* And set up PMU specification */