public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [patch v2 00/14] Improve /proc/interrupts further and add a binary interface
@ 2026-03-20 13:21 Thomas Gleixner
  2026-03-20 13:21 ` [patch v2 01/14] x86/irq: Optimize interrupts decimals printing Thomas Gleixner
                   ` (14 more replies)
  0 siblings, 15 replies; 43+ messages in thread
From: Thomas Gleixner @ 2026-03-20 13:21 UTC (permalink / raw)
  To: LKML; +Cc: x86, Dmitry Ilvokhin, Neil Horman, Radu Rendec

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)
 {

^ permalink raw reply related	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2026-03-27 11:03 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-20 13:21 [patch v2 00/14] Improve /proc/interrupts further and add a binary interface Thomas Gleixner
2026-03-20 13:21 ` [patch v2 01/14] x86/irq: Optimize interrupts decimals printing Thomas Gleixner
2026-03-21 16:10   ` Radu Rendec
2026-03-20 13:21 ` [patch v2 02/14] genirq/proc: Avoid formatting zero counts in /proc/interrupts Thomas Gleixner
2026-03-21 16:38   ` Radu Rendec
2026-03-20 13:21 ` [patch v2 03/14] genirq/proc: Utilize irq_desc::tot_count to avoid evaluation Thomas Gleixner
2026-03-22 19:59   ` Radu Rendec
2026-03-20 13:21 ` [patch v2 04/14] x86/irq: Make irqstats array based Thomas Gleixner
2026-03-20 16:39   ` Michael Kelley
2026-03-21 16:38     ` Thomas Gleixner
2026-03-21 20:32       ` Michael Kelley
2026-03-23 19:24   ` Radu Rendec
2026-03-24 19:54     ` Thomas Gleixner
2026-03-24 20:21       ` Thomas Gleixner
2026-03-24 20:32         ` Radu Rendec
2026-03-25 19:20           ` Radu Rendec
2026-03-25 22:52             ` Thomas Gleixner
2026-03-25 22:54               ` Florian Fainelli
2026-03-26 10:29                 ` Thomas Gleixner
2026-03-26 23:00                   ` Florian Fainelli
2026-03-27 11:03                     ` Thomas Gleixner
2026-03-26 12:34               ` Radu Rendec
2026-03-20 13:21 ` [patch v2 05/14] genirq: Expose nr_irqs in core code Thomas Gleixner
2026-03-23 19:48   ` Radu Rendec
2026-03-23 21:27     ` Thomas Gleixner
2026-03-20 13:21 ` [patch v2 06/14] genirq: Cache the condition for /proc/interrupts exposure Thomas Gleixner
2026-03-23 20:58   ` Radu Rendec
2026-03-24 20:31     ` Thomas Gleixner
2026-03-24 20:36       ` Radu Rendec
2026-03-20 13:21 ` [patch v2 07/14] genirq: Calculate precision only when required Thomas Gleixner
2026-03-25 19:47   ` Radu Rendec
2026-03-20 13:22 ` [patch v2 08/14] genirq: Add rcuref count to struct irq_desc Thomas Gleixner
2026-03-26 18:43   ` Dmitry Ilvokhin
2026-03-20 13:22 ` [patch v2 09/14] genirq: Expose irq_find_desc_at_or_after() in core code Thomas Gleixner
2026-03-26 19:13   ` Dmitry Ilvokhin
2026-03-26 21:11     ` Thomas Gleixner
2026-03-26 21:25       ` Thomas Gleixner
2026-03-20 13:22 ` [patch v2 10/14] genirq/proc: Speed up /proc/interrupts iteration Thomas Gleixner
2026-03-20 13:22 ` [patch v2 11/14] [RFC] genirq: Cache target CPU for single CPU affinities Thomas Gleixner
2026-03-20 13:22 ` [patch v2 12/14] [RFC] genirq/proc: Provide binary statistic interface Thomas Gleixner
2026-03-20 13:22 ` [patch v2 13/14] [RFC] genirq/proc: Provide architecture specific binary statistics Thomas Gleixner
2026-03-20 13:22 ` [patch v2 14/14] [RFC] x86/irq: Hook up architecture specific stats Thomas Gleixner
2026-03-20 16:45 ` [patch v2 00/14] Improve /proc/interrupts further and add a binary interface Michael Kelley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox