From mboxrd@z Thu Jan 1 00:00:00 1970 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 28C543B9604 for ; Fri, 20 Mar 2026 13:21:29 +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=1774012890; cv=none; b=BrE44MOoqq+PMBMbo0t4ii3ZyJok/fN1n4LbT+/V3F35Y2x045nlscaOlstqx+5slDekRaTyoLRuPFqT6lhirgTpqhYNxVJobYfGpT8wUtRp96labvX4mqMkPXV67QHB80heN+JGtC1+jV7D9/PfoajDveltY1dzdsIv0KM6aDk= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774012890; c=relaxed/simple; bh=bWuExAxSaUYUHb2XrrPt/Xuf/wNrsHCDu0Vgp2hIZvY=; h=Date:Message-ID:From:To:Cc:Subject; b=RcAYleEub4eRBtb61fZ4wuZ1lrCCWWMAO8ErtsQmX64f6zCcJofcMVVRqGNGXI27gBxjXCHsnDz+x7jPRiB/PYy6xIowsNtDA9yQ+71V1A1qWInuoRAnNRf6LIVfGdu3KQEphlAlm3SYU4+9alOKA+WXTeENz1+IM7KEsCfqbnU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MTI/MI4R; 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="MTI/MI4R" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5801DC2BCB2; Fri, 20 Mar 2026 13:21:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774012889; bh=bWuExAxSaUYUHb2XrrPt/Xuf/wNrsHCDu0Vgp2hIZvY=; h=Date:From:To:Cc:Subject:From; b=MTI/MI4RQXU/4SdoFPRl2CMcwRIaa3FuieoZu6GM1jDqCrZ9BStxvWRv358DlD2KS H4eMcEbPOxg9wdnkp8jaPYqxqazqxW0QJcbFwapcxKfns/BGReCQXxi6jTZm74lG5P ZNohJjCWbyhYv7RL4ztmHdE2o9qd1ceelmj9aBUtfXDPgcIR3P56LszolgTmA3cefn e80KN/xGIJZEgxxT0yqx3w/KjLAxZF+MmBhArcyDIluRhtNZ0rLh5WNnKFkphPkBpw IRE416iLP/uSOXfKtp+oPnu5dQ04I4owSdmY8LTp+AVAsNe33gJ4dQHShu3cDxpj7X 48RGmqzarSzWA== Date: Fri, 20 Mar 2026 14:21:26 +0100 Message-ID: <20260320131108.344376329@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Dmitry Ilvokhin , Neil Horman , Radu Rendec Subject: [patch v2 00/14] Improve /proc/interrupts further and add a binary interface Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: This is a follow up to v1 which can be found here: https://lore.kernel.org/20260303150539.513068586@kernel.org The v1 cover letter contains a full analysis, explanation and numbers. TLDR: - The performance of reading of /proc/interrupts has been improved piecewise over the years, but most of the low hanging fruit has been left on the table. - For a long time a binary readout interface was considered to be the better option, but it never materialized. The series fixes the real big performance issues and provides a design study for a binary interface. Changes vs. V1: - Addressed the review comments from Dmitry and Michael - Slightly changed the approach to skip x86 vectors - Picked up tags where appropriate The last four patches related to the binary interface need obviously some thought vs. the interface and are therefore still marked RFC. Delta patch against v1 is below. The series applies on top of v7.0-rc3 and is also available via git: git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git irq/core Thanks, tglx --- diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h index b0186f22a19e..544e6b7bb499 100644 --- a/arch/x86/include/asm/hardirq.h +++ b/arch/x86/include/asm/hardirq.h @@ -17,8 +17,8 @@ enum { #ifdef CONFIG_SMP IRQ_COUNT_RESCHEDULE, IRQ_COUNT_CALL_FUNCTION, - IRQ_COUNT_TLB, #endif + IRQ_COUNT_TLB, #ifdef CONFIG_X86_THERMAL_VECTOR IRQ_COUNT_THERMAL_APIC, #endif diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h index 194dfff84cb1..25d22e33e58c 100644 --- a/arch/x86/include/asm/irq.h +++ b/arch/x86/include/asm/irq.h @@ -47,4 +47,6 @@ void arch_trigger_cpumask_backtrace(const struct cpumask *mask, #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace #endif +void irq_init_stats(void); + #endif /* _ASM_X86_IRQ_H */ diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index 6af2c622bfb1..8f8485a8abdf 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -191,7 +191,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_stimer0) { struct pt_regs *old_regs = set_irq_regs(regs); - inc_irq_stat(HYPERV_STIMER0) + inc_irq_stat(HYPERV_STIMER0); if (hv_stimer0_handler) hv_stimer0_handler(); add_interrupt_randomness(HYPERV_STIMER0_VECTOR); diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index bfa189e5a3b6..2bd8c08f8d91 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -63,7 +63,7 @@ void ack_bad_irq(unsigned int irq) } struct irq_stat_info { - unsigned int test_vector; + unsigned int skip_vector; const char *symbol; const char *text; }; @@ -71,9 +71,9 @@ struct irq_stat_info { #define ISS(idx, sym, txt) [IRQ_COUNT_##idx] = { .symbol = sym, .text = txt } #define ITS(idx, sym, txt) [IRQ_COUNT_##idx] = \ - { .test_vector = idx## _VECTOR, .symbol = sym, .text = txt } + { .skip_vector = idx## _VECTOR, .symbol = sym, .text = txt } -static const struct irq_stat_info irq_stat_info[IRQ_COUNT_MAX] = { +static struct irq_stat_info irq_stat_info[IRQ_COUNT_MAX] __ro_after_init = { ISS(NMI, "NMI", " Non-maskable interrupts\n"), #ifdef CONFIG_X86_LOCAL_APIC ISS(APIC_TIMER, "LOC", " Local timer interrupts\n"), @@ -86,8 +86,8 @@ static const struct irq_stat_info irq_stat_info[IRQ_COUNT_MAX] = { #ifdef CONFIG_SMP ISS(RESCHEDULE, "RES", " Rescheduling interrupts\n"), ISS(CALL_FUNCTION, "CAL", " Function call interrupts\n"), - ISS(TLB, "TLB", " TLB shootdowns\n"), #endif + ISS(TLB, "TLB", " TLB shootdowns\n"), #ifdef CONFIG_X86_THERMAL_VECTOR ISS(THERMAL_APIC, "TRM", " Thermal event interrupt\n"), #endif @@ -105,7 +105,7 @@ static const struct irq_stat_info irq_stat_info[IRQ_COUNT_MAX] = { ITS(HYPERVISOR_CALLBACK, "HYP", " Hypervisor callback interrupts\n"), #endif #if IS_ENABLED(CONFIG_HYPERV) - ITS(HYPERV_REENLIGHTMENT, "HRE", " Hyper-V reenlightment interrupts\n"), + ITS(HYPERV_REENLIGHTENMENT, "HRE", " Hyper-V reenlightment interrupts\n"), ITS(HYPERV_STIMER0, "HVS", " Hyper-V stimer0 interrupts\n"), #endif #if IS_ENABLED(CONFIG_KVM) @@ -121,6 +121,24 @@ static const struct irq_stat_info irq_stat_info[IRQ_COUNT_MAX] = { #endif }; +void __init irq_init_stats(void) +{ + struct irq_stat_info *info = irq_stat_info; + + for (unsigned int i = 0; i < ARRAY_SIZE(irq_stat_info); i++, info++) { + if (info->skip_vector && test_bit(info->skip_vector, system_vectors)) + info->skip_vector = 0; + } + + if (!x86_platform_ipi_callback) + irq_stat_info[IRQ_COUNT_X86_PLATFORM_IPI].skip_vector = 1; + +#ifdef CONFIG_X86_POSTED_MSI + if (!posted_msi_enabled()) + irq_stat_info[IRQ_COUNT_X86_POSTED_MSI].skip_vector = 1; +#endif +} + /* * /proc/interrupts printing for arch specific interrupts */ @@ -129,7 +147,7 @@ int arch_show_interrupts(struct seq_file *p, int prec) const struct irq_stat_info *info = irq_stat_info; for (unsigned int i = 0; i < ARRAY_SIZE(irq_stat_info); i++, info++) { - if (info->test_vector && !test_bit(info->test_vector, system_vectors)) + if (info->skip_vector) continue; seq_printf(p, "%*s:", prec, info->symbol); @@ -137,9 +155,9 @@ int arch_show_interrupts(struct seq_file *p, int prec) seq_puts(p, info->text); } - seq_printf(p, "ERR: %10u\n", (unsigned int) atomic_read(&irq_err_count)); + seq_printf(p, "%*s: %10u\n", prec, "ERR", 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)); + seq_printf(p, "%*s: %10u\n", prec, "MIS", atomic_read(&irq_mis_count)); return 0; } @@ -245,7 +263,7 @@ DEFINE_IDTENTRY_IRQ(common_interrupt) #ifdef CONFIG_X86_LOCAL_APIC /* Function pointer for generic interrupt vector handling */ -void (*x86_platform_ipi_callback)(void) = NULL; +void (*x86_platform_ipi_callback)(void) __ro_after_init = NULL; /* * Handler for X86_PLATFORM_IPI_VECTOR. */ diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c index 6ab9eac64670..325c0ad8fb9c 100644 --- a/arch/x86/kernel/irqinit.c +++ b/arch/x86/kernel/irqinit.c @@ -104,6 +104,8 @@ void __init native_init_IRQ(void) if (!cpu_feature_enabled(X86_FEATURE_FRED)) idt_setup_apic_and_irq_gates(); + irq_init_stats(); + lapic_assign_system_vectors(); if (!acpi_ioapic && !of_ioapic && nr_legacy_irqs()) { diff --git a/include/linux/irq.h b/include/linux/irq.h index b44c90aabe53..9d0929b1feaf 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -99,7 +99,7 @@ enum { IRQ_DISABLE_UNLAZY = (1 << 19), IRQ_HIDDEN = (1 << 20), IRQ_NO_DEBUG = (1 << 21), - IRQF_RESERVED = (1 << 22), + IRQ_RESERVED = (1 << 22), }; #define IRQF_MODIFY_MASK \ diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 3859cef24d58..37eec0337867 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -139,7 +139,6 @@ extern void unregister_irq_proc(unsigned int irq, struct irq_desc *desc); extern void register_handler_proc(unsigned int irq, struct irqaction *action); extern void unregister_handler_proc(unsigned int irq, struct irqaction *action); 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 *desc) { } static inline void unregister_irq_proc(unsigned int irq, struct irq_desc *desc) { } @@ -148,6 +147,11 @@ static inline void register_handler_proc(unsigned int irq, static inline void unregister_handler_proc(unsigned int irq, struct irqaction *action) { } static inline void irq_proc_update_valid(struct irq_desc *desc) { } +#endif + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_GENERIC_IRQ_SHOW) +void irq_proc_calc_prec(void); +#else static inline void irq_proc_calc_prec(void) { } #endif diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 9f83e2bc86cf..084c84ca457d 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -477,7 +477,7 @@ void irq_proc_calc_prec(void) } #define ZSTR1 " 0" -#define ZSTR1_LEN 11 +#define ZSTR1_LEN (sizeof(ZSTR1) - 1) #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 \ diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h index d15410b4a089..0a0c027a5d34 100644 --- a/kernel/irq/settings.h +++ b/kernel/irq/settings.h @@ -18,6 +18,7 @@ enum { _IRQ_DISABLE_UNLAZY = IRQ_DISABLE_UNLAZY, _IRQ_HIDDEN = IRQ_HIDDEN, _IRQ_NO_DEBUG = IRQ_NO_DEBUG, + _IRQ_PROC_VALID = IRQ_RESERVED, _IRQF_MODIFY_MASK = IRQF_MODIFY_MASK, }; @@ -34,12 +35,10 @@ enum { #define IRQ_DISABLE_UNLAZY GOT_YOU_MORON #define IRQ_HIDDEN GOT_YOU_MORON #define IRQ_NO_DEBUG GOT_YOU_MORON +#define IRQ_RESERVED GOT_YOU_MORON #undef IRQF_MODIFY_MASK #define IRQF_MODIFY_MASK GOT_YOU_MORON -#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) {