aboutsummaryrefslogtreecommitdiffstats
path: root/tools/power/cpupower
diff options
context:
space:
mode:
authorThomas Renninger <trenn@suse.de>2013-06-28 09:34:33 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-07-04 19:52:19 -0400
commit7ee767b69b6885dd81bafaf1881c5028033a6177 (patch)
treed5875991f2b9582da406ace83b41355396824cd5 /tools/power/cpupower
parent2aa1ca75c48f1da2c9bdc81ec4403eaf89a410d5 (diff)
cpupower: Add Haswell family 0x45 specific idle monitor to show PC8,9,10 states
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>
Diffstat (limited to 'tools/power/cpupower')
-rw-r--r--tools/power/cpupower/Makefile1
-rw-r--r--tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c196
-rw-r--r--tools/power/cpupower/utils/idle_monitor/idle_monitors.def1
3 files changed, 198 insertions, 0 deletions
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index ce17f30f04ba..cbfec92af327 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 \
128 utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ 128 utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \
129 utils/helpers/pci.o utils/helpers/bitmask.o \ 129 utils/helpers/pci.o utils/helpers/bitmask.o \
130 utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ 130 utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \
131 utils/idle_monitor/hsw_ext_idle.o \
131 utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \ 132 utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \
132 utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \ 133 utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \
133 utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ 134 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 000000000000..ebeaba6571a3
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
@@ -0,0 +1,196 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 * Based on SandyBridge monitor. Implements the new package C-states
7 * (PC8, PC9, PC10) coming with a specific Haswell (family 0x45) CPU.
8 */
9
10#if defined(__i386__) || defined(__x86_64__)
11
12#include <stdio.h>
13#include <stdint.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include "helpers/helpers.h"
18#include "idle_monitor/cpupower-monitor.h"
19
20#define MSR_PKG_C8_RESIDENCY 0x00000630
21#define MSR_PKG_C9_RESIDENCY 0x00000631
22#define MSR_PKG_C10_RESIDENCY 0x00000632
23
24#define MSR_TSC 0x10
25
26enum intel_hsw_ext_id { PC8 = 0, PC9, PC10, HSW_EXT_CSTATE_COUNT,
27 TSC = 0xFFFF };
28
29static int hsw_ext_get_count_percent(unsigned int self_id, double *percent,
30 unsigned int cpu);
31
32static cstate_t hsw_ext_cstates[HSW_EXT_CSTATE_COUNT] = {
33 {
34 .name = "PC8",
35 .desc = N_("Processor Package C8"),
36 .id = PC8,
37 .range = RANGE_PACKAGE,
38 .get_count_percent = hsw_ext_get_count_percent,
39 },
40 {
41 .name = "PC9",
42 .desc = N_("Processor Package C9"),
43 .desc = N_("Processor Package C2"),
44 .id = PC9,
45 .range = RANGE_PACKAGE,
46 .get_count_percent = hsw_ext_get_count_percent,
47 },
48 {
49 .name = "PC10",
50 .desc = N_("Processor Package C10"),
51 .id = PC10,
52 .range = RANGE_PACKAGE,
53 .get_count_percent = hsw_ext_get_count_percent,
54 },
55};
56
57static unsigned long long tsc_at_measure_start;
58static unsigned long long tsc_at_measure_end;
59static unsigned long long *previous_count[HSW_EXT_CSTATE_COUNT];
60static unsigned long long *current_count[HSW_EXT_CSTATE_COUNT];
61/* valid flag for all CPUs. If a MSR read failed it will be zero */
62static int *is_valid;
63
64static int hsw_ext_get_count(enum intel_hsw_ext_id id, unsigned long long *val,
65 unsigned int cpu)
66{
67 int msr;
68
69 switch (id) {
70 case PC8:
71 msr = MSR_PKG_C8_RESIDENCY;
72 break;
73 case PC9:
74 msr = MSR_PKG_C9_RESIDENCY;
75 break;
76 case PC10:
77 msr = MSR_PKG_C10_RESIDENCY;
78 break;
79 case TSC:
80 msr = MSR_TSC;
81 break;
82 default:
83 return -1;
84 };
85 if (read_msr(cpu, msr, val))
86 return -1;
87 return 0;
88}
89
90static int hsw_ext_get_count_percent(unsigned int id, double *percent,
91 unsigned int cpu)
92{
93 *percent = 0.0;
94
95 if (!is_valid[cpu])
96 return -1;
97
98 *percent = (100.0 *
99 (current_count[id][cpu] - previous_count[id][cpu])) /
100 (tsc_at_measure_end - tsc_at_measure_start);
101
102 dprint("%s: previous: %llu - current: %llu - (%u)\n",
103 hsw_ext_cstates[id].name, previous_count[id][cpu],
104 current_count[id][cpu], cpu);
105
106 dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",
107 hsw_ext_cstates[id].name,
108 (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,
109 current_count[id][cpu] - previous_count[id][cpu],
110 *percent, cpu);
111
112 return 0;
113}
114
115static int hsw_ext_start(void)
116{
117 int num, cpu;
118 unsigned long long val;
119
120 for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
121 for (cpu = 0; cpu < cpu_count; cpu++) {
122 hsw_ext_get_count(num, &val, cpu);
123 previous_count[num][cpu] = val;
124 }
125 }
126 hsw_ext_get_count(TSC, &tsc_at_measure_start, 0);
127 return 0;
128}
129
130static int hsw_ext_stop(void)
131{
132 unsigned long long val;
133 int num, cpu;
134
135 hsw_ext_get_count(TSC, &tsc_at_measure_end, 0);
136
137 for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
138 for (cpu = 0; cpu < cpu_count; cpu++) {
139 is_valid[cpu] = !hsw_ext_get_count(num, &val, cpu);
140 current_count[num][cpu] = val;
141 }
142 }
143 return 0;
144}
145
146struct cpuidle_monitor intel_hsw_ext_monitor;
147
148static struct cpuidle_monitor *hsw_ext_register(void)
149{
150 int num;
151
152 if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL
153 || cpupower_cpu_info.family != 6)
154 return NULL;
155
156 switch (cpupower_cpu_info.model) {
157 case 0x45: /* HSW */
158 break;
159 default:
160 return NULL;
161 }
162
163 is_valid = calloc(cpu_count, sizeof(int));
164 for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
165 previous_count[num] = calloc(cpu_count,
166 sizeof(unsigned long long));
167 current_count[num] = calloc(cpu_count,
168 sizeof(unsigned long long));
169 }
170 intel_hsw_ext_monitor.name_len = strlen(intel_hsw_ext_monitor.name);
171 return &intel_hsw_ext_monitor;
172}
173
174void hsw_ext_unregister(void)
175{
176 int num;
177 free(is_valid);
178 for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
179 free(previous_count[num]);
180 free(current_count[num]);
181 }
182}
183
184struct cpuidle_monitor intel_hsw_ext_monitor = {
185 .name = "HaswellExtended",
186 .hw_states = hsw_ext_cstates,
187 .hw_states_num = HSW_EXT_CSTATE_COUNT,
188 .start = hsw_ext_start,
189 .stop = hsw_ext_stop,
190 .do_register = hsw_ext_register,
191 .unregister = hsw_ext_unregister,
192 .needs_root = 1,
193 .overflow_s = 922000000 /* 922337203 seconds TSC overflow
194 at 20GHz */
195};
196#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 e3f8d9b2b18f..0d6ba4dbb9c7 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 @@
2DEF(amd_fam14h) 2DEF(amd_fam14h)
3DEF(intel_nhm) 3DEF(intel_nhm)
4DEF(intel_snb) 4DEF(intel_snb)
5DEF(intel_hsw_ext)
5DEF(mperf) 6DEF(mperf)
6#endif 7#endif
7DEF(cpuidle_sysfs) 8DEF(cpuidle_sysfs)