perf_counter: x86: self-IPI for pending work
authorPeter Zijlstra <a.p.zijlstra@chello.nl>
Mon, 6 Apr 2009 09:45:03 +0000 (11:45 +0200)
committerIngo Molnar <mingo@elte.hu>
Tue, 7 Apr 2009 08:48:56 +0000 (10:48 +0200)
Implement set_perf_counter_pending() with a self-IPI so that it will
run ASAP in a usable context.

For now use a second IRQ vector, because the primary vector pokes
the apic in funny ways that seem to confuse things.

Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
LKML-Reference: <20090406094517.724626696@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/include/asm/entry_arch.h
arch/x86/include/asm/hardirq.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/perf_counter.h
arch/x86/kernel/cpu/perf_counter.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/irq.c
arch/x86/kernel/irqinit_32.c
arch/x86/kernel/irqinit_64.c

index c2e6bed..fe24d28 100644 (file)
@@ -50,6 +50,7 @@ BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
 
 #ifdef CONFIG_PERF_COUNTERS
 BUILD_INTERRUPT(perf_counter_interrupt, LOCAL_PERF_VECTOR)
+BUILD_INTERRUPT(perf_pending_interrupt, LOCAL_PENDING_VECTOR)
 #endif
 
 #ifdef CONFIG_X86_MCE_P4THERMAL
index 2545442..f5ebe2a 100644 (file)
@@ -14,6 +14,7 @@ typedef struct {
 #endif
        unsigned int generic_irqs;      /* arch dependent */
        unsigned int apic_perf_irqs;
+       unsigned int apic_pending_irqs;
 #ifdef CONFIG_SMP
        unsigned int irq_resched_count;
        unsigned int irq_call_count;
index ae80f64..7309c0a 100644 (file)
@@ -30,6 +30,7 @@ extern void apic_timer_interrupt(void);
 extern void generic_interrupt(void);
 extern void error_interrupt(void);
 extern void perf_counter_interrupt(void);
+extern void perf_pending_interrupt(void);
 
 extern void spurious_interrupt(void);
 extern void thermal_interrupt(void);
index 3cbd79b..545bb81 100644 (file)
 #define GENERIC_INTERRUPT_VECTOR       0xed
 
 /*
+ * Performance monitoring pending work vector:
+ */
+#define LOCAL_PENDING_VECTOR           0xec
+
+/*
  * First APIC vector available to drivers: (vectors 0x30-0xee) we
  * start at 0x31(0x41) to spread out vectors evenly between priority
  * levels. (0x80 is the syscall vector)
index e2b0e66..d08dd52 100644 (file)
@@ -84,7 +84,8 @@ union cpuid10_edx {
 #define MSR_ARCH_PERFMON_FIXED_CTR2                    0x30b
 #define X86_PMC_IDX_FIXED_BUS_CYCLES                   (X86_PMC_IDX_FIXED + 2)
 
-#define set_perf_counter_pending()     do { } while (0)
+extern void set_perf_counter_pending(void);
+
 #define clear_perf_counter_pending()   do { } while (0)
 #define test_perf_counter_pending()    (0)
 
index c74e20d..4384158 100644 (file)
@@ -849,6 +849,20 @@ void smp_perf_counter_interrupt(struct pt_regs *regs)
        irq_exit();
 }
 
+void smp_perf_pending_interrupt(struct pt_regs *regs)
+{
+       irq_enter();
+       ack_APIC_irq();
+       inc_irq_stat(apic_pending_irqs);
+       perf_counter_do_pending();
+       irq_exit();
+}
+
+void set_perf_counter_pending(void)
+{
+       apic->send_IPI_self(LOCAL_PENDING_VECTOR);
+}
+
 void perf_counters_lapic_init(int nmi)
 {
        u32 apic_val;
index 3f129d9..1d46cba 100644 (file)
@@ -1028,6 +1028,8 @@ apicinterrupt SPURIOUS_APIC_VECTOR \
 #ifdef CONFIG_PERF_COUNTERS
 apicinterrupt LOCAL_PERF_VECTOR \
        perf_counter_interrupt smp_perf_counter_interrupt
+apicinterrupt LOCAL_PENDING_VECTOR \
+       perf_pending_interrupt smp_perf_pending_interrupt
 #endif
 
 /*
index 9c27543..d465487 100644 (file)
@@ -67,6 +67,10 @@ static int show_other_interrupts(struct seq_file *p, int prec)
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", irq_stats(j)->apic_perf_irqs);
        seq_printf(p, "  Performance counter interrupts\n");
+       seq_printf(p, "PND: ");
+       for_each_online_cpu(j)
+               seq_printf(p, "%10u ", irq_stats(j)->apic_pending_irqs);
+       seq_printf(p, "  Performance pending work\n");
 #endif
        if (generic_interrupt_extension) {
                seq_printf(p, "PLT: ");
@@ -171,6 +175,7 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
        sum += irq_stats(cpu)->apic_timer_irqs;
        sum += irq_stats(cpu)->irq_spurious_count;
        sum += irq_stats(cpu)->apic_perf_irqs;
+       sum += irq_stats(cpu)->apic_pending_irqs;
 #endif
        if (generic_interrupt_extension)
                sum += irq_stats(cpu)->generic_irqs;
index 925d87c..3190a6b 100644 (file)
@@ -166,6 +166,7 @@ static void __init apic_intr_init(void)
        alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
 # ifdef CONFIG_PERF_COUNTERS
        alloc_intr_gate(LOCAL_PERF_VECTOR, perf_counter_interrupt);
+       alloc_intr_gate(LOCAL_PENDING_VECTOR, perf_pending_interrupt);
 # endif
 
 # ifdef CONFIG_X86_MCE_P4THERMAL
index 665e2ab..53ceb26 100644 (file)
@@ -156,6 +156,7 @@ static void __init apic_intr_init(void)
        /* Performance monitoring interrupt: */
 #ifdef CONFIG_PERF_COUNTERS
        alloc_intr_gate(LOCAL_PERF_VECTOR, perf_counter_interrupt);
+       alloc_intr_gate(LOCAL_PENDING_VECTOR, perf_pending_interrupt);
 #endif
 }