[PATCH 5/5] cpupower: Add Haswell family 0x45 specific idle monitor to show PC8, 9, 10 states

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxx>
---
 tools/power/cpupower/Makefile                      |    1 +
 .../cpupower/utils/idle_monitor/hsw_ext_idle.c     |  196 ++++++++++++++++++++
 .../cpupower/utils/idle_monitor/idle_monitors.def  |    1 +
 3 files changed, 198 insertions(+), 0 deletions(-)
 create mode 100644 tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c

diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index ce17f30..cbfec92 100644
--- a/tools/power/cpupower/Makefile
+++ b/tools/power/cpupower/Makefile
@@ -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
index 0000000..ebeaba6
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
@@ -0,0 +1,196 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@xxxxxxx>, 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__) */
diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
index e3f8d9b..0d6ba4d 100644
--- a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
+++ b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
@@ -2,6 +2,7 @@
 DEF(amd_fam14h)
 DEF(intel_nhm)
 DEF(intel_snb)
+DEF(intel_hsw_ext)
 DEF(mperf)
 #endif
 DEF(cpuidle_sysfs)
-- 
1.7.6.1





[Index of Archives]     [Linux ACPI]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [CPU Freq]     [Kernel Newbies]     [Fedora Kernel]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux