RE: [patch 04/14] x86/irq: Make irqstats array based

From: Michael Kelley

Date: Wed Mar 04 2026 - 17:18:55 EST


From: Thomas Gleixner <tglx@xxxxxxxxxx> Sent: Wednesday, March 4, 2026 10:56 AM
>
> Having the x86 specific interrupt statistics as a data structure with
> individual members instead of an array is just stupid as it requires
> endless copy and paste in arch_show_interrupts() and arch_irq_stat_cpu(),
> where the latter does not even take the latest interrupt additions into
> account. The resulting #ifdef orgy is just disgusting.
>
> Convert it to an array of counters, which does not make a difference in the
> actual interrupt hotpath increment as the array index is constant and
> therefore not any different than the member based access.
>
> But in arch_show_interrupts() and arch_irq_stat_cpu() this just turns into
> a loop, which reduces the text size by ~2k (~12%):
>
> text data bss dec hex filename
> 19643 15250 904 35797 8bd5 ../build/arch/x86/kernel/irq.o
> 17355 15250 904 33509 82e5 ../build/arch/x86/kernel/irq.o
>
> Adding a new vector or software counter only requires to update the table
> and everything just works. Using the core provided emit function which
> speeds up 0 outputs makes it significantly faster.
>
> Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxx>
> ---
> arch/x86/events/amd/core.c | 2
> arch/x86/events/amd/ibs.c | 2
> arch/x86/events/core.c | 2
> arch/x86/events/intel/core.c | 2
> arch/x86/events/intel/knc.c | 2
> arch/x86/events/intel/p4.c | 2
> arch/x86/events/zhaoxin/core.c | 2
> arch/x86/hyperv/hv_init.c | 2
> arch/x86/include/asm/hardirq.h | 69 ++++++----
> arch/x86/include/asm/mce.h | 3
> arch/x86/kernel/apic/apic.c | 4
> arch/x86/kernel/apic/ipi.c | 2
> arch/x86/kernel/cpu/acrn.c | 2
> arch/x86/kernel/cpu/mce/amd.c | 2
> arch/x86/kernel/cpu/mce/core.c | 8 -
> arch/x86/kernel/cpu/mce/threshold.c | 2
> arch/x86/kernel/cpu/mshyperv.c | 4
> arch/x86/kernel/irq.c | 227 ++++++++++--------------------------
> arch/x86/kernel/irq_work.c | 2
> arch/x86/kernel/kvm.c | 2
> arch/x86/kernel/nmi.c | 4
> arch/x86/kernel/smp.c | 6
> arch/x86/mm/tlb.c | 2
> arch/x86/xen/enlighten_hvm.c | 2
> arch/x86/xen/enlighten_pv.c | 2
> arch/x86/xen/smp.c | 6
> arch/x86/xen/smp_pv.c | 2
> 27 files changed, 135 insertions(+), 232 deletions(-)
>

[snip]

> --- a/arch/x86/kernel/cpu/mshyperv.c
> +++ b/arch/x86/kernel/cpu/mshyperv.c
> @@ -154,7 +154,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_cal
> {
> struct pt_regs *old_regs = set_irq_regs(regs);
>
> - inc_irq_stat(irq_hv_callback_count);
> + inc_irq_stat(HYPERVISOR_CALLBACK);
> if (mshv_handler)
> mshv_handler();
>
> @@ -191,7 +191,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_sti
> {
> struct pt_regs *old_regs = set_irq_regs(regs);
>
> - inc_irq_stat(hyperv_stimer0_count);
> + inc_irq_stat(HYPERV_STIMER0)

Missing semicolon at the end of this line causes a compile error.

> if (hv_stimer0_handler)
> hv_stimer0_handler();
> add_interrupt_randomness(HYPERV_STIMER0_VECTOR);
> --- a/arch/x86/kernel/irq.c
> +++ b/arch/x86/kernel/irq.c
> @@ -62,156 +62,84 @@ void ack_bad_irq(unsigned int irq)
> apic_eoi();
> }
>
> -/*
> - * A helper routine for putting space and decimal number without overhead
> - * from rich format of printf().
> - */
> -static void put_decimal(struct seq_file *p, unsigned long long num)
> -{
> - const char *delimiter = " ";
> - unsigned int width = 10;
> +struct irq_stat_info {
> + unsigned int test_vector;
> + const char *symbol;
> + const char *text;
> +};
>
> - seq_put_decimal_ull_width(p, delimiter, num, width);
> -}
> +#define ISS(idx, sym, txt) [IRQ_COUNT_##idx] = { .symbol = sym, .text = txt }
>
> -#define irq_stats(x) (&per_cpu(irq_stat, x))
> -/*
> - * /proc/interrupts printing for arch specific interrupts
> - */
> -int arch_show_interrupts(struct seq_file *p, int prec)
> -{
> - int j;
> +#define ITS(idx, sym, txt) [IRQ_COUNT_##idx] = \
> + { .test_vector = idx## _VECTOR, .symbol = sym, .text = txt }
>
> - seq_printf(p, "%*s:", prec, "NMI");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->__nmi_count);
> - seq_puts(p, " Non-maskable interrupts\n");
> +static const struct irq_stat_info irq_stat_info[IRQ_COUNT_MAX] = {
> + ISS(NMI, "NMI", " Non-maskable interrupts\n"),
> #ifdef CONFIG_X86_LOCAL_APIC
> - seq_printf(p, "%*s:", prec, "LOC");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->apic_timer_irqs);
> - seq_puts(p, " Local timer interrupts\n");
> -
> - seq_printf(p, "%*s:", prec, "SPU");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->irq_spurious_count);
> - seq_puts(p, " Spurious interrupts\n");
> - seq_printf(p, "%*s:", prec, "PMI");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->apic_perf_irqs);
> - seq_puts(p, " Performance monitoring interrupts\n");
> - seq_printf(p, "%*s:", prec, "IWI");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->apic_irq_work_irqs);
> - seq_puts(p, " IRQ work interrupts\n");
> - seq_printf(p, "%*s:", prec, "RTR");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->icr_read_retry_count);
> - seq_puts(p, " APIC ICR read retries\n");
> - if (x86_platform_ipi_callback) {
> - seq_printf(p, "%*s:", prec, "PLT");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->x86_platform_ipis);
> - seq_puts(p, " Platform interrupts\n");
> - }
> + ISS(APIC_TIMER, "LOC", " Local timer interrupts\n"),
> + ISS(SPURIOUS, "SPU", " Spurious interrupts\n"),
> + ISS(APIC_PERF, "PMI", " Performance monitoring interrupts\n"),
> + ISS(IRQ_WORK, "IWI", " IRQ work interrupts\n"),
> + ISS(ICR_READ_RETRY, "RTR", " APIC ICR read retries\n"),
> + ISS(X86_PLATFORM_IPI, "PLT", " Platform interrupts\n"),
> #endif
> #ifdef CONFIG_SMP
> - seq_printf(p, "%*s:", prec, "RES");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->irq_resched_count);
> - seq_puts(p, " Rescheduling interrupts\n");
> - seq_printf(p, "%*s:", prec, "CAL");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->irq_call_count);
> - seq_puts(p, " Function call interrupts\n");
> - seq_printf(p, "%*s:", prec, "TLB");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->irq_tlb_count);
> - seq_puts(p, " TLB shootdowns\n");
> + ISS(RESCHEDULE, "RES", " Rescheduling interrupts\n"),
> + ISS(CALL_FUNCTION, "CAL", " Function call interrupts\n"),
> + ISS(TLB, "TLB", " TLB shootdowns\n"),
> #endif
> #ifdef CONFIG_X86_THERMAL_VECTOR
> - seq_printf(p, "%*s:", prec, "TRM");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->irq_thermal_count);
> - seq_puts(p, " Thermal event interrupts\n");
> + ISS(THERMAL_APIC, "TRM", " Thermal event interrupt\n"),
> #endif
> #ifdef CONFIG_X86_MCE_THRESHOLD
> - seq_printf(p, "%*s:", prec, "THR");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->irq_threshold_count);
> - seq_puts(p, " Threshold APIC interrupts\n");
> + ISS(THRESHOLD_APIC, "THR", " Threshold APIC interrupts\n"),
> #endif
> #ifdef CONFIG_X86_MCE_AMD
> - seq_printf(p, "%*s:", prec, "DFR");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->irq_deferred_error_count);
> - seq_puts(p, " Deferred Error APIC interrupts\n");
> + ISS(DEFERRED_ERROR, "DFR", " Deferred Error APIC interrupts\n"),
> #endif
> #ifdef CONFIG_X86_MCE
> - seq_printf(p, "%*s:", prec, "MCE");
> - for_each_online_cpu(j)
> - put_decimal(p, per_cpu(mce_exception_count, j));
> - seq_puts(p, " Machine check exceptions\n");
> - seq_printf(p, "%*s:", prec, "MCP");
> - for_each_online_cpu(j)
> - put_decimal(p, per_cpu(mce_poll_count, j));
> - seq_puts(p, " Machine check polls\n");
> + ISS(MCE_EXCEPTION, "MCE", " Machine check exceptions\n"),
> + ISS(MCE_POLL, "MCP", " Machine check polls\n"),
> #endif
> #ifdef CONFIG_X86_HV_CALLBACK_VECTOR
> - if (test_bit(HYPERVISOR_CALLBACK_VECTOR, system_vectors)) {
> - seq_printf(p, "%*s:", prec, "HYP");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->irq_hv_callback_count);
> - seq_puts(p, " Hypervisor callback interrupts\n");
> - }
> + ITS(HYPERVISOR_CALLBACK, "HYP", " Hypervisor callback interrupts\n"),
> #endif
> #if IS_ENABLED(CONFIG_HYPERV)
> - if (test_bit(HYPERV_REENLIGHTENMENT_VECTOR, system_vectors)) {
> - seq_printf(p, "%*s:", prec, "HRE");
> - for_each_online_cpu(j)
> - put_decimal(p,
> - irq_stats(j)->irq_hv_reenlightenment_count);
> - seq_puts(p, " Hyper-V reenlightenment interrupts\n");
> - }
> - if (test_bit(HYPERV_STIMER0_VECTOR, system_vectors)) {
> - seq_printf(p, "%*s:", prec, "HVS");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->hyperv_stimer0_count);
> - seq_puts(p, " Hyper-V stimer0 interrupts\n");
> - }
> -#endif
> - seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
> -#if defined(CONFIG_X86_IO_APIC)
> - seq_printf(p, "%*s: %10u\n", prec, "MIS", atomic_read(&irq_mis_count));
> + ITS(HYPERV_REENLIGHTMENT, "HRE", " Hyper-V reenlightment interrupts\n"),

s/HYPERV_REENLIGHTMENT/HYPERV_REENLIGHTENMENT/ (causes compile error)
s/reenlightment/reenlightenment/

> + ITS(HYPERV_STIMER0, "HVS", " Hyper-V stimer0 interrupts\n"),
> #endif
> #if IS_ENABLED(CONFIG_KVM)
> - seq_printf(p, "%*s:", prec, "PIN");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->kvm_posted_intr_ipis);
> - seq_puts(p, " Posted-interrupt notification event\n");
> -
> - seq_printf(p, "%*s:", prec, "NPI");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->kvm_posted_intr_nested_ipis);
> - seq_puts(p, " Nested posted-interrupt event\n");
> -
> - seq_printf(p, "%*s:", prec, "PIW");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->kvm_posted_intr_wakeup_ipis);
> - seq_puts(p, " Posted-interrupt wakeup event\n");
> + ITS(POSTED_INTR, "PIN", " Posted-interrupt notification event\n"),
> + ITS(POSTED_INTR_NESTED, "NPI", " Nested posted-interrupt event\n"),
> + ITS(POSTED_INTR_WAKEUP, "PIW", " Posted-interrupt wakeup event\n"),
> #endif
> #ifdef CONFIG_GUEST_PERF_EVENTS
> - seq_printf(p, "%*s:", prec, "VPMI");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->perf_guest_mediated_pmis);
> - seq_puts(p, " Perf Guest Mediated PMI\n");
> + ISS(PERF_GUEST_MEDIATED_PMI, "VPMI", " Perf Guest Mediated PMI\n"),
> #endif
> #ifdef CONFIG_X86_POSTED_MSI
> - seq_printf(p, "%*s:", prec, "PMN");
> - for_each_online_cpu(j)
> - put_decimal(p, irq_stats(j)->posted_msi_notification_count);
> - seq_puts(p, " Posted MSI notification event\n");
> + ISS(POSTED_MSI_NOTIFICATION, "PMN", " Posted MSI notification event\n"),
> #endif
> +};