Re: [PATCH] create /proc/all-interrupts

From: Sven-Thorsten Dietrich
Date: Mon Jul 30 2007 - 13:33:44 EST


On Thu, 2007-07-26 at 11:56 -0700, H. Peter Anvin wrote:
> Joe Korty wrote:
> > Create /proc/all-interrupts for some architectures.
> >
> > Create a version of /proc/interrupts that displays _every_
> > IRQ vector, not just those that someone thought might be
> > interesting, and add an entry in the commentary column
> > for those vectors which lacked such a comment.
> >
> > Rationale: /proc/interrupts is not truly useful unless it
> > displays every IRQ vector, not just those somebody thought
> > would be interesting. For example, since /proc/interrupts
> > does not display the rescheduling interrupt, the occurance
> > of rescheduling interrupt floods ends up affecting
> > latencies, yet without an entry in /proc/interrupts, it
> > is difficult to discern why latencies are being affected.
> >
> > Rather than modify /proc/interrupts, this patch creates
> > a new version of /proc/interrupts, on the off-chance
> > that adding new lines to /proc/interrupts, and appending
> > new fields to the end of old lines, might break some
> > longstanding script. However, these kinds of changes
> > traditionally do not affect scripts, so it might be
> > reasonable to fold /proc/all-interrupts back into
> > /proc/interrupts.
>
> I think that would be the right thing to do. We have added things to
> /proc/interrupts in the past.
>
Hi Andrew,

Would it make sense to drop this patch into -mm for feedback?

Thanks,

Sven
--- Begin Message --- Add missing IRQs to /proc/interrupts.

/proc/interrupts is not truly useful unless it displays
every IRQ vector, not just those somebody thought
would be interesting. For example, since the default
/proc/interrupts setup did not display the rescheduling
interrupt, the occurance of rescheduling interrupt floods
ends up affecting latencies, yet without an entry in
/proc/interrupts, it is difficult to discern why latencies
are being affected.

Also does a silly little expansion of the 'ERR:' display
to be per cpu. This makes its layout identical to all
the other display lines in /proc/interrupts.

Signed-off-by: Joe Korty <joe.korty@xxxxxxxx>

Index: 2.6.22.1-rt8/arch/i386/kernel/apic.c
===================================================================
--- 2.6.22.1-rt8.orig/arch/i386/kernel/apic.c 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/arch/i386/kernel/apic.c 2007-07-25 16:07:43.000000000 -0400
@@ -1268,6 +1268,8 @@
{
unsigned long v;

+ atomic_inc(&__get_cpu_var(irq_spur_counts));
+
irq_enter();
/*
* Check if this really is a spurious interrupt and ACK it
@@ -1297,7 +1299,7 @@
apic_write(APIC_ESR, 0);
v1 = apic_read(APIC_ESR);
ack_APIC_irq();
- atomic_inc(&irq_err_count);
+ atomic_inc(&__get_cpu_var(irq_err_counts));

/* Here is what the APIC error bits mean:
0: Send CS error
Index: 2.6.22.1-rt8/arch/i386/kernel/cpu/mcheck/p4.c
===================================================================
--- 2.6.22.1-rt8.orig/arch/i386/kernel/cpu/mcheck/p4.c 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/arch/i386/kernel/cpu/mcheck/p4.c 2007-07-25 16:07:43.000000000 -0400
@@ -60,6 +60,7 @@
fastcall void smp_thermal_interrupt(struct pt_regs *regs)
{
irq_enter();
+ atomic_inc(&__get_cpu_var(irq_thermal_counts));
vendor_thermal_interrupt(regs);
irq_exit();
}
Index: 2.6.22.1-rt8/arch/i386/kernel/i8259.c
===================================================================
--- 2.6.22.1-rt8.orig/arch/i386/kernel/i8259.c 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/arch/i386/kernel/i8259.c 2007-07-25 16:07:43.000000000 -0400
@@ -209,7 +209,7 @@
printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq);
spurious_irq_mask |= irqmask;
}
- atomic_inc(&irq_err_count);
+ atomic_inc(&__get_cpu_var(irq_err_counts));
/*
* Theoretically we do not have to handle this IRQ,
* but in Linux this does not cause problems and is
Index: 2.6.22.1-rt8/arch/i386/kernel/io_apic.c
===================================================================
--- 2.6.22.1-rt8.orig/arch/i386/kernel/io_apic.c 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/arch/i386/kernel/io_apic.c 2007-07-25 16:07:43.000000000 -0400
@@ -51,7 +51,6 @@
#include "io_ports.h"

int (*ioapic_renumber_irq)(int ioapic, int irq);
-atomic_t irq_mis_count;

/* Where if anywhere is the i8259 connect in external int mode */
static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
@@ -2031,7 +2030,7 @@
ack_APIC_irq();

if (!(v & (1 << (i & 0x1f)))) {
- atomic_inc(&irq_mis_count);
+ atomic_inc(&__get_cpu_var(irq_mis_counts));
spin_lock(&ioapic_lock);
/* mask = 1, trigger = 0 */
__modify_IO_APIC_irq(irq, 0x00010000, 0x00008000);
Index: 2.6.22.1-rt8/arch/i386/kernel/irq.c
===================================================================
--- 2.6.22.1-rt8.orig/arch/i386/kernel/irq.c 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/arch/i386/kernel/irq.c 2007-07-25 16:23:12.000000000 -0400
@@ -252,7 +252,13 @@
* Interrupt statistics:
*/

-atomic_t irq_err_count;
+DEFINE_PER_CPU(atomic_t, irq_resched_counts);
+DEFINE_PER_CPU(atomic_t, irq_call_counts);
+DEFINE_PER_CPU(atomic_t, irq_spur_counts);
+DEFINE_PER_CPU(atomic_t, irq_tlb_counts);
+DEFINE_PER_CPU(atomic_t, irq_thermal_counts);
+DEFINE_PER_CPU(atomic_t, irq_err_counts);
+DEFINE_PER_CPU(atomic_t, irq_mis_counts);

/*
* /proc/interrupts printing:
@@ -305,9 +311,60 @@
per_cpu(irq_stat,j).apic_timer_irqs);
seq_putc(p, '\n');
#endif
- seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
-#if defined(CONFIG_X86_IO_APIC)
- seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
+#ifdef CONFIG_SMP
+#ifdef RESCHEDULE_VECTOR
+ seq_printf(p, "RES: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ",
+ atomic_read(&per_cpu(irq_resched_counts, j)));
+ seq_putc(p, '\n');
+#endif
+#endif
+#ifdef CONFIG_SMP
+#ifdef CALL_FUNCTION_VECTOR
+ seq_printf(p, "CAL: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ",
+ atomic_read(&per_cpu(irq_call_counts, j)));
+ seq_putc(p, '\n');
+#endif
+#endif
+#ifdef CONFIG_SMP
+#ifdef INVALIDATE_TLB_VECTOR
+ seq_printf(p, "TLB: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ",
+ atomic_read(&per_cpu(irq_tlb_counts, j)));
+ seq_putc(p, '\n');
+#endif
+#endif
+#ifdef THERMAL_APIC_VECTOR
+ seq_printf(p, "TRM: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ",
+ atomic_read(&per_cpu(irq_thermal_counts, j)));
+ seq_putc(p, '\n');
+#endif
+#ifdef SPURIOUS_APIC_VECTOR
+ seq_printf(p, "SPU: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ",
+ atomic_read(&per_cpu(irq_spur_counts, j)));
+ seq_putc(p, '\n');
+#endif
+#ifdef ERROR_APIC_VECTOR
+ seq_printf(p, "ERR: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ",
+ atomic_read(&per_cpu(irq_err_counts, j)));
+ seq_putc(p, '\n');
+#endif
+#if defined(CONFIG_X86_IO_APIC) && defined(APIC_MISMATCH_DEBUG)
+ seq_printf(p, "MIS: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ",
+ atomic_read(&per_cpu(irq_mis_counts, j)));
+ seq_putc(p, '\n');
#endif
}
return 0;
Index: 2.6.22.1-rt8/arch/i386/kernel/smp.c
===================================================================
--- 2.6.22.1-rt8.orig/arch/i386/kernel/smp.c 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/arch/i386/kernel/smp.c 2007-07-25 16:07:43.000000000 -0400
@@ -315,6 +315,7 @@
unsigned long cpu;

cpu = get_cpu();
+ atomic_inc(&__get_cpu_var(irq_tlb_counts));

if (!cpu_isset(cpu, flush_cpumask))
goto out;
@@ -658,6 +659,7 @@
{
trace_special(regs->eip, 0, 0);
ack_APIC_irq();
+ atomic_inc(&__get_cpu_var(irq_resched_counts));
set_tsk_need_resched(current);
}

@@ -668,6 +670,7 @@
int wait = call_data->wait;

ack_APIC_irq();
+ atomic_inc(&__get_cpu_var(irq_call_counts));
/*
* Notify initiating CPU that I've grabbed the data and am
* about to execute the function
Index: 2.6.22.1-rt8/arch/x86_64/kernel/apic.c
===================================================================
--- 2.6.22.1-rt8.orig/arch/x86_64/kernel/apic.c 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/arch/x86_64/kernel/apic.c 2007-07-25 16:07:43.000000000 -0400
@@ -1099,6 +1099,9 @@
asmlinkage void smp_spurious_interrupt(void)
{
unsigned int v;
+
+ atomic_inc(&__get_cpu_var(irq_spur_counts));
+
exit_idle();
irq_enter();
/*
@@ -1127,7 +1130,7 @@
apic_write(APIC_ESR, 0);
v1 = apic_read(APIC_ESR);
ack_APIC_irq();
- atomic_inc(&irq_err_count);
+ atomic_inc(&__get_cpu_var(irq_err_counts));

/* Here is what the APIC error bits mean:
0: Send CS error
Index: 2.6.22.1-rt8/arch/x86_64/kernel/i8259.c
===================================================================
--- 2.6.22.1-rt8.orig/arch/x86_64/kernel/i8259.c 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/arch/x86_64/kernel/i8259.c 2007-07-25 16:07:43.000000000 -0400
@@ -273,7 +273,7 @@
printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq);
spurious_irq_mask |= irqmask;
}
- atomic_inc(&irq_err_count);
+ atomic_inc(&__get_cpu_var(irq_err_counts));
/*
* Theoretically we do not have to handle this IRQ,
* but in Linux this does not cause problems and is
Index: 2.6.22.1-rt8/arch/x86_64/kernel/irq.c
===================================================================
--- 2.6.22.1-rt8.orig/arch/x86_64/kernel/irq.c 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/arch/x86_64/kernel/irq.c 2007-07-25 16:23:12.000000000 -0400
@@ -20,7 +20,18 @@
#include <asm/idle.h>
#include <asm/smp.h>

-atomic_t irq_err_count;
+DEFINE_PER_CPU(atomic_t, irq_resched_counts);
+DEFINE_PER_CPU(atomic_t, irq_call_counts);
+DEFINE_PER_CPU(atomic_t, irq_spur_counts);
+DEFINE_PER_CPU(atomic_t, irq_tlb_counts);
+DEFINE_PER_CPU(atomic_t, irq_threshold_counts);
+DEFINE_PER_CPU(atomic_t, irq_thermal_counts);
+DEFINE_PER_CPU(atomic_t, irq_err_counts);
+#ifdef CONFIG_X86_IO_APIC
+#ifdef APIC_MISMATCH_DEBUG
+DEFINE_PER_CPU(atomic_t, irq_mis_counts);
+#endif
+#endif

#ifdef CONFIG_DEBUG_STACKOVERFLOW
/*
@@ -93,7 +104,62 @@
for_each_online_cpu(j)
seq_printf(p, "%10u ", cpu_pda(j)->apic_timer_irqs);
seq_putc(p, '\n');
- seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+#ifdef CONFIG_SMP
+#ifdef RESCHEDULE_VECTOR
+ seq_printf(p, "RES: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", atomic_read(&per_cpu(irq_resched_counts, j)));
+ seq_putc(p, '\n');
+#endif
+#endif
+#ifdef CONFIG_SMP
+#ifdef CALL_FUNCTION_VECTOR
+ seq_printf(p, "CAL: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", atomic_read(&per_cpu(irq_call_counts, j)));
+ seq_putc(p, '\n');
+#endif
+#endif
+#ifdef CONFIG_SMP
+#ifdef INVALIDATE_TLB_VECTOR_START
+ seq_printf(p, "TLB: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", atomic_read(&per_cpu(irq_tlb_counts, j)));
+ seq_putc(p, '\n');
+#endif
+#endif
+#ifdef THERMAL_APIC_VECTOR
+ seq_printf(p, "TRM: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", atomic_read(&per_cpu(irq_thermal_counts, j)));
+ seq_putc(p, '\n');
+#endif
+#ifdef THRESHOLD_APIC_VECTOR
+ seq_printf(p, "THR: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", atomic_read(&per_cpu(irq_threshold_counts, j)));
+ seq_putc(p, '\n');
+#endif
+#ifdef SPURIOUS_APIC_VECTOR
+ seq_printf(p, "SPU: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", atomic_read(&per_cpu(irq_spur_counts, j)));
+ seq_putc(p, '\n');
+#endif
+#ifdef ERROR_APIC_VECTOR
+ seq_printf(p, "ERR: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", atomic_read(&per_cpu(irq_err_counts, j)));
+ seq_putc(p, '\n');
+#endif
+#ifdef CONFIG_X86_IO_APIC
+#ifdef APIC_MISMATCH_DEBUG
+ seq_printf(p, "MIS: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", atomic_read(&per_cpu(irq_mis_counts, j)));
+ seq_putc(p, '\n');
+#endif
+#endif
}
return 0;
}
Index: 2.6.22.1-rt8/arch/x86_64/kernel/mce_amd.c
===================================================================
--- 2.6.22.1-rt8.orig/arch/x86_64/kernel/mce_amd.c 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/arch/x86_64/kernel/mce_amd.c 2007-07-25 16:07:43.000000000 -0400
@@ -186,6 +186,8 @@
exit_idle();
irq_enter();

+ atomic_inc(&__get_cpu_var(irq_threshold_counts));
+
memset(&m, 0, sizeof(m));
rdtscll(m.tsc);
m.cpu = smp_processor_id();
Index: 2.6.22.1-rt8/arch/x86_64/kernel/mce_intel.c
===================================================================
--- 2.6.22.1-rt8.orig/arch/x86_64/kernel/mce_intel.c 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/arch/x86_64/kernel/mce_intel.c 2007-07-25 16:07:43.000000000 -0400
@@ -21,6 +21,7 @@

exit_idle();
irq_enter();
+ atomic_inc(&__get_cpu_var(irq_thermal_counts));

rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
if (therm_throt_process(msr_val & 1))
Index: 2.6.22.1-rt8/include/asm-i386/apic.h
===================================================================
--- 2.6.22.1-rt8.orig/include/asm-i386/apic.h 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/include/asm-i386/apic.h 2007-07-25 16:07:43.000000000 -0400
@@ -7,6 +7,7 @@
#include <asm/apicdef.h>
#include <asm/processor.h>
#include <asm/system.h>
+#include <asm/atomic.h>

#define Dprintk(x...)

@@ -118,6 +119,9 @@

extern void smp_send_nmi_allbutself(void);

+DECLARE_PER_CPU(atomic_t, irq_spur_counts);
+DECLARE_PER_CPU(atomic_t, irq_thermal_counts);
+
#else /* !CONFIG_X86_LOCAL_APIC */
static inline void lapic_shutdown(void) { }

Index: 2.6.22.1-rt8/include/asm-i386/hw_irq.h
===================================================================
--- 2.6.22.1-rt8.orig/include/asm-i386/hw_irq.h 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/include/asm-i386/hw_irq.h 2007-07-25 16:07:43.000000000 -0400
@@ -13,6 +13,7 @@
*/

#include <linux/profile.h>
+#include <linux/percpu.h>
#include <asm/atomic.h>
#include <asm/irq.h>
#include <asm/sections.h>
@@ -58,8 +59,11 @@

extern unsigned long io_apic_irqs;

-extern atomic_t irq_err_count;
-extern atomic_t irq_mis_count;
+DECLARE_PER_CPU(atomic_t, irq_resched_counts);
+DECLARE_PER_CPU(atomic_t, irq_call_counts);
+DECLARE_PER_CPU(atomic_t, irq_tlb_counts);
+DECLARE_PER_CPU(atomic_t, irq_err_counts);
+DECLARE_PER_CPU(atomic_t, irq_mis_counts);

#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))

Index: 2.6.22.1-rt8/include/asm-x86_64/apic.h
===================================================================
--- 2.6.22.1-rt8.orig/include/asm-x86_64/apic.h 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/include/asm-x86_64/apic.h 2007-07-25 16:07:43.000000000 -0400
@@ -6,6 +6,7 @@
#include <asm/fixmap.h>
#include <asm/apicdef.h>
#include <asm/system.h>
+#include <asm/atomic.h>

#define Dprintk(x...)

@@ -101,4 +102,7 @@
extern unsigned boot_cpu_id;
extern int local_apic_timer_c2_ok;

+DECLARE_PER_CPU(atomic_t, irq_spur_counts);
+DECLARE_PER_CPU(atomic_t, irq_thermal_counts);
+
#endif /* __ASM_APIC_H */
Index: 2.6.22.1-rt8/include/asm-x86_64/hw_irq.h
===================================================================
--- 2.6.22.1-rt8.orig/include/asm-x86_64/hw_irq.h 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/include/asm-x86_64/hw_irq.h 2007-07-25 16:07:43.000000000 -0400
@@ -123,8 +123,12 @@

extern unsigned long io_apic_irqs;

-extern atomic_t irq_err_count;
-extern atomic_t irq_mis_count;
+DECLARE_PER_CPU(atomic_t, irq_resched_counts);
+DECLARE_PER_CPU(atomic_t, irq_call_counts);
+DECLARE_PER_CPU(atomic_t, irq_tlb_counts);
+DECLARE_PER_CPU(atomic_t, irq_threshold_counts);
+DECLARE_PER_CPU(atomic_t, irq_err_counts);
+DECLARE_PER_CPU(atomic_t, irq_mis_counts);

#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))

Index: 2.6.22.1-rt8/arch/x86_64/kernel/smp.c
===================================================================
--- 2.6.22.1-rt8.orig/arch/x86_64/kernel/smp.c 2007-07-25 16:07:23.000000000 -0400
+++ 2.6.22.1-rt8/arch/x86_64/kernel/smp.c 2007-07-25 16:07:43.000000000 -0400
@@ -133,6 +133,8 @@
int sender;
union smp_flush_state *f;

+ atomic_inc(&__get_cpu_var(irq_tlb_counts));
+
cpu = smp_processor_id();
/*
* orig_rax contains the negated interrupt vector.
@@ -508,6 +510,7 @@
asmlinkage void smp_reschedule_interrupt(void)
{
ack_APIC_irq();
+ atomic_inc(&__get_cpu_var(irq_resched_counts));
}

asmlinkage void smp_call_function_interrupt(void)
@@ -517,6 +520,7 @@
int wait = call_data->wait;

ack_APIC_irq();
+ atomic_inc(&__get_cpu_var(irq_call_counts));
/*
* Notify initiating CPU that I've grabbed the data and am
* about to execute the function

--- End Message ---