* [PATCH] Add more features to xenoprof
@ 2009-09-15 8:55 Yang, Xiaowei
0 siblings, 0 replies; only message in thread
From: Yang, Xiaowei @ 2009-09-15 8:55 UTC (permalink / raw)
To: xen-devel@lists.xensource.com
[-- Attachment #1: Type: text/plain, Size: 518 bytes --]
This patch set syncs xenoprof features with Linux upstream:
01_cpu_type.patch: add support for Core i7 and Atom.
02_arch_perfmon.patch: add architectural perfmon support. One benefit is that
more perfmon counters can be used on Nehalem.
03_force_arch_perfmon: force use of architectural perfmon instead of the CPU
specific event set, which may be not supported by oprofile user space tool yet.
Signed-off-by: Yang Zhang <yang.zhang@intel.com>
Signed-off-by: Yang Xiaowei <xiaowei.yang@intel.com>
Thanks,
xiaowei
[-- Attachment #2: 01_cpu_type.patch --]
[-- Type: text/x-patch, Size: 772 bytes --]
diff -r e277fb77063c xen/arch/x86/oprofile/nmi_int.c
--- a/xen/arch/x86/oprofile/nmi_int.c Sun Aug 23 16:51:46 2009 +0800
+++ b/xen/arch/x86/oprofile/nmi_int.c Sun Aug 23 16:56:08 2009 +0800
@@ -357,22 +357,28 @@
*cpu_type = "i386/pii";
break;
case 6 ... 8:
+ case 10 ... 11:
*cpu_type = "i386/piii";
break;
case 9:
+ case 13:
*cpu_type = "i386/p6_mobile";
- break;
- case 10 ... 13:
- *cpu_type = "i386/p6";
break;
case 14:
*cpu_type = "i386/core";
break;
case 15:
case 23:
- case 26:
case 29:
*cpu_type = "i386/core_2";
+ ppro_has_global_ctrl = 1;
+ break;
+ case 26:
+ *cpu_type = "i386/core_i7";
+ ppro_has_global_ctrl = 1;
+ break;
+ case 28:
+ *cpu_type = "i386/atom";
ppro_has_global_ctrl = 1;
break;
default:
[-- Attachment #3: 02_arch_perfmon.patch --]
[-- Type: text/x-patch, Size: 12617 bytes --]
diff -r 629937ccc0e6 xen/arch/x86/cpu/intel.c
--- a/xen/arch/x86/cpu/intel.c Sun Aug 23 16:56:09 2009 +0800
+++ b/xen/arch/x86/cpu/intel.c Fri Sep 11 14:06:27 2009 +0800
@@ -148,6 +148,12 @@
select_idle_routine(c);
l2 = init_intel_cacheinfo(c);
+ if (c->cpuid_level > 9) {
+ unsigned eax = cpuid_eax(10);
+ /* Check for version and the number of counters */
+ if ((eax & 0xff) && (((eax>>8) & 0xff) > 1))
+ set_bit(X86_FEATURE_ARCH_PERFMON, c->x86_capability);
+ }
/* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until model 3 mask 3 */
if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633)
diff -r 629937ccc0e6 xen/arch/x86/oprofile/nmi_int.c
--- a/xen/arch/x86/oprofile/nmi_int.c Sun Aug 23 16:56:09 2009 +0800
+++ b/xen/arch/x86/oprofile/nmi_int.c Fri Sep 11 14:06:27 2009 +0800
@@ -374,18 +374,15 @@
ppro_has_global_ctrl = 1;
break;
case 26:
+ arch_perfmon_setup_counters();
*cpu_type = "i386/core_i7";
ppro_has_global_ctrl = 1;
break;
case 28:
*cpu_type = "i386/atom";
- ppro_has_global_ctrl = 1;
break;
default:
/* Unknown */
- printk("xenoprof: Initialization failed. "
- "Intel processor model %d for P6 class family is not "
- "supported\n", cpu_model);
return 0;
}
@@ -393,10 +390,21 @@
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;
+}
+
static int __init nmi_init(void)
{
__u8 vendor = current_cpu_data.x86_vendor;
__u8 family = current_cpu_data.x86;
+ __u8 _model = current_cpu_data.x86_model;
if (!cpu_has_apic) {
printk("xenoprof: Initialization failed. No APIC\n");
@@ -438,21 +446,22 @@
switch (family) {
/* Pentium IV */
case 0xf:
- if (!p4_init(&cpu_type))
- return -ENODEV;
+ p4_init(&cpu_type);
break;
/* A P6-class processor */
case 6:
- if (!ppro_init(&cpu_type))
- return -ENODEV;
+ ppro_init(&cpu_type);
break;
default:
+ break;
+ }
+ if (!cpu_type && !arch_perfmon_init(&cpu_type)) {
printk("xenoprof: Initialization failed. "
- "Intel processor family %d is not "
- "supported\n", family);
- return -ENODEV;
+ "Intel processor family %d model %d"
+ "is not supported\n", family, _model);
+ return -ENODEV;
}
break;
diff -r 629937ccc0e6 xen/arch/x86/oprofile/op_model_ppro.c
--- a/xen/arch/x86/oprofile/op_model_ppro.c Sun Aug 23 16:56:09 2009 +0800
+++ b/xen/arch/x86/oprofile/op_model_ppro.c Fri Sep 11 14:06:27 2009 +0800
@@ -24,12 +24,24 @@
#include "op_x86_model.h"
#include "op_counter.h"
-#define NUM_COUNTERS 2
-#define NUM_CONTROLS 2
+/*
+ * Intel "Architectural Performance Monitoring" CPUID
+ * detection/enumeration details:
+ */
+union cpuid10_eax {
+ struct {
+ unsigned int version_id:8;
+ unsigned int num_counters:8;
+ unsigned int bit_width:8;
+ unsigned int mask_length:8;
+ } split;
+ unsigned int full;
+};
-#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, -(u32)(l), -1);} while (0)
-#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
+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)
@@ -43,17 +55,18 @@
#define CTRL_SET_EVENT(val, e) (val |= e)
#define IS_ACTIVE(val) (val & (1 << 22) )
#define IS_ENABLE(val) (val & (1 << 20) )
-static unsigned long reset_value[NUM_COUNTERS];
+static unsigned long reset_value[OP_MAX_COUNTER];
int ppro_has_global_ctrl = 0;
extern int is_passive(struct domain *d);
static void ppro_fill_in_addresses(struct op_msrs * const msrs)
{
- msrs->counters[0].addr = MSR_P6_PERFCTR0;
- msrs->counters[1].addr = MSR_P6_PERFCTR1;
-
- msrs->controls[0].addr = MSR_P6_EVNTSEL0;
- msrs->controls[1].addr = MSR_P6_EVNTSEL1;
+ int i;
+
+ for (i = 0; i < num_counters; i++)
+ msrs->counters[i].addr = MSR_P6_PERFCTR0 + i;
+ for (i = 0; i < num_counters; i++)
+ msrs->controls[i].addr = MSR_P6_EVNTSEL0 + i;
}
@@ -61,25 +74,41 @@
{
unsigned int low, high;
int i;
+
+ if (cpu_has_arch_perfmon) {
+ union cpuid10_eax eax;
+ eax.full = cpuid_eax(0xa);
+
+ /*
+ * For Core2 (family 6, model 15), don't reset the
+ * counter width:
+ */
+ if (!(eax.split.version_id == 0 &&
+ current_cpu_data.x86 == 6 &&
+ current_cpu_data.x86_model == 15)) {
+
+ if (counter_width < eax.split.bit_width)
+ counter_width = eax.split.bit_width;
+ }
+ }
/* clear all counters */
- for (i = 0 ; i < NUM_CONTROLS; ++i) {
+ for (i = 0 ; i < num_counters; ++i) {
CTRL_READ(low, high, msrs, i);
CTRL_CLEAR(low);
CTRL_WRITE(low, high, msrs, i);
}
/* avoid a false detection of ctr overflows in NMI handler */
- for (i = 0; i < NUM_COUNTERS; ++i) {
- CTR_WRITE(1, msrs, i);
- }
+ for (i = 0; i < num_counters; ++i)
+ wrmsrl(msrs->counters[i].addr, -1LL);
/* enable active counters */
- for (i = 0; i < NUM_COUNTERS; ++i) {
+ for (i = 0; i < num_counters; ++i) {
if (counter_config[i].enabled) {
reset_value[i] = counter_config[i].count;
- CTR_WRITE(counter_config[i].count, msrs, i);
+ wrmsrl(msrs->counters[i].addr, -reset_value[i]);
CTRL_READ(low, high, msrs, i);
CTRL_CLEAR(low);
@@ -89,6 +118,8 @@
CTRL_SET_UM(low, counter_config[i].unit_mask);
CTRL_SET_EVENT(low, counter_config[i].event);
CTRL_WRITE(low, high, msrs, i);
+ } else {
+ reset_value[i] = 0;
}
}
}
@@ -102,26 +133,26 @@
struct op_msrs const * const msrs,
struct cpu_user_regs * const regs)
{
- unsigned int low, high;
+ u64 val;
int i;
int ovf = 0;
unsigned long eip = regs->eip;
int mode = xenoprofile_get_mode(current, regs);
struct arch_msr_pair *msrs_content = vcpu_vpmu(current)->context;
- for (i = 0 ; i < NUM_COUNTERS; ++i) {
+ for (i = 0 ; i < num_counters; ++i) {
if (!reset_value[i])
continue;
- CTR_READ(low, high, msrs, i);
- if (CTR_OVERFLOWED(low)) {
+ rdmsrl(msrs->counters[i].addr, val);
+ if (CTR_OVERFLOWED(val)) {
xenoprof_log_event(current, regs, eip, mode, i);
- CTR_WRITE(reset_value[i], msrs, i);
+ wrmsrl(msrs->counters[i].addr, -reset_value[i]);
if ( is_passive(current->domain) && (mode != 2) &&
(vcpu_vpmu(current)->flags & PASSIVE_DOMAIN_ALLOCATED) )
{
if ( IS_ACTIVE(msrs_content[i].control) )
{
- msrs_content[i].counter = (low | (u64)high << 32);
+ msrs_content[i].counter = val;
if ( IS_ENABLE(msrs_content[i].control) )
ovf = 2;
}
@@ -144,7 +175,7 @@
unsigned int low,high;
int i;
- for (i = 0; i < NUM_COUNTERS; ++i) {
+ for (i = 0; i < num_counters; ++i) {
if (reset_value[i]) {
CTRL_READ(low, high, msrs, i);
CTRL_SET_ACTIVE(low);
@@ -155,7 +186,7 @@
* However, this may not hold true when xenoprof starts to run.
*/
if ( ppro_has_global_ctrl )
- wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, (1<<NUM_COUNTERS) - 1);
+ wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, (1<<num_counters) - 1);
}
@@ -164,7 +195,7 @@
unsigned int low,high;
int i;
- for (i = 0; i < NUM_COUNTERS; ++i) {
+ for (i = 0; i < num_counters; ++i) {
if (!reset_value[i])
continue;
CTRL_READ(low, high, msrs, i);
@@ -178,14 +209,14 @@
static int ppro_is_arch_pmu_msr(u64 msr_index, int *type, int *index)
{
if ( (msr_index >= MSR_IA32_PERFCTR0) &&
- (msr_index < (MSR_IA32_PERFCTR0 + NUM_COUNTERS)) )
+ (msr_index < (MSR_IA32_PERFCTR0 + num_counters)) )
{
*type = MSR_TYPE_ARCH_COUNTER;
*index = msr_index - MSR_IA32_PERFCTR0;
return 1;
}
if ( (msr_index >= MSR_P6_EVNTSEL0) &&
- (msr_index < (MSR_P6_EVNTSEL0 + NUM_CONTROLS)) )
+ (msr_index < (MSR_P6_EVNTSEL0 + num_counters)) )
{
*type = MSR_TYPE_ARCH_CTRL;
*index = msr_index - MSR_P6_EVNTSEL0;
@@ -199,11 +230,11 @@
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
struct arch_msr_pair *msr_content;
-
- msr_content = xmalloc_bytes( sizeof(struct arch_msr_pair) * NUM_COUNTERS );
+
+ msr_content = xmalloc_bytes( sizeof(struct arch_msr_pair) * num_counters );
if ( !msr_content )
goto out;
- memset(msr_content, 0, sizeof(struct arch_msr_pair) * NUM_COUNTERS);
+ memset(msr_content, 0, sizeof(struct arch_msr_pair) * num_counters);
vpmu->context = (void *)msr_content;
vpmu->flags = 0;
vpmu->flags |= PASSIVE_DOMAIN_ALLOCATED;
@@ -254,9 +285,39 @@
}
}
-struct op_x86_model_spec const op_ppro_spec = {
- .num_counters = NUM_COUNTERS,
- .num_controls = NUM_CONTROLS,
+/*
+ * Architectural performance monitoring.
+ *
+ * Newer Intel CPUs (Core1+) have support for architectural
+ * events described in CPUID 0xA. See the IA32 SDM Vol3b.18 for details.
+ * The advantage of this is that it can be done without knowing about
+ * the specific CPU.
+ */
+void arch_perfmon_setup_counters(void)
+{
+ union cpuid10_eax eax;
+
+ eax.full = cpuid_eax(0xa);
+
+ /* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */
+ if (eax.split.version_id == 0 && current_cpu_data.x86 == 6 &&
+ current_cpu_data.x86_model == 15) {
+ eax.split.version_id = 2;
+ eax.split.num_counters = 2;
+ eax.split.bit_width = 40;
+ }
+
+ num_counters = min_t(u8, eax.split.num_counters, OP_MAX_COUNTER);
+
+ 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_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,
@@ -268,3 +329,17 @@
.load_msr = &ppro_load_msr,
.save_msr = &ppro_save_msr
};
+
+struct op_x86_model_spec op_arch_perfmon_spec = {
+ /* num_counters/num_controls filled in at runtime */
+ .fill_in_addresses = &ppro_fill_in_addresses,
+ .setup_ctrs = &ppro_setup_ctrs,
+ .check_ctrs = &ppro_check_ctrs,
+ .start = &ppro_start,
+ .stop = &ppro_stop,
+ .is_arch_pmu_msr = &ppro_is_arch_pmu_msr,
+ .allocated_msr = &ppro_allocate_msr,
+ .free_msr = &ppro_free_msr,
+ .load_msr = &ppro_load_msr,
+ .save_msr = &ppro_save_msr
+};
diff -r 629937ccc0e6 xen/arch/x86/oprofile/op_x86_model.h
--- a/xen/arch/x86/oprofile/op_x86_model.h Sun Aug 23 16:56:09 2009 +0800
+++ b/xen/arch/x86/oprofile/op_x86_model.h Fri Sep 11 14:06:27 2009 +0800
@@ -32,8 +32,8 @@
* various x86 CPU model's perfctr support.
*/
struct op_x86_model_spec {
- unsigned int const num_counters;
- unsigned int const num_controls;
+ 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)(unsigned int const cpu,
@@ -48,9 +48,11 @@
void (*save_msr)(struct vcpu * const v, int type, int index, u64 msr_content);
};
-extern struct op_x86_model_spec const op_ppro_spec;
+extern struct op_x86_model_spec op_ppro_spec;
+extern struct op_x86_model_spec op_arch_perfmon_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_athlon_spec;
+void arch_perfmon_setup_counters(void);
#endif /* OP_X86_MODEL_H */
diff -r 629937ccc0e6 xen/include/asm-x86/cpufeature.h
--- a/xen/include/asm-x86/cpufeature.h Sun Aug 23 16:56:09 2009 +0800
+++ b/xen/include/asm-x86/cpufeature.h Fri Sep 11 14:06:27 2009 +0800
@@ -76,6 +76,7 @@
#define X86_FEATURE_CONSTANT_TSC (3*32+ 8) /* TSC ticks at a constant rate */
#define X86_FEATURE_NOSTOP_TSC (3*32+ 9) /* TSC does not stop in C states */
#define X86_FEATURE_ARAT (3*32+ 10) /* Always running APIC timer */
+#define X86_FEATURE_ARCH_PERFMON (3*32+11) /* Intel Architectural PerfMon */
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
#define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */
@@ -188,6 +189,8 @@
&& boot_cpu_has(X86_FEATURE_FFXSR))
#define cpu_has_x2apic boot_cpu_has(X86_FEATURE_X2APIC)
+#define cpu_has_arch_perfmon boot_cpu_has(X86_FEATURE_ARCH_PERFMON)
+
#endif /* __ASM_I386_CPUFEATURE_H */
/*
[-- Attachment #4: 03_force_arch_perfmon.patch --]
[-- Type: text/x-patch, Size: 803 bytes --]
diff -r 3557803e455d xen/arch/x86/oprofile/nmi_int.c
--- a/xen/arch/x86/oprofile/nmi_int.c Fri Sep 11 13:56:58 2009 +0800
+++ b/xen/arch/x86/oprofile/nmi_int.c Fri Sep 11 14:03:59 2009 +0800
@@ -344,10 +344,25 @@
}
+static int force_arch_perfmon;
+static int force_cpu_type(const char *str)
+{
+ if (!strcmp(str, "arch_perfmon")) {
+ force_arch_perfmon = 1;
+ printk(KERN_INFO "oprofile: forcing architectural perfmon\n");
+ }
+
+ return 0;
+}
+custom_param("cpu_type", force_cpu_type);
+
extern int ppro_has_global_ctrl;
static int __init ppro_init(char ** cpu_type)
{
__u8 cpu_model = current_cpu_data.x86_model;
+
+ if (force_arch_perfmon && cpu_has_arch_perfmon)
+ return 0;
switch (cpu_model) {
case 0 ... 2:
[-- Attachment #5: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2009-09-15 8:55 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-09-15 8:55 [PATCH] Add more features to xenoprof Yang, Xiaowei
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.