[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.