# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1278955826 -3600
# Node ID c41211b25b44a9df6ca9c62c22200a0df3be69a7
# Parent f12837d7a50e3e5f843bd1a7113bb329661c7dd0
x86, pm: provide core/package cstate residencies
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@xxxxxxxxx>
---
xen/arch/x86/acpi/cpu_idle.c | 75 +++++++++++++++++++++++++++++++++++++++++++
xen/arch/x86/time.c | 7 ++++
xen/include/asm-x86/time.h | 2 +
xen/include/public/sysctl.h | 5 ++
4 files changed, 89 insertions(+)
diff -r f12837d7a50e -r c41211b25b44 xen/arch/x86/acpi/cpu_idle.c
--- a/xen/arch/x86/acpi/cpu_idle.c Mon Jul 12 10:48:34 2010 +0100
+++ b/xen/arch/x86/acpi/cpu_idle.c Mon Jul 12 18:30:26 2010 +0100
@@ -55,6 +55,14 @@
/*#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);
@@ -75,6 +83,63 @@ boolean_param("lapic_timer_c2_ok", local
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 = ¤t_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[] =
{
@@ -113,6 +178,7 @@ static void print_acpi_power(uint32_t cp
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, s
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, s
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;
}
diff -r f12837d7a50e -r c41211b25b44 xen/arch/x86/time.c
--- a/xen/arch/x86/time.c Mon Jul 12 10:48:34 2010 +0100
+++ b/xen/arch/x86/time.c Mon Jul 12 18:30:26 2010 +0100
@@ -785,6 +785,13 @@ s_time_t get_s_time(void)
now = t->stime_local_stamp + scale_delta(delta, &t->tsc_scale);
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. */
diff -r f12837d7a50e -r c41211b25b44 xen/include/asm-x86/time.h
--- a/xen/include/asm-x86/time.h Mon Jul 12 10:48:34 2010 +0100
+++ b/xen/include/asm-x86/time.h Mon Jul 12 18:30:26 2010 +0100
@@ -56,6 +56,8 @@ uint64_t acpi_pm_tick_to_ns(uint64_t tic
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);
diff -r f12837d7a50e -r c41211b25b44 xen/include/public/sysctl.h
--- a/xen/include/public/sysctl.h Mon Jul 12 10:48:34 2010 +0100
+++ b/xen/include/public/sysctl.h Mon Jul 12 18:30:26 2010 +0100
@@ -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 {
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|