cpupower: Add Haswell family 0x45 specific idle monitor to show PC8,9,10 states
authorThomas Renninger <trenn@suse.de>
Fri, 28 Jun 2013 13:34:33 +0000 (15:34 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 4 Jul 2013 23:52:19 +0000 (01:52 +0200)
This specific processor supports 3 new package sleep states.
Provide a monitor, so that the user can see their usage.

Signed-off-by: Thomas Renninger <trenn@suse.de>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
tools/power/cpupower/Makefile
tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/idle_monitors.def

index ce17f30f04ba142d27b25fee1b8d0f0b61430fff..cbfec92af32766b2570cc9add2ce4c3290bcd75e 100644 (file)
@@ -128,6 +128,7 @@ UTIL_OBJS =  utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \
        utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \
        utils/helpers/pci.o utils/helpers/bitmask.o \
        utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \
+       utils/idle_monitor/hsw_ext_idle.o \
        utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \
        utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \
        utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \
diff --git a/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
new file mode 100644 (file)
index 0000000..ebeaba6
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  Based on SandyBridge monitor. Implements the new package C-states
+ *  (PC8, PC9, PC10) coming with a specific Haswell (family 0x45) CPU.
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "helpers/helpers.h"
+#include "idle_monitor/cpupower-monitor.h"
+
+#define MSR_PKG_C8_RESIDENCY           0x00000630
+#define MSR_PKG_C9_RESIDENCY           0x00000631
+#define MSR_PKG_C10_RESIDENCY          0x00000632
+
+#define MSR_TSC        0x10
+
+enum intel_hsw_ext_id { PC8 = 0, PC9, PC10, HSW_EXT_CSTATE_COUNT,
+                       TSC = 0xFFFF };
+
+static int hsw_ext_get_count_percent(unsigned int self_id, double *percent,
+                                unsigned int cpu);
+
+static cstate_t hsw_ext_cstates[HSW_EXT_CSTATE_COUNT] = {
+       {
+               .name                   = "PC8",
+               .desc                   = N_("Processor Package C8"),
+               .id                     = PC8,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = hsw_ext_get_count_percent,
+       },
+       {
+               .name                   = "PC9",
+               .desc                   = N_("Processor Package C9"),
+               .desc                   = N_("Processor Package C2"),
+               .id                     = PC9,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = hsw_ext_get_count_percent,
+       },
+       {
+               .name                   = "PC10",
+               .desc                   = N_("Processor Package C10"),
+               .id                     = PC10,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = hsw_ext_get_count_percent,
+       },
+};
+
+static unsigned long long tsc_at_measure_start;
+static unsigned long long tsc_at_measure_end;
+static unsigned long long *previous_count[HSW_EXT_CSTATE_COUNT];
+static unsigned long long *current_count[HSW_EXT_CSTATE_COUNT];
+/* valid flag for all CPUs. If a MSR read failed it will be zero */
+static int *is_valid;
+
+static int hsw_ext_get_count(enum intel_hsw_ext_id id, unsigned long long *val,
+                       unsigned int cpu)
+{
+       int msr;
+
+       switch (id) {
+       case PC8:
+               msr = MSR_PKG_C8_RESIDENCY;
+               break;
+       case PC9:
+               msr = MSR_PKG_C9_RESIDENCY;
+               break;
+       case PC10:
+               msr = MSR_PKG_C10_RESIDENCY;
+               break;
+       case TSC:
+               msr = MSR_TSC;
+               break;
+       default:
+               return -1;
+       };
+       if (read_msr(cpu, msr, val))
+               return -1;
+       return 0;
+}
+
+static int hsw_ext_get_count_percent(unsigned int id, double *percent,
+                                unsigned int cpu)
+{
+       *percent = 0.0;
+
+       if (!is_valid[cpu])
+               return -1;
+
+       *percent = (100.0 *
+               (current_count[id][cpu] - previous_count[id][cpu])) /
+               (tsc_at_measure_end - tsc_at_measure_start);
+
+       dprint("%s: previous: %llu - current: %llu - (%u)\n",
+               hsw_ext_cstates[id].name, previous_count[id][cpu],
+               current_count[id][cpu], cpu);
+
+       dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",
+              hsw_ext_cstates[id].name,
+              (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,
+              current_count[id][cpu] - previous_count[id][cpu],
+              *percent, cpu);
+
+       return 0;
+}
+
+static int hsw_ext_start(void)
+{
+       int num, cpu;
+       unsigned long long val;
+
+       for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++) {
+                       hsw_ext_get_count(num, &val, cpu);
+                       previous_count[num][cpu] = val;
+               }
+       }
+       hsw_ext_get_count(TSC, &tsc_at_measure_start, 0);
+       return 0;
+}
+
+static int hsw_ext_stop(void)
+{
+       unsigned long long val;
+       int num, cpu;
+
+       hsw_ext_get_count(TSC, &tsc_at_measure_end, 0);
+
+       for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++) {
+                       is_valid[cpu] = !hsw_ext_get_count(num, &val, cpu);
+                       current_count[num][cpu] = val;
+               }
+       }
+       return 0;
+}
+
+struct cpuidle_monitor intel_hsw_ext_monitor;
+
+static struct cpuidle_monitor *hsw_ext_register(void)
+{
+       int num;
+
+       if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL
+           || cpupower_cpu_info.family != 6)
+               return NULL;
+
+       switch (cpupower_cpu_info.model) {
+       case 0x45: /* HSW */
+               break;
+       default:
+               return NULL;
+       }
+
+       is_valid = calloc(cpu_count, sizeof(int));
+       for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
+               previous_count[num] = calloc(cpu_count,
+                                       sizeof(unsigned long long));
+               current_count[num]  = calloc(cpu_count,
+                                       sizeof(unsigned long long));
+       }
+       intel_hsw_ext_monitor.name_len = strlen(intel_hsw_ext_monitor.name);
+       return &intel_hsw_ext_monitor;
+}
+
+void hsw_ext_unregister(void)
+{
+       int num;
+       free(is_valid);
+       for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
+               free(previous_count[num]);
+               free(current_count[num]);
+       }
+}
+
+struct cpuidle_monitor intel_hsw_ext_monitor = {
+       .name                   = "HaswellExtended",
+       .hw_states              = hsw_ext_cstates,
+       .hw_states_num          = HSW_EXT_CSTATE_COUNT,
+       .start                  = hsw_ext_start,
+       .stop                   = hsw_ext_stop,
+       .do_register            = hsw_ext_register,
+       .unregister             = hsw_ext_unregister,
+       .needs_root             = 1,
+       .overflow_s             = 922000000 /* 922337203 seconds TSC overflow
+                                              at 20GHz */
+};
+#endif /* defined(__i386__) || defined(__x86_64__) */
index e3f8d9b2b18f027ff2623f16431cc090d004d63a..0d6ba4dbb9c7181a5ed3adc66bda613d3898cf43 100644 (file)
@@ -2,6 +2,7 @@
 DEF(amd_fam14h)
 DEF(intel_nhm)
 DEF(intel_snb)
+DEF(intel_hsw_ext)
 DEF(mperf)
 #endif
 DEF(cpuidle_sysfs)