From 849620fab413355eff48232eac5a8c53c57615c5 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 14 May 2009 17:10:52 +0200 Subject: Revert "oprofile: discover counters for op ppro too" This reverts commit 59512900baab03c5629f2ff5efad1d5d4e682ece. arch_perfmon_setup_counters() is actually never called for ppro, so there is no code that changes the numbers in op_ppro_spec. The patch as it is has no effect. Cc: Andi Kleen Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_ppro.c | 8 +++----- arch/x86/oprofile/op_x86_model.h | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 10131fbdaad..2a123990a84 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -213,9 +213,9 @@ static void ppro_shutdown(struct op_msrs const * const msrs) } -struct op_x86_model_spec op_ppro_spec = { - .num_counters = 2, /* can be overriden */ - .num_controls = 2, /* dito */ +struct op_x86_model_spec const op_ppro_spec = { + .num_counters = 2, + .num_controls = 2, .fill_in_addresses = &ppro_fill_in_addresses, .setup_ctrs = &ppro_setup_ctrs, .check_ctrs = &ppro_check_ctrs, @@ -251,8 +251,6 @@ void arch_perfmon_setup_counters(void) op_arch_perfmon_spec.num_counters = num_counters; op_arch_perfmon_spec.num_controls = num_counters; - op_ppro_spec.num_counters = num_counters; - op_ppro_spec.num_controls = num_counters; } struct op_x86_model_spec op_arch_perfmon_spec = { diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 825e79064d6..2317149c94f 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -45,7 +45,7 @@ struct op_x86_model_spec { void (*shutdown)(struct op_msrs const * const msrs); }; -extern struct op_x86_model_spec op_ppro_spec; +extern struct op_x86_model_spec const op_ppro_spec; extern struct op_x86_model_spec const op_p4_spec; extern struct op_x86_model_spec const op_p4_ht2_spec; extern struct op_x86_model_spec const op_amd_spec; -- cgit v1.2.3-18-g5258 From e419294ed3c98cccc145202e4fe165bfd8099d63 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Sun, 12 Oct 2008 15:12:34 -0400 Subject: x86/oprofile: moving arch_perfmon counter setup to op_x86_model_spec.init The function arch_perfmon_init() in nmi_int.c is model specific. This patch moves it to op_model_ppro.c by using the init function pointer in struct op_x86_model_spec. Cc: Andi Kleen Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 21 +++++++++------------ arch/x86/oprofile/op_model_ppro.c | 9 ++++++++- arch/x86/oprofile/op_x86_model.h | 2 -- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 3b285e656e2..dd8515301fb 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -427,7 +427,7 @@ static int __init ppro_init(char **cpu_type) *cpu_type = "i386/core_2"; break; case 26: - arch_perfmon_setup_counters(); + model = &op_arch_perfmon_spec; *cpu_type = "i386/core_i7"; break; case 28: @@ -442,16 +442,6 @@ static int __init ppro_init(char **cpu_type) return 1; } -static int __init arch_perfmon_init(char **cpu_type) -{ - if (!cpu_has_arch_perfmon) - return 0; - *cpu_type = "i386/arch_perfmon"; - model = &op_arch_perfmon_spec; - arch_perfmon_setup_counters(); - return 1; -} - /* in order to get sysfs right */ static int using_nmi; @@ -509,8 +499,15 @@ int __init op_nmi_init(struct oprofile_operations *ops) break; } - if (!cpu_type && !arch_perfmon_init(&cpu_type)) + if (cpu_type) + break; + + if (!cpu_has_arch_perfmon) return -ENODEV; + + /* use arch perfmon as fallback */ + cpu_type = "i386/arch_perfmon"; + model = &op_arch_perfmon_spec; break; default: diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 2a123990a84..ae581196688 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -233,7 +233,7 @@ struct op_x86_model_spec const op_ppro_spec = { * the specific CPU. */ -void arch_perfmon_setup_counters(void) +static void arch_perfmon_setup_counters(void) { union cpuid10_eax eax; @@ -253,7 +253,14 @@ void arch_perfmon_setup_counters(void) op_arch_perfmon_spec.num_controls = num_counters; } +static int arch_perfmon_init(struct oprofile_operations *ignore) +{ + arch_perfmon_setup_counters(); + return 0; +} + struct op_x86_model_spec op_arch_perfmon_spec = { + .init = &arch_perfmon_init, /* num_counters/num_controls filled in at runtime */ .fill_in_addresses = &ppro_fill_in_addresses, /* user space does the cpuid check for available events */ diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 2317149c94f..ed27783bb0d 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -51,6 +51,4 @@ extern struct op_x86_model_spec const op_p4_ht2_spec; extern struct op_x86_model_spec const op_amd_spec; extern struct op_x86_model_spec op_arch_perfmon_spec; -extern void arch_perfmon_setup_counters(void); - #endif /* OP_X86_MODEL_H */ -- cgit v1.2.3-18-g5258 From 06552ccc36abeb12e37efc16c384dc7f30794f85 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 28 May 2009 02:12:36 +0200 Subject: x86/oprofile: minor style changes in struct op_x86_model_spec Some vertical alignments. Variables are now located in the beginning of the struct. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_x86_model.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index ed27783bb0d..bd8157d12ff 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -32,17 +32,17 @@ struct pt_regs; * various x86 CPU models' perfctr support. */ struct op_x86_model_spec { - int (*init)(struct oprofile_operations *ops); - void (*exit)(void); - unsigned int num_counters; - unsigned int num_controls; - void (*fill_in_addresses)(struct op_msrs * const msrs); - void (*setup_ctrs)(struct op_msrs const * const msrs); - int (*check_ctrs)(struct pt_regs * const regs, - struct op_msrs const * const msrs); - void (*start)(struct op_msrs const * const msrs); - void (*stop)(struct op_msrs const * const msrs); - void (*shutdown)(struct op_msrs const * const msrs); + unsigned int num_counters; + unsigned int num_controls; + int (*init)(struct oprofile_operations *ops); + void (*exit)(void); + void (*fill_in_addresses)(struct op_msrs * const msrs); + void (*setup_ctrs)(struct op_msrs const * const msrs); + int (*check_ctrs)(struct pt_regs * const regs, + struct op_msrs const * const msrs); + void (*start)(struct op_msrs const * const msrs); + void (*stop)(struct op_msrs const * const msrs); + void (*shutdown)(struct op_msrs const * const msrs); }; extern struct op_x86_model_spec const op_ppro_spec; -- cgit v1.2.3-18-g5258 From 0dc8335aa3e59f1adbb0fce7c9c0b342146cd036 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 7 May 2009 15:09:33 +0200 Subject: oprofile: remove irq_flags in struct op_entry This became obsolete with this commit: 304cc6a ring_buffer: remove unused flags parameter, fix Signed-off-by: Robert Richter --- include/linux/oprofile.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index 1d9518bc4c5..dbbe2dbc441 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -171,7 +171,6 @@ struct op_sample; struct op_entry { struct ring_buffer_event *event; struct op_sample *sample; - unsigned long irq_flags; unsigned long size; unsigned long *data; }; -- cgit v1.2.3-18-g5258 From fecfe6320ba71eed6d16849683298f0894aa60de Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 7 May 2009 16:07:41 +0200 Subject: oprofile: remove obselete include headers This became obsolete with this commit: 6dad828 oprofile: port to the new ring_buffer Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 242257b1944..50640cc5eef 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -21,7 +21,6 @@ #include #include -#include #include #include "event_buffer.h" -- cgit v1.2.3-18-g5258 From 9063759540daac40cc1f402f83a3be6b489f8583 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 10 Mar 2009 19:15:57 +0100 Subject: x86/oprofile: remove #ifdefs in ibs functions IBS code is moved to separate functions. This allows the removal of #ifdefs in functions. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 80 +++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 8fdf06e4edf..b54c0880b7d 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -220,6 +220,50 @@ op_amd_handle_ibs(struct pt_regs * const regs, return 1; } +static inline void op_amd_start_ibs(void) +{ + unsigned int low, high; + if (has_ibs && ibs_config.fetch_enabled) { + low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; + high = ((ibs_config.rand_en & 0x1) << 25) /* bit 57 */ + + IBS_FETCH_HIGH_ENABLE; + wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); + } + + if (has_ibs && ibs_config.op_enabled) { + low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) + + ((ibs_config.dispatched_ops & 0x1) << 19) /* bit 19 */ + + IBS_OP_LOW_ENABLE; + high = 0; + wrmsr(MSR_AMD64_IBSOPCTL, low, high); + } +} + +static void op_amd_stop_ibs(void) +{ + unsigned int low, high; + if (has_ibs && ibs_config.fetch_enabled) { + /* clear max count and enable */ + low = 0; + high = 0; + wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); + } + + if (has_ibs && ibs_config.op_enabled) { + /* clear max count and enable */ + low = 0; + high = 0; + wrmsr(MSR_AMD64_IBSOPCTL, low, high); + } +} + +#else + +static inline int op_amd_handle_ibs(struct pt_regs * const regs, + struct op_msrs const * const msrs) { } +static inline void op_amd_start_ibs(void) { } +static inline void op_amd_stop_ibs(void) { } + #endif static int op_amd_check_ctrs(struct pt_regs * const regs, @@ -238,9 +282,7 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, } } -#ifdef CONFIG_OPROFILE_IBS op_amd_handle_ibs(regs, msrs); -#endif /* See op_model_ppro.c */ return 1; @@ -258,25 +300,9 @@ static void op_amd_start(struct op_msrs const * const msrs) } } -#ifdef CONFIG_OPROFILE_IBS - if (has_ibs && ibs_config.fetch_enabled) { - low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; - high = ((ibs_config.rand_en & 0x1) << 25) /* bit 57 */ - + IBS_FETCH_HIGH_ENABLE; - wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); - } - - if (has_ibs && ibs_config.op_enabled) { - low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) - + ((ibs_config.dispatched_ops & 0x1) << 19) /* bit 19 */ - + IBS_OP_LOW_ENABLE; - high = 0; - wrmsr(MSR_AMD64_IBSOPCTL, low, high); - } -#endif + op_amd_start_ibs(); } - static void op_amd_stop(struct op_msrs const * const msrs) { unsigned int low, high; @@ -294,21 +320,7 @@ static void op_amd_stop(struct op_msrs const * const msrs) CTRL_WRITE(low, high, msrs, i); } -#ifdef CONFIG_OPROFILE_IBS - if (has_ibs && ibs_config.fetch_enabled) { - /* clear max count and enable */ - low = 0; - high = 0; - wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); - } - - if (has_ibs && ibs_config.op_enabled) { - /* clear max count and enable */ - low = 0; - high = 0; - wrmsr(MSR_AMD64_IBSOPCTL, low, high); - } -#endif + op_amd_stop_ibs(); } static void op_amd_shutdown(struct op_msrs const * const msrs) -- cgit v1.2.3-18-g5258 From d20f24c66011f8a397bca6c5d1a6a7c7e612d2d7 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Sun, 11 Jan 2009 13:01:16 +0100 Subject: x86/oprofile: simplify AMD cpu init code Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index dd8515301fb..ae0ab03959b 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -460,27 +460,26 @@ int __init op_nmi_init(struct oprofile_operations *ops) /* Needs to be at least an Athlon (or hammer in 32bit mode) */ switch (family) { - default: - return -ENODEV; case 6: - model = &op_amd_spec; cpu_type = "i386/athlon"; break; case 0xf: - model = &op_amd_spec; - /* Actually it could be i386/hammer too, but give - user space an consistent name. */ + /* + * Actually it could be i386/hammer too, but + * give user space an consistent name. + */ cpu_type = "x86-64/hammer"; break; case 0x10: - model = &op_amd_spec; cpu_type = "x86-64/family10"; break; case 0x11: - model = &op_amd_spec; cpu_type = "x86-64/family11h"; break; + default: + return -ENODEV; } + model = &op_amd_spec; break; case X86_VENDOR_INTEL: -- cgit v1.2.3-18-g5258 From ff9faa8b676e195476b86f03fe58db0f01bda8f3 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 22 May 2009 15:36:29 +0200 Subject: x86/oprofile: move common macros to op_x86_model.h There are duplicate macro implementations in model specific code. This patch moves all common macros to op_x86_model.h. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 8 -------- arch/x86/oprofile/op_model_p4.c | 2 -- arch/x86/oprofile/op_model_ppro.c | 8 -------- arch/x86/oprofile/op_x86_model.h | 9 +++++++++ 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index b54c0880b7d..4b9254a67e6 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -26,22 +26,14 @@ #define NUM_COUNTERS 4 #define NUM_CONTROLS 4 -#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0) #define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0) #define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0) #define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) -#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0) #define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0) #define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0) -#define CTRL_SET_ACTIVE(n) (n |= (1<<22)) -#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22)) #define CTRL_CLEAR_LO(x) (x &= (1<<21)) #define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0) -#define CTRL_SET_ENABLE(val) (val |= 1<<20) -#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16)) -#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17)) -#define CTRL_SET_UM(val, m) (val |= (m << 8)) #define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff)) #define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf)) #define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9)) diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 819b131fd75..420c15e7123 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -366,8 +366,6 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = { #define CCCR_OVF_P(cccr) ((cccr) & (1U<<31)) #define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31))) -#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0) -#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0) #define CTR_READ(l, h, i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h)); } while (0) #define CTR_WRITE(l, i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1); } while (0) #define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000)) diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index ae581196688..a922a1a815c 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -26,19 +26,11 @@ static int num_counters = 2; static int counter_width = 32; -#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0) #define CTR_OVERFLOWED(n) (!((n) & (1ULL<<(counter_width-1)))) -#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0) #define CTRL_READ(l, h, msrs, c) do {rdmsr((msrs->controls[(c)].addr), (l), (h)); } while (0) #define CTRL_WRITE(l, h, msrs, c) do {wrmsr((msrs->controls[(c)].addr), (l), (h)); } while (0) -#define CTRL_SET_ACTIVE(n) (n |= (1<<22)) -#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22)) #define CTRL_CLEAR(x) (x &= (1<<21)) -#define CTRL_SET_ENABLE(val) (val |= 1<<20) -#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16)) -#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17)) -#define CTRL_SET_UM(val, m) (val |= (m << 8)) #define CTRL_SET_EVENT(val, e) (val |= e) static u64 *reset_value; diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index bd8157d12ff..c80ec7d0999 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -11,6 +11,15 @@ #ifndef OP_X86_MODEL_H #define OP_X86_MODEL_H +#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0) +#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0) +#define CTRL_SET_ACTIVE(n) (n |= (1<<22)) +#define CTRL_SET_ENABLE(val) (val |= 1<<20) +#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22)) +#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17)) +#define CTRL_SET_UM(val, m) (val |= (m << 8)) +#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16)) + struct op_saved_msr { unsigned int high; unsigned int low; -- cgit v1.2.3-18-g5258 From d2731a4387ad6c6bca07abfe9ed41d450fb6d665 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 22 May 2009 19:47:38 +0200 Subject: x86/oprofile: remove MSR macros for AMD cpus The macros CTRL_READ() and CTRL_WRITE() make the code hard to read and maintain. This patch replaces them by rdmsr()/wrmsr() functions and simplifies the code. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 4b9254a67e6..c6181c265ae 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -26,12 +26,7 @@ #define NUM_COUNTERS 4 #define NUM_CONTROLS 4 -#define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0) -#define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0) #define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) - -#define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0) -#define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0) #define CTRL_CLEAR_LO(x) (x &= (1<<21)) #define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0) #define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff)) @@ -101,17 +96,17 @@ static void op_amd_setup_ctrs(struct op_msrs const * const msrs) for (i = 0 ; i < NUM_CONTROLS; ++i) { if (unlikely(!CTRL_IS_RESERVED(msrs, i))) continue; - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_CLEAR_LO(low); CTRL_CLEAR_HI(high); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } /* avoid a false detection of ctr overflows in NMI handler */ for (i = 0; i < NUM_COUNTERS; ++i) { if (unlikely(!CTR_IS_RESERVED(msrs, i))) continue; - CTR_WRITE(1, msrs, i); + wrmsr(msrs->counters[i].addr, -1, -1); } /* enable active counters */ @@ -119,9 +114,9 @@ static void op_amd_setup_ctrs(struct op_msrs const * const msrs) if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { reset_value[i] = counter_config[i].count; - CTR_WRITE(counter_config[i].count, msrs, i); + wrmsr(msrs->counters[i].addr, -(unsigned int)counter_config[i].count, -1); - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_CLEAR_LO(low); CTRL_CLEAR_HI(high); CTRL_SET_ENABLE(low); @@ -133,7 +128,7 @@ static void op_amd_setup_ctrs(struct op_msrs const * const msrs) CTRL_SET_HOST_ONLY(high, 0); CTRL_SET_GUEST_ONLY(high, 0); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } else { reset_value[i] = 0; } @@ -267,10 +262,10 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, for (i = 0 ; i < NUM_COUNTERS; ++i) { if (!reset_value[i]) continue; - CTR_READ(low, high, msrs, i); + rdmsr(msrs->counters[i].addr, low, high); if (CTR_OVERFLOWED(low)) { oprofile_add_sample(regs, i); - CTR_WRITE(reset_value[i], msrs, i); + wrmsr(msrs->counters[i].addr, -(unsigned int)reset_value[i], -1); } } @@ -286,9 +281,9 @@ static void op_amd_start(struct op_msrs const * const msrs) int i; for (i = 0 ; i < NUM_COUNTERS ; ++i) { if (reset_value[i]) { - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_SET_ACTIVE(low); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } } @@ -307,9 +302,9 @@ static void op_amd_stop(struct op_msrs const * const msrs) for (i = 0 ; i < NUM_COUNTERS ; ++i) { if (!reset_value[i]) continue; - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_SET_INACTIVE(low); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } op_amd_stop_ibs(); -- cgit v1.2.3-18-g5258 From 74c9a5c341bb1f6cbb5095b07c77230f19682ce8 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 22 May 2009 19:47:38 +0200 Subject: x86/oprofile: remove MSR macros for ppro cpus The macros CTRL_READ() and CTRL_WRITE() make the code hard to read and maintain. This patch replaces them by rdmsr()/wrmsr() functions and simplifies the code. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_ppro.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index a922a1a815c..6c5d288c566 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -27,9 +27,6 @@ static int num_counters = 2; static int counter_width = 32; #define CTR_OVERFLOWED(n) (!((n) & (1ULL<<(counter_width-1)))) - -#define CTRL_READ(l, h, msrs, c) do {rdmsr((msrs->controls[(c)].addr), (l), (h)); } while (0) -#define CTRL_WRITE(l, h, msrs, c) do {wrmsr((msrs->controls[(c)].addr), (l), (h)); } while (0) #define CTRL_CLEAR(x) (x &= (1<<21)) #define CTRL_SET_EVENT(val, e) (val |= e) @@ -88,9 +85,9 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs) for (i = 0 ; i < num_counters; ++i) { if (unlikely(!CTRL_IS_RESERVED(msrs, i))) continue; - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_CLEAR(low); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } /* avoid a false detection of ctr overflows in NMI handler */ @@ -107,14 +104,14 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs) wrmsrl(msrs->counters[i].addr, -reset_value[i]); - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_CLEAR(low); CTRL_SET_ENABLE(low); CTRL_SET_USR(low, counter_config[i].user); CTRL_SET_KERN(low, counter_config[i].kernel); CTRL_SET_UM(low, counter_config[i].unit_mask); CTRL_SET_EVENT(low, counter_config[i].event); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } else { reset_value[i] = 0; } @@ -162,9 +159,9 @@ static void ppro_start(struct op_msrs const * const msrs) return; for (i = 0; i < num_counters; ++i) { if (reset_value[i]) { - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_SET_ACTIVE(low); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } } } @@ -180,9 +177,9 @@ static void ppro_stop(struct op_msrs const * const msrs) for (i = 0; i < num_counters; ++i) { if (!reset_value[i]) continue; - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_SET_INACTIVE(low); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } } -- cgit v1.2.3-18-g5258 From 1131a478245b00664ae2dbc0f68db987b51fa806 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 20:23:23 +0200 Subject: x86/oprofile: remove MSR macros for p4 cpus The macros CTRL_READ() and CTRL_WRITE() make the code hard to read and maintain. This patch replaces them by rdmsr()/wrmsr() functions and simplifies the code. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_p4.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 420c15e7123..365d8a9c03d 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -350,8 +350,6 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = { #define ESCR_SET_OS_1(escr, os) ((escr) |= (((os) & 1) << 1)) #define ESCR_SET_EVENT_SELECT(escr, sel) ((escr) |= (((sel) & 0x3f) << 25)) #define ESCR_SET_EVENT_MASK(escr, mask) ((escr) |= (((mask) & 0xffff) << 9)) -#define ESCR_READ(escr, high, ev, i) do {rdmsr(ev->bindings[(i)].escr_address, (escr), (high)); } while (0) -#define ESCR_WRITE(escr, high, ev, i) do {wrmsr(ev->bindings[(i)].escr_address, (escr), (high)); } while (0) #define CCCR_RESERVED_BITS 0x38030FFF #define CCCR_CLEAR(cccr) ((cccr) &= CCCR_RESERVED_BITS) @@ -361,13 +359,9 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = { #define CCCR_SET_PMI_OVF_1(cccr) ((cccr) |= (1<<27)) #define CCCR_SET_ENABLE(cccr) ((cccr) |= (1<<12)) #define CCCR_SET_DISABLE(cccr) ((cccr) &= ~(1<<12)) -#define CCCR_READ(low, high, i) do {rdmsr(p4_counters[(i)].cccr_address, (low), (high)); } while (0) -#define CCCR_WRITE(low, high, i) do {wrmsr(p4_counters[(i)].cccr_address, (low), (high)); } while (0) #define CCCR_OVF_P(cccr) ((cccr) & (1U<<31)) #define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31))) -#define CTR_READ(l, h, i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h)); } while (0) -#define CTR_WRITE(l, i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1); } while (0) #define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000)) @@ -513,7 +507,7 @@ static void pmc_setup_one_p4_counter(unsigned int ctr) if (ev->bindings[i].virt_counter & counter_bit) { /* modify ESCR */ - ESCR_READ(escr, high, ev, i); + rdmsr(ev->bindings[i].escr_address, escr, high); ESCR_CLEAR(escr); if (stag == 0) { ESCR_SET_USR_0(escr, counter_config[ctr].user); @@ -524,10 +518,11 @@ static void pmc_setup_one_p4_counter(unsigned int ctr) } ESCR_SET_EVENT_SELECT(escr, ev->event_select); ESCR_SET_EVENT_MASK(escr, counter_config[ctr].unit_mask); - ESCR_WRITE(escr, high, ev, i); + wrmsr(ev->bindings[i].escr_address, escr, high); /* modify CCCR */ - CCCR_READ(cccr, high, VIRT_CTR(stag, ctr)); + rdmsr(p4_counters[VIRT_CTR(stag, ctr)].cccr_address, + cccr, high); CCCR_CLEAR(cccr); CCCR_SET_REQUIRED_BITS(cccr); CCCR_SET_ESCR_SELECT(cccr, ev->escr_select); @@ -535,7 +530,8 @@ static void pmc_setup_one_p4_counter(unsigned int ctr) CCCR_SET_PMI_OVF_0(cccr); else CCCR_SET_PMI_OVF_1(cccr); - CCCR_WRITE(cccr, high, VIRT_CTR(stag, ctr)); + wrmsr(p4_counters[VIRT_CTR(stag, ctr)].cccr_address, + cccr, high); return; } } @@ -582,7 +578,8 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs) if ((counter_config[i].enabled) && (CTRL_IS_RESERVED(msrs, i))) { reset_value[i] = counter_config[i].count; pmc_setup_one_p4_counter(i); - CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i)); + wrmsr(p4_counters[VIRT_CTR(stag, i)].counter_address, + -(u32)counter_config[i].count, -1); } else { reset_value[i] = 0; } @@ -622,14 +619,16 @@ static int p4_check_ctrs(struct pt_regs * const regs, real = VIRT_CTR(stag, i); - CCCR_READ(low, high, real); - CTR_READ(ctr, high, real); + rdmsr(p4_counters[real].cccr_address, low, high); + rdmsr(p4_counters[real].counter_address, ctr, high); if (CCCR_OVF_P(low) || CTR_OVERFLOW_P(ctr)) { oprofile_add_sample(regs, i); - CTR_WRITE(reset_value[i], real); + wrmsr(p4_counters[real].counter_address, + -(u32)reset_value[i], -1); CCCR_CLEAR_OVF(low); - CCCR_WRITE(low, high, real); - CTR_WRITE(reset_value[i], real); + wrmsr(p4_counters[real].cccr_address, low, high); + wrmsr(p4_counters[real].counter_address, + -(u32)reset_value[i], -1); } } @@ -651,9 +650,9 @@ static void p4_start(struct op_msrs const * const msrs) for (i = 0; i < num_counters; ++i) { if (!reset_value[i]) continue; - CCCR_READ(low, high, VIRT_CTR(stag, i)); + rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high); CCCR_SET_ENABLE(low); - CCCR_WRITE(low, high, VIRT_CTR(stag, i)); + wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high); } } @@ -668,9 +667,9 @@ static void p4_stop(struct op_msrs const * const msrs) for (i = 0; i < num_counters; ++i) { if (!reset_value[i]) continue; - CCCR_READ(low, high, VIRT_CTR(stag, i)); + rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high); CCCR_SET_DISABLE(low); - CCCR_WRITE(low, high, VIRT_CTR(stag, i)); + wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high); } } -- cgit v1.2.3-18-g5258 From ec064c093e254f4433afb17dcef7f964c76436af Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 15:05:50 +0200 Subject: x86/oprofile: fix and cleanup CTRL_SET_* macros This patch fixes missing braces around macro parameters. Macro definitions from intel_arch_perfmon.h are used where possible. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_ppro.c | 1 - arch/x86/oprofile/op_x86_model.h | 18 ++++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 6c5d288c566..61ee8f64053 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -18,7 +18,6 @@ #include #include #include -#include #include "op_x86_model.h" #include "op_counter.h" diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index c80ec7d0999..a207b1c46e2 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -11,14 +11,16 @@ #ifndef OP_X86_MODEL_H #define OP_X86_MODEL_H -#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0) -#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0) -#define CTRL_SET_ACTIVE(n) (n |= (1<<22)) -#define CTRL_SET_ENABLE(val) (val |= 1<<20) -#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22)) -#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17)) -#define CTRL_SET_UM(val, m) (val |= (m << 8)) -#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16)) +#include + +#define CTR_IS_RESERVED(msrs, c) ((msrs)->counters[(c)].addr ? 1 : 0) +#define CTRL_IS_RESERVED(msrs, c) ((msrs)->controls[(c)].addr ? 1 : 0) +#define CTRL_SET_ACTIVE(val) ((val) |= ARCH_PERFMON_EVENTSEL0_ENABLE) +#define CTRL_SET_ENABLE(val) ((val) |= ARCH_PERFMON_EVENTSEL_INT) +#define CTRL_SET_INACTIVE(val) ((val) &= ~ARCH_PERFMON_EVENTSEL0_ENABLE) +#define CTRL_SET_KERN(val, k) ((val) |= ((k) ? ARCH_PERFMON_EVENTSEL_OS : 0)) +#define CTRL_SET_USR(val, u) ((val) |= ((u) ? ARCH_PERFMON_EVENTSEL_USR : 0)) +#define CTRL_SET_UM(val, m) ((val) |= ((m) << 8)) struct op_saved_msr { unsigned int high; -- cgit v1.2.3-18-g5258 From 9c59354b48ce9cf28048b02fea73dd0236f876ea Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 18:16:43 +0200 Subject: x86/oprofile: remove unused macros for AMD virtualization profiling The use of the macros has no effect. The oprofilefs has to be extended first to support these features. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index c6181c265ae..aaa7ffaed6b 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -31,8 +31,6 @@ #define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0) #define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff)) #define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf)) -#define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9)) -#define CTRL_SET_GUEST_ONLY(val, h) (val |= ((h & 1) << 8)) static unsigned long reset_value[NUM_COUNTERS]; @@ -125,9 +123,6 @@ static void op_amd_setup_ctrs(struct op_msrs const * const msrs) CTRL_SET_UM(low, counter_config[i].unit_mask); CTRL_SET_EVENT_LOW(low, counter_config[i].event); CTRL_SET_EVENT_HIGH(high, counter_config[i].event); - CTRL_SET_HOST_ONLY(high, 0); - CTRL_SET_GUEST_ONLY(high, 0); - wrmsr(msrs->controls[i].addr, low, high); } else { reset_value[i] = 0; -- cgit v1.2.3-18-g5258 From ef8828ddf828174785421af67c281144d4b8e796 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 19:31:44 +0200 Subject: x86/oprofile: pass the model to setup_ctrs() functions In follow-on patches the setup_ctrs() functions will need data that describes the model. This patch extends the function argument list to pass a pointer of the model to these function. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 2 +- arch/x86/oprofile/op_model_amd.c | 3 ++- arch/x86/oprofile/op_model_p4.c | 3 ++- arch/x86/oprofile/op_model_ppro.c | 3 ++- arch/x86/oprofile/op_x86_model.h | 3 ++- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index ae0ab03959b..c31f87bbf43 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -125,7 +125,7 @@ static void nmi_cpu_setup(void *dummy) int cpu = smp_processor_id(); struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); spin_lock(&oprofilefs_lock); - model->setup_ctrs(msrs); + model->setup_ctrs(model, msrs); spin_unlock(&oprofilefs_lock); per_cpu(saved_lvtpc, cpu) = apic_read(APIC_LVTPC); apic_write(APIC_LVTPC, APIC_DM_NMI); diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index aaa7ffaed6b..86e0a01ba12 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -85,7 +85,8 @@ static void op_amd_fill_in_addresses(struct op_msrs * const msrs) } -static void op_amd_setup_ctrs(struct op_msrs const * const msrs) +static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, + struct op_msrs const * const msrs) { unsigned int low, high; int i; diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 365d8a9c03d..05ba0287b1f 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -542,7 +542,8 @@ static void pmc_setup_one_p4_counter(unsigned int ctr) } -static void p4_setup_ctrs(struct op_msrs const * const msrs) +static void p4_setup_ctrs(struct op_x86_model_spec const *model, + struct op_msrs const * const msrs) { unsigned int i; unsigned int low, high; diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 61ee8f64053..40b44ee521d 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -51,7 +51,8 @@ static void ppro_fill_in_addresses(struct op_msrs * const msrs) } -static void ppro_setup_ctrs(struct op_msrs const * const msrs) +static void ppro_setup_ctrs(struct op_x86_model_spec const *model, + struct op_msrs const * const msrs) { unsigned int low, high; int i; diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index a207b1c46e2..6161c7f0e7f 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -48,7 +48,8 @@ struct op_x86_model_spec { int (*init)(struct oprofile_operations *ops); void (*exit)(void); void (*fill_in_addresses)(struct op_msrs * const msrs); - void (*setup_ctrs)(struct op_msrs const * const msrs); + void (*setup_ctrs)(struct op_x86_model_spec const *model, + struct op_msrs const * const msrs); int (*check_ctrs)(struct pt_regs * const regs, struct op_msrs const * const msrs); void (*start)(struct op_msrs const * const msrs); -- cgit v1.2.3-18-g5258 From 3370d358569755625aba4d9a846a040ce691d9ed Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 15:10:32 +0200 Subject: x86/oprofile: replace macros to calculate control register This patch introduces op_x86_get_ctrl() to calculate the value of the performance control register. This is generic code usable for all models. The event and reserved masks are model specific and stored in struct op_x86_model_spec. 64 bit MSR functions are used now. The patch removes many hard to read macros used for ctrl calculation. The function op_x86_get_ctrl() is common code and the first step to further merge performance counter implementations for x86 models. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 20 +++++++++++++++++++ arch/x86/oprofile/op_model_amd.c | 41 +++++++++++++++------------------------ arch/x86/oprofile/op_model_ppro.c | 29 +++++++++++++-------------- arch/x86/oprofile/op_x86_model.h | 15 ++++++++++---- 4 files changed, 60 insertions(+), 45 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index c31f87bbf43..388ee15e0e4 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -31,6 +31,26 @@ static DEFINE_PER_CPU(unsigned long, saved_lvtpc); /* 0 == registered but off, 1 == registered and on */ static int nmi_enabled = 0; +/* common functions */ + +u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, + struct op_counter_config *counter_config) +{ + u64 val = 0; + u16 event = (u16)counter_config->event; + + val |= ARCH_PERFMON_EVENTSEL_INT; + val |= counter_config->user ? ARCH_PERFMON_EVENTSEL_USR : 0; + val |= counter_config->kernel ? ARCH_PERFMON_EVENTSEL_OS : 0; + val |= (counter_config->unit_mask & 0xFF) << 8; + event &= model->event_mask ? model->event_mask : 0xFF; + val |= event & 0xFF; + val |= (event & 0x0F00) << 24; + + return val; +} + + static int profile_exceptions_notify(struct notifier_block *self, unsigned long val, void *data) { diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 86e0a01ba12..2406ab86360 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -25,12 +25,11 @@ #define NUM_COUNTERS 4 #define NUM_CONTROLS 4 +#define OP_EVENT_MASK 0x0FFF + +#define MSR_AMD_EVENTSEL_RESERVED ((0xFFFFFCF0ULL<<32)|(1ULL<<21)) #define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) -#define CTRL_CLEAR_LO(x) (x &= (1<<21)) -#define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0) -#define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff)) -#define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf)) static unsigned long reset_value[NUM_COUNTERS]; @@ -84,21 +83,19 @@ static void op_amd_fill_in_addresses(struct op_msrs * const msrs) } } - static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, struct op_msrs const * const msrs) { - unsigned int low, high; + u64 val; int i; /* clear all counters */ for (i = 0 ; i < NUM_CONTROLS; ++i) { if (unlikely(!CTRL_IS_RESERVED(msrs, i))) continue; - rdmsr(msrs->controls[i].addr, low, high); - CTRL_CLEAR_LO(low); - CTRL_CLEAR_HI(high); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + wrmsrl(msrs->controls[i].addr, val); } /* avoid a false detection of ctr overflows in NMI handler */ @@ -112,19 +109,11 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, for (i = 0; i < NUM_COUNTERS; ++i) { if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { reset_value[i] = counter_config[i].count; - wrmsr(msrs->counters[i].addr, -(unsigned int)counter_config[i].count, -1); - - rdmsr(msrs->controls[i].addr, low, high); - CTRL_CLEAR_LO(low); - CTRL_CLEAR_HI(high); - CTRL_SET_ENABLE(low); - CTRL_SET_USR(low, counter_config[i].user); - CTRL_SET_KERN(low, counter_config[i].kernel); - CTRL_SET_UM(low, counter_config[i].unit_mask); - CTRL_SET_EVENT_LOW(low, counter_config[i].event); - CTRL_SET_EVENT_HIGH(high, counter_config[i].event); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + val |= op_x86_get_ctrl(model, &counter_config[i]); + wrmsrl(msrs->controls[i].addr, val); } else { reset_value[i] = 0; } @@ -486,14 +475,16 @@ static void op_amd_exit(void) {} #endif /* CONFIG_OPROFILE_IBS */ struct op_x86_model_spec const op_amd_spec = { - .init = op_amd_init, - .exit = op_amd_exit, .num_counters = NUM_COUNTERS, .num_controls = NUM_CONTROLS, + .reserved = MSR_AMD_EVENTSEL_RESERVED, + .event_mask = OP_EVENT_MASK, + .init = op_amd_init, + .exit = op_amd_exit, .fill_in_addresses = &op_amd_fill_in_addresses, .setup_ctrs = &op_amd_setup_ctrs, .check_ctrs = &op_amd_check_ctrs, .start = &op_amd_start, .stop = &op_amd_stop, - .shutdown = &op_amd_shutdown + .shutdown = &op_amd_shutdown, }; diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 40b44ee521d..3092f998baf 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -10,6 +10,7 @@ * @author Philippe Elie * @author Graydon Hoare * @author Andi Kleen + * @author Robert Richter */ #include @@ -26,8 +27,8 @@ static int num_counters = 2; static int counter_width = 32; #define CTR_OVERFLOWED(n) (!((n) & (1ULL<<(counter_width-1)))) -#define CTRL_CLEAR(x) (x &= (1<<21)) -#define CTRL_SET_EVENT(val, e) (val |= e) + +#define MSR_PPRO_EVENTSEL_RESERVED ((0xFFFFFFFFULL<<32)|(1ULL<<21)) static u64 *reset_value; @@ -54,7 +55,7 @@ static void ppro_fill_in_addresses(struct op_msrs * const msrs) static void ppro_setup_ctrs(struct op_x86_model_spec const *model, struct op_msrs const * const msrs) { - unsigned int low, high; + u64 val; int i; if (!reset_value) { @@ -85,9 +86,9 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model, for (i = 0 ; i < num_counters; ++i) { if (unlikely(!CTRL_IS_RESERVED(msrs, i))) continue; - rdmsr(msrs->controls[i].addr, low, high); - CTRL_CLEAR(low); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + wrmsrl(msrs->controls[i].addr, val); } /* avoid a false detection of ctr overflows in NMI handler */ @@ -101,17 +102,11 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model, for (i = 0; i < num_counters; ++i) { if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { reset_value[i] = counter_config[i].count; - wrmsrl(msrs->counters[i].addr, -reset_value[i]); - - rdmsr(msrs->controls[i].addr, low, high); - CTRL_CLEAR(low); - CTRL_SET_ENABLE(low); - CTRL_SET_USR(low, counter_config[i].user); - CTRL_SET_KERN(low, counter_config[i].kernel); - CTRL_SET_UM(low, counter_config[i].unit_mask); - CTRL_SET_EVENT(low, counter_config[i].event); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + val |= op_x86_get_ctrl(model, &counter_config[i]); + wrmsrl(msrs->controls[i].addr, val); } else { reset_value[i] = 0; } @@ -205,6 +200,7 @@ static void ppro_shutdown(struct op_msrs const * const msrs) struct op_x86_model_spec const op_ppro_spec = { .num_counters = 2, .num_controls = 2, + .reserved = MSR_PPRO_EVENTSEL_RESERVED, .fill_in_addresses = &ppro_fill_in_addresses, .setup_ctrs = &ppro_setup_ctrs, .check_ctrs = &ppro_check_ctrs, @@ -249,6 +245,7 @@ static int arch_perfmon_init(struct oprofile_operations *ignore) } struct op_x86_model_spec op_arch_perfmon_spec = { + .reserved = MSR_PPRO_EVENTSEL_RESERVED, .init = &arch_perfmon_init, /* num_counters/num_controls filled in at runtime */ .fill_in_addresses = &ppro_fill_in_addresses, diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 6161c7f0e7f..3220d4ce632 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -6,21 +6,19 @@ * @remark Read the file COPYING * * @author Graydon Hoare + * @author Robert Richter */ #ifndef OP_X86_MODEL_H #define OP_X86_MODEL_H +#include #include #define CTR_IS_RESERVED(msrs, c) ((msrs)->counters[(c)].addr ? 1 : 0) #define CTRL_IS_RESERVED(msrs, c) ((msrs)->controls[(c)].addr ? 1 : 0) #define CTRL_SET_ACTIVE(val) ((val) |= ARCH_PERFMON_EVENTSEL0_ENABLE) -#define CTRL_SET_ENABLE(val) ((val) |= ARCH_PERFMON_EVENTSEL_INT) #define CTRL_SET_INACTIVE(val) ((val) &= ~ARCH_PERFMON_EVENTSEL0_ENABLE) -#define CTRL_SET_KERN(val, k) ((val) |= ((k) ? ARCH_PERFMON_EVENTSEL_OS : 0)) -#define CTRL_SET_USR(val, u) ((val) |= ((u) ? ARCH_PERFMON_EVENTSEL_USR : 0)) -#define CTRL_SET_UM(val, m) ((val) |= ((m) << 8)) struct op_saved_msr { unsigned int high; @@ -39,12 +37,16 @@ struct op_msrs { struct pt_regs; +struct oprofile_operations; + /* The model vtable abstracts the differences between * various x86 CPU models' perfctr support. */ struct op_x86_model_spec { unsigned int num_counters; unsigned int num_controls; + u64 reserved; + u16 event_mask; int (*init)(struct oprofile_operations *ops); void (*exit)(void); void (*fill_in_addresses)(struct op_msrs * const msrs); @@ -57,6 +59,11 @@ struct op_x86_model_spec { void (*shutdown)(struct op_msrs const * const msrs); }; +struct op_counter_config; + +extern u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, + struct op_counter_config *counter_config); + extern struct op_x86_model_spec const op_ppro_spec; extern struct op_x86_model_spec const op_p4_spec; extern struct op_x86_model_spec const op_p4_ht2_spec; -- cgit v1.2.3-18-g5258 From 42399adb239d4f1413899cc618ecf640779e79df Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 17:59:06 +0200 Subject: x86/oprofile: replace CTR_OVERFLOWED macros The patch replaces all CTR_OVERFLOWED macros. 64 bit MSR functions and 64 bit counter values are used now. Thus, it will be easier to later extend the models to use more than 32 bit width counters. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 16 ++++++++-------- arch/x86/oprofile/op_model_p4.c | 6 +++--- arch/x86/oprofile/op_model_ppro.c | 10 ++++------ 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 2406ab86360..b5d678fbf03 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -26,11 +26,10 @@ #define NUM_COUNTERS 4 #define NUM_CONTROLS 4 #define OP_EVENT_MASK 0x0FFF +#define OP_CTR_OVERFLOW (1ULL<<31) #define MSR_AMD_EVENTSEL_RESERVED ((0xFFFFFCF0ULL<<32)|(1ULL<<21)) -#define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) - static unsigned long reset_value[NUM_COUNTERS]; #ifdef CONFIG_OPROFILE_IBS @@ -241,17 +240,18 @@ static inline void op_amd_stop_ibs(void) { } static int op_amd_check_ctrs(struct pt_regs * const regs, struct op_msrs const * const msrs) { - unsigned int low, high; + u64 val; int i; for (i = 0 ; i < NUM_COUNTERS; ++i) { if (!reset_value[i]) continue; - rdmsr(msrs->counters[i].addr, low, high); - if (CTR_OVERFLOWED(low)) { - oprofile_add_sample(regs, i); - wrmsr(msrs->counters[i].addr, -(unsigned int)reset_value[i], -1); - } + rdmsrl(msrs->counters[i].addr, val); + /* bit is clear if overflowed: */ + if (val & OP_CTR_OVERFLOW) + continue; + oprofile_add_sample(regs, i); + wrmsr(msrs->counters[i].addr, -(unsigned int)reset_value[i], -1); } op_amd_handle_ibs(regs, msrs); diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 05ba0287b1f..ac4ca28b9ed 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -32,6 +32,8 @@ #define NUM_CCCRS_HT2 9 #define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2) +#define OP_CTR_OVERFLOW (1ULL<<31) + static unsigned int num_counters = NUM_COUNTERS_NON_HT; static unsigned int num_controls = NUM_CONTROLS_NON_HT; @@ -362,8 +364,6 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = { #define CCCR_OVF_P(cccr) ((cccr) & (1U<<31)) #define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31))) -#define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000)) - /* this assigns a "stagger" to the current CPU, which is used throughout the code in this module as an extra array offset, to select the "even" @@ -622,7 +622,7 @@ static int p4_check_ctrs(struct pt_regs * const regs, rdmsr(p4_counters[real].cccr_address, low, high); rdmsr(p4_counters[real].counter_address, ctr, high); - if (CCCR_OVF_P(low) || CTR_OVERFLOW_P(ctr)) { + if (CCCR_OVF_P(low) || !(ctr & OP_CTR_OVERFLOW)) { oprofile_add_sample(regs, i); wrmsr(p4_counters[real].counter_address, -(u32)reset_value[i], -1); diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 3092f998baf..82db396dc3e 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -26,8 +26,6 @@ static int num_counters = 2; static int counter_width = 32; -#define CTR_OVERFLOWED(n) (!((n) & (1ULL<<(counter_width-1)))) - #define MSR_PPRO_EVENTSEL_RESERVED ((0xFFFFFFFFULL<<32)|(1ULL<<21)) static u64 *reset_value; @@ -124,10 +122,10 @@ static int ppro_check_ctrs(struct pt_regs * const regs, if (!reset_value[i]) continue; rdmsrl(msrs->counters[i].addr, val); - if (CTR_OVERFLOWED(val)) { - oprofile_add_sample(regs, i); - wrmsrl(msrs->counters[i].addr, -reset_value[i]); - } + if (val & (1ULL << (counter_width - 1))) + continue; + oprofile_add_sample(regs, i); + wrmsrl(msrs->counters[i].addr, -reset_value[i]); } /* Only P6 based Pentium M need to re-unmask the apic vector but it -- cgit v1.2.3-18-g5258 From dea3766ca052a4f572b16a23a322553c064d75af Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 18:11:52 +0200 Subject: x86/oprofile: replace CTRL_SET_*ACTIVE macros The patch replaces all CTRL_SET_*ACTIVE macros. 64 bit MSR functions and 64 bit counter values are used now. The code uses bit masks from . Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 16 ++++++++-------- arch/x86/oprofile/op_model_ppro.c | 16 ++++++++-------- arch/x86/oprofile/op_x86_model.h | 2 -- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index b5d678fbf03..4ac9d283e8d 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -262,13 +262,13 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, static void op_amd_start(struct op_msrs const * const msrs) { - unsigned int low, high; + u64 val; int i; for (i = 0 ; i < NUM_COUNTERS ; ++i) { if (reset_value[i]) { - rdmsr(msrs->controls[i].addr, low, high); - CTRL_SET_ACTIVE(low); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val |= ARCH_PERFMON_EVENTSEL0_ENABLE; + wrmsrl(msrs->controls[i].addr, val); } } @@ -277,7 +277,7 @@ static void op_amd_start(struct op_msrs const * const msrs) static void op_amd_stop(struct op_msrs const * const msrs) { - unsigned int low, high; + u64 val; int i; /* @@ -287,9 +287,9 @@ static void op_amd_stop(struct op_msrs const * const msrs) for (i = 0 ; i < NUM_COUNTERS ; ++i) { if (!reset_value[i]) continue; - rdmsr(msrs->controls[i].addr, low, high); - CTRL_SET_INACTIVE(low); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; + wrmsrl(msrs->controls[i].addr, val); } op_amd_stop_ibs(); diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 82db396dc3e..566b43f0b6c 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -145,16 +145,16 @@ static int ppro_check_ctrs(struct pt_regs * const regs, static void ppro_start(struct op_msrs const * const msrs) { - unsigned int low, high; + u64 val; int i; if (!reset_value) return; for (i = 0; i < num_counters; ++i) { if (reset_value[i]) { - rdmsr(msrs->controls[i].addr, low, high); - CTRL_SET_ACTIVE(low); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val |= ARCH_PERFMON_EVENTSEL0_ENABLE; + wrmsrl(msrs->controls[i].addr, val); } } } @@ -162,7 +162,7 @@ static void ppro_start(struct op_msrs const * const msrs) static void ppro_stop(struct op_msrs const * const msrs) { - unsigned int low, high; + u64 val; int i; if (!reset_value) @@ -170,9 +170,9 @@ static void ppro_stop(struct op_msrs const * const msrs) for (i = 0; i < num_counters; ++i) { if (!reset_value[i]) continue; - rdmsr(msrs->controls[i].addr, low, high); - CTRL_SET_INACTIVE(low); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; + wrmsrl(msrs->controls[i].addr, val); } } diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 3220d4ce632..1c4577795a9 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -17,8 +17,6 @@ #define CTR_IS_RESERVED(msrs, c) ((msrs)->counters[(c)].addr ? 1 : 0) #define CTRL_IS_RESERVED(msrs, c) ((msrs)->controls[(c)].addr ? 1 : 0) -#define CTRL_SET_ACTIVE(val) ((val) |= ARCH_PERFMON_EVENTSEL0_ENABLE) -#define CTRL_SET_INACTIVE(val) ((val) &= ~ARCH_PERFMON_EVENTSEL0_ENABLE) struct op_saved_msr { unsigned int high; -- cgit v1.2.3-18-g5258 From 217d3cfb959756cb493fc03106c0253baa420ce8 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 4 Jun 2009 02:36:44 +0200 Subject: x86/oprofile: replace CTR*_IS_RESERVED macros The patch replaces all CTR*_IS_RESERVED macros. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 10 +++++----- arch/x86/oprofile/op_model_p4.c | 10 +++++----- arch/x86/oprofile/op_model_ppro.c | 10 +++++----- arch/x86/oprofile/op_x86_model.h | 3 --- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 4ac9d283e8d..c5c5eec2fa7 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -90,7 +90,7 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, /* clear all counters */ for (i = 0 ; i < NUM_CONTROLS; ++i) { - if (unlikely(!CTRL_IS_RESERVED(msrs, i))) + if (unlikely(!msrs->controls[i].addr)) continue; rdmsrl(msrs->controls[i].addr, val); val &= model->reserved; @@ -99,14 +99,14 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, /* avoid a false detection of ctr overflows in NMI handler */ for (i = 0; i < NUM_COUNTERS; ++i) { - if (unlikely(!CTR_IS_RESERVED(msrs, i))) + if (unlikely(!msrs->counters[i].addr)) continue; wrmsr(msrs->counters[i].addr, -1, -1); } /* enable active counters */ for (i = 0; i < NUM_COUNTERS; ++i) { - if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { + if (counter_config[i].enabled && msrs->counters[i].addr) { reset_value[i] = counter_config[i].count; wrmsr(msrs->counters[i].addr, -(unsigned int)counter_config[i].count, -1); rdmsrl(msrs->controls[i].addr, val); @@ -300,11 +300,11 @@ static void op_amd_shutdown(struct op_msrs const * const msrs) int i; for (i = 0 ; i < NUM_COUNTERS ; ++i) { - if (CTR_IS_RESERVED(msrs, i)) + if (msrs->counters[i].addr) release_perfctr_nmi(MSR_K7_PERFCTR0 + i); } for (i = 0 ; i < NUM_CONTROLS ; ++i) { - if (CTRL_IS_RESERVED(msrs, i)) + if (msrs->controls[i].addr) release_evntsel_nmi(MSR_K7_EVNTSEL0 + i); } } diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index ac4ca28b9ed..9db0ca9af76 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -559,7 +559,7 @@ static void p4_setup_ctrs(struct op_x86_model_spec const *model, /* clear the cccrs we will use */ for (i = 0 ; i < num_counters ; i++) { - if (unlikely(!CTRL_IS_RESERVED(msrs, i))) + if (unlikely(!msrs->controls[i].addr)) continue; rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high); CCCR_CLEAR(low); @@ -569,14 +569,14 @@ static void p4_setup_ctrs(struct op_x86_model_spec const *model, /* clear all escrs (including those outside our concern) */ for (i = num_counters; i < num_controls; i++) { - if (unlikely(!CTRL_IS_RESERVED(msrs, i))) + if (unlikely(!msrs->controls[i].addr)) continue; wrmsr(msrs->controls[i].addr, 0, 0); } /* setup all counters */ for (i = 0 ; i < num_counters ; ++i) { - if ((counter_config[i].enabled) && (CTRL_IS_RESERVED(msrs, i))) { + if (counter_config[i].enabled && msrs->controls[i].addr) { reset_value[i] = counter_config[i].count; pmc_setup_one_p4_counter(i); wrmsr(p4_counters[VIRT_CTR(stag, i)].counter_address, @@ -679,7 +679,7 @@ static void p4_shutdown(struct op_msrs const * const msrs) int i; for (i = 0 ; i < num_counters ; ++i) { - if (CTR_IS_RESERVED(msrs, i)) + if (msrs->counters[i].addr) release_perfctr_nmi(msrs->counters[i].addr); } /* @@ -688,7 +688,7 @@ static void p4_shutdown(struct op_msrs const * const msrs) * This saves a few bits. */ for (i = num_counters ; i < num_controls ; ++i) { - if (CTRL_IS_RESERVED(msrs, i)) + if (msrs->controls[i].addr) release_evntsel_nmi(msrs->controls[i].addr); } } diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 566b43f0b6c..0a261a5c696 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -82,7 +82,7 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model, /* clear all counters */ for (i = 0 ; i < num_counters; ++i) { - if (unlikely(!CTRL_IS_RESERVED(msrs, i))) + if (unlikely(!msrs->controls[i].addr)) continue; rdmsrl(msrs->controls[i].addr, val); val &= model->reserved; @@ -91,14 +91,14 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model, /* avoid a false detection of ctr overflows in NMI handler */ for (i = 0; i < num_counters; ++i) { - if (unlikely(!CTR_IS_RESERVED(msrs, i))) + if (unlikely(!msrs->counters[i].addr)) continue; wrmsrl(msrs->counters[i].addr, -1LL); } /* enable active counters */ for (i = 0; i < num_counters; ++i) { - if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { + if (counter_config[i].enabled && msrs->counters[i].addr) { reset_value[i] = counter_config[i].count; wrmsrl(msrs->counters[i].addr, -reset_value[i]); rdmsrl(msrs->controls[i].addr, val); @@ -181,11 +181,11 @@ static void ppro_shutdown(struct op_msrs const * const msrs) int i; for (i = 0 ; i < num_counters ; ++i) { - if (CTR_IS_RESERVED(msrs, i)) + if (msrs->counters[i].addr) release_perfctr_nmi(MSR_P6_PERFCTR0 + i); } for (i = 0 ; i < num_counters ; ++i) { - if (CTRL_IS_RESERVED(msrs, i)) + if (msrs->controls[i].addr) release_evntsel_nmi(MSR_P6_EVNTSEL0 + i); } if (reset_value) { diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 1c4577795a9..69f1eb46e1b 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -15,9 +15,6 @@ #include #include -#define CTR_IS_RESERVED(msrs, c) ((msrs)->counters[(c)].addr ? 1 : 0) -#define CTRL_IS_RESERVED(msrs, c) ((msrs)->controls[(c)].addr ? 1 : 0) - struct op_saved_msr { unsigned int high; unsigned int low; -- cgit v1.2.3-18-g5258 From bbc5986d2db427fdd61b6116ff8b9ed988e663a8 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 17:38:19 +0200 Subject: x86/oprofile: use 64 bit wrmsr functions This patch replaces some wrmsr() functions with wrmsrl(). Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 7 ++++--- arch/x86/oprofile/op_model_p4.c | 12 ++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index c5c5eec2fa7..9bf90176241 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -101,14 +101,15 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, for (i = 0; i < NUM_COUNTERS; ++i) { if (unlikely(!msrs->counters[i].addr)) continue; - wrmsr(msrs->counters[i].addr, -1, -1); + wrmsrl(msrs->counters[i].addr, -1LL); } /* enable active counters */ for (i = 0; i < NUM_COUNTERS; ++i) { if (counter_config[i].enabled && msrs->counters[i].addr) { reset_value[i] = counter_config[i].count; - wrmsr(msrs->counters[i].addr, -(unsigned int)counter_config[i].count, -1); + wrmsrl(msrs->counters[i].addr, + -(s64)counter_config[i].count); rdmsrl(msrs->controls[i].addr, val); val &= model->reserved; val |= op_x86_get_ctrl(model, &counter_config[i]); @@ -251,7 +252,7 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, if (val & OP_CTR_OVERFLOW) continue; oprofile_add_sample(regs, i); - wrmsr(msrs->counters[i].addr, -(unsigned int)reset_value[i], -1); + wrmsrl(msrs->counters[i].addr, -(s64)reset_value[i]); } op_amd_handle_ibs(regs, msrs); diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 9db0ca9af76..f01e53b118f 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -579,8 +579,8 @@ static void p4_setup_ctrs(struct op_x86_model_spec const *model, if (counter_config[i].enabled && msrs->controls[i].addr) { reset_value[i] = counter_config[i].count; pmc_setup_one_p4_counter(i); - wrmsr(p4_counters[VIRT_CTR(stag, i)].counter_address, - -(u32)counter_config[i].count, -1); + wrmsrl(p4_counters[VIRT_CTR(stag, i)].counter_address, + -(s64)counter_config[i].count); } else { reset_value[i] = 0; } @@ -624,12 +624,12 @@ static int p4_check_ctrs(struct pt_regs * const regs, rdmsr(p4_counters[real].counter_address, ctr, high); if (CCCR_OVF_P(low) || !(ctr & OP_CTR_OVERFLOW)) { oprofile_add_sample(regs, i); - wrmsr(p4_counters[real].counter_address, - -(u32)reset_value[i], -1); + wrmsrl(p4_counters[real].counter_address, + -(s64)reset_value[i]); CCCR_CLEAR_OVF(low); wrmsr(p4_counters[real].cccr_address, low, high); - wrmsr(p4_counters[real].counter_address, - -(u32)reset_value[i], -1); + wrmsrl(p4_counters[real].counter_address, + -(s64)reset_value[i]); } } -- cgit v1.2.3-18-g5258 From 95e74e62c1540b1115fe8cec5b592f22960f2bb2 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 3 Jun 2009 19:09:27 +0200 Subject: x86/oprofile: use 64 bit values to save MSR states This patch removes struct op_saved_msr and replaces it by an u64 variable. This makes code easier and it is possible to use 64 bit MSR functions. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 28 ++++++++-------------------- arch/x86/oprofile/op_x86_model.h | 9 ++------- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 388ee15e0e4..3b84b789de0 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -78,19 +78,13 @@ static void nmi_cpu_save_registers(struct op_msrs *msrs) unsigned int i; for (i = 0; i < nr_ctrs; ++i) { - if (counters[i].addr) { - rdmsr(counters[i].addr, - counters[i].saved.low, - counters[i].saved.high); - } + if (counters[i].addr) + rdmsrl(counters[i].addr, counters[i].saved); } for (i = 0; i < nr_ctrls; ++i) { - if (controls[i].addr) { - rdmsr(controls[i].addr, - controls[i].saved.low, - controls[i].saved.high); - } + if (controls[i].addr) + rdmsrl(controls[i].addr, controls[i].saved); } } @@ -204,19 +198,13 @@ static void nmi_restore_registers(struct op_msrs *msrs) unsigned int i; for (i = 0; i < nr_ctrls; ++i) { - if (controls[i].addr) { - wrmsr(controls[i].addr, - controls[i].saved.low, - controls[i].saved.high); - } + if (controls[i].addr) + wrmsrl(controls[i].addr, controls[i].saved); } for (i = 0; i < nr_ctrs; ++i) { - if (counters[i].addr) { - wrmsr(counters[i].addr, - counters[i].saved.low, - counters[i].saved.high); - } + if (counters[i].addr) + wrmsrl(counters[i].addr, counters[i].saved); } } diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 69f1eb46e1b..fda52b4c1b9 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -15,14 +15,9 @@ #include #include -struct op_saved_msr { - unsigned int high; - unsigned int low; -}; - struct op_msr { - unsigned long addr; - struct op_saved_msr saved; + unsigned long addr; + u64 saved; }; struct op_msrs { -- cgit v1.2.3-18-g5258 From 1a245c45343651a87ff63afc5ddeb8e24d731835 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 5 Jun 2009 15:54:24 +0200 Subject: x86/oprofile: remove some local variables in MSR save/restore functions The patch removes some local variables in these functions. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 3b84b789de0..80b63d5db50 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -71,18 +71,16 @@ static int profile_exceptions_notify(struct notifier_block *self, static void nmi_cpu_save_registers(struct op_msrs *msrs) { - unsigned int const nr_ctrs = model->num_counters; - unsigned int const nr_ctrls = model->num_controls; struct op_msr *counters = msrs->counters; struct op_msr *controls = msrs->controls; unsigned int i; - for (i = 0; i < nr_ctrs; ++i) { + for (i = 0; i < model->num_counters; ++i) { if (counters[i].addr) rdmsrl(counters[i].addr, counters[i].saved); } - for (i = 0; i < nr_ctrls; ++i) { + for (i = 0; i < model->num_controls; ++i) { if (controls[i].addr) rdmsrl(controls[i].addr, controls[i].saved); } @@ -191,18 +189,16 @@ static int nmi_setup(void) static void nmi_restore_registers(struct op_msrs *msrs) { - unsigned int const nr_ctrs = model->num_counters; - unsigned int const nr_ctrls = model->num_controls; struct op_msr *counters = msrs->counters; struct op_msr *controls = msrs->controls; unsigned int i; - for (i = 0; i < nr_ctrls; ++i) { + for (i = 0; i < model->num_controls; ++i) { if (controls[i].addr) wrmsrl(controls[i].addr, controls[i].saved); } - for (i = 0; i < nr_ctrs; ++i) { + for (i = 0; i < model->num_counters; ++i) { if (counters[i].addr) wrmsrl(counters[i].addr, counters[i].saved); } -- cgit v1.2.3-18-g5258 From c572ae4efd1b0a5cc76c5e6aae05c1b182b6a69c Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 3 Jun 2009 20:10:39 +0200 Subject: x86/oprofile: use 64 bit values in IBS functions The IBS code internally uses 32 bit values (a low and a high value) to represent a 64 bit value. This patch changes this and now 64 bit values are used instead. 64 bit MSR functions can be used now. No functional changes. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 131 ++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 70 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 9bf90176241..6493ef7ae9a 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -35,16 +35,18 @@ static unsigned long reset_value[NUM_COUNTERS]; #ifdef CONFIG_OPROFILE_IBS /* IbsFetchCtl bits/masks */ -#define IBS_FETCH_HIGH_VALID_BIT (1UL << 17) /* bit 49 */ -#define IBS_FETCH_HIGH_ENABLE (1UL << 16) /* bit 48 */ -#define IBS_FETCH_LOW_MAX_CNT_MASK 0x0000FFFFUL /* MaxCnt mask */ +#define IBS_FETCH_RAND_EN (1ULL<<57) +#define IBS_FETCH_VAL (1ULL<<49) +#define IBS_FETCH_ENABLE (1ULL<<48) +#define IBS_FETCH_CNT_MASK 0xFFFF0000ULL /*IbsOpCtl bits */ -#define IBS_OP_LOW_VALID_BIT (1ULL<<18) /* bit 18 */ -#define IBS_OP_LOW_ENABLE (1ULL<<17) /* bit 17 */ +#define IBS_OP_CNT_CTL (1ULL<<19) +#define IBS_OP_VAL (1ULL<<18) +#define IBS_OP_ENABLE (1ULL<<17) -#define IBS_FETCH_SIZE 6 -#define IBS_OP_SIZE 12 +#define IBS_FETCH_SIZE 6 +#define IBS_OP_SIZE 12 static int has_ibs; /* AMD Family10h and later */ @@ -126,66 +128,63 @@ static inline int op_amd_handle_ibs(struct pt_regs * const regs, struct op_msrs const * const msrs) { - u32 low, high; - u64 msr; + u64 val, ctl; struct op_entry entry; if (!has_ibs) return 1; if (ibs_config.fetch_enabled) { - rdmsr(MSR_AMD64_IBSFETCHCTL, low, high); - if (high & IBS_FETCH_HIGH_VALID_BIT) { - rdmsrl(MSR_AMD64_IBSFETCHLINAD, msr); - oprofile_write_reserve(&entry, regs, msr, + rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl); + if (ctl & IBS_FETCH_VAL) { + rdmsrl(MSR_AMD64_IBSFETCHLINAD, val); + oprofile_write_reserve(&entry, regs, val, IBS_FETCH_CODE, IBS_FETCH_SIZE); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); - oprofile_add_data(&entry, low); - oprofile_add_data(&entry, high); - rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, msr); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data(&entry, (u32)ctl); + oprofile_add_data(&entry, (u32)(ctl >> 32)); + rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, val); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); oprofile_write_commit(&entry); /* reenable the IRQ */ - high &= ~IBS_FETCH_HIGH_VALID_BIT; - high |= IBS_FETCH_HIGH_ENABLE; - low &= IBS_FETCH_LOW_MAX_CNT_MASK; - wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); + ctl &= ~(IBS_FETCH_VAL | IBS_FETCH_CNT_MASK); + ctl |= IBS_FETCH_ENABLE; + wrmsrl(MSR_AMD64_IBSFETCHCTL, ctl); } } if (ibs_config.op_enabled) { - rdmsr(MSR_AMD64_IBSOPCTL, low, high); - if (low & IBS_OP_LOW_VALID_BIT) { - rdmsrl(MSR_AMD64_IBSOPRIP, msr); - oprofile_write_reserve(&entry, regs, msr, + rdmsrl(MSR_AMD64_IBSOPCTL, ctl); + if (ctl & IBS_OP_VAL) { + rdmsrl(MSR_AMD64_IBSOPRIP, val); + oprofile_write_reserve(&entry, regs, val, IBS_OP_CODE, IBS_OP_SIZE); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); - rdmsrl(MSR_AMD64_IBSOPDATA, msr); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); - rdmsrl(MSR_AMD64_IBSOPDATA2, msr); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); - rdmsrl(MSR_AMD64_IBSOPDATA3, msr); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); - rdmsrl(MSR_AMD64_IBSDCLINAD, msr); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); - rdmsrl(MSR_AMD64_IBSDCPHYSAD, msr); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); + rdmsrl(MSR_AMD64_IBSOPDATA, val); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); + rdmsrl(MSR_AMD64_IBSOPDATA2, val); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); + rdmsrl(MSR_AMD64_IBSOPDATA3, val); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); + rdmsrl(MSR_AMD64_IBSDCLINAD, val); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); + rdmsrl(MSR_AMD64_IBSDCPHYSAD, val); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); oprofile_write_commit(&entry); /* reenable the IRQ */ - high = 0; - low &= ~IBS_OP_LOW_VALID_BIT; - low |= IBS_OP_LOW_ENABLE; - wrmsr(MSR_AMD64_IBSOPCTL, low, high); + ctl &= ~IBS_OP_VAL & 0xFFFFFFFF; + ctl |= IBS_OP_ENABLE; + wrmsrl(MSR_AMD64_IBSOPCTL, ctl); } } @@ -194,39 +193,31 @@ op_amd_handle_ibs(struct pt_regs * const regs, static inline void op_amd_start_ibs(void) { - unsigned int low, high; + u64 val; if (has_ibs && ibs_config.fetch_enabled) { - low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; - high = ((ibs_config.rand_en & 0x1) << 25) /* bit 57 */ - + IBS_FETCH_HIGH_ENABLE; - wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); + val = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; + val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0; + val |= IBS_FETCH_ENABLE; + wrmsrl(MSR_AMD64_IBSFETCHCTL, val); } if (has_ibs && ibs_config.op_enabled) { - low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) - + ((ibs_config.dispatched_ops & 0x1) << 19) /* bit 19 */ - + IBS_OP_LOW_ENABLE; - high = 0; - wrmsr(MSR_AMD64_IBSOPCTL, low, high); + val = (ibs_config.max_cnt_op >> 4) & 0xFFFF; + val |= ibs_config.dispatched_ops ? IBS_OP_CNT_CTL : 0; + val |= IBS_OP_ENABLE; + wrmsrl(MSR_AMD64_IBSOPCTL, val); } } static void op_amd_stop_ibs(void) { - unsigned int low, high; - if (has_ibs && ibs_config.fetch_enabled) { + if (has_ibs && ibs_config.fetch_enabled) /* clear max count and enable */ - low = 0; - high = 0; - wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); - } + wrmsrl(MSR_AMD64_IBSFETCHCTL, 0); - if (has_ibs && ibs_config.op_enabled) { + if (has_ibs && ibs_config.op_enabled) /* clear max count and enable */ - low = 0; - high = 0; - wrmsr(MSR_AMD64_IBSOPCTL, low, high); - } + wrmsrl(MSR_AMD64_IBSOPCTL, 0); } #else -- cgit v1.2.3-18-g5258 From 51563a0e5650d0d76539625388d72d62b34c726e Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 3 Jun 2009 20:54:56 +0200 Subject: x86/oprofile: introduce oprofile_add_data64() The IBS implemention writes 64 bit register values to the cpu buffer by writing two 32 values using oprofile_add_data(). This patch introduces oprofile_add_data64() to write a single 64 bit value to the buffer. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 27 +++++++++------------------ drivers/oprofile/cpu_buffer.c | 15 +++++++++++++++ include/linux/oprofile.h | 1 + 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 6493ef7ae9a..cc930467575 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -140,13 +140,10 @@ op_amd_handle_ibs(struct pt_regs * const regs, rdmsrl(MSR_AMD64_IBSFETCHLINAD, val); oprofile_write_reserve(&entry, regs, val, IBS_FETCH_CODE, IBS_FETCH_SIZE); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); - oprofile_add_data(&entry, (u32)ctl); - oprofile_add_data(&entry, (u32)(ctl >> 32)); + oprofile_add_data64(&entry, val); + oprofile_add_data64(&entry, ctl); rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, val); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data64(&entry, val); oprofile_write_commit(&entry); /* reenable the IRQ */ @@ -162,23 +159,17 @@ op_amd_handle_ibs(struct pt_regs * const regs, rdmsrl(MSR_AMD64_IBSOPRIP, val); oprofile_write_reserve(&entry, regs, val, IBS_OP_CODE, IBS_OP_SIZE); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data64(&entry, val); rdmsrl(MSR_AMD64_IBSOPDATA, val); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data64(&entry, val); rdmsrl(MSR_AMD64_IBSOPDATA2, val); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data64(&entry, val); rdmsrl(MSR_AMD64_IBSOPDATA3, val); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data64(&entry, val); rdmsrl(MSR_AMD64_IBSDCLINAD, val); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data64(&entry, val); rdmsrl(MSR_AMD64_IBSDCPHYSAD, val); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data64(&entry, val); oprofile_write_commit(&entry); /* reenable the IRQ */ diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 50640cc5eef..a7aae24f288 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -406,6 +406,21 @@ int oprofile_add_data(struct op_entry *entry, unsigned long val) return op_cpu_buffer_add_data(entry, val); } +int oprofile_add_data64(struct op_entry *entry, u64 val) +{ + if (!entry->event) + return 0; + if (op_cpu_buffer_get_size(entry) < 2) + /* + * the function returns 0 to indicate a too small + * buffer, even if there is some space left + */ + return 0; + if (!op_cpu_buffer_add_data(entry, (u32)val)) + return 0; + return op_cpu_buffer_add_data(entry, (u32)(val >> 32)); +} + int oprofile_write_commit(struct op_entry *entry) { if (!entry->event) diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index dbbe2dbc441..d68d2ed94f1 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -179,6 +179,7 @@ void oprofile_write_reserve(struct op_entry *entry, struct pt_regs * const regs, unsigned long pc, int code, int size); int oprofile_add_data(struct op_entry *entry, unsigned long val); +int oprofile_add_data64(struct op_entry *entry, u64 val); int oprofile_write_commit(struct op_entry *entry); #endif /* OPROFILE_H */ -- cgit v1.2.3-18-g5258 From 1cc4ce6f5f89cdc355013aa43f06a14a015766d1 Mon Sep 17 00:00:00 2001 From: Maynard Johnson Date: Wed, 27 May 2009 10:15:08 -0500 Subject: oprofile: reset bt_lost_no_mapping with other stats The bt_lost_no_mapping is not getting reset at the start of a profiling run, thus the oprofiled.log shows erroneous values for this statistic. The attached patch fixes this problem. Signed-off-by: Maynard Johnson Signed-off-by: Robert Richter --- drivers/oprofile/oprofile_stats.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index e1f6ce03705..efefae539a5 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -33,6 +33,7 @@ void oprofile_reset_stats(void) atomic_set(&oprofile_stats.sample_lost_no_mm, 0); atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); atomic_set(&oprofile_stats.event_lost_overflow, 0); + atomic_set(&oprofile_stats.bt_lost_no_mapping,0); } -- cgit v1.2.3-18-g5258 From 802070f5474af1a49435a9528aede47bb18abd47 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 12 Jun 2009 18:32:07 +0200 Subject: x86/oprofile: fix initialization of arch_perfmon for core_i7 Commit: e419294 x86/oprofile: moving arch_perfmon counter setup to op_x86_model_spec.init introduced a bug in the initialization of core_i7 leading to the incorrect model setup to &op_ppro_spec. This patch fixes this. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 7826dfcc842..28ee490c1b8 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -406,6 +406,7 @@ module_param_call(cpu_type, force_cpu_type, NULL, NULL, 0); static int __init ppro_init(char **cpu_type) { __u8 cpu_model = boot_cpu_data.x86_model; + struct op_x86_model_spec const *spec = &op_ppro_spec; /* default */ if (force_arch_perfmon && cpu_has_arch_perfmon) return 0; @@ -432,7 +433,7 @@ static int __init ppro_init(char **cpu_type) *cpu_type = "i386/core_2"; break; case 26: - model = &op_arch_perfmon_spec; + spec = &op_arch_perfmon_spec; *cpu_type = "i386/core_i7"; break; case 28: @@ -443,7 +444,7 @@ static int __init ppro_init(char **cpu_type) return 0; } - model = &op_ppro_spec; + model = spec; return 1; } -- cgit v1.2.3-18-g5258 From 21e70878215f620fe99ea7d7c74bc641aeec932f Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Thu, 18 Jun 2009 17:09:27 +0530 Subject: x86: oprofile/op_model_amd.c set return values for op_amd_handle_ibs() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit op_amd_handle_ibs() should return 0 when IBS is not present or not defined. Fix compilation warning: CC [M] arch/x86/oprofile/op_model_amd.o arch/x86/oprofile/op_model_amd.c: In function ‘op_amd_handle_ibs’: arch/x86/oprofile/op_model_amd.c:217: warning: no return statement in function returning non-void Signed-off-by: Jaswinder Singh Rajput Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index cc930467575..e95268eb922 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -132,7 +132,7 @@ op_amd_handle_ibs(struct pt_regs * const regs, struct op_entry entry; if (!has_ibs) - return 1; + return 0; if (ibs_config.fetch_enabled) { rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl); @@ -214,7 +214,10 @@ static void op_amd_stop_ibs(void) #else static inline int op_amd_handle_ibs(struct pt_regs * const regs, - struct op_msrs const * const msrs) { } + struct op_msrs const * const msrs) +{ + return 0; +} static inline void op_amd_start_ibs(void) { } static inline void op_amd_stop_ibs(void) { } -- cgit v1.2.3-18-g5258 From 8045a4c293d36c61656a20d581b11f7f0cd7acd5 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 7 Jul 2009 19:30:25 +0200 Subject: x86/oprofile: Fix cast of counter value When casting the counter value to a 64 bit value in 32 bit mode, sign extension may lead to broken counter values. This patch fixes this by casting to (u64) instead of (s64). Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 4 ++-- arch/x86/oprofile/op_model_p4.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index e95268eb922..7ca8306aefa 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -111,7 +111,7 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, if (counter_config[i].enabled && msrs->counters[i].addr) { reset_value[i] = counter_config[i].count; wrmsrl(msrs->counters[i].addr, - -(s64)counter_config[i].count); + -(u64)counter_config[i].count); rdmsrl(msrs->controls[i].addr, val); val &= model->reserved; val |= op_x86_get_ctrl(model, &counter_config[i]); @@ -237,7 +237,7 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, if (val & OP_CTR_OVERFLOW) continue; oprofile_add_sample(regs, i); - wrmsrl(msrs->counters[i].addr, -(s64)reset_value[i]); + wrmsrl(msrs->counters[i].addr, -(u64)reset_value[i]); } op_amd_handle_ibs(regs, msrs); diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index f01e53b118f..9db9e361182 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -580,7 +580,7 @@ static void p4_setup_ctrs(struct op_x86_model_spec const *model, reset_value[i] = counter_config[i].count; pmc_setup_one_p4_counter(i); wrmsrl(p4_counters[VIRT_CTR(stag, i)].counter_address, - -(s64)counter_config[i].count); + -(u64)counter_config[i].count); } else { reset_value[i] = 0; } @@ -625,11 +625,11 @@ static int p4_check_ctrs(struct pt_regs * const regs, if (CCCR_OVF_P(low) || !(ctr & OP_CTR_OVERFLOW)) { oprofile_add_sample(regs, i); wrmsrl(p4_counters[real].counter_address, - -(s64)reset_value[i]); + -(u64)reset_value[i]); CCCR_CLEAR_OVF(low); wrmsr(p4_counters[real].cccr_address, low, high); wrmsrl(p4_counters[real].counter_address, - -(s64)reset_value[i]); + -(u64)reset_value[i]); } } -- cgit v1.2.3-18-g5258 From 44ab9a6b0e909145d42615493952fe986b1ce5c2 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 18:33:02 +0200 Subject: x86/oprofile: Rework and simplify nmi_cpu_setup() This patch removes the function nmi_save_registers(). Per-cpu code is now executed only in the function nmi_cpu_setup(). Also, it renames the per-cpu function nmi_restore_registers() to nmi_cpu_restore_registers(). Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 93df76dd60f..25da1e17815 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -87,13 +87,6 @@ static void nmi_cpu_save_registers(struct op_msrs *msrs) } } -static void nmi_save_registers(void *dummy) -{ - int cpu = smp_processor_id(); - struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); - nmi_cpu_save_registers(msrs); -} - static void free_msrs(void) { int i; @@ -137,6 +130,7 @@ static void nmi_cpu_setup(void *dummy) { int cpu = smp_processor_id(); struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); + nmi_cpu_save_registers(msrs); spin_lock(&oprofilefs_lock); model->setup_ctrs(model, msrs); spin_unlock(&oprofilefs_lock); @@ -182,13 +176,12 @@ static int nmi_setup(void) } } - on_each_cpu(nmi_save_registers, NULL, 1); on_each_cpu(nmi_cpu_setup, NULL, 1); nmi_enabled = 1; return 0; } -static void nmi_restore_registers(struct op_msrs *msrs) +static void nmi_cpu_restore_registers(struct op_msrs *msrs) { struct op_msr *counters = msrs->counters; struct op_msr *controls = msrs->controls; @@ -220,7 +213,7 @@ static void nmi_cpu_shutdown(void *dummy) apic_write(APIC_LVTERR, v | APIC_LVT_MASKED); apic_write(APIC_LVTPC, per_cpu(saved_lvtpc, cpu)); apic_write(APIC_LVTERR, v); - nmi_restore_registers(msrs); + nmi_cpu_restore_registers(msrs); } static void nmi_shutdown(void) -- cgit v1.2.3-18-g5258 From 6e63ea4b0b14ff5fb8a3ca704fcda7d28b95f079 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 7 Jul 2009 19:25:39 +0200 Subject: x86/oprofile: Whitespaces changes only This patch fixes whitespace changes of code that will be touched in follow-on patches. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 12 ++++++------ arch/x86/oprofile/op_model_amd.c | 12 ++++++------ arch/x86/oprofile/op_model_p4.c | 8 ++++---- arch/x86/oprofile/op_model_ppro.c | 8 ++++---- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 25da1e17815..fca8dc94531 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -516,12 +516,12 @@ int __init op_nmi_init(struct oprofile_operations *ops) register_cpu_notifier(&oprofile_cpu_nb); #endif /* default values, can be overwritten by model */ - ops->create_files = nmi_create_files; - ops->setup = nmi_setup; - ops->shutdown = nmi_shutdown; - ops->start = nmi_start; - ops->stop = nmi_stop; - ops->cpu_type = cpu_type; + ops->create_files = nmi_create_files; + ops->setup = nmi_setup; + ops->shutdown = nmi_shutdown; + ops->start = nmi_start; + ops->stop = nmi_stop; + ops->cpu_type = cpu_type; if (model->init) ret = model->init(ops); diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 7ca8306aefa..f676f8825a3 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -91,7 +91,7 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, int i; /* clear all counters */ - for (i = 0 ; i < NUM_CONTROLS; ++i) { + for (i = 0; i < NUM_CONTROLS; ++i) { if (unlikely(!msrs->controls[i].addr)) continue; rdmsrl(msrs->controls[i].addr, val); @@ -229,7 +229,7 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, u64 val; int i; - for (i = 0 ; i < NUM_COUNTERS; ++i) { + for (i = 0; i < NUM_COUNTERS; ++i) { if (!reset_value[i]) continue; rdmsrl(msrs->counters[i].addr, val); @@ -250,7 +250,7 @@ static void op_amd_start(struct op_msrs const * const msrs) { u64 val; int i; - for (i = 0 ; i < NUM_COUNTERS ; ++i) { + for (i = 0; i < NUM_COUNTERS; ++i) { if (reset_value[i]) { rdmsrl(msrs->controls[i].addr, val); val |= ARCH_PERFMON_EVENTSEL0_ENABLE; @@ -270,7 +270,7 @@ static void op_amd_stop(struct op_msrs const * const msrs) * Subtle: stop on all counters to avoid race with setting our * pm callback */ - for (i = 0 ; i < NUM_COUNTERS ; ++i) { + for (i = 0; i < NUM_COUNTERS; ++i) { if (!reset_value[i]) continue; rdmsrl(msrs->controls[i].addr, val); @@ -285,11 +285,11 @@ static void op_amd_shutdown(struct op_msrs const * const msrs) { int i; - for (i = 0 ; i < NUM_COUNTERS ; ++i) { + for (i = 0; i < NUM_COUNTERS; ++i) { if (msrs->counters[i].addr) release_perfctr_nmi(MSR_K7_PERFCTR0 + i); } - for (i = 0 ; i < NUM_CONTROLS ; ++i) { + for (i = 0; i < NUM_CONTROLS; ++i) { if (msrs->controls[i].addr) release_evntsel_nmi(MSR_K7_EVNTSEL0 + i); } diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 9db9e361182..5921b7fc724 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -558,7 +558,7 @@ static void p4_setup_ctrs(struct op_x86_model_spec const *model, } /* clear the cccrs we will use */ - for (i = 0 ; i < num_counters ; i++) { + for (i = 0; i < num_counters; i++) { if (unlikely(!msrs->controls[i].addr)) continue; rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high); @@ -575,7 +575,7 @@ static void p4_setup_ctrs(struct op_x86_model_spec const *model, } /* setup all counters */ - for (i = 0 ; i < num_counters ; ++i) { + for (i = 0; i < num_counters; ++i) { if (counter_config[i].enabled && msrs->controls[i].addr) { reset_value[i] = counter_config[i].count; pmc_setup_one_p4_counter(i); @@ -678,7 +678,7 @@ static void p4_shutdown(struct op_msrs const * const msrs) { int i; - for (i = 0 ; i < num_counters ; ++i) { + for (i = 0; i < num_counters; ++i) { if (msrs->counters[i].addr) release_perfctr_nmi(msrs->counters[i].addr); } @@ -687,7 +687,7 @@ static void p4_shutdown(struct op_msrs const * const msrs) * conjunction with the counter registers (hence the starting offset). * This saves a few bits. */ - for (i = num_counters ; i < num_controls ; ++i) { + for (i = num_counters; i < num_controls; ++i) { if (msrs->controls[i].addr) release_evntsel_nmi(msrs->controls[i].addr); } diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index cd72d5c73b4..570d717c330 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -81,7 +81,7 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model, } /* clear all counters */ - for (i = 0 ; i < num_counters; ++i) { + for (i = 0; i < num_counters; ++i) { if (unlikely(!msrs->controls[i].addr)) continue; rdmsrl(msrs->controls[i].addr, val); @@ -125,7 +125,7 @@ static int ppro_check_ctrs(struct pt_regs * const regs, if (unlikely(!reset_value)) goto out; - for (i = 0 ; i < num_counters; ++i) { + for (i = 0; i < num_counters; ++i) { if (!reset_value[i]) continue; rdmsrl(msrs->counters[i].addr, val); @@ -188,11 +188,11 @@ static void ppro_shutdown(struct op_msrs const * const msrs) { int i; - for (i = 0 ; i < num_counters ; ++i) { + for (i = 0; i < num_counters; ++i) { if (msrs->counters[i].addr) release_perfctr_nmi(MSR_P6_PERFCTR0 + i); } - for (i = 0 ; i < num_counters ; ++i) { + for (i = 0; i < num_counters; ++i) { if (msrs->controls[i].addr) release_evntsel_nmi(MSR_P6_EVNTSEL0 + i); } -- cgit v1.2.3-18-g5258 From 4d4036e0e7299c6cbb2d2421b4b30b7a409ce61a Mon Sep 17 00:00:00 2001 From: Jason Yeh Date: Wed, 8 Jul 2009 13:49:38 +0200 Subject: oprofile: Implement performance counter multiplexing The number of hardware counters is limited. The multiplexing feature enables OProfile to gather more events than counters are provided by the hardware. This is realized by switching between events at an user specified time interval. A new file (/dev/oprofile/time_slice) is added for the user to specify the timer interval in ms. If the number of events to profile is higher than the number of hardware counters available, the patch will schedule a work queue that switches the event counter and re-writes the different sets of values into it. The switching mechanism needs to be implemented for each architecture to support multiplexing. This patch only implements AMD CPU support, but multiplexing can be easily extended for other models and architectures. There are follow-on patches that rework parts of this patch. Signed-off-by: Jason Yeh Signed-off-by: Robert Richter --- arch/Kconfig | 12 +++ arch/x86/oprofile/nmi_int.c | 162 ++++++++++++++++++++++++++++++++++++-- arch/x86/oprofile/op_counter.h | 2 +- arch/x86/oprofile/op_model_amd.c | 110 ++++++++++++++++++++++---- arch/x86/oprofile/op_model_p4.c | 4 + arch/x86/oprofile/op_model_ppro.c | 2 + arch/x86/oprofile/op_x86_model.h | 7 ++ drivers/oprofile/oprof.c | 78 ++++++++++++++++++ drivers/oprofile/oprof.h | 2 + drivers/oprofile/oprofile_files.c | 43 ++++++++++ drivers/oprofile/oprofile_stats.c | 10 +++ include/linux/oprofile.h | 3 + 12 files changed, 415 insertions(+), 20 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index 99193b16023..beea3ccebb5 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -30,6 +30,18 @@ config OPROFILE_IBS If unsure, say N. +config OPROFILE_EVENT_MULTIPLEX + bool "OProfile multiplexing support (EXPERIMENTAL)" + default n + depends on OPROFILE && X86 + help + The number of hardware counters is limited. The multiplexing + feature enables OProfile to gather more events than counters + are provided by the hardware. This is realized by switching + between events at an user specified time interval. + + If unsure, say N. + config HAVE_OPROFILE bool diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index fca8dc94531..e54f6a0b35a 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -1,11 +1,14 @@ /** * @file nmi_int.c * - * @remark Copyright 2002-2008 OProfile authors + * @remark Copyright 2002-2009 OProfile authors * @remark Read the file COPYING * * @author John Levon * @author Robert Richter + * @author Barry Kasindorf + * @author Jason Yeh + * @author Suravee Suthikulpanit */ #include @@ -24,6 +27,12 @@ #include "op_counter.h" #include "op_x86_model.h" + +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX +DEFINE_PER_CPU(int, switch_index); +#endif + + static struct op_x86_model_spec const *model; static DEFINE_PER_CPU(struct op_msrs, cpu_msrs); static DEFINE_PER_CPU(unsigned long, saved_lvtpc); @@ -31,6 +40,13 @@ static DEFINE_PER_CPU(unsigned long, saved_lvtpc); /* 0 == registered but off, 1 == registered and on */ static int nmi_enabled = 0; + +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX +extern atomic_t multiplex_counter; +#endif + +struct op_counter_config counter_config[OP_MAX_COUNTER]; + /* common functions */ u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, @@ -95,6 +111,11 @@ static void free_msrs(void) per_cpu(cpu_msrs, i).counters = NULL; kfree(per_cpu(cpu_msrs, i).controls); per_cpu(cpu_msrs, i).controls = NULL; + +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + kfree(per_cpu(cpu_msrs, i).multiplex); + per_cpu(cpu_msrs, i).multiplex = NULL; +#endif } } @@ -103,6 +124,9 @@ static int allocate_msrs(void) int success = 1; size_t controls_size = sizeof(struct op_msr) * model->num_controls; size_t counters_size = sizeof(struct op_msr) * model->num_counters; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + size_t multiplex_size = sizeof(struct op_msr) * model->num_virt_counters; +#endif int i; for_each_possible_cpu(i) { @@ -118,6 +142,14 @@ static int allocate_msrs(void) success = 0; break; } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + per_cpu(cpu_msrs, i).multiplex = + kmalloc(multiplex_size, GFP_KERNEL); + if (!per_cpu(cpu_msrs, i).multiplex) { + success = 0; + break; + } +#endif } if (!success) @@ -126,6 +158,25 @@ static int allocate_msrs(void) return success; } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void nmi_setup_cpu_mux(struct op_msrs const * const msrs) +{ + int i; + struct op_msr *multiplex = msrs->multiplex; + + for (i = 0; i < model->num_virt_counters; ++i) { + if (counter_config[i].enabled) { + multiplex[i].saved = -(u64)counter_config[i].count; + } else { + multiplex[i].addr = 0; + multiplex[i].saved = 0; + } + } +} + +#endif + static void nmi_cpu_setup(void *dummy) { int cpu = smp_processor_id(); @@ -133,6 +184,9 @@ static void nmi_cpu_setup(void *dummy) nmi_cpu_save_registers(msrs); spin_lock(&oprofilefs_lock); model->setup_ctrs(model, msrs); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + nmi_setup_cpu_mux(msrs); +#endif spin_unlock(&oprofilefs_lock); per_cpu(saved_lvtpc, cpu) = apic_read(APIC_LVTPC); apic_write(APIC_LVTPC, APIC_DM_NMI); @@ -173,14 +227,52 @@ static int nmi_setup(void) memcpy(per_cpu(cpu_msrs, cpu).controls, per_cpu(cpu_msrs, 0).controls, sizeof(struct op_msr) * model->num_controls); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + memcpy(per_cpu(cpu_msrs, cpu).multiplex, + per_cpu(cpu_msrs, 0).multiplex, + sizeof(struct op_msr) * model->num_virt_counters); +#endif } - } on_each_cpu(nmi_cpu_setup, NULL, 1); nmi_enabled = 1; return 0; } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void nmi_cpu_save_mpx_registers(struct op_msrs *msrs) +{ + unsigned int si = __get_cpu_var(switch_index); + struct op_msr *multiplex = msrs->multiplex; + unsigned int i; + + for (i = 0; i < model->num_counters; ++i) { + int offset = i + si; + if (multiplex[offset].addr) { + rdmsrl(multiplex[offset].addr, + multiplex[offset].saved); + } + } +} + +static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs) +{ + unsigned int si = __get_cpu_var(switch_index); + struct op_msr *multiplex = msrs->multiplex; + unsigned int i; + + for (i = 0; i < model->num_counters; ++i) { + int offset = i + si; + if (multiplex[offset].addr) { + wrmsrl(multiplex[offset].addr, + multiplex[offset].saved); + } + } +} + +#endif + static void nmi_cpu_restore_registers(struct op_msrs *msrs) { struct op_msr *counters = msrs->counters; @@ -214,6 +306,9 @@ static void nmi_cpu_shutdown(void *dummy) apic_write(APIC_LVTPC, per_cpu(saved_lvtpc, cpu)); apic_write(APIC_LVTERR, v); nmi_cpu_restore_registers(msrs); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + __get_cpu_var(switch_index) = 0; +#endif } static void nmi_shutdown(void) @@ -252,16 +347,15 @@ static void nmi_stop(void) on_each_cpu(nmi_cpu_stop, NULL, 1); } -struct op_counter_config counter_config[OP_MAX_COUNTER]; - static int nmi_create_files(struct super_block *sb, struct dentry *root) { unsigned int i; - for (i = 0; i < model->num_counters; ++i) { + for (i = 0; i < model->num_virt_counters; ++i) { struct dentry *dir; char buf[4]; +#ifndef CONFIG_OPROFILE_EVENT_MULTIPLEX /* quick little hack to _not_ expose a counter if it is not * available for use. This should protect userspace app. * NOTE: assumes 1:1 mapping here (that counters are organized @@ -269,6 +363,7 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root) */ if (unlikely(!avail_to_resrv_perfctr_nmi_bit(i))) continue; +#endif /* CONFIG_OPROFILE_EVENT_MULTIPLEX */ snprintf(buf, sizeof(buf), "%d", i); dir = oprofilefs_mkdir(sb, root, buf); @@ -283,6 +378,57 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root) return 0; } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void nmi_cpu_switch(void *dummy) +{ + int cpu = smp_processor_id(); + int si = per_cpu(switch_index, cpu); + struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); + + nmi_cpu_stop(NULL); + nmi_cpu_save_mpx_registers(msrs); + + /* move to next set */ + si += model->num_counters; + if ((si > model->num_virt_counters) || (counter_config[si].count == 0)) + per_cpu(switch_index, cpu) = 0; + else + per_cpu(switch_index, cpu) = si; + + model->switch_ctrl(model, msrs); + nmi_cpu_restore_mpx_registers(msrs); + + nmi_cpu_start(NULL); +} + + +/* + * Quick check to see if multiplexing is necessary. + * The check should be sufficient since counters are used + * in ordre. + */ +static int nmi_multiplex_on(void) +{ + return counter_config[model->num_counters].count ? 0 : -EINVAL; +} + +static int nmi_switch_event(void) +{ + if (!model->switch_ctrl) + return -ENOSYS; /* not implemented */ + if (nmi_multiplex_on() < 0) + return -EINVAL; /* not necessary */ + + on_each_cpu(nmi_cpu_switch, NULL, 1); + + atomic_inc(&multiplex_counter); + + return 0; +} + +#endif + #ifdef CONFIG_SMP static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, void *data) @@ -516,12 +662,18 @@ int __init op_nmi_init(struct oprofile_operations *ops) register_cpu_notifier(&oprofile_cpu_nb); #endif /* default values, can be overwritten by model */ +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + __raw_get_cpu_var(switch_index) = 0; +#endif ops->create_files = nmi_create_files; ops->setup = nmi_setup; ops->shutdown = nmi_shutdown; ops->start = nmi_start; ops->stop = nmi_stop; ops->cpu_type = cpu_type; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + ops->switch_events = nmi_switch_event; +#endif if (model->init) ret = model->init(ops); diff --git a/arch/x86/oprofile/op_counter.h b/arch/x86/oprofile/op_counter.h index 91b6a116165..e28398df0df 100644 --- a/arch/x86/oprofile/op_counter.h +++ b/arch/x86/oprofile/op_counter.h @@ -10,7 +10,7 @@ #ifndef OP_COUNTER_H #define OP_COUNTER_H -#define OP_MAX_COUNTER 8 +#define OP_MAX_COUNTER 32 /* Per-perfctr configuration as set via * oprofilefs. diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index f676f8825a3..fdbed3a0c87 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -9,12 +9,15 @@ * @author Philippe Elie * @author Graydon Hoare * @author Robert Richter - * @author Barry Kasindorf + * @author Barry Kasindorf + * @author Jason Yeh + * @author Suravee Suthikulpanit */ #include #include #include +#include #include #include @@ -25,12 +28,23 @@ #define NUM_COUNTERS 4 #define NUM_CONTROLS 4 +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX +#define NUM_VIRT_COUNTERS 32 +#define NUM_VIRT_CONTROLS 32 +#else +#define NUM_VIRT_COUNTERS NUM_COUNTERS +#define NUM_VIRT_CONTROLS NUM_CONTROLS +#endif + #define OP_EVENT_MASK 0x0FFF #define OP_CTR_OVERFLOW (1ULL<<31) #define MSR_AMD_EVENTSEL_RESERVED ((0xFFFFFCF0ULL<<32)|(1ULL<<21)) -static unsigned long reset_value[NUM_COUNTERS]; +static unsigned long reset_value[NUM_VIRT_COUNTERS]; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX +DECLARE_PER_CPU(int, switch_index); +#endif #ifdef CONFIG_OPROFILE_IBS @@ -82,6 +96,16 @@ static void op_amd_fill_in_addresses(struct op_msrs * const msrs) else msrs->controls[i].addr = 0; } + +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + for (i = 0; i < NUM_VIRT_COUNTERS; i++) { + int hw_counter = i % NUM_CONTROLS; + if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i)) + msrs->multiplex[i].addr = MSR_K7_PERFCTR0 + hw_counter; + else + msrs->multiplex[i].addr = 0; + } +#endif } static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, @@ -90,6 +114,15 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, u64 val; int i; + /* setup reset_value */ + for (i = 0; i < NUM_VIRT_COUNTERS; ++i) { + if (counter_config[i].enabled) { + reset_value[i] = counter_config[i].count; + } else { + reset_value[i] = 0; + } + } + /* clear all counters */ for (i = 0; i < NUM_CONTROLS; ++i) { if (unlikely(!msrs->controls[i].addr)) @@ -108,20 +141,49 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, /* enable active counters */ for (i = 0; i < NUM_COUNTERS; ++i) { - if (counter_config[i].enabled && msrs->counters[i].addr) { - reset_value[i] = counter_config[i].count; - wrmsrl(msrs->counters[i].addr, - -(u64)counter_config[i].count); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + int offset = i + __get_cpu_var(switch_index); +#else + int offset = i; +#endif + if (counter_config[offset].enabled && msrs->counters[i].addr) { + /* setup counter registers */ + wrmsrl(msrs->counters[i].addr, -(u64)reset_value[offset]); + + /* setup control registers */ rdmsrl(msrs->controls[i].addr, val); val &= model->reserved; - val |= op_x86_get_ctrl(model, &counter_config[i]); + val |= op_x86_get_ctrl(model, &counter_config[offset]); + wrmsrl(msrs->controls[i].addr, val); + } + } +} + + +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void op_amd_switch_ctrl(struct op_x86_model_spec const *model, + struct op_msrs const * const msrs) +{ + u64 val; + int i; + + /* enable active counters */ + for (i = 0; i < NUM_COUNTERS; ++i) { + int offset = i + __get_cpu_var(switch_index); + if (counter_config[offset].enabled) { + /* setup control registers */ + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + val |= op_x86_get_ctrl(model, &counter_config[offset]); wrmsrl(msrs->controls[i].addr, val); - } else { - reset_value[i] = 0; } } } +#endif + + #ifdef CONFIG_OPROFILE_IBS static inline int @@ -230,14 +292,19 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, int i; for (i = 0; i < NUM_COUNTERS; ++i) { - if (!reset_value[i]) +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + int offset = i + __get_cpu_var(switch_index); +#else + int offset = i; +#endif + if (!reset_value[offset]) continue; rdmsrl(msrs->counters[i].addr, val); /* bit is clear if overflowed: */ if (val & OP_CTR_OVERFLOW) continue; - oprofile_add_sample(regs, i); - wrmsrl(msrs->counters[i].addr, -(u64)reset_value[i]); + oprofile_add_sample(regs, offset); + wrmsrl(msrs->counters[i].addr, -(u64)reset_value[offset]); } op_amd_handle_ibs(regs, msrs); @@ -250,8 +317,14 @@ static void op_amd_start(struct op_msrs const * const msrs) { u64 val; int i; + for (i = 0; i < NUM_COUNTERS; ++i) { - if (reset_value[i]) { +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + int offset = i + __get_cpu_var(switch_index); +#else + int offset = i; +#endif + if (reset_value[offset]) { rdmsrl(msrs->controls[i].addr, val); val |= ARCH_PERFMON_EVENTSEL0_ENABLE; wrmsrl(msrs->controls[i].addr, val); @@ -271,7 +344,11 @@ static void op_amd_stop(struct op_msrs const * const msrs) * pm callback */ for (i = 0; i < NUM_COUNTERS; ++i) { +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + if (!reset_value[i + per_cpu(switch_index, smp_processor_id())]) +#else if (!reset_value[i]) +#endif continue; rdmsrl(msrs->controls[i].addr, val); val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; @@ -289,7 +366,7 @@ static void op_amd_shutdown(struct op_msrs const * const msrs) if (msrs->counters[i].addr) release_perfctr_nmi(MSR_K7_PERFCTR0 + i); } - for (i = 0; i < NUM_CONTROLS; ++i) { + for (i = 0; i < NUM_COUNTERS; ++i) { if (msrs->controls[i].addr) release_evntsel_nmi(MSR_K7_EVNTSEL0 + i); } @@ -463,6 +540,8 @@ static void op_amd_exit(void) {} struct op_x86_model_spec const op_amd_spec = { .num_counters = NUM_COUNTERS, .num_controls = NUM_CONTROLS, + .num_virt_counters = NUM_VIRT_COUNTERS, + .num_virt_controls = NUM_VIRT_CONTROLS, .reserved = MSR_AMD_EVENTSEL_RESERVED, .event_mask = OP_EVENT_MASK, .init = op_amd_init, @@ -473,4 +552,7 @@ struct op_x86_model_spec const op_amd_spec = { .start = &op_amd_start, .stop = &op_amd_stop, .shutdown = &op_amd_shutdown, +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + .switch_ctrl = &op_amd_switch_ctrl, +#endif }; diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 5921b7fc724..65b9237cde8 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -698,6 +698,8 @@ static void p4_shutdown(struct op_msrs const * const msrs) struct op_x86_model_spec const op_p4_ht2_spec = { .num_counters = NUM_COUNTERS_HT2, .num_controls = NUM_CONTROLS_HT2, + .num_virt_counters = NUM_COUNTERS_HT2, + .num_virt_controls = NUM_CONTROLS_HT2, .fill_in_addresses = &p4_fill_in_addresses, .setup_ctrs = &p4_setup_ctrs, .check_ctrs = &p4_check_ctrs, @@ -710,6 +712,8 @@ struct op_x86_model_spec const op_p4_ht2_spec = { struct op_x86_model_spec const op_p4_spec = { .num_counters = NUM_COUNTERS_NON_HT, .num_controls = NUM_CONTROLS_NON_HT, + .num_virt_counters = NUM_COUNTERS_NON_HT, + .num_virt_controls = NUM_CONTROLS_NON_HT, .fill_in_addresses = &p4_fill_in_addresses, .setup_ctrs = &p4_setup_ctrs, .check_ctrs = &p4_check_ctrs, diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 570d717c330..098cbca5c0b 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -206,6 +206,8 @@ static void ppro_shutdown(struct op_msrs const * const msrs) struct op_x86_model_spec const op_ppro_spec = { .num_counters = 2, .num_controls = 2, + .num_virt_counters = 2, + .num_virt_controls = 2, .reserved = MSR_PPRO_EVENTSEL_RESERVED, .fill_in_addresses = &ppro_fill_in_addresses, .setup_ctrs = &ppro_setup_ctrs, diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 505489873b9..0d07d23cb06 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -23,6 +23,7 @@ struct op_msr { struct op_msrs { struct op_msr *counters; struct op_msr *controls; + struct op_msr *multiplex; }; struct pt_regs; @@ -35,6 +36,8 @@ struct oprofile_operations; struct op_x86_model_spec { unsigned int num_counters; unsigned int num_controls; + unsigned int num_virt_counters; + unsigned int num_virt_controls; u64 reserved; u16 event_mask; int (*init)(struct oprofile_operations *ops); @@ -47,6 +50,10 @@ struct op_x86_model_spec { void (*start)(struct op_msrs const * const msrs); void (*stop)(struct op_msrs const * const msrs); void (*shutdown)(struct op_msrs const * const msrs); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + void (*switch_ctrl)(struct op_x86_model_spec const *model, + struct op_msrs const * const msrs); +#endif }; struct op_counter_config; diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 3cffce90f82..7bc64af7cf9 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include "oprof.h" @@ -27,6 +29,15 @@ unsigned long oprofile_backtrace_depth; static unsigned long is_setup; static DEFINE_MUTEX(start_mutex); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void switch_worker(struct work_struct *work); +static DECLARE_DELAYED_WORK(switch_work, switch_worker); +unsigned long timeout_jiffies; +#define MULTIPLEXING_TIMER_DEFAULT 1 + +#endif + /* timer 0 - use performance monitoring hardware if available 1 - use the timer int mechanism regardless @@ -87,6 +98,20 @@ out: return err; } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void start_switch_worker(void) +{ + schedule_delayed_work(&switch_work, timeout_jiffies); +} + +static void switch_worker(struct work_struct *work) +{ + if (!oprofile_ops.switch_events()) + start_switch_worker(); +} + +#endif /* Actually start profiling (echo 1>/dev/oprofile/enable) */ int oprofile_start(void) @@ -108,6 +133,11 @@ int oprofile_start(void) if ((err = oprofile_ops.start())) goto out; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + if (oprofile_ops.switch_events) + start_switch_worker(); +#endif + oprofile_started = 1; out: mutex_unlock(&start_mutex); @@ -123,6 +153,11 @@ void oprofile_stop(void) goto out; oprofile_ops.stop(); oprofile_started = 0; + +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + cancel_delayed_work_sync(&switch_work); +#endif + /* wake up the daemon to read what remains */ wake_up_buffer_waiter(); out: @@ -155,6 +190,36 @@ post_sync: mutex_unlock(&start_mutex); } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +/* User inputs in ms, converts to jiffies */ +int oprofile_set_timeout(unsigned long val_msec) +{ + int err = 0; + + mutex_lock(&start_mutex); + + if (oprofile_started) { + err = -EBUSY; + goto out; + } + + if (!oprofile_ops.switch_events) { + err = -EINVAL; + goto out; + } + + timeout_jiffies = msecs_to_jiffies(val_msec); + if (timeout_jiffies == MAX_JIFFY_OFFSET) + timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT); + +out: + mutex_unlock(&start_mutex); + return err; + +} + +#endif int oprofile_set_backtrace(unsigned long val) { @@ -179,10 +244,23 @@ out: return err; } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void __init oprofile_multiplexing_init(void) +{ + timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT); +} + +#endif + static int __init oprofile_init(void) { int err; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + oprofile_multiplexing_init(); +#endif + err = oprofile_arch_init(&oprofile_ops); if (err < 0 || timer) { diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index c288d3c24b5..ee38abcc74f 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h @@ -27,6 +27,7 @@ extern unsigned long oprofile_buffer_watershed; extern struct oprofile_operations oprofile_ops; extern unsigned long oprofile_started; extern unsigned long oprofile_backtrace_depth; +extern unsigned long timeout_jiffies; struct super_block; struct dentry; @@ -35,5 +36,6 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root); void oprofile_timer_init(struct oprofile_operations *ops); int oprofile_set_backtrace(unsigned long depth); +int oprofile_set_timeout(unsigned long time); #endif /* OPROF_H */ diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 5d36ffc30dd..468ec3e4f85 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -9,6 +9,7 @@ #include #include +#include #include "event_buffer.h" #include "oprofile_stats.h" @@ -22,6 +23,45 @@ unsigned long oprofile_buffer_size; unsigned long oprofile_cpu_buffer_size; unsigned long oprofile_buffer_watershed; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static ssize_t timeout_read(struct file *file, char __user *buf, + size_t count, loff_t *offset) +{ + return oprofilefs_ulong_to_user(jiffies_to_msecs(timeout_jiffies), + buf, count, offset); +} + + +static ssize_t timeout_write(struct file *file, char const __user *buf, + size_t count, loff_t *offset) +{ + unsigned long val; + int retval; + + if (*offset) + return -EINVAL; + + retval = oprofilefs_ulong_from_user(&val, buf, count); + if (retval) + return retval; + + retval = oprofile_set_timeout(val); + + if (retval) + return retval; + return count; +} + + +static const struct file_operations timeout_fops = { + .read = timeout_read, + .write = timeout_write, +}; + +#endif + + static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { return oprofilefs_ulong_to_user(oprofile_backtrace_depth, buf, count, @@ -139,6 +179,9 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root) oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops); oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + oprofilefs_create_file(sb, root, "time_slice", &timeout_fops); +#endif oprofile_create_stats_files(sb, root); if (oprofile_ops.create_files) oprofile_ops.create_files(sb, root); diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index 3c2270a8300..77a57a6792f 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -16,6 +16,9 @@ #include "cpu_buffer.h" struct oprofile_stat_struct oprofile_stats; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX +atomic_t multiplex_counter; +#endif void oprofile_reset_stats(void) { @@ -34,6 +37,9 @@ void oprofile_reset_stats(void) atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); atomic_set(&oprofile_stats.event_lost_overflow, 0); atomic_set(&oprofile_stats.bt_lost_no_mapping, 0); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + atomic_set(&multiplex_counter, 0); +#endif } @@ -76,4 +82,8 @@ void oprofile_create_stats_files(struct super_block *sb, struct dentry *root) &oprofile_stats.event_lost_overflow); oprofilefs_create_ro_atomic(sb, dir, "bt_lost_no_mapping", &oprofile_stats.bt_lost_no_mapping); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + oprofilefs_create_ro_atomic(sb, dir, "multiplex_counter", + &multiplex_counter); +#endif } diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index d68d2ed94f1..5171639ecf0 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -67,6 +67,9 @@ struct oprofile_operations { /* Initiate a stack backtrace. Optional. */ void (*backtrace)(struct pt_regs * const regs, unsigned int depth); + + /* Multiplex between different events. Optional. */ + int (*switch_events)(void); /* CPU identification string. */ char * cpu_type; }; -- cgit v1.2.3-18-g5258 From 5e766e3e433fa2d5d2fdfd8e2432804c91393387 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 8 Jul 2009 14:54:17 +0200 Subject: x86/oprofile: Fix usage of NUM_CONTROLS/NUM_COUNTERS macros Use the corresponding macros when iterating over counter and control registers. Since NUM_CONTROLS and NUM_COUNTERS are equal for AMD cpus the fix is more a cosmetical change. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index fdbed3a0c87..dcfd4505cac 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -99,7 +99,7 @@ static void op_amd_fill_in_addresses(struct op_msrs * const msrs) #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX for (i = 0; i < NUM_VIRT_COUNTERS; i++) { - int hw_counter = i % NUM_CONTROLS; + int hw_counter = i % NUM_COUNTERS; if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i)) msrs->multiplex[i].addr = MSR_K7_PERFCTR0 + hw_counter; else @@ -366,7 +366,7 @@ static void op_amd_shutdown(struct op_msrs const * const msrs) if (msrs->counters[i].addr) release_perfctr_nmi(MSR_K7_PERFCTR0 + i); } - for (i = 0; i < NUM_COUNTERS; ++i) { + for (i = 0; i < NUM_CONTROLS; ++i) { if (msrs->controls[i].addr) release_evntsel_nmi(MSR_K7_EVNTSEL0 + i); } -- cgit v1.2.3-18-g5258 From 82a225283fb0d9438549595d9e6f3ecc42b42ad6 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 16:29:34 +0200 Subject: x86/oprofile: Use per_cpu() instead of __get_cpu_var() __get_cpu_var() calls smp_processor_id(). When the cpu id is already known, instead use per_cpu() to avoid generating the id again. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index e54f6a0b35a..8cd4658370b 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -294,7 +294,7 @@ static void nmi_cpu_shutdown(void *dummy) { unsigned int v; int cpu = smp_processor_id(); - struct op_msrs *msrs = &__get_cpu_var(cpu_msrs); + struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); /* restoring APIC_LVTPC can trigger an apic error because the delivery * mode and vector nr combination can be illegal. That's by design: on @@ -307,7 +307,7 @@ static void nmi_cpu_shutdown(void *dummy) apic_write(APIC_LVTERR, v); nmi_cpu_restore_registers(msrs); #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - __get_cpu_var(switch_index) = 0; + per_cpu(switch_index, cpu) = 0; #endif } -- cgit v1.2.3-18-g5258 From 6bfccd099c2841e1c42530f1b6d2553bfa13be3a Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 19:23:50 +0200 Subject: x86/oprofile: Fix initialization of switch_index Variable switch_index must be initialized for each cpu. This patch fixes the initialization by moving it to the per-cpu init function nmi_cpu_setup(). Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 8cd4658370b..b211d335e07 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -160,7 +160,7 @@ static int allocate_msrs(void) #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX -static void nmi_setup_cpu_mux(struct op_msrs const * const msrs) +static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { int i; struct op_msr *multiplex = msrs->multiplex; @@ -173,8 +173,15 @@ static void nmi_setup_cpu_mux(struct op_msrs const * const msrs) multiplex[i].saved = 0; } } + + per_cpu(switch_index, cpu) = 0; } +#else + +static inline void +nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { } + #endif static void nmi_cpu_setup(void *dummy) @@ -184,9 +191,7 @@ static void nmi_cpu_setup(void *dummy) nmi_cpu_save_registers(msrs); spin_lock(&oprofilefs_lock); model->setup_ctrs(model, msrs); -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - nmi_setup_cpu_mux(msrs); -#endif + nmi_cpu_setup_mux(cpu, msrs); spin_unlock(&oprofilefs_lock); per_cpu(saved_lvtpc, cpu) = apic_read(APIC_LVTPC); apic_write(APIC_LVTPC, APIC_DM_NMI); @@ -662,9 +667,6 @@ int __init op_nmi_init(struct oprofile_operations *ops) register_cpu_notifier(&oprofile_cpu_nb); #endif /* default values, can be overwritten by model */ -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - __raw_get_cpu_var(switch_index) = 0; -#endif ops->create_files = nmi_create_files; ops->setup = nmi_setup; ops->shutdown = nmi_shutdown; -- cgit v1.2.3-18-g5258 From 2051cade7ccbe45a8bf8b7809d56b23d6d75ad03 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 15 Jul 2009 15:44:18 +0200 Subject: oprofile: oprofile_set_timeout(), return with error for invalid args Return with -EINVAL for invalid parameters instead of setting the default value in oprofile_set_timeout(). Signed-off-by: Robert Richter --- drivers/oprofile/oprof.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 7bc64af7cf9..42c9c765f9f 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -196,6 +196,7 @@ post_sync: int oprofile_set_timeout(unsigned long val_msec) { int err = 0; + unsigned long time_slice; mutex_lock(&start_mutex); @@ -209,9 +210,13 @@ int oprofile_set_timeout(unsigned long val_msec) goto out; } - timeout_jiffies = msecs_to_jiffies(val_msec); - if (timeout_jiffies == MAX_JIFFY_OFFSET) - timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT); + time_slice = msecs_to_jiffies(val_msec); + if (time_slice == MAX_JIFFY_OFFSET) { + err = -EINVAL; + goto out; + } + + timeout_jiffies = time_slice; out: mutex_unlock(&start_mutex); -- cgit v1.2.3-18-g5258 From afe1b50fe6aa56093e9234bdc08779e9fe20b5bf Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 15 Jul 2009 15:19:29 +0200 Subject: oprofile: Rename variable timeout_jiffies and move to oprofile_files.c This patch renames timeout_jiffies into an oprofile specific name. The macro MULTIPLEXING_TIMER_DEFAULT is changed too. Also, since this variable is controlled using oprofilefs, its definition is moved to oprofile_files.c. Signed-off-by: Robert Richter --- drivers/oprofile/oprof.c | 9 ++++----- drivers/oprofile/oprof.h | 3 ++- drivers/oprofile/oprofile_files.c | 5 +++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 42c9c765f9f..2b33de71641 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -33,8 +33,7 @@ static DEFINE_MUTEX(start_mutex); static void switch_worker(struct work_struct *work); static DECLARE_DELAYED_WORK(switch_work, switch_worker); -unsigned long timeout_jiffies; -#define MULTIPLEXING_TIMER_DEFAULT 1 +#define TIME_SLICE_DEFAULT 1 #endif @@ -102,7 +101,7 @@ out: static void start_switch_worker(void) { - schedule_delayed_work(&switch_work, timeout_jiffies); + schedule_delayed_work(&switch_work, oprofile_time_slice); } static void switch_worker(struct work_struct *work) @@ -216,7 +215,7 @@ int oprofile_set_timeout(unsigned long val_msec) goto out; } - timeout_jiffies = time_slice; + oprofile_time_slice = time_slice; out: mutex_unlock(&start_mutex); @@ -253,7 +252,7 @@ out: static void __init oprofile_multiplexing_init(void) { - timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT); + oprofile_time_slice = msecs_to_jiffies(TIME_SLICE_DEFAULT); } #endif diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index ee38abcc74f..cb92f5c98c1 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h @@ -24,10 +24,11 @@ struct oprofile_operations; extern unsigned long oprofile_buffer_size; extern unsigned long oprofile_cpu_buffer_size; extern unsigned long oprofile_buffer_watershed; +extern unsigned long oprofile_time_slice; + extern struct oprofile_operations oprofile_ops; extern unsigned long oprofile_started; extern unsigned long oprofile_backtrace_depth; -extern unsigned long timeout_jiffies; struct super_block; struct dentry; diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 468ec3e4f85..4c5b9477584 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -22,14 +22,15 @@ unsigned long oprofile_buffer_size; unsigned long oprofile_cpu_buffer_size; unsigned long oprofile_buffer_watershed; +unsigned long oprofile_time_slice; #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX static ssize_t timeout_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { - return oprofilefs_ulong_to_user(jiffies_to_msecs(timeout_jiffies), - buf, count, offset); + return oprofilefs_ulong_to_user(jiffies_to_msecs(oprofile_time_slice), + buf, count, offset); } -- cgit v1.2.3-18-g5258 From 16422a6e2d16a39861ae5b0b11d9b411a245ab83 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 15 Jul 2009 15:44:18 +0200 Subject: oprofile: Remove oprofile_multiplexing_init() oprofile_multiplexing_init() can be removed when moving the initialization of oprofile_time_slice to oprofile_create_files(). Signed-off-by: Robert Richter --- drivers/oprofile/oprof.c | 14 -------------- drivers/oprofile/oprofile_files.c | 2 ++ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 2b33de71641..fa6cccd87cf 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -33,7 +33,6 @@ static DEFINE_MUTEX(start_mutex); static void switch_worker(struct work_struct *work); static DECLARE_DELAYED_WORK(switch_work, switch_worker); -#define TIME_SLICE_DEFAULT 1 #endif @@ -248,23 +247,10 @@ out: return err; } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -static void __init oprofile_multiplexing_init(void) -{ - oprofile_time_slice = msecs_to_jiffies(TIME_SLICE_DEFAULT); -} - -#endif - static int __init oprofile_init(void) { int err; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - oprofile_multiplexing_init(); -#endif - err = oprofile_arch_init(&oprofile_ops); if (err < 0 || timer) { diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 4c5b9477584..bbd7516e086 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -18,6 +18,7 @@ #define BUFFER_SIZE_DEFAULT 131072 #define CPU_BUFFER_SIZE_DEFAULT 8192 #define BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */ +#define TIME_SLICE_DEFAULT 1 unsigned long oprofile_buffer_size; unsigned long oprofile_cpu_buffer_size; @@ -170,6 +171,7 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root) oprofile_buffer_size = BUFFER_SIZE_DEFAULT; oprofile_cpu_buffer_size = CPU_BUFFER_SIZE_DEFAULT; oprofile_buffer_watershed = BUFFER_WATERSHED_DEFAULT; + oprofile_time_slice = msecs_to_jiffies(TIME_SLICE_DEFAULT); oprofilefs_create_file(sb, root, "enable", &enable_fops); oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666); -- cgit v1.2.3-18-g5258 From a5659d17adb815fb35e11745e2f39c3f0bfd579f Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 19 Jun 2009 16:45:34 +0200 Subject: oprofile: Grouping multiplexing code in oprof.c This patch moves multiplexing code to a single section of code. This reduces the use of #ifdefs especially within functions. Signed-off-by: Robert Richter --- drivers/oprofile/oprof.c | 100 +++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index fa6cccd87cf..a48294a8ebe 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -29,13 +29,6 @@ unsigned long oprofile_backtrace_depth; static unsigned long is_setup; static DEFINE_MUTEX(start_mutex); -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -static void switch_worker(struct work_struct *work); -static DECLARE_DELAYED_WORK(switch_work, switch_worker); - -#endif - /* timer 0 - use performance monitoring hardware if available 1 - use the timer int mechanism regardless @@ -98,9 +91,18 @@ out: #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX +static void switch_worker(struct work_struct *work); +static DECLARE_DELAYED_WORK(switch_work, switch_worker); + static void start_switch_worker(void) { - schedule_delayed_work(&switch_work, oprofile_time_slice); + if (oprofile_ops.switch_events) + schedule_delayed_work(&switch_work, oprofile_time_slice); +} + +static void stop_switch_worker(void) +{ + cancel_delayed_work_sync(&switch_work); } static void switch_worker(struct work_struct *work) @@ -109,6 +111,43 @@ static void switch_worker(struct work_struct *work) start_switch_worker(); } +/* User inputs in ms, converts to jiffies */ +int oprofile_set_timeout(unsigned long val_msec) +{ + int err = 0; + unsigned long time_slice; + + mutex_lock(&start_mutex); + + if (oprofile_started) { + err = -EBUSY; + goto out; + } + + if (!oprofile_ops.switch_events) { + err = -EINVAL; + goto out; + } + + time_slice = msecs_to_jiffies(val_msec); + if (time_slice == MAX_JIFFY_OFFSET) { + err = -EINVAL; + goto out; + } + + oprofile_time_slice = time_slice; + +out: + mutex_unlock(&start_mutex); + return err; + +} + +#else + +static inline void start_switch_worker(void) { } +static inline void stop_switch_worker(void) { } + #endif /* Actually start profiling (echo 1>/dev/oprofile/enable) */ @@ -131,10 +170,7 @@ int oprofile_start(void) if ((err = oprofile_ops.start())) goto out; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - if (oprofile_ops.switch_events) - start_switch_worker(); -#endif + start_switch_worker(); oprofile_started = 1; out: @@ -152,9 +188,7 @@ void oprofile_stop(void) oprofile_ops.stop(); oprofile_started = 0; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - cancel_delayed_work_sync(&switch_work); -#endif + stop_switch_worker(); /* wake up the daemon to read what remains */ wake_up_buffer_waiter(); @@ -188,42 +222,6 @@ post_sync: mutex_unlock(&start_mutex); } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -/* User inputs in ms, converts to jiffies */ -int oprofile_set_timeout(unsigned long val_msec) -{ - int err = 0; - unsigned long time_slice; - - mutex_lock(&start_mutex); - - if (oprofile_started) { - err = -EBUSY; - goto out; - } - - if (!oprofile_ops.switch_events) { - err = -EINVAL; - goto out; - } - - time_slice = msecs_to_jiffies(val_msec); - if (time_slice == MAX_JIFFY_OFFSET) { - err = -EINVAL; - goto out; - } - - oprofile_time_slice = time_slice; - -out: - mutex_unlock(&start_mutex); - return err; - -} - -#endif - int oprofile_set_backtrace(unsigned long val) { int err = 0; -- cgit v1.2.3-18-g5258 From d8471ad3ab613a1ba7abd3aad46659de39a2871c Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 16 Jul 2009 13:04:43 +0200 Subject: oprofile: Introduce op_x86_phys_to_virt() This new function translates physical to virtual counter numbers. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 43 +++++++++++---------- arch/x86/oprofile/op_model_amd.c | 80 ++++++++++++++++------------------------ arch/x86/oprofile/op_x86_model.h | 1 + 3 files changed, 55 insertions(+), 69 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index b211d335e07..02b57b8d0e6 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -27,12 +27,6 @@ #include "op_counter.h" #include "op_x86_model.h" - -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX -DEFINE_PER_CPU(int, switch_index); -#endif - - static struct op_x86_model_spec const *model; static DEFINE_PER_CPU(struct op_msrs, cpu_msrs); static DEFINE_PER_CPU(unsigned long, saved_lvtpc); @@ -103,6 +97,21 @@ static void nmi_cpu_save_registers(struct op_msrs *msrs) } } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static DEFINE_PER_CPU(int, switch_index); + +inline int op_x86_phys_to_virt(int phys) +{ + return __get_cpu_var(switch_index) + phys; +} + +#else + +inline int op_x86_phys_to_virt(int phys) { return phys; } + +#endif + static void free_msrs(void) { int i; @@ -248,31 +257,25 @@ static int nmi_setup(void) static void nmi_cpu_save_mpx_registers(struct op_msrs *msrs) { - unsigned int si = __get_cpu_var(switch_index); struct op_msr *multiplex = msrs->multiplex; - unsigned int i; + int i; for (i = 0; i < model->num_counters; ++i) { - int offset = i + si; - if (multiplex[offset].addr) { - rdmsrl(multiplex[offset].addr, - multiplex[offset].saved); - } + int virt = op_x86_phys_to_virt(i); + if (multiplex[virt].addr) + rdmsrl(multiplex[virt].addr, multiplex[virt].saved); } } static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs) { - unsigned int si = __get_cpu_var(switch_index); struct op_msr *multiplex = msrs->multiplex; - unsigned int i; + int i; for (i = 0; i < model->num_counters; ++i) { - int offset = i + si; - if (multiplex[offset].addr) { - wrmsrl(multiplex[offset].addr, - multiplex[offset].saved); - } + int virt = op_x86_phys_to_virt(i); + if (multiplex[virt].addr) + wrmsrl(multiplex[virt].addr, multiplex[virt].saved); } } diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index dcfd4505cac..67f830d12e0 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -42,9 +42,6 @@ #define MSR_AMD_EVENTSEL_RESERVED ((0xFFFFFCF0ULL<<32)|(1ULL<<21)) static unsigned long reset_value[NUM_VIRT_COUNTERS]; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX -DECLARE_PER_CPU(int, switch_index); -#endif #ifdef CONFIG_OPROFILE_IBS @@ -141,21 +138,20 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, /* enable active counters */ for (i = 0; i < NUM_COUNTERS; ++i) { -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - int offset = i + __get_cpu_var(switch_index); -#else - int offset = i; -#endif - if (counter_config[offset].enabled && msrs->counters[i].addr) { - /* setup counter registers */ - wrmsrl(msrs->counters[i].addr, -(u64)reset_value[offset]); - - /* setup control registers */ - rdmsrl(msrs->controls[i].addr, val); - val &= model->reserved; - val |= op_x86_get_ctrl(model, &counter_config[offset]); - wrmsrl(msrs->controls[i].addr, val); - } + int virt = op_x86_phys_to_virt(i); + if (!counter_config[virt].enabled) + continue; + if (!msrs->counters[i].addr) + continue; + + /* setup counter registers */ + wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]); + + /* setup control registers */ + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + val |= op_x86_get_ctrl(model, &counter_config[virt]); + wrmsrl(msrs->controls[i].addr, val); } } @@ -170,14 +166,13 @@ static void op_amd_switch_ctrl(struct op_x86_model_spec const *model, /* enable active counters */ for (i = 0; i < NUM_COUNTERS; ++i) { - int offset = i + __get_cpu_var(switch_index); - if (counter_config[offset].enabled) { - /* setup control registers */ - rdmsrl(msrs->controls[i].addr, val); - val &= model->reserved; - val |= op_x86_get_ctrl(model, &counter_config[offset]); - wrmsrl(msrs->controls[i].addr, val); - } + int virt = op_x86_phys_to_virt(i); + if (!counter_config[virt].enabled) + continue; + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + val |= op_x86_get_ctrl(model, &counter_config[virt]); + wrmsrl(msrs->controls[i].addr, val); } } @@ -292,19 +287,15 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, int i; for (i = 0; i < NUM_COUNTERS; ++i) { -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - int offset = i + __get_cpu_var(switch_index); -#else - int offset = i; -#endif - if (!reset_value[offset]) + int virt = op_x86_phys_to_virt(i); + if (!reset_value[virt]) continue; rdmsrl(msrs->counters[i].addr, val); /* bit is clear if overflowed: */ if (val & OP_CTR_OVERFLOW) continue; - oprofile_add_sample(regs, offset); - wrmsrl(msrs->counters[i].addr, -(u64)reset_value[offset]); + oprofile_add_sample(regs, virt); + wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]); } op_amd_handle_ibs(regs, msrs); @@ -319,16 +310,11 @@ static void op_amd_start(struct op_msrs const * const msrs) int i; for (i = 0; i < NUM_COUNTERS; ++i) { -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - int offset = i + __get_cpu_var(switch_index); -#else - int offset = i; -#endif - if (reset_value[offset]) { - rdmsrl(msrs->controls[i].addr, val); - val |= ARCH_PERFMON_EVENTSEL0_ENABLE; - wrmsrl(msrs->controls[i].addr, val); - } + if (!reset_value[op_x86_phys_to_virt(i)]) + continue; + rdmsrl(msrs->controls[i].addr, val); + val |= ARCH_PERFMON_EVENTSEL0_ENABLE; + wrmsrl(msrs->controls[i].addr, val); } op_amd_start_ibs(); @@ -344,11 +330,7 @@ static void op_amd_stop(struct op_msrs const * const msrs) * pm callback */ for (i = 0; i < NUM_COUNTERS; ++i) { -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - if (!reset_value[i + per_cpu(switch_index, smp_processor_id())]) -#else - if (!reset_value[i]) -#endif + if (!reset_value[op_x86_phys_to_virt(i)]) continue; rdmsrl(msrs->controls[i].addr, val); val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 0d07d23cb06..e874dc3565a 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -60,6 +60,7 @@ struct op_counter_config; extern u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, struct op_counter_config *counter_config); +extern int op_x86_phys_to_virt(int phys); extern struct op_x86_model_spec const op_ppro_spec; extern struct op_x86_model_spec const op_p4_spec; -- cgit v1.2.3-18-g5258 From 7e7478c6bc0e011d2854b21f190cc3a1dba89905 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 16 Jul 2009 13:09:53 +0200 Subject: oprofile: Grouping multiplexing code in op_model_amd.c This patch moves some multiplexing code to the new function op_mux_fill_in_addresses(). Also, the whole multiplexing code is now at a single location. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 75 ++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 67f830d12e0..644980f0392 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -74,6 +74,45 @@ static struct op_ibs_config ibs_config; #endif +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void op_mux_fill_in_addresses(struct op_msrs * const msrs) +{ + int i; + + for (i = 0; i < NUM_VIRT_COUNTERS; i++) { + int hw_counter = i % NUM_COUNTERS; + if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i)) + msrs->multiplex[i].addr = MSR_K7_PERFCTR0 + hw_counter; + else + msrs->multiplex[i].addr = 0; + } +} + +static void op_mux_switch_ctrl(struct op_x86_model_spec const *model, + struct op_msrs const * const msrs) +{ + u64 val; + int i; + + /* enable active counters */ + for (i = 0; i < NUM_COUNTERS; ++i) { + int virt = op_x86_phys_to_virt(i); + if (!counter_config[virt].enabled) + continue; + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + val |= op_x86_get_ctrl(model, &counter_config[virt]); + wrmsrl(msrs->controls[i].addr, val); + } +} + +#else + +static inline void op_mux_fill_in_addresses(struct op_msrs * const msrs) { } + +#endif + /* functions for op_amd_spec */ static void op_amd_fill_in_addresses(struct op_msrs * const msrs) @@ -94,15 +133,7 @@ static void op_amd_fill_in_addresses(struct op_msrs * const msrs) msrs->controls[i].addr = 0; } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - for (i = 0; i < NUM_VIRT_COUNTERS; i++) { - int hw_counter = i % NUM_COUNTERS; - if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i)) - msrs->multiplex[i].addr = MSR_K7_PERFCTR0 + hw_counter; - else - msrs->multiplex[i].addr = 0; - } -#endif + op_mux_fill_in_addresses(msrs); } static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, @@ -155,30 +186,6 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, } } - -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -static void op_amd_switch_ctrl(struct op_x86_model_spec const *model, - struct op_msrs const * const msrs) -{ - u64 val; - int i; - - /* enable active counters */ - for (i = 0; i < NUM_COUNTERS; ++i) { - int virt = op_x86_phys_to_virt(i); - if (!counter_config[virt].enabled) - continue; - rdmsrl(msrs->controls[i].addr, val); - val &= model->reserved; - val |= op_x86_get_ctrl(model, &counter_config[virt]); - wrmsrl(msrs->controls[i].addr, val); - } -} - -#endif - - #ifdef CONFIG_OPROFILE_IBS static inline int @@ -535,6 +542,6 @@ struct op_x86_model_spec const op_amd_spec = { .stop = &op_amd_stop, .shutdown = &op_amd_shutdown, #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - .switch_ctrl = &op_amd_switch_ctrl, + .switch_ctrl = &op_mux_switch_ctrl, #endif }; -- cgit v1.2.3-18-g5258 From 6ab82f958a5dca591a6ea17a3ca6f2aca06f4f2f Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 14:40:04 +0200 Subject: x86/oprofile: Implement multiplexing setup/shutdown functions This patch implements nmi_setup_mux() and nmi_shutdown_mux() functions to setup/shutdown multiplexing. Multiplexing code in nmi_int.c is now much more separated. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 76 ++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 02b57b8d0e6..674fa37d150 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -106,9 +106,35 @@ inline int op_x86_phys_to_virt(int phys) return __get_cpu_var(switch_index) + phys; } +static void nmi_shutdown_mux(void) +{ + int i; + for_each_possible_cpu(i) { + kfree(per_cpu(cpu_msrs, i).multiplex); + per_cpu(cpu_msrs, i).multiplex = NULL; + per_cpu(switch_index, i) = 0; + } +} + +static int nmi_setup_mux(void) +{ + size_t multiplex_size = + sizeof(struct op_msr) * model->num_virt_counters; + int i; + for_each_possible_cpu(i) { + per_cpu(cpu_msrs, i).multiplex = + kmalloc(multiplex_size, GFP_KERNEL); + if (!per_cpu(cpu_msrs, i).multiplex) + return 0; + } + return 1; +} + #else inline int op_x86_phys_to_virt(int phys) { return phys; } +static inline void nmi_shutdown_mux(void) { } +static inline int nmi_setup_mux(void) { return 1; } #endif @@ -120,51 +146,27 @@ static void free_msrs(void) per_cpu(cpu_msrs, i).counters = NULL; kfree(per_cpu(cpu_msrs, i).controls); per_cpu(cpu_msrs, i).controls = NULL; - -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - kfree(per_cpu(cpu_msrs, i).multiplex); - per_cpu(cpu_msrs, i).multiplex = NULL; -#endif } } static int allocate_msrs(void) { - int success = 1; size_t controls_size = sizeof(struct op_msr) * model->num_controls; size_t counters_size = sizeof(struct op_msr) * model->num_counters; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - size_t multiplex_size = sizeof(struct op_msr) * model->num_virt_counters; -#endif int i; for_each_possible_cpu(i) { per_cpu(cpu_msrs, i).counters = kmalloc(counters_size, - GFP_KERNEL); - if (!per_cpu(cpu_msrs, i).counters) { - success = 0; - break; - } + GFP_KERNEL); + if (!per_cpu(cpu_msrs, i).counters) + return 0; per_cpu(cpu_msrs, i).controls = kmalloc(controls_size, - GFP_KERNEL); - if (!per_cpu(cpu_msrs, i).controls) { - success = 0; - break; - } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - per_cpu(cpu_msrs, i).multiplex = - kmalloc(multiplex_size, GFP_KERNEL); - if (!per_cpu(cpu_msrs, i).multiplex) { - success = 0; - break; - } -#endif + GFP_KERNEL); + if (!per_cpu(cpu_msrs, i).controls) + return 0; } - if (!success) - free_msrs(); - - return success; + return 1; } #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX @@ -218,11 +220,15 @@ static int nmi_setup(void) int cpu; if (!allocate_msrs()) - return -ENOMEM; + err = -ENOMEM; + else if (!nmi_setup_mux()) + err = -ENOMEM; + else + err = register_die_notifier(&profile_exceptions_nb); - err = register_die_notifier(&profile_exceptions_nb); if (err) { free_msrs(); + nmi_shutdown_mux(); return err; } @@ -314,9 +320,6 @@ static void nmi_cpu_shutdown(void *dummy) apic_write(APIC_LVTPC, per_cpu(saved_lvtpc, cpu)); apic_write(APIC_LVTERR, v); nmi_cpu_restore_registers(msrs); -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - per_cpu(switch_index, cpu) = 0; -#endif } static void nmi_shutdown(void) @@ -326,6 +329,7 @@ static void nmi_shutdown(void) nmi_enabled = 0; on_each_cpu(nmi_cpu_shutdown, NULL, 1); unregister_die_notifier(&profile_exceptions_nb); + nmi_shutdown_mux(); msrs = &get_cpu_var(cpu_msrs); model->shutdown(msrs); free_msrs(); -- cgit v1.2.3-18-g5258 From 48fb4b46712c7d3e8adc79826311abd9ccbf7f1d Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 14:38:49 +0200 Subject: x86/oprofile: Moving nmi_setup_cpu_mux() in nmi_int.c This patch moves some code in nmi_int.c to get a single separate multiplexing code section. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 674fa37d150..b1edfc922e7 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -130,11 +130,30 @@ static int nmi_setup_mux(void) return 1; } +static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) +{ + int i; + struct op_msr *multiplex = msrs->multiplex; + + for (i = 0; i < model->num_virt_counters; ++i) { + if (counter_config[i].enabled) { + multiplex[i].saved = -(u64)counter_config[i].count; + } else { + multiplex[i].addr = 0; + multiplex[i].saved = 0; + } + } + + per_cpu(switch_index, cpu) = 0; +} + #else inline int op_x86_phys_to_virt(int phys) { return phys; } static inline void nmi_shutdown_mux(void) { } static inline int nmi_setup_mux(void) { return 1; } +static inline void +nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { } #endif @@ -169,32 +188,6 @@ static int allocate_msrs(void) return 1; } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) -{ - int i; - struct op_msr *multiplex = msrs->multiplex; - - for (i = 0; i < model->num_virt_counters; ++i) { - if (counter_config[i].enabled) { - multiplex[i].saved = -(u64)counter_config[i].count; - } else { - multiplex[i].addr = 0; - multiplex[i].saved = 0; - } - } - - per_cpu(switch_index, cpu) = 0; -} - -#else - -static inline void -nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { } - -#endif - static void nmi_cpu_setup(void *dummy) { int cpu = smp_processor_id(); -- cgit v1.2.3-18-g5258 From d0f585dd20010f8479e56b5c6f391ef18e26877e Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 14:38:49 +0200 Subject: x86/oprofile: Moving nmi_cpu_save/restore_mpx_registers() in nmi_int.c This patch moves some code in nmi_int.c to get a single separate multiplexing code section. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 52 +++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index b1edfc922e7..f38c5cf0fdb 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -147,6 +147,30 @@ static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) per_cpu(switch_index, cpu) = 0; } +static void nmi_cpu_save_mpx_registers(struct op_msrs *msrs) +{ + struct op_msr *multiplex = msrs->multiplex; + int i; + + for (i = 0; i < model->num_counters; ++i) { + int virt = op_x86_phys_to_virt(i); + if (multiplex[virt].addr) + rdmsrl(multiplex[virt].addr, multiplex[virt].saved); + } +} + +static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs) +{ + struct op_msr *multiplex = msrs->multiplex; + int i; + + for (i = 0; i < model->num_counters; ++i) { + int virt = op_x86_phys_to_virt(i); + if (multiplex[virt].addr) + wrmsrl(multiplex[virt].addr, multiplex[virt].saved); + } +} + #else inline int op_x86_phys_to_virt(int phys) { return phys; } @@ -252,34 +276,6 @@ static int nmi_setup(void) return 0; } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -static void nmi_cpu_save_mpx_registers(struct op_msrs *msrs) -{ - struct op_msr *multiplex = msrs->multiplex; - int i; - - for (i = 0; i < model->num_counters; ++i) { - int virt = op_x86_phys_to_virt(i); - if (multiplex[virt].addr) - rdmsrl(multiplex[virt].addr, multiplex[virt].saved); - } -} - -static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs) -{ - struct op_msr *multiplex = msrs->multiplex; - int i; - - for (i = 0; i < model->num_counters; ++i) { - int virt = op_x86_phys_to_virt(i); - if (multiplex[virt].addr) - wrmsrl(multiplex[virt].addr, multiplex[virt].saved); - } -} - -#endif - static void nmi_cpu_restore_registers(struct op_msrs *msrs) { struct op_msr *counters = msrs->counters; -- cgit v1.2.3-18-g5258 From b28d1b923ab52d535c0719155dccf3b3d98bab9f Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 14:38:49 +0200 Subject: x86/oprofile: Moving nmi_cpu_switch() in nmi_int.c This patch moves some code in nmi_int.c to get a single separate multiplexing code section. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 144 +++++++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 74 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index f38c5cf0fdb..998c7dca31e 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -97,6 +97,29 @@ static void nmi_cpu_save_registers(struct op_msrs *msrs) } } +static void nmi_cpu_start(void *dummy) +{ + struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs); + model->start(msrs); +} + +static int nmi_start(void) +{ + on_each_cpu(nmi_cpu_start, NULL, 1); + return 0; +} + +static void nmi_cpu_stop(void *dummy) +{ + struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs); + model->stop(msrs); +} + +static void nmi_stop(void) +{ + on_each_cpu(nmi_cpu_stop, NULL, 1); +} + #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX static DEFINE_PER_CPU(int, switch_index); @@ -171,6 +194,53 @@ static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs) } } +static void nmi_cpu_switch(void *dummy) +{ + int cpu = smp_processor_id(); + int si = per_cpu(switch_index, cpu); + struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); + + nmi_cpu_stop(NULL); + nmi_cpu_save_mpx_registers(msrs); + + /* move to next set */ + si += model->num_counters; + if ((si > model->num_virt_counters) || (counter_config[si].count == 0)) + per_cpu(switch_index, cpu) = 0; + else + per_cpu(switch_index, cpu) = si; + + model->switch_ctrl(model, msrs); + nmi_cpu_restore_mpx_registers(msrs); + + nmi_cpu_start(NULL); +} + + +/* + * Quick check to see if multiplexing is necessary. + * The check should be sufficient since counters are used + * in ordre. + */ +static int nmi_multiplex_on(void) +{ + return counter_config[model->num_counters].count ? 0 : -EINVAL; +} + +static int nmi_switch_event(void) +{ + if (!model->switch_ctrl) + return -ENOSYS; /* not implemented */ + if (nmi_multiplex_on() < 0) + return -EINVAL; /* not necessary */ + + on_each_cpu(nmi_cpu_switch, NULL, 1); + + atomic_inc(&multiplex_counter); + + return 0; +} + #else inline int op_x86_phys_to_virt(int phys) { return phys; } @@ -325,29 +395,6 @@ static void nmi_shutdown(void) put_cpu_var(cpu_msrs); } -static void nmi_cpu_start(void *dummy) -{ - struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs); - model->start(msrs); -} - -static int nmi_start(void) -{ - on_each_cpu(nmi_cpu_start, NULL, 1); - return 0; -} - -static void nmi_cpu_stop(void *dummy) -{ - struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs); - model->stop(msrs); -} - -static void nmi_stop(void) -{ - on_each_cpu(nmi_cpu_stop, NULL, 1); -} - static int nmi_create_files(struct super_block *sb, struct dentry *root) { unsigned int i; @@ -379,57 +426,6 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root) return 0; } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -static void nmi_cpu_switch(void *dummy) -{ - int cpu = smp_processor_id(); - int si = per_cpu(switch_index, cpu); - struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); - - nmi_cpu_stop(NULL); - nmi_cpu_save_mpx_registers(msrs); - - /* move to next set */ - si += model->num_counters; - if ((si > model->num_virt_counters) || (counter_config[si].count == 0)) - per_cpu(switch_index, cpu) = 0; - else - per_cpu(switch_index, cpu) = si; - - model->switch_ctrl(model, msrs); - nmi_cpu_restore_mpx_registers(msrs); - - nmi_cpu_start(NULL); -} - - -/* - * Quick check to see if multiplexing is necessary. - * The check should be sufficient since counters are used - * in ordre. - */ -static int nmi_multiplex_on(void) -{ - return counter_config[model->num_counters].count ? 0 : -EINVAL; -} - -static int nmi_switch_event(void) -{ - if (!model->switch_ctrl) - return -ENOSYS; /* not implemented */ - if (nmi_multiplex_on() < 0) - return -EINVAL; /* not necessary */ - - on_each_cpu(nmi_cpu_switch, NULL, 1); - - atomic_inc(&multiplex_counter); - - return 0; -} - -#endif - #ifdef CONFIG_SMP static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, void *data) -- cgit v1.2.3-18-g5258 From 259a83a8abdb9d2664819ec80ad12ebaeb251e32 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 15:12:35 +0200 Subject: x86/oprofile: Remove const qualifier from struct op_x86_model_spec This patch removes the const qualifier from struct op_x86_model_spec to make model parameters changable. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 4 ++-- arch/x86/oprofile/op_model_amd.c | 2 +- arch/x86/oprofile/op_model_p4.c | 4 ++-- arch/x86/oprofile/op_model_ppro.c | 2 +- arch/x86/oprofile/op_x86_model.h | 8 ++++---- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 998c7dca31e..826f391b422 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -27,7 +27,7 @@ #include "op_counter.h" #include "op_x86_model.h" -static struct op_x86_model_spec const *model; +static struct op_x86_model_spec *model; static DEFINE_PER_CPU(struct op_msrs, cpu_msrs); static DEFINE_PER_CPU(unsigned long, saved_lvtpc); @@ -542,7 +542,7 @@ module_param_call(cpu_type, force_cpu_type, NULL, NULL, 0); static int __init ppro_init(char **cpu_type) { __u8 cpu_model = boot_cpu_data.x86_model; - struct op_x86_model_spec const *spec = &op_ppro_spec; /* default */ + struct op_x86_model_spec *spec = &op_ppro_spec; /* default */ if (force_arch_perfmon && cpu_has_arch_perfmon) return 0; diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 644980f0392..39604b429d6 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -526,7 +526,7 @@ static void op_amd_exit(void) {} #endif /* CONFIG_OPROFILE_IBS */ -struct op_x86_model_spec const op_amd_spec = { +struct op_x86_model_spec op_amd_spec = { .num_counters = NUM_COUNTERS, .num_controls = NUM_CONTROLS, .num_virt_counters = NUM_VIRT_COUNTERS, diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 65b9237cde8..40df028d0d9 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -695,7 +695,7 @@ static void p4_shutdown(struct op_msrs const * const msrs) #ifdef CONFIG_SMP -struct op_x86_model_spec const op_p4_ht2_spec = { +struct op_x86_model_spec op_p4_ht2_spec = { .num_counters = NUM_COUNTERS_HT2, .num_controls = NUM_CONTROLS_HT2, .num_virt_counters = NUM_COUNTERS_HT2, @@ -709,7 +709,7 @@ struct op_x86_model_spec const op_p4_ht2_spec = { }; #endif -struct op_x86_model_spec const op_p4_spec = { +struct op_x86_model_spec op_p4_spec = { .num_counters = NUM_COUNTERS_NON_HT, .num_controls = NUM_CONTROLS_NON_HT, .num_virt_counters = NUM_COUNTERS_NON_HT, diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 098cbca5c0b..659f3b6f86f 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -203,7 +203,7 @@ static void ppro_shutdown(struct op_msrs const * const msrs) } -struct op_x86_model_spec const op_ppro_spec = { +struct op_x86_model_spec op_ppro_spec = { .num_counters = 2, .num_controls = 2, .num_virt_counters = 2, diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index e874dc3565a..0c886fa0369 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -62,10 +62,10 @@ extern u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, struct op_counter_config *counter_config); extern int op_x86_phys_to_virt(int phys); -extern struct op_x86_model_spec const op_ppro_spec; -extern struct op_x86_model_spec const op_p4_spec; -extern struct op_x86_model_spec const op_p4_ht2_spec; -extern struct op_x86_model_spec const op_amd_spec; +extern struct op_x86_model_spec op_ppro_spec; +extern struct op_x86_model_spec op_p4_spec; +extern struct op_x86_model_spec op_p4_ht2_spec; +extern struct op_x86_model_spec op_amd_spec; extern struct op_x86_model_spec op_arch_perfmon_spec; #endif /* OP_X86_MODEL_H */ -- cgit v1.2.3-18-g5258 From 2904a527575344a804fdd82b1f8d09a8731d8d49 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 12:33:41 +0200 Subject: x86/oprofile: Remove unused num_virt_controls from struct op_x86_model_spec The member num_virt_controls of struct op_x86_model_spec is not used. This patch removes it. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 1 - arch/x86/oprofile/op_model_p4.c | 2 -- arch/x86/oprofile/op_model_ppro.c | 1 - arch/x86/oprofile/op_x86_model.h | 1 - 4 files changed, 5 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 39604b429d6..dce69b5979e 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -530,7 +530,6 @@ struct op_x86_model_spec op_amd_spec = { .num_counters = NUM_COUNTERS, .num_controls = NUM_CONTROLS, .num_virt_counters = NUM_VIRT_COUNTERS, - .num_virt_controls = NUM_VIRT_CONTROLS, .reserved = MSR_AMD_EVENTSEL_RESERVED, .event_mask = OP_EVENT_MASK, .init = op_amd_init, diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 40df028d0d9..0a4f2deb9e8 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -699,7 +699,6 @@ struct op_x86_model_spec op_p4_ht2_spec = { .num_counters = NUM_COUNTERS_HT2, .num_controls = NUM_CONTROLS_HT2, .num_virt_counters = NUM_COUNTERS_HT2, - .num_virt_controls = NUM_CONTROLS_HT2, .fill_in_addresses = &p4_fill_in_addresses, .setup_ctrs = &p4_setup_ctrs, .check_ctrs = &p4_check_ctrs, @@ -713,7 +712,6 @@ struct op_x86_model_spec op_p4_spec = { .num_counters = NUM_COUNTERS_NON_HT, .num_controls = NUM_CONTROLS_NON_HT, .num_virt_counters = NUM_COUNTERS_NON_HT, - .num_virt_controls = NUM_CONTROLS_NON_HT, .fill_in_addresses = &p4_fill_in_addresses, .setup_ctrs = &p4_setup_ctrs, .check_ctrs = &p4_check_ctrs, diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 659f3b6f86f..753a02ab215 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -207,7 +207,6 @@ struct op_x86_model_spec op_ppro_spec = { .num_counters = 2, .num_controls = 2, .num_virt_counters = 2, - .num_virt_controls = 2, .reserved = MSR_PPRO_EVENTSEL_RESERVED, .fill_in_addresses = &ppro_fill_in_addresses, .setup_ctrs = &ppro_setup_ctrs, diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 0c886fa0369..4e2e7c2c519 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -37,7 +37,6 @@ struct op_x86_model_spec { unsigned int num_counters; unsigned int num_controls; unsigned int num_virt_counters; - unsigned int num_virt_controls; u64 reserved; u16 event_mask; int (*init)(struct oprofile_operations *ops); -- cgit v1.2.3-18-g5258 From 52471c67ee2fa5ed6f700ef57bf27833c63b2192 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 6 Jul 2009 14:43:55 +0200 Subject: x86/oprofile: Modify initialization of num_virt_counters Models that do not yet support counter multiplexing have to setup num_virt_counters. This patch implements the setup from num_counters if num_virt_counters is not set. Thus, num_virt_counters must be setup only for multiplexing support. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 3 +++ arch/x86/oprofile/op_model_p4.c | 2 -- arch/x86/oprofile/op_model_ppro.c | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 826f391b422..82ee29517f1 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -674,6 +674,9 @@ int __init op_nmi_init(struct oprofile_operations *ops) if (ret) return ret; + if (!model->num_virt_counters) + model->num_virt_counters = model->num_counters; + init_sysfs(); using_nmi = 1; printk(KERN_INFO "oprofile: using NMI interrupt.\n"); diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 0a4f2deb9e8..ac6b354becd 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -698,7 +698,6 @@ static void p4_shutdown(struct op_msrs const * const msrs) struct op_x86_model_spec op_p4_ht2_spec = { .num_counters = NUM_COUNTERS_HT2, .num_controls = NUM_CONTROLS_HT2, - .num_virt_counters = NUM_COUNTERS_HT2, .fill_in_addresses = &p4_fill_in_addresses, .setup_ctrs = &p4_setup_ctrs, .check_ctrs = &p4_check_ctrs, @@ -711,7 +710,6 @@ struct op_x86_model_spec op_p4_ht2_spec = { struct op_x86_model_spec op_p4_spec = { .num_counters = NUM_COUNTERS_NON_HT, .num_controls = NUM_CONTROLS_NON_HT, - .num_virt_counters = NUM_COUNTERS_NON_HT, .fill_in_addresses = &p4_fill_in_addresses, .setup_ctrs = &p4_setup_ctrs, .check_ctrs = &p4_check_ctrs, diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 753a02ab215..4899215999d 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -206,7 +206,6 @@ static void ppro_shutdown(struct op_msrs const * const msrs) struct op_x86_model_spec op_ppro_spec = { .num_counters = 2, .num_controls = 2, - .num_virt_counters = 2, .reserved = MSR_PPRO_EVENTSEL_RESERVED, .fill_in_addresses = &ppro_fill_in_addresses, .setup_ctrs = &ppro_setup_ctrs, -- cgit v1.2.3-18-g5258 From 39e97f40c3a5e71de0532368deaa683e09b74ba2 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 15:11:45 +0200 Subject: x86/oprofile: Add function has_mux() to check multiplexing support The check is used to prevent running multiplexing code for models not supporting multiplexing. Before, the code was running but without effect. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 82ee29517f1..dca7240aeb2 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -124,6 +124,11 @@ static void nmi_stop(void) static DEFINE_PER_CPU(int, switch_index); +static inline int has_mux(void) +{ + return !!model->switch_ctrl; +} + inline int op_x86_phys_to_virt(int phys) { return __get_cpu_var(switch_index) + phys; @@ -132,6 +137,10 @@ inline int op_x86_phys_to_virt(int phys) static void nmi_shutdown_mux(void) { int i; + + if (!has_mux()) + return; + for_each_possible_cpu(i) { kfree(per_cpu(cpu_msrs, i).multiplex); per_cpu(cpu_msrs, i).multiplex = NULL; @@ -144,12 +153,17 @@ static int nmi_setup_mux(void) size_t multiplex_size = sizeof(struct op_msr) * model->num_virt_counters; int i; + + if (!has_mux()) + return 1; + for_each_possible_cpu(i) { per_cpu(cpu_msrs, i).multiplex = kmalloc(multiplex_size, GFP_KERNEL); if (!per_cpu(cpu_msrs, i).multiplex) return 0; } + return 1; } @@ -158,6 +172,9 @@ static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) int i; struct op_msr *multiplex = msrs->multiplex; + if (!has_mux()) + return; + for (i = 0; i < model->num_virt_counters; ++i) { if (counter_config[i].enabled) { multiplex[i].saved = -(u64)counter_config[i].count; @@ -229,7 +246,7 @@ static int nmi_multiplex_on(void) static int nmi_switch_event(void) { - if (!model->switch_ctrl) + if (!has_mux()) return -ENOSYS; /* not implemented */ if (nmi_multiplex_on() < 0) return -EINVAL; /* not necessary */ -- cgit v1.2.3-18-g5258 From 5280514471c2803776701c43c027038decac1103 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 16:02:44 +0200 Subject: x86/oprofile: Enable multiplexing only if the model supports it This patch checks if the model supports multiplexing. Only then multiplexing will be enabled. The code is added to the common x86 initialization. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index dca7240aeb2..f0fb44725d8 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -258,6 +258,12 @@ static int nmi_switch_event(void) return 0; } +static inline void mux_init(struct oprofile_operations *ops) +{ + if (has_mux()) + ops->switch_events = nmi_switch_event; +} + #else inline int op_x86_phys_to_virt(int phys) { return phys; } @@ -265,6 +271,7 @@ static inline void nmi_shutdown_mux(void) { } static inline int nmi_setup_mux(void) { return 1; } static inline void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { } +static inline void mux_init(struct oprofile_operations *ops) { } #endif @@ -682,9 +689,6 @@ int __init op_nmi_init(struct oprofile_operations *ops) ops->start = nmi_start; ops->stop = nmi_stop; ops->cpu_type = cpu_type; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - ops->switch_events = nmi_switch_event; -#endif if (model->init) ret = model->init(ops); @@ -694,6 +698,8 @@ int __init op_nmi_init(struct oprofile_operations *ops) if (!model->num_virt_counters) model->num_virt_counters = model->num_counters; + mux_init(ops); + init_sysfs(); using_nmi = 1; printk(KERN_INFO "oprofile: using NMI interrupt.\n"); -- cgit v1.2.3-18-g5258 From 4d015f79e972cea1761cfee8872b1c0992ccd8b2 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 21:42:51 +0200 Subject: x86/oprofile: Implement mux_clone() To setup a counter for all cpus, its structure is cloned from cpu 0. This patch implements mux_clone() to do this part for multiplexing data. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index f0fb44725d8..da6d2ab31c6 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -264,6 +264,16 @@ static inline void mux_init(struct oprofile_operations *ops) ops->switch_events = nmi_switch_event; } +static void mux_clone(int cpu) +{ + if (!has_mux()) + return; + + memcpy(per_cpu(cpu_msrs, cpu).multiplex, + per_cpu(cpu_msrs, 0).multiplex, + sizeof(struct op_msr) * model->num_virt_counters); +} + #else inline int op_x86_phys_to_virt(int phys) { return phys; } @@ -272,6 +282,7 @@ static inline int nmi_setup_mux(void) { return 1; } static inline void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { } static inline void mux_init(struct oprofile_operations *ops) { } +static void mux_clone(int cpu) { } #endif @@ -350,20 +361,18 @@ static int nmi_setup(void) /* Assume saved/restored counters are the same on all CPUs */ model->fill_in_addresses(&per_cpu(cpu_msrs, 0)); for_each_possible_cpu(cpu) { - if (cpu != 0) { - memcpy(per_cpu(cpu_msrs, cpu).counters, - per_cpu(cpu_msrs, 0).counters, - sizeof(struct op_msr) * model->num_counters); - - memcpy(per_cpu(cpu_msrs, cpu).controls, - per_cpu(cpu_msrs, 0).controls, - sizeof(struct op_msr) * model->num_controls); -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - memcpy(per_cpu(cpu_msrs, cpu).multiplex, - per_cpu(cpu_msrs, 0).multiplex, - sizeof(struct op_msr) * model->num_virt_counters); -#endif - } + if (!cpu) + continue; + + memcpy(per_cpu(cpu_msrs, cpu).counters, + per_cpu(cpu_msrs, 0).counters, + sizeof(struct op_msr) * model->num_counters); + + memcpy(per_cpu(cpu_msrs, cpu).controls, + per_cpu(cpu_msrs, 0).controls, + sizeof(struct op_msr) * model->num_controls); + + mux_clone(cpu); } on_each_cpu(nmi_cpu_setup, NULL, 1); nmi_enabled = 1; -- cgit v1.2.3-18-g5258 From 1b294f5960cd89e49eeb3e797860c552b03f2272 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 14:56:25 +0200 Subject: oprofile: Adding switch counter to oprofile statistic variables This patch moves the multiplexing switch counter from x86 code to common oprofile statistic variables. Now the value will be available and usable for all architectures. The initialization and incrementation also moved to common code. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 7 ------- drivers/oprofile/oprof.c | 7 +++++-- drivers/oprofile/oprofile_stats.c | 9 ++------- drivers/oprofile/oprofile_stats.h | 1 + 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index da6d2ab31c6..7b3362f9abd 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -34,11 +34,6 @@ static DEFINE_PER_CPU(unsigned long, saved_lvtpc); /* 0 == registered but off, 1 == registered and on */ static int nmi_enabled = 0; - -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX -extern atomic_t multiplex_counter; -#endif - struct op_counter_config counter_config[OP_MAX_COUNTER]; /* common functions */ @@ -253,8 +248,6 @@ static int nmi_switch_event(void) on_each_cpu(nmi_cpu_switch, NULL, 1); - atomic_inc(&multiplex_counter); - return 0; } diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index a48294a8ebe..dc8a0428260 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -107,8 +107,11 @@ static void stop_switch_worker(void) static void switch_worker(struct work_struct *work) { - if (!oprofile_ops.switch_events()) - start_switch_worker(); + if (oprofile_ops.switch_events()) + return; + + atomic_inc(&oprofile_stats.multiplex_counter); + start_switch_worker(); } /* User inputs in ms, converts to jiffies */ diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index 77a57a6792f..61689e814d4 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -16,9 +16,6 @@ #include "cpu_buffer.h" struct oprofile_stat_struct oprofile_stats; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX -atomic_t multiplex_counter; -#endif void oprofile_reset_stats(void) { @@ -37,9 +34,7 @@ void oprofile_reset_stats(void) atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); atomic_set(&oprofile_stats.event_lost_overflow, 0); atomic_set(&oprofile_stats.bt_lost_no_mapping, 0); -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - atomic_set(&multiplex_counter, 0); -#endif + atomic_set(&oprofile_stats.multiplex_counter, 0); } @@ -84,6 +79,6 @@ void oprofile_create_stats_files(struct super_block *sb, struct dentry *root) &oprofile_stats.bt_lost_no_mapping); #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX oprofilefs_create_ro_atomic(sb, dir, "multiplex_counter", - &multiplex_counter); + &oprofile_stats.multiplex_counter); #endif } diff --git a/drivers/oprofile/oprofile_stats.h b/drivers/oprofile/oprofile_stats.h index 3da0d08dc1f..0b54e46c3c1 100644 --- a/drivers/oprofile/oprofile_stats.h +++ b/drivers/oprofile/oprofile_stats.h @@ -17,6 +17,7 @@ struct oprofile_stat_struct { atomic_t sample_lost_no_mapping; atomic_t bt_lost_no_mapping; atomic_t event_lost_overflow; + atomic_t multiplex_counter; }; extern struct oprofile_stat_struct oprofile_stats; -- cgit v1.2.3-18-g5258 From 61d149d5248ad7428801cdede0f5fcc2b90cd61c Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 10 Jul 2009 15:47:17 +0200 Subject: x86/oprofile: Implement op_x86_virt_to_phys() This patch implements a common x86 function to convert virtual counter numbers to physical. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 6 ++++++ arch/x86/oprofile/op_model_amd.c | 2 +- arch/x86/oprofile/op_x86_model.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 7b3362f9abd..5856e61cb09 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -129,6 +129,11 @@ inline int op_x86_phys_to_virt(int phys) return __get_cpu_var(switch_index) + phys; } +inline int op_x86_virt_to_phys(int virt) +{ + return virt % model->num_counters; +} + static void nmi_shutdown_mux(void) { int i; @@ -270,6 +275,7 @@ static void mux_clone(int cpu) #else inline int op_x86_phys_to_virt(int phys) { return phys; } +inline int op_x86_virt_to_phys(int virt) { return virt; } static inline void nmi_shutdown_mux(void) { } static inline int nmi_setup_mux(void) { return 1; } static inline void diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index dce69b5979e..1ea19829d98 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -81,7 +81,7 @@ static void op_mux_fill_in_addresses(struct op_msrs * const msrs) int i; for (i = 0; i < NUM_VIRT_COUNTERS; i++) { - int hw_counter = i % NUM_COUNTERS; + int hw_counter = op_x86_virt_to_phys(i); if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i)) msrs->multiplex[i].addr = MSR_K7_PERFCTR0 + hw_counter; else diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 4e2e7c2c519..b83776180c7 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -60,6 +60,7 @@ struct op_counter_config; extern u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, struct op_counter_config *counter_config); extern int op_x86_phys_to_virt(int phys); +extern int op_x86_virt_to_phys(int virt); extern struct op_x86_model_spec op_ppro_spec; extern struct op_x86_model_spec op_p4_spec; -- cgit v1.2.3-18-g5258 From 11be1a7b54283021777f409aa983ce125945e67c Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 10 Jul 2009 18:15:21 +0200 Subject: x86/oprofile: Add counter reservation check for virtual counters This patch adds a check for the availability of a counter. A virtual counter is used only if its physical counter is not reserved. Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 5856e61cb09..cb88b1a0bd5 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -435,15 +435,13 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root) struct dentry *dir; char buf[4]; -#ifndef CONFIG_OPROFILE_EVENT_MULTIPLEX /* quick little hack to _not_ expose a counter if it is not * available for use. This should protect userspace app. * NOTE: assumes 1:1 mapping here (that counters are organized * sequentially in their struct assignment). */ - if (unlikely(!avail_to_resrv_perfctr_nmi_bit(i))) + if (!avail_to_resrv_perfctr_nmi_bit(op_x86_virt_to_phys(i))) continue; -#endif /* CONFIG_OPROFILE_EVENT_MULTIPLEX */ snprintf(buf, sizeof(buf), "%d", i); dir = oprofilefs_mkdir(sb, root, buf); -- cgit v1.2.3-18-g5258 From c550091edd6fac2ed9dac1b30d986b6c58b216fa Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 16 Jul 2009 13:11:16 +0200 Subject: x86/oprofile: Small coding style fixes Some small coding style fixes. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 1ea19829d98..827beecb67a 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -144,11 +144,10 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, /* setup reset_value */ for (i = 0; i < NUM_VIRT_COUNTERS; ++i) { - if (counter_config[i].enabled) { + if (counter_config[i].enabled) reset_value[i] = counter_config[i].count; - } else { + else reset_value[i] = 0; - } } /* clear all counters */ -- cgit v1.2.3-18-g5258 From 54a0bf3c2cad3fd118ea725f26a493aece6ea01d Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 4 Aug 2009 15:52:38 +0200 Subject: Revert "x86: oprofile/op_model_amd.c set return values for op_amd_handle_ibs()" This reverts commit 21e70878215f620fe99ea7d7c74bc641aeec932f. Instead Andrew's patch will be applied he posted at the same time. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 827beecb67a..37d19c768d5 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -195,7 +195,7 @@ op_amd_handle_ibs(struct pt_regs * const regs, struct op_entry entry; if (!has_ibs) - return 0; + return 1; if (ibs_config.fetch_enabled) { rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl); @@ -277,10 +277,7 @@ static void op_amd_stop_ibs(void) #else static inline int op_amd_handle_ibs(struct pt_regs * const regs, - struct op_msrs const * const msrs) -{ - return 0; -} + struct op_msrs const * const msrs) { } static inline void op_amd_start_ibs(void) { } static inline void op_amd_stop_ibs(void) { } -- cgit v1.2.3-18-g5258 From 4680e64a88c4ce2c4e736dade99233e3def13fa7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 23 Jun 2009 12:36:08 -0700 Subject: arch/x86/oprofile/op_model_amd.c: fix op_amd_handle_ibs() return type arch/x86/oprofile/op_model_amd.c: In function 'op_amd_handle_ibs': arch/x86/oprofile/op_model_amd.c:217: warning: no return statement in function returning non-void Fix this by making op_amd_handle_ibs() return void. Cc: Robert Richter Signed-off-by: Andrew Morton Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 37d19c768d5..39686c29f03 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -187,7 +187,7 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, #ifdef CONFIG_OPROFILE_IBS -static inline int +static inline void op_amd_handle_ibs(struct pt_regs * const regs, struct op_msrs const * const msrs) { @@ -195,7 +195,7 @@ op_amd_handle_ibs(struct pt_regs * const regs, struct op_entry entry; if (!has_ibs) - return 1; + return; if (ibs_config.fetch_enabled) { rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl); @@ -241,8 +241,6 @@ op_amd_handle_ibs(struct pt_regs * const regs, wrmsrl(MSR_AMD64_IBSOPCTL, ctl); } } - - return 1; } static inline void op_amd_start_ibs(void) @@ -276,7 +274,7 @@ static void op_amd_stop_ibs(void) #else -static inline int op_amd_handle_ibs(struct pt_regs * const regs, +static inline void op_amd_handle_ibs(struct pt_regs * const regs, struct op_msrs const * const msrs) { } static inline void op_amd_start_ibs(void) { } static inline void op_amd_stop_ibs(void) { } -- cgit v1.2.3-18-g5258