]> xenbits.xensource.com Git - xen.git/commitdiff
x86, pm: provide core/package cstate residencies
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 12 Jul 2010 17:30:26 +0000 (18:30 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 12 Jul 2010 17:30:26 +0000 (18:30 +0100)
According to Intel 64 and IA32 Architectures SDM 3B Appendix B, Intel
Nehalem/Westmere processors provide h/w MSR to report the core/package
cstate residencies. Extend sysctl_get_pmstat interface to pass the
core/package cstate residencies.

Signed-off-by: Wei Gang <gang.wei@intel.com>
xen/arch/x86/acpi/cpu_idle.c
xen/arch/x86/time.c
xen/include/asm-x86/time.h
xen/include/public/sysctl.h

index ffbdc52a60a561878a599e343942f5d28b403d67..6c79d17f834296de9991e164c554fc7fe8b2af8a 100644 (file)
 
 /*#define DEBUG_PM_CX*/
 
+#define GET_HW_RES_IN_NS(msr, val) \
+    do { rdmsrl(msr, val); val = tsc_ticks2ns(val); } while( 0 )
+#define GET_PC3_RES(val)  GET_HW_RES_IN_NS(0x3F8, val)
+#define GET_PC6_RES(val)  GET_HW_RES_IN_NS(0x3F9, val)
+#define GET_PC7_RES(val)  GET_HW_RES_IN_NS(0x3FA, val)
+#define GET_CC3_RES(val)  GET_HW_RES_IN_NS(0x3FC, val)
+#define GET_CC6_RES(val)  GET_HW_RES_IN_NS(0x3FD, val)
+
 static void lapic_timer_nop(void) { }
 static void (*lapic_timer_off)(void);
 static void (*lapic_timer_on)(void);
@@ -76,6 +84,63 @@ boolean_param("lapic_timer_c2_ok", local_apic_timer_c2_ok);
 
 static struct acpi_processor_power *__read_mostly processor_powers[NR_CPUS];
 
+struct hw_residencies
+{
+    uint64_t pc3;
+    uint64_t pc6;
+    uint64_t pc7;
+    uint64_t cc3;
+    uint64_t cc6;
+};
+
+static void do_get_hw_residencies(void *arg)
+{
+    struct cpuinfo_x86 *c = &current_cpu_data;
+    struct hw_residencies *hw_res = (struct hw_residencies *)arg;
+
+    if ( c->x86_vendor != X86_VENDOR_INTEL || c->x86 != 6 )
+        return;
+
+    switch ( c->x86_model )
+    {
+    /* Nehalem */
+    case 0x1A:
+    case 0x1E:
+    case 0x1F:
+    case 0x2E:
+    /* Westmere */
+    case 0x25:
+    case 0x2C:
+        GET_PC3_RES(hw_res->pc3);
+        GET_PC6_RES(hw_res->pc6);
+        GET_PC7_RES(hw_res->pc7);
+        GET_CC3_RES(hw_res->cc3);
+        GET_CC6_RES(hw_res->cc6);
+        break;
+    }
+}
+
+static void get_hw_residencies(uint32_t cpu, struct hw_residencies *hw_res)
+{
+    if ( smp_processor_id() == cpu )
+        do_get_hw_residencies((void *)hw_res);
+    else
+        on_selected_cpus(cpumask_of(cpu),
+                         do_get_hw_residencies, (void *)hw_res, 1);
+}
+
+static void print_hw_residencies(uint32_t cpu)
+{
+    struct hw_residencies hw_res = {0};
+
+    get_hw_residencies(cpu, &hw_res);
+
+    printk("PC3[%"PRId64"] PC6[%"PRId64"] PC7[%"PRId64"]\n",
+           hw_res.pc3, hw_res.pc6, hw_res.pc7);
+    printk("CC3[%"PRId64"] CC6[%"PRId64"]\n",
+           hw_res.cc3, hw_res.cc6);
+}
+
 static char* acpi_cstate_method_name[] =
 {
     "NONE",
@@ -113,6 +178,7 @@ static void print_acpi_power(uint32_t cpu, struct acpi_processor_power *power)
     printk("    C0:\tusage[%08d] duration[%"PRId64"]\n",
            idle_usage, NOW() - idle_res);
 
+    print_hw_residencies(cpu);
 }
 
 static void dump_cx(unsigned char key)
@@ -933,6 +999,7 @@ int pmstat_get_cx_stat(uint32_t cpuid, struct pm_cx_stat *stat)
     const struct acpi_processor_power *power = processor_powers[cpuid];
     uint64_t usage, res, idle_usage = 0, idle_res = 0;
     int i;
+    struct hw_residencies hw_res = {0};
 
     if ( power == NULL )
     {
@@ -965,6 +1032,14 @@ int pmstat_get_cx_stat(uint32_t cpuid, struct pm_cx_stat *stat)
             return -EFAULT;
     }
 
+    get_hw_residencies(cpuid, &hw_res);
+
+    stat->pc3 = hw_res.pc3;
+    stat->pc6 = hw_res.pc6;
+    stat->pc7 = hw_res.pc7;
+    stat->cc3 = hw_res.cc3;
+    stat->cc6 = hw_res.cc6;
+
     return 0;
 }
 
index 3a824ec516bf05f9c59c595d8280959b43cd6656..8a08a53791f397a83a97ddeb1f0b728a1b80ee48 100644 (file)
@@ -787,6 +787,13 @@ s_time_t get_s_time(void)
     return now;
 }
 
+uint64_t tsc_ticks2ns(uint64_t ticks)
+{
+    struct cpu_time *t = &this_cpu(cpu_time);
+
+    return scale_delta(ticks, &t->tsc_scale);
+}
+
 /* Explicitly OR with 1 just in case version number gets out of sync. */
 #define version_update_begin(v) (((v)+1)|1)
 #define version_update_end(v)   ((v)+1)
index 99038eed7c1a777b28ef5699e96364c42fe046e7..a54414d583751644a2130cd45214e0010593c07d 100644 (file)
@@ -56,6 +56,8 @@ int pit_broadcast_is_available(void);
 uint64_t acpi_pm_tick_to_ns(uint64_t ticks);
 uint64_t ns_to_acpi_pm_tick(uint64_t ns);
 
+uint64_t tsc_ticks2ns(uint64_t ticks);
+
 void pv_soft_rdtsc(struct vcpu *v, struct cpu_user_regs *regs, int rdtscp);
 u64 gtime_to_gtsc(struct domain *d, u64 tsc);
 
index 65e508772f8217e1840e2e6fc6acd8a662ee8d9c..56506e56a49d4021f18f9cfcbcdb962aa44e41c9 100644 (file)
@@ -223,6 +223,11 @@ struct pm_cx_stat {
     uint64_aligned_t idle_time;                 /* idle time from boot */
     XEN_GUEST_HANDLE_64(uint64) triggers;    /* Cx trigger counts */
     XEN_GUEST_HANDLE_64(uint64) residencies; /* Cx residencies */
+    uint64_aligned_t pc3;
+    uint64_aligned_t pc6;
+    uint64_aligned_t pc7;
+    uint64_aligned_t cc3;
+    uint64_aligned_t cc6;
 };
 
 struct xen_sysctl_get_pmstat {