[patch V5 00/15] Improve /proc/interrupts further

From: Thomas Gleixner

Date: Wed Apr 01 2026 - 17:51:36 EST


This is a follow up to v4 which can be found here:

https://lore.kernel.org/20260331071453.172185305@xxxxxxxxxx

The v1 cover letter contains a full analysis, explanation and numbers:

https://lore.kernel.org/20260303150539.513068586@xxxxxxxxxx

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.

Changes vs. V4:

- Moved the header printing ahead of the architecture and update comment
- Dmitry

- Fix the gdbscript so it works with a bitmap larger than one entry and
bring show_irq_err_count() back as it's required by MIPS

- Removed unused variable and resort hunks so it's bisectable.

Delta patch against v4 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-proc-v5

Thanks,

tglx
---
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index ae8b06e01948..7eb07e3bdb4c 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -2066,7 +2066,6 @@ static const void *__cleanup_nmi(unsigned int irq, struct irq_desc *desc)
const void *free_nmi(unsigned int irq, void *dev_id)
{
struct irq_desc *desc = irq_to_desc(irq);
- void *ret;

if (!desc || WARN_ON(!irq_is_nmi(desc)))
return NULL;
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index a62d4694f063..3bd394aa7617 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -540,10 +540,7 @@ static int irq_seq_show(struct seq_file *p, void *v)
struct irq_desc *desc = v;
struct irqaction *action;

- if (desc == ARCH_PROC_IRQDESC)
- return arch_show_interrupts(p, constr->num_prec);
-
- /* print header for the first interrupt indicated by !p>private */
+ /* Print header for the first interrupt? */
if (constr->print_header) {
unsigned int cpu;

@@ -554,6 +551,9 @@ static int irq_seq_show(struct seq_file *p, void *v)
constr->print_header = false;
}

+ if (desc == ARCH_PROC_IRQDESC)
+ return arch_show_interrupts(p, constr->num_prec);
+
seq_put_decimal_ull_width(p, "", irq_desc_get_irq(desc), constr->num_prec);
seq_putc(p, ':');

@@ -617,9 +617,9 @@ static void *irq_seq_next_desc(loff_t *pos)
if (desc) {
*pos = 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 valid for output then 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;
diff --git a/scripts/gdb/linux/interrupts.py b/scripts/gdb/linux/interrupts.py
index 418f3ece2f0f..cf0a02c8124d 100644
--- a/scripts/gdb/linux/interrupts.py
+++ b/scripts/gdb/linux/interrupts.py
@@ -103,12 +103,12 @@ def x86_show_interupts(prec):
info_type = gdb.lookup_type('struct irq_stat_info')
info = gdb.parse_and_eval('irq_stat_info')
bitmap = gdb.parse_and_eval('irq_stat_count_show')
- nbits = 8 * int(bitmap.type.sizeof)
+ bitsperlong = 8 * int(bitmap.type.target().sizeof)

text = ""
for idx in range(int(info.type.sizeof / info_type.sizeof)):
- show = bitmap[idx / nbits]
- if not show & 1 << (idx % nbits):
+ show = bitmap[int(idx / bitsperlong)]
+ if not show & 1 << int(idx % bitsperlong):
continue
pfx = info[idx]['symbol'].string()
desc = info[idx]['text'].string()
@@ -145,6 +145,13 @@ def aarch64_show_interrupts(prec):
text += "%*s: %10lu\n" % (prec, "ERR", gdb.parse_and_eval("irq_err_count"))
return text

+def show_irq_err_count(prec):
+ cnt = utils.gdb_eval_or_none("irq_err_count")
+ text = ""
+ if cnt is not None:
+ text += "%*s: %10u\n" % (prec, "ERR", cnt['counter'])
+ return text
+
def arch_show_interrupts(prec):
text = ""
if utils.is_target_arch("x86"):