From nobody Fri Apr 10 00:56:50 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 81EE03D5242 for ; Wed, 4 Mar 2026 18:55:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650535; cv=none; b=VxXXJv07PNaLt0dMe6ntEF/Op1v7CI3dmf5EvlDFR1fYmjxb6lvFOuK9so4gxGEVPwoeRwircXtBZaZV3B26wyM30WNTcSdl5kWgnEKCTAVhYIJqJvuNkWLzyv6vqZGyErc/SGJyI7PmpUecDTaOr2eZALPkjcgAs32989GWi1g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650535; c=relaxed/simple; bh=5/YJcGbPneiW3axb3xDnS52zu3QFvBBPw24JJ/4Gzu8=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=ejQ73ETKjg2m2XP6g28r377O7vqoXmvs0cV5IvGBKSA6154o5/9Ahe2liLMmsqY3+gbv7UV2p04XtRZJ2jWQBZGm5rXtvS4foauanP9NSPCA5ZzxpRfRfvkUbN0DBKbPVPnXYX9+eDmZlkM89S4KXyCCVHn4DBUMVNZdUAppnFY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lUq3mAsk; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="lUq3mAsk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 64519C2BC86; Wed, 4 Mar 2026 18:55:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772650535; bh=5/YJcGbPneiW3axb3xDnS52zu3QFvBBPw24JJ/4Gzu8=; h=Date:From:To:Cc:Subject:References:From; b=lUq3mAskXDnIqXu3KFw0KawWLJYhZSnqR1ot2iXa8nAa8etLBGhZ00rc4nINRTQH8 VfIfP3rFExJh2FxcLLjtGdqzFvO4ertE0h6XK5FnmUesWT8CVXDcF7MuqJUmAv4Gxv /YmO4cDR6sLasgpu1R1xHsXutE6l4Zcf6i2Uqj9cRskedruFYDl78Bx7BnJTv17yWT hYYYA6HdtclNkONDwiPlxFbaCHgquF2gPrZb1o6BKR/T7I0STaIJ+CnD0v0Rcd2MOA yUaCRz/zQZH3qAAWTJevZAYHlhDiiIawQ4K4iJYal0Mzw7XuKvDSg0DUhwzLYtEouP Y6IfhFoTzVmlw== Date: Wed, 04 Mar 2026 19:55:31 +0100 Message-ID: <20260303154548.004368407@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman Subject: [patch 01/14] x86/irq: Optimize interrupts decimals printing References: <20260303150539.513068586@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Dmitry Ilvokhin Monitoring tools periodically scan /proc/interrupts to export metrics as a timeseries for future analysis and investigation. In large fleets, /proc/interrupts is polled (often every few seconds) on every machine. The cumulative overhead adds up quickly across thousands of nodes, so reducing the cost of generating these stats does have a measurable operational impact. With the ongoing trend toward higher core counts per machine, this cost becomes even more noticeable over time, since interrupt counters are per-CPU. In Meta's fleet, we have observed this overhead at scale. Although a binary /proc interface would be a better long-term solution due to lower formatting (kernel side) and parsing (userspace side) overhead, the text interface will remain in use for some time, even if better solutions will be available. Optimizing the /proc/interrupts printing code is therefore still beneficial. Function seq_printf() supports rich format string for decimals printing, but it doesn't required for printing /proc/interrupts per CPU counters, seq_put_decimal_ull_width() function can be used instead to print per CPU counters, because very limited formatting is required for this case. Similar optimization idea is already used in show_interrupts(). Performance counter stats (truncated) for 'sh -c cat /proc/interrupts Before: 3.42 msec task-clock # 0.802 CPUs utilized ( +- 0.05% ) 1 context-switches # 291.991 /sec ( +- 0.74% ) 0 cpu-migrations # 0.000 /sec 343 page-faults # 100.153 K/sec ( +- 0.01% ) 8,932,242 instructions # 1.66 insn per cycle ( +- 0.34% ) 5,374,427 cycles # 1.569 GHz ( +- 0.04% ) 1,483,154 branches # 433.068 M/sec ( +- 0.22% ) 28,768 branch-misses # 1.94% of all branches ( +- 0.31% ) 0.00427182 +- 0.00000215 seconds time elapsed ( +- 0.05% ) After: 2.39 msec task-clock # 0.796 CPUs utilized ( +- 0.06% ) 1 context-switches # 418.541 /sec ( +- 0.70% ) 0 cpu-migrations # 0.000 /sec 343 page-faults # 143.560 K/sec ( +- 0.01% ) 7,020,982 instructions # 1.30 insn per cycle ( +- 0.52% ) 5,397,266 cycles # 2.259 GHz ( +- 0.06% ) 1,569,648 branches # 656.962 M/sec ( +- 0.08% ) 25,419 branch-misses # 1.62% of all branches ( +- 0.72% ) 0.00299996 +- 0.00000206 seconds time elapsed ( +- 0.07% ) Relative speed up in time elapsed is around 29%. [ tglx: Fixed it up so it applies to current mainline ] Signed-off-by: Dmitry Ilvokhin Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/aQj5mGZ6_BBlAm3B@shell.ilvokhin.com --- Changes v2: - Expanded commit message: add more rationale for the proposed change. - Renamed helper put_spaced_decimal() -> put_decimal() primarely to make checkpatch.pl --strict pass. arch/x86/kernel/irq.c | 112 ++++++++++++++++++++++++++-------------------= ----- 1 file changed, 59 insertions(+), 53 deletions(-) --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -62,6 +62,18 @@ void ack_bad_irq(unsigned int irq) apic_eoi(); } =20 +/* + * 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 =3D " "; + unsigned int width =3D 10; + + seq_put_decimal_ull_width(p, delimiter, num, width); +} + #define irq_stats(x) (&per_cpu(irq_stat, x)) /* * /proc/interrupts printing for arch specific interrupts @@ -70,103 +82,101 @@ int arch_show_interrupts(struct seq_file { int j; =20 - seq_printf(p, "%*s: ", prec, "NMI"); + seq_printf(p, "%*s:", prec, "NMI"); for_each_online_cpu(j) - seq_printf(p, "%10u ", irq_stats(j)->__nmi_count); + put_decimal(p, irq_stats(j)->__nmi_count); seq_puts(p, " Non-maskable interrupts\n"); #ifdef CONFIG_X86_LOCAL_APIC - seq_printf(p, "%*s: ", prec, "LOC"); + seq_printf(p, "%*s:", prec, "LOC"); for_each_online_cpu(j) - seq_printf(p, "%10u ", irq_stats(j)->apic_timer_irqs); + put_decimal(p, irq_stats(j)->apic_timer_irqs); seq_puts(p, " Local timer interrupts\n"); =20 - seq_printf(p, "%*s: ", prec, "SPU"); + seq_printf(p, "%*s:", prec, "SPU"); for_each_online_cpu(j) - seq_printf(p, "%10u ", irq_stats(j)->irq_spurious_count); + put_decimal(p, irq_stats(j)->irq_spurious_count); seq_puts(p, " Spurious interrupts\n"); - seq_printf(p, "%*s: ", prec, "PMI"); + seq_printf(p, "%*s:", prec, "PMI"); for_each_online_cpu(j) - seq_printf(p, "%10u ", irq_stats(j)->apic_perf_irqs); + put_decimal(p, irq_stats(j)->apic_perf_irqs); seq_puts(p, " Performance monitoring interrupts\n"); - seq_printf(p, "%*s: ", prec, "IWI"); + seq_printf(p, "%*s:", prec, "IWI"); for_each_online_cpu(j) - seq_printf(p, "%10u ", irq_stats(j)->apic_irq_work_irqs); + put_decimal(p, irq_stats(j)->apic_irq_work_irqs); seq_puts(p, " IRQ work interrupts\n"); - seq_printf(p, "%*s: ", prec, "RTR"); + seq_printf(p, "%*s:", prec, "RTR"); for_each_online_cpu(j) - seq_printf(p, "%10u ", irq_stats(j)->icr_read_retry_count); + 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"); + seq_printf(p, "%*s:", prec, "PLT"); for_each_online_cpu(j) - seq_printf(p, "%10u ", irq_stats(j)->x86_platform_ipis); + put_decimal(p, irq_stats(j)->x86_platform_ipis); seq_puts(p, " Platform interrupts\n"); } #endif #ifdef CONFIG_SMP - seq_printf(p, "%*s: ", prec, "RES"); + seq_printf(p, "%*s:", prec, "RES"); for_each_online_cpu(j) - seq_printf(p, "%10u ", irq_stats(j)->irq_resched_count); + put_decimal(p, irq_stats(j)->irq_resched_count); seq_puts(p, " Rescheduling interrupts\n"); - seq_printf(p, "%*s: ", prec, "CAL"); + seq_printf(p, "%*s:", prec, "CAL"); for_each_online_cpu(j) - seq_printf(p, "%10u ", irq_stats(j)->irq_call_count); + put_decimal(p, irq_stats(j)->irq_call_count); seq_puts(p, " Function call interrupts\n"); - seq_printf(p, "%*s: ", prec, "TLB"); + seq_printf(p, "%*s:", prec, "TLB"); for_each_online_cpu(j) - seq_printf(p, "%10u ", irq_stats(j)->irq_tlb_count); + put_decimal(p, irq_stats(j)->irq_tlb_count); seq_puts(p, " TLB shootdowns\n"); #endif #ifdef CONFIG_X86_THERMAL_VECTOR - seq_printf(p, "%*s: ", prec, "TRM"); + seq_printf(p, "%*s:", prec, "TRM"); for_each_online_cpu(j) - seq_printf(p, "%10u ", irq_stats(j)->irq_thermal_count); + put_decimal(p, irq_stats(j)->irq_thermal_count); seq_puts(p, " Thermal event interrupts\n"); #endif #ifdef CONFIG_X86_MCE_THRESHOLD - seq_printf(p, "%*s: ", prec, "THR"); + seq_printf(p, "%*s:", prec, "THR"); for_each_online_cpu(j) - seq_printf(p, "%10u ", irq_stats(j)->irq_threshold_count); + put_decimal(p, irq_stats(j)->irq_threshold_count); seq_puts(p, " Threshold APIC interrupts\n"); #endif #ifdef CONFIG_X86_MCE_AMD - seq_printf(p, "%*s: ", prec, "DFR"); + seq_printf(p, "%*s:", prec, "DFR"); for_each_online_cpu(j) - seq_printf(p, "%10u ", irq_stats(j)->irq_deferred_error_count); + put_decimal(p, irq_stats(j)->irq_deferred_error_count); seq_puts(p, " Deferred Error APIC interrupts\n"); #endif #ifdef CONFIG_X86_MCE - seq_printf(p, "%*s: ", prec, "MCE"); + seq_printf(p, "%*s:", prec, "MCE"); for_each_online_cpu(j) - seq_printf(p, "%10u ", per_cpu(mce_exception_count, j)); + put_decimal(p, per_cpu(mce_exception_count, j)); seq_puts(p, " Machine check exceptions\n"); - seq_printf(p, "%*s: ", prec, "MCP"); + seq_printf(p, "%*s:", prec, "MCP"); for_each_online_cpu(j) - seq_printf(p, "%10u ", per_cpu(mce_poll_count, j)); + put_decimal(p, per_cpu(mce_poll_count, j)); seq_puts(p, " 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"); + seq_printf(p, "%*s:", prec, "HYP"); for_each_online_cpu(j) - seq_printf(p, "%10u ", - irq_stats(j)->irq_hv_callback_count); + put_decimal(p, irq_stats(j)->irq_hv_callback_count); seq_puts(p, " Hypervisor callback interrupts\n"); } #endif #if IS_ENABLED(CONFIG_HYPERV) if (test_bit(HYPERV_REENLIGHTENMENT_VECTOR, system_vectors)) { - seq_printf(p, "%*s: ", prec, "HRE"); + seq_printf(p, "%*s:", prec, "HRE"); for_each_online_cpu(j) - seq_printf(p, "%10u ", - irq_stats(j)->irq_hv_reenlightenment_count); + 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"); + seq_printf(p, "%*s:", prec, "HVS"); for_each_online_cpu(j) - seq_printf(p, "%10u ", - irq_stats(j)->hyperv_stimer0_count); + put_decimal(p, irq_stats(j)->hyperv_stimer0_count); seq_puts(p, " Hyper-V stimer0 interrupts\n"); } #endif @@ -175,35 +185,31 @@ int arch_show_interrupts(struct seq_file seq_printf(p, "%*s: %10u\n", prec, "MIS", atomic_read(&irq_mis_count)); #endif #if IS_ENABLED(CONFIG_KVM) - seq_printf(p, "%*s: ", prec, "PIN"); + seq_printf(p, "%*s:", prec, "PIN"); for_each_online_cpu(j) - seq_printf(p, "%10u ", irq_stats(j)->kvm_posted_intr_ipis); + put_decimal(p, irq_stats(j)->kvm_posted_intr_ipis); seq_puts(p, " Posted-interrupt notification event\n"); =20 - seq_printf(p, "%*s: ", prec, "NPI"); + seq_printf(p, "%*s:", prec, "NPI"); for_each_online_cpu(j) - seq_printf(p, "%10u ", - irq_stats(j)->kvm_posted_intr_nested_ipis); + put_decimal(p, irq_stats(j)->kvm_posted_intr_nested_ipis); seq_puts(p, " Nested posted-interrupt event\n"); =20 - seq_printf(p, "%*s: ", prec, "PIW"); + seq_printf(p, "%*s:", prec, "PIW"); for_each_online_cpu(j) - seq_printf(p, "%10u ", - irq_stats(j)->kvm_posted_intr_wakeup_ipis); + put_decimal(p, irq_stats(j)->kvm_posted_intr_wakeup_ipis); seq_puts(p, " Posted-interrupt wakeup event\n"); #endif #ifdef CONFIG_GUEST_PERF_EVENTS - seq_printf(p, "%*s: ", prec, "VPMI"); + seq_printf(p, "%*s:", prec, "VPMI"); for_each_online_cpu(j) - seq_printf(p, "%10u ", - irq_stats(j)->perf_guest_mediated_pmis); + put_decimal(p, irq_stats(j)->perf_guest_mediated_pmis); seq_puts(p, " Perf Guest Mediated PMI\n"); #endif #ifdef CONFIG_X86_POSTED_MSI - seq_printf(p, "%*s: ", prec, "PMN"); + seq_printf(p, "%*s:", prec, "PMN"); for_each_online_cpu(j) - seq_printf(p, "%10u ", - irq_stats(j)->posted_msi_notification_count); + put_decimal(p, irq_stats(j)->posted_msi_notification_count); seq_puts(p, " Posted MSI notification event\n"); #endif return 0; From nobody Fri Apr 10 00:56:50 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 623D13CE49B for ; Wed, 4 Mar 2026 18:55:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650539; cv=none; b=kryTHx1gWPUAkC28F4eYQBBakeeZzPG4qdxHiN3pDQApQK3Zp8SJWRRDrDij2G1OZcmVOOWIbbXR92Eey4bxpoQCL5ntuM+LzDgr/ei/hQXPcuG/d9MS0c2hkyRPqmIHl6pHfrZyfhi/alQNFybm7BVWHm3x+WZtmCacycPCHwY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650539; c=relaxed/simple; bh=8kSxdhX4H/+8X510szjjiKOKnfifKZh1pmVxuuSMnNE=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=XE/hpueFa+qKSYNXw8NzwJgVLLe2tuly2laxkcbo34kBHLJNg1PynxjZPT7cjgwcmzW8noMXynDHWh+UUNbxS09CseDAl1td4s6GrO5Zbj1U2+uM1cpmLudHdC6hZDSGd+7zU1aBPI+kxhkUu1oHm4kwlhGhi9S2Cgeld6Sl5XY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=rS6eFOux; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="rS6eFOux" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D29F2C19425; Wed, 4 Mar 2026 18:55:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772650539; bh=8kSxdhX4H/+8X510szjjiKOKnfifKZh1pmVxuuSMnNE=; h=Date:From:To:Cc:Subject:References:From; b=rS6eFOuxH9Jpsyc4ntCTRjY3dghaLIsycNSTpwJCYzumd0/uiEeMDS5dVdGqKqSjw 0eBVSfJuYe2owGI5pgeL7XPZoz2ppu3vmWh3lmR9oj+CxPUP6QBFRXeYI3mCpZXH2K TFMD0ym3UwaPEOew5oH1qHo4Qd5rfLEAfx48IVqBdNgpskFCCklZP4rtnYGRuEDu3m JGqkV6BV4m+f62GSDIdbTmj5D17sm3U17UGUQD6OyMJv/BPJYHSYr4xDf/0USlLTwP KeUOro2XJ5B1uOJGGPj+s0MGonkb3ogZNfmr3f1Zw236w/FdZfTQ1sCx916cChPO1M bG/nHf9gCRLSQ== Date: Wed, 04 Mar 2026 19:55:36 +0100 Message-ID: <20260303154548.082654896@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman Subject: [patch 02/14] genirq/proc: Avoid formatting zero counts in /proc/interrupts References: <20260303150539.513068586@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" A large portion of interrupt count entries are zero. There is no point in formatting the zero value as it is way cheeper to just emit a constant string. Collect the number of consecutive zero counts and emit them in one go before a non-zero count and at the end of the line. Signed-off-by: Thomas Gleixner Reviewed-by: Dmitry Ilvokhin --- include/linux/interrupt.h | 1 + kernel/irq/proc.c | 42 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 5 deletions(-) --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -864,6 +864,7 @@ static inline void init_irq_proc(void) struct seq_file; int show_interrupts(struct seq_file *p, void *v); int arch_show_interrupts(struct seq_file *p, int prec); +void irq_proc_emit_counts(struct seq_file *p, unsigned int __percpu *cnts); =20 extern int early_irq_init(void); extern int arch_probe_nr_irqs(void); --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -450,6 +450,42 @@ int __weak arch_show_interrupts(struct s # define ACTUAL_NR_IRQS irq_get_nr_irqs() #endif =20 +#define ZSTR1 " 0" +#define ZSTR1_LEN 11 +#define ZSTR16 ZSTR1 ZSTR1 ZSTR1 ZSTR1 ZSTR1 ZSTR1 ZSTR1 ZSTR1 \ + ZSTR1 ZSTR1 ZSTR1 ZSTR1 ZSTR1 ZSTR1 ZSTR1 ZSTR1 +#define ZSTR256 ZSTR16 ZSTR16 ZSTR16 ZSTR16 ZSTR16 ZSTR16 ZSTR16 ZSTR16 \ + ZSTR16 ZSTR16 ZSTR16 ZSTR16 ZSTR16 ZSTR16 ZSTR16 ZSTR16 + +static inline void irq_proc_emit_zero_counts(struct seq_file *p, unsigned = int zeros) +{ + if (!zeros) + return; + + for (unsigned int n =3D min(zeros, 256); n; zeros -=3D n, n =3D min(zeros= , 256)) + seq_write(p, ZSTR256, n * ZSTR1_LEN); +} + +static inline unsigned int irq_proc_emit_count(struct seq_file *p, unsigne= d int cnt, + unsigned int zeros) +{ + if (!cnt) + return zeros + 1; + + irq_proc_emit_zero_counts(p, zeros); + seq_put_decimal_ull_width(p, " ", cnt, 10); + return 0; +} + +void irq_proc_emit_counts(struct seq_file *p, unsigned int __percpu *cnts) +{ + unsigned int cpu, zeros =3D 0; + + for_each_online_cpu(cpu) + zeros =3D irq_proc_emit_count(p, per_cpu(*cnts, cpu), zeros); + irq_proc_emit_zero_counts(p, zeros); +} + int show_interrupts(struct seq_file *p, void *v) { const unsigned int nr_irqs =3D irq_get_nr_irqs(); @@ -485,11 +521,7 @@ int show_interrupts(struct seq_file *p, return 0; =20 seq_printf(p, "%*d:", prec, i); - for_each_online_cpu(j) { - unsigned int cnt =3D desc->kstat_irqs ? per_cpu(desc->kstat_irqs->cnt, j= ) : 0; - - seq_put_decimal_ull_width(p, " ", cnt, 10); - } + irq_proc_emit_counts(p, &desc->kstat_irqs->cnt); seq_putc(p, ' '); =20 guard(raw_spinlock_irq)(&desc->lock); From nobody Fri Apr 10 00:56:50 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DC21C3CE480 for ; Wed, 4 Mar 2026 18:55:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650543; cv=none; b=ti7215HcyXnNjkTZxIGEV01c4qsioP+wbNaRULBBB6UoHaRMAnWvDmwDFbrN06uXj2ROU3l3TcvQbPg+iE2gjTe4bBKb+imgdFcHrxaU89dQuxLIfWhw6uhGSEML3QqV+CWzxc2HX/Wu+HYkJCzuMh9cFE29M3M6nKHBnwaFAmU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650543; c=relaxed/simple; bh=uU+MjNuDc3MmvGzJZFgFDvkd5lwPR7SasutZ5GzfIN0=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=Xgla5naAg4apYgedsvmsDUPHKF2BhwjYLaoFGsyG6ifJXImy5g5H0z77dBb1zR9KohH3F5c+j5MOE5Hu3nG1mhFE9fLGsV+Hd7GNO/0BfkvhaLXVUaiDoIITNjQilO0A6zikZpU3TVwtC9uaXs+fuELUM7iuG2VbNb5J7uawO6A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=K2NgRPCG; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="K2NgRPCG" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 29800C4CEF7; Wed, 4 Mar 2026 18:55:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772650543; bh=uU+MjNuDc3MmvGzJZFgFDvkd5lwPR7SasutZ5GzfIN0=; h=Date:From:To:Cc:Subject:References:From; b=K2NgRPCGJz8/wmsjr9vR0ylOBUbFvaZj1iQD7830nh+pyrv3cPyT/ybdLnEnfjq2o dhuzJ4JB7h9GC5UhC9I40r2OnhGxm4zQNpUMli5Gq1JAgdVF25EJt/OWIzNauGfhaj ztYD8QerfuqE0DQdymQ/McJTXJuPfUk2x/AMY0yb1on5sLeRNFl6J7lDvGzLPcjSoG QjzTYMFXX3wVRW37CHkdAsmXJF3hQ1FP03bBV4opJr+scVog0MMIK1ds1+iUXg8xZD nce5+xaFdMV6vqscc22O5VLHm4hbgaAkRwahghXN8nWyJZ3N9fzUGmpLgej4qPdeRE q9u0gQteDupdA== Date: Wed, 04 Mar 2026 19:55:40 +0100 Message-ID: <20260303154548.149638880@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman Subject: [patch 03/14] genirq/proc: Utilize irq_desc::tot_count to avoid evaluation References: <20260303150539.513068586@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Interrupts which are not marked per CPU increment not only the per CPU statistics, but also the accumulation counter irq_desc::tot_count. Change the counter to type unsigned long so it does not produce sporadic zeros due to wrap arounds on 64-bit machines and do a quick check for non per CPU interrupts. If the counter is zero, then simply emit a full set of zero strings. That spares the evaluation of the per CPU counters completely for interrupts with zero events. Signed-off-by: Thomas Gleixner Reviewed-by: Dmitry Ilvokhin --- include/linux/irqdesc.h | 6 +++--- kernel/irq/proc.c | 11 ++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -52,8 +52,8 @@ struct irq_redirect { * @depth: disable-depth, for nested irq_disable() calls * @wake_depth: enable depth, for multiple irq_set_irq_wake() callers * @tot_count: stats field for non-percpu irqs - * @irq_count: stats field to detect stalled irqs * @last_unhandled: aging timer for unhandled count + * @irq_count: stats field to detect stalled irqs * @irqs_unhandled: stats field for spurious unhandled interrupts * @threads_handled: stats field for deferred spurious detection of thread= ed handlers * @threads_handled_last: comparator field for deferred spurious detection= of threaded handlers @@ -87,9 +87,9 @@ struct irq_desc { unsigned int core_internal_state__do_not_mess_with_it; unsigned int depth; /* nested irq disables */ unsigned int wake_depth; /* nested wake enables */ - unsigned int tot_count; - unsigned int irq_count; /* For detecting broken IRQs */ + unsigned long tot_count; unsigned long last_unhandled; /* Aging timer for unhandled count */ + unsigned int irq_count; /* For detecting broken IRQs */ unsigned int irqs_unhandled; atomic_t threads_handled; int threads_handled_last; --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -521,7 +521,16 @@ int show_interrupts(struct seq_file *p, return 0; =20 seq_printf(p, "%*d:", prec, i); - irq_proc_emit_counts(p, &desc->kstat_irqs->cnt); + + /* + * Always output per CPU interrupts. Output device interrupts only when + * desc::tot_count is not zero. + */ + if (irq_settings_is_per_cpu(desc) || irq_settings_is_per_cpu_devid(desc) = || + data_race(desc->tot_count)) + irq_proc_emit_counts(p, &desc->kstat_irqs->cnt); + else + irq_proc_emit_zero_counts(p, num_online_cpus()); seq_putc(p, ' '); =20 guard(raw_spinlock_irq)(&desc->lock); From nobody Fri Apr 10 00:56:50 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 17FAE3DA5AC for ; Wed, 4 Mar 2026 18:55:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650548; cv=none; b=tZiOhVzLKt7ZOPFiCkIeqdn81HJa4cVRSymNcMKCiYe0J8Axv0fcpbok6XQFcO/o2kbWlw1GqfkdJlxzU7Bq4zYnAiOEWHzFgU5YhMAotwk3+l7Q6+Me1tW/DVVHIsdP33D2wwOz2fuZsRihLO7bJfauHTzZ3Tq8onUdhQMq7Yo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650548; c=relaxed/simple; bh=uE4S9eN3qg+F7ShLM292lQVJd1nQ6nbIyHZ3Vs0nolI=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=EVGdPpxPmZ/6v5K20zrylsLCQIXERs64fm+56I35M+dvN/Uqh2TgTFBesp0AaNSIDna8HxQVoJ1/m8FhgBegXMS3lW2HsEONIVK0OopWlDNBHSkY05Ft87++SZ2UFvkKLsROgtFhcx1XdZvd3ydfmdxvX2Yeiy1KieaWfESPmNQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ja+JWDST; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ja+JWDST" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 596AFC2BC86; Wed, 4 Mar 2026 18:55:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772650548; bh=uE4S9eN3qg+F7ShLM292lQVJd1nQ6nbIyHZ3Vs0nolI=; h=Date:From:To:Cc:Subject:References:From; b=ja+JWDSTeILgiFfCRjpJcOQPviRITqs2YwsoM3zIybTC/rqDosZyYvQ2MwQY1b213 cUSZMUbPhrO5iiRUG8ojMKPqxrGcU6LrAF8yaGJfGbprYw9VApT+7VS7IRDcJkwkYv BgwDA01aioCv4Aq2UdGxQc5obAVpBu5JoFAv7F69meOU5IwCEMabFKAjr7Ib31FX2I nZ9ZNNWTBEpCdluzbIPrut/qeAE5EO4VAbIn2tAnSWCjIxUadBnJxqk7uyg4JmA7sC uG81k09w6Ilf1TU8WdIPghx7+mnAuwDlvNWVBTSpTqXdvKLXFBXkFyFU8Nk+zIBgma vuUTOTFQcyTZg== Date: Wed, 04 Mar 2026 19:55:45 +0100 Message-ID: <20260303154548.218256740@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman Subject: [patch 04/14] x86/irq: Make irqstats array based References: <20260303150539.513068586@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- arch/x86/events/amd/core.c | 2=20 arch/x86/events/amd/ibs.c | 2=20 arch/x86/events/core.c | 2=20 arch/x86/events/intel/core.c | 2=20 arch/x86/events/intel/knc.c | 2=20 arch/x86/events/intel/p4.c | 2=20 arch/x86/events/zhaoxin/core.c | 2=20 arch/x86/hyperv/hv_init.c | 2=20 arch/x86/include/asm/hardirq.h | 69 ++++++---- arch/x86/include/asm/mce.h | 3=20 arch/x86/kernel/apic/apic.c | 4=20 arch/x86/kernel/apic/ipi.c | 2=20 arch/x86/kernel/cpu/acrn.c | 2=20 arch/x86/kernel/cpu/mce/amd.c | 2=20 arch/x86/kernel/cpu/mce/core.c | 8 - arch/x86/kernel/cpu/mce/threshold.c | 2=20 arch/x86/kernel/cpu/mshyperv.c | 4=20 arch/x86/kernel/irq.c | 227 ++++++++++---------------------= ----- arch/x86/kernel/irq_work.c | 2=20 arch/x86/kernel/kvm.c | 2=20 arch/x86/kernel/nmi.c | 4=20 arch/x86/kernel/smp.c | 6=20 arch/x86/mm/tlb.c | 2=20 arch/x86/xen/enlighten_hvm.c | 2=20 arch/x86/xen/enlighten_pv.c | 2=20 arch/x86/xen/smp.c | 6=20 arch/x86/xen/smp_pv.c | 2=20 27 files changed, 135 insertions(+), 232 deletions(-) --- a/arch/x86/events/amd/core.c +++ b/arch/x86/events/amd/core.c @@ -1032,7 +1032,7 @@ static int amd_pmu_v2_handle_irq(struct * Unmasking the LVTPC is not required as the Mask (M) bit of the LVT * PMI entry is not set by the local APIC when a PMC overflow occurs */ - inc_irq_stat(apic_perf_irqs); + inc_irq_stat(APIC_PERF); =20 done: cpuc->enabled =3D pmu_enabled; --- a/arch/x86/events/amd/ibs.c +++ b/arch/x86/events/amd/ibs.c @@ -1403,7 +1403,7 @@ perf_ibs_nmi_handler(unsigned int cmd, s handled +=3D perf_ibs_handle_irq(&perf_ibs_op, regs); =20 if (handled) - inc_irq_stat(apic_perf_irqs); + inc_irq_stat(APIC_PERF); =20 perf_sample_event_took(sched_clock() - stamp); =20 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1747,7 +1747,7 @@ int x86_pmu_handle_irq(struct pt_regs *r } =20 if (handled) - inc_irq_stat(apic_perf_irqs); + inc_irq_stat(APIC_PERF); =20 return handled; } --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3504,7 +3504,7 @@ static int handle_pmi_common(struct pt_r int bit; int handled =3D 0; =20 - inc_irq_stat(apic_perf_irqs); + inc_irq_stat(APIC_PERF); =20 /* * Ignore a range of extra bits in status that do not indicate --- a/arch/x86/events/intel/knc.c +++ b/arch/x86/events/intel/knc.c @@ -238,7 +238,7 @@ static int knc_pmu_handle_irq(struct pt_ goto done; } =20 - inc_irq_stat(apic_perf_irqs); + inc_irq_stat(APIC_PERF); =20 for_each_set_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) { struct perf_event *event =3D cpuc->events[bit]; --- a/arch/x86/events/intel/p4.c +++ b/arch/x86/events/intel/p4.c @@ -1077,7 +1077,7 @@ static int p4_pmu_handle_irq(struct pt_r } =20 if (handled) - inc_irq_stat(apic_perf_irqs); + inc_irq_stat(APIC_PERF); =20 /* * When dealing with the unmasking of the LVTPC on P4 perf hw, it has --- a/arch/x86/events/zhaoxin/core.c +++ b/arch/x86/events/zhaoxin/core.c @@ -373,7 +373,7 @@ static int zhaoxin_pmu_handle_irq(struct else zhaoxin_pmu_ack_status(status); =20 - inc_irq_stat(apic_perf_irqs); + inc_irq_stat(APIC_PERF); =20 /* * CondChgd bit 63 doesn't mean any overflow status. Ignore --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c @@ -219,7 +219,7 @@ static inline bool hv_reenlightenment_av DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_reenlightenment) { apic_eoi(); - inc_irq_stat(irq_hv_reenlightenment_count); + inc_irq_stat(HYPERV_REENLIGHTENMENT); schedule_delayed_work(&hv_reenlightenment_work, HZ/10); } =20 --- a/arch/x86/include/asm/hardirq.h +++ b/arch/x86/include/asm/hardirq.h @@ -4,51 +4,60 @@ =20 #include =20 -typedef struct { -#if IS_ENABLED(CONFIG_CPU_MITIGATIONS) && IS_ENABLED(CONFIG_KVM_INTEL) - u8 kvm_cpu_l1tf_flush_l1d; -#endif - unsigned int __nmi_count; /* arch dependent */ +enum { + IRQ_COUNT_NMI, #ifdef CONFIG_X86_LOCAL_APIC - unsigned int apic_timer_irqs; /* arch dependent */ - unsigned int irq_spurious_count; - unsigned int icr_read_retry_count; + IRQ_COUNT_APIC_TIMER, + IRQ_COUNT_SPURIOUS, + IRQ_COUNT_APIC_PERF, + IRQ_COUNT_IRQ_WORK, + IRQ_COUNT_ICR_READ_RETRY, + IRQ_COUNT_X86_PLATFORM_IPI, #endif -#if IS_ENABLED(CONFIG_KVM) - unsigned int kvm_posted_intr_ipis; - unsigned int kvm_posted_intr_wakeup_ipis; - unsigned int kvm_posted_intr_nested_ipis; -#endif -#ifdef CONFIG_GUEST_PERF_EVENTS - unsigned int perf_guest_mediated_pmis; -#endif - unsigned int x86_platform_ipis; /* arch dependent */ - unsigned int apic_perf_irqs; - unsigned int apic_irq_work_irqs; #ifdef CONFIG_SMP - unsigned int irq_resched_count; - unsigned int irq_call_count; + IRQ_COUNT_RESCHEDULE, + IRQ_COUNT_CALL_FUNCTION, + IRQ_COUNT_TLB, #endif - unsigned int irq_tlb_count; #ifdef CONFIG_X86_THERMAL_VECTOR - unsigned int irq_thermal_count; + IRQ_COUNT_THERMAL_APIC, #endif #ifdef CONFIG_X86_MCE_THRESHOLD - unsigned int irq_threshold_count; + IRQ_COUNT_THRESHOLD_APIC, #endif #ifdef CONFIG_X86_MCE_AMD - unsigned int irq_deferred_error_count; + IRQ_COUNT_DEFERRED_ERROR, +#endif +#ifdef CONFIG_X86_MCE + IRQ_COUNT_MCE_EXCEPTION, + IRQ_COUNT_MCE_POLL, #endif #ifdef CONFIG_X86_HV_CALLBACK_VECTOR - unsigned int irq_hv_callback_count; + IRQ_COUNT_HYPERVISOR_CALLBACK, #endif #if IS_ENABLED(CONFIG_HYPERV) - unsigned int irq_hv_reenlightenment_count; - unsigned int hyperv_stimer0_count; + IRQ_COUNT_HYPERV_REENLIGHTENMENT, + IRQ_COUNT_HYPERV_STIMER0, +#endif +#if IS_ENABLED(CONFIG_KVM) + IRQ_COUNT_POSTED_INTR, + IRQ_COUNT_POSTED_INTR_NESTED, + IRQ_COUNT_POSTED_INTR_WAKEUP, +#endif +#ifdef CONFIG_GUEST_PERF_EVENTS + IRQ_COUNT_PERF_GUEST_MEDIATED_PMI, #endif #ifdef CONFIG_X86_POSTED_MSI - unsigned int posted_msi_notification_count; + IRQ_COUNT_POSTED_MSI_NOTIFICATION, +#endif + IRQ_COUNT_MAX, +}; + +typedef struct { +#if IS_ENABLED(CONFIG_CPU_MITIGATIONS) && IS_ENABLED(CONFIG_KVM_INTEL) + u8 kvm_cpu_l1tf_flush_l1d; #endif + unsigned int counts[IRQ_COUNT_MAX]; } ____cacheline_aligned irq_cpustat_t; =20 DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); @@ -58,7 +67,7 @@ DECLARE_PER_CPU_ALIGNED(struct pi_desc, #endif #define __ARCH_IRQ_STAT =20 -#define inc_irq_stat(member) this_cpu_inc(irq_stat.member) +#define inc_irq_stat(index) this_cpu_inc(irq_stat.counts[IRQ_COUNT_##index= ]) =20 extern void ack_bad_irq(unsigned int irq); =20 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -291,9 +291,6 @@ bool mce_is_memory_error(struct mce *m); bool mce_is_correctable(struct mce *m); bool mce_usable_address(struct mce *m); =20 -DECLARE_PER_CPU(unsigned, mce_exception_count); -DECLARE_PER_CPU(unsigned, mce_poll_count); - typedef DECLARE_BITMAP(mce_banks_t, MAX_NR_BANKS); DECLARE_PER_CPU(mce_banks_t, mce_poll_banks); =20 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1040,7 +1040,7 @@ static void local_apic_timer_interrupt(v /* * the NMI deadlock-detector uses this. */ - inc_irq_stat(apic_timer_irqs); + inc_irq_stat(APIC_TIMER); =20 evt->event_handler(evt); } @@ -2108,7 +2108,7 @@ static noinline void handle_spurious_int =20 trace_spurious_apic_entry(vector); =20 - inc_irq_stat(irq_spurious_count); + inc_irq_stat(SPURIOUS); =20 /* * If this is a spurious interrupt then do not acknowledge --- a/arch/x86/kernel/apic/ipi.c +++ b/arch/x86/kernel/apic/ipi.c @@ -120,7 +120,7 @@ u32 apic_mem_wait_icr_idle_timeout(void) for (cnt =3D 0; cnt < 1000; cnt++) { if (!(apic_read(APIC_ICR) & APIC_ICR_BUSY)) return 0; - inc_irq_stat(icr_read_retry_count); + inc_irq_stat(ICR_READ_RETRY); udelay(100); } return APIC_ICR_BUSY; --- a/arch/x86/kernel/cpu/acrn.c +++ b/arch/x86/kernel/cpu/acrn.c @@ -52,7 +52,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_acrn_hv_ca * HYPERVISOR_CALLBACK_VECTOR. */ apic_eoi(); - inc_irq_stat(irq_hv_callback_count); + inc_irq_stat(HYPERVISOR_CALLBACK); =20 if (acrn_intr_handler) acrn_intr_handler(); --- a/arch/x86/kernel/cpu/mce/amd.c +++ b/arch/x86/kernel/cpu/mce/amd.c @@ -840,7 +840,7 @@ bool amd_mce_usable_address(struct mce * DEFINE_IDTENTRY_SYSVEC(sysvec_deferred_error) { trace_deferred_error_apic_entry(DEFERRED_ERROR_VECTOR); - inc_irq_stat(irq_deferred_error_count); + inc_irq_stat(DEFERRED_ERROR); deferred_error_int_vector(); trace_deferred_error_apic_exit(DEFERRED_ERROR_VECTOR); apic_eoi(); --- a/arch/x86/kernel/cpu/mce/core.c +++ b/arch/x86/kernel/cpu/mce/core.c @@ -67,8 +67,6 @@ static DEFINE_MUTEX(mce_sysfs_mutex); =20 #define SPINUNIT 100 /* 100ns */ =20 -DEFINE_PER_CPU(unsigned, mce_exception_count); - DEFINE_PER_CPU_READ_MOSTLY(unsigned int, mce_num_banks); =20 DEFINE_PER_CPU_READ_MOSTLY(struct mce_bank[MAX_NR_BANKS], mce_banks_array); @@ -716,8 +714,6 @@ static noinstr void mce_read_aux(struct } } =20 -DEFINE_PER_CPU(unsigned, mce_poll_count); - /* * We have three scenarios for checking for Deferred errors: * @@ -820,7 +816,7 @@ void machine_check_poll(enum mcp_flags f struct mce *m; int i; =20 - this_cpu_inc(mce_poll_count); + inc_irq_stat(MCE_POLL); =20 mce_gather_info(&err, NULL); m =3D &err.m; @@ -1595,7 +1591,7 @@ noinstr void do_machine_check(struct pt_ */ lmce =3D 1; =20 - this_cpu_inc(mce_exception_count); + inc_irq_stat(MCE_EXCEPTION); =20 mce_gather_info(&err, regs); m =3D &err.m; --- a/arch/x86/kernel/cpu/mce/threshold.c +++ b/arch/x86/kernel/cpu/mce/threshold.c @@ -37,7 +37,7 @@ void (*mce_threshold_vector)(void) =3D def DEFINE_IDTENTRY_SYSVEC(sysvec_threshold) { trace_threshold_apic_entry(THRESHOLD_APIC_VECTOR); - inc_irq_stat(irq_threshold_count); + inc_irq_stat(THRESHOLD_APIC); mce_threshold_vector(); trace_threshold_apic_exit(THRESHOLD_APIC_VECTOR); apic_eoi(); --- 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 =3D set_irq_regs(regs); =20 - inc_irq_stat(irq_hv_callback_count); + inc_irq_stat(HYPERVISOR_CALLBACK); if (mshv_handler) mshv_handler(); =20 @@ -191,7 +191,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_sti { struct pt_regs *old_regs =3D set_irq_regs(regs); =20 - inc_irq_stat(hyperv_stimer0_count); + inc_irq_stat(HYPERV_STIMER0) 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(); } =20 -/* - * 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 =3D " "; - unsigned int width =3D 10; +struct irq_stat_info { + unsigned int test_vector; + const char *symbol; + const char *text; +}; =20 - seq_put_decimal_ull_width(p, delimiter, num, width); -} +#define ISS(idx, sym, txt) [IRQ_COUNT_##idx] =3D { .symbol =3D sym, .text = =3D txt } =20 -#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] =3D \ + { .test_vector =3D idx## _VECTOR, .symbol =3D sym, .text =3D txt } =20 - 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] =3D { + 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"), + 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 +}; + +/* + * /proc/interrupts printing for arch specific interrupts + */ +int arch_show_interrupts(struct seq_file *p, int prec) +{ + const struct irq_stat_info *info =3D irq_stat_info; + + for (unsigned int i =3D 0; i < ARRAY_SIZE(irq_stat_info); i++, info++) { + if (info->test_vector && !test_bit(info->test_vector, system_vectors)) + continue; + + seq_printf(p, "%*s:", prec, info->symbol); + irq_proc_emit_counts(p, &irq_stat.counts[i]); + seq_puts(p, info->text); + } + + seq_printf(p, "ERR: %10u\n", (unsigned int) atomic_read(&irq_err_count)); + if (IS_ENABLED(CONFIG_X86_IO_APIC)) + seq_printf(p, "MIS: %10u\n", (unsigned int) atomic_read(&irq_mis_count)); return 0; } =20 @@ -220,38 +148,11 @@ int arch_show_interrupts(struct seq_file */ u64 arch_irq_stat_cpu(unsigned int cpu) { - u64 sum =3D irq_stats(cpu)->__nmi_count; + irq_cpustat_t *p =3D per_cpu_ptr(&irq_stat, cpu); + u64 sum =3D 0; =20 -#ifdef CONFIG_X86_LOCAL_APIC - sum +=3D irq_stats(cpu)->apic_timer_irqs; - sum +=3D irq_stats(cpu)->irq_spurious_count; - sum +=3D irq_stats(cpu)->apic_perf_irqs; - sum +=3D irq_stats(cpu)->apic_irq_work_irqs; - sum +=3D irq_stats(cpu)->icr_read_retry_count; - if (x86_platform_ipi_callback) - sum +=3D irq_stats(cpu)->x86_platform_ipis; -#endif -#ifdef CONFIG_SMP - sum +=3D irq_stats(cpu)->irq_resched_count; - sum +=3D irq_stats(cpu)->irq_call_count; -#endif -#ifdef CONFIG_X86_THERMAL_VECTOR - sum +=3D irq_stats(cpu)->irq_thermal_count; -#endif -#ifdef CONFIG_X86_MCE_THRESHOLD - sum +=3D irq_stats(cpu)->irq_threshold_count; -#endif -#ifdef CONFIG_X86_HV_CALLBACK_VECTOR - sum +=3D irq_stats(cpu)->irq_hv_callback_count; -#endif -#if IS_ENABLED(CONFIG_HYPERV) - sum +=3D irq_stats(cpu)->irq_hv_reenlightenment_count; - sum +=3D irq_stats(cpu)->hyperv_stimer0_count; -#endif -#ifdef CONFIG_X86_MCE - sum +=3D per_cpu(mce_exception_count, cpu); - sum +=3D per_cpu(mce_poll_count, cpu); -#endif + for (unsigned int i =3D 0; i < ARRAY_SIZE(irq_stat_info); i++) + sum +=3D p->counts[i]; return sum; } =20 @@ -354,7 +255,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_x86_platfo =20 apic_eoi(); trace_x86_platform_ipi_entry(X86_PLATFORM_IPI_VECTOR); - inc_irq_stat(x86_platform_ipis); + inc_irq_stat(X86_PLATFORM_IPI); if (x86_platform_ipi_callback) x86_platform_ipi_callback(); trace_x86_platform_ipi_exit(X86_PLATFORM_IPI_VECTOR); @@ -369,7 +270,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_x86_platfo DEFINE_IDTENTRY_SYSVEC(sysvec_perf_guest_mediated_pmi_handler) { apic_eoi(); - inc_irq_stat(perf_guest_mediated_pmis); + inc_irq_stat(PERF_GUEST_MEDIATED_PMI); perf_guest_handle_mediated_pmi(); } #endif @@ -395,7 +296,7 @@ EXPORT_SYMBOL_FOR_KVM(kvm_set_posted_int DEFINE_IDTENTRY_SYSVEC_SIMPLE(sysvec_kvm_posted_intr_ipi) { apic_eoi(); - inc_irq_stat(kvm_posted_intr_ipis); + inc_irq_stat(POSTED_INTR); } =20 /* @@ -404,7 +305,7 @@ DEFINE_IDTENTRY_SYSVEC_SIMPLE(sysvec_kvm DEFINE_IDTENTRY_SYSVEC(sysvec_kvm_posted_intr_wakeup_ipi) { apic_eoi(); - inc_irq_stat(kvm_posted_intr_wakeup_ipis); + inc_irq_stat(POSTED_INTR_WAKEUP); kvm_posted_intr_wakeup_handler(); } =20 @@ -414,7 +315,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_kvm_posted DEFINE_IDTENTRY_SYSVEC_SIMPLE(sysvec_kvm_posted_intr_nested_ipi) { apic_eoi(); - inc_irq_stat(kvm_posted_intr_nested_ipis); + inc_irq_stat(POSTED_INTR_NESTED); } #endif =20 @@ -488,7 +389,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_posted_msi =20 /* Mark the handler active for intel_ack_posted_msi_irq() */ __this_cpu_write(posted_msi_handler_active, true); - inc_irq_stat(posted_msi_notification_count); + inc_irq_stat(POSTED_MSI_NOTIFICATION); irq_enter(); =20 /* @@ -583,7 +484,7 @@ static void smp_thermal_vector(void) DEFINE_IDTENTRY_SYSVEC(sysvec_thermal) { trace_thermal_apic_entry(THERMAL_APIC_VECTOR); - inc_irq_stat(irq_thermal_count); + inc_irq_stat(THERMAL_APIC); smp_thermal_vector(); trace_thermal_apic_exit(THERMAL_APIC_VECTOR); apic_eoi(); --- a/arch/x86/kernel/irq_work.c +++ b/arch/x86/kernel/irq_work.c @@ -18,7 +18,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_irq_work) { apic_eoi(); trace_irq_work_entry(IRQ_WORK_VECTOR); - inc_irq_stat(apic_irq_work_irqs); + inc_irq_stat(IRQ_WORK); irq_work_run(); trace_irq_work_exit(IRQ_WORK_VECTOR); } --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -310,7 +310,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_kvm_asyncp =20 apic_eoi(); =20 - inc_irq_stat(irq_hv_callback_count); + inc_irq_stat(HYPERVISOR_CALLBACK); =20 if (__this_cpu_read(async_pf_enabled)) { token =3D __this_cpu_read(apf_reason.token); --- a/arch/x86/kernel/nmi.c +++ b/arch/x86/kernel/nmi.c @@ -576,7 +576,7 @@ DEFINE_IDTENTRY_RAW(exc_nmi) =20 irq_state =3D irqentry_nmi_enter(regs); =20 - inc_irq_stat(__nmi_count); + inc_irq_stat(NMI); =20 if (IS_ENABLED(CONFIG_NMI_CHECK_CPU) && ignore_nmis) { WRITE_ONCE(nsp->idt_ignored, nsp->idt_ignored + 1); @@ -725,7 +725,7 @@ DEFINE_FREDENTRY_NMI(exc_nmi) =20 irq_state =3D irqentry_nmi_enter(regs); =20 - inc_irq_stat(__nmi_count); + inc_irq_stat(NMI); default_do_nmi(regs); =20 irqentry_nmi_exit(regs, irq_state); --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -249,7 +249,7 @@ DEFINE_IDTENTRY_SYSVEC_SIMPLE(sysvec_res { apic_eoi(); trace_reschedule_entry(RESCHEDULE_VECTOR); - inc_irq_stat(irq_resched_count); + inc_irq_stat(RESCHEDULE); scheduler_ipi(); trace_reschedule_exit(RESCHEDULE_VECTOR); } @@ -258,7 +258,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_call_funct { apic_eoi(); trace_call_function_entry(CALL_FUNCTION_VECTOR); - inc_irq_stat(irq_call_count); + inc_irq_stat(CALL_FUNCTION); generic_smp_call_function_interrupt(); trace_call_function_exit(CALL_FUNCTION_VECTOR); } @@ -267,7 +267,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_call_funct { apic_eoi(); trace_call_function_single_entry(CALL_FUNCTION_SINGLE_VECTOR); - inc_irq_stat(irq_call_count); + inc_irq_stat(CALL_FUNCTION); generic_smp_call_function_single_interrupt(); trace_call_function_single_exit(CALL_FUNCTION_SINGLE_VECTOR); } --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -1144,7 +1144,7 @@ static void flush_tlb_func(void *info) VM_WARN_ON(!irqs_disabled()); =20 if (!local) { - inc_irq_stat(irq_tlb_count); + inc_irq_stat(TLB); count_vm_tlb_event(NR_TLB_REMOTE_FLUSH_RECEIVED); } =20 --- a/arch/x86/xen/enlighten_hvm.c +++ b/arch/x86/xen/enlighten_hvm.c @@ -125,7 +125,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_xen_hvm_ca if (xen_percpu_upcall) apic_eoi(); =20 - inc_irq_stat(irq_hv_callback_count); + inc_irq_stat(HYPERVISOR_CALLBACK); =20 xen_evtchn_do_upcall(); =20 --- a/arch/x86/xen/enlighten_pv.c +++ b/arch/x86/xen/enlighten_pv.c @@ -728,7 +728,7 @@ static void __xen_pv_evtchn_do_upcall(st { struct pt_regs *old_regs =3D set_irq_regs(regs); =20 - inc_irq_stat(irq_hv_callback_count); + inc_irq_stat(HYPERVISOR_CALLBACK); =20 xen_evtchn_do_upcall(); =20 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -23,7 +23,7 @@ static irqreturn_t xen_call_function_sin */ static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id) { - inc_irq_stat(irq_resched_count); + inc_irq_stat(RESCHEDULE); scheduler_ipi(); =20 return IRQ_HANDLED; @@ -254,7 +254,7 @@ void xen_send_IPI_allbutself(int vector) static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id) { generic_smp_call_function_interrupt(); - inc_irq_stat(irq_call_count); + inc_irq_stat(CALL_FUNCTION); =20 return IRQ_HANDLED; } @@ -262,7 +262,7 @@ static irqreturn_t xen_call_function_int static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_i= d) { generic_smp_call_function_single_interrupt(); - inc_irq_stat(irq_call_count); + inc_irq_stat(CALL_FUNCTION); =20 return IRQ_HANDLED; } --- a/arch/x86/xen/smp_pv.c +++ b/arch/x86/xen/smp_pv.c @@ -400,7 +400,7 @@ static void xen_pv_stop_other_cpus(int w static irqreturn_t xen_irq_work_interrupt(int irq, void *dev_id) { irq_work_run(); - inc_irq_stat(apic_irq_work_irqs); + inc_irq_stat(IRQ_WORK); =20 return IRQ_HANDLED; } From nobody Fri Apr 10 00:56:50 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 467E13D75B1 for ; Wed, 4 Mar 2026 18:55:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650552; cv=none; b=BLsWxXuW/o8C8S7yANuZxssAe+FyObwINX7BTpZw39UMaM4Yd230LUb7lFSz/bJzqsg4jEVuVLu75ZAIyjY3St7YtfIRfWY607naBcYIV4jf9jcuf8wnWe8+fzCLGBEAn/VzwUc9f5RSb9a7+n8Ks0OehtAlHEdE/0eDp8b6NAQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650552; c=relaxed/simple; bh=4wenpkUxAQ8gwYYCAHvVIPfDkzr/bpUywnC4/3LB0WE=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=AutMHrTFmUSl2tJbRofT3MkQhS1BGupZNS0uuhVdGLly+ZM8mi4KgL/5ZlTOMACvkpGBiHCpDmqS2yFvkfDYTdWjRXim1zsPd60o+I7sPbBuw6UeRxu8HT4XIVGvzQ1uva8wVb7Vm082KPwyJ3zEZ+Mxt37LIgahzWY7YWQdolU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=VO7SN3EA; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="VO7SN3EA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id BAB83C4CEF7; Wed, 4 Mar 2026 18:55:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772650552; bh=4wenpkUxAQ8gwYYCAHvVIPfDkzr/bpUywnC4/3LB0WE=; h=Date:From:To:Cc:Subject:References:From; b=VO7SN3EAZ1zwstxRzsMSiSMW96SfEIaAPmLzfCXL28K6904jukNUk12hU8MdKME15 HesTFVCevzr6srlZe8NpcuuXp9vrgxQtCpWgpZeRY7PVr+OcDwQEYdx9K2m4jZSgcl xfQrOOS1hY0UHkB7L13YZN6vDFTdj614sNTlv7KTSFoWWY01fI22jNCfeNqVMCqLc+ 81BFQlZf3IfuO5vN22/TXHxScCI7IFBkUJdpYE6ckOqa7lJUefi0/OsoPLuneV0E0p dmCj6haYbV/OV/m6O6HB3Nf7I2mUMfNS1RPjdAtAtF4RxpS7uq+FiUajnosIV2ywpF XFQIKzt5KD6jA== Date: Wed, 04 Mar 2026 19:55:49 +0100 Message-ID: <20260303154548.286441920@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman Subject: [patch 05/14] genirq: Expose nr_irqs in core code References: <20260303150539.513068586@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" ... to avoid function calls in the core code to retrieve the maximum number of interrupts. Signed-off-by: Thomas Gleixner Reviewed-by: Dmitry Ilvokhin --- kernel/irq/internals.h | 1 + kernel/irq/irqdesc.c | 28 ++++++++++++++-------------- kernel/irq/proc.c | 2 +- 3 files changed, 16 insertions(+), 15 deletions(-) --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -21,6 +21,7 @@ =20 extern bool noirqdebug; extern int irq_poll_cpu; +extern unsigned int total_nr_irqs; =20 extern struct irqaction chained_action; =20 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -140,14 +140,14 @@ static void desc_set_defaults(unsigned i desc_smp_init(desc, node, affinity); } =20 -static unsigned int nr_irqs =3D NR_IRQS; +unsigned int total_nr_irqs __read_mostly =3D NR_IRQS; =20 /** * irq_get_nr_irqs() - Number of interrupts supported by the system. */ unsigned int irq_get_nr_irqs(void) { - return nr_irqs; + return total_nr_irqs; } EXPORT_SYMBOL_GPL(irq_get_nr_irqs); =20 @@ -159,7 +159,7 @@ EXPORT_SYMBOL_GPL(irq_get_nr_irqs); */ unsigned int irq_set_nr_irqs(unsigned int nr) { - nr_irqs =3D nr; + total_nr_irqs =3D nr; =20 return nr; } @@ -187,9 +187,9 @@ static unsigned int irq_find_at_or_after struct irq_desc *desc; =20 guard(rcu)(); - desc =3D mt_find(&sparse_irqs, &index, nr_irqs); + desc =3D mt_find(&sparse_irqs, &index, total_nr_irqs); =20 - return desc ? irq_desc_get_irq(desc) : nr_irqs; + return desc ? irq_desc_get_irq(desc) : total_nr_irqs; } =20 static void irq_insert_desc(unsigned int irq, struct irq_desc *desc) @@ -543,7 +543,7 @@ static bool irq_expand_nr_irqs(unsigned { if (nr > MAX_SPARSE_IRQS) return false; - nr_irqs =3D nr; + total_nr_irqs =3D nr; return true; } =20 @@ -557,16 +557,16 @@ int __init early_irq_init(void) /* Let arch update nr_irqs and return the nr of preallocated irqs */ initcnt =3D arch_probe_nr_irqs(); printk(KERN_INFO "NR_IRQS: %d, nr_irqs: %d, preallocated irqs: %d\n", - NR_IRQS, nr_irqs, initcnt); + NR_IRQS, total_nr_irqs, initcnt); =20 - if (WARN_ON(nr_irqs > MAX_SPARSE_IRQS)) - nr_irqs =3D MAX_SPARSE_IRQS; + if (WARN_ON(total_nr_irqs > MAX_SPARSE_IRQS)) + total_nr_irqs =3D MAX_SPARSE_IRQS; =20 if (WARN_ON(initcnt > MAX_SPARSE_IRQS)) initcnt =3D MAX_SPARSE_IRQS; =20 - if (initcnt > nr_irqs) - nr_irqs =3D initcnt; + if (initcnt > total_nr_irqs) + total_nr_irqs =3D initcnt; =20 for (i =3D 0; i < initcnt; i++) { desc =3D alloc_desc(i, node, 0, NULL, NULL); @@ -862,7 +862,7 @@ void irq_free_descs(unsigned int from, u { int i; =20 - if (from >=3D nr_irqs || (from + cnt) > nr_irqs) + if (from >=3D total_nr_irqs || (from + cnt) > total_nr_irqs) return; =20 guard(mutex)(&sparse_irq_lock); @@ -911,7 +911,7 @@ int __ref __irq_alloc_descs(int irq, uns if (irq >=3D0 && start !=3D irq) return -EEXIST; =20 - if (start + cnt > nr_irqs) { + if (start + cnt > total_nr_irqs) { if (!irq_expand_nr_irqs(start + cnt)) return -ENOMEM; } @@ -923,7 +923,7 @@ EXPORT_SYMBOL_GPL(__irq_alloc_descs); * irq_get_next_irq - get next allocated irq number * @offset: where to start the search * - * Returns next irq number after offset or nr_irqs if none is found. + * Returns next irq number after offset or total_nr_irqs if none is found. */ unsigned int irq_get_next_irq(unsigned int offset) { --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -447,7 +447,7 @@ int __weak arch_show_interrupts(struct s } =20 #ifndef ACTUAL_NR_IRQS -# define ACTUAL_NR_IRQS irq_get_nr_irqs() +# define ACTUAL_NR_IRQS total_nr_irqs #endif =20 #define ZSTR1 " 0" From nobody Fri Apr 10 00:56:50 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 34B4E3DEAE7 for ; Wed, 4 Mar 2026 18:55:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650557; cv=none; b=HcDVVM8rP4wxZ1pkehjhonaXdmr+Qt2qAOPxofAG9hdO9v8HdFnubR+R8Qb+NI095HXn6Yof9NrfnS8Udqgfbj4Z8ovxGGk0IQAaWbP2z0XbaaqWudJQVz5M50rUNh4y4z6NCfldzIJvPEbIPhaX5yt9vBOkFNjfL/zSQAjyg1c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650557; c=relaxed/simple; bh=9GnKQpUDDB6wgOMPQ4HJYdK556+J3tQtA2gHuY3qfmo=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=BkbbvjouYKAYlBgqIG0GjyOgP8qL+mzfq/BSlq9R6SIt9bRhT4JCkr1eqPGDQS9Zueh/YMR1gySCcsVzJVDg3Lu7URvQtyN45yWj/vflgz5/0Fh4sgZP+OadIJDu4VzvwNLKuYzr160XxoQTu4+zdPKcgXNnAnowHlyKuc3pkY4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FvosRdwO; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FvosRdwO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 282A8C4CEF7; Wed, 4 Mar 2026 18:55:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772650556; bh=9GnKQpUDDB6wgOMPQ4HJYdK556+J3tQtA2gHuY3qfmo=; h=Date:From:To:Cc:Subject:References:From; b=FvosRdwOlpPd/5my2+iWTrTIc7EIY1LMQhtjTbxyn8Y+gu2P/8SS6+FHLD24Mq26E Fq9LCyzvoIYBdiwDkFls/M3Ae6JoVLFFk7Yrlimj+dPFO3Nz5QdVd2cW9PiYUVjvQi voPhpWV9bJCAuWhONKTTiuCEv5SJi78SDGuNgJxmXNuQyOalkXITDon7XkbL0LGEe+ kCukVwobJoP13DrH8OkgEu2v2P2pTJ6bhUD/SnKpGbIGcGGpQyBaWHO8lg/uzV5Hh6 /Il8neh9bO7iv2OAOSt//2tpwt5yCB3W7etUD5+F8fiA4SZJjgtmhkhhqdpPY5jVmA POUDW0Vp9Akhg== Date: Wed, 04 Mar 2026 19:55:53 +0100 Message-ID: <20260303154548.366781240@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman Subject: [patch 06/14] genirq: Cache the condition for /proc/interrupts exposure References: <20260303150539.513068586@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" show_interrupts() evaluates a boatload of conditions to establish whether exposing an interrupt in /proc/interrupts or not. That can be simplified by caching the condition in an internal status flag, which is updated when one of the relevant inputs changes. As a result the number of instructions and branches for reading /proc/interrupts is reduced significantly. Signed-off-by: Thomas Gleixner Reviewed-by: Dmitry Ilvokhin --- include/linux/irq.h | 1 + kernel/irq/chip.c | 2 ++ kernel/irq/internals.h | 2 ++ kernel/irq/manage.c | 2 ++ kernel/irq/proc.c | 16 ++++++++++++---- kernel/irq/settings.h | 14 ++++++++++++++ 6 files changed, 33 insertions(+), 4 deletions(-) --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -99,6 +99,7 @@ enum { IRQ_DISABLE_UNLAZY =3D (1 << 19), IRQ_HIDDEN =3D (1 << 20), IRQ_NO_DEBUG =3D (1 << 21), + IRQF_RESERVED =3D (1 << 22), }; =20 #define IRQF_MODIFY_MASK \ --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -1004,6 +1004,7 @@ static void WARN_ON(irq_chip_pm_get(irq_desc_get_irq_data(desc))); irq_activate_and_startup(desc, IRQ_RESEND); } + irq_proc_update_valid(desc); } =20 void __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is= _chained, @@ -1064,6 +1065,7 @@ void irq_modify_status(unsigned int irq, trigger =3D tmp; =20 irqd_set(&desc->irq_data, trigger); + irq_proc_update_valid(desc); } } EXPORT_SYMBOL_GPL(irq_modify_status); --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -123,6 +123,7 @@ extern void register_irq_proc(unsigned i extern void unregister_irq_proc(unsigned int irq, struct irq_desc *desc); extern void register_handler_proc(unsigned int irq, struct irqaction *acti= on); extern void unregister_handler_proc(unsigned int irq, struct irqaction *ac= tion); +void irq_proc_update_valid(struct irq_desc *desc); #else static inline void register_irq_proc(unsigned int irq, struct irq_desc *de= sc) { } static inline void unregister_irq_proc(unsigned int irq, struct irq_desc *= desc) { } @@ -130,6 +131,7 @@ static inline void register_handler_proc struct irqaction *action) { } static inline void unregister_handler_proc(unsigned int irq, struct irqaction *action) { } +static inline void irq_proc_update_valid(struct irq_desc *desc) { } #endif =20 extern bool irq_can_set_affinity_usr(unsigned int irq); --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1802,6 +1802,7 @@ static int __enable_irq(desc); } =20 + irq_proc_update_valid(desc); raw_spin_unlock_irqrestore(&desc->lock, flags); chip_bus_sync_unlock(desc); mutex_unlock(&desc->request_mutex); @@ -1906,6 +1907,7 @@ static struct irqaction *__free_irq(stru desc->affinity_hint =3D NULL; #endif =20 + irq_proc_update_valid(desc); raw_spin_unlock_irqrestore(&desc->lock, flags); /* * Drop bus_lock here so the changes which were done in the chip --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -439,6 +439,17 @@ void init_irq_proc(void) register_irq_proc(irq, desc); } =20 +void irq_proc_update_valid(struct irq_desc *desc) +{ + u32 set =3D _IRQ_PROC_VALID; + + if (irq_settings_is_hidden(desc) || !desc->action || + irq_desc_is_chained(desc) || !desc->kstat_irqs) + set =3D 0; + + irq_settings_update_proc_valid(desc, set); +} + #ifdef CONFIG_GENERIC_IRQ_SHOW =20 int __weak arch_show_interrupts(struct seq_file *p, int prec) @@ -514,10 +525,7 @@ int show_interrupts(struct seq_file *p, =20 guard(rcu)(); desc =3D irq_to_desc(i); - if (!desc || irq_settings_is_hidden(desc)) - return 0; - - if (!desc->action || irq_desc_is_chained(desc) || !desc->kstat_irqs) + if (!desc || !irq_settings_proc_valid(desc)) return 0; =20 seq_printf(p, "%*d:", prec, i); --- a/kernel/irq/settings.h +++ b/kernel/irq/settings.h @@ -37,6 +37,9 @@ enum { #undef IRQF_MODIFY_MASK #define IRQF_MODIFY_MASK GOT_YOU_MORON =20 +#define _IRQ_PROC_VALID IRQF_RESERVED +#undef IRQF_RESERVED + static inline void irq_settings_clr_and_set(struct irq_desc *desc, u32 clr, u32 set) { @@ -180,3 +183,14 @@ static inline bool irq_settings_no_debug { return desc->status_use_accessors & _IRQ_NO_DEBUG; } + +static inline bool irq_settings_proc_valid(struct irq_desc *desc) +{ + return desc->status_use_accessors & _IRQ_PROC_VALID; +} + +static inline void irq_settings_update_proc_valid(struct irq_desc *desc, u= 32 set) +{ + desc->status_use_accessors &=3D ~_IRQ_PROC_VALID; + desc->status_use_accessors |=3D (set & _IRQ_PROC_VALID); +} From nobody Fri Apr 10 00:56:50 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DE4C73DA5A6 for ; Wed, 4 Mar 2026 18:56:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650562; cv=none; b=MJgABAs/yELuOwfiuCfktHgMg2fPFpxvWFXxJGJWiOg5LiTkd+ITDX20Ai0XrzEzno3b2kgNVZihEXQZhNzlt8yOK36n8qz631cQsxM4BwOb0g/eGUjmIyi13eTx+2WvgPg8XjFH8l5oW9dKZZfj9OTZupb6RBt+0gGr/ju+b+Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650562; c=relaxed/simple; bh=O6MV+XeAU0ooSXDYEg1TFDDp7I4Fk1tqjohxewwRhpc=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=nr5dNuL6ivXwgXsqXdQ9uQX6vm1dE5NwQ+/tRKLFJa60vHzjbNlw1l5ATaqT3JHIAf4R/ZaYrzuyEzu8M6PvCH2Io7rlQ9oC0FpZQ4DgLFFYTlXvtGZhslBlniEZVL4uDnEeUKm/JzH95Tqlu7CeYjRG4V7wcV3d5mIOS8TYjYA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XzmifzCy; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="XzmifzCy" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E5395C2BC86; Wed, 4 Mar 2026 18:56:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772650561; bh=O6MV+XeAU0ooSXDYEg1TFDDp7I4Fk1tqjohxewwRhpc=; h=Date:From:To:Cc:Subject:References:From; b=XzmifzCyqaUFONL690OycRs6smkEiXeTNJwxZNsgfMfWuA3fE23o/Cs+dMH9LEGlU 5xLWqFLXLT80ZoTJm9z0tkteB4X8g/Pyp0MntCqghGrAlyZOHUWoa52JzZ1WJ2oW8m qCrVRfk6MQdDpNVEjLZnF2NrrUx1gzBrxAdMm8KQH9+cvQjTQmKVZpnCnmxKnZslvD jfBhBufOaiqSKlV4e7gETenEkXnyi7Q5HNP1GHTf2lmuQL659deMeCmEKQyLyHWInC x+Sg9dcrOF3yf38c8aCF6ofveMEYGoOgGFgsRT6X/8KgGq01OZZzOHYdFb1adCkxQF EaEH+EFcs6swA== Date: Wed, 04 Mar 2026 19:55:58 +0100 Message-ID: <20260303154548.435226377@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman Subject: [patch 07/14] genirq: Calculate precision only when required References: <20260303150539.513068586@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Calculating the precision of the interrupt number column on every initial show_interrupt() invocation is a pointless exercise as the underlying maximum number of interrupts rarely changes. Calculate it only when that number is modified and let show_interrupts() use the cached value. Signed-off-by: Thomas Gleixner Reviewed-by: Dmitry Ilvokhin --- kernel/irq/internals.h | 2 ++ kernel/irq/irqdesc.c | 10 ++++++---- kernel/irq/proc.c | 28 +++++++++++++++++++--------- 3 files changed, 27 insertions(+), 13 deletions(-) --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -124,6 +124,7 @@ extern void unregister_irq_proc(unsigned extern void register_handler_proc(unsigned int irq, struct irqaction *acti= on); extern void unregister_handler_proc(unsigned int irq, struct irqaction *ac= tion); void irq_proc_update_valid(struct irq_desc *desc); +void irq_proc_calc_prec(void); #else static inline void register_irq_proc(unsigned int irq, struct irq_desc *de= sc) { } static inline void unregister_irq_proc(unsigned int irq, struct irq_desc *= desc) { } @@ -132,6 +133,7 @@ static inline void register_handler_proc static inline void unregister_handler_proc(unsigned int irq, struct irqaction *action) { } static inline void irq_proc_update_valid(struct irq_desc *desc) { } +static inline void irq_proc_calc_prec(void) { } #endif =20 extern bool irq_can_set_affinity_usr(unsigned int irq); --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -157,13 +157,12 @@ EXPORT_SYMBOL_GPL(irq_get_nr_irqs); * * Return: @nr. */ -unsigned int irq_set_nr_irqs(unsigned int nr) +unsigned int __init irq_set_nr_irqs(unsigned int nr) { total_nr_irqs =3D nr; - + irq_proc_calc_prec(); return nr; } -EXPORT_SYMBOL_GPL(irq_set_nr_irqs); =20 static DEFINE_MUTEX(sparse_irq_lock); static struct maple_tree sparse_irqs =3D MTREE_INIT_EXT(sparse_irqs, @@ -544,6 +543,7 @@ static bool irq_expand_nr_irqs(unsigned if (nr > MAX_SPARSE_IRQS) return false; total_nr_irqs =3D nr; + irq_proc_calc_prec(); return true; } =20 @@ -572,6 +572,7 @@ int __init early_irq_init(void) desc =3D alloc_desc(i, node, 0, NULL, NULL); irq_insert_desc(i, desc); } + irq_proc_calc_prec(); return arch_early_irq_init(); } =20 @@ -592,7 +593,7 @@ int __init early_irq_init(void) =20 init_irq_default_affinity(); =20 - printk(KERN_INFO "NR_IRQS: %d\n", NR_IRQS); + pr_info("NR_IRQS: %d\n", NR_IRQS); =20 count =3D ARRAY_SIZE(irq_desc); =20 @@ -602,6 +603,7 @@ int __init early_irq_init(void) goto __free_desc_res; } =20 + irq_proc_calc_prec(); return arch_early_irq_init(); =20 __free_desc_res: --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -457,10 +457,21 @@ int __weak arch_show_interrupts(struct s return 0; } =20 +static int irq_num_prec __read_mostly =3D 3; + #ifndef ACTUAL_NR_IRQS # define ACTUAL_NR_IRQS total_nr_irqs #endif =20 +void irq_proc_calc_prec(void) +{ + unsigned int prec, n; + + for (prec =3D 3, n =3D 1000; prec < 10 && n <=3D total_nr_irqs; ++prec) + n *=3D 10; + WRITE_ONCE(irq_num_prec, prec); +} + #define ZSTR1 " 0" #define ZSTR1_LEN 11 #define ZSTR16 ZSTR1 ZSTR1 ZSTR1 ZSTR1 ZSTR1 ZSTR1 ZSTR1 ZSTR1 \ @@ -499,8 +510,7 @@ void irq_proc_emit_counts(struct seq_fil =20 int show_interrupts(struct seq_file *p, void *v) { - const unsigned int nr_irqs =3D irq_get_nr_irqs(); - static int prec; + int prec =3D READ_ONCE(irq_num_prec); =20 int i =3D *(loff_t *) v, j; struct irqaction *action; @@ -514,9 +524,6 @@ int show_interrupts(struct seq_file *p, =20 /* print header and calculate the width of the first column */ if (i =3D=3D 0) { - for (prec =3D 3, j =3D 1000; prec < 10 && j <=3D nr_irqs; ++prec) - j *=3D 10; - seq_printf(p, "%*s", prec + 8, ""); for_each_online_cpu(j) seq_printf(p, "CPU%-8d", j); @@ -552,13 +559,16 @@ int show_interrupts(struct seq_file *p, } else { seq_printf(p, "%8s", "None"); } + + seq_putc(p, ' '); if (desc->irq_data.domain) - seq_printf(p, " %*lu", prec, desc->irq_data.hwirq); + seq_put_decimal_ull_width(p, "", desc->irq_data.hwirq, prec); else seq_printf(p, " %*s", prec, ""); -#ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL - seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "E= dge"); -#endif + + if (IS_ENABLED(CONFIG_GENERIC_IRQ_SHOW_LEVEL)) + seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "= Edge"); + if (desc->name) seq_printf(p, "-%-8s", desc->name); From nobody Fri Apr 10 00:56:50 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 06FD73CE49B for ; Wed, 4 Mar 2026 18:56:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650566; cv=none; b=pxDXZByF93Liv0mGiiJWiZ1VX2eoJ65HLHChv7bt0N9p2zooHVVGQeIB9Gt+ioxS9YQOR0rrXJP1cbirJD8uTqgXxyyLj8SBR7LYpKU6DBmX9R0W9P1NT0/cc5CCtwSqeJdF+HdrKm/3bZRqOjiH7Ds/lzKRiuF31MapIBWKlFo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650566; c=relaxed/simple; bh=euwJdLgeT7b9lR0hIlZSAhWMeg39XLuevPloetSJoSY=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=JCqk8SJ2OgtDUfRODJAhF7kt52df0ofMuSA1UJXbob83qTK0gnnHB0RQm4Y5k6oyEGRkTDgfv5oedvq5PmbK4ep0U3fbGgh8guEQRjEET+bkwGxzHXtQcIR+d+I9yzM8TRZyGhV0xkdqA9L2yQu5VhQ7JCI9zK3tIIeMIhlTpBw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kGx1Bkl0; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kGx1Bkl0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2E759C4CEF7; Wed, 4 Mar 2026 18:56:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772650565; bh=euwJdLgeT7b9lR0hIlZSAhWMeg39XLuevPloetSJoSY=; h=Date:From:To:Cc:Subject:References:From; b=kGx1Bkl0P6S0UT4ki4yGrxG9qqjmQHPC/a/zHmm3eT872GOUtql5cTUUpsYgMuUAS OEGyHEo5wQJjs7XdHVDUpjuf7mX6dQTwXv5CORSFnEM9Xk6D9A8XCjXU3hMzmQYeNm ka9uBw0O7NGIf/fPi7yzv8pRmmiq0OFXG66sQVdOfMuYQiK4huinhmr4AVfOLk0yOu FxyPE9q9gH7pLFCSNl+mJhML8QWPDkOIvqKj0WvkfuSCMcKsV/kkhSHUzmP4x+YAtu 0qL1SbEx9p7wExqrfBuua/63jZ2YAI1E11Mdq6TFWDdFNYstUxSHGmIG5tX2HZDTE9 JniHdgVbAH5lw== Date: Wed, 04 Mar 2026 19:56:03 +0100 Message-ID: <20260303154548.502647289@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman Subject: [patch 08/14] genirq: Add rcuref count to struct irq_desc References: <20260303150539.513068586@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Prepare for a smarter iterator for /proc/interrupts so that the next interrupt descriptor can be cached after lookup. Signed-off-by: Thomas Gleixner --- include/linux/irqdesc.h | 2 ++ kernel/irq/internals.h | 17 ++++++++++++++++- kernel/irq/irqdesc.c | 21 +++++++++++++-------- 3 files changed, 31 insertions(+), 9 deletions(-) --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -70,6 +70,7 @@ struct irq_redirect { * IRQF_NO_SUSPEND set * @force_resume_depth: number of irqactions on a irq descriptor with * IRQF_FORCE_RESUME set + * @refcnt: Reference count mainly for /proc/interrupts * @rcu: rcu head for delayed free * @kobj: kobject used to represent this struct in sysfs * @request_mutex: mutex to protect request/free before locking desc->lock @@ -119,6 +120,7 @@ struct irq_desc { struct dentry *debugfs_file; const char *dev_name; #endif + rcuref_t refcnt; #ifdef CONFIG_SPARSE_IRQ struct rcu_head rcu; struct kobject kobj; --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -9,6 +9,7 @@ #include #include #include +#include #include =20 #ifdef CONFIG_SPARSE_IRQ @@ -101,9 +102,23 @@ extern void unmask_irq(struct irq_desc * extern void unmask_threaded_irq(struct irq_desc *desc); =20 #ifdef CONFIG_SPARSE_IRQ -static inline void irq_mark_irq(unsigned int irq) { } +static __always_inline void irq_mark_irq(unsigned int irq) { } +void irq_desc_free_rcu(struct irq_desc *desc); + +static __always_inline bool irq_desc_get_ref(struct irq_desc *desc) +{ + return rcuref_get(&desc->refcnt); +} + +static __always_inline void irq_desc_put_ref(struct irq_desc *desc) +{ + if (rcuref_put(&desc->refcnt)) + irq_desc_free_rcu(desc); +} #else extern void irq_mark_irq(unsigned int irq); +static __always_inline bool irq_desc_get_ref(struct irq_desc *desc) { retu= rn true; } +static __always_inline void irq_desc_put_ref(struct irq_desc *desc) { } #endif =20 irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc); --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -137,6 +137,7 @@ static void desc_set_defaults(unsigned i desc->tot_count =3D 0; desc->name =3D NULL; desc->owner =3D owner; + rcuref_init(&desc->refcnt, 1); desc_smp_init(desc, node, affinity); } =20 @@ -465,6 +466,17 @@ static void delayed_free_desc(struct rcu kobject_put(&desc->kobj); } =20 +void irq_desc_free_rcu(struct irq_desc *desc) +{ + /* + * We free the descriptor, masks and stat fields via RCU. That + * allows demultiplex interrupts to do rcu based management of + * the child interrupts. + * This also allows us to use rcu in kstat_irqs_usr(). + */ + call_rcu(&desc->rcu, delayed_free_desc); +} + static void free_desc(unsigned int irq) { struct irq_desc *desc =3D irq_to_desc(irq); @@ -483,14 +495,7 @@ static void free_desc(unsigned int irq) */ irq_sysfs_del(desc); delete_irq_desc(irq); - - /* - * We free the descriptor, masks and stat fields via RCU. That - * allows demultiplex interrupts to do rcu based management of - * the child interrupts. - * This also allows us to use rcu in kstat_irqs_usr(). - */ - call_rcu(&desc->rcu, delayed_free_desc); + irq_desc_put_ref(desc); } =20 static int alloc_descs(unsigned int start, unsigned int cnt, int node, From nobody Fri Apr 10 00:56:50 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 100263D5242 for ; Wed, 4 Mar 2026 18:56:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650570; cv=none; b=LnXreDTYzEXhAatW5HgRZ+ioyFiZtvf1I+ccQejllxxsWUB09E87GuTY2hDz0yPYDkh06j6GnWqBsuFqX9nZ4ERGNGvmZbr4icsERcQO5ipLfGSzZ0TSkJJVeSN+igit9TiibhV6QPHcljpMhzPxt3ENBIC0ZaYA6KbA7PIVqew= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650570; c=relaxed/simple; bh=Uv2G0LOyhDTgHwb12rNvd64iifQKYLHJSBXNUsqoGcg=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=U+lQ66QA6hro0p++fIawQEGSWf9OEQBOaWzUixDpwJii25CpVylgCChoyPp9gQun/UB6zIBqzEhwmrYn+C1KvjIHNhQ5LOs+puDUcFuzeCpefJbUodpKyf+WJGOYIUZvs+eSsU/WfkM4dGEkXyB07bROuxiBwfdY2gB7iRHqpnQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=L3fyQp9Q; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="L3fyQp9Q" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4F6A0C4CEF7; Wed, 4 Mar 2026 18:56:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772650569; bh=Uv2G0LOyhDTgHwb12rNvd64iifQKYLHJSBXNUsqoGcg=; h=Date:From:To:Cc:Subject:References:From; b=L3fyQp9QHY0T0zbp9sN5wbB7AVKS7pPJ+E22vpwRjEHn1q3zP+xGSlhqaIFcpZD0c 0Osm9uXWJeGCj52ilrGUHytrRC6B32AlI3fOOUGubSKYLzvRYZbiCq3USqRLBod9EK pn1CEvwe05AAd/LWlgVQXZIsuzrpmNedQI7q1K3sGQ8KVAjwLwYIZwWxsmfBYERV1G f189DdYhRWsP9CzpAFfGeE9Hdmw2N3A3DtHIqlzELg11YVPullFxn0HeNxZqPLp5rF kKsEZ62sF53kZDJjurtVL4C8UTPLsPBtvsDSScyVUzHe51vQAkDQCKximHavxpl6hY NTHgu0Zov9ygw== Date: Wed, 04 Mar 2026 19:56:07 +0100 Message-ID: <20260303154548.571362045@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman Subject: [patch 09/14] genirq: Expose irq_find_desc_at_or_after() in core code References: <20260303150539.513068586@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" --- in preparation for a smarter iterator for /proc/interrupts. Signed-off-by: Thomas Gleixner --- kernel/irq/internals.h | 2 ++ kernel/irq/irqdesc.c | 12 +++++------- 2 files changed, 7 insertions(+), 7 deletions(-) --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -151,6 +151,8 @@ static inline void irq_proc_update_valid static inline void irq_proc_calc_prec(void) { } #endif =20 +struct irq_desc *irq_find_desc_at_or_after(unsigned int offset); + extern bool irq_can_set_affinity_usr(unsigned int irq); =20 extern int irq_do_set_affinity(struct irq_data *data, --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -181,15 +181,11 @@ static int irq_find_free_area(unsigned i return mas.index; } =20 -static unsigned int irq_find_at_or_after(unsigned int offset) +struct irq_desc *irq_find_desc_at_or_after(unsigned int offset) { unsigned long index =3D offset; - struct irq_desc *desc; - - guard(rcu)(); - desc =3D mt_find(&sparse_irqs, &index, total_nr_irqs); =20 - return desc ? irq_desc_get_irq(desc) : total_nr_irqs; + return mt_find(&sparse_irqs, &index, total_nr_irqs); } =20 static void irq_insert_desc(unsigned int irq, struct irq_desc *desc) @@ -934,7 +930,9 @@ EXPORT_SYMBOL_GPL(__irq_alloc_descs); */ unsigned int irq_get_next_irq(unsigned int offset) { - return irq_find_at_or_after(offset); + struct irq_desc *desc =3D irq_find_desc_at_or_after(offset); + + return desc ? irq_desc_get_irq(desc) : total_nr_irqs; } =20 struct irq_desc *__irq_get_desc_lock(unsigned int irq, unsigned long *flag= s, bool bus, From nobody Fri Apr 10 00:56:50 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0E4923D5242 for ; Wed, 4 Mar 2026 18:56:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650574; cv=none; b=JV/GMl5pyqVI5pM2/DeVh5VvpQ/exJeH449BOIzrv7PrqGQpEi4hL6Qss3ZvNBZQtV1dKTB/IVK4dR2HoLbdmAArOOc+yHCOoaHlss99xCzYHsEvKPgvhtlMK1E77xcc50V+7FAkzV7w4d5X6i1oQr2A75RSgYWTug1e0MGvlVQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650574; c=relaxed/simple; bh=O3APnRX8qmvXPCKagjJK3cyA8Md07uXBTpZEDOrJFKA=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=s4HYKA9v8x+NJDDDneEY/YQxpHmbjBEVp0srBJnJrJNoKPJOtRuYQx/XRZAKwShm7jfVkEdrARrntEFbF0yUi7cN4C+MaxfW8SnuuCpYahN9HlPAbsgQ2vXSKborerekv2koSSuaeRu73uEgrax51bMC535cA+I6ripZT001hF8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=cnfHdCsP; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="cnfHdCsP" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 82AFEC4CEF7; Wed, 4 Mar 2026 18:56:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772650573; bh=O3APnRX8qmvXPCKagjJK3cyA8Md07uXBTpZEDOrJFKA=; h=Date:From:To:Cc:Subject:References:From; b=cnfHdCsP769HuDrc00+sPexVCvdJyanbYkVGODd7+gVhTW0QqDU2Q+Ta49Hym1dnO hAmARYEuCCaHaOgvtSu0OX917baL/QD9LzU5RIXfbKmq5x0HEni3g5sMvhDB6KOKy9 eamkdYw81W98bRXsNVou2TBD9H9lFAhFCYbmeCJ+LYp+tzOwpOfgB0UYfUfvNmQGLE 4vzMp5pEZ3gufsKxV6ibqG+gp19J9Y70D02KD4rXoL94Zq94taUa87ZeZ6KimrP0Ev qanHjVVaJf3LTRduKGH+zPXluz3A/z3yYOS+T1N1u9MgVRzHnRJnO+jzkbaFb2ZL08 v2OAiMH8Or+Fw== Date: Wed, 04 Mar 2026 19:56:11 +0100 Message-ID: <20260303154548.638088280@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman Subject: [patch 10/14] genirq/proc: Speed up /proc/interrupts iteration References: <20260303150539.513068586@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Reading /proc/interrupts iterates over the interrupt number space one by one and looks up the descriptors one by one. That's just a waste of time. When CONFIG_GENERIC_IRQ_SHOW is enabled this can utilize the maple tree and cache the descriptor pointer efficiently for the sequence file operations. Implement a CONFIG_GENERIC_IRQ_SHOW specific version in the core code and leave the fs/proc/ variant for the legacy architectures which ignore generic code. This reduces the time wasted for looking up the next record significantly. Signed-off-by: Thomas Gleixner --- fs/proc/Makefile | 4 +- kernel/irq/proc.c | 99 +++++++++++++++++++++++++++++++++++++++++++------= ----- 2 files changed, 83 insertions(+), 20 deletions(-) --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -16,7 +16,9 @@ proc-y +=3D cmdline.o proc-y +=3D consoles.o proc-y +=3D cpuinfo.o proc-y +=3D devices.o -proc-y +=3D interrupts.o +ifneq ($(CONFIG_GENERIC_IRQ_SHOW),y) +proc-y +=3D interrupts.o +endif proc-y +=3D loadavg.o proc-y +=3D meminfo.o proc-y +=3D stat.o --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -452,6 +452,8 @@ void irq_proc_update_valid(struct irq_de =20 #ifdef CONFIG_GENERIC_IRQ_SHOW =20 +#define ARCH_PROC_IRQDESC ((void *)0x00001111) + int __weak arch_show_interrupts(struct seq_file *p, int prec) { return 0; @@ -508,34 +510,29 @@ void irq_proc_emit_counts(struct seq_fil irq_proc_emit_zero_counts(p, zeros); } =20 -int show_interrupts(struct seq_file *p, void *v) +static int irq_seq_show(struct seq_file *p, void *v) { - int prec =3D READ_ONCE(irq_num_prec); - - int i =3D *(loff_t *) v, j; + int prec =3D (int)(unsigned long)p->private; + struct irq_desc *desc =3D v; struct irqaction *action; - struct irq_desc *desc; - - if (i > ACTUAL_NR_IRQS) - return 0; =20 - if (i =3D=3D ACTUAL_NR_IRQS) + if (desc =3D=3D ARCH_PROC_IRQDESC) return arch_show_interrupts(p, prec); =20 - /* print header and calculate the width of the first column */ - if (i =3D=3D 0) { + /* print header for the first interrupt indicated by !p>private */ + if (!prec) { + unsigned int cpu; + + prec =3D READ_ONCE(irq_num_prec); seq_printf(p, "%*s", prec + 8, ""); - for_each_online_cpu(j) - seq_printf(p, "CPU%-8d", j); + for_each_online_cpu(cpu) + seq_printf(p, "CPU%-8d", cpu); seq_putc(p, '\n'); + p->private =3D (void *)(unsigned long)prec; } =20 - guard(rcu)(); - desc =3D irq_to_desc(i); - if (!desc || !irq_settings_proc_valid(desc)) - return 0; - - seq_printf(p, "%*d:", prec, i); + seq_put_decimal_ull_width(p, "", irq_desc_get_irq(desc), prec); + seq_putc(p, ':'); =20 /* * Always output per CPU interrupts. Output device interrupts only when @@ -582,4 +579,68 @@ int show_interrupts(struct seq_file *p, seq_putc(p, '\n'); return 0; } + +static void *irq_seq_next_desc(loff_t *pos) +{ + struct irq_desc *desc; + + if (*pos > total_nr_irqs) + return NULL; + + guard(rcu)(); + for (;;) { + desc =3D irq_find_desc_at_or_after((unsigned int) *pos); + if (desc) { + *pos =3D irq_desc_get_irq(desc); + /* + * If valid for output try to acquire a reference count + * on the descriptor so that it can't be freed after + * dropping RCU read lock on return. + */ + if (irq_settings_proc_valid(desc) && irq_desc_get_ref(desc)) + return desc; + (*pos)++; + } else { + *pos =3D total_nr_irqs; + return ARCH_PROC_IRQDESC; + } + } +} + +static void *irq_seq_start(struct seq_file *f, loff_t *pos) +{ + if (!*pos) + f->private =3D NULL; + return irq_seq_next_desc(pos); +} + +static void *irq_seq_next(struct seq_file *f, void *v, loff_t *pos) +{ + if (v && v !=3D ARCH_PROC_IRQDESC) + irq_desc_put_ref(v); + + (*pos)++; + return irq_seq_next_desc(pos); +} + +static void irq_seq_stop(struct seq_file *f, void *v) +{ + if (v && v !=3D ARCH_PROC_IRQDESC) + irq_desc_put_ref(v); +} + +static const struct seq_operations irq_seq_ops =3D { + .start =3D irq_seq_start, + .next =3D irq_seq_next, + .stop =3D irq_seq_stop, + .show =3D irq_seq_show, +}; + +static int __init irq_proc_init(void) +{ + proc_create_seq("interrupts", 0, NULL, &irq_seq_ops); + return 0; +} +fs_initcall(irq_proc_init); + #endif From nobody Fri Apr 10 00:56:50 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 75CCA3D412B for ; Wed, 4 Mar 2026 18:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650578; cv=none; b=mLv6wiPMA6HM555c/ESuMYrH4GPJ0mNXW5spPG/E8+Q5r0zlyTnpzqcD0VJvrPhMpgqKR0YT3M4aWDS/LlJJoT8sGXx24GLYlzRAgB42E8xHvJmplyfKwtmOawSSYseOk+W1eLGoQ5uGg0OrF7TmjVyiPBSzHipug+5k5VQ5mKI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650578; c=relaxed/simple; bh=LZ5V5KnNkhK0zSCP/yI0pLrdMCYdhpN1lNNhrspEuHc=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=KSqbqFjXIjJm8cLzETh1GCItpcbns7n463IO33+Nx4DClLbIImyFeSXZ710RySIzXziJ59DDLZi7dcbNqxU1SxLMZwwW9APW3HJDPqxX/Jt55fC7sDSvQXf9myU44atuNO06jw9+fh63nwxY2/a5k7L/KqV/pCsTLq6CLljrkIw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GHUXLy+i; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GHUXLy+i" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A4593C4CEF7; Wed, 4 Mar 2026 18:56:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772650578; bh=LZ5V5KnNkhK0zSCP/yI0pLrdMCYdhpN1lNNhrspEuHc=; h=Date:From:To:Cc:Subject:References:From; b=GHUXLy+if6QZ2gU8s0rcRSjG21eNDuT4MZtgU1CeC+8Q4Tkh8+m3qkx/7/x9e74FT qIX6Q7DpwFeXs6T6wvFHP7HL1AjH5rMRvpv2qgaUWzZwzVNPAMFybWaTBvvdis7FJn Wkuy+xVGu507Vpu2TlPZVos0iDBrHVCRvIMpVouawnGsaLqy/UE7l341tEbskUjOqB MV7o3u8plxxD39tMN8cVYUjuYd+GrvO3LBegRrnuHV4H+3YUZC82fPIBFRONu+XXkm 6ASEqWcmCQN50CQaP4h38sKP/ig9IXRGy4AlkTQA8fMvl85OcUSoJgVGt8Oh7EtUhh iYG+wnVxR73rg== Date: Wed, 04 Mar 2026 19:56:15 +0100 Message-ID: <20260303154548.705513675@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman Subject: [patch 11/14] [RFC] genirq: Cache target CPU for single CPU affinities References: <20260303150539.513068586@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Some places can be optimized by caching the target CPU for single CPU affinities. That avoids finding the single CPU in the effective affinity mask. Provide infrastructure for that. Signed-off-by: Thomas Gleixner --- include/linux/irq.h | 17 +++++++++++++++++ kernel/irq/manage.c | 14 ++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -140,6 +140,8 @@ struct irq_domain; * @effective_affinity: The effective IRQ affinity on SMP as some irq * chips do not allow multi CPU destinations. * A subset of @affinity. + * @target_cpu: The target CPU when @effective_affinity contains + * only a single CPU, IRQ_TARGET_MULTI_CPU otherwise * @msi_desc: MSI descriptor * @ipi_offset: Offset of first IPI target cpu in @affinity. Optional. */ @@ -155,6 +157,7 @@ struct irq_common_data { #endif #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK cpumask_var_t effective_affinity; + unsigned int target_cpu; #endif #ifdef CONFIG_GENERIC_IRQ_IPI unsigned int ipi_offset; @@ -903,6 +906,8 @@ static inline const struct cpumask *irq_ return d ? irq_data_get_affinity_mask(d) : NULL; } =20 +#define IRQ_TARGET_MULTI_CPU UINT_MAX + #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK static inline const struct cpumask *irq_data_get_effective_affinity_mask(struct irq_data= *d) @@ -914,6 +919,14 @@ static inline void irq_data_update_effec { cpumask_copy(d->common->effective_affinity, m); } +static inline unsigned int irq_data_get_single_target(struct irq_data *d) +{ + return d->common->target_cpu; +} +static inline void irq_data_set_single_target(struct irq_data *d, unsigned= int cpu) +{ + d->common->target_cpu =3D cpu; +} #else static inline void irq_data_update_effective_affinity(struct irq_data *d, const struct cpumask *m) @@ -924,6 +937,10 @@ const struct cpumask *irq_data_get_effec { return irq_data_get_affinity_mask(d); } +static inline unsigned int irq_data_get_single_target(struct irq_data *d) +{ + return IRQ_TARGET_MULTI_CPU; +} #endif =20 static inline --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -217,11 +217,17 @@ static void irq_validate_effective_affin { const struct cpumask *m =3D irq_data_get_effective_affinity_mask(data); struct irq_chip *chip =3D irq_data_get_irq_chip(data); + unsigned int target =3D IRQ_TARGET_MULTI_CPU; =20 - if (!cpumask_empty(m)) - return; - pr_warn_once("irq_chip %s did not update eff. affinity mask of irq %u\n", - chip->name, data->irq); + switch (cpumask_weight(m)) { + case 0: + pr_warn_once("irq_chip %s did not update eff. affinity mask of irq %u\n", + chip->name, data->irq); + break; + case 1: + target =3D cpumask_first(m); + } + irq_data_set_single_target(data, target); } #else static inline void irq_validate_effective_affinity(struct irq_data *data) = { } From nobody Fri Apr 10 00:56:50 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8391F36C0C0 for ; Wed, 4 Mar 2026 18:56:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650582; cv=none; b=Oa7fTP5Kuk5oSZpIpqHs0LSd32VBwMqXFIRYHBhvD1T3YISxfFzfTIj4aMHaPd2PxA9h026a2V2IFJFGp42C69h8xSrJADSZYsOaEN/EOMmr+shucBJq+y0XilqeLyO5YWwrKw/7KjG4MCYPwtyJbbLjAugbRipfk+HXmkNSPfs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650582; c=relaxed/simple; bh=61fhgSGiy5ROHd7OfsE5blduSs8gdWZQGM9chDZUlSk=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=EVvDKJOjk8Mm0hWn5UhKceMGfg+Nn7uKc9plCxwZBThUUloTvLhqZfdvFT+CN1RPzemfZwKdnQ9LjVE6rI3aot7zXyNKpdJg5574fxFwx7OrUoiNSLBbmPVNrlLSgB8mtfQVOPLsfmnyfGSabDQ7IfRXAMQ7vCsvrxDLWI1GK0E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=o0W3y/lj; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="o0W3y/lj" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C82E7C4CEF7; Wed, 4 Mar 2026 18:56:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772650582; bh=61fhgSGiy5ROHd7OfsE5blduSs8gdWZQGM9chDZUlSk=; h=Date:From:To:Cc:Subject:References:From; b=o0W3y/ljbi62+AJfzml57ODgqncf7MAp6Ehyo1nYAAnx/sAa3BKS2iufY25PF8r1Q iYq7LaY+rGTnU8uhU3h/MYTfpsttK85QInUUT0VOxg0eP9Ksv0AQ7cJaqN8ESG5COD JTiXYXa6BjP+m24IzyWHHnSL7YRt05rdbWwgH3Z23WAubOECfIXxjiwSV2wCKjXw/f CfB93ec+0CdIxiMMw7W1bYxnhF9CmtC4eICcRSGaPnraUqk97AGaPNibevb1uIVu1g LLmVtNTU3xBFJcbaUj9CNXvvF+VvlH5/cr+h7LlfDJaRObzH1fclFJ3BUQ3DSdVPdc aw9fjcemjCSlg== Date: Wed, 04 Mar 2026 19:56:19 +0100 Message-ID: <20260303154548.773390707@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman Subject: [patch 12/14] [RFC] genirq/proc: Provide binary statistic interface References: <20260303150539.513068586@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" /proc/interrupts is expensive to evaluate for monitoring because: - it is text based and contains a lot of information which is not relevant for interrupt frequency analysis. Due to the extra information like chip name, hardware interrupt number, interrupt action names, it has to take the interrupt descriptor lock to output those items into the seq_file buffer. That obviously interferes with high frequency interrupt workloads. - it contains both device interrupts, per CPU and architecture specific interrupt counters without being able to look at them separately. The file is seekable by some definition of seekable as the position can change when interrupts are requested or freed, so the data has to be read completely to get a coherent picture. - it emits records for requested interrupts even if their interrupt count is zero. - it always prints the per CPU counters even if all but one of them are zero. - converting numbers to text and then parsing the text back to numbers in user space is a pretty wasteful exercise Provide a new interface which addresses the above pain points: 1) The interface is binary and emits variable length records per interrupt. Each record starts with a header containing the interrupt number and the number of data entries following the header. The data entries consist of a CPU number and count pair. 2) Interrupts with a total count of zero are skipped and produce no output at all. 3) Interrupts which have a single CPU affinity either due to a restricted affinity mask or due to the underlying interrupt chip restricting a mask to a single CPU target emit only one data entry. That means they are not emitting the stale counts on previous target CPUs but they are not really interesting for interrupt frequency analysis as they are not changing and therefore pointless for accounting. 4) The interface separates device interrupts, per CPU interrupts and architecture specific interrupts. Per CPU and architecture specific interrupts can only be monitored, while device interrupts can also be steered by changing the affinity unless they are affinity managed by the kernel. Per CPU interrupts are only available on architectures, e.g. ARM64, which use the regular interrupt descriptor mechanism for per CPU interrupt handling. Architectures which have their own mechanics, e.g. x86, do not enable and provide the per CPU interface as those interrupts are covered by the architecture specific accounting. 5) The readout is fully lockless so it does not interfere with concurrent interrupt handling. 6) Seek is restricted to seek(fd, 0, SEEK_SET) as that's the only operation which makes sense due to the variable record length and the dynamics of interrupt request/free operations which influence the position of the records in the output. For all other seek() invocations return the current file position, which makes e.g. python happy as an error code causes the file open checks to mark the resulting file object non-seekable. Implement support for /proc/irq/device_stats and /proc/irq/percpu_stats. The support for architecture specific interrupt statistics is added in a separate step. Reading /proc/irq/device_stats on a 256 CPU x86 machine with 83 requested interrupts produces 13 records due to skipping zero count interrupts. It results in 13 * 16 =3D 208 bytes of data as all device interrupts on x86 are single CPU targeted. That readout takes ~8us time in the kernel, while the full /proc/interrupts readout takes about 360us. Signed-off-by: Thomas Gleixner --- include/uapi/linux/irqstats.h | 27 +++ kernel/irq/Kconfig | 3=20 kernel/irq/proc.c | 314 +++++++++++++++++++++++++++++++++++++= +++++ 3 files changed, 344 insertions(+) --- /dev/null +++ b/include/uapi/linux/irqstats.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +#ifndef LINUX_UAPI_IRQSTATS_H +#define LINUX_UAPI_IRQSTATS_H + +/** + * irq_proc_stat_cpu - Data record for /proc/irq/stats + * @cpu: The CPU associated to @cnt + * @cnt: The count assiciated to @cpu + */ +struct irq_proc_stat_cpu { + unsigned int cpu; + unsigned int cnt; +}; + +/** + * irq_proc_stat_data - Data header for /proc/irq/stats + * @irqnr: The interrupt number + * @entries: The number of records (max. nr_cpu_ids) + * @pcpu: Runtime sized array of per CPU stat records + */ +struct irq_proc_stat_data { + unsigned int irqnr; + unsigned int entries; + struct irq_proc_stat_cpu pcpu[]; +}; + +#endif --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig @@ -18,6 +18,9 @@ config GENERIC_IRQ_SHOW config GENERIC_IRQ_SHOW_LEVEL bool =20 +config GENERIC_IRQ_STATS_PERCPU + bool + # Supports effective affinity mask config GENERIC_IRQ_EFFECTIVE_AFF_MASK depends on SMP --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include =20 #include "internals.h" =20 @@ -636,9 +638,321 @@ static const struct seq_operations irq_s .show =3D irq_seq_show, }; =20 +/* + * /proc/irq/stats related code + * + * /proc/irq/stats provides variable record sized statistics for device + * interrupts. + */ +struct irq_proc_stat { + unsigned int irqnr; + bool percpu; + bool first; + size_t from; + size_t count; + loff_t read_pos; + struct irq_desc *desc; + struct irq_proc_stat_data *data; +}; + +static inline bool irq_stat_valid_irq(struct irq_proc_stat *s) +{ + struct irq_desc *desc =3D s->desc; + + /* Check for general validity */ + if (!irq_settings_proc_valid(desc)) + return false; + + if (!s->percpu) { + /* + * Device interrupts update desc::tot_count. Per CPU + * interrupts are not touching that fields due to the + * obvious concurrency issues. For device interrupts it's + * therefore sufficient to evaluate desc::tot_count. + */ + if (!data_race(desc->tot_count)) + return false; + } else { + /* + * Per CPU interrupts are marked accordingly in the + * settings. + */ + if (!irq_settings_is_per_cpu(desc) && !irq_settings_is_per_cpu_devid(des= c)) + return false; + } + + /* Try to get a reference to prevent freeing before it's evaluated */ + return irq_desc_get_ref(desc); +} + +static inline bool irq_stat_find_irq(struct irq_proc_stat *s) +{ + /* Loop until a valid interrupt is found */ + guard(rcu)(); + for (;; s->irqnr++) { + s->desc =3D irq_find_desc_at_or_after(s->irqnr); + /* NULL means there is no interrupt anymore in the maple tree */ + if (!s->desc) { + s->irqnr =3D total_nr_irqs; + return false; + } + + /* Save the interrupt number for the next search */ + s->irqnr =3D irq_desc_get_irq(s->desc); + + if (irq_stat_valid_irq(s)) + return true; + } +} + +static inline void irq_stat_next_irq(struct irq_proc_stat *s) +{ + s->irqnr++; + irq_stat_find_irq(s); +} + +static void irq_dev_stat_update_one(struct irq_proc_stat *s) +{ + struct irq_proc_stat_data *d =3D s->data; + struct irq_desc *desc =3D s->desc; + struct irq_data *irqd; + unsigned int cpu; + + /* + * Optimize for single CPU target affinities. Otherwise walk the + * effective affinity mask, which falls back to the real affinity + * mask if the architecture does not support effective affinity + * masks. Bad luck... + */ + irqd =3D irq_desc_get_irq_data(desc); + cpu =3D irq_data_get_single_target(irqd); + if (cpu < nr_cpu_ids) { + struct irq_proc_stat_cpu pcpu =3D { + .cpu =3D cpu, + .cnt =3D data_race(per_cpu(desc->kstat_irqs->cnt, cpu)), + }; + + if (pcpu.cnt) + d->pcpu[d->entries++] =3D pcpu; + } else { + const struct cpumask *m =3D irq_data_get_effective_affinity_mask(irqd); + + for_each_cpu(cpu, m) { + struct irq_proc_stat_cpu pcpu =3D { + .cpu =3D cpu, + .cnt =3D data_race(per_cpu(desc->kstat_irqs->cnt, cpu)), + }; + + if (pcpu.cnt) + d->pcpu[d->entries++] =3D pcpu; + } + } +} + +static void irq_percpu_stat_update_one(struct irq_proc_stat *s) +{ + struct irq_proc_stat_data *d =3D s->data; + struct irq_desc *desc =3D s->desc; + unsigned int cpu; + + for_each_online_cpu(cpu) { + struct irq_proc_stat_cpu pcpu =3D { + .cpu =3D cpu, + .cnt =3D data_race(per_cpu(desc->kstat_irqs->cnt, cpu)), + }; + + if (pcpu.cnt) + d->pcpu[d->entries++] =3D pcpu; + } +} + +static bool irq_stat_update_one(struct irq_proc_stat *s) +{ + struct irq_proc_stat_data *d =3D s->data; + + if (IS_ENABLED(CONFIG_GENERIC_IRQ_PERCPU_STATS) && s->percpu) + irq_percpu_stat_update_one(s); + else + irq_dev_stat_update_one(s); + + /* Only output data if there is an actual count */ + if (d->entries) { + d->irqnr =3D s->irqnr; + s->count =3D sizeof(*d) + d->entries * sizeof(*d->pcpu); + } + + /* Drop the reference count which got acquired in irq_stat_find_irq() */ + irq_desc_put_ref(s->desc); + s->desc =3D NULL; + return !!s->count; +} + +static __always_inline bool irq_stat_next_data(struct irq_proc_stat *s) +{ + /* + * On the first read or after a lseek(fd, 0, SEEK_SET) find the + * first interrupt. Otherwise find the next one. + */ + if (unlikely(s->first)) { + s->irqnr =3D 0; + s->first =3D false; + irq_stat_find_irq(s); + } else { + irq_stat_next_irq(s); + } + + /* Repeat until an interrupt with non-zero counts is found */ + for (; s->desc; irq_stat_next_irq(s)) { + if (irq_stat_update_one(s)) + return true; + } + return false; +} + +static size_t irq_stat_copy_to_iter(struct irq_proc_stat *s, struct iov_it= er *iter) +{ + size_t n =3D copy_to_iter(((char *)s->data) + s->from, s->count, iter); + + s->count -=3D n; + s->from +=3D n; + return n; +} + +/* Force inline as otherwise next() becomes a indirect call */ +static __always_inline ssize_t __irq_stats_read(struct kiocb *iocb, struct= iov_iter *iter, + bool (*next)(struct irq_proc_stat *)) +{ + struct irq_proc_stat *s =3D iocb->ki_filp->private_data; + size_t copied =3D 0; + + /* Real seek is not supported. See irq_stat_lseek() */ + if (WARN_ON_ONCE(iocb->ki_pos !=3D s->read_pos)) + goto done; + + if (s->count) + copied +=3D irq_stat_copy_to_iter(s, iter); + + for (; !s->count;) { + s->count =3D s->from =3D 0; + s->data->entries =3D 0; + + if (!next(s)) + goto done; + copied +=3D irq_stat_copy_to_iter(s, iter); + } + + if (!copied) + return -EFAULT; +done: + iocb->ki_pos +=3D copied; + s->read_pos +=3D copied; + return copied; +} + +static ssize_t irq_stats_read(struct kiocb *iocb, struct iov_iter *iter) +{ + return __irq_stats_read(iocb, iter, irq_stat_next_data); +} + +static loff_t irq_stats_llseek(struct file *filp, loff_t offset, int whenc= e) +{ + struct irq_proc_stat *s =3D filp->private_data; + loff_t ret; + + /* + * As this is a variable record interface and the actual use case is to + * get a full snapshot of the active interrupts, there is no point in + * trying to be fully seekable. Just support rewind to the beginning of + * the data set. For all other operations return the current position + * which makes e.g. python happy. + */ + if (whence !=3D SEEK_SET || offset) + return noop_llseek(filp, offset, whence); + + ret =3D default_llseek(filp, 0, SEEK_SET); + if (ret < 0) + return ret; + + /* Reset the position, drop any leftovers and indicate to start over */ + s->read_pos =3D 0; + s->count =3D 0; + s->first =3D true; + return 0; +} + +static int __irq_stats_open(struct inode *inode, struct file *filp, bool p= ercpu) +{ + struct irq_proc_stat *s =3D kzalloc_obj(*s); + + if (!s) + return -ENOMEM; + + s->data =3D kzalloc_flex(*s->data, pcpu, num_possible_cpus()); + if (!s->data) { + kfree(s); + return -ENOMEM; + } + + s->first =3D true; + s->percpu =3D percpu; + filp->private_data =3D s; + return 0; +} + +static int irq_stats_open(struct inode *inode, struct file *filp) +{ + return __irq_stats_open(inode, filp, false); +} + +static int irq_stats_release(struct inode *inode, struct file *filp) +{ + struct irq_proc_stat *s =3D filp->private_data; + + if (s) { + kfree(s->data); + kfree(s); + } + return 0; +} + +static const struct proc_ops irq_dev_stat_ops =3D { + .proc_flags =3D PROC_ENTRY_PERMANENT, + .proc_open =3D irq_stats_open, + .proc_release =3D irq_stats_release, + .proc_read_iter =3D irq_stats_read, + .proc_lseek =3D irq_stats_llseek, +}; + +#ifdef CONFIG_GENERIC_IRQ_STATS_PERCPU +static int irq_pcp_stats_open(struct inode *inode, struct file *filp) +{ + return __irq_stats_open(inode, filp, true); +} + +static const struct proc_ops irq_pcp_stat_ops =3D { + .proc_flags =3D PROC_ENTRY_PERMANENT, + .proc_open =3D irq_pcp_stats_open, + .proc_release =3D irq_stats_release, + .proc_read_iter =3D irq_stats_read, + .proc_lseek =3D irq_stats_llseek, +}; + +static __init void irq_pcp_stats_init(void) +{ + proc_create("percpu_stats", 0, root_irq_dir, &irq_pcp_stat_ops); +} +#else /* CONFIG_GENERIC_IRQ_STATS_PERCPU */ +static inline void irq_pcp_stats_init(void) { } +#endif /* !CONFIG_GENERIC_IRQ_STATS_PERCPU */ + static int __init irq_proc_init(void) { proc_create_seq("interrupts", 0, NULL, &irq_seq_ops); + if (!root_irq_dir) + return 0; + + proc_create("device_stats", 0, root_irq_dir, &irq_dev_stat_ops); + irq_pcp_stats_init(); return 0; } fs_initcall(irq_proc_init); From nobody Fri Apr 10 00:56:51 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 278C33DA5DD for ; Wed, 4 Mar 2026 18:56:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650587; cv=none; b=P0LOiipvEhIztNji0ETB/Sqjgnno/74eLwryECK/6w9IjIUX6DTq6rPsjjbmYIan7r9QZcuUqeS2YuRINUCwN7ttF0DmA0kJv13WzBOdOMqfxZSRikZY/4xUkC5hYzIDsLWy1/Exwpyzuwohds/zUxg+a3pnrD1NsvttSW0LRLg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650587; c=relaxed/simple; bh=PGEc4KC2iWY9rDhQYE7v/0YdgSyfeejBfw29Au/4+4o=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=YiKcf0UNW3KUSCSgIU2Kj/KrKesfk/VFSDyp98lr/O3NYxL80+PWCIPw3387a21lN62Ti04lXMtArt9Bgu2Yl+ViADXyphO21eeTYsCIw/JJvCPJxrmCJDWARKTULGLaZg3KT9zGNxAtVFjpPlOz1RcYOZ1BjUh0UrwXHbymAG4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ojGrX0gy; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ojGrX0gy" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4D873C4CEF7; Wed, 4 Mar 2026 18:56:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772650586; bh=PGEc4KC2iWY9rDhQYE7v/0YdgSyfeejBfw29Au/4+4o=; h=Date:From:To:Cc:Subject:References:From; b=ojGrX0gyijSnbKZihkwRS/N2r9FErkkpP5jRSfvyV3rJuN69Jij2t+/i1qJ2uyHHN j6cwbOGWsscVegxOt3wyKxKr70UWZQaQZLtfdCTJo9YzbRDlaB+l+wKuxZeOPp93GC hVfv++9xtmSoho7LFqsRtmOkeRVvS0GteogHX5qvGLf7dkwnujMQ80ZeI8C6YgomLQ HD0AZRuJ94mxfUqkYF7+ZVIzz2L9ugPwv1F/7CthoyVkEaER2kli/xrINCixoDiH17 xGunbNYzMzbUh+/nDXxH2268KRsXVAcO6Jr9D2iXzaGVUpJd7XbBfXVnc0lXr6xzqS hIXliGWqnlBYw== Date: Wed, 04 Mar 2026 19:56:24 +0100 Message-ID: <20260303154548.840416557@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman Subject: [patch 13/14] [RFC] genirq/proc: Provide architecture specific binary statistics References: <20260303150539.513068586@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Provide a binary statistics interface similar to the per device and per CPU interfaces to access the architecture specific interrupt statistics. The architecture has to select it in Kconfig and provide an accessor to the per CPU interrupt information and the number of architecture specific entries. The entries are ordered by a numerical index starting from 0, which corresponds to the ordering of those interrupts in /proc/interrupt. The output format is the same as for the per device and per CPU interfaces and only contains entries which have an interrupt count > 0. Reading the architecture specific counters of a 256 CPU x86 system takes 36us kernel time for 6 interrupts with non-zero counts and produces about 10k of data. Signed-off-by: Thomas Gleixner --- kernel/irq/Kconfig | 3 ++ kernel/irq/proc.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++= +++++ 2 files changed, 59 insertions(+) --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig @@ -18,6 +18,9 @@ config GENERIC_IRQ_SHOW config GENERIC_IRQ_SHOW_LEVEL bool =20 +config GENERIC_IRQ_STATS_ARCH + bool + config GENERIC_IRQ_STATS_PERCPU bool =20 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -945,6 +945,61 @@ static __init void irq_pcp_stats_init(vo static inline void irq_pcp_stats_init(void) { } #endif /* !CONFIG_GENERIC_IRQ_STATS_PERCPU */ =20 +#ifdef CONFIG_GENERIC_IRQ_STATS_ARCH +static inline void arch_stat_update_one(struct irq_proc_stat *s) +{ + struct irq_proc_stat_data *d =3D s->data; + unsigned int cpu, idx =3D s->irqnr; + + for_each_online_cpu(cpu) { + struct irq_proc_stat_cpu pcpu =3D { + .cpu =3D cpu, + .cnt =3D arch_get_irq_stat(cpu, idx), + }; + + if (pcpu.cnt) + d->pcpu[d->entries++] =3D pcpu; + } + + if (d->entries) { + d->irqnr =3D idx; + s->count =3D sizeof(*d) + d->entries * sizeof(*d->pcpu); + } +} + +static __always_inline bool arch_stat_next_data(struct irq_proc_stat *s) +{ + if (unlikely(s->first)) { + s->irqnr =3D 0; + s->first =3D false; + } + + for(; !s->count && s->irqnr < ARCH_IRQ_STATS_NUM_IRQS; s->irqnr++) + arch_stat_update_one(s); + return !!s->count; +} + +static ssize_t irq_arch_stats_read(struct kiocb *iocb, struct iov_iter *it= er) +{ + return __irq_stats_read(iocb, iter, arch_stat_next_data); +} + +static const struct proc_ops irq_arch_stat_ops =3D { + .proc_flags =3D PROC_ENTRY_PERMANENT, + .proc_open =3D irq_stats_open, + .proc_release =3D irq_stats_release, + .proc_read_iter =3D irq_arch_stats_read, + .proc_lseek =3D irq_stats_llseek, +}; + +static __init void irq_arch_stats_init(void) +{ + proc_create("arch_stats", 0, root_irq_dir, &irq_arch_stat_ops); +} +#else /* CONFIG_GENERIC_IRQ_STATS_ARCH */ +static inline void irq_arch_stats_init(void) { } +#endif /* !CONFIG_GENERIC_IRQ_STATS_ARCH */ + static int __init irq_proc_init(void) { proc_create_seq("interrupts", 0, NULL, &irq_seq_ops); @@ -953,6 +1008,7 @@ static int __init irq_proc_init(void) =20 proc_create("device_stats", 0, root_irq_dir, &irq_dev_stat_ops); irq_pcp_stats_init(); + irq_arch_stats_init(); return 0; } fs_initcall(irq_proc_init); From nobody Fri Apr 10 00:56:51 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0C5D43DEAC4 for ; Wed, 4 Mar 2026 18:56:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650591; cv=none; b=uHhR3qx2QTrTGyfATkKqXcHpn7hF5a+GxSALxKDDLdO1CqDLCb8n/0A/ttxBwYNK9i8ZUuSqkq6KvliF2umPEXp+MbbTOdWAufKzG8YD0au6+6xwOFCf0Vh5RVYlDUtWBExNVGyQLMq6C5XeeU19h1BtPrB0X1OomZT68g0gagE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772650591; c=relaxed/simple; bh=QbC1t90YvyHplW2TxJf6x38jggAFTIZypPZm8R7wXV8=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=m/5J2CZxDHlvvVuDcRuJYgKTHn1fe7yq3Vxx8Nn+Suu3ARvqwsrbiaOrzi9xxNllcu4CcZgTrhJgW36OEWc4ItPPO5Muwxu6sEUX2M16U0zOc9IRjTsDTtQJEKCuZQ4zBPQyVdttEZ00L/m5OUjul2WTluVhqE+ckeQF49KeIKA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=nAZsRjsv; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="nAZsRjsv" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 800C4C19425; Wed, 4 Mar 2026 18:56:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772650590; bh=QbC1t90YvyHplW2TxJf6x38jggAFTIZypPZm8R7wXV8=; h=Date:From:To:Cc:Subject:References:From; b=nAZsRjsvSV2emPsxEMbOgyEr3QOr4i2YvTggbaesEwrOrhkEoYPXYah6VWcGV4oL5 +6XeVcxIk6QtX6SoN8cJrLaxbHljqFWFsPtdqQ/5yu1cYW2Y+UALtMZHV8svAdFun8 eph7FbPlYPCIxvSxr/4G2RfxcvfNCd+rXqY+1v1v0W51HQI9HIfJIE5+zpU381ZCj2 ENfpG/v0zKEI6582Lp50WmvhLCc7EEgp7wB84IQNsd1v5RRbcgpJ2pBQ2tLa7eCkyR gNeU9RB7vffkGQJaJtI60djHdeG7TW9nKVhBVnDqYvPbnXV9KIVIYwN50I7lOkcjIl 0a7nul7sLffiw== Date: Wed, 04 Mar 2026 19:56:28 +0100 Message-ID: <20260303154548.907517219@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman Subject: [patch 14/14] [RFC] x86/irq: Hook up architecture specific stats References: <20260303150539.513068586@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Enable the binary statistics interface for architecture specific interrupts. Signed-off-by: Thomas Gleixner --- arch/x86/Kconfig | 1 + arch/x86/include/asm/hardirq.h | 7 +++++++ 2 files changed, 8 insertions(+) --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -177,6 +177,7 @@ config X86 select GENERIC_IRQ_PROBE select GENERIC_IRQ_RESERVATION_MODE select GENERIC_IRQ_SHOW + select GENERIC_IRQ_STATS_ARCH select GENERIC_PENDING_IRQ if SMP select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL --- a/arch/x86/include/asm/hardirq.h +++ b/arch/x86/include/asm/hardirq.h @@ -65,7 +65,14 @@ DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpust #ifdef CONFIG_X86_POSTED_MSI DECLARE_PER_CPU_ALIGNED(struct pi_desc, posted_msi_pi_desc); #endif + #define __ARCH_IRQ_STAT +#define ARCH_IRQ_STATS_NUM_IRQS IRQ_COUNT_MAX + +static inline unsigned int arch_get_irq_stat(unsigned int cpu, unsigned in= t idx) +{ + return data_race(per_cpu_ptr(&irq_stat, cpu)->counts[idx]); +} =20 #define inc_irq_stat(index) this_cpu_inc(irq_stat.counts[IRQ_COUNT_##index= ])