Commit 241771ef authored by Ingo Molnar's avatar Ingo Molnar

performance counters: x86 support

Implement performance counters for x86 Intel CPUs.

It's simplified right now: the PERFMON CPU feature is assumed,
which is available in Core2 and later Intel CPUs.

The design is flexible to be extended to more CPU types as well.
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent e7bc62b6
...@@ -643,6 +643,7 @@ config X86_UP_IOAPIC ...@@ -643,6 +643,7 @@ config X86_UP_IOAPIC
config X86_LOCAL_APIC config X86_LOCAL_APIC
def_bool y def_bool y
depends on X86_64 || (X86_32 && (X86_UP_APIC || (SMP && !X86_VOYAGER) || X86_GENERICARCH)) depends on X86_64 || (X86_32 && (X86_UP_APIC || (SMP && !X86_VOYAGER) || X86_GENERICARCH))
select HAVE_PERF_COUNTERS
config X86_IO_APIC config X86_IO_APIC
def_bool y def_bool y
......
...@@ -823,7 +823,8 @@ ia32_sys_call_table: ...@@ -823,7 +823,8 @@ ia32_sys_call_table:
.quad compat_sys_signalfd4 .quad compat_sys_signalfd4
.quad sys_eventfd2 .quad sys_eventfd2
.quad sys_epoll_create1 .quad sys_epoll_create1
.quad sys_dup3 /* 330 */ .quad sys_dup3 /* 330 */
.quad sys_pipe2 .quad sys_pipe2
.quad sys_inotify_init1 .quad sys_inotify_init1
.quad sys_perf_counter_open
ia32_syscall_end: ia32_syscall_end:
...@@ -9,6 +9,7 @@ typedef struct { ...@@ -9,6 +9,7 @@ typedef struct {
unsigned long idle_timestamp; unsigned long idle_timestamp;
unsigned int __nmi_count; /* arch dependent */ unsigned int __nmi_count; /* arch dependent */
unsigned int apic_timer_irqs; /* arch dependent */ unsigned int apic_timer_irqs; /* arch dependent */
unsigned int apic_perf_irqs; /* arch dependent */
unsigned int irq0_irqs; unsigned int irq0_irqs;
unsigned int irq_resched_count; unsigned int irq_resched_count;
unsigned int irq_call_count; unsigned int irq_call_count;
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
/* Interrupt handlers registered during init_IRQ */ /* Interrupt handlers registered during init_IRQ */
extern void apic_timer_interrupt(void); extern void apic_timer_interrupt(void);
extern void error_interrupt(void); extern void error_interrupt(void);
extern void perf_counter_interrupt(void);
extern void spurious_interrupt(void); extern void spurious_interrupt(void);
extern void thermal_interrupt(void); extern void thermal_interrupt(void);
extern void reschedule_interrupt(void); extern void reschedule_interrupt(void);
......
#ifndef _ASM_X86_INTEL_ARCH_PERFMON_H #ifndef _ASM_X86_INTEL_ARCH_PERFMON_H
#define _ASM_X86_INTEL_ARCH_PERFMON_H #define _ASM_X86_INTEL_ARCH_PERFMON_H
#define MSR_ARCH_PERFMON_PERFCTR0 0xc1 #define MSR_ARCH_PERFMON_PERFCTR0 0xc1
#define MSR_ARCH_PERFMON_PERFCTR1 0xc2 #define MSR_ARCH_PERFMON_PERFCTR1 0xc2
#define MSR_ARCH_PERFMON_EVENTSEL0 0x186 #define MSR_ARCH_PERFMON_EVENTSEL0 0x186
#define MSR_ARCH_PERFMON_EVENTSEL1 0x187 #define MSR_ARCH_PERFMON_EVENTSEL1 0x187
#define ARCH_PERFMON_EVENTSEL0_ENABLE (1 << 22) #define ARCH_PERFMON_EVENTSEL0_ENABLE (1 << 22)
#define ARCH_PERFMON_EVENTSEL_INT (1 << 20) #define ARCH_PERFMON_EVENTSEL_INT (1 << 20)
#define ARCH_PERFMON_EVENTSEL_OS (1 << 17) #define ARCH_PERFMON_EVENTSEL_OS (1 << 17)
#define ARCH_PERFMON_EVENTSEL_USR (1 << 16) #define ARCH_PERFMON_EVENTSEL_USR (1 << 16)
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL (0x3c) #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL 0x3c
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8) #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8)
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX (0) #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX 0
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT \ #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT \
(1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX)) (1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX))
#define ARCH_PERFMON_BRANCH_MISSES_RETIRED 6
union cpuid10_eax { union cpuid10_eax {
struct { struct {
...@@ -28,4 +30,12 @@ union cpuid10_eax { ...@@ -28,4 +30,12 @@ union cpuid10_eax {
unsigned int full; unsigned int full;
}; };
#ifdef CONFIG_PERF_COUNTERS
extern void init_hw_perf_counters(void);
extern void perf_counters_lapic_init(int nmi);
#else
static inline void init_hw_perf_counters(void) { }
static inline void perf_counters_lapic_init(int nmi) { }
#endif
#endif /* _ASM_X86_INTEL_ARCH_PERFMON_H */ #endif /* _ASM_X86_INTEL_ARCH_PERFMON_H */
...@@ -86,6 +86,11 @@ ...@@ -86,6 +86,11 @@
*/ */
#define LOCAL_TIMER_VECTOR 0xef #define LOCAL_TIMER_VECTOR 0xef
/*
* Performance monitoring interrupt vector:
*/
#define LOCAL_PERF_VECTOR 0xee
/* /*
* 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
......
...@@ -25,10 +25,15 @@ BUILD_INTERRUPT(irq_move_cleanup_interrupt,IRQ_MOVE_CLEANUP_VECTOR) ...@@ -25,10 +25,15 @@ BUILD_INTERRUPT(irq_move_cleanup_interrupt,IRQ_MOVE_CLEANUP_VECTOR)
* a much simpler SMP time architecture: * a much simpler SMP time architecture:
*/ */
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR)
BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
#ifdef CONFIG_PERF_COUNTERS
BUILD_INTERRUPT(perf_counter_interrupt, LOCAL_PERF_VECTOR)
#endif
#ifdef CONFIG_X86_MCE_P4THERMAL #ifdef CONFIG_X86_MCE_P4THERMAL
BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR) BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR)
#endif #endif
......
...@@ -30,6 +30,7 @@ struct x8664_pda { ...@@ -30,6 +30,7 @@ struct x8664_pda {
short isidle; short isidle;
struct mm_struct *active_mm; struct mm_struct *active_mm;
unsigned apic_timer_irqs; unsigned apic_timer_irqs;
unsigned apic_perf_irqs;
unsigned irq0_irqs; unsigned irq0_irqs;
unsigned irq_resched_count; unsigned irq_resched_count;
unsigned irq_call_count; unsigned irq_call_count;
......
...@@ -80,6 +80,7 @@ struct thread_info { ...@@ -80,6 +80,7 @@ struct thread_info {
#define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
#define TIF_SECCOMP 8 /* secure computing */ #define TIF_SECCOMP 8 /* secure computing */
#define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */ #define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */
#define TIF_PERF_COUNTERS 11 /* notify perf counter work */
#define TIF_NOTSC 16 /* TSC is not accessible in userland */ #define TIF_NOTSC 16 /* TSC is not accessible in userland */
#define TIF_IA32 17 /* 32bit process */ #define TIF_IA32 17 /* 32bit process */
#define TIF_FORK 18 /* ret_from_fork */ #define TIF_FORK 18 /* ret_from_fork */
...@@ -103,6 +104,7 @@ struct thread_info { ...@@ -103,6 +104,7 @@ struct thread_info {
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP) #define _TIF_SECCOMP (1 << TIF_SECCOMP)
#define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY) #define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY)
#define _TIF_PERF_COUNTERS (1 << TIF_PERF_COUNTERS)
#define _TIF_NOTSC (1 << TIF_NOTSC) #define _TIF_NOTSC (1 << TIF_NOTSC)
#define _TIF_IA32 (1 << TIF_IA32) #define _TIF_IA32 (1 << TIF_IA32)
#define _TIF_FORK (1 << TIF_FORK) #define _TIF_FORK (1 << TIF_FORK)
...@@ -135,7 +137,7 @@ struct thread_info { ...@@ -135,7 +137,7 @@ struct thread_info {
/* Only used for 64 bit */ /* Only used for 64 bit */
#define _TIF_DO_NOTIFY_MASK \ #define _TIF_DO_NOTIFY_MASK \
(_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_NOTIFY_RESUME) (_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_PERF_COUNTERS|_TIF_NOTIFY_RESUME)
/* flags to check in __switch_to() */ /* flags to check in __switch_to() */
#define _TIF_WORK_CTXSW \ #define _TIF_WORK_CTXSW \
......
...@@ -338,6 +338,7 @@ ...@@ -338,6 +338,7 @@
#define __NR_dup3 330 #define __NR_dup3 330
#define __NR_pipe2 331 #define __NR_pipe2 331
#define __NR_inotify_init1 332 #define __NR_inotify_init1 332
#define __NR_perf_counter_open 333
#ifdef __KERNEL__ #ifdef __KERNEL__
......
...@@ -653,7 +653,8 @@ __SYSCALL(__NR_dup3, sys_dup3) ...@@ -653,7 +653,8 @@ __SYSCALL(__NR_dup3, sys_dup3)
__SYSCALL(__NR_pipe2, sys_pipe2) __SYSCALL(__NR_pipe2, sys_pipe2)
#define __NR_inotify_init1 294 #define __NR_inotify_init1 294
__SYSCALL(__NR_inotify_init1, sys_inotify_init1) __SYSCALL(__NR_inotify_init1, sys_inotify_init1)
#define __NR_perf_counter_open 295
__SYSCALL(__NR_perf_counter_open, sys_perf_counter_open)
#ifndef __NO_STUBS #ifndef __NO_STUBS
#define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_READDIR
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/dmar.h> #include <linux/dmar.h>
#include <asm/intel_arch_perfmon.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/mtrr.h> #include <asm/mtrr.h>
...@@ -1147,6 +1148,7 @@ void __cpuinit setup_local_APIC(void) ...@@ -1147,6 +1148,7 @@ void __cpuinit setup_local_APIC(void)
apic_write(APIC_ESR, 0); apic_write(APIC_ESR, 0);
} }
#endif #endif
perf_counters_lapic_init(0);
preempt_disable(); preempt_disable();
......
# #
# Makefile for x86-compatible CPU details and quirks # Makefile for x86-compatible CPU details, features and quirks
# #
obj-y := intel_cacheinfo.o addon_cpuid_features.o obj-y := intel_cacheinfo.o addon_cpuid_features.o
...@@ -16,11 +16,13 @@ obj-$(CONFIG_CPU_SUP_CENTAUR_64) += centaur_64.o ...@@ -16,11 +16,13 @@ obj-$(CONFIG_CPU_SUP_CENTAUR_64) += centaur_64.o
obj-$(CONFIG_CPU_SUP_TRANSMETA_32) += transmeta.o obj-$(CONFIG_CPU_SUP_TRANSMETA_32) += transmeta.o
obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o
obj-$(CONFIG_X86_MCE) += mcheck/ obj-$(CONFIG_PERF_COUNTERS) += perf_counter.o
obj-$(CONFIG_MTRR) += mtrr/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o obj-$(CONFIG_X86_MCE) += mcheck/
obj-$(CONFIG_MTRR) += mtrr/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o
quiet_cmd_mkcapflags = MKCAP $@ quiet_cmd_mkcapflags = MKCAP $@
cmd_mkcapflags = $(PERL) $(srctree)/$(src)/mkcapflags.pl $< $@ cmd_mkcapflags = $(PERL) $(srctree)/$(src)/mkcapflags.pl $< $@
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/mtrr.h> #include <asm/mtrr.h>
#include <asm/mce.h> #include <asm/mce.h>
#include <asm/intel_arch_perfmon.h>
#include <asm/pat.h> #include <asm/pat.h>
#include <asm/asm.h> #include <asm/asm.h>
#include <asm/numa.h> #include <asm/numa.h>
...@@ -750,6 +751,7 @@ void __init identify_boot_cpu(void) ...@@ -750,6 +751,7 @@ void __init identify_boot_cpu(void)
#else #else
vgetcpu_set_mode(); vgetcpu_set_mode();
#endif #endif
init_hw_perf_counters();
} }
void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c) void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
......
This diff is collapsed.
...@@ -984,6 +984,11 @@ apicinterrupt ERROR_APIC_VECTOR \ ...@@ -984,6 +984,11 @@ apicinterrupt ERROR_APIC_VECTOR \
apicinterrupt SPURIOUS_APIC_VECTOR \ apicinterrupt SPURIOUS_APIC_VECTOR \
spurious_interrupt smp_spurious_interrupt spurious_interrupt smp_spurious_interrupt
#ifdef CONFIG_PERF_COUNTERS
apicinterrupt LOCAL_PERF_VECTOR \
perf_counter_interrupt smp_perf_counter_interrupt
#endif
/* /*
* Exception entry points. * Exception entry points.
*/ */
......
...@@ -56,6 +56,10 @@ static int show_other_interrupts(struct seq_file *p) ...@@ -56,6 +56,10 @@ static int show_other_interrupts(struct seq_file *p)
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->apic_timer_irqs); seq_printf(p, "%10u ", irq_stats(j)->apic_timer_irqs);
seq_printf(p, " Local timer interrupts\n"); seq_printf(p, " Local timer interrupts\n");
seq_printf(p, "CNT: ");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->apic_perf_irqs);
seq_printf(p, " Performance counter interrupts\n");
#endif #endif
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
seq_printf(p, "RES: "); seq_printf(p, "RES: ");
...@@ -160,6 +164,7 @@ u64 arch_irq_stat_cpu(unsigned int cpu) ...@@ -160,6 +164,7 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
sum += irq_stats(cpu)->apic_timer_irqs; sum += irq_stats(cpu)->apic_timer_irqs;
sum += irq_stats(cpu)->apic_perf_irqs;
#endif #endif
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
sum += irq_stats(cpu)->irq_resched_count; sum += irq_stats(cpu)->irq_resched_count;
......
...@@ -160,6 +160,9 @@ void __init native_init_IRQ(void) ...@@ -160,6 +160,9 @@ void __init native_init_IRQ(void)
/* IPI vectors for APIC spurious and error interrupts */ /* IPI vectors for APIC spurious and error interrupts */
alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
# ifdef CONFIG_PERF_COUNTERS
alloc_intr_gate(LOCAL_PERF_VECTOR, perf_counter_interrupt);
# endif
#endif #endif
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_MCE_P4THERMAL) #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_MCE_P4THERMAL)
......
...@@ -138,6 +138,11 @@ static void __init apic_intr_init(void) ...@@ -138,6 +138,11 @@ static void __init apic_intr_init(void)
/* IPI vectors for APIC spurious and error interrupts */ /* IPI vectors for APIC spurious and error interrupts */
alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
/* Performance monitoring interrupt: */
#ifdef CONFIG_PERF_COUNTERS
alloc_intr_gate(LOCAL_PERF_VECTOR, perf_counter_interrupt);
#endif
} }
void __init native_init_IRQ(void) void __init native_init_IRQ(void)
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes
* 2000-2002 x86-64 support by Andi Kleen * 2000-2002 x86-64 support by Andi Kleen
*/ */
#include <linux/perf_counter.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/smp.h> #include <linux/smp.h>
...@@ -891,6 +891,11 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) ...@@ -891,6 +891,11 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
tracehook_notify_resume(regs); tracehook_notify_resume(regs);
} }
if (thread_info_flags & _TIF_PERF_COUNTERS) {
clear_thread_flag(TIF_PERF_COUNTERS);
perf_counter_notify(regs);
}
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
clear_thread_flag(TIF_IRET); clear_thread_flag(TIF_IRET);
#endif /* CONFIG_X86_32 */ #endif /* CONFIG_X86_32 */
......
...@@ -332,3 +332,4 @@ ENTRY(sys_call_table) ...@@ -332,3 +332,4 @@ ENTRY(sys_call_table)
.long sys_dup3 /* 330 */ .long sys_dup3 /* 330 */
.long sys_pipe2 .long sys_pipe2
.long sys_inotify_init1 .long sys_inotify_init1
.long sys_perf_counter_open
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