diff options
author | Thomas Renninger <trenn@suse.de> | 2013-06-28 09:34:33 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-07-04 19:52:19 -0400 |
commit | 7ee767b69b6885dd81bafaf1881c5028033a6177 (patch) | |
tree | d5875991f2b9582da406ace83b41355396824cd5 /tools/power/cpupower | |
parent | 2aa1ca75c48f1da2c9bdc81ec4403eaf89a410d5 (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/Makefile | 1 | ||||
-rw-r--r-- | tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c | 196 | ||||
-rw-r--r-- | tools/power/cpupower/utils/idle_monitor/idle_monitors.def | 1 |
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 | |||
26 | enum intel_hsw_ext_id { PC8 = 0, PC9, PC10, HSW_EXT_CSTATE_COUNT, | ||
27 | TSC = 0xFFFF }; | ||
28 | |||
29 | static int hsw_ext_get_count_percent(unsigned int self_id, double *percent, | ||
30 | unsigned int cpu); | ||
31 | |||
32 | static 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 | |||
57 | static unsigned long long tsc_at_measure_start; | ||
58 | static unsigned long long tsc_at_measure_end; | ||
59 | static unsigned long long *previous_count[HSW_EXT_CSTATE_COUNT]; | ||
60 | static unsigned long long *current_count[HSW_EXT_CSTATE_COUNT]; | ||
61 | /* valid flag for all CPUs. If a MSR read failed it will be zero */ | ||
62 | static int *is_valid; | ||
63 | |||
64 | static 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 | |||
90 | static 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 | |||
115 | static 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 | |||
130 | static 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 | |||
146 | struct cpuidle_monitor intel_hsw_ext_monitor; | ||
147 | |||
148 | static 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 | |||
174 | void 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 | |||
184 | struct 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 @@ | |||
2 | DEF(amd_fam14h) | 2 | DEF(amd_fam14h) |
3 | DEF(intel_nhm) | 3 | DEF(intel_nhm) |
4 | DEF(intel_snb) | 4 | DEF(intel_snb) |
5 | DEF(intel_hsw_ext) | ||
5 | DEF(mperf) | 6 | DEF(mperf) |
6 | #endif | 7 | #endif |
7 | DEF(cpuidle_sysfs) | 8 | DEF(cpuidle_sysfs) |