Commit b6276f35 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar

perf_counter: x86: self-IPI for pending work

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: default avatarPeter 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: default avatarIngo Molnar <mingo@elte.hu>
parent 671dec5d
...@@ -50,6 +50,7 @@ BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) ...@@ -50,6 +50,7 @@ BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
#ifdef CONFIG_PERF_COUNTERS #ifdef CONFIG_PERF_COUNTERS
BUILD_INTERRUPT(perf_counter_interrupt, LOCAL_PERF_VECTOR) BUILD_INTERRUPT(perf_counter_interrupt, LOCAL_PERF_VECTOR)
BUILD_INTERRUPT(perf_pending_interrupt, LOCAL_PENDING_VECTOR)
#endif #endif
#ifdef CONFIG_X86_MCE_P4THERMAL #ifdef CONFIG_X86_MCE_P4THERMAL
......
...@@ -14,6 +14,7 @@ typedef struct { ...@@ -14,6 +14,7 @@ typedef struct {
#endif #endif
unsigned int generic_irqs; /* arch dependent */ unsigned int generic_irqs; /* arch dependent */
unsigned int apic_perf_irqs; unsigned int apic_perf_irqs;
unsigned int apic_pending_irqs;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
unsigned int irq_resched_count; unsigned int irq_resched_count;
unsigned int irq_call_count; unsigned int irq_call_count;
......
...@@ -30,6 +30,7 @@ extern void apic_timer_interrupt(void); ...@@ -30,6 +30,7 @@ extern void apic_timer_interrupt(void);
extern void generic_interrupt(void); extern void generic_interrupt(void);
extern void error_interrupt(void); extern void error_interrupt(void);
extern void perf_counter_interrupt(void); extern void perf_counter_interrupt(void);
extern void perf_pending_interrupt(void);
extern void spurious_interrupt(void); extern void spurious_interrupt(void);
extern void thermal_interrupt(void); extern void thermal_interrupt(void);
......
...@@ -116,6 +116,11 @@ ...@@ -116,6 +116,11 @@
*/ */
#define GENERIC_INTERRUPT_VECTOR 0xed #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 * First APIC vector available to drivers: (vectors 0x30-0xee) we
* start at 0x31(0x41) to spread out vectors evenly between priority * start at 0x31(0x41) to spread out vectors evenly between priority
......
...@@ -84,7 +84,8 @@ union cpuid10_edx { ...@@ -84,7 +84,8 @@ union cpuid10_edx {
#define MSR_ARCH_PERFMON_FIXED_CTR2 0x30b #define MSR_ARCH_PERFMON_FIXED_CTR2 0x30b
#define X86_PMC_IDX_FIXED_BUS_CYCLES (X86_PMC_IDX_FIXED + 2) #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 clear_perf_counter_pending() do { } while (0)
#define test_perf_counter_pending() (0) #define test_perf_counter_pending() (0)
......
...@@ -849,6 +849,20 @@ void smp_perf_counter_interrupt(struct pt_regs *regs) ...@@ -849,6 +849,20 @@ void smp_perf_counter_interrupt(struct pt_regs *regs)
irq_exit(); 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) void perf_counters_lapic_init(int nmi)
{ {
u32 apic_val; u32 apic_val;
......
...@@ -1028,6 +1028,8 @@ apicinterrupt SPURIOUS_APIC_VECTOR \ ...@@ -1028,6 +1028,8 @@ apicinterrupt SPURIOUS_APIC_VECTOR \
#ifdef CONFIG_PERF_COUNTERS #ifdef CONFIG_PERF_COUNTERS
apicinterrupt LOCAL_PERF_VECTOR \ apicinterrupt LOCAL_PERF_VECTOR \
perf_counter_interrupt smp_perf_counter_interrupt perf_counter_interrupt smp_perf_counter_interrupt
apicinterrupt LOCAL_PENDING_VECTOR \
perf_pending_interrupt smp_perf_pending_interrupt
#endif #endif
/* /*
......
...@@ -67,6 +67,10 @@ static int show_other_interrupts(struct seq_file *p, int prec) ...@@ -67,6 +67,10 @@ static int show_other_interrupts(struct seq_file *p, int prec)
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->apic_perf_irqs); seq_printf(p, "%10u ", irq_stats(j)->apic_perf_irqs);
seq_printf(p, " Performance counter interrupts\n"); 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 #endif
if (generic_interrupt_extension) { if (generic_interrupt_extension) {
seq_printf(p, "PLT: "); seq_printf(p, "PLT: ");
...@@ -171,6 +175,7 @@ u64 arch_irq_stat_cpu(unsigned int cpu) ...@@ -171,6 +175,7 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
sum += irq_stats(cpu)->apic_timer_irqs; sum += irq_stats(cpu)->apic_timer_irqs;
sum += irq_stats(cpu)->irq_spurious_count; sum += irq_stats(cpu)->irq_spurious_count;
sum += irq_stats(cpu)->apic_perf_irqs; sum += irq_stats(cpu)->apic_perf_irqs;
sum += irq_stats(cpu)->apic_pending_irqs;
#endif #endif
if (generic_interrupt_extension) if (generic_interrupt_extension)
sum += irq_stats(cpu)->generic_irqs; sum += irq_stats(cpu)->generic_irqs;
......
...@@ -166,6 +166,7 @@ static void __init apic_intr_init(void) ...@@ -166,6 +166,7 @@ static void __init apic_intr_init(void)
alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
# ifdef CONFIG_PERF_COUNTERS # ifdef CONFIG_PERF_COUNTERS
alloc_intr_gate(LOCAL_PERF_VECTOR, perf_counter_interrupt); alloc_intr_gate(LOCAL_PERF_VECTOR, perf_counter_interrupt);
alloc_intr_gate(LOCAL_PENDING_VECTOR, perf_pending_interrupt);
# endif # endif
# ifdef CONFIG_X86_MCE_P4THERMAL # ifdef CONFIG_X86_MCE_P4THERMAL
......
...@@ -156,6 +156,7 @@ static void __init apic_intr_init(void) ...@@ -156,6 +156,7 @@ static void __init apic_intr_init(void)
/* Performance monitoring interrupt: */ /* Performance monitoring interrupt: */
#ifdef CONFIG_PERF_COUNTERS #ifdef CONFIG_PERF_COUNTERS
alloc_intr_gate(LOCAL_PERF_VECTOR, perf_counter_interrupt); alloc_intr_gate(LOCAL_PERF_VECTOR, perf_counter_interrupt);
alloc_intr_gate(LOCAL_PENDING_VECTOR, perf_pending_interrupt);
#endif #endif
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment