[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] xenoprof: support Intel's architectural perfmon registers.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1253005396 -3600 # Node ID 15f5cff84adf32d1d24245207fc6e9a72a4cae13 # Parent 65968459de751a49498b1ad23279e272a6dfd044 xenoprof: support Intel's architectural perfmon registers. One benefit is that more perfmon counters can be used on Nehalem. Signed-off-by: Yang Zhang <yang.zhang@xxxxxxxxx> Signed-off-by: Yang Xiaowei <xiaowei.yang@xxxxxxxxx> --- xen/arch/x86/cpu/intel.c | 6 + xen/arch/x86/oprofile/nmi_int.c | 31 ++++-- xen/arch/x86/oprofile/op_model_ppro.c | 157 +++++++++++++++++++++++++--------- xen/arch/x86/oprofile/op_x86_model.h | 8 + xen/include/asm-x86/cpufeature.h | 3 5 files changed, 150 insertions(+), 55 deletions(-) diff -r 65968459de75 -r 15f5cff84adf xen/arch/x86/cpu/intel.c --- a/xen/arch/x86/cpu/intel.c Tue Sep 15 10:02:15 2009 +0100 +++ b/xen/arch/x86/cpu/intel.c Tue Sep 15 10:03:16 2009 +0100 @@ -148,6 +148,12 @@ static void __devinit init_intel(struct 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 65968459de75 -r 15f5cff84adf xen/arch/x86/oprofile/nmi_int.c --- a/xen/arch/x86/oprofile/nmi_int.c Tue Sep 15 10:02:15 2009 +0100 +++ b/xen/arch/x86/oprofile/nmi_int.c Tue Sep 15 10:03:16 2009 +0100 @@ -374,22 +374,29 @@ static int __init ppro_init(char ** cpu_ 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; } model = &op_ppro_spec; + 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; } @@ -397,6 +404,7 @@ 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 @@ static int __init nmi_init(void) 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 65968459de75 -r 15f5cff84adf xen/arch/x86/oprofile/op_model_ppro.c --- a/xen/arch/x86/oprofile/op_model_ppro.c Tue Sep 15 10:02:15 2009 +0100 +++ b/xen/arch/x86/oprofile/op_model_ppro.c Tue Sep 15 10:03:16 2009 +0100 @@ -24,12 +24,24 @@ #include "op_x86_model.h" #include "op_counter.h" -#define NUM_COUNTERS 2 -#define NUM_CONTROLS 2 - -#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))) +/* + * 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; +}; + +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,43 +55,60 @@ #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; + 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; +} + + +static void ppro_setup_ctrs(struct op_msrs const * const msrs) +{ + unsigned int low, high; + int i; - msrs->controls[0].addr = MSR_P6_EVNTSEL0; - msrs->controls[1].addr = MSR_P6_EVNTSEL1; -} - - -static void ppro_setup_ctrs(struct op_msrs const * const msrs) -{ - 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 @@ static void ppro_setup_ctrs(struct op_ms 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 @@ static int ppro_check_ctrs(unsigned int 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 @@ static void ppro_start(struct op_msrs co 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 @@ static void ppro_start(struct op_msrs co * 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 @@ static void ppro_stop(struct op_msrs con 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_ 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 @@ static int ppro_allocate_msr(struct vcpu { 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 @@ static void ppro_save_msr(struct vcpu *v } } -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 @@ struct op_x86_model_spec const op_ppro_s .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 65968459de75 -r 15f5cff84adf xen/arch/x86/oprofile/op_x86_model.h --- a/xen/arch/x86/oprofile/op_x86_model.h Tue Sep 15 10:02:15 2009 +0100 +++ b/xen/arch/x86/oprofile/op_x86_model.h Tue Sep 15 10:03:16 2009 +0100 @@ -32,8 +32,8 @@ struct pt_regs; * 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 @@ struct op_x86_model_spec { 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 65968459de75 -r 15f5cff84adf xen/include/asm-x86/cpufeature.h --- a/xen/include/asm-x86/cpufeature.h Tue Sep 15 10:02:15 2009 +0100 +++ b/xen/include/asm-x86/cpufeature.h Tue Sep 15 10:03:16 2009 +0100 @@ -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 */ /* _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |