Commit | Line | Data |
---|---|---|
a61127c2 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
103a8fea LB |
2 | /* |
3 | * turbostat -- show CPU frequency and C-state residency | |
34041551 | 4 | * on modern Intel and AMD processors. |
103a8fea | 5 | * |
de7839ee | 6 | * Copyright (c) 2023 Intel Corporation. |
103a8fea | 7 | * Len Brown <len.brown@intel.com> |
103a8fea LB |
8 | */ |
9 | ||
88c3281f | 10 | #define _GNU_SOURCE |
b731f311 | 11 | #include MSRHEADER |
869ce69e | 12 | #include INTEL_FAMILY_HEADER |
95aebc44 | 13 | #include <stdarg.h> |
103a8fea | 14 | #include <stdio.h> |
b2c95d90 | 15 | #include <err.h> |
103a8fea LB |
16 | #include <unistd.h> |
17 | #include <sys/types.h> | |
18 | #include <sys/wait.h> | |
19 | #include <sys/stat.h> | |
b9ad8ee0 | 20 | #include <sys/select.h> |
103a8fea LB |
21 | #include <sys/resource.h> |
22 | #include <fcntl.h> | |
23 | #include <signal.h> | |
24 | #include <sys/time.h> | |
25 | #include <stdlib.h> | |
d8af6f5f | 26 | #include <getopt.h> |
103a8fea LB |
27 | #include <dirent.h> |
28 | #include <string.h> | |
29 | #include <ctype.h> | |
88c3281f | 30 | #include <sched.h> |
2a0609c0 | 31 | #include <time.h> |
2b92865e | 32 | #include <cpuid.h> |
fcaa681c | 33 | #include <sys/capability.h> |
98481e79 | 34 | #include <errno.h> |
9392bd98 | 35 | #include <math.h> |
2af4f9b8 LB |
36 | #include <linux/perf_event.h> |
37 | #include <asm/unistd.h> | |
7ab5ff49 | 38 | #include <stdbool.h> |
3e404846 | 39 | #include <assert.h> |
05a2f07d | 40 | #include <linux/kernel.h> |
103a8fea | 41 | |
9878bf7a LB |
42 | #define UNUSED(x) (void)(x) |
43 | ||
164d7a96 LB |
44 | /* |
45 | * This list matches the column headers, except | |
46 | * 1. built-in only, the sysfs counters are not here -- we learn of those at run-time | |
47 | * 2. Core and CPU are moved to the end, we can't have strings that contain them | |
48 | * matching on them for --show and --hide. | |
49 | */ | |
50 | ||
51 | /* | |
52 | * buffer size used by sscanf() for added column names | |
53 | * Usually truncated to 7 characters, but also handles 18 columns for raw 64-bit counters | |
54 | */ | |
55 | #define NAME_BYTES 20 | |
56 | #define PATH_BYTES 128 | |
57 | ||
3ac1d14d WK |
58 | #define MAX_NOFILE 0x8000 |
59 | ||
164d7a96 LB |
60 | enum counter_scope { SCOPE_CPU, SCOPE_CORE, SCOPE_PACKAGE }; |
61 | enum counter_type { COUNTER_ITEMS, COUNTER_CYCLES, COUNTER_SECONDS, COUNTER_USEC }; | |
62 | enum counter_format { FORMAT_RAW, FORMAT_DELTA, FORMAT_PERCENT }; | |
e48934c9 | 63 | enum amperf_source { AMPERF_SOURCE_PERF, AMPERF_SOURCE_MSR }; |
05a2f07d | 64 | enum rapl_source { RAPL_SOURCE_NONE, RAPL_SOURCE_PERF, RAPL_SOURCE_MSR }; |
164d7a96 LB |
65 | |
66 | struct msr_counter { | |
67 | unsigned int msr_num; | |
68 | char name[NAME_BYTES]; | |
69 | char path[PATH_BYTES]; | |
70 | unsigned int width; | |
71 | enum counter_type type; | |
72 | enum counter_format format; | |
73 | struct msr_counter *next; | |
74 | unsigned int flags; | |
75 | #define FLAGS_HIDE (1 << 0) | |
76 | #define FLAGS_SHOW (1 << 1) | |
77 | #define SYSFS_PERCPU (1 << 1) | |
78 | }; | |
79 | ||
80 | struct msr_counter bic[] = { | |
9878bf7a LB |
81 | { 0x0, "usec", "", 0, 0, 0, NULL, 0 }, |
82 | { 0x0, "Time_Of_Day_Seconds", "", 0, 0, 0, NULL, 0 }, | |
83 | { 0x0, "Package", "", 0, 0, 0, NULL, 0 }, | |
84 | { 0x0, "Node", "", 0, 0, 0, NULL, 0 }, | |
85 | { 0x0, "Avg_MHz", "", 0, 0, 0, NULL, 0 }, | |
86 | { 0x0, "Busy%", "", 0, 0, 0, NULL, 0 }, | |
87 | { 0x0, "Bzy_MHz", "", 0, 0, 0, NULL, 0 }, | |
88 | { 0x0, "TSC_MHz", "", 0, 0, 0, NULL, 0 }, | |
89 | { 0x0, "IRQ", "", 0, 0, 0, NULL, 0 }, | |
90 | { 0x0, "SMI", "", 32, 0, FORMAT_DELTA, NULL, 0 }, | |
91 | { 0x0, "sysfs", "", 0, 0, 0, NULL, 0 }, | |
92 | { 0x0, "CPU%c1", "", 0, 0, 0, NULL, 0 }, | |
93 | { 0x0, "CPU%c3", "", 0, 0, 0, NULL, 0 }, | |
94 | { 0x0, "CPU%c6", "", 0, 0, 0, NULL, 0 }, | |
95 | { 0x0, "CPU%c7", "", 0, 0, 0, NULL, 0 }, | |
96 | { 0x0, "ThreadC", "", 0, 0, 0, NULL, 0 }, | |
97 | { 0x0, "CoreTmp", "", 0, 0, 0, NULL, 0 }, | |
98 | { 0x0, "CoreCnt", "", 0, 0, 0, NULL, 0 }, | |
99 | { 0x0, "PkgTmp", "", 0, 0, 0, NULL, 0 }, | |
100 | { 0x0, "GFX%rc6", "", 0, 0, 0, NULL, 0 }, | |
101 | { 0x0, "GFXMHz", "", 0, 0, 0, NULL, 0 }, | |
102 | { 0x0, "Pkg%pc2", "", 0, 0, 0, NULL, 0 }, | |
103 | { 0x0, "Pkg%pc3", "", 0, 0, 0, NULL, 0 }, | |
104 | { 0x0, "Pkg%pc6", "", 0, 0, 0, NULL, 0 }, | |
105 | { 0x0, "Pkg%pc7", "", 0, 0, 0, NULL, 0 }, | |
106 | { 0x0, "Pkg%pc8", "", 0, 0, 0, NULL, 0 }, | |
107 | { 0x0, "Pkg%pc9", "", 0, 0, 0, NULL, 0 }, | |
108 | { 0x0, "Pk%pc10", "", 0, 0, 0, NULL, 0 }, | |
109 | { 0x0, "CPU%LPI", "", 0, 0, 0, NULL, 0 }, | |
110 | { 0x0, "SYS%LPI", "", 0, 0, 0, NULL, 0 }, | |
111 | { 0x0, "PkgWatt", "", 0, 0, 0, NULL, 0 }, | |
112 | { 0x0, "CorWatt", "", 0, 0, 0, NULL, 0 }, | |
113 | { 0x0, "GFXWatt", "", 0, 0, 0, NULL, 0 }, | |
114 | { 0x0, "PkgCnt", "", 0, 0, 0, NULL, 0 }, | |
115 | { 0x0, "RAMWatt", "", 0, 0, 0, NULL, 0 }, | |
116 | { 0x0, "PKG_%", "", 0, 0, 0, NULL, 0 }, | |
117 | { 0x0, "RAM_%", "", 0, 0, 0, NULL, 0 }, | |
118 | { 0x0, "Pkg_J", "", 0, 0, 0, NULL, 0 }, | |
119 | { 0x0, "Cor_J", "", 0, 0, 0, NULL, 0 }, | |
120 | { 0x0, "GFX_J", "", 0, 0, 0, NULL, 0 }, | |
121 | { 0x0, "RAM_J", "", 0, 0, 0, NULL, 0 }, | |
122 | { 0x0, "Mod%c6", "", 0, 0, 0, NULL, 0 }, | |
123 | { 0x0, "Totl%C0", "", 0, 0, 0, NULL, 0 }, | |
124 | { 0x0, "Any%C0", "", 0, 0, 0, NULL, 0 }, | |
125 | { 0x0, "GFX%C0", "", 0, 0, 0, NULL, 0 }, | |
126 | { 0x0, "CPUGFX%", "", 0, 0, 0, NULL, 0 }, | |
127 | { 0x0, "Core", "", 0, 0, 0, NULL, 0 }, | |
128 | { 0x0, "CPU", "", 0, 0, 0, NULL, 0 }, | |
129 | { 0x0, "APIC", "", 0, 0, 0, NULL, 0 }, | |
130 | { 0x0, "X2APIC", "", 0, 0, 0, NULL, 0 }, | |
131 | { 0x0, "Die", "", 0, 0, 0, NULL, 0 }, | |
132 | { 0x0, "GFXAMHz", "", 0, 0, 0, NULL, 0 }, | |
133 | { 0x0, "IPC", "", 0, 0, 0, NULL, 0 }, | |
134 | { 0x0, "CoreThr", "", 0, 0, 0, NULL, 0 }, | |
a5c6d65d | 135 | { 0x0, "UncMHz", "", 0, 0, 0, NULL, 0 }, |
3bbb331c ZR |
136 | { 0x0, "SAM%mc6", "", 0, 0, 0, NULL, 0 }, |
137 | { 0x0, "SAMMHz", "", 0, 0, 0, NULL, 0 }, | |
138 | { 0x0, "SAMAMHz", "", 0, 0, 0, NULL, 0 }, | |
164d7a96 LB |
139 | }; |
140 | ||
141 | #define MAX_BIC (sizeof(bic) / sizeof(struct msr_counter)) | |
142 | #define BIC_USEC (1ULL << 0) | |
143 | #define BIC_TOD (1ULL << 1) | |
144 | #define BIC_Package (1ULL << 2) | |
145 | #define BIC_Node (1ULL << 3) | |
146 | #define BIC_Avg_MHz (1ULL << 4) | |
147 | #define BIC_Busy (1ULL << 5) | |
148 | #define BIC_Bzy_MHz (1ULL << 6) | |
149 | #define BIC_TSC_MHz (1ULL << 7) | |
150 | #define BIC_IRQ (1ULL << 8) | |
151 | #define BIC_SMI (1ULL << 9) | |
152 | #define BIC_sysfs (1ULL << 10) | |
153 | #define BIC_CPU_c1 (1ULL << 11) | |
154 | #define BIC_CPU_c3 (1ULL << 12) | |
155 | #define BIC_CPU_c6 (1ULL << 13) | |
156 | #define BIC_CPU_c7 (1ULL << 14) | |
157 | #define BIC_ThreadC (1ULL << 15) | |
158 | #define BIC_CoreTmp (1ULL << 16) | |
159 | #define BIC_CoreCnt (1ULL << 17) | |
160 | #define BIC_PkgTmp (1ULL << 18) | |
161 | #define BIC_GFX_rc6 (1ULL << 19) | |
162 | #define BIC_GFXMHz (1ULL << 20) | |
163 | #define BIC_Pkgpc2 (1ULL << 21) | |
164 | #define BIC_Pkgpc3 (1ULL << 22) | |
165 | #define BIC_Pkgpc6 (1ULL << 23) | |
166 | #define BIC_Pkgpc7 (1ULL << 24) | |
167 | #define BIC_Pkgpc8 (1ULL << 25) | |
168 | #define BIC_Pkgpc9 (1ULL << 26) | |
169 | #define BIC_Pkgpc10 (1ULL << 27) | |
170 | #define BIC_CPU_LPI (1ULL << 28) | |
171 | #define BIC_SYS_LPI (1ULL << 29) | |
172 | #define BIC_PkgWatt (1ULL << 30) | |
173 | #define BIC_CorWatt (1ULL << 31) | |
174 | #define BIC_GFXWatt (1ULL << 32) | |
175 | #define BIC_PkgCnt (1ULL << 33) | |
176 | #define BIC_RAMWatt (1ULL << 34) | |
177 | #define BIC_PKG__ (1ULL << 35) | |
178 | #define BIC_RAM__ (1ULL << 36) | |
179 | #define BIC_Pkg_J (1ULL << 37) | |
180 | #define BIC_Cor_J (1ULL << 38) | |
181 | #define BIC_GFX_J (1ULL << 39) | |
182 | #define BIC_RAM_J (1ULL << 40) | |
183 | #define BIC_Mod_c6 (1ULL << 41) | |
184 | #define BIC_Totl_c0 (1ULL << 42) | |
185 | #define BIC_Any_c0 (1ULL << 43) | |
186 | #define BIC_GFX_c0 (1ULL << 44) | |
187 | #define BIC_CPUGFX (1ULL << 45) | |
188 | #define BIC_Core (1ULL << 46) | |
189 | #define BIC_CPU (1ULL << 47) | |
190 | #define BIC_APIC (1ULL << 48) | |
191 | #define BIC_X2APIC (1ULL << 49) | |
192 | #define BIC_Die (1ULL << 50) | |
193 | #define BIC_GFXACTMHz (1ULL << 51) | |
194 | #define BIC_IPC (1ULL << 52) | |
195 | #define BIC_CORE_THROT_CNT (1ULL << 53) | |
a5c6d65d | 196 | #define BIC_UNCORE_MHZ (1ULL << 54) |
3bbb331c ZR |
197 | #define BIC_SAM_mc6 (1ULL << 55) |
198 | #define BIC_SAMMHz (1ULL << 56) | |
199 | #define BIC_SAMACTMHz (1ULL << 57) | |
164d7a96 LB |
200 | |
201 | #define BIC_TOPOLOGY (BIC_Package | BIC_Node | BIC_CoreCnt | BIC_PkgCnt | BIC_Core | BIC_CPU | BIC_Die ) | |
202 | #define BIC_THERMAL_PWR ( BIC_CoreTmp | BIC_PkgTmp | BIC_PkgWatt | BIC_CorWatt | BIC_GFXWatt | BIC_RAMWatt | BIC_PKG__ | BIC_RAM__) | |
3bbb331c ZR |
203 | #define BIC_FREQUENCY (BIC_Avg_MHz | BIC_Busy | BIC_Bzy_MHz | BIC_TSC_MHz | BIC_GFXMHz | BIC_GFXACTMHz | BIC_SAMMHz | BIC_SAMACTMHz | BIC_UNCORE_MHZ) |
204 | #define BIC_IDLE (BIC_sysfs | BIC_CPU_c1 | BIC_CPU_c3 | BIC_CPU_c6 | BIC_CPU_c7 | BIC_GFX_rc6 | BIC_Pkgpc2 | BIC_Pkgpc3 | BIC_Pkgpc6 | BIC_Pkgpc7 | BIC_Pkgpc8 | BIC_Pkgpc9 | BIC_Pkgpc10 | BIC_CPU_LPI | BIC_SYS_LPI | BIC_Mod_c6 | BIC_Totl_c0 | BIC_Any_c0 | BIC_GFX_c0 | BIC_CPUGFX | BIC_SAM_mc6) | |
164d7a96 LB |
205 | #define BIC_OTHER ( BIC_IRQ | BIC_SMI | BIC_ThreadC | BIC_CoreTmp | BIC_IPC) |
206 | ||
207 | #define BIC_DISABLED_BY_DEFAULT (BIC_USEC | BIC_TOD | BIC_APIC | BIC_X2APIC) | |
208 | ||
209 | unsigned long long bic_enabled = (0xFFFFFFFFFFFFFFFFULL & ~BIC_DISABLED_BY_DEFAULT); | |
210 | unsigned long long bic_present = BIC_USEC | BIC_TOD | BIC_sysfs | BIC_APIC | BIC_X2APIC; | |
211 | ||
212 | #define DO_BIC(COUNTER_NAME) (bic_enabled & bic_present & COUNTER_NAME) | |
213 | #define DO_BIC_READ(COUNTER_NAME) (bic_present & COUNTER_NAME) | |
214 | #define ENABLE_BIC(COUNTER_NAME) (bic_enabled |= COUNTER_NAME) | |
215 | #define BIC_PRESENT(COUNTER_BIT) (bic_present |= COUNTER_BIT) | |
216 | #define BIC_NOT_PRESENT(COUNTER_BIT) (bic_present &= ~COUNTER_BIT) | |
217 | #define BIC_IS_ENABLED(COUNTER_BIT) (bic_enabled & COUNTER_BIT) | |
218 | ||
e48934c9 PW |
219 | struct amperf_group_fd; |
220 | ||
103a8fea | 221 | char *proc_stat = "/proc/stat"; |
b7d8c148 | 222 | FILE *outf; |
36229897 | 223 | int *fd_percpu; |
2af4f9b8 | 224 | int *fd_instr_count_percpu; |
e48934c9 | 225 | struct amperf_group_fd *fd_amperf_percpu; /* File descriptors for perf group with APERF and MPERF counters. */ |
1b439f01 LB |
226 | struct timeval interval_tv = { 5, 0 }; |
227 | struct timespec interval_ts = { 5, 0 }; | |
e9d3092f | 228 | |
023fe0ac | 229 | unsigned int num_iterations; |
c7e399f8 | 230 | unsigned int header_iterations; |
d8af6f5f | 231 | unsigned int debug; |
96e47158 | 232 | unsigned int quiet; |
3f44a5c6 | 233 | unsigned int shown; |
0de6c0df | 234 | unsigned int sums_need_wide_columns; |
d8af6f5f LB |
235 | unsigned int rapl_joules; |
236 | unsigned int summary_only; | |
c8ade361 | 237 | unsigned int list_header_only; |
d8af6f5f | 238 | unsigned int dump_only; |
103a8fea | 239 | unsigned int has_aperf; |
889facbe | 240 | unsigned int has_epb; |
3ea8e52e | 241 | unsigned int has_turbo; |
774627c5 | 242 | unsigned int is_hybrid; |
fc04cc67 | 243 | unsigned int units = 1000000; /* MHz etc */ |
103a8fea | 244 | unsigned int genuine_intel; |
34041551 | 245 | unsigned int authentic_amd; |
c1c10cc7 | 246 | unsigned int hygon_genuine; |
34041551 | 247 | unsigned int max_level, max_extended_level; |
103a8fea | 248 | unsigned int has_invariant_tsc; |
b2b34dfe | 249 | unsigned int aperf_mperf_multiplier = 1; |
103a8fea | 250 | double bclk; |
a2b7b749 | 251 | double base_hz; |
21ed5574 | 252 | unsigned int has_base_hz; |
a2b7b749 | 253 | double tsc_tweak = 1.0; |
c98d5d94 LB |
254 | unsigned int show_pkg_only; |
255 | unsigned int show_core_only; | |
256 | char *output_buffer, *outp; | |
889facbe LB |
257 | unsigned int do_dts; |
258 | unsigned int do_ptm; | |
2af4f9b8 | 259 | unsigned int do_ipc; |
be0e54c4 LB |
260 | unsigned long long cpuidle_cur_cpu_lpi_us; |
261 | unsigned long long cpuidle_cur_sys_lpi_us; | |
55279aef ZR |
262 | unsigned int tj_max; |
263 | unsigned int tj_max_override; | |
40ee8e3b AS |
264 | double rapl_power_units, rapl_time_units; |
265 | double rapl_dram_energy_units, rapl_energy_units; | |
889facbe | 266 | double rapl_joule_counter_range; |
8a5bdf41 LB |
267 | unsigned int crystal_hz; |
268 | unsigned long long tsc_hz; | |
7ce7d5de | 269 | int base_cpu; |
1b439f01 | 270 | unsigned int has_hwp; /* IA32_PM_ENABLE, IA32_HWP_CAPABILITIES */ |
7f5c258e | 271 | /* IA32_HWP_REQUEST, IA32_HWP_STATUS */ |
1b439f01 | 272 | unsigned int has_hwp_notify; /* IA32_HWP_INTERRUPT */ |
7f5c258e | 273 | unsigned int has_hwp_activity_window; /* IA32_HWP_REQUEST[bits 41:32] */ |
1b439f01 LB |
274 | unsigned int has_hwp_epp; /* IA32_HWP_REQUEST[bits 31:24] */ |
275 | unsigned int has_hwp_pkg; /* IA32_HWP_REQUEST_PKG */ | |
4c2122d4 | 276 | unsigned int first_counter_read = 1; |
c026c236 | 277 | int ignore_stdin; |
3e404846 | 278 | bool no_msr; |
a0e86c90 | 279 | bool no_perf; |
e48934c9 | 280 | enum amperf_source amperf_source; |
889facbe | 281 | |
4e2bbbf7 ZR |
282 | enum gfx_sysfs_idx { |
283 | GFX_rc6, | |
284 | GFX_MHz, | |
285 | GFX_ACTMHz, | |
3bbb331c ZR |
286 | SAM_mc6, |
287 | SAM_MHz, | |
288 | SAM_ACTMHz, | |
4e2bbbf7 ZR |
289 | GFX_MAX |
290 | }; | |
291 | ||
292 | struct gfx_sysfs_info { | |
293 | const char *path; | |
de39d38c ZR |
294 | FILE *fp; |
295 | unsigned int val; | |
296 | unsigned long long val_ull; | |
4e2bbbf7 ZR |
297 | }; |
298 | ||
299 | static struct gfx_sysfs_info gfx_info[GFX_MAX]; | |
300 | ||
71e84129 ZR |
301 | int get_msr(int cpu, off_t offset, unsigned long long *msr); |
302 | ||
45232ab1 ZR |
303 | /* Model specific support Start */ |
304 | ||
305 | /* List of features that may diverge among different platforms */ | |
306 | struct platform_features { | |
778fc34a | 307 | bool has_msr_misc_feature_control; /* MSR_MISC_FEATURE_CONTROL */ |
3dd0e754 | 308 | bool has_msr_misc_pwr_mgmt; /* MSR_MISC_PWR_MGMT */ |
045acf60 | 309 | bool has_nhm_msrs; /* MSR_PLATFORM_INFO, MSR_IA32_TEMPERATURE_TARGET, MSR_SMI_COUNT, MSR_PKG_CST_CONFIG_CONTROL, MSR_IA32_POWER_CTL, TRL MSRs */ |
a61c9cb4 | 310 | bool has_config_tdp; /* MSR_CONFIG_TDP_NOMINAL/LEVEL_1/LEVEL_2/CONTROL, MSR_TURBO_ACTIVATION_RATIO */ |
71e84129 | 311 | int bclk_freq; /* CPU base clock */ |
a5d1ab93 | 312 | int crystal_freq; /* Crystal clock to use when not available from CPUID.15 */ |
3c6a17b8 | 313 | int supported_cstates; /* Core cstates and Package cstates supported */ |
3989fc89 | 314 | int cst_limit; /* MSR_PKG_CST_CONFIG_CONTROL */ |
d90120bf | 315 | bool has_cst_auto_convension; /* AUTOMATIC_CSTATE_CONVERSION bit in MSR_PKG_CST_CONFIG_CONTROL */ |
148df4fd | 316 | bool has_irtl_msrs; /* MSR_PKGC3/PKGC6/PKGC7/PKGC8/PKGC9/PKGC10_IRTL */ |
76d83d2a | 317 | bool has_msr_core_c1_res; /* MSR_CORE_C1_RES */ |
9cc1c103 | 318 | bool has_msr_module_c6_res_ms; /* MSR_MODULE_C6_RES_MS */ |
6c36882e | 319 | bool has_msr_c6_demotion_policy_config; /* MSR_CC6_DEMOTION_POLICY_CONFIG/MSR_MC6_DEMOTION_POLICY_CONFIG */ |
c8202a6c | 320 | bool has_msr_atom_pkg_c6_residency; /* MSR_ATOM_PKG_C6_RESIDENCY */ |
80d132cb | 321 | bool has_msr_knl_core_c6_residency; /* MSR_KNL_CORE_C6_RESIDENCY */ |
58ddb691 | 322 | bool has_ext_cst_msrs; /* MSR_PKG_WEIGHTED_CORE_C0_RES/MSR_PKG_ANY_CORE_C0_RES/MSR_PKG_ANY_GFXE_C0_RES/MSR_PKG_BOTH_CORE_GFXE_C0_RES */ |
7d0ebe6f | 323 | bool has_cst_prewake_bit; /* Cstate prewake bit in MSR_IA32_POWER_CTL */ |
10d85d85 | 324 | int trl_msrs; /* MSR_TURBO_RATIO_LIMIT/LIMIT1/LIMIT2/SECONDARY, Atom TRL MSRs */ |
0c057cf7 | 325 | int plr_msrs; /* MSR_CORE/GFX/RING_PERF_LIMIT_REASONS */ |
86ba263d | 326 | int rapl_msrs; /* RAPL PKG/DRAM/CORE/GFX MSRs, AMD RAPL MSRs */ |
e338831b | 327 | bool has_per_core_rapl; /* Indicates cores energy collection is per-core, not per-package. AMD specific for now */ |
6d35b8c4 | 328 | bool has_rapl_divisor; /* Divisor for Energy unit raw value from MSR_RAPL_POWER_UNIT */ |
9e6f3515 | 329 | bool has_fixed_rapl_unit; /* Fixed Energy Unit used for DRAM RAPL Domain */ |
7c604093 | 330 | int rapl_quirk_tdp; /* Hardcoded TDP value when cannot be retrieved from hardware */ |
d8e1623b | 331 | int tcc_offset_bits; /* TCC Offset bits in MSR_IA32_TEMPERATURE_TARGET */ |
485a017c | 332 | bool enable_tsc_tweak; /* Use CPU Base freq instead of TSC freq for aperf/mperf counter */ |
ed43247b | 333 | bool need_perf_multiplier; /* mperf/aperf multiplier */ |
45232ab1 ZR |
334 | }; |
335 | ||
336 | struct platform_data { | |
337 | unsigned int model; | |
338 | const struct platform_features *features; | |
339 | }; | |
340 | ||
71e84129 ZR |
341 | /* For BCLK */ |
342 | enum bclk_freq { | |
343 | BCLK_100MHZ = 1, | |
344 | BCLK_133MHZ, | |
345 | BCLK_SLV, | |
346 | }; | |
347 | ||
348 | #define SLM_BCLK_FREQS 5 | |
349 | double slm_freq_table[SLM_BCLK_FREQS] = { 83.3, 100.0, 133.3, 116.7, 80.0 }; | |
350 | ||
351 | double slm_bclk(void) | |
352 | { | |
353 | unsigned long long msr = 3; | |
354 | unsigned int i; | |
355 | double freq; | |
356 | ||
357 | if (get_msr(base_cpu, MSR_FSB_FREQ, &msr)) | |
358 | fprintf(outf, "SLM BCLK: unknown\n"); | |
359 | ||
360 | i = msr & 0xf; | |
361 | if (i >= SLM_BCLK_FREQS) { | |
362 | fprintf(outf, "SLM BCLK[%d] invalid\n", i); | |
363 | i = 3; | |
364 | } | |
365 | freq = slm_freq_table[i]; | |
366 | ||
367 | if (!quiet) | |
368 | fprintf(outf, "SLM BCLK: %.1f Mhz\n", freq); | |
369 | ||
370 | return freq; | |
371 | } | |
372 | ||
3989fc89 ZR |
373 | /* For Package cstate limit */ |
374 | enum package_cstate_limit { | |
375 | CST_LIMIT_NHM = 1, | |
376 | CST_LIMIT_SNB, | |
377 | CST_LIMIT_HSW, | |
378 | CST_LIMIT_SKX, | |
379 | CST_LIMIT_ICX, | |
380 | CST_LIMIT_SLV, | |
381 | CST_LIMIT_AMT, | |
382 | CST_LIMIT_KNL, | |
383 | CST_LIMIT_GMT, | |
384 | }; | |
385 | ||
10d85d85 ZR |
386 | /* For Turbo Ratio Limit MSRs */ |
387 | enum turbo_ratio_limit_msrs { | |
388 | TRL_BASE = BIT(0), | |
389 | TRL_LIMIT1 = BIT(1), | |
390 | TRL_LIMIT2 = BIT(2), | |
391 | TRL_ATOM = BIT(3), | |
392 | TRL_KNL = BIT(4), | |
393 | TRL_CORECOUNT = BIT(5), | |
394 | }; | |
395 | ||
0c057cf7 ZR |
396 | /* For Perf Limit Reason MSRs */ |
397 | enum perf_limit_reason_msrs { | |
398 | PLR_CORE = BIT(0), | |
399 | PLR_GFX = BIT(1), | |
400 | PLR_RING = BIT(2), | |
401 | }; | |
402 | ||
b9cd6683 ZR |
403 | /* For RAPL MSRs */ |
404 | enum rapl_msrs { | |
405 | RAPL_PKG_POWER_LIMIT = BIT(0), /* 0x610 MSR_PKG_POWER_LIMIT */ | |
406 | RAPL_PKG_ENERGY_STATUS = BIT(1), /* 0x611 MSR_PKG_ENERGY_STATUS */ | |
407 | RAPL_PKG_PERF_STATUS = BIT(2), /* 0x613 MSR_PKG_PERF_STATUS */ | |
408 | RAPL_PKG_POWER_INFO = BIT(3), /* 0x614 MSR_PKG_POWER_INFO */ | |
409 | RAPL_DRAM_POWER_LIMIT = BIT(4), /* 0x618 MSR_DRAM_POWER_LIMIT */ | |
410 | RAPL_DRAM_ENERGY_STATUS = BIT(5), /* 0x619 MSR_DRAM_ENERGY_STATUS */ | |
411 | RAPL_DRAM_PERF_STATUS = BIT(6), /* 0x61b MSR_DRAM_PERF_STATUS */ | |
412 | RAPL_DRAM_POWER_INFO = BIT(7), /* 0x61c MSR_DRAM_POWER_INFO */ | |
413 | RAPL_CORE_POWER_LIMIT = BIT(8), /* 0x638 MSR_PP0_POWER_LIMIT */ | |
414 | RAPL_CORE_ENERGY_STATUS = BIT(9), /* 0x639 MSR_PP0_ENERGY_STATUS */ | |
415 | RAPL_CORE_POLICY = BIT(10), /* 0x63a MSR_PP0_POLICY */ | |
416 | RAPL_GFX_POWER_LIMIT = BIT(11), /* 0x640 MSR_PP1_POWER_LIMIT */ | |
417 | RAPL_GFX_ENERGY_STATUS = BIT(12), /* 0x641 MSR_PP1_ENERGY_STATUS */ | |
418 | RAPL_GFX_POLICY = BIT(13), /* 0x642 MSR_PP1_POLICY */ | |
419 | RAPL_AMD_PWR_UNIT = BIT(14), /* 0xc0010299 MSR_AMD_RAPL_POWER_UNIT */ | |
420 | RAPL_AMD_CORE_ENERGY_STAT = BIT(15), /* 0xc001029a MSR_AMD_CORE_ENERGY_STATUS */ | |
421 | RAPL_AMD_PKG_ENERGY_STAT = BIT(16), /* 0xc001029b MSR_AMD_PKG_ENERGY_STATUS */ | |
b9cd6683 ZR |
422 | }; |
423 | ||
424 | #define RAPL_PKG (RAPL_PKG_ENERGY_STATUS | RAPL_PKG_POWER_LIMIT) | |
425 | #define RAPL_DRAM (RAPL_DRAM_ENERGY_STATUS | RAPL_DRAM_POWER_LIMIT) | |
426 | #define RAPL_CORE (RAPL_CORE_ENERGY_STATUS | RAPL_CORE_POWER_LIMIT) | |
427 | #define RAPL_GFX (RAPL_GFX_POWER_LIMIT | RAPL_GFX_ENERGY_STATUS) | |
428 | ||
429 | #define RAPL_PKG_ALL (RAPL_PKG | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO) | |
430 | #define RAPL_DRAM_ALL (RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_DRAM_POWER_INFO) | |
431 | #define RAPL_CORE_ALL (RAPL_CORE | RAPL_CORE_POLICY) | |
432 | #define RAPL_GFX_ALL (RAPL_GFX | RAPL_GFX_POLIGY) | |
433 | ||
434 | #define RAPL_AMD_F17H (RAPL_AMD_PWR_UNIT | RAPL_AMD_CORE_ENERGY_STAT | RAPL_AMD_PKG_ENERGY_STAT) | |
435 | ||
3c6a17b8 ZR |
436 | /* For Cstates */ |
437 | enum cstates { | |
438 | CC1 = BIT(0), | |
439 | CC3 = BIT(1), | |
440 | CC6 = BIT(2), | |
441 | CC7 = BIT(3), | |
442 | PC2 = BIT(4), | |
443 | PC3 = BIT(5), | |
444 | PC6 = BIT(6), | |
445 | PC7 = BIT(7), | |
446 | PC8 = BIT(8), | |
447 | PC9 = BIT(9), | |
448 | PC10 = BIT(10), | |
449 | }; | |
450 | ||
45232ab1 | 451 | static const struct platform_features nhm_features = { |
3dd0e754 | 452 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 453 | .has_nhm_msrs = 1, |
71e84129 | 454 | .bclk_freq = BCLK_133MHZ, |
6f1935c0 | 455 | .supported_cstates = CC1 | CC3 | CC6 | PC3 | PC6, |
3989fc89 | 456 | .cst_limit = CST_LIMIT_NHM, |
10d85d85 | 457 | .trl_msrs = TRL_BASE, |
45232ab1 ZR |
458 | }; |
459 | ||
460 | static const struct platform_features nhx_features = { | |
3dd0e754 | 461 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 462 | .has_nhm_msrs = 1, |
71e84129 | 463 | .bclk_freq = BCLK_133MHZ, |
6f1935c0 | 464 | .supported_cstates = CC1 | CC3 | CC6 | PC3 | PC6, |
3989fc89 | 465 | .cst_limit = CST_LIMIT_NHM, |
45232ab1 ZR |
466 | }; |
467 | ||
468 | static const struct platform_features snb_features = { | |
778fc34a | 469 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 470 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 471 | .has_nhm_msrs = 1, |
71e84129 | 472 | .bclk_freq = BCLK_100MHZ, |
192cbf04 | 473 | .supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7, |
3989fc89 | 474 | .cst_limit = CST_LIMIT_SNB, |
148df4fd | 475 | .has_irtl_msrs = 1, |
10d85d85 | 476 | .trl_msrs = TRL_BASE, |
86ba263d | 477 | .rapl_msrs = RAPL_PKG | RAPL_CORE_ALL | RAPL_GFX | RAPL_PKG_POWER_INFO, |
45232ab1 ZR |
478 | }; |
479 | ||
480 | static const struct platform_features snx_features = { | |
778fc34a | 481 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 482 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 483 | .has_nhm_msrs = 1, |
71e84129 | 484 | .bclk_freq = BCLK_100MHZ, |
192cbf04 | 485 | .supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7, |
3989fc89 | 486 | .cst_limit = CST_LIMIT_SNB, |
148df4fd | 487 | .has_irtl_msrs = 1, |
10d85d85 | 488 | .trl_msrs = TRL_BASE, |
86ba263d | 489 | .rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM_ALL, |
45232ab1 ZR |
490 | }; |
491 | ||
492 | static const struct platform_features ivb_features = { | |
778fc34a | 493 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 494 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 495 | .has_nhm_msrs = 1, |
a61c9cb4 | 496 | .has_config_tdp = 1, |
71e84129 | 497 | .bclk_freq = BCLK_100MHZ, |
192cbf04 | 498 | .supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7, |
3989fc89 | 499 | .cst_limit = CST_LIMIT_SNB, |
148df4fd | 500 | .has_irtl_msrs = 1, |
10d85d85 | 501 | .trl_msrs = TRL_BASE, |
86ba263d | 502 | .rapl_msrs = RAPL_PKG | RAPL_CORE_ALL | RAPL_GFX | RAPL_PKG_POWER_INFO, |
45232ab1 ZR |
503 | }; |
504 | ||
505 | static const struct platform_features ivx_features = { | |
778fc34a | 506 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 507 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 508 | .has_nhm_msrs = 1, |
71e84129 | 509 | .bclk_freq = BCLK_100MHZ, |
192cbf04 | 510 | .supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7, |
3989fc89 | 511 | .cst_limit = CST_LIMIT_SNB, |
148df4fd | 512 | .has_irtl_msrs = 1, |
10d85d85 | 513 | .trl_msrs = TRL_BASE | TRL_LIMIT1, |
86ba263d | 514 | .rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM_ALL, |
45232ab1 ZR |
515 | }; |
516 | ||
517 | static const struct platform_features hsw_features = { | |
778fc34a | 518 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 519 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 520 | .has_nhm_msrs = 1, |
a61c9cb4 | 521 | .has_config_tdp = 1, |
71e84129 | 522 | .bclk_freq = BCLK_100MHZ, |
192cbf04 | 523 | .supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7, |
3989fc89 | 524 | .cst_limit = CST_LIMIT_HSW, |
148df4fd | 525 | .has_irtl_msrs = 1, |
10d85d85 | 526 | .trl_msrs = TRL_BASE, |
0c057cf7 | 527 | .plr_msrs = PLR_CORE | PLR_GFX | PLR_RING, |
86ba263d | 528 | .rapl_msrs = RAPL_PKG | RAPL_CORE_ALL | RAPL_GFX | RAPL_PKG_POWER_INFO, |
45232ab1 ZR |
529 | }; |
530 | ||
531 | static const struct platform_features hsx_features = { | |
778fc34a | 532 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 533 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 534 | .has_nhm_msrs = 1, |
a61c9cb4 | 535 | .has_config_tdp = 1, |
71e84129 | 536 | .bclk_freq = BCLK_100MHZ, |
192cbf04 | 537 | .supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7, |
3989fc89 | 538 | .cst_limit = CST_LIMIT_HSW, |
148df4fd | 539 | .has_irtl_msrs = 1, |
10d85d85 | 540 | .trl_msrs = TRL_BASE | TRL_LIMIT1 | TRL_LIMIT2, |
0c057cf7 | 541 | .plr_msrs = PLR_CORE | PLR_RING, |
86ba263d | 542 | .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, |
9e6f3515 | 543 | .has_fixed_rapl_unit = 1, |
45232ab1 ZR |
544 | }; |
545 | ||
546 | static const struct platform_features hswl_features = { | |
778fc34a | 547 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 548 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 549 | .has_nhm_msrs = 1, |
a61c9cb4 | 550 | .has_config_tdp = 1, |
71e84129 | 551 | .bclk_freq = BCLK_100MHZ, |
4d2c95d4 | 552 | .supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7 | PC8 | PC9 | PC10, |
3989fc89 | 553 | .cst_limit = CST_LIMIT_HSW, |
148df4fd | 554 | .has_irtl_msrs = 1, |
10d85d85 | 555 | .trl_msrs = TRL_BASE, |
0c057cf7 | 556 | .plr_msrs = PLR_CORE | PLR_GFX | PLR_RING, |
86ba263d | 557 | .rapl_msrs = RAPL_PKG | RAPL_CORE_ALL | RAPL_GFX | RAPL_PKG_POWER_INFO, |
45232ab1 ZR |
558 | }; |
559 | ||
560 | static const struct platform_features hswg_features = { | |
778fc34a | 561 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 562 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 563 | .has_nhm_msrs = 1, |
a61c9cb4 | 564 | .has_config_tdp = 1, |
71e84129 | 565 | .bclk_freq = BCLK_100MHZ, |
192cbf04 | 566 | .supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7, |
3989fc89 | 567 | .cst_limit = CST_LIMIT_HSW, |
148df4fd | 568 | .has_irtl_msrs = 1, |
10d85d85 | 569 | .trl_msrs = TRL_BASE, |
0c057cf7 | 570 | .plr_msrs = PLR_CORE | PLR_GFX | PLR_RING, |
86ba263d | 571 | .rapl_msrs = RAPL_PKG | RAPL_CORE_ALL | RAPL_GFX | RAPL_PKG_POWER_INFO, |
45232ab1 ZR |
572 | }; |
573 | ||
574 | static const struct platform_features bdw_features = { | |
778fc34a | 575 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 576 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 577 | .has_nhm_msrs = 1, |
a61c9cb4 | 578 | .has_config_tdp = 1, |
71e84129 | 579 | .bclk_freq = BCLK_100MHZ, |
4d2c95d4 | 580 | .supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7 | PC8 | PC9 | PC10, |
3989fc89 | 581 | .cst_limit = CST_LIMIT_HSW, |
148df4fd | 582 | .has_irtl_msrs = 1, |
10d85d85 | 583 | .trl_msrs = TRL_BASE, |
86ba263d | 584 | .rapl_msrs = RAPL_PKG | RAPL_CORE_ALL | RAPL_GFX | RAPL_PKG_POWER_INFO, |
45232ab1 ZR |
585 | }; |
586 | ||
587 | static const struct platform_features bdwg_features = { | |
778fc34a | 588 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 589 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 590 | .has_nhm_msrs = 1, |
a61c9cb4 | 591 | .has_config_tdp = 1, |
71e84129 | 592 | .bclk_freq = BCLK_100MHZ, |
192cbf04 | 593 | .supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7, |
3989fc89 | 594 | .cst_limit = CST_LIMIT_HSW, |
148df4fd | 595 | .has_irtl_msrs = 1, |
10d85d85 | 596 | .trl_msrs = TRL_BASE, |
86ba263d | 597 | .rapl_msrs = RAPL_PKG | RAPL_CORE_ALL | RAPL_GFX | RAPL_PKG_POWER_INFO, |
45232ab1 ZR |
598 | }; |
599 | ||
600 | static const struct platform_features bdx_features = { | |
778fc34a | 601 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 602 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 603 | .has_nhm_msrs = 1, |
a61c9cb4 | 604 | .has_config_tdp = 1, |
71e84129 | 605 | .bclk_freq = BCLK_100MHZ, |
11096948 | 606 | .supported_cstates = CC1 | CC3 | CC6 | PC2 | PC3 | PC6, |
3989fc89 | 607 | .cst_limit = CST_LIMIT_HSW, |
148df4fd | 608 | .has_irtl_msrs = 1, |
d90120bf | 609 | .has_cst_auto_convension = 1, |
10d85d85 | 610 | .trl_msrs = TRL_BASE, |
86ba263d | 611 | .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, |
9e6f3515 | 612 | .has_fixed_rapl_unit = 1, |
45232ab1 ZR |
613 | }; |
614 | ||
615 | static const struct platform_features skl_features = { | |
778fc34a | 616 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 617 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 618 | .has_nhm_msrs = 1, |
a61c9cb4 | 619 | .has_config_tdp = 1, |
71e84129 | 620 | .bclk_freq = BCLK_100MHZ, |
a5d1ab93 | 621 | .crystal_freq = 24000000, |
4d2c95d4 | 622 | .supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7 | PC8 | PC9 | PC10, |
3989fc89 | 623 | .cst_limit = CST_LIMIT_HSW, |
148df4fd | 624 | .has_irtl_msrs = 1, |
58ddb691 | 625 | .has_ext_cst_msrs = 1, |
10d85d85 | 626 | .trl_msrs = TRL_BASE, |
d8e1623b | 627 | .tcc_offset_bits = 6, |
86ba263d | 628 | .rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_GFX, |
485a017c | 629 | .enable_tsc_tweak = 1, |
45232ab1 ZR |
630 | }; |
631 | ||
632 | static const struct platform_features cnl_features = { | |
778fc34a | 633 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 634 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 635 | .has_nhm_msrs = 1, |
a61c9cb4 | 636 | .has_config_tdp = 1, |
71e84129 | 637 | .bclk_freq = BCLK_100MHZ, |
cd7a2b6a | 638 | .supported_cstates = CC1 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7 | PC8 | PC9 | PC10, |
3989fc89 | 639 | .cst_limit = CST_LIMIT_HSW, |
148df4fd | 640 | .has_irtl_msrs = 1, |
05ad96ff | 641 | .has_msr_core_c1_res = 1, |
58ddb691 | 642 | .has_ext_cst_msrs = 1, |
10d85d85 | 643 | .trl_msrs = TRL_BASE, |
d8e1623b | 644 | .tcc_offset_bits = 6, |
86ba263d | 645 | .rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_GFX, |
485a017c | 646 | .enable_tsc_tweak = 1, |
45232ab1 ZR |
647 | }; |
648 | ||
6b74a30b ZR |
649 | static const struct platform_features adl_features = { |
650 | .has_msr_misc_feature_control = 1, | |
651 | .has_msr_misc_pwr_mgmt = 1, | |
652 | .has_nhm_msrs = 1, | |
653 | .has_config_tdp = 1, | |
654 | .bclk_freq = BCLK_100MHZ, | |
655 | .supported_cstates = CC1 | CC6 | CC7 | PC2 | PC3 | PC6 | PC8 | PC10, | |
656 | .cst_limit = CST_LIMIT_HSW, | |
657 | .has_irtl_msrs = 1, | |
658 | .has_msr_core_c1_res = 1, | |
659 | .has_ext_cst_msrs = 1, | |
660 | .trl_msrs = TRL_BASE, | |
661 | .tcc_offset_bits = 6, | |
662 | .rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_GFX, | |
663 | .enable_tsc_tweak = 1, | |
664 | }; | |
665 | ||
45232ab1 | 666 | static const struct platform_features skx_features = { |
778fc34a | 667 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 668 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 669 | .has_nhm_msrs = 1, |
a61c9cb4 | 670 | .has_config_tdp = 1, |
71e84129 | 671 | .bclk_freq = BCLK_100MHZ, |
24d16bec | 672 | .supported_cstates = CC1 | CC6 | PC2 | PC6, |
3989fc89 | 673 | .cst_limit = CST_LIMIT_SKX, |
148df4fd | 674 | .has_irtl_msrs = 1, |
d90120bf | 675 | .has_cst_auto_convension = 1, |
10d85d85 | 676 | .trl_msrs = TRL_BASE | TRL_CORECOUNT, |
86ba263d | 677 | .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, |
9e6f3515 | 678 | .has_fixed_rapl_unit = 1, |
45232ab1 ZR |
679 | }; |
680 | ||
681 | static const struct platform_features icx_features = { | |
778fc34a | 682 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 683 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 684 | .has_nhm_msrs = 1, |
a61c9cb4 | 685 | .has_config_tdp = 1, |
71e84129 | 686 | .bclk_freq = BCLK_100MHZ, |
24d16bec | 687 | .supported_cstates = CC1 | CC6 | PC2 | PC6, |
3989fc89 | 688 | .cst_limit = CST_LIMIT_ICX, |
bb5db22c | 689 | .has_msr_core_c1_res = 1, |
148df4fd | 690 | .has_irtl_msrs = 1, |
7d0ebe6f | 691 | .has_cst_prewake_bit = 1, |
10d85d85 | 692 | .trl_msrs = TRL_BASE | TRL_CORECOUNT, |
86ba263d | 693 | .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, |
9e6f3515 | 694 | .has_fixed_rapl_unit = 1, |
45232ab1 ZR |
695 | }; |
696 | ||
697 | static const struct platform_features spr_features = { | |
778fc34a | 698 | .has_msr_misc_feature_control = 1, |
3dd0e754 | 699 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 700 | .has_nhm_msrs = 1, |
a61c9cb4 | 701 | .has_config_tdp = 1, |
71e84129 | 702 | .bclk_freq = BCLK_100MHZ, |
24d16bec | 703 | .supported_cstates = CC1 | CC6 | PC2 | PC6, |
3989fc89 | 704 | .cst_limit = CST_LIMIT_SKX, |
0e3f10e6 | 705 | .has_msr_core_c1_res = 1, |
148df4fd | 706 | .has_irtl_msrs = 1, |
7d0ebe6f | 707 | .has_cst_prewake_bit = 1, |
10d85d85 | 708 | .trl_msrs = TRL_BASE | TRL_CORECOUNT, |
86ba263d | 709 | .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, |
45232ab1 ZR |
710 | }; |
711 | ||
d33605f3 ZR |
712 | static const struct platform_features srf_features = { |
713 | .has_msr_misc_feature_control = 1, | |
714 | .has_msr_misc_pwr_mgmt = 1, | |
715 | .has_nhm_msrs = 1, | |
716 | .has_config_tdp = 1, | |
717 | .bclk_freq = BCLK_100MHZ, | |
718 | .supported_cstates = CC1 | CC6 | PC2 | PC6, | |
719 | .cst_limit = CST_LIMIT_SKX, | |
720 | .has_msr_core_c1_res = 1, | |
721 | .has_msr_module_c6_res_ms = 1, | |
722 | .has_irtl_msrs = 1, | |
723 | .has_cst_prewake_bit = 1, | |
724 | .trl_msrs = TRL_BASE | TRL_CORECOUNT, | |
725 | .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, | |
726 | }; | |
727 | ||
5a6efcb9 ZR |
728 | static const struct platform_features grr_features = { |
729 | .has_msr_misc_feature_control = 1, | |
730 | .has_msr_misc_pwr_mgmt = 1, | |
731 | .has_nhm_msrs = 1, | |
732 | .has_config_tdp = 1, | |
733 | .bclk_freq = BCLK_100MHZ, | |
734 | .supported_cstates = CC1 | CC6, | |
735 | .cst_limit = CST_LIMIT_SKX, | |
736 | .has_msr_core_c1_res = 1, | |
737 | .has_msr_module_c6_res_ms = 1, | |
738 | .has_irtl_msrs = 1, | |
739 | .has_cst_prewake_bit = 1, | |
740 | .trl_msrs = TRL_BASE | TRL_CORECOUNT, | |
741 | .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, | |
742 | }; | |
743 | ||
45232ab1 | 744 | static const struct platform_features slv_features = { |
fcfa1ce0 | 745 | .has_nhm_msrs = 1, |
71e84129 | 746 | .bclk_freq = BCLK_SLV, |
cd7a2b6a | 747 | .supported_cstates = CC1 | CC6 | PC6, |
3989fc89 | 748 | .cst_limit = CST_LIMIT_SLV, |
76d83d2a | 749 | .has_msr_core_c1_res = 1, |
9cc1c103 | 750 | .has_msr_module_c6_res_ms = 1, |
6c36882e | 751 | .has_msr_c6_demotion_policy_config = 1, |
c8202a6c | 752 | .has_msr_atom_pkg_c6_residency = 1, |
10d85d85 | 753 | .trl_msrs = TRL_ATOM, |
86ba263d | 754 | .rapl_msrs = RAPL_PKG | RAPL_CORE, |
6d35b8c4 | 755 | .has_rapl_divisor = 1, |
7c604093 | 756 | .rapl_quirk_tdp = 30, |
45232ab1 ZR |
757 | }; |
758 | ||
759 | static const struct platform_features slvd_features = { | |
3dd0e754 | 760 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 761 | .has_nhm_msrs = 1, |
71e84129 | 762 | .bclk_freq = BCLK_SLV, |
cd7a2b6a | 763 | .supported_cstates = CC1 | CC6 | PC3 | PC6, |
3989fc89 | 764 | .cst_limit = CST_LIMIT_SLV, |
c8202a6c | 765 | .has_msr_atom_pkg_c6_residency = 1, |
10d85d85 | 766 | .trl_msrs = TRL_BASE, |
86ba263d | 767 | .rapl_msrs = RAPL_PKG | RAPL_CORE, |
7c604093 | 768 | .rapl_quirk_tdp = 30, |
45232ab1 ZR |
769 | }; |
770 | ||
771 | static const struct platform_features amt_features = { | |
fcfa1ce0 | 772 | .has_nhm_msrs = 1, |
71e84129 | 773 | .bclk_freq = BCLK_133MHZ, |
6f1935c0 | 774 | .supported_cstates = CC1 | CC3 | CC6 | PC3 | PC6, |
3989fc89 | 775 | .cst_limit = CST_LIMIT_AMT, |
10d85d85 | 776 | .trl_msrs = TRL_BASE, |
45232ab1 ZR |
777 | }; |
778 | ||
779 | static const struct platform_features gmt_features = { | |
3dd0e754 | 780 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 781 | .has_nhm_msrs = 1, |
71e84129 | 782 | .bclk_freq = BCLK_100MHZ, |
a5d1ab93 | 783 | .crystal_freq = 19200000, |
4d2c95d4 | 784 | .supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7 | PC8 | PC9 | PC10, |
3989fc89 | 785 | .cst_limit = CST_LIMIT_GMT, |
148df4fd | 786 | .has_irtl_msrs = 1, |
10d85d85 | 787 | .trl_msrs = TRL_BASE | TRL_CORECOUNT, |
86ba263d | 788 | .rapl_msrs = RAPL_PKG | RAPL_PKG_POWER_INFO, |
45232ab1 ZR |
789 | }; |
790 | ||
791 | static const struct platform_features gmtd_features = { | |
3dd0e754 | 792 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 793 | .has_nhm_msrs = 1, |
71e84129 | 794 | .bclk_freq = BCLK_100MHZ, |
a5d1ab93 | 795 | .crystal_freq = 25000000, |
8e20ced0 | 796 | .supported_cstates = CC1 | CC6 | PC2 | PC6, |
3989fc89 | 797 | .cst_limit = CST_LIMIT_GMT, |
148df4fd | 798 | .has_irtl_msrs = 1, |
76d83d2a | 799 | .has_msr_core_c1_res = 1, |
10d85d85 | 800 | .trl_msrs = TRL_BASE | TRL_CORECOUNT, |
86ba263d | 801 | .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_CORE_ENERGY_STATUS, |
45232ab1 ZR |
802 | }; |
803 | ||
804 | static const struct platform_features gmtp_features = { | |
3dd0e754 | 805 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 806 | .has_nhm_msrs = 1, |
71e84129 | 807 | .bclk_freq = BCLK_100MHZ, |
a5d1ab93 | 808 | .crystal_freq = 19200000, |
4d2c95d4 | 809 | .supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7 | PC8 | PC9 | PC10, |
3989fc89 | 810 | .cst_limit = CST_LIMIT_GMT, |
148df4fd | 811 | .has_irtl_msrs = 1, |
10d85d85 | 812 | .trl_msrs = TRL_BASE, |
86ba263d | 813 | .rapl_msrs = RAPL_PKG | RAPL_PKG_POWER_INFO, |
45232ab1 ZR |
814 | }; |
815 | ||
816 | static const struct platform_features tmt_features = { | |
3dd0e754 | 817 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 818 | .has_nhm_msrs = 1, |
71e84129 | 819 | .bclk_freq = BCLK_100MHZ, |
cd7a2b6a | 820 | .supported_cstates = CC1 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7 | PC8 | PC9 | PC10, |
3989fc89 | 821 | .cst_limit = CST_LIMIT_GMT, |
148df4fd | 822 | .has_irtl_msrs = 1, |
10d85d85 | 823 | .trl_msrs = TRL_BASE, |
86ba263d | 824 | .rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_GFX, |
485a017c | 825 | .enable_tsc_tweak = 1, |
45232ab1 ZR |
826 | }; |
827 | ||
828 | static const struct platform_features tmtd_features = { | |
3dd0e754 | 829 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 830 | .has_nhm_msrs = 1, |
71e84129 | 831 | .bclk_freq = BCLK_100MHZ, |
3d982ac0 | 832 | .supported_cstates = CC1 | CC6, |
3989fc89 | 833 | .cst_limit = CST_LIMIT_GMT, |
148df4fd | 834 | .has_irtl_msrs = 1, |
10d85d85 | 835 | .trl_msrs = TRL_BASE | TRL_CORECOUNT, |
86ba263d | 836 | .rapl_msrs = RAPL_PKG_ALL, |
45232ab1 ZR |
837 | }; |
838 | ||
839 | static const struct platform_features knl_features = { | |
3dd0e754 | 840 | .has_msr_misc_pwr_mgmt = 1, |
fcfa1ce0 | 841 | .has_nhm_msrs = 1, |
a61c9cb4 | 842 | .has_config_tdp = 1, |
71e84129 | 843 | .bclk_freq = BCLK_100MHZ, |
cd7a2b6a | 844 | .supported_cstates = CC1 | CC6 | PC3 | PC6, |
3989fc89 | 845 | .cst_limit = CST_LIMIT_KNL, |
80d132cb | 846 | .has_msr_knl_core_c6_residency = 1, |
10d85d85 | 847 | .trl_msrs = TRL_KNL, |
86ba263d | 848 | .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, |
9e6f3515 | 849 | .has_fixed_rapl_unit = 1, |
ed43247b | 850 | .need_perf_multiplier = 1, |
45232ab1 ZR |
851 | }; |
852 | ||
853 | static const struct platform_features default_features = { | |
854 | }; | |
855 | ||
86ba263d ZR |
856 | static const struct platform_features amd_features_with_rapl = { |
857 | .rapl_msrs = RAPL_AMD_F17H, | |
e338831b | 858 | .has_per_core_rapl = 1, |
7c604093 | 859 | .rapl_quirk_tdp = 280, /* This is the max stock TDP of HEDT/Server Fam17h+ chips */ |
86ba263d ZR |
860 | }; |
861 | ||
45232ab1 ZR |
862 | static const struct platform_data turbostat_pdata[] = { |
863 | { INTEL_FAM6_NEHALEM, &nhm_features }, | |
864 | { INTEL_FAM6_NEHALEM_G, &nhm_features }, | |
865 | { INTEL_FAM6_NEHALEM_EP, &nhm_features }, | |
866 | { INTEL_FAM6_NEHALEM_EX, &nhx_features }, | |
867 | { INTEL_FAM6_WESTMERE, &nhm_features }, | |
868 | { INTEL_FAM6_WESTMERE_EP, &nhm_features }, | |
869 | { INTEL_FAM6_WESTMERE_EX, &nhx_features }, | |
870 | { INTEL_FAM6_SANDYBRIDGE, &snb_features }, | |
871 | { INTEL_FAM6_SANDYBRIDGE_X, &snx_features }, | |
872 | { INTEL_FAM6_IVYBRIDGE, &ivb_features }, | |
873 | { INTEL_FAM6_IVYBRIDGE_X, &ivx_features }, | |
874 | { INTEL_FAM6_HASWELL, &hsw_features }, | |
875 | { INTEL_FAM6_HASWELL_X, &hsx_features }, | |
876 | { INTEL_FAM6_HASWELL_L, &hswl_features }, | |
877 | { INTEL_FAM6_HASWELL_G, &hswg_features }, | |
878 | { INTEL_FAM6_BROADWELL, &bdw_features }, | |
879 | { INTEL_FAM6_BROADWELL_G, &bdwg_features }, | |
880 | { INTEL_FAM6_BROADWELL_X, &bdx_features }, | |
881 | { INTEL_FAM6_BROADWELL_D, &bdx_features }, | |
882 | { INTEL_FAM6_SKYLAKE_L, &skl_features }, | |
883 | { INTEL_FAM6_SKYLAKE, &skl_features }, | |
884 | { INTEL_FAM6_SKYLAKE_X, &skx_features }, | |
885 | { INTEL_FAM6_KABYLAKE_L, &skl_features }, | |
886 | { INTEL_FAM6_KABYLAKE, &skl_features }, | |
887 | { INTEL_FAM6_COMETLAKE, &skl_features }, | |
888 | { INTEL_FAM6_COMETLAKE_L, &skl_features }, | |
889 | { INTEL_FAM6_CANNONLAKE_L, &cnl_features }, | |
890 | { INTEL_FAM6_ICELAKE_X, &icx_features }, | |
891 | { INTEL_FAM6_ICELAKE_D, &icx_features }, | |
892 | { INTEL_FAM6_ICELAKE_L, &cnl_features }, | |
893 | { INTEL_FAM6_ICELAKE_NNPI, &cnl_features }, | |
894 | { INTEL_FAM6_ROCKETLAKE, &cnl_features }, | |
895 | { INTEL_FAM6_TIGERLAKE_L, &cnl_features }, | |
896 | { INTEL_FAM6_TIGERLAKE, &cnl_features }, | |
897 | { INTEL_FAM6_SAPPHIRERAPIDS_X, &spr_features }, | |
898 | { INTEL_FAM6_EMERALDRAPIDS_X, &spr_features }, | |
5feab4a6 | 899 | { INTEL_FAM6_GRANITERAPIDS_X, &spr_features }, |
45232ab1 | 900 | { INTEL_FAM6_LAKEFIELD, &cnl_features }, |
6b74a30b ZR |
901 | { INTEL_FAM6_ALDERLAKE, &adl_features }, |
902 | { INTEL_FAM6_ALDERLAKE_L, &adl_features }, | |
903 | { INTEL_FAM6_RAPTORLAKE, &adl_features }, | |
904 | { INTEL_FAM6_RAPTORLAKE_P, &adl_features }, | |
905 | { INTEL_FAM6_RAPTORLAKE_S, &adl_features }, | |
45232ab1 ZR |
906 | { INTEL_FAM6_METEORLAKE, &cnl_features }, |
907 | { INTEL_FAM6_METEORLAKE_L, &cnl_features }, | |
7b57e7b6 | 908 | { INTEL_FAM6_ARROWLAKE, &cnl_features }, |
956dbd3d | 909 | { INTEL_FAM6_LUNARLAKE_M, &cnl_features }, |
45232ab1 ZR |
910 | { INTEL_FAM6_ATOM_SILVERMONT, &slv_features }, |
911 | { INTEL_FAM6_ATOM_SILVERMONT_D, &slvd_features }, | |
912 | { INTEL_FAM6_ATOM_AIRMONT, &amt_features }, | |
913 | { INTEL_FAM6_ATOM_GOLDMONT, &gmt_features }, | |
914 | { INTEL_FAM6_ATOM_GOLDMONT_D, &gmtd_features }, | |
915 | { INTEL_FAM6_ATOM_GOLDMONT_PLUS, &gmtp_features }, | |
916 | { INTEL_FAM6_ATOM_TREMONT_D, &tmtd_features }, | |
917 | { INTEL_FAM6_ATOM_TREMONT, &tmt_features }, | |
918 | { INTEL_FAM6_ATOM_TREMONT_L, &tmt_features }, | |
6b74a30b | 919 | { INTEL_FAM6_ATOM_GRACEMONT, &adl_features }, |
d33605f3 | 920 | { INTEL_FAM6_ATOM_CRESTMONT_X, &srf_features }, |
5a6efcb9 | 921 | { INTEL_FAM6_ATOM_CRESTMONT, &grr_features }, |
45232ab1 ZR |
922 | { INTEL_FAM6_XEON_PHI_KNL, &knl_features }, |
923 | { INTEL_FAM6_XEON_PHI_KNM, &knl_features }, | |
924 | /* | |
925 | * Missing support for | |
926 | * INTEL_FAM6_ICELAKE | |
927 | * INTEL_FAM6_ATOM_SILVERMONT_MID | |
928 | * INTEL_FAM6_ATOM_AIRMONT_MID | |
929 | * INTEL_FAM6_ATOM_AIRMONT_NP | |
930 | */ | |
931 | { 0, NULL }, | |
932 | }; | |
933 | ||
934 | static const struct platform_features *platform; | |
935 | ||
936 | void probe_platform_features(unsigned int family, unsigned int model) | |
937 | { | |
938 | int i; | |
939 | ||
32e8c616 | 940 | platform = &default_features; |
86ba263d | 941 | |
32e8c616 | 942 | if (authentic_amd || hygon_genuine) { |
86ba263d ZR |
943 | if (max_extended_level >= 0x80000007) { |
944 | unsigned int eax, ebx, ecx, edx; | |
945 | ||
946 | __cpuid(0x80000007, eax, ebx, ecx, edx); | |
947 | /* RAPL (Fam 17h+) */ | |
e338831b | 948 | if ((edx & (1 << 14)) && family >= 0x17) |
86ba263d | 949 | platform = &amd_features_with_rapl; |
86ba263d | 950 | } |
45232ab1 ZR |
951 | return; |
952 | } | |
953 | ||
45232ab1 ZR |
954 | if (!genuine_intel || family != 6) |
955 | return; | |
956 | ||
957 | for (i = 0; turbostat_pdata[i].features; i++) { | |
958 | if (turbostat_pdata[i].model == model) { | |
959 | platform = turbostat_pdata[i].features; | |
960 | return; | |
961 | } | |
962 | } | |
963 | } | |
964 | ||
965 | /* Model specific support End */ | |
966 | ||
889facbe LB |
967 | #define TJMAX_DEFAULT 100 |
968 | ||
9392bd98 CW |
969 | /* MSRs that are not yet in the kernel-provided header. */ |
970 | #define MSR_RAPL_PWR_UNIT 0xc0010299 | |
971 | #define MSR_CORE_ENERGY_STAT 0xc001029a | |
972 | #define MSR_PKG_ENERGY_STAT 0xc001029b | |
973 | ||
889facbe | 974 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) |
103a8fea | 975 | |
103a8fea LB |
976 | int backwards_count; |
977 | char *progname; | |
103a8fea | 978 | |
1ef7d21a | 979 | #define CPU_SUBSET_MAXCPUS 1024 /* need to use before probe... */ |
f638858d ZR |
980 | cpu_set_t *cpu_present_set, *cpu_effective_set, *cpu_allowed_set, *cpu_affinity_set, *cpu_subset; |
981 | size_t cpu_present_setsize, cpu_effective_setsize, cpu_allowed_setsize, cpu_affinity_setsize, cpu_subset_size; | |
0748eaf0 LB |
982 | #define MAX_ADDED_COUNTERS 8 |
983 | #define MAX_ADDED_THREAD_COUNTERS 24 | |
0e2d8f05 | 984 | #define BITMASK_SIZE 32 |
c98d5d94 | 985 | |
05a2f07d PW |
986 | /* Indexes used to map data read from perf and MSRs into global variables */ |
987 | enum rapl_rci_index { | |
988 | RAPL_RCI_INDEX_ENERGY_PKG = 0, | |
989 | RAPL_RCI_INDEX_ENERGY_CORES = 1, | |
990 | RAPL_RCI_INDEX_DRAM = 2, | |
991 | RAPL_RCI_INDEX_GFX = 3, | |
992 | RAPL_RCI_INDEX_PKG_PERF_STATUS = 4, | |
993 | RAPL_RCI_INDEX_DRAM_PERF_STATUS = 5, | |
994 | RAPL_RCI_INDEX_CORE_ENERGY = 6, | |
995 | NUM_RAPL_COUNTERS, | |
996 | }; | |
997 | ||
998 | enum rapl_unit { | |
999 | RAPL_UNIT_INVALID, | |
1000 | RAPL_UNIT_JOULES, | |
1001 | RAPL_UNIT_WATTS, | |
1002 | }; | |
1003 | ||
1004 | struct rapl_counter_info_t { | |
1005 | unsigned long long data[NUM_RAPL_COUNTERS]; | |
1006 | enum rapl_source source[NUM_RAPL_COUNTERS]; | |
1007 | unsigned long long flags[NUM_RAPL_COUNTERS]; | |
1008 | double scale[NUM_RAPL_COUNTERS]; | |
1009 | enum rapl_unit unit[NUM_RAPL_COUNTERS]; | |
1010 | ||
1011 | union { | |
1012 | /* Active when source == RAPL_SOURCE_MSR */ | |
1013 | struct { | |
1014 | unsigned long long msr[NUM_RAPL_COUNTERS]; | |
1015 | unsigned long long msr_mask[NUM_RAPL_COUNTERS]; | |
1016 | int msr_shift[NUM_RAPL_COUNTERS]; | |
1017 | }; | |
1018 | }; | |
1019 | ||
1020 | int fd_perf; | |
1021 | }; | |
1022 | ||
1023 | /* struct rapl_counter_info_t for each RAPL domain */ | |
1024 | struct rapl_counter_info_t *rapl_counter_info_perdomain; | |
1025 | ||
1026 | #define RAPL_COUNTER_FLAG_USE_MSR_SUM (1u << 1) | |
1027 | ||
1028 | struct rapl_counter_arch_info { | |
1029 | int feature_mask; /* Mask for testing if the counter is supported on host */ | |
1030 | const char *perf_subsys; | |
1031 | const char *perf_name; | |
1032 | unsigned long long msr; | |
1033 | unsigned long long msr_mask; | |
1034 | int msr_shift; /* Positive mean shift right, negative mean shift left */ | |
1035 | double *platform_rapl_msr_scale; /* Scale applied to values read by MSR (platform dependent, filled at runtime) */ | |
1036 | unsigned int rci_index; /* Maps data from perf counters to global variables */ | |
1037 | unsigned long long bic; | |
1038 | double compat_scale; /* Some counters require constant scaling to be in the same range as other, similar ones */ | |
1039 | unsigned long long flags; | |
1040 | }; | |
1041 | ||
1042 | static const struct rapl_counter_arch_info rapl_counter_arch_infos[] = { | |
1043 | { | |
1044 | .feature_mask = RAPL_PKG, | |
1045 | .perf_subsys = "power", | |
1046 | .perf_name = "energy-pkg", | |
1047 | .msr = MSR_PKG_ENERGY_STATUS, | |
1048 | .msr_mask = 0xFFFFFFFFFFFFFFFF, | |
1049 | .msr_shift = 0, | |
1050 | .platform_rapl_msr_scale = &rapl_energy_units, | |
1051 | .rci_index = RAPL_RCI_INDEX_ENERGY_PKG, | |
1052 | .bic = BIC_PkgWatt | BIC_Pkg_J, | |
1053 | .compat_scale = 1.0, | |
1054 | .flags = RAPL_COUNTER_FLAG_USE_MSR_SUM, | |
1055 | }, | |
1056 | { | |
1057 | .feature_mask = RAPL_AMD_F17H, | |
1058 | .perf_subsys = "power", | |
1059 | .perf_name = "energy-pkg", | |
1060 | .msr = MSR_PKG_ENERGY_STAT, | |
1061 | .msr_mask = 0xFFFFFFFFFFFFFFFF, | |
1062 | .msr_shift = 0, | |
1063 | .platform_rapl_msr_scale = &rapl_energy_units, | |
1064 | .rci_index = RAPL_RCI_INDEX_ENERGY_PKG, | |
1065 | .bic = BIC_PkgWatt | BIC_Pkg_J, | |
1066 | .compat_scale = 1.0, | |
1067 | .flags = RAPL_COUNTER_FLAG_USE_MSR_SUM, | |
1068 | }, | |
1069 | { | |
1070 | .feature_mask = RAPL_CORE_ENERGY_STATUS, | |
1071 | .perf_subsys = "power", | |
1072 | .perf_name = "energy-cores", | |
1073 | .msr = MSR_PP0_ENERGY_STATUS, | |
1074 | .msr_mask = 0xFFFFFFFFFFFFFFFF, | |
1075 | .msr_shift = 0, | |
1076 | .platform_rapl_msr_scale = &rapl_energy_units, | |
1077 | .rci_index = RAPL_RCI_INDEX_ENERGY_CORES, | |
1078 | .bic = BIC_CorWatt | BIC_Cor_J, | |
1079 | .compat_scale = 1.0, | |
1080 | .flags = RAPL_COUNTER_FLAG_USE_MSR_SUM, | |
1081 | }, | |
1082 | { | |
1083 | .feature_mask = RAPL_DRAM, | |
1084 | .perf_subsys = "power", | |
1085 | .perf_name = "energy-ram", | |
1086 | .msr = MSR_DRAM_ENERGY_STATUS, | |
1087 | .msr_mask = 0xFFFFFFFFFFFFFFFF, | |
1088 | .msr_shift = 0, | |
1089 | .platform_rapl_msr_scale = &rapl_dram_energy_units, | |
1090 | .rci_index = RAPL_RCI_INDEX_DRAM, | |
1091 | .bic = BIC_RAMWatt | BIC_RAM_J, | |
1092 | .compat_scale = 1.0, | |
1093 | .flags = RAPL_COUNTER_FLAG_USE_MSR_SUM, | |
1094 | }, | |
1095 | { | |
1096 | .feature_mask = RAPL_GFX, | |
1097 | .perf_subsys = "power", | |
1098 | .perf_name = "energy-gpu", | |
1099 | .msr = MSR_PP1_ENERGY_STATUS, | |
1100 | .msr_mask = 0xFFFFFFFFFFFFFFFF, | |
1101 | .msr_shift = 0, | |
1102 | .platform_rapl_msr_scale = &rapl_energy_units, | |
1103 | .rci_index = RAPL_RCI_INDEX_GFX, | |
1104 | .bic = BIC_GFXWatt | BIC_GFX_J, | |
1105 | .compat_scale = 1.0, | |
1106 | .flags = RAPL_COUNTER_FLAG_USE_MSR_SUM, | |
1107 | }, | |
1108 | { | |
1109 | .feature_mask = RAPL_PKG_PERF_STATUS, | |
1110 | .perf_subsys = NULL, | |
1111 | .perf_name = NULL, | |
1112 | .msr = MSR_PKG_PERF_STATUS, | |
1113 | .msr_mask = 0xFFFFFFFFFFFFFFFF, | |
1114 | .msr_shift = 0, | |
1115 | .platform_rapl_msr_scale = &rapl_time_units, | |
1116 | .rci_index = RAPL_RCI_INDEX_PKG_PERF_STATUS, | |
1117 | .bic = BIC_PKG__, | |
1118 | .compat_scale = 100.0, | |
1119 | .flags = RAPL_COUNTER_FLAG_USE_MSR_SUM, | |
1120 | }, | |
1121 | { | |
1122 | .feature_mask = RAPL_DRAM_PERF_STATUS, | |
1123 | .perf_subsys = NULL, | |
1124 | .perf_name = NULL, | |
1125 | .msr = MSR_DRAM_PERF_STATUS, | |
1126 | .msr_mask = 0xFFFFFFFFFFFFFFFF, | |
1127 | .msr_shift = 0, | |
1128 | .platform_rapl_msr_scale = &rapl_time_units, | |
1129 | .rci_index = RAPL_RCI_INDEX_DRAM_PERF_STATUS, | |
1130 | .bic = BIC_RAM__, | |
1131 | .compat_scale = 100.0, | |
1132 | .flags = RAPL_COUNTER_FLAG_USE_MSR_SUM, | |
1133 | }, | |
1134 | { | |
1135 | .feature_mask = RAPL_AMD_F17H, | |
1136 | .perf_subsys = NULL, | |
1137 | .perf_name = NULL, | |
1138 | .msr = MSR_CORE_ENERGY_STAT, | |
1139 | .msr_mask = 0xFFFFFFFF, | |
1140 | .msr_shift = 0, | |
1141 | .platform_rapl_msr_scale = &rapl_energy_units, | |
1142 | .rci_index = RAPL_RCI_INDEX_CORE_ENERGY, | |
1143 | .bic = BIC_CorWatt | BIC_Cor_J, | |
1144 | .compat_scale = 1.0, | |
1145 | .flags = 0, | |
1146 | }, | |
1147 | }; | |
1148 | ||
1149 | struct rapl_counter { | |
1150 | unsigned long long raw_value; | |
1151 | enum rapl_unit unit; | |
1152 | double scale; | |
1153 | }; | |
1154 | ||
c98d5d94 | 1155 | struct thread_data { |
f4fdf2b4 LB |
1156 | struct timeval tv_begin; |
1157 | struct timeval tv_end; | |
d4794f25 | 1158 | struct timeval tv_delta; |
c98d5d94 LB |
1159 | unsigned long long tsc; |
1160 | unsigned long long aperf; | |
1161 | unsigned long long mperf; | |
144b44b1 | 1162 | unsigned long long c1; |
2af4f9b8 | 1163 | unsigned long long instr_count; |
1b439f01 | 1164 | unsigned long long irq_count; |
1ed51011 | 1165 | unsigned int smi_count; |
c98d5d94 | 1166 | unsigned int cpu_id; |
4c2122d4 LB |
1167 | unsigned int apic_id; |
1168 | unsigned int x2apic_id; | |
c98d5d94 | 1169 | unsigned int flags; |
7ab5ff49 | 1170 | bool is_atom; |
0748eaf0 | 1171 | unsigned long long counter[MAX_ADDED_THREAD_COUNTERS]; |
c98d5d94 LB |
1172 | } *thread_even, *thread_odd; |
1173 | ||
1174 | struct core_data { | |
ccf8a052 | 1175 | int base_cpu; |
c98d5d94 LB |
1176 | unsigned long long c3; |
1177 | unsigned long long c6; | |
1178 | unsigned long long c7; | |
0539ba11 | 1179 | unsigned long long mc6_us; /* duplicate as per-core for now, even though per module */ |
889facbe | 1180 | unsigned int core_temp_c; |
05a2f07d | 1181 | struct rapl_counter core_energy; /* MSR_CORE_ENERGY_STAT */ |
c98d5d94 | 1182 | unsigned int core_id; |
eae97e05 | 1183 | unsigned long long core_throt_cnt; |
678a3bd1 | 1184 | unsigned long long counter[MAX_ADDED_COUNTERS]; |
c98d5d94 LB |
1185 | } *core_even, *core_odd; |
1186 | ||
1187 | struct pkg_data { | |
ccf8a052 | 1188 | int base_cpu; |
c98d5d94 LB |
1189 | unsigned long long pc2; |
1190 | unsigned long long pc3; | |
1191 | unsigned long long pc6; | |
1192 | unsigned long long pc7; | |
ca58710f KCA |
1193 | unsigned long long pc8; |
1194 | unsigned long long pc9; | |
1195 | unsigned long long pc10; | |
227ed18f CY |
1196 | long long cpu_lpi; |
1197 | long long sys_lpi; | |
0b2bb692 LB |
1198 | unsigned long long pkg_wtd_core_c0; |
1199 | unsigned long long pkg_any_core_c0; | |
1200 | unsigned long long pkg_any_gfxe_c0; | |
1201 | unsigned long long pkg_both_core_gfxe_c0; | |
9185e988 | 1202 | long long gfx_rc6_ms; |
27d47356 | 1203 | unsigned int gfx_mhz; |
b4b91569 | 1204 | unsigned int gfx_act_mhz; |
3bbb331c ZR |
1205 | long long sam_mc6_ms; |
1206 | unsigned int sam_mhz; | |
1207 | unsigned int sam_act_mhz; | |
c98d5d94 | 1208 | unsigned int package_id; |
05a2f07d PW |
1209 | struct rapl_counter energy_pkg; /* MSR_PKG_ENERGY_STATUS */ |
1210 | struct rapl_counter energy_dram; /* MSR_DRAM_ENERGY_STATUS */ | |
1211 | struct rapl_counter energy_cores; /* MSR_PP0_ENERGY_STATUS */ | |
1212 | struct rapl_counter energy_gfx; /* MSR_PP1_ENERGY_STATUS */ | |
1213 | struct rapl_counter rapl_pkg_perf_status; /* MSR_PKG_PERF_STATUS */ | |
1214 | struct rapl_counter rapl_dram_perf_status; /* MSR_DRAM_PERF_STATUS */ | |
889facbe | 1215 | unsigned int pkg_temp_c; |
a5c6d65d | 1216 | unsigned int uncore_mhz; |
678a3bd1 | 1217 | unsigned long long counter[MAX_ADDED_COUNTERS]; |
c98d5d94 LB |
1218 | } *package_even, *package_odd; |
1219 | ||
1220 | #define ODD_COUNTERS thread_odd, core_odd, package_odd | |
1221 | #define EVEN_COUNTERS thread_even, core_even, package_even | |
1222 | ||
40f5cfe7 PB |
1223 | #define GET_THREAD(thread_base, thread_no, core_no, node_no, pkg_no) \ |
1224 | ((thread_base) + \ | |
1225 | ((pkg_no) * \ | |
1226 | topo.nodes_per_pkg * topo.cores_per_node * topo.threads_per_core) + \ | |
1227 | ((node_no) * topo.cores_per_node * topo.threads_per_core) + \ | |
1228 | ((core_no) * topo.threads_per_core) + \ | |
1229 | (thread_no)) | |
1230 | ||
1231 | #define GET_CORE(core_base, core_no, node_no, pkg_no) \ | |
1232 | ((core_base) + \ | |
1233 | ((pkg_no) * topo.nodes_per_pkg * topo.cores_per_node) + \ | |
1234 | ((node_no) * topo.cores_per_node) + \ | |
1235 | (core_no)) | |
1236 | ||
c98d5d94 LB |
1237 | #define GET_PKG(pkg_base, pkg_no) (pkg_base + pkg_no) |
1238 | ||
87e15da9 CY |
1239 | /* |
1240 | * The accumulated sum of MSR is defined as a monotonic | |
1241 | * increasing MSR, it will be accumulated periodically, | |
1242 | * despite its register's bit width. | |
1243 | */ | |
1244 | enum { | |
1245 | IDX_PKG_ENERGY, | |
1246 | IDX_DRAM_ENERGY, | |
1247 | IDX_PP0_ENERGY, | |
1248 | IDX_PP1_ENERGY, | |
1249 | IDX_PKG_PERF, | |
1250 | IDX_DRAM_PERF, | |
1251 | IDX_COUNT, | |
1252 | }; | |
1253 | ||
1254 | int get_msr_sum(int cpu, off_t offset, unsigned long long *msr); | |
1255 | ||
1256 | struct msr_sum_array { | |
1257 | /* get_msr_sum() = sum + (get_msr() - last) */ | |
1258 | struct { | |
1b439f01 | 1259 | /*The accumulated MSR value is updated by the timer */ |
87e15da9 | 1260 | unsigned long long sum; |
1b439f01 | 1261 | /*The MSR footprint recorded in last timer */ |
87e15da9 CY |
1262 | unsigned long long last; |
1263 | } entries[IDX_COUNT]; | |
1264 | }; | |
1265 | ||
1266 | /* The percpu MSR sum array.*/ | |
1267 | struct msr_sum_array *per_cpu_msr_sum; | |
1268 | ||
13a779de | 1269 | off_t idx_to_offset(int idx) |
87e15da9 | 1270 | { |
13a779de | 1271 | off_t offset; |
87e15da9 CY |
1272 | |
1273 | switch (idx) { | |
1274 | case IDX_PKG_ENERGY: | |
86ba263d | 1275 | if (platform->rapl_msrs & RAPL_AMD_F17H) |
301b1d3a BN |
1276 | offset = MSR_PKG_ENERGY_STAT; |
1277 | else | |
1278 | offset = MSR_PKG_ENERGY_STATUS; | |
87e15da9 CY |
1279 | break; |
1280 | case IDX_DRAM_ENERGY: | |
1281 | offset = MSR_DRAM_ENERGY_STATUS; | |
1282 | break; | |
1283 | case IDX_PP0_ENERGY: | |
1284 | offset = MSR_PP0_ENERGY_STATUS; | |
1285 | break; | |
1286 | case IDX_PP1_ENERGY: | |
1287 | offset = MSR_PP1_ENERGY_STATUS; | |
1288 | break; | |
1289 | case IDX_PKG_PERF: | |
1290 | offset = MSR_PKG_PERF_STATUS; | |
1291 | break; | |
1292 | case IDX_DRAM_PERF: | |
1293 | offset = MSR_DRAM_PERF_STATUS; | |
1294 | break; | |
1295 | default: | |
1296 | offset = -1; | |
1297 | } | |
1298 | return offset; | |
1299 | } | |
1300 | ||
13a779de | 1301 | int offset_to_idx(off_t offset) |
87e15da9 CY |
1302 | { |
1303 | int idx; | |
1304 | ||
1305 | switch (offset) { | |
1306 | case MSR_PKG_ENERGY_STATUS: | |
301b1d3a | 1307 | case MSR_PKG_ENERGY_STAT: |
87e15da9 CY |
1308 | idx = IDX_PKG_ENERGY; |
1309 | break; | |
1310 | case MSR_DRAM_ENERGY_STATUS: | |
1311 | idx = IDX_DRAM_ENERGY; | |
1312 | break; | |
1313 | case MSR_PP0_ENERGY_STATUS: | |
1314 | idx = IDX_PP0_ENERGY; | |
1315 | break; | |
1316 | case MSR_PP1_ENERGY_STATUS: | |
1317 | idx = IDX_PP1_ENERGY; | |
1318 | break; | |
1319 | case MSR_PKG_PERF_STATUS: | |
1320 | idx = IDX_PKG_PERF; | |
1321 | break; | |
1322 | case MSR_DRAM_PERF_STATUS: | |
1323 | idx = IDX_DRAM_PERF; | |
1324 | break; | |
1325 | default: | |
1326 | idx = -1; | |
1327 | } | |
1328 | return idx; | |
1329 | } | |
1330 | ||
1331 | int idx_valid(int idx) | |
1332 | { | |
1333 | switch (idx) { | |
1334 | case IDX_PKG_ENERGY: | |
86ba263d | 1335 | return platform->rapl_msrs & (RAPL_PKG | RAPL_AMD_F17H); |
87e15da9 | 1336 | case IDX_DRAM_ENERGY: |
86ba263d | 1337 | return platform->rapl_msrs & RAPL_DRAM; |
87e15da9 | 1338 | case IDX_PP0_ENERGY: |
86ba263d | 1339 | return platform->rapl_msrs & RAPL_CORE_ENERGY_STATUS; |
87e15da9 | 1340 | case IDX_PP1_ENERGY: |
86ba263d | 1341 | return platform->rapl_msrs & RAPL_GFX; |
87e15da9 | 1342 | case IDX_PKG_PERF: |
86ba263d | 1343 | return platform->rapl_msrs & RAPL_PKG_PERF_STATUS; |
87e15da9 | 1344 | case IDX_DRAM_PERF: |
86ba263d | 1345 | return platform->rapl_msrs & RAPL_DRAM_PERF_STATUS; |
87e15da9 CY |
1346 | default: |
1347 | return 0; | |
1348 | } | |
1349 | } | |
1b439f01 | 1350 | |
388e9c81 | 1351 | struct sys_counters { |
678a3bd1 LB |
1352 | unsigned int added_thread_counters; |
1353 | unsigned int added_core_counters; | |
1354 | unsigned int added_package_counters; | |
388e9c81 LB |
1355 | struct msr_counter *tp; |
1356 | struct msr_counter *cp; | |
1357 | struct msr_counter *pp; | |
1358 | } sys; | |
1359 | ||
4a1bb4da PW |
1360 | void free_sys_counters(void) |
1361 | { | |
1362 | struct msr_counter *p = sys.tp, *pnext = NULL; | |
1363 | while (p) { | |
1364 | pnext = p->next; | |
1365 | free(p); | |
1366 | p = pnext; | |
1367 | } | |
1368 | ||
1369 | p = sys.cp, pnext = NULL; | |
1370 | while (p) { | |
1371 | pnext = p->next; | |
1372 | free(p); | |
1373 | p = pnext; | |
1374 | } | |
1375 | ||
1376 | p = sys.pp, pnext = NULL; | |
1377 | while (p) { | |
1378 | pnext = p->next; | |
1379 | free(p); | |
1380 | p = pnext; | |
1381 | } | |
1382 | ||
1383 | sys.added_thread_counters = 0; | |
1384 | sys.added_core_counters = 0; | |
1385 | sys.added_package_counters = 0; | |
1386 | sys.tp = NULL; | |
1387 | sys.cp = NULL; | |
1388 | sys.pp = NULL; | |
1389 | } | |
1390 | ||
c98d5d94 LB |
1391 | struct system_summary { |
1392 | struct thread_data threads; | |
1393 | struct core_data cores; | |
1394 | struct pkg_data packages; | |
388e9c81 | 1395 | } average; |
c98d5d94 | 1396 | |
0e2d8f05 LB |
1397 | struct cpu_topology { |
1398 | int physical_package_id; | |
6de68fe1 | 1399 | int die_id; |
0e2d8f05 | 1400 | int logical_cpu_id; |
ef605741 PB |
1401 | int physical_node_id; |
1402 | int logical_node_id; /* 0-based count within the package */ | |
0e2d8f05 | 1403 | int physical_core_id; |
8cb48b32 | 1404 | int thread_id; |
1b439f01 | 1405 | cpu_set_t *put_ids; /* Processing Unit/Thread IDs */ |
0e2d8f05 | 1406 | } *cpus; |
c98d5d94 LB |
1407 | |
1408 | struct topo_params { | |
1409 | int num_packages; | |
6de68fe1 | 1410 | int num_die; |
c98d5d94 LB |
1411 | int num_cpus; |
1412 | int num_cores; | |
0fe37529 ZR |
1413 | int allowed_packages; |
1414 | int allowed_cpus; | |
1415 | int allowed_cores; | |
c98d5d94 | 1416 | int max_cpu_num; |
ef605741 | 1417 | int max_node_num; |
70a9c6e8 PB |
1418 | int nodes_per_pkg; |
1419 | int cores_per_node; | |
1420 | int threads_per_core; | |
c98d5d94 LB |
1421 | } topo; |
1422 | ||
1423 | struct timeval tv_even, tv_odd, tv_delta; | |
1424 | ||
1b439f01 | 1425 | int *irq_column_2_cpu; /* /proc/interrupts column numbers */ |
562a2d37 LB |
1426 | int *irqs_per_cpu; /* indexed by cpu_num */ |
1427 | ||
c25ef0e5 | 1428 | void setup_all_buffers(bool startup); |
c98d5d94 | 1429 | |
1f81c5ef LB |
1430 | char *sys_lpi_file; |
1431 | char *sys_lpi_file_sysfs = "/sys/devices/system/cpu/cpuidle/low_power_idle_system_residency_us"; | |
1432 | char *sys_lpi_file_debugfs = "/sys/kernel/debug/pmc_core/slp_s0_residency_usec"; | |
1433 | ||
c98d5d94 | 1434 | int cpu_is_not_present(int cpu) |
d15cf7c1 | 1435 | { |
c98d5d94 | 1436 | return !CPU_ISSET_S(cpu, cpu_present_setsize, cpu_present_set); |
d15cf7c1 | 1437 | } |
1b439f01 | 1438 | |
71cfd1da ZR |
1439 | int cpu_is_not_allowed(int cpu) |
1440 | { | |
1441 | return !CPU_ISSET_S(cpu, cpu_allowed_setsize, cpu_allowed_set); | |
1442 | } | |
1443 | ||
88c3281f | 1444 | /* |
c98d5d94 LB |
1445 | * run func(thread, core, package) in topology order |
1446 | * skip non-present cpus | |
88c3281f | 1447 | */ |
c98d5d94 | 1448 | |
1b439f01 LB |
1449 | int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pkg_data *), |
1450 | struct thread_data *thread_base, struct core_data *core_base, struct pkg_data *pkg_base) | |
88c3281f | 1451 | { |
40f5cfe7 | 1452 | int retval, pkg_no, core_no, thread_no, node_no; |
d15cf7c1 | 1453 | |
c98d5d94 | 1454 | for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) { |
df2f677d LB |
1455 | for (node_no = 0; node_no < topo.nodes_per_pkg; node_no++) { |
1456 | for (core_no = 0; core_no < topo.cores_per_node; ++core_no) { | |
1b439f01 | 1457 | for (thread_no = 0; thread_no < topo.threads_per_core; ++thread_no) { |
40f5cfe7 PB |
1458 | struct thread_data *t; |
1459 | struct core_data *c; | |
1460 | struct pkg_data *p; | |
1b439f01 | 1461 | t = GET_THREAD(thread_base, thread_no, core_no, node_no, pkg_no); |
40f5cfe7 | 1462 | |
4ede6d1c | 1463 | if (cpu_is_not_allowed(t->cpu_id)) |
40f5cfe7 PB |
1464 | continue; |
1465 | ||
1b439f01 | 1466 | c = GET_CORE(core_base, core_no, node_no, pkg_no); |
40f5cfe7 PB |
1467 | p = GET_PKG(pkg_base, pkg_no); |
1468 | ||
1469 | retval = func(t, c, p); | |
1470 | if (retval) | |
1471 | return retval; | |
1472 | } | |
c98d5d94 LB |
1473 | } |
1474 | } | |
1475 | } | |
1476 | return 0; | |
88c3281f LB |
1477 | } |
1478 | ||
74318add ZR |
1479 | int is_cpu_first_thread_in_core(struct thread_data *t, struct core_data *c, struct pkg_data *p) |
1480 | { | |
74318add ZR |
1481 | UNUSED(p); |
1482 | ||
ccf8a052 | 1483 | return ((int)t->cpu_id == c->base_cpu || c->base_cpu < 0); |
74318add ZR |
1484 | } |
1485 | ||
1486 | int is_cpu_first_core_in_package(struct thread_data *t, struct core_data *c, struct pkg_data *p) | |
1487 | { | |
1488 | UNUSED(c); | |
74318add | 1489 | |
ccf8a052 | 1490 | return ((int)t->cpu_id == p->base_cpu || p->base_cpu < 0); |
74318add ZR |
1491 | } |
1492 | ||
1493 | int is_cpu_first_thread_in_package(struct thread_data *t, struct core_data *c, struct pkg_data *p) | |
1494 | { | |
ccf8a052 | 1495 | return is_cpu_first_thread_in_core(t, c, p) && is_cpu_first_core_in_package(t, c, p); |
74318add ZR |
1496 | } |
1497 | ||
88c3281f LB |
1498 | int cpu_migrate(int cpu) |
1499 | { | |
c98d5d94 LB |
1500 | CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set); |
1501 | CPU_SET_S(cpu, cpu_affinity_setsize, cpu_affinity_set); | |
1502 | if (sched_setaffinity(0, cpu_affinity_setsize, cpu_affinity_set) == -1) | |
88c3281f LB |
1503 | return -1; |
1504 | else | |
1505 | return 0; | |
1506 | } | |
1b439f01 | 1507 | |
36229897 | 1508 | int get_msr_fd(int cpu) |
103a8fea | 1509 | { |
103a8fea LB |
1510 | char pathname[32]; |
1511 | int fd; | |
1512 | ||
36229897 LB |
1513 | fd = fd_percpu[cpu]; |
1514 | ||
1515 | if (fd) | |
1516 | return fd; | |
1517 | ||
103a8fea LB |
1518 | sprintf(pathname, "/dev/cpu/%d/msr", cpu); |
1519 | fd = open(pathname, O_RDONLY); | |
15aaa346 | 1520 | if (fd < 0) |
3e404846 PW |
1521 | err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, " |
1522 | "or run with --no-msr, or run as root", pathname); | |
103a8fea | 1523 | |
36229897 LB |
1524 | fd_percpu[cpu] = fd; |
1525 | ||
1526 | return fd; | |
1527 | } | |
1528 | ||
3e404846 PW |
1529 | static void bic_disable_msr_access(void) |
1530 | { | |
1531 | const unsigned long bic_msrs = | |
3e404846 PW |
1532 | BIC_SMI | |
1533 | BIC_CPU_c1 | | |
1534 | BIC_CPU_c3 | | |
1535 | BIC_CPU_c6 | | |
1536 | BIC_CPU_c7 | | |
1537 | BIC_Mod_c6 | | |
1538 | BIC_CoreTmp | | |
1539 | BIC_Totl_c0 | | |
1540 | BIC_Any_c0 | | |
1541 | BIC_GFX_c0 | | |
1542 | BIC_CPUGFX | | |
1543 | BIC_Pkgpc2 | BIC_Pkgpc3 | BIC_Pkgpc6 | BIC_Pkgpc7 | BIC_Pkgpc8 | BIC_Pkgpc9 | BIC_Pkgpc10 | BIC_PkgTmp; | |
1544 | ||
1545 | bic_enabled &= ~bic_msrs; | |
4a1bb4da PW |
1546 | |
1547 | free_sys_counters(); | |
3e404846 PW |
1548 | } |
1549 | ||
2af4f9b8 LB |
1550 | static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags) |
1551 | { | |
a0e86c90 PW |
1552 | assert(!no_perf); |
1553 | ||
2af4f9b8 LB |
1554 | return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags); |
1555 | } | |
1556 | ||
5088741e | 1557 | static long open_perf_counter(int cpu, unsigned int type, unsigned int config, int group_fd, __u64 read_format) |
2af4f9b8 | 1558 | { |
e48934c9 PW |
1559 | struct perf_event_attr attr; |
1560 | const pid_t pid = -1; | |
1561 | const unsigned long flags = 0; | |
1562 | ||
5088741e PW |
1563 | assert(!no_perf); |
1564 | ||
e48934c9 | 1565 | memset(&attr, 0, sizeof(struct perf_event_attr)); |
2af4f9b8 | 1566 | |
e48934c9 PW |
1567 | attr.type = type; |
1568 | attr.size = sizeof(struct perf_event_attr); | |
1569 | attr.config = config; | |
1570 | attr.disabled = 0; | |
1571 | attr.sample_type = PERF_SAMPLE_IDENTIFIER; | |
1572 | attr.read_format = read_format; | |
2af4f9b8 | 1573 | |
e48934c9 | 1574 | const int fd = perf_event_open(&attr, pid, cpu, group_fd, flags); |
2af4f9b8 LB |
1575 | |
1576 | return fd; | |
1577 | } | |
1578 | ||
1579 | int get_instr_count_fd(int cpu) | |
1580 | { | |
1581 | if (fd_instr_count_percpu[cpu]) | |
1582 | return fd_instr_count_percpu[cpu]; | |
1583 | ||
5088741e | 1584 | fd_instr_count_percpu[cpu] = open_perf_counter(cpu, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS, -1, 0); |
2af4f9b8 LB |
1585 | |
1586 | return fd_instr_count_percpu[cpu]; | |
1587 | } | |
1588 | ||
36229897 LB |
1589 | int get_msr(int cpu, off_t offset, unsigned long long *msr) |
1590 | { | |
1591 | ssize_t retval; | |
1592 | ||
3e404846 PW |
1593 | assert(!no_msr); |
1594 | ||
36229897 | 1595 | retval = pread(get_msr_fd(cpu), msr, sizeof(*msr), offset); |
15aaa346 | 1596 | |
98481e79 | 1597 | if (retval != sizeof *msr) |
cf4cbe53 | 1598 | err(-1, "cpu%d: msr offset 0x%llx read failed", cpu, (unsigned long long)offset); |
15aaa346 LB |
1599 | |
1600 | return 0; | |
103a8fea LB |
1601 | } |
1602 | ||
05a2f07d PW |
1603 | int probe_msr(int cpu, off_t offset) |
1604 | { | |
1605 | ssize_t retval; | |
1606 | unsigned long long dummy; | |
1607 | ||
1608 | assert(!no_msr); | |
1609 | ||
1610 | retval = pread(get_msr_fd(cpu), &dummy, sizeof(dummy), offset); | |
1611 | ||
1612 | if (retval != sizeof(dummy)) | |
1613 | return 1; | |
1614 | ||
1615 | return 0; | |
1616 | } | |
1617 | ||
dd778a5e | 1618 | #define MAX_DEFERRED 16 |
0fc521bc | 1619 | char *deferred_add_names[MAX_DEFERRED]; |
dd778a5e | 1620 | char *deferred_skip_names[MAX_DEFERRED]; |
0fc521bc | 1621 | int deferred_add_index; |
dd778a5e LB |
1622 | int deferred_skip_index; |
1623 | ||
1624 | /* | |
1625 | * HIDE_LIST - hide this list of counters, show the rest [default] | |
1626 | * SHOW_LIST - show this list of counters, hide the rest | |
1627 | */ | |
1628 | enum show_hide_mode { SHOW_LIST, HIDE_LIST } global_show_hide_mode = HIDE_LIST; | |
1629 | ||
1630 | void help(void) | |
1631 | { | |
1632 | fprintf(outf, | |
1b439f01 LB |
1633 | "Usage: turbostat [OPTIONS][(--interval seconds) | COMMAND ...]\n" |
1634 | "\n" | |
1635 | "Turbostat forks the specified COMMAND and prints statistics\n" | |
1636 | "when COMMAND completes.\n" | |
1637 | "If no COMMAND is specified, turbostat wakes every 5-seconds\n" | |
1638 | "to print statistics, until interrupted.\n" | |
1639 | " -a, --add add a counter\n" | |
1640 | " eg. --add msr0x10,u64,cpu,delta,MY_TSC\n" | |
1641 | " -c, --cpu cpu-set limit output to summary plus cpu-set:\n" | |
1642 | " {core | package | j,k,l..m,n-p }\n" | |
1643 | " -d, --debug displays usec, Time_Of_Day_Seconds and more debugging\n" | |
1644 | " -D, --Dump displays the raw counter values\n" | |
1645 | " -e, --enable [all | column]\n" | |
1646 | " shows all or the specified disabled column\n" | |
1647 | " -H, --hide [column|column,column,...]\n" | |
1648 | " hide the specified column(s)\n" | |
1649 | " -i, --interval sec.subsec\n" | |
1650 | " Override default 5-second measurement interval\n" | |
1651 | " -J, --Joules displays energy in Joules instead of Watts\n" | |
1652 | " -l, --list list column headers only\n" | |
3e404846 | 1653 | " -M, --no-msr Disable all uses of the MSR driver\n" |
a0e86c90 | 1654 | " -P, --no-perf Disable all uses of the perf API\n" |
1b439f01 LB |
1655 | " -n, --num_iterations num\n" |
1656 | " number of the measurement iterations\n" | |
c7e399f8 ZLCH |
1657 | " -N, --header_iterations num\n" |
1658 | " print header every num iterations\n" | |
1b439f01 LB |
1659 | " -o, --out file\n" |
1660 | " create or truncate \"file\" for all output\n" | |
1661 | " -q, --quiet skip decoding system configuration header\n" | |
1662 | " -s, --show [column|column,column,...]\n" | |
1663 | " show only the specified column(s)\n" | |
1664 | " -S, --Summary\n" | |
1665 | " limits output to 1-line system summary per interval\n" | |
1666 | " -T, --TCC temperature\n" | |
1667 | " sets the Thermal Control Circuit temperature in\n" | |
1668 | " degrees Celsius\n" | |
1669 | " -h, --help print this help message\n" | |
1670 | " -v, --version print version information\n" "\n" "For more help, run \"man turbostat\"\n"); | |
dd778a5e LB |
1671 | } |
1672 | ||
812db3f7 LB |
1673 | /* |
1674 | * bic_lookup | |
1675 | * for all the strings in comma separate name_list, | |
1676 | * set the approprate bit in return value. | |
1677 | */ | |
dd778a5e | 1678 | unsigned long long bic_lookup(char *name_list, enum show_hide_mode mode) |
812db3f7 | 1679 | { |
9878bf7a | 1680 | unsigned int i; |
812db3f7 LB |
1681 | unsigned long long retval = 0; |
1682 | ||
1683 | while (name_list) { | |
1684 | char *comma; | |
1685 | ||
1686 | comma = strchr(name_list, ','); | |
1687 | ||
1688 | if (comma) | |
1689 | *comma = '\0'; | |
1690 | ||
1691 | for (i = 0; i < MAX_BIC; ++i) { | |
1692 | if (!strcmp(name_list, bic[i].name)) { | |
1693 | retval |= (1ULL << i); | |
1694 | break; | |
1695 | } | |
5dc241f2 LB |
1696 | if (!strcmp(name_list, "all")) { |
1697 | retval |= ~0; | |
1698 | break; | |
1699 | } else if (!strcmp(name_list, "topology")) { | |
1700 | retval |= BIC_TOPOLOGY; | |
1701 | break; | |
1702 | } else if (!strcmp(name_list, "power")) { | |
1703 | retval |= BIC_THERMAL_PWR; | |
1704 | break; | |
1705 | } else if (!strcmp(name_list, "idle")) { | |
1706 | retval |= BIC_IDLE; | |
1707 | break; | |
1708 | } else if (!strcmp(name_list, "frequency")) { | |
1709 | retval |= BIC_FREQUENCY; | |
1710 | break; | |
1711 | } else if (!strcmp(name_list, "other")) { | |
1712 | retval |= BIC_OTHER; | |
1713 | break; | |
1714 | } | |
1715 | ||
812db3f7 LB |
1716 | } |
1717 | if (i == MAX_BIC) { | |
dd778a5e | 1718 | if (mode == SHOW_LIST) { |
0fc521bc ZLCH |
1719 | deferred_add_names[deferred_add_index++] = name_list; |
1720 | if (deferred_add_index >= MAX_DEFERRED) { | |
1721 | fprintf(stderr, "More than max %d un-recognized --add options '%s'\n", | |
164d7a96 | 1722 | MAX_DEFERRED, name_list); |
0fc521bc ZLCH |
1723 | help(); |
1724 | exit(1); | |
1725 | } | |
1726 | } else { | |
1727 | deferred_skip_names[deferred_skip_index++] = name_list; | |
1728 | if (debug) | |
1729 | fprintf(stderr, "deferred \"%s\"\n", name_list); | |
1730 | if (deferred_skip_index >= MAX_DEFERRED) { | |
1731 | fprintf(stderr, "More than max %d un-recognized --skip options '%s'\n", | |
164d7a96 | 1732 | MAX_DEFERRED, name_list); |
0fc521bc ZLCH |
1733 | help(); |
1734 | exit(1); | |
1735 | } | |
dd778a5e | 1736 | } |
812db3f7 LB |
1737 | } |
1738 | ||
1739 | name_list = comma; | |
1740 | if (name_list) | |
1741 | name_list++; | |
1742 | ||
1743 | } | |
1744 | return retval; | |
1745 | } | |
fc04cc67 | 1746 | |
c8ade361 | 1747 | void print_header(char *delim) |
103a8fea | 1748 | { |
388e9c81 | 1749 | struct msr_counter *mp; |
6168c2e0 | 1750 | int printed = 0; |
388e9c81 | 1751 | |
3f44a5c6 LB |
1752 | if (DO_BIC(BIC_USEC)) |
1753 | outp += sprintf(outp, "%susec", (printed++ ? delim : "")); | |
1754 | if (DO_BIC(BIC_TOD)) | |
1755 | outp += sprintf(outp, "%sTime_Of_Day_Seconds", (printed++ ? delim : "")); | |
812db3f7 | 1756 | if (DO_BIC(BIC_Package)) |
6168c2e0 | 1757 | outp += sprintf(outp, "%sPackage", (printed++ ? delim : "")); |
6de68fe1 LB |
1758 | if (DO_BIC(BIC_Die)) |
1759 | outp += sprintf(outp, "%sDie", (printed++ ? delim : "")); | |
01235041 PB |
1760 | if (DO_BIC(BIC_Node)) |
1761 | outp += sprintf(outp, "%sNode", (printed++ ? delim : "")); | |
812db3f7 | 1762 | if (DO_BIC(BIC_Core)) |
6168c2e0 | 1763 | outp += sprintf(outp, "%sCore", (printed++ ? delim : "")); |
812db3f7 | 1764 | if (DO_BIC(BIC_CPU)) |
6168c2e0 | 1765 | outp += sprintf(outp, "%sCPU", (printed++ ? delim : "")); |
4c2122d4 LB |
1766 | if (DO_BIC(BIC_APIC)) |
1767 | outp += sprintf(outp, "%sAPIC", (printed++ ? delim : "")); | |
1768 | if (DO_BIC(BIC_X2APIC)) | |
1769 | outp += sprintf(outp, "%sX2APIC", (printed++ ? delim : "")); | |
812db3f7 | 1770 | if (DO_BIC(BIC_Avg_MHz)) |
6168c2e0 | 1771 | outp += sprintf(outp, "%sAvg_MHz", (printed++ ? delim : "")); |
812db3f7 | 1772 | if (DO_BIC(BIC_Busy)) |
6168c2e0 | 1773 | outp += sprintf(outp, "%sBusy%%", (printed++ ? delim : "")); |
812db3f7 | 1774 | if (DO_BIC(BIC_Bzy_MHz)) |
6168c2e0 | 1775 | outp += sprintf(outp, "%sBzy_MHz", (printed++ ? delim : "")); |
812db3f7 | 1776 | if (DO_BIC(BIC_TSC_MHz)) |
6168c2e0 | 1777 | outp += sprintf(outp, "%sTSC_MHz", (printed++ ? delim : "")); |
1cc21f7b | 1778 | |
2af4f9b8 LB |
1779 | if (DO_BIC(BIC_IPC)) |
1780 | outp += sprintf(outp, "%sIPC", (printed++ ? delim : "")); | |
1781 | ||
0de6c0df LB |
1782 | if (DO_BIC(BIC_IRQ)) { |
1783 | if (sums_need_wide_columns) | |
6168c2e0 | 1784 | outp += sprintf(outp, "%s IRQ", (printed++ ? delim : "")); |
0de6c0df | 1785 | else |
6168c2e0 | 1786 | outp += sprintf(outp, "%sIRQ", (printed++ ? delim : "")); |
0de6c0df LB |
1787 | } |
1788 | ||
812db3f7 | 1789 | if (DO_BIC(BIC_SMI)) |
6168c2e0 | 1790 | outp += sprintf(outp, "%sSMI", (printed++ ? delim : "")); |
1cc21f7b | 1791 | |
388e9c81 | 1792 | for (mp = sys.tp; mp; mp = mp->next) { |
dd778a5e | 1793 | |
388e9c81 LB |
1794 | if (mp->format == FORMAT_RAW) { |
1795 | if (mp->width == 64) | |
dd778a5e | 1796 | outp += sprintf(outp, "%s%18.18s", (printed++ ? delim : ""), mp->name); |
388e9c81 | 1797 | else |
dd778a5e | 1798 | outp += sprintf(outp, "%s%10.10s", (printed++ ? delim : ""), mp->name); |
388e9c81 | 1799 | } else { |
0de6c0df | 1800 | if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns) |
dd778a5e | 1801 | outp += sprintf(outp, "%s%8s", (printed++ ? delim : ""), mp->name); |
0de6c0df | 1802 | else |
dd778a5e | 1803 | outp += sprintf(outp, "%s%s", (printed++ ? delim : ""), mp->name); |
388e9c81 LB |
1804 | } |
1805 | } | |
1806 | ||
41618e63 | 1807 | if (DO_BIC(BIC_CPU_c1)) |
6168c2e0 | 1808 | outp += sprintf(outp, "%sCPU%%c1", (printed++ ? delim : "")); |
562855ee | 1809 | if (DO_BIC(BIC_CPU_c3)) |
6168c2e0 | 1810 | outp += sprintf(outp, "%sCPU%%c3", (printed++ ? delim : "")); |
812db3f7 | 1811 | if (DO_BIC(BIC_CPU_c6)) |
6168c2e0 | 1812 | outp += sprintf(outp, "%sCPU%%c6", (printed++ ? delim : "")); |
812db3f7 | 1813 | if (DO_BIC(BIC_CPU_c7)) |
6168c2e0 | 1814 | outp += sprintf(outp, "%sCPU%%c7", (printed++ ? delim : "")); |
678a3bd1 | 1815 | |
0539ba11 | 1816 | if (DO_BIC(BIC_Mod_c6)) |
6168c2e0 | 1817 | outp += sprintf(outp, "%sMod%%c6", (printed++ ? delim : "")); |
678a3bd1 | 1818 | |
812db3f7 | 1819 | if (DO_BIC(BIC_CoreTmp)) |
6168c2e0 | 1820 | outp += sprintf(outp, "%sCoreTmp", (printed++ ? delim : "")); |
388e9c81 | 1821 | |
eae97e05 CY |
1822 | if (DO_BIC(BIC_CORE_THROT_CNT)) |
1823 | outp += sprintf(outp, "%sCoreThr", (printed++ ? delim : "")); | |
1824 | ||
86ba263d | 1825 | if (platform->rapl_msrs && !rapl_joules) { |
e338831b | 1826 | if (DO_BIC(BIC_CorWatt) && platform->has_per_core_rapl) |
9392bd98 | 1827 | outp += sprintf(outp, "%sCorWatt", (printed++ ? delim : "")); |
86ba263d | 1828 | } else if (platform->rapl_msrs && rapl_joules) { |
e338831b | 1829 | if (DO_BIC(BIC_Cor_J) && platform->has_per_core_rapl) |
9392bd98 CW |
1830 | outp += sprintf(outp, "%sCor_J", (printed++ ? delim : "")); |
1831 | } | |
1832 | ||
388e9c81 LB |
1833 | for (mp = sys.cp; mp; mp = mp->next) { |
1834 | if (mp->format == FORMAT_RAW) { | |
1835 | if (mp->width == 64) | |
c8ade361 | 1836 | outp += sprintf(outp, "%s%18.18s", delim, mp->name); |
388e9c81 | 1837 | else |
c8ade361 | 1838 | outp += sprintf(outp, "%s%10.10s", delim, mp->name); |
388e9c81 | 1839 | } else { |
0de6c0df LB |
1840 | if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns) |
1841 | outp += sprintf(outp, "%s%8s", delim, mp->name); | |
1842 | else | |
1843 | outp += sprintf(outp, "%s%s", delim, mp->name); | |
388e9c81 LB |
1844 | } |
1845 | } | |
1846 | ||
812db3f7 | 1847 | if (DO_BIC(BIC_PkgTmp)) |
6168c2e0 | 1848 | outp += sprintf(outp, "%sPkgTmp", (printed++ ? delim : "")); |
889facbe | 1849 | |
812db3f7 | 1850 | if (DO_BIC(BIC_GFX_rc6)) |
6168c2e0 | 1851 | outp += sprintf(outp, "%sGFX%%rc6", (printed++ ? delim : "")); |
fdf676e5 | 1852 | |
812db3f7 | 1853 | if (DO_BIC(BIC_GFXMHz)) |
6168c2e0 | 1854 | outp += sprintf(outp, "%sGFXMHz", (printed++ ? delim : "")); |
27d47356 | 1855 | |
b4b91569 RA |
1856 | if (DO_BIC(BIC_GFXACTMHz)) |
1857 | outp += sprintf(outp, "%sGFXAMHz", (printed++ ? delim : "")); | |
1858 | ||
3bbb331c ZR |
1859 | if (DO_BIC(BIC_SAM_mc6)) |
1860 | outp += sprintf(outp, "%sSAM%%mc6", (printed++ ? delim : "")); | |
1861 | ||
1862 | if (DO_BIC(BIC_SAMMHz)) | |
1863 | outp += sprintf(outp, "%sSAMMHz", (printed++ ? delim : "")); | |
1864 | ||
1865 | if (DO_BIC(BIC_SAMACTMHz)) | |
1866 | outp += sprintf(outp, "%sSAMAMHz", (printed++ ? delim : "")); | |
1867 | ||
a99d8730 | 1868 | if (DO_BIC(BIC_Totl_c0)) |
6168c2e0 | 1869 | outp += sprintf(outp, "%sTotl%%C0", (printed++ ? delim : "")); |
a99d8730 | 1870 | if (DO_BIC(BIC_Any_c0)) |
6168c2e0 | 1871 | outp += sprintf(outp, "%sAny%%C0", (printed++ ? delim : "")); |
a99d8730 | 1872 | if (DO_BIC(BIC_GFX_c0)) |
6168c2e0 | 1873 | outp += sprintf(outp, "%sGFX%%C0", (printed++ ? delim : "")); |
a99d8730 | 1874 | if (DO_BIC(BIC_CPUGFX)) |
6168c2e0 | 1875 | outp += sprintf(outp, "%sCPUGFX%%", (printed++ ? delim : "")); |
0b2bb692 | 1876 | |
0f47c08d | 1877 | if (DO_BIC(BIC_Pkgpc2)) |
6168c2e0 | 1878 | outp += sprintf(outp, "%sPkg%%pc2", (printed++ ? delim : "")); |
0f47c08d | 1879 | if (DO_BIC(BIC_Pkgpc3)) |
6168c2e0 | 1880 | outp += sprintf(outp, "%sPkg%%pc3", (printed++ ? delim : "")); |
0f47c08d | 1881 | if (DO_BIC(BIC_Pkgpc6)) |
6168c2e0 | 1882 | outp += sprintf(outp, "%sPkg%%pc6", (printed++ ? delim : "")); |
0f47c08d | 1883 | if (DO_BIC(BIC_Pkgpc7)) |
6168c2e0 | 1884 | outp += sprintf(outp, "%sPkg%%pc7", (printed++ ? delim : "")); |
0f47c08d | 1885 | if (DO_BIC(BIC_Pkgpc8)) |
6168c2e0 | 1886 | outp += sprintf(outp, "%sPkg%%pc8", (printed++ ? delim : "")); |
0f47c08d | 1887 | if (DO_BIC(BIC_Pkgpc9)) |
6168c2e0 | 1888 | outp += sprintf(outp, "%sPkg%%pc9", (printed++ ? delim : "")); |
0f47c08d | 1889 | if (DO_BIC(BIC_Pkgpc10)) |
6168c2e0 | 1890 | outp += sprintf(outp, "%sPk%%pc10", (printed++ ? delim : "")); |
be0e54c4 LB |
1891 | if (DO_BIC(BIC_CPU_LPI)) |
1892 | outp += sprintf(outp, "%sCPU%%LPI", (printed++ ? delim : "")); | |
1893 | if (DO_BIC(BIC_SYS_LPI)) | |
1894 | outp += sprintf(outp, "%sSYS%%LPI", (printed++ ? delim : "")); | |
103a8fea | 1895 | |
86ba263d | 1896 | if (platform->rapl_msrs && !rapl_joules) { |
812db3f7 | 1897 | if (DO_BIC(BIC_PkgWatt)) |
6168c2e0 | 1898 | outp += sprintf(outp, "%sPkgWatt", (printed++ ? delim : "")); |
e338831b | 1899 | if (DO_BIC(BIC_CorWatt) && !platform->has_per_core_rapl) |
6168c2e0 | 1900 | outp += sprintf(outp, "%sCorWatt", (printed++ ? delim : "")); |
812db3f7 | 1901 | if (DO_BIC(BIC_GFXWatt)) |
6168c2e0 | 1902 | outp += sprintf(outp, "%sGFXWatt", (printed++ ? delim : "")); |
812db3f7 | 1903 | if (DO_BIC(BIC_RAMWatt)) |
6168c2e0 | 1904 | outp += sprintf(outp, "%sRAMWatt", (printed++ ? delim : "")); |
812db3f7 | 1905 | if (DO_BIC(BIC_PKG__)) |
6168c2e0 | 1906 | outp += sprintf(outp, "%sPKG_%%", (printed++ ? delim : "")); |
812db3f7 | 1907 | if (DO_BIC(BIC_RAM__)) |
6168c2e0 | 1908 | outp += sprintf(outp, "%sRAM_%%", (printed++ ? delim : "")); |
86ba263d | 1909 | } else if (platform->rapl_msrs && rapl_joules) { |
812db3f7 | 1910 | if (DO_BIC(BIC_Pkg_J)) |
6168c2e0 | 1911 | outp += sprintf(outp, "%sPkg_J", (printed++ ? delim : "")); |
e338831b | 1912 | if (DO_BIC(BIC_Cor_J) && !platform->has_per_core_rapl) |
6168c2e0 | 1913 | outp += sprintf(outp, "%sCor_J", (printed++ ? delim : "")); |
812db3f7 | 1914 | if (DO_BIC(BIC_GFX_J)) |
6168c2e0 | 1915 | outp += sprintf(outp, "%sGFX_J", (printed++ ? delim : "")); |
812db3f7 | 1916 | if (DO_BIC(BIC_RAM_J)) |
6168c2e0 | 1917 | outp += sprintf(outp, "%sRAM_J", (printed++ ? delim : "")); |
812db3f7 | 1918 | if (DO_BIC(BIC_PKG__)) |
6168c2e0 | 1919 | outp += sprintf(outp, "%sPKG_%%", (printed++ ? delim : "")); |
812db3f7 | 1920 | if (DO_BIC(BIC_RAM__)) |
6168c2e0 | 1921 | outp += sprintf(outp, "%sRAM_%%", (printed++ ? delim : "")); |
5c56be9a | 1922 | } |
a5c6d65d LB |
1923 | if (DO_BIC(BIC_UNCORE_MHZ)) |
1924 | outp += sprintf(outp, "%sUncMHz", (printed++ ? delim : "")); | |
1925 | ||
388e9c81 LB |
1926 | for (mp = sys.pp; mp; mp = mp->next) { |
1927 | if (mp->format == FORMAT_RAW) { | |
1928 | if (mp->width == 64) | |
c8ade361 | 1929 | outp += sprintf(outp, "%s%18.18s", delim, mp->name); |
388e9c81 | 1930 | else |
c8ade361 | 1931 | outp += sprintf(outp, "%s%10.10s", delim, mp->name); |
388e9c81 | 1932 | } else { |
0de6c0df LB |
1933 | if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns) |
1934 | outp += sprintf(outp, "%s%8s", delim, mp->name); | |
1935 | else | |
1936 | outp += sprintf(outp, "%s%s", delim, mp->name); | |
388e9c81 LB |
1937 | } |
1938 | } | |
1939 | ||
c98d5d94 | 1940 | outp += sprintf(outp, "\n"); |
103a8fea LB |
1941 | } |
1942 | ||
1b439f01 | 1943 | int dump_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) |
103a8fea | 1944 | { |
388e9c81 LB |
1945 | int i; |
1946 | struct msr_counter *mp; | |
1947 | ||
3b4d5c7f | 1948 | outp += sprintf(outp, "t %p, c %p, p %p\n", t, c, p); |
c98d5d94 LB |
1949 | |
1950 | if (t) { | |
1b439f01 | 1951 | outp += sprintf(outp, "CPU: %d flags 0x%x\n", t->cpu_id, t->flags); |
3b4d5c7f AS |
1952 | outp += sprintf(outp, "TSC: %016llX\n", t->tsc); |
1953 | outp += sprintf(outp, "aperf: %016llX\n", t->aperf); | |
1954 | outp += sprintf(outp, "mperf: %016llX\n", t->mperf); | |
1955 | outp += sprintf(outp, "c1: %016llX\n", t->c1); | |
6886fee4 | 1956 | |
2af4f9b8 LB |
1957 | if (DO_BIC(BIC_IPC)) |
1958 | outp += sprintf(outp, "IPC: %lld\n", t->instr_count); | |
1959 | ||
812db3f7 | 1960 | if (DO_BIC(BIC_IRQ)) |
0de6c0df | 1961 | outp += sprintf(outp, "IRQ: %lld\n", t->irq_count); |
812db3f7 | 1962 | if (DO_BIC(BIC_SMI)) |
218f0e8d | 1963 | outp += sprintf(outp, "SMI: %d\n", t->smi_count); |
388e9c81 LB |
1964 | |
1965 | for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) { | |
2d2ccd57 LB |
1966 | outp += |
1967 | sprintf(outp, "tADDED [%d] %8s msr0x%x: %08llX %s\n", i, mp->name, mp->msr_num, | |
1968 | t->counter[i], mp->path); | |
388e9c81 | 1969 | } |
c98d5d94 | 1970 | } |
103a8fea | 1971 | |
2d2ccd57 | 1972 | if (c && is_cpu_first_thread_in_core(t, c, p)) { |
3b4d5c7f AS |
1973 | outp += sprintf(outp, "core: %d\n", c->core_id); |
1974 | outp += sprintf(outp, "c3: %016llX\n", c->c3); | |
1975 | outp += sprintf(outp, "c6: %016llX\n", c->c6); | |
1976 | outp += sprintf(outp, "c7: %016llX\n", c->c7); | |
1977 | outp += sprintf(outp, "DTS: %dC\n", c->core_temp_c); | |
eae97e05 | 1978 | outp += sprintf(outp, "cpu_throt_count: %016llX\n", c->core_throt_cnt); |
05a2f07d PW |
1979 | |
1980 | const unsigned long long energy_value = c->core_energy.raw_value * c->core_energy.scale; | |
1981 | const double energy_scale = c->core_energy.scale; | |
1982 | if (c->core_energy.unit == RAPL_UNIT_JOULES) | |
1983 | outp += sprintf(outp, "Joules: %0llX (scale: %lf)\n", energy_value, energy_scale); | |
388e9c81 LB |
1984 | |
1985 | for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) { | |
2d2ccd57 LB |
1986 | outp += |
1987 | sprintf(outp, "cADDED [%d] %8s msr0x%x: %08llX %s\n", i, mp->name, mp->msr_num, | |
1988 | c->counter[i], mp->path); | |
388e9c81 | 1989 | } |
0539ba11 | 1990 | outp += sprintf(outp, "mc6_us: %016llX\n", c->mc6_us); |
c98d5d94 | 1991 | } |
103a8fea | 1992 | |
2d2ccd57 | 1993 | if (p && is_cpu_first_core_in_package(t, c, p)) { |
3b4d5c7f | 1994 | outp += sprintf(outp, "package: %d\n", p->package_id); |
0b2bb692 LB |
1995 | |
1996 | outp += sprintf(outp, "Weighted cores: %016llX\n", p->pkg_wtd_core_c0); | |
1997 | outp += sprintf(outp, "Any cores: %016llX\n", p->pkg_any_core_c0); | |
1998 | outp += sprintf(outp, "Any GFX: %016llX\n", p->pkg_any_gfxe_c0); | |
1999 | outp += sprintf(outp, "CPU + GFX: %016llX\n", p->pkg_both_core_gfxe_c0); | |
2000 | ||
3b4d5c7f | 2001 | outp += sprintf(outp, "pc2: %016llX\n", p->pc2); |
0f47c08d | 2002 | if (DO_BIC(BIC_Pkgpc3)) |
ee7e38e3 | 2003 | outp += sprintf(outp, "pc3: %016llX\n", p->pc3); |
0f47c08d | 2004 | if (DO_BIC(BIC_Pkgpc6)) |
ee7e38e3 | 2005 | outp += sprintf(outp, "pc6: %016llX\n", p->pc6); |
0f47c08d | 2006 | if (DO_BIC(BIC_Pkgpc7)) |
ee7e38e3 | 2007 | outp += sprintf(outp, "pc7: %016llX\n", p->pc7); |
3b4d5c7f AS |
2008 | outp += sprintf(outp, "pc8: %016llX\n", p->pc8); |
2009 | outp += sprintf(outp, "pc9: %016llX\n", p->pc9); | |
2010 | outp += sprintf(outp, "pc10: %016llX\n", p->pc10); | |
be0e54c4 LB |
2011 | outp += sprintf(outp, "cpu_lpi: %016llX\n", p->cpu_lpi); |
2012 | outp += sprintf(outp, "sys_lpi: %016llX\n", p->sys_lpi); | |
05a2f07d PW |
2013 | outp += sprintf(outp, "Joules PKG: %0llX\n", p->energy_pkg.raw_value); |
2014 | outp += sprintf(outp, "Joules COR: %0llX\n", p->energy_cores.raw_value); | |
2015 | outp += sprintf(outp, "Joules GFX: %0llX\n", p->energy_gfx.raw_value); | |
2016 | outp += sprintf(outp, "Joules RAM: %0llX\n", p->energy_dram.raw_value); | |
2017 | outp += sprintf(outp, "Throttle PKG: %0llX\n", p->rapl_pkg_perf_status.raw_value); | |
2018 | outp += sprintf(outp, "Throttle RAM: %0llX\n", p->rapl_dram_perf_status.raw_value); | |
3b4d5c7f | 2019 | outp += sprintf(outp, "PTM: %dC\n", p->pkg_temp_c); |
388e9c81 LB |
2020 | |
2021 | for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) { | |
2d2ccd57 LB |
2022 | outp += |
2023 | sprintf(outp, "pADDED [%d] %8s msr0x%x: %08llX %s\n", i, mp->name, mp->msr_num, | |
2024 | p->counter[i], mp->path); | |
388e9c81 | 2025 | } |
c98d5d94 | 2026 | } |
3b4d5c7f AS |
2027 | |
2028 | outp += sprintf(outp, "\n"); | |
2029 | ||
c98d5d94 | 2030 | return 0; |
103a8fea LB |
2031 | } |
2032 | ||
05a2f07d PW |
2033 | double rapl_counter_get_value(const struct rapl_counter *c, enum rapl_unit desired_unit, double interval) |
2034 | { | |
2035 | assert(desired_unit != RAPL_UNIT_INVALID); | |
2036 | ||
2037 | /* | |
2038 | * For now we don't expect anything other than joules, | |
2039 | * so just simplify the logic. | |
2040 | */ | |
2041 | assert(c->unit == RAPL_UNIT_JOULES); | |
2042 | ||
2043 | const double scaled = c->raw_value * c->scale; | |
2044 | ||
2045 | if (desired_unit == RAPL_UNIT_WATTS) | |
2046 | return scaled / interval; | |
2047 | return scaled; | |
2048 | } | |
2049 | ||
e23da037 LB |
2050 | /* |
2051 | * column formatting convention & formats | |
e23da037 | 2052 | */ |
1b439f01 | 2053 | int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) |
103a8fea | 2054 | { |
008d396e | 2055 | double interval_float, tsc; |
fc04cc67 | 2056 | char *fmt8; |
388e9c81 LB |
2057 | int i; |
2058 | struct msr_counter *mp; | |
6168c2e0 LB |
2059 | char *delim = "\t"; |
2060 | int printed = 0; | |
103a8fea | 2061 | |
1b439f01 | 2062 | /* if showing only 1st thread in core and this isn't one, bail out */ |
74318add | 2063 | if (show_core_only && !is_cpu_first_thread_in_core(t, c, p)) |
c98d5d94 LB |
2064 | return 0; |
2065 | ||
1b439f01 | 2066 | /* if showing only 1st thread in pkg and this isn't one, bail out */ |
74318add | 2067 | if (show_pkg_only && !is_cpu_first_core_in_package(t, c, p)) |
c98d5d94 LB |
2068 | return 0; |
2069 | ||
1ef7d21a | 2070 | /*if not summary line and --cpu is used */ |
1b439f01 | 2071 | if ((t != &average.threads) && (cpu_subset && !CPU_ISSET_S(t->cpu_id, cpu_subset_size, cpu_subset))) |
1ef7d21a LB |
2072 | return 0; |
2073 | ||
3f44a5c6 | 2074 | if (DO_BIC(BIC_USEC)) { |
f4fdf2b4 LB |
2075 | /* on each row, print how many usec each timestamp took to gather */ |
2076 | struct timeval tv; | |
2077 | ||
2078 | timersub(&t->tv_end, &t->tv_begin, &tv); | |
2079 | outp += sprintf(outp, "%5ld\t", tv.tv_sec * 1000000 + tv.tv_usec); | |
2080 | } | |
2081 | ||
3f44a5c6 LB |
2082 | /* Time_Of_Day_Seconds: on each row, print sec.usec last timestamp taken */ |
2083 | if (DO_BIC(BIC_TOD)) | |
2084 | outp += sprintf(outp, "%10ld.%06ld\t", t->tv_end.tv_sec, t->tv_end.tv_usec); | |
2085 | ||
1b439f01 | 2086 | interval_float = t->tv_delta.tv_sec + t->tv_delta.tv_usec / 1000000.0; |
103a8fea | 2087 | |
008d396e LB |
2088 | tsc = t->tsc * tsc_tweak; |
2089 | ||
c98d5d94 LB |
2090 | /* topo columns, print blanks on 1st (average) line */ |
2091 | if (t == &average.threads) { | |
812db3f7 | 2092 | if (DO_BIC(BIC_Package)) |
6168c2e0 | 2093 | outp += sprintf(outp, "%s-", (printed++ ? delim : "")); |
6de68fe1 LB |
2094 | if (DO_BIC(BIC_Die)) |
2095 | outp += sprintf(outp, "%s-", (printed++ ? delim : "")); | |
01235041 PB |
2096 | if (DO_BIC(BIC_Node)) |
2097 | outp += sprintf(outp, "%s-", (printed++ ? delim : "")); | |
812db3f7 | 2098 | if (DO_BIC(BIC_Core)) |
6168c2e0 | 2099 | outp += sprintf(outp, "%s-", (printed++ ? delim : "")); |
812db3f7 | 2100 | if (DO_BIC(BIC_CPU)) |
6168c2e0 | 2101 | outp += sprintf(outp, "%s-", (printed++ ? delim : "")); |
4c2122d4 LB |
2102 | if (DO_BIC(BIC_APIC)) |
2103 | outp += sprintf(outp, "%s-", (printed++ ? delim : "")); | |
2104 | if (DO_BIC(BIC_X2APIC)) | |
2105 | outp += sprintf(outp, "%s-", (printed++ ? delim : "")); | |
103a8fea | 2106 | } else { |
812db3f7 | 2107 | if (DO_BIC(BIC_Package)) { |
c98d5d94 | 2108 | if (p) |
6168c2e0 | 2109 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->package_id); |
c98d5d94 | 2110 | else |
6168c2e0 | 2111 | outp += sprintf(outp, "%s-", (printed++ ? delim : "")); |
c98d5d94 | 2112 | } |
6de68fe1 LB |
2113 | if (DO_BIC(BIC_Die)) { |
2114 | if (c) | |
2115 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), cpus[t->cpu_id].die_id); | |
2116 | else | |
2117 | outp += sprintf(outp, "%s-", (printed++ ? delim : "")); | |
2118 | } | |
01235041 PB |
2119 | if (DO_BIC(BIC_Node)) { |
2120 | if (t) | |
2121 | outp += sprintf(outp, "%s%d", | |
1b439f01 | 2122 | (printed++ ? delim : ""), cpus[t->cpu_id].physical_node_id); |
01235041 | 2123 | else |
1b439f01 | 2124 | outp += sprintf(outp, "%s-", (printed++ ? delim : "")); |
01235041 | 2125 | } |
812db3f7 | 2126 | if (DO_BIC(BIC_Core)) { |
c98d5d94 | 2127 | if (c) |
6168c2e0 | 2128 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), c->core_id); |
c98d5d94 | 2129 | else |
6168c2e0 | 2130 | outp += sprintf(outp, "%s-", (printed++ ? delim : "")); |
c98d5d94 | 2131 | } |
812db3f7 | 2132 | if (DO_BIC(BIC_CPU)) |
6168c2e0 | 2133 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->cpu_id); |
4c2122d4 LB |
2134 | if (DO_BIC(BIC_APIC)) |
2135 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->apic_id); | |
2136 | if (DO_BIC(BIC_X2APIC)) | |
2137 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->x2apic_id); | |
103a8fea | 2138 | } |
fc04cc67 | 2139 | |
812db3f7 | 2140 | if (DO_BIC(BIC_Avg_MHz)) |
1b439f01 | 2141 | outp += sprintf(outp, "%s%.0f", (printed++ ? delim : ""), 1.0 / units * t->aperf / interval_float); |
fc04cc67 | 2142 | |
812db3f7 | 2143 | if (DO_BIC(BIC_Busy)) |
1b439f01 | 2144 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * t->mperf / tsc); |
103a8fea | 2145 | |
812db3f7 | 2146 | if (DO_BIC(BIC_Bzy_MHz)) { |
21ed5574 | 2147 | if (has_base_hz) |
1b439f01 LB |
2148 | outp += |
2149 | sprintf(outp, "%s%.0f", (printed++ ? delim : ""), base_hz / units * t->aperf / t->mperf); | |
21ed5574 | 2150 | else |
6168c2e0 | 2151 | outp += sprintf(outp, "%s%.0f", (printed++ ? delim : ""), |
1b439f01 | 2152 | tsc / units * t->aperf / t->mperf / interval_float); |
21ed5574 | 2153 | } |
103a8fea | 2154 | |
812db3f7 | 2155 | if (DO_BIC(BIC_TSC_MHz)) |
1b439f01 | 2156 | outp += sprintf(outp, "%s%.0f", (printed++ ? delim : ""), 1.0 * t->tsc / units / interval_float); |
103a8fea | 2157 | |
2af4f9b8 LB |
2158 | if (DO_BIC(BIC_IPC)) |
2159 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 1.0 * t->instr_count / t->aperf); | |
2160 | ||
562a2d37 | 2161 | /* IRQ */ |
0de6c0df LB |
2162 | if (DO_BIC(BIC_IRQ)) { |
2163 | if (sums_need_wide_columns) | |
6168c2e0 | 2164 | outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), t->irq_count); |
0de6c0df | 2165 | else |
6168c2e0 | 2166 | outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), t->irq_count); |
0de6c0df | 2167 | } |
562a2d37 | 2168 | |
1cc21f7b | 2169 | /* SMI */ |
812db3f7 | 2170 | if (DO_BIC(BIC_SMI)) |
6168c2e0 | 2171 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->smi_count); |
1cc21f7b | 2172 | |
678a3bd1 | 2173 | /* Added counters */ |
388e9c81 LB |
2174 | for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) { |
2175 | if (mp->format == FORMAT_RAW) { | |
2176 | if (mp->width == 32) | |
1b439f01 LB |
2177 | outp += |
2178 | sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int)t->counter[i]); | |
388e9c81 | 2179 | else |
6168c2e0 | 2180 | outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), t->counter[i]); |
388e9c81 | 2181 | } else if (mp->format == FORMAT_DELTA) { |
0de6c0df | 2182 | if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns) |
6168c2e0 | 2183 | outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), t->counter[i]); |
0de6c0df | 2184 | else |
6168c2e0 | 2185 | outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), t->counter[i]); |
388e9c81 | 2186 | } else if (mp->format == FORMAT_PERCENT) { |
41618e63 | 2187 | if (mp->type == COUNTER_USEC) |
1b439f01 LB |
2188 | outp += |
2189 | sprintf(outp, "%s%.2f", (printed++ ? delim : ""), | |
2190 | t->counter[i] / interval_float / 10000); | |
41618e63 | 2191 | else |
1b439f01 | 2192 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * t->counter[i] / tsc); |
388e9c81 LB |
2193 | } |
2194 | } | |
2195 | ||
41618e63 LB |
2196 | /* C1 */ |
2197 | if (DO_BIC(BIC_CPU_c1)) | |
1b439f01 | 2198 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * t->c1 / tsc); |
41618e63 | 2199 | |
678a3bd1 | 2200 | /* print per-core data only for 1st thread in core */ |
74318add | 2201 | if (!is_cpu_first_thread_in_core(t, c, p)) |
678a3bd1 LB |
2202 | goto done; |
2203 | ||
562855ee | 2204 | if (DO_BIC(BIC_CPU_c3)) |
1b439f01 | 2205 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->c3 / tsc); |
812db3f7 | 2206 | if (DO_BIC(BIC_CPU_c6)) |
1b439f01 | 2207 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->c6 / tsc); |
812db3f7 | 2208 | if (DO_BIC(BIC_CPU_c7)) |
1b439f01 | 2209 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->c7 / tsc); |
678a3bd1 | 2210 | |
0539ba11 LB |
2211 | /* Mod%c6 */ |
2212 | if (DO_BIC(BIC_Mod_c6)) | |
6168c2e0 | 2213 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->mc6_us / tsc); |
0539ba11 | 2214 | |
812db3f7 | 2215 | if (DO_BIC(BIC_CoreTmp)) |
6168c2e0 | 2216 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), c->core_temp_c); |
889facbe | 2217 | |
eae97e05 CY |
2218 | /* Core throttle count */ |
2219 | if (DO_BIC(BIC_CORE_THROT_CNT)) | |
2220 | outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), c->core_throt_cnt); | |
2221 | ||
388e9c81 LB |
2222 | for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) { |
2223 | if (mp->format == FORMAT_RAW) { | |
2224 | if (mp->width == 32) | |
1b439f01 LB |
2225 | outp += |
2226 | sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int)c->counter[i]); | |
388e9c81 | 2227 | else |
6168c2e0 | 2228 | outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), c->counter[i]); |
388e9c81 | 2229 | } else if (mp->format == FORMAT_DELTA) { |
0de6c0df | 2230 | if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns) |
6168c2e0 | 2231 | outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), c->counter[i]); |
0de6c0df | 2232 | else |
6168c2e0 | 2233 | outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), c->counter[i]); |
388e9c81 | 2234 | } else if (mp->format == FORMAT_PERCENT) { |
1b439f01 | 2235 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->counter[i] / tsc); |
388e9c81 LB |
2236 | } |
2237 | } | |
2238 | ||
9972d5d8 | 2239 | fmt8 = "%s%.2f"; |
9392bd98 | 2240 | |
e338831b | 2241 | if (DO_BIC(BIC_CorWatt) && platform->has_per_core_rapl) |
1b439f01 | 2242 | outp += |
05a2f07d PW |
2243 | sprintf(outp, fmt8, (printed++ ? delim : ""), |
2244 | rapl_counter_get_value(&c->core_energy, RAPL_UNIT_WATTS, interval_float)); | |
e338831b | 2245 | if (DO_BIC(BIC_Cor_J) && platform->has_per_core_rapl) |
05a2f07d PW |
2246 | outp += sprintf(outp, fmt8, (printed++ ? delim : ""), |
2247 | rapl_counter_get_value(&c->core_energy, RAPL_UNIT_JOULES, interval_float)); | |
9392bd98 | 2248 | |
c98d5d94 | 2249 | /* print per-package data only for 1st core in package */ |
74318add | 2250 | if (!is_cpu_first_core_in_package(t, c, p)) |
c98d5d94 LB |
2251 | goto done; |
2252 | ||
0b2bb692 | 2253 | /* PkgTmp */ |
812db3f7 | 2254 | if (DO_BIC(BIC_PkgTmp)) |
6168c2e0 | 2255 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->pkg_temp_c); |
889facbe | 2256 | |
fdf676e5 | 2257 | /* GFXrc6 */ |
812db3f7 | 2258 | if (DO_BIC(BIC_GFX_rc6)) { |
ba3dec99 | 2259 | if (p->gfx_rc6_ms == -1) { /* detect GFX counter reset */ |
6168c2e0 | 2260 | outp += sprintf(outp, "%s**.**", (printed++ ? delim : "")); |
9185e988 | 2261 | } else { |
6168c2e0 | 2262 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), |
1b439f01 | 2263 | p->gfx_rc6_ms / 10.0 / interval_float); |
9185e988 LB |
2264 | } |
2265 | } | |
fdf676e5 | 2266 | |
27d47356 | 2267 | /* GFXMHz */ |
812db3f7 | 2268 | if (DO_BIC(BIC_GFXMHz)) |
6168c2e0 | 2269 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->gfx_mhz); |
27d47356 | 2270 | |
b4b91569 RA |
2271 | /* GFXACTMHz */ |
2272 | if (DO_BIC(BIC_GFXACTMHz)) | |
2273 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->gfx_act_mhz); | |
2274 | ||
3bbb331c ZR |
2275 | /* SAMmc6 */ |
2276 | if (DO_BIC(BIC_SAM_mc6)) { | |
2277 | if (p->sam_mc6_ms == -1) { /* detect GFX counter reset */ | |
2278 | outp += sprintf(outp, "%s**.**", (printed++ ? delim : "")); | |
2279 | } else { | |
2280 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), | |
2281 | p->sam_mc6_ms / 10.0 / interval_float); | |
2282 | } | |
2283 | } | |
2284 | ||
2285 | /* SAMMHz */ | |
2286 | if (DO_BIC(BIC_SAMMHz)) | |
2287 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->sam_mhz); | |
2288 | ||
2289 | /* SAMACTMHz */ | |
2290 | if (DO_BIC(BIC_SAMACTMHz)) | |
2291 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->sam_act_mhz); | |
2292 | ||
0b2bb692 | 2293 | /* Totl%C0, Any%C0 GFX%C0 CPUGFX% */ |
a99d8730 | 2294 | if (DO_BIC(BIC_Totl_c0)) |
1b439f01 | 2295 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_wtd_core_c0 / tsc); |
a99d8730 | 2296 | if (DO_BIC(BIC_Any_c0)) |
1b439f01 | 2297 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_any_core_c0 / tsc); |
a99d8730 | 2298 | if (DO_BIC(BIC_GFX_c0)) |
1b439f01 | 2299 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_any_gfxe_c0 / tsc); |
a99d8730 | 2300 | if (DO_BIC(BIC_CPUGFX)) |
1b439f01 | 2301 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_both_core_gfxe_c0 / tsc); |
0b2bb692 | 2302 | |
0f47c08d | 2303 | if (DO_BIC(BIC_Pkgpc2)) |
1b439f01 | 2304 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc2 / tsc); |
0f47c08d | 2305 | if (DO_BIC(BIC_Pkgpc3)) |
1b439f01 | 2306 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc3 / tsc); |
0f47c08d | 2307 | if (DO_BIC(BIC_Pkgpc6)) |
1b439f01 | 2308 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc6 / tsc); |
0f47c08d | 2309 | if (DO_BIC(BIC_Pkgpc7)) |
1b439f01 | 2310 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc7 / tsc); |
0f47c08d | 2311 | if (DO_BIC(BIC_Pkgpc8)) |
1b439f01 | 2312 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc8 / tsc); |
0f47c08d | 2313 | if (DO_BIC(BIC_Pkgpc9)) |
1b439f01 | 2314 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc9 / tsc); |
0f47c08d | 2315 | if (DO_BIC(BIC_Pkgpc10)) |
1b439f01 | 2316 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc10 / tsc); |
889facbe | 2317 | |
227ed18f CY |
2318 | if (DO_BIC(BIC_CPU_LPI)) { |
2319 | if (p->cpu_lpi >= 0) | |
2320 | outp += | |
2321 | sprintf(outp, "%s%.2f", (printed++ ? delim : ""), | |
2322 | 100.0 * p->cpu_lpi / 1000000.0 / interval_float); | |
2323 | else | |
2324 | outp += sprintf(outp, "%s(neg)", (printed++ ? delim : "")); | |
2325 | } | |
2326 | if (DO_BIC(BIC_SYS_LPI)) { | |
2327 | if (p->sys_lpi >= 0) | |
2328 | outp += | |
2329 | sprintf(outp, "%s%.2f", (printed++ ? delim : ""), | |
2330 | 100.0 * p->sys_lpi / 1000000.0 / interval_float); | |
2331 | else | |
2332 | outp += sprintf(outp, "%s(neg)", (printed++ ? delim : "")); | |
2333 | } | |
be0e54c4 | 2334 | |
812db3f7 | 2335 | if (DO_BIC(BIC_PkgWatt)) |
1b439f01 | 2336 | outp += |
05a2f07d PW |
2337 | sprintf(outp, fmt8, (printed++ ? delim : ""), |
2338 | rapl_counter_get_value(&p->energy_pkg, RAPL_UNIT_WATTS, interval_float)); | |
e338831b | 2339 | if (DO_BIC(BIC_CorWatt) && !platform->has_per_core_rapl) |
1b439f01 | 2340 | outp += |
05a2f07d PW |
2341 | sprintf(outp, fmt8, (printed++ ? delim : ""), |
2342 | rapl_counter_get_value(&p->energy_cores, RAPL_UNIT_WATTS, interval_float)); | |
812db3f7 | 2343 | if (DO_BIC(BIC_GFXWatt)) |
1b439f01 | 2344 | outp += |
05a2f07d PW |
2345 | sprintf(outp, fmt8, (printed++ ? delim : ""), |
2346 | rapl_counter_get_value(&p->energy_gfx, RAPL_UNIT_WATTS, interval_float)); | |
812db3f7 | 2347 | if (DO_BIC(BIC_RAMWatt)) |
1b439f01 LB |
2348 | outp += |
2349 | sprintf(outp, fmt8, (printed++ ? delim : ""), | |
05a2f07d | 2350 | rapl_counter_get_value(&p->energy_dram, RAPL_UNIT_WATTS, interval_float)); |
812db3f7 | 2351 | if (DO_BIC(BIC_Pkg_J)) |
05a2f07d PW |
2352 | outp += sprintf(outp, fmt8, (printed++ ? delim : ""), |
2353 | rapl_counter_get_value(&p->energy_pkg, RAPL_UNIT_JOULES, interval_float)); | |
e338831b | 2354 | if (DO_BIC(BIC_Cor_J) && !platform->has_per_core_rapl) |
05a2f07d PW |
2355 | outp += sprintf(outp, fmt8, (printed++ ? delim : ""), |
2356 | rapl_counter_get_value(&p->energy_cores, RAPL_UNIT_JOULES, interval_float)); | |
812db3f7 | 2357 | if (DO_BIC(BIC_GFX_J)) |
05a2f07d PW |
2358 | outp += sprintf(outp, fmt8, (printed++ ? delim : ""), |
2359 | rapl_counter_get_value(&p->energy_gfx, RAPL_UNIT_JOULES, interval_float)); | |
812db3f7 | 2360 | if (DO_BIC(BIC_RAM_J)) |
05a2f07d PW |
2361 | outp += sprintf(outp, fmt8, (printed++ ? delim : ""), |
2362 | rapl_counter_get_value(&p->energy_dram, RAPL_UNIT_JOULES, interval_float)); | |
812db3f7 | 2363 | if (DO_BIC(BIC_PKG__)) |
1b439f01 LB |
2364 | outp += |
2365 | sprintf(outp, fmt8, (printed++ ? delim : ""), | |
05a2f07d | 2366 | rapl_counter_get_value(&p->rapl_pkg_perf_status, RAPL_UNIT_WATTS, interval_float)); |
812db3f7 | 2367 | if (DO_BIC(BIC_RAM__)) |
1b439f01 LB |
2368 | outp += |
2369 | sprintf(outp, fmt8, (printed++ ? delim : ""), | |
05a2f07d | 2370 | rapl_counter_get_value(&p->rapl_dram_perf_status, RAPL_UNIT_WATTS, interval_float)); |
a5c6d65d LB |
2371 | /* UncMHz */ |
2372 | if (DO_BIC(BIC_UNCORE_MHZ)) | |
2373 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->uncore_mhz); | |
812db3f7 | 2374 | |
388e9c81 LB |
2375 | for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) { |
2376 | if (mp->format == FORMAT_RAW) { | |
2377 | if (mp->width == 32) | |
1b439f01 LB |
2378 | outp += |
2379 | sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int)p->counter[i]); | |
388e9c81 | 2380 | else |
6168c2e0 | 2381 | outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), p->counter[i]); |
388e9c81 | 2382 | } else if (mp->format == FORMAT_DELTA) { |
0de6c0df | 2383 | if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns) |
6168c2e0 | 2384 | outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), p->counter[i]); |
0de6c0df | 2385 | else |
6168c2e0 | 2386 | outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), p->counter[i]); |
388e9c81 | 2387 | } else if (mp->format == FORMAT_PERCENT) { |
1b439f01 | 2388 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->counter[i] / tsc); |
388e9c81 LB |
2389 | } |
2390 | } | |
2391 | ||
c98d5d94 | 2392 | done: |
94d6ab4b LB |
2393 | if (*(outp - 1) != '\n') |
2394 | outp += sprintf(outp, "\n"); | |
c98d5d94 LB |
2395 | |
2396 | return 0; | |
103a8fea LB |
2397 | } |
2398 | ||
b7d8c148 | 2399 | void flush_output_stdout(void) |
c98d5d94 | 2400 | { |
b7d8c148 LB |
2401 | FILE *filep; |
2402 | ||
2403 | if (outf == stderr) | |
2404 | filep = stdout; | |
2405 | else | |
2406 | filep = outf; | |
2407 | ||
2408 | fputs(output_buffer, filep); | |
2409 | fflush(filep); | |
2410 | ||
c98d5d94 LB |
2411 | outp = output_buffer; |
2412 | } | |
1b439f01 | 2413 | |
b7d8c148 | 2414 | void flush_output_stderr(void) |
c98d5d94 | 2415 | { |
b7d8c148 LB |
2416 | fputs(output_buffer, outf); |
2417 | fflush(outf); | |
c98d5d94 LB |
2418 | outp = output_buffer; |
2419 | } | |
1b439f01 | 2420 | |
c98d5d94 | 2421 | void format_all_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) |
103a8fea | 2422 | { |
c7e399f8 | 2423 | static int count; |
103a8fea | 2424 | |
c7e399f8 | 2425 | if ((!count || (header_iterations && !(count % header_iterations))) || !summary_only) |
c8ade361 | 2426 | print_header("\t"); |
103a8fea | 2427 | |
9d83601a | 2428 | format_counters(&average.threads, &average.cores, &average.packages); |
103a8fea | 2429 | |
c7e399f8 | 2430 | count++; |
e23da037 LB |
2431 | |
2432 | if (summary_only) | |
2433 | return; | |
2434 | ||
c98d5d94 | 2435 | for_all_cpus(format_counters, t, c, p); |
103a8fea LB |
2436 | } |
2437 | ||
889facbe | 2438 | #define DELTA_WRAP32(new, old) \ |
7c2ccc50 | 2439 | old = ((((unsigned long long)new << 32) - ((unsigned long long)old << 32)) >> 32); |
889facbe | 2440 | |
1b439f01 | 2441 | int delta_package(struct pkg_data *new, struct pkg_data *old) |
c98d5d94 | 2442 | { |
388e9c81 LB |
2443 | int i; |
2444 | struct msr_counter *mp; | |
0b2bb692 | 2445 | |
a99d8730 | 2446 | if (DO_BIC(BIC_Totl_c0)) |
0b2bb692 | 2447 | old->pkg_wtd_core_c0 = new->pkg_wtd_core_c0 - old->pkg_wtd_core_c0; |
a99d8730 | 2448 | if (DO_BIC(BIC_Any_c0)) |
0b2bb692 | 2449 | old->pkg_any_core_c0 = new->pkg_any_core_c0 - old->pkg_any_core_c0; |
a99d8730 | 2450 | if (DO_BIC(BIC_GFX_c0)) |
0b2bb692 | 2451 | old->pkg_any_gfxe_c0 = new->pkg_any_gfxe_c0 - old->pkg_any_gfxe_c0; |
a99d8730 | 2452 | if (DO_BIC(BIC_CPUGFX)) |
0b2bb692 | 2453 | old->pkg_both_core_gfxe_c0 = new->pkg_both_core_gfxe_c0 - old->pkg_both_core_gfxe_c0; |
a99d8730 | 2454 | |
c98d5d94 | 2455 | old->pc2 = new->pc2 - old->pc2; |
0f47c08d | 2456 | if (DO_BIC(BIC_Pkgpc3)) |
ee7e38e3 | 2457 | old->pc3 = new->pc3 - old->pc3; |
0f47c08d | 2458 | if (DO_BIC(BIC_Pkgpc6)) |
ee7e38e3 | 2459 | old->pc6 = new->pc6 - old->pc6; |
0f47c08d | 2460 | if (DO_BIC(BIC_Pkgpc7)) |
ee7e38e3 | 2461 | old->pc7 = new->pc7 - old->pc7; |
ca58710f KCA |
2462 | old->pc8 = new->pc8 - old->pc8; |
2463 | old->pc9 = new->pc9 - old->pc9; | |
2464 | old->pc10 = new->pc10 - old->pc10; | |
be0e54c4 LB |
2465 | old->cpu_lpi = new->cpu_lpi - old->cpu_lpi; |
2466 | old->sys_lpi = new->sys_lpi - old->sys_lpi; | |
889facbe LB |
2467 | old->pkg_temp_c = new->pkg_temp_c; |
2468 | ||
9185e988 | 2469 | /* flag an error when rc6 counter resets/wraps */ |
1b439f01 | 2470 | if (old->gfx_rc6_ms > new->gfx_rc6_ms) |
9185e988 LB |
2471 | old->gfx_rc6_ms = -1; |
2472 | else | |
2473 | old->gfx_rc6_ms = new->gfx_rc6_ms - old->gfx_rc6_ms; | |
2474 | ||
a5c6d65d | 2475 | old->uncore_mhz = new->uncore_mhz; |
27d47356 | 2476 | old->gfx_mhz = new->gfx_mhz; |
b4b91569 | 2477 | old->gfx_act_mhz = new->gfx_act_mhz; |
27d47356 | 2478 | |
3bbb331c ZR |
2479 | /* flag an error when mc6 counter resets/wraps */ |
2480 | if (old->sam_mc6_ms > new->sam_mc6_ms) | |
2481 | old->sam_mc6_ms = -1; | |
2482 | else | |
2483 | old->sam_mc6_ms = new->sam_mc6_ms - old->sam_mc6_ms; | |
2484 | ||
2485 | old->sam_mhz = new->sam_mhz; | |
2486 | old->sam_act_mhz = new->sam_act_mhz; | |
2487 | ||
05a2f07d PW |
2488 | old->energy_pkg.raw_value = new->energy_pkg.raw_value - old->energy_pkg.raw_value; |
2489 | old->energy_cores.raw_value = new->energy_cores.raw_value - old->energy_cores.raw_value; | |
2490 | old->energy_gfx.raw_value = new->energy_gfx.raw_value - old->energy_gfx.raw_value; | |
2491 | old->energy_dram.raw_value = new->energy_dram.raw_value - old->energy_dram.raw_value; | |
2492 | old->rapl_pkg_perf_status.raw_value = new->rapl_pkg_perf_status.raw_value - old->rapl_pkg_perf_status.raw_value; | |
2493 | old->rapl_dram_perf_status.raw_value = | |
2494 | new->rapl_dram_perf_status.raw_value - old->rapl_dram_perf_status.raw_value; | |
ba3dec99 | 2495 | |
388e9c81 LB |
2496 | for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) { |
2497 | if (mp->format == FORMAT_RAW) | |
2498 | old->counter[i] = new->counter[i]; | |
2499 | else | |
2500 | old->counter[i] = new->counter[i] - old->counter[i]; | |
2501 | } | |
2502 | ||
ba3dec99 | 2503 | return 0; |
c98d5d94 | 2504 | } |
103a8fea | 2505 | |
1b439f01 | 2506 | void delta_core(struct core_data *new, struct core_data *old) |
103a8fea | 2507 | { |
388e9c81 LB |
2508 | int i; |
2509 | struct msr_counter *mp; | |
2510 | ||
c98d5d94 LB |
2511 | old->c3 = new->c3 - old->c3; |
2512 | old->c6 = new->c6 - old->c6; | |
2513 | old->c7 = new->c7 - old->c7; | |
889facbe | 2514 | old->core_temp_c = new->core_temp_c; |
eae97e05 | 2515 | old->core_throt_cnt = new->core_throt_cnt; |
0539ba11 | 2516 | old->mc6_us = new->mc6_us - old->mc6_us; |
388e9c81 | 2517 | |
05a2f07d | 2518 | DELTA_WRAP32(new->core_energy.raw_value, old->core_energy.raw_value); |
9392bd98 | 2519 | |
388e9c81 LB |
2520 | for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) { |
2521 | if (mp->format == FORMAT_RAW) | |
2522 | old->counter[i] = new->counter[i]; | |
2523 | else | |
2524 | old->counter[i] = new->counter[i] - old->counter[i]; | |
2525 | } | |
c98d5d94 | 2526 | } |
103a8fea | 2527 | |
1e9042b9 SP |
2528 | int soft_c1_residency_display(int bic) |
2529 | { | |
76d83d2a | 2530 | if (!DO_BIC(BIC_CPU_c1) || platform->has_msr_core_c1_res) |
1e9042b9 SP |
2531 | return 0; |
2532 | ||
2533 | return DO_BIC_READ(bic); | |
2534 | } | |
2535 | ||
c3ae331d LB |
2536 | /* |
2537 | * old = new - old | |
2538 | */ | |
1b439f01 | 2539 | int delta_thread(struct thread_data *new, struct thread_data *old, struct core_data *core_delta) |
c98d5d94 | 2540 | { |
388e9c81 LB |
2541 | int i; |
2542 | struct msr_counter *mp; | |
2543 | ||
4c2122d4 LB |
2544 | /* we run cpuid just the 1st time, copy the results */ |
2545 | if (DO_BIC(BIC_APIC)) | |
2546 | new->apic_id = old->apic_id; | |
2547 | if (DO_BIC(BIC_X2APIC)) | |
2548 | new->x2apic_id = old->x2apic_id; | |
2549 | ||
3f44a5c6 LB |
2550 | /* |
2551 | * the timestamps from start of measurement interval are in "old" | |
2552 | * the timestamp from end of measurement interval are in "new" | |
2553 | * over-write old w/ new so we can print end of interval values | |
2554 | */ | |
2555 | ||
d4794f25 | 2556 | timersub(&new->tv_begin, &old->tv_begin, &old->tv_delta); |
3f44a5c6 LB |
2557 | old->tv_begin = new->tv_begin; |
2558 | old->tv_end = new->tv_end; | |
2559 | ||
c98d5d94 LB |
2560 | old->tsc = new->tsc - old->tsc; |
2561 | ||
2562 | /* check for TSC < 1 Mcycles over interval */ | |
b2c95d90 JT |
2563 | if (old->tsc < (1000 * 1000)) |
2564 | errx(-3, "Insanely slow TSC rate, TSC stops in idle?\n" | |
2565 | "You can disable all c-states by booting with \"idle=poll\"\n" | |
2566 | "or just the deep ones with \"processor.max_cstate=1\""); | |
103a8fea | 2567 | |
c98d5d94 | 2568 | old->c1 = new->c1 - old->c1; |
103a8fea | 2569 | |
f2c1dba3 LB |
2570 | if (DO_BIC(BIC_Avg_MHz) || DO_BIC(BIC_Busy) || DO_BIC(BIC_Bzy_MHz) || DO_BIC(BIC_IPC) |
2571 | || soft_c1_residency_display(BIC_Avg_MHz)) { | |
a729617c LB |
2572 | if ((new->aperf > old->aperf) && (new->mperf > old->mperf)) { |
2573 | old->aperf = new->aperf - old->aperf; | |
2574 | old->mperf = new->mperf - old->mperf; | |
2575 | } else { | |
ba3dec99 | 2576 | return -1; |
103a8fea | 2577 | } |
c98d5d94 | 2578 | } |
103a8fea | 2579 | |
76d83d2a | 2580 | if (platform->has_msr_core_c1_res) { |
144b44b1 LB |
2581 | /* |
2582 | * Some models have a dedicated C1 residency MSR, | |
2583 | * which should be more accurate than the derivation below. | |
2584 | */ | |
2585 | } else { | |
2586 | /* | |
2587 | * As counter collection is not atomic, | |
2588 | * it is possible for mperf's non-halted cycles + idle states | |
2589 | * to exceed TSC's all cycles: show c1 = 0% in that case. | |
2590 | */ | |
95149369 | 2591 | if ((old->mperf + core_delta->c3 + core_delta->c6 + core_delta->c7) > (old->tsc * tsc_tweak)) |
144b44b1 LB |
2592 | old->c1 = 0; |
2593 | else { | |
2594 | /* normal case, derive c1 */ | |
008d396e | 2595 | old->c1 = (old->tsc * tsc_tweak) - old->mperf - core_delta->c3 |
1b439f01 | 2596 | - core_delta->c6 - core_delta->c7; |
144b44b1 | 2597 | } |
c98d5d94 | 2598 | } |
c3ae331d | 2599 | |
c98d5d94 | 2600 | if (old->mperf == 0) { |
b7d8c148 LB |
2601 | if (debug > 1) |
2602 | fprintf(outf, "cpu%d MPERF 0!\n", old->cpu_id); | |
c98d5d94 | 2603 | old->mperf = 1; /* divide by 0 protection */ |
103a8fea | 2604 | } |
c98d5d94 | 2605 | |
2af4f9b8 LB |
2606 | if (DO_BIC(BIC_IPC)) |
2607 | old->instr_count = new->instr_count - old->instr_count; | |
2608 | ||
812db3f7 | 2609 | if (DO_BIC(BIC_IRQ)) |
562a2d37 LB |
2610 | old->irq_count = new->irq_count - old->irq_count; |
2611 | ||
812db3f7 | 2612 | if (DO_BIC(BIC_SMI)) |
1ed51011 | 2613 | old->smi_count = new->smi_count - old->smi_count; |
ba3dec99 | 2614 | |
388e9c81 LB |
2615 | for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) { |
2616 | if (mp->format == FORMAT_RAW) | |
2617 | old->counter[i] = new->counter[i]; | |
2618 | else | |
2619 | old->counter[i] = new->counter[i] - old->counter[i]; | |
2620 | } | |
ba3dec99 | 2621 | return 0; |
c98d5d94 LB |
2622 | } |
2623 | ||
2624 | int delta_cpu(struct thread_data *t, struct core_data *c, | |
1b439f01 | 2625 | struct pkg_data *p, struct thread_data *t2, struct core_data *c2, struct pkg_data *p2) |
c98d5d94 | 2626 | { |
ba3dec99 LB |
2627 | int retval = 0; |
2628 | ||
c98d5d94 | 2629 | /* calculate core delta only for 1st thread in core */ |
74318add | 2630 | if (is_cpu_first_thread_in_core(t, c, p)) |
c98d5d94 LB |
2631 | delta_core(c, c2); |
2632 | ||
2633 | /* always calculate thread delta */ | |
ba3dec99 LB |
2634 | retval = delta_thread(t, t2, c2); /* c2 is core delta */ |
2635 | if (retval) | |
2636 | return retval; | |
c98d5d94 LB |
2637 | |
2638 | /* calculate package delta only for 1st core in package */ | |
74318add | 2639 | if (is_cpu_first_core_in_package(t, c, p)) |
ba3dec99 | 2640 | retval = delta_package(p, p2); |
c98d5d94 | 2641 | |
ba3dec99 | 2642 | return retval; |
103a8fea LB |
2643 | } |
2644 | ||
05a2f07d PW |
2645 | void rapl_counter_clear(struct rapl_counter *c) |
2646 | { | |
2647 | c->raw_value = 0; | |
2648 | c->scale = 0.0; | |
2649 | c->unit = RAPL_UNIT_INVALID; | |
2650 | } | |
2651 | ||
c98d5d94 LB |
2652 | void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) |
2653 | { | |
388e9c81 | 2654 | int i; |
1b439f01 | 2655 | struct msr_counter *mp; |
388e9c81 | 2656 | |
3f44a5c6 LB |
2657 | t->tv_begin.tv_sec = 0; |
2658 | t->tv_begin.tv_usec = 0; | |
2659 | t->tv_end.tv_sec = 0; | |
2660 | t->tv_end.tv_usec = 0; | |
d4794f25 YG |
2661 | t->tv_delta.tv_sec = 0; |
2662 | t->tv_delta.tv_usec = 0; | |
3f44a5c6 | 2663 | |
c98d5d94 LB |
2664 | t->tsc = 0; |
2665 | t->aperf = 0; | |
2666 | t->mperf = 0; | |
2667 | t->c1 = 0; | |
2668 | ||
2af4f9b8 LB |
2669 | t->instr_count = 0; |
2670 | ||
562a2d37 LB |
2671 | t->irq_count = 0; |
2672 | t->smi_count = 0; | |
2673 | ||
c98d5d94 LB |
2674 | c->c3 = 0; |
2675 | c->c6 = 0; | |
2676 | c->c7 = 0; | |
0539ba11 | 2677 | c->mc6_us = 0; |
889facbe | 2678 | c->core_temp_c = 0; |
05a2f07d | 2679 | rapl_counter_clear(&c->core_energy); |
eae97e05 | 2680 | c->core_throt_cnt = 0; |
c98d5d94 | 2681 | |
0b2bb692 LB |
2682 | p->pkg_wtd_core_c0 = 0; |
2683 | p->pkg_any_core_c0 = 0; | |
2684 | p->pkg_any_gfxe_c0 = 0; | |
2685 | p->pkg_both_core_gfxe_c0 = 0; | |
2686 | ||
c98d5d94 | 2687 | p->pc2 = 0; |
0f47c08d | 2688 | if (DO_BIC(BIC_Pkgpc3)) |
ee7e38e3 | 2689 | p->pc3 = 0; |
0f47c08d | 2690 | if (DO_BIC(BIC_Pkgpc6)) |
ee7e38e3 | 2691 | p->pc6 = 0; |
0f47c08d | 2692 | if (DO_BIC(BIC_Pkgpc7)) |
ee7e38e3 | 2693 | p->pc7 = 0; |
ca58710f KCA |
2694 | p->pc8 = 0; |
2695 | p->pc9 = 0; | |
2696 | p->pc10 = 0; | |
be0e54c4 LB |
2697 | p->cpu_lpi = 0; |
2698 | p->sys_lpi = 0; | |
889facbe | 2699 | |
05a2f07d PW |
2700 | rapl_counter_clear(&p->energy_pkg); |
2701 | rapl_counter_clear(&p->energy_dram); | |
2702 | rapl_counter_clear(&p->energy_cores); | |
2703 | rapl_counter_clear(&p->energy_gfx); | |
2704 | rapl_counter_clear(&p->rapl_pkg_perf_status); | |
2705 | rapl_counter_clear(&p->rapl_dram_perf_status); | |
889facbe | 2706 | p->pkg_temp_c = 0; |
27d47356 | 2707 | |
fdf676e5 | 2708 | p->gfx_rc6_ms = 0; |
a5c6d65d | 2709 | p->uncore_mhz = 0; |
27d47356 | 2710 | p->gfx_mhz = 0; |
b4b91569 | 2711 | p->gfx_act_mhz = 0; |
3bbb331c ZR |
2712 | p->sam_mc6_ms = 0; |
2713 | p->sam_mhz = 0; | |
2714 | p->sam_act_mhz = 0; | |
388e9c81 LB |
2715 | for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) |
2716 | t->counter[i] = 0; | |
2717 | ||
2718 | for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) | |
2719 | c->counter[i] = 0; | |
2720 | ||
2721 | for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) | |
2722 | p->counter[i] = 0; | |
c98d5d94 | 2723 | } |
1b439f01 | 2724 | |
05a2f07d PW |
2725 | void rapl_counter_accumulate(struct rapl_counter *dst, const struct rapl_counter *src) |
2726 | { | |
2727 | /* Copy unit and scale from src if dst is not initialized */ | |
2728 | if (dst->unit == RAPL_UNIT_INVALID) { | |
2729 | dst->unit = src->unit; | |
2730 | dst->scale = src->scale; | |
2731 | } | |
2732 | ||
2733 | assert(dst->unit == src->unit); | |
2734 | assert(dst->scale == src->scale); | |
2735 | ||
2736 | dst->raw_value += src->raw_value; | |
2737 | } | |
2738 | ||
1b439f01 | 2739 | int sum_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) |
103a8fea | 2740 | { |
388e9c81 LB |
2741 | int i; |
2742 | struct msr_counter *mp; | |
2743 | ||
4c2122d4 LB |
2744 | /* copy un-changing apic_id's */ |
2745 | if (DO_BIC(BIC_APIC)) | |
2746 | average.threads.apic_id = t->apic_id; | |
2747 | if (DO_BIC(BIC_X2APIC)) | |
2748 | average.threads.x2apic_id = t->x2apic_id; | |
2749 | ||
3f44a5c6 LB |
2750 | /* remember first tv_begin */ |
2751 | if (average.threads.tv_begin.tv_sec == 0) | |
2752 | average.threads.tv_begin = t->tv_begin; | |
2753 | ||
2754 | /* remember last tv_end */ | |
2755 | average.threads.tv_end = t->tv_end; | |
2756 | ||
c98d5d94 LB |
2757 | average.threads.tsc += t->tsc; |
2758 | average.threads.aperf += t->aperf; | |
2759 | average.threads.mperf += t->mperf; | |
2760 | average.threads.c1 += t->c1; | |
103a8fea | 2761 | |
2af4f9b8 LB |
2762 | average.threads.instr_count += t->instr_count; |
2763 | ||
562a2d37 LB |
2764 | average.threads.irq_count += t->irq_count; |
2765 | average.threads.smi_count += t->smi_count; | |
2766 | ||
388e9c81 LB |
2767 | for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) { |
2768 | if (mp->format == FORMAT_RAW) | |
2769 | continue; | |
2770 | average.threads.counter[i] += t->counter[i]; | |
2771 | } | |
2772 | ||
c98d5d94 | 2773 | /* sum per-core values only for 1st thread in core */ |
74318add | 2774 | if (!is_cpu_first_thread_in_core(t, c, p)) |
c98d5d94 | 2775 | return 0; |
103a8fea | 2776 | |
c98d5d94 LB |
2777 | average.cores.c3 += c->c3; |
2778 | average.cores.c6 += c->c6; | |
2779 | average.cores.c7 += c->c7; | |
0539ba11 | 2780 | average.cores.mc6_us += c->mc6_us; |
c98d5d94 | 2781 | |
889facbe | 2782 | average.cores.core_temp_c = MAX(average.cores.core_temp_c, c->core_temp_c); |
eae97e05 | 2783 | average.cores.core_throt_cnt = MAX(average.cores.core_throt_cnt, c->core_throt_cnt); |
889facbe | 2784 | |
05a2f07d | 2785 | rapl_counter_accumulate(&average.cores.core_energy, &c->core_energy); |
9392bd98 | 2786 | |
388e9c81 LB |
2787 | for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) { |
2788 | if (mp->format == FORMAT_RAW) | |
2789 | continue; | |
2790 | average.cores.counter[i] += c->counter[i]; | |
2791 | } | |
2792 | ||
c98d5d94 | 2793 | /* sum per-pkg values only for 1st core in pkg */ |
74318add | 2794 | if (!is_cpu_first_core_in_package(t, c, p)) |
c98d5d94 LB |
2795 | return 0; |
2796 | ||
a99d8730 | 2797 | if (DO_BIC(BIC_Totl_c0)) |
0b2bb692 | 2798 | average.packages.pkg_wtd_core_c0 += p->pkg_wtd_core_c0; |
a99d8730 | 2799 | if (DO_BIC(BIC_Any_c0)) |
0b2bb692 | 2800 | average.packages.pkg_any_core_c0 += p->pkg_any_core_c0; |
a99d8730 | 2801 | if (DO_BIC(BIC_GFX_c0)) |
0b2bb692 | 2802 | average.packages.pkg_any_gfxe_c0 += p->pkg_any_gfxe_c0; |
a99d8730 | 2803 | if (DO_BIC(BIC_CPUGFX)) |
0b2bb692 | 2804 | average.packages.pkg_both_core_gfxe_c0 += p->pkg_both_core_gfxe_c0; |
0b2bb692 | 2805 | |
c98d5d94 | 2806 | average.packages.pc2 += p->pc2; |
0f47c08d | 2807 | if (DO_BIC(BIC_Pkgpc3)) |
ee7e38e3 | 2808 | average.packages.pc3 += p->pc3; |
0f47c08d | 2809 | if (DO_BIC(BIC_Pkgpc6)) |
ee7e38e3 | 2810 | average.packages.pc6 += p->pc6; |
0f47c08d | 2811 | if (DO_BIC(BIC_Pkgpc7)) |
ee7e38e3 | 2812 | average.packages.pc7 += p->pc7; |
ca58710f KCA |
2813 | average.packages.pc8 += p->pc8; |
2814 | average.packages.pc9 += p->pc9; | |
2815 | average.packages.pc10 += p->pc10; | |
c98d5d94 | 2816 | |
be0e54c4 LB |
2817 | average.packages.cpu_lpi = p->cpu_lpi; |
2818 | average.packages.sys_lpi = p->sys_lpi; | |
2819 | ||
05a2f07d PW |
2820 | rapl_counter_accumulate(&average.packages.energy_pkg, &p->energy_pkg); |
2821 | rapl_counter_accumulate(&average.packages.energy_dram, &p->energy_dram); | |
2822 | rapl_counter_accumulate(&average.packages.energy_cores, &p->energy_cores); | |
2823 | rapl_counter_accumulate(&average.packages.energy_gfx, &p->energy_gfx); | |
889facbe | 2824 | |
fdf676e5 | 2825 | average.packages.gfx_rc6_ms = p->gfx_rc6_ms; |
a5c6d65d | 2826 | average.packages.uncore_mhz = p->uncore_mhz; |
27d47356 | 2827 | average.packages.gfx_mhz = p->gfx_mhz; |
b4b91569 | 2828 | average.packages.gfx_act_mhz = p->gfx_act_mhz; |
3bbb331c ZR |
2829 | average.packages.sam_mc6_ms = p->sam_mc6_ms; |
2830 | average.packages.sam_mhz = p->sam_mhz; | |
2831 | average.packages.sam_act_mhz = p->sam_act_mhz; | |
27d47356 | 2832 | |
889facbe LB |
2833 | average.packages.pkg_temp_c = MAX(average.packages.pkg_temp_c, p->pkg_temp_c); |
2834 | ||
05a2f07d PW |
2835 | rapl_counter_accumulate(&average.packages.rapl_pkg_perf_status, &p->rapl_pkg_perf_status); |
2836 | rapl_counter_accumulate(&average.packages.rapl_dram_perf_status, &p->rapl_dram_perf_status); | |
388e9c81 LB |
2837 | |
2838 | for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) { | |
e5f4e68e DS |
2839 | if ((mp->format == FORMAT_RAW) && (topo.num_packages == 0)) |
2840 | average.packages.counter[i] = p->counter[i]; | |
2841 | else | |
2842 | average.packages.counter[i] += p->counter[i]; | |
388e9c81 | 2843 | } |
c98d5d94 LB |
2844 | return 0; |
2845 | } | |
1b439f01 | 2846 | |
c98d5d94 LB |
2847 | /* |
2848 | * sum the counters for all cpus in the system | |
2849 | * compute the weighted average | |
2850 | */ | |
1b439f01 | 2851 | void compute_average(struct thread_data *t, struct core_data *c, struct pkg_data *p) |
c98d5d94 | 2852 | { |
388e9c81 LB |
2853 | int i; |
2854 | struct msr_counter *mp; | |
2855 | ||
c98d5d94 LB |
2856 | clear_counters(&average.threads, &average.cores, &average.packages); |
2857 | ||
2858 | for_all_cpus(sum_counters, t, c, p); | |
2859 | ||
d4794f25 YG |
2860 | /* Use the global time delta for the average. */ |
2861 | average.threads.tv_delta = tv_delta; | |
2862 | ||
0fe37529 ZR |
2863 | average.threads.tsc /= topo.allowed_cpus; |
2864 | average.threads.aperf /= topo.allowed_cpus; | |
2865 | average.threads.mperf /= topo.allowed_cpus; | |
2866 | average.threads.instr_count /= topo.allowed_cpus; | |
2867 | average.threads.c1 /= topo.allowed_cpus; | |
c98d5d94 | 2868 | |
0de6c0df LB |
2869 | if (average.threads.irq_count > 9999999) |
2870 | sums_need_wide_columns = 1; | |
2871 | ||
0fe37529 ZR |
2872 | average.cores.c3 /= topo.allowed_cores; |
2873 | average.cores.c6 /= topo.allowed_cores; | |
2874 | average.cores.c7 /= topo.allowed_cores; | |
2875 | average.cores.mc6_us /= topo.allowed_cores; | |
c98d5d94 | 2876 | |
a99d8730 | 2877 | if (DO_BIC(BIC_Totl_c0)) |
0fe37529 | 2878 | average.packages.pkg_wtd_core_c0 /= topo.allowed_packages; |
a99d8730 | 2879 | if (DO_BIC(BIC_Any_c0)) |
0fe37529 | 2880 | average.packages.pkg_any_core_c0 /= topo.allowed_packages; |
a99d8730 | 2881 | if (DO_BIC(BIC_GFX_c0)) |
0fe37529 | 2882 | average.packages.pkg_any_gfxe_c0 /= topo.allowed_packages; |
a99d8730 | 2883 | if (DO_BIC(BIC_CPUGFX)) |
0fe37529 | 2884 | average.packages.pkg_both_core_gfxe_c0 /= topo.allowed_packages; |
0b2bb692 | 2885 | |
0fe37529 | 2886 | average.packages.pc2 /= topo.allowed_packages; |
0f47c08d | 2887 | if (DO_BIC(BIC_Pkgpc3)) |
0fe37529 | 2888 | average.packages.pc3 /= topo.allowed_packages; |
0f47c08d | 2889 | if (DO_BIC(BIC_Pkgpc6)) |
0fe37529 | 2890 | average.packages.pc6 /= topo.allowed_packages; |
0f47c08d | 2891 | if (DO_BIC(BIC_Pkgpc7)) |
0fe37529 | 2892 | average.packages.pc7 /= topo.allowed_packages; |
ca58710f | 2893 | |
0fe37529 ZR |
2894 | average.packages.pc8 /= topo.allowed_packages; |
2895 | average.packages.pc9 /= topo.allowed_packages; | |
2896 | average.packages.pc10 /= topo.allowed_packages; | |
388e9c81 LB |
2897 | |
2898 | for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) { | |
2899 | if (mp->format == FORMAT_RAW) | |
2900 | continue; | |
0de6c0df LB |
2901 | if (mp->type == COUNTER_ITEMS) { |
2902 | if (average.threads.counter[i] > 9999999) | |
2903 | sums_need_wide_columns = 1; | |
41618e63 | 2904 | continue; |
0de6c0df | 2905 | } |
0fe37529 | 2906 | average.threads.counter[i] /= topo.allowed_cpus; |
388e9c81 LB |
2907 | } |
2908 | for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) { | |
2909 | if (mp->format == FORMAT_RAW) | |
2910 | continue; | |
0de6c0df LB |
2911 | if (mp->type == COUNTER_ITEMS) { |
2912 | if (average.cores.counter[i] > 9999999) | |
2913 | sums_need_wide_columns = 1; | |
2914 | } | |
0fe37529 | 2915 | average.cores.counter[i] /= topo.allowed_cores; |
388e9c81 LB |
2916 | } |
2917 | for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) { | |
2918 | if (mp->format == FORMAT_RAW) | |
2919 | continue; | |
0de6c0df LB |
2920 | if (mp->type == COUNTER_ITEMS) { |
2921 | if (average.packages.counter[i] > 9999999) | |
2922 | sums_need_wide_columns = 1; | |
2923 | } | |
0fe37529 | 2924 | average.packages.counter[i] /= topo.allowed_packages; |
388e9c81 | 2925 | } |
103a8fea LB |
2926 | } |
2927 | ||
c98d5d94 | 2928 | static unsigned long long rdtsc(void) |
103a8fea | 2929 | { |
c98d5d94 | 2930 | unsigned int low, high; |
15aaa346 | 2931 | |
1b439f01 | 2932 | asm volatile ("rdtsc":"=a" (low), "=d"(high)); |
15aaa346 | 2933 | |
c98d5d94 LB |
2934 | return low | ((unsigned long long)high) << 32; |
2935 | } | |
15aaa346 | 2936 | |
495c7654 LB |
2937 | /* |
2938 | * Open a file, and exit on failure | |
2939 | */ | |
2940 | FILE *fopen_or_die(const char *path, const char *mode) | |
2941 | { | |
2942 | FILE *filep = fopen(path, mode); | |
2943 | ||
2944 | if (!filep) | |
2945 | err(1, "%s: open failed", path); | |
2946 | return filep; | |
2947 | } | |
1b439f01 | 2948 | |
495c7654 LB |
2949 | /* |
2950 | * snapshot_sysfs_counter() | |
2951 | * | |
2952 | * return snapshot of given counter | |
2953 | */ | |
2954 | unsigned long long snapshot_sysfs_counter(char *path) | |
2955 | { | |
2956 | FILE *fp; | |
2957 | int retval; | |
2958 | unsigned long long counter; | |
2959 | ||
2960 | fp = fopen_or_die(path, "r"); | |
2961 | ||
2962 | retval = fscanf(fp, "%lld", &counter); | |
2963 | if (retval != 1) | |
2964 | err(1, "snapshot_sysfs_counter(%s)", path); | |
2965 | ||
2966 | fclose(fp); | |
2967 | ||
2968 | return counter; | |
2969 | } | |
2970 | ||
2971 | int get_mp(int cpu, struct msr_counter *mp, unsigned long long *counterp) | |
2972 | { | |
2973 | if (mp->msr_num != 0) { | |
3e404846 | 2974 | assert(!no_msr); |
495c7654 LB |
2975 | if (get_msr(cpu, mp->msr_num, counterp)) |
2976 | return -1; | |
2977 | } else { | |
46c27978 | 2978 | char path[128 + PATH_BYTES]; |
41618e63 LB |
2979 | |
2980 | if (mp->flags & SYSFS_PERCPU) { | |
1b439f01 | 2981 | sprintf(path, "/sys/devices/system/cpu/cpu%d/%s", cpu, mp->path); |
41618e63 LB |
2982 | |
2983 | *counterp = snapshot_sysfs_counter(path); | |
2984 | } else { | |
2985 | *counterp = snapshot_sysfs_counter(mp->path); | |
2986 | } | |
495c7654 LB |
2987 | } |
2988 | ||
2989 | return 0; | |
2990 | } | |
2991 | ||
a5c6d65d LB |
2992 | unsigned long long get_uncore_mhz(int package, int die) |
2993 | { | |
2994 | char path[128]; | |
2995 | ||
60add818 | 2996 | sprintf(path, "/sys/devices/system/cpu/intel_uncore_frequency/package_%02d_die_%02d/current_freq_khz", package, |
a5c6d65d LB |
2997 | die); |
2998 | ||
2999 | return (snapshot_sysfs_counter(path) / 1000); | |
3000 | } | |
3001 | ||
6d6501d9 BP |
3002 | int get_epb(int cpu) |
3003 | { | |
3004 | char path[128 + PATH_BYTES]; | |
7f1b11ba | 3005 | unsigned long long msr; |
6d6501d9 BP |
3006 | int ret, epb = -1; |
3007 | FILE *fp; | |
3008 | ||
3009 | sprintf(path, "/sys/devices/system/cpu/cpu%d/power/energy_perf_bias", cpu); | |
3010 | ||
7f1b11ba BP |
3011 | fp = fopen(path, "r"); |
3012 | if (!fp) | |
3013 | goto msr_fallback; | |
6d6501d9 BP |
3014 | |
3015 | ret = fscanf(fp, "%d", &epb); | |
3016 | if (ret != 1) | |
3017 | err(1, "%s(%s)", __func__, path); | |
3018 | ||
3019 | fclose(fp); | |
3020 | ||
3021 | return epb; | |
7f1b11ba BP |
3022 | |
3023 | msr_fallback: | |
3e404846 PW |
3024 | if (no_msr) |
3025 | return -1; | |
3026 | ||
7f1b11ba BP |
3027 | get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr); |
3028 | ||
3029 | return msr & 0xf; | |
6d6501d9 BP |
3030 | } |
3031 | ||
4c2122d4 LB |
3032 | void get_apic_id(struct thread_data *t) |
3033 | { | |
34041551 | 3034 | unsigned int eax, ebx, ecx, edx; |
4c2122d4 | 3035 | |
34041551 LB |
3036 | if (DO_BIC(BIC_APIC)) { |
3037 | eax = ebx = ecx = edx = 0; | |
3038 | __cpuid(1, eax, ebx, ecx, edx); | |
4c2122d4 | 3039 | |
34041551 LB |
3040 | t->apic_id = (ebx >> 24) & 0xff; |
3041 | } | |
3042 | ||
3043 | if (!DO_BIC(BIC_X2APIC)) | |
4c2122d4 LB |
3044 | return; |
3045 | ||
c1c10cc7 | 3046 | if (authentic_amd || hygon_genuine) { |
34041551 | 3047 | unsigned int topology_extensions; |
4c2122d4 | 3048 | |
34041551 LB |
3049 | if (max_extended_level < 0x8000001e) |
3050 | return; | |
4c2122d4 | 3051 | |
34041551 LB |
3052 | eax = ebx = ecx = edx = 0; |
3053 | __cpuid(0x80000001, eax, ebx, ecx, edx); | |
1b439f01 | 3054 | topology_extensions = ecx & (1 << 22); |
34041551 LB |
3055 | |
3056 | if (topology_extensions == 0) | |
3057 | return; | |
3058 | ||
3059 | eax = ebx = ecx = edx = 0; | |
3060 | __cpuid(0x8000001e, eax, ebx, ecx, edx); | |
3061 | ||
3062 | t->x2apic_id = eax; | |
4c2122d4 | 3063 | return; |
34041551 | 3064 | } |
4c2122d4 | 3065 | |
34041551 LB |
3066 | if (!genuine_intel) |
3067 | return; | |
3068 | ||
3069 | if (max_level < 0xb) | |
4c2122d4 LB |
3070 | return; |
3071 | ||
3072 | ecx = 0; | |
3073 | __cpuid(0xb, eax, ebx, ecx, edx); | |
3074 | t->x2apic_id = edx; | |
3075 | ||
34041551 | 3076 | if (debug && (t->apic_id != (t->x2apic_id & 0xff))) |
1b439f01 | 3077 | fprintf(outf, "cpu%d: BIOS BUG: apic 0x%x x2apic 0x%x\n", t->cpu_id, t->apic_id, t->x2apic_id); |
4c2122d4 LB |
3078 | } |
3079 | ||
eae97e05 CY |
3080 | int get_core_throt_cnt(int cpu, unsigned long long *cnt) |
3081 | { | |
3082 | char path[128 + PATH_BYTES]; | |
3083 | unsigned long long tmp; | |
3084 | FILE *fp; | |
3085 | int ret; | |
3086 | ||
3087 | sprintf(path, "/sys/devices/system/cpu/cpu%d/thermal_throttle/core_throttle_count", cpu); | |
3088 | fp = fopen(path, "r"); | |
3089 | if (!fp) | |
3090 | return -1; | |
3091 | ret = fscanf(fp, "%lld", &tmp); | |
5e5fd36c | 3092 | fclose(fp); |
eae97e05 CY |
3093 | if (ret != 1) |
3094 | return -1; | |
eae97e05 CY |
3095 | *cnt = tmp; |
3096 | ||
3097 | return 0; | |
3098 | } | |
3099 | ||
e48934c9 PW |
3100 | struct amperf_group_fd { |
3101 | int aperf; /* Also the group descriptor */ | |
3102 | int mperf; | |
3103 | }; | |
3104 | ||
05a2f07d | 3105 | static int read_perf_counter_info(const char *const path, const char *const parse_format, void *value_ptr) |
e48934c9 PW |
3106 | { |
3107 | int fdmt; | |
05a2f07d PW |
3108 | int bytes_read; |
3109 | char buf[64]; | |
3110 | int ret = -1; | |
e48934c9 PW |
3111 | |
3112 | fdmt = open(path, O_RDONLY, 0); | |
05a2f07d PW |
3113 | if (fdmt == -1) { |
3114 | if (debug) | |
3115 | fprintf(stderr, "Failed to parse perf counter info %s\n", path); | |
3116 | ret = -1; | |
3117 | goto cleanup_and_exit; | |
3118 | } | |
e48934c9 | 3119 | |
05a2f07d PW |
3120 | bytes_read = read(fdmt, buf, sizeof(buf) - 1); |
3121 | if (bytes_read <= 0 || bytes_read >= (int)sizeof(buf)) { | |
3122 | if (debug) | |
3123 | fprintf(stderr, "Failed to parse perf counter info %s\n", path); | |
3124 | ret = -1; | |
3125 | goto cleanup_and_exit; | |
3126 | } | |
e48934c9 | 3127 | |
05a2f07d | 3128 | buf[bytes_read] = '\0'; |
e48934c9 | 3129 | |
05a2f07d PW |
3130 | if (sscanf(buf, parse_format, value_ptr) != 1) { |
3131 | if (debug) | |
3132 | fprintf(stderr, "Failed to parse perf counter info %s\n", path); | |
3133 | ret = -1; | |
3134 | goto cleanup_and_exit; | |
3135 | } | |
e48934c9 | 3136 | |
05a2f07d PW |
3137 | ret = 0; |
3138 | ||
3139 | cleanup_and_exit: | |
e48934c9 | 3140 | close(fdmt); |
05a2f07d PW |
3141 | return ret; |
3142 | } | |
3143 | ||
3144 | static unsigned int read_perf_counter_info_n(const char *const path, const char *const parse_format) | |
3145 | { | |
3146 | unsigned int v; | |
3147 | int status; | |
3148 | ||
3149 | status = read_perf_counter_info(path, parse_format, &v); | |
3150 | if (status) | |
3151 | v = -1; | |
e48934c9 PW |
3152 | |
3153 | return v; | |
3154 | } | |
3155 | ||
3156 | static unsigned read_msr_type(void) | |
3157 | { | |
3158 | const char *const path = "/sys/bus/event_source/devices/msr/type"; | |
3159 | const char *const format = "%u"; | |
3160 | ||
05a2f07d | 3161 | return read_perf_counter_info_n(path, format); |
e48934c9 PW |
3162 | } |
3163 | ||
3164 | static unsigned read_aperf_config(void) | |
3165 | { | |
3166 | const char *const path = "/sys/bus/event_source/devices/msr/events/aperf"; | |
3167 | const char *const format = "event=%x"; | |
3168 | ||
05a2f07d | 3169 | return read_perf_counter_info_n(path, format); |
e48934c9 PW |
3170 | } |
3171 | ||
3172 | static unsigned read_mperf_config(void) | |
3173 | { | |
3174 | const char *const path = "/sys/bus/event_source/devices/msr/events/mperf"; | |
3175 | const char *const format = "event=%x"; | |
3176 | ||
05a2f07d PW |
3177 | return read_perf_counter_info_n(path, format); |
3178 | } | |
3179 | ||
3180 | static unsigned read_perf_type(const char *subsys) | |
3181 | { | |
3182 | const char *const path_format = "/sys/bus/event_source/devices/%s/type"; | |
3183 | const char *const format = "%u"; | |
3184 | char path[128]; | |
3185 | ||
3186 | snprintf(path, sizeof(path), path_format, subsys); | |
3187 | ||
3188 | return read_perf_counter_info_n(path, format); | |
3189 | } | |
3190 | ||
3191 | static unsigned read_rapl_config(const char *subsys, const char *event_name) | |
3192 | { | |
3193 | const char *const path_format = "/sys/bus/event_source/devices/%s/events/%s"; | |
3194 | const char *const format = "event=%x"; | |
3195 | char path[128]; | |
3196 | ||
3197 | snprintf(path, sizeof(path), path_format, subsys, event_name); | |
3198 | ||
3199 | return read_perf_counter_info_n(path, format); | |
3200 | } | |
3201 | ||
3202 | static unsigned read_perf_rapl_unit(const char *subsys, const char *event_name) | |
3203 | { | |
3204 | const char *const path_format = "/sys/bus/event_source/devices/%s/events/%s.unit"; | |
3205 | const char *const format = "%s"; | |
3206 | char path[128]; | |
3207 | char unit_buffer[16]; | |
3208 | ||
3209 | snprintf(path, sizeof(path), path_format, subsys, event_name); | |
3210 | ||
3211 | read_perf_counter_info(path, format, &unit_buffer); | |
3212 | if (strcmp("Joules", unit_buffer) == 0) | |
3213 | return RAPL_UNIT_JOULES; | |
3214 | ||
3215 | return RAPL_UNIT_INVALID; | |
3216 | } | |
3217 | ||
3218 | static double read_perf_rapl_scale(const char *subsys, const char *event_name) | |
3219 | { | |
3220 | const char *const path_format = "/sys/bus/event_source/devices/%s/events/%s.scale"; | |
3221 | const char *const format = "%lf"; | |
3222 | char path[128]; | |
3223 | double scale; | |
3224 | ||
3225 | snprintf(path, sizeof(path), path_format, subsys, event_name); | |
3226 | ||
3227 | if (read_perf_counter_info(path, format, &scale)) | |
3228 | return 0.0; | |
3229 | ||
3230 | return scale; | |
e48934c9 PW |
3231 | } |
3232 | ||
3233 | static struct amperf_group_fd open_amperf_fd(int cpu) | |
3234 | { | |
3235 | const unsigned int msr_type = read_msr_type(); | |
3236 | const unsigned int aperf_config = read_aperf_config(); | |
3237 | const unsigned int mperf_config = read_mperf_config(); | |
3238 | struct amperf_group_fd fds = {.aperf = -1,.mperf = -1 }; | |
3239 | ||
5088741e PW |
3240 | fds.aperf = open_perf_counter(cpu, msr_type, aperf_config, -1, PERF_FORMAT_GROUP); |
3241 | fds.mperf = open_perf_counter(cpu, msr_type, mperf_config, fds.aperf, PERF_FORMAT_GROUP); | |
e48934c9 PW |
3242 | |
3243 | return fds; | |
3244 | } | |
3245 | ||
3246 | static int get_amperf_fd(int cpu) | |
3247 | { | |
3248 | assert(fd_amperf_percpu); | |
3249 | ||
3250 | if (fd_amperf_percpu[cpu].aperf) | |
3251 | return fd_amperf_percpu[cpu].aperf; | |
3252 | ||
3253 | fd_amperf_percpu[cpu] = open_amperf_fd(cpu); | |
3254 | ||
3255 | return fd_amperf_percpu[cpu].aperf; | |
3256 | } | |
3257 | ||
3258 | /* Read APERF, MPERF and TSC using the perf API. */ | |
3259 | static int read_aperf_mperf_tsc_perf(struct thread_data *t, int cpu) | |
3260 | { | |
3261 | union { | |
3262 | struct { | |
3263 | unsigned long nr_entries; | |
3264 | unsigned long aperf; | |
3265 | unsigned long mperf; | |
3266 | }; | |
3267 | ||
3268 | unsigned long as_array[3]; | |
3269 | } cnt; | |
3270 | ||
3271 | const int fd_amperf = get_amperf_fd(cpu); | |
3272 | ||
3273 | /* | |
3274 | * Read the TSC with rdtsc, because we want the absolute value and not | |
3275 | * the offset from the start of the counter. | |
3276 | */ | |
3277 | t->tsc = rdtsc(); | |
3278 | ||
3279 | const int n = read(fd_amperf, &cnt.as_array[0], sizeof(cnt.as_array)); | |
3280 | if (n != sizeof(cnt.as_array)) | |
3281 | return -2; | |
3282 | ||
3283 | t->aperf = cnt.aperf * aperf_mperf_multiplier; | |
3284 | t->mperf = cnt.mperf * aperf_mperf_multiplier; | |
3285 | ||
3286 | return 0; | |
3287 | } | |
3288 | ||
3289 | /* Read APERF, MPERF and TSC using the MSR driver and rdtsc instruction. */ | |
3290 | static int read_aperf_mperf_tsc_msr(struct thread_data *t, int cpu) | |
3291 | { | |
3292 | unsigned long long tsc_before, tsc_between, tsc_after, aperf_time, mperf_time; | |
3293 | int aperf_mperf_retry_count = 0; | |
3294 | ||
3295 | /* | |
3296 | * The TSC, APERF and MPERF must be read together for | |
3297 | * APERF/MPERF and MPERF/TSC to give accurate results. | |
3298 | * | |
3299 | * Unfortunately, APERF and MPERF are read by | |
3300 | * individual system call, so delays may occur | |
3301 | * between them. If the time to read them | |
3302 | * varies by a large amount, we re-read them. | |
3303 | */ | |
3304 | ||
3305 | /* | |
3306 | * This initial dummy APERF read has been seen to | |
3307 | * reduce jitter in the subsequent reads. | |
3308 | */ | |
3309 | ||
3310 | if (get_msr(cpu, MSR_IA32_APERF, &t->aperf)) | |
3311 | return -3; | |
3312 | ||
3313 | retry: | |
3314 | t->tsc = rdtsc(); /* re-read close to APERF */ | |
3315 | ||
3316 | tsc_before = t->tsc; | |
3317 | ||
3318 | if (get_msr(cpu, MSR_IA32_APERF, &t->aperf)) | |
3319 | return -3; | |
3320 | ||
3321 | tsc_between = rdtsc(); | |
3322 | ||
3323 | if (get_msr(cpu, MSR_IA32_MPERF, &t->mperf)) | |
3324 | return -4; | |
3325 | ||
3326 | tsc_after = rdtsc(); | |
3327 | ||
3328 | aperf_time = tsc_between - tsc_before; | |
3329 | mperf_time = tsc_after - tsc_between; | |
3330 | ||
3331 | /* | |
3332 | * If the system call latency to read APERF and MPERF | |
3333 | * differ by more than 2x, then try again. | |
3334 | */ | |
3335 | if ((aperf_time > (2 * mperf_time)) || (mperf_time > (2 * aperf_time))) { | |
3336 | aperf_mperf_retry_count++; | |
3337 | if (aperf_mperf_retry_count < 5) | |
3338 | goto retry; | |
3339 | else | |
3340 | warnx("cpu%d jitter %lld %lld", cpu, aperf_time, mperf_time); | |
3341 | } | |
3342 | aperf_mperf_retry_count = 0; | |
3343 | ||
3344 | t->aperf = t->aperf * aperf_mperf_multiplier; | |
3345 | t->mperf = t->mperf * aperf_mperf_multiplier; | |
3346 | ||
3347 | return 0; | |
3348 | } | |
3349 | ||
05a2f07d PW |
3350 | size_t rapl_counter_info_count_perf(const struct rapl_counter_info_t *rci) |
3351 | { | |
3352 | size_t ret = 0; | |
3353 | ||
3354 | for (int i = 0; i < NUM_RAPL_COUNTERS; ++i) | |
3355 | if (rci->source[i] == RAPL_SOURCE_PERF) | |
3356 | ++ret; | |
3357 | ||
3358 | return ret; | |
3359 | } | |
3360 | ||
3361 | void write_rapl_counter(struct rapl_counter *rc, struct rapl_counter_info_t *rci, unsigned int idx) | |
3362 | { | |
3363 | rc->raw_value = rci->data[idx]; | |
3364 | rc->unit = rci->unit[idx]; | |
3365 | rc->scale = rci->scale[idx]; | |
3366 | } | |
3367 | ||
3368 | int get_rapl_counters(int cpu, int domain, struct core_data *c, struct pkg_data *p) | |
3369 | { | |
3370 | unsigned long long perf_data[NUM_RAPL_COUNTERS + 1]; | |
3371 | struct rapl_counter_info_t *rci = &rapl_counter_info_perdomain[domain]; | |
3372 | ||
3373 | if (debug) | |
3374 | fprintf(stderr, "get_rapl_counters: cpu%d domain%d\n", cpu, domain); | |
3375 | ||
3376 | assert(rapl_counter_info_perdomain); | |
3377 | ||
3378 | /* | |
3379 | * If we have any perf counters to read, read them all now, in bulk | |
3380 | */ | |
3381 | if (rci->fd_perf != -1) { | |
3382 | size_t num_perf_counters = rapl_counter_info_count_perf(rci); | |
3383 | const ssize_t expected_read_size = (num_perf_counters + 1) * sizeof(unsigned long long); | |
3384 | const ssize_t actual_read_size = read(rci->fd_perf, &perf_data[0], sizeof(perf_data)); | |
3385 | if (actual_read_size != expected_read_size) | |
3386 | err(-1, "get_rapl_counters: failed to read perf_data (%zu %zu)", expected_read_size, | |
3387 | actual_read_size); | |
3388 | } | |
3389 | ||
3390 | for (unsigned int i = 0, pi = 1; i < NUM_RAPL_COUNTERS; ++i) { | |
3391 | switch (rci->source[i]) { | |
3392 | case RAPL_SOURCE_NONE: | |
3393 | break; | |
3394 | ||
3395 | case RAPL_SOURCE_PERF: | |
3396 | assert(pi < ARRAY_SIZE(perf_data)); | |
3397 | assert(rci->fd_perf != -1); | |
3398 | ||
3399 | if (debug) | |
3400 | fprintf(stderr, "Reading rapl counter via perf at %u (%llu %e %lf)\n", | |
3401 | i, perf_data[pi], rci->scale[i], perf_data[pi] * rci->scale[i]); | |
3402 | ||
3403 | rci->data[i] = perf_data[pi]; | |
3404 | ||
3405 | ++pi; | |
3406 | break; | |
3407 | ||
3408 | case RAPL_SOURCE_MSR: | |
3409 | if (debug) | |
3410 | fprintf(stderr, "Reading rapl counter via msr at %u\n", i); | |
3411 | ||
3412 | assert(!no_msr); | |
3413 | if (rci->flags[i] & RAPL_COUNTER_FLAG_USE_MSR_SUM) { | |
3414 | if (get_msr_sum(cpu, rci->msr[i], &rci->data[i])) | |
3415 | return -13 - i; | |
3416 | } else { | |
3417 | if (get_msr(cpu, rci->msr[i], &rci->data[i])) | |
3418 | return -13 - i; | |
3419 | } | |
3420 | ||
3421 | rci->data[i] &= rci->msr_mask[i]; | |
3422 | if (rci->msr_shift[i] >= 0) | |
3423 | rci->data[i] >>= abs(rci->msr_shift[i]); | |
3424 | else | |
3425 | rci->data[i] <<= abs(rci->msr_shift[i]); | |
3426 | ||
3427 | break; | |
3428 | } | |
3429 | } | |
3430 | ||
3431 | _Static_assert(NUM_RAPL_COUNTERS == 7); | |
3432 | write_rapl_counter(&p->energy_pkg, rci, RAPL_RCI_INDEX_ENERGY_PKG); | |
3433 | write_rapl_counter(&p->energy_cores, rci, RAPL_RCI_INDEX_ENERGY_CORES); | |
3434 | write_rapl_counter(&p->energy_dram, rci, RAPL_RCI_INDEX_DRAM); | |
3435 | write_rapl_counter(&p->energy_gfx, rci, RAPL_RCI_INDEX_GFX); | |
3436 | write_rapl_counter(&p->rapl_pkg_perf_status, rci, RAPL_RCI_INDEX_PKG_PERF_STATUS); | |
3437 | write_rapl_counter(&p->rapl_dram_perf_status, rci, RAPL_RCI_INDEX_DRAM_PERF_STATUS); | |
3438 | write_rapl_counter(&c->core_energy, rci, RAPL_RCI_INDEX_CORE_ENERGY); | |
3439 | ||
3440 | return 0; | |
3441 | } | |
3442 | ||
c98d5d94 LB |
3443 | /* |
3444 | * get_counters(...) | |
3445 | * migrate to cpu | |
3446 | * acquire and record local counters for that cpu | |
3447 | */ | |
3448 | int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) | |
3449 | { | |
3450 | int cpu = t->cpu_id; | |
889facbe | 3451 | unsigned long long msr; |
388e9c81 LB |
3452 | struct msr_counter *mp; |
3453 | int i; | |
05a2f07d | 3454 | int status; |
88c3281f | 3455 | |
e52966c0 | 3456 | if (cpu_migrate(cpu)) { |
3d7772ea | 3457 | fprintf(outf, "get_counters: Could not migrate to CPU %d\n", cpu); |
c98d5d94 | 3458 | return -1; |
e52966c0 | 3459 | } |
15aaa346 | 3460 | |
d4794f25 YG |
3461 | gettimeofday(&t->tv_begin, (struct timezone *)NULL); |
3462 | ||
4c2122d4 LB |
3463 | if (first_counter_read) |
3464 | get_apic_id(t); | |
e48934c9 | 3465 | |
c98d5d94 LB |
3466 | t->tsc = rdtsc(); /* we are running on local CPU of interest */ |
3467 | ||
f2c1dba3 LB |
3468 | if (DO_BIC(BIC_Avg_MHz) || DO_BIC(BIC_Busy) || DO_BIC(BIC_Bzy_MHz) || DO_BIC(BIC_IPC) |
3469 | || soft_c1_residency_display(BIC_Avg_MHz)) { | |
e48934c9 | 3470 | int status = -1; |
0102b067 | 3471 | |
e48934c9 | 3472 | assert(!no_perf || !no_msr); |
0102b067 | 3473 | |
e48934c9 PW |
3474 | switch (amperf_source) { |
3475 | case AMPERF_SOURCE_PERF: | |
3476 | status = read_aperf_mperf_tsc_perf(t, cpu); | |
3477 | break; | |
3478 | case AMPERF_SOURCE_MSR: | |
3479 | status = read_aperf_mperf_tsc_msr(t, cpu); | |
3480 | break; | |
0102b067 | 3481 | } |
0102b067 | 3482 | |
e48934c9 PW |
3483 | if (status != 0) |
3484 | return status; | |
c98d5d94 LB |
3485 | } |
3486 | ||
2af4f9b8 LB |
3487 | if (DO_BIC(BIC_IPC)) |
3488 | if (read(get_instr_count_fd(cpu), &t->instr_count, sizeof(long long)) != sizeof(long long)) | |
3489 | return -4; | |
3490 | ||
812db3f7 | 3491 | if (DO_BIC(BIC_IRQ)) |
562a2d37 | 3492 | t->irq_count = irqs_per_cpu[cpu]; |
812db3f7 | 3493 | if (DO_BIC(BIC_SMI)) { |
1ed51011 LB |
3494 | if (get_msr(cpu, MSR_SMI_COUNT, &msr)) |
3495 | return -5; | |
3496 | t->smi_count = msr & 0xFFFFFFFF; | |
3497 | } | |
76d83d2a | 3498 | if (DO_BIC(BIC_CPU_c1) && platform->has_msr_core_c1_res) { |
144b44b1 LB |
3499 | if (get_msr(cpu, MSR_CORE_C1_RES, &t->c1)) |
3500 | return -6; | |
3501 | } | |
3502 | ||
388e9c81 | 3503 | for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) { |
495c7654 | 3504 | if (get_mp(cpu, mp, &t->counter[i])) |
388e9c81 LB |
3505 | return -10; |
3506 | } | |
3507 | ||
c98d5d94 | 3508 | /* collect core counters only for 1st thread in core */ |
74318add | 3509 | if (!is_cpu_first_thread_in_core(t, c, p)) |
f4fdf2b4 | 3510 | goto done; |
c98d5d94 | 3511 | |
05a2f07d PW |
3512 | if (platform->has_per_core_rapl) { |
3513 | status = get_rapl_counters(cpu, c->core_id, c, p); | |
3514 | if (status != 0) | |
3515 | return status; | |
3516 | } | |
3517 | ||
1e9042b9 | 3518 | if (DO_BIC(BIC_CPU_c3) || soft_c1_residency_display(BIC_CPU_c3)) { |
c98d5d94 LB |
3519 | if (get_msr(cpu, MSR_CORE_C3_RESIDENCY, &c->c3)) |
3520 | return -6; | |
144b44b1 LB |
3521 | } |
3522 | ||
80d132cb | 3523 | if ((DO_BIC(BIC_CPU_c6) || soft_c1_residency_display(BIC_CPU_c6)) && !platform->has_msr_knl_core_c6_residency) { |
c98d5d94 LB |
3524 | if (get_msr(cpu, MSR_CORE_C6_RESIDENCY, &c->c6)) |
3525 | return -7; | |
80d132cb | 3526 | } else if (platform->has_msr_knl_core_c6_residency && soft_c1_residency_display(BIC_CPU_c6)) { |
fb5d4327 DC |
3527 | if (get_msr(cpu, MSR_KNL_CORE_C6_RESIDENCY, &c->c6)) |
3528 | return -7; | |
c98d5d94 LB |
3529 | } |
3530 | ||
7ab5ff49 | 3531 | if (DO_BIC(BIC_CPU_c7) || soft_c1_residency_display(BIC_CPU_c7)) { |
c98d5d94 LB |
3532 | if (get_msr(cpu, MSR_CORE_C7_RESIDENCY, &c->c7)) |
3533 | return -8; | |
7ab5ff49 ZR |
3534 | else if (t->is_atom) { |
3535 | /* | |
3536 | * For Atom CPUs that has core cstate deeper than c6, | |
3537 | * MSR_CORE_C6_RESIDENCY returns residency of cc6 and deeper. | |
3538 | * Minus CC7 (and deeper cstates) residency to get | |
3539 | * accturate cc6 residency. | |
3540 | */ | |
3541 | c->c6 -= c->c7; | |
3542 | } | |
3543 | } | |
c98d5d94 | 3544 | |
0539ba11 LB |
3545 | if (DO_BIC(BIC_Mod_c6)) |
3546 | if (get_msr(cpu, MSR_MODULE_C6_RES_MS, &c->mc6_us)) | |
3547 | return -8; | |
3548 | ||
812db3f7 | 3549 | if (DO_BIC(BIC_CoreTmp)) { |
889facbe LB |
3550 | if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr)) |
3551 | return -9; | |
55279aef | 3552 | c->core_temp_c = tj_max - ((msr >> 16) & 0x7F); |
889facbe LB |
3553 | } |
3554 | ||
eae97e05 CY |
3555 | if (DO_BIC(BIC_CORE_THROT_CNT)) |
3556 | get_core_throt_cnt(cpu, &c->core_throt_cnt); | |
3557 | ||
388e9c81 | 3558 | for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) { |
495c7654 | 3559 | if (get_mp(cpu, mp, &c->counter[i])) |
388e9c81 LB |
3560 | return -10; |
3561 | } | |
889facbe | 3562 | |
c98d5d94 | 3563 | /* collect package counters only for 1st core in package */ |
74318add | 3564 | if (!is_cpu_first_core_in_package(t, c, p)) |
f4fdf2b4 | 3565 | goto done; |
c98d5d94 | 3566 | |
a99d8730 | 3567 | if (DO_BIC(BIC_Totl_c0)) { |
0b2bb692 LB |
3568 | if (get_msr(cpu, MSR_PKG_WEIGHTED_CORE_C0_RES, &p->pkg_wtd_core_c0)) |
3569 | return -10; | |
a99d8730 LB |
3570 | } |
3571 | if (DO_BIC(BIC_Any_c0)) { | |
0b2bb692 LB |
3572 | if (get_msr(cpu, MSR_PKG_ANY_CORE_C0_RES, &p->pkg_any_core_c0)) |
3573 | return -11; | |
a99d8730 LB |
3574 | } |
3575 | if (DO_BIC(BIC_GFX_c0)) { | |
0b2bb692 LB |
3576 | if (get_msr(cpu, MSR_PKG_ANY_GFXE_C0_RES, &p->pkg_any_gfxe_c0)) |
3577 | return -12; | |
a99d8730 LB |
3578 | } |
3579 | if (DO_BIC(BIC_CPUGFX)) { | |
0b2bb692 LB |
3580 | if (get_msr(cpu, MSR_PKG_BOTH_CORE_GFXE_C0_RES, &p->pkg_both_core_gfxe_c0)) |
3581 | return -13; | |
3582 | } | |
0f47c08d | 3583 | if (DO_BIC(BIC_Pkgpc3)) |
c98d5d94 LB |
3584 | if (get_msr(cpu, MSR_PKG_C3_RESIDENCY, &p->pc3)) |
3585 | return -9; | |
0f47c08d | 3586 | if (DO_BIC(BIC_Pkgpc6)) { |
c8202a6c | 3587 | if (platform->has_msr_atom_pkg_c6_residency) { |
0539ba11 LB |
3588 | if (get_msr(cpu, MSR_ATOM_PKG_C6_RESIDENCY, &p->pc6)) |
3589 | return -10; | |
3590 | } else { | |
3591 | if (get_msr(cpu, MSR_PKG_C6_RESIDENCY, &p->pc6)) | |
3592 | return -10; | |
3593 | } | |
3594 | } | |
3595 | ||
0f47c08d | 3596 | if (DO_BIC(BIC_Pkgpc2)) |
c98d5d94 LB |
3597 | if (get_msr(cpu, MSR_PKG_C2_RESIDENCY, &p->pc2)) |
3598 | return -11; | |
0f47c08d | 3599 | if (DO_BIC(BIC_Pkgpc7)) |
c98d5d94 LB |
3600 | if (get_msr(cpu, MSR_PKG_C7_RESIDENCY, &p->pc7)) |
3601 | return -12; | |
0f47c08d | 3602 | if (DO_BIC(BIC_Pkgpc8)) |
ca58710f KCA |
3603 | if (get_msr(cpu, MSR_PKG_C8_RESIDENCY, &p->pc8)) |
3604 | return -13; | |
0f47c08d | 3605 | if (DO_BIC(BIC_Pkgpc9)) |
ca58710f KCA |
3606 | if (get_msr(cpu, MSR_PKG_C9_RESIDENCY, &p->pc9)) |
3607 | return -13; | |
0f47c08d | 3608 | if (DO_BIC(BIC_Pkgpc10)) |
ca58710f KCA |
3609 | if (get_msr(cpu, MSR_PKG_C10_RESIDENCY, &p->pc10)) |
3610 | return -13; | |
0f47c08d | 3611 | |
be0e54c4 LB |
3612 | if (DO_BIC(BIC_CPU_LPI)) |
3613 | p->cpu_lpi = cpuidle_cur_cpu_lpi_us; | |
3614 | if (DO_BIC(BIC_SYS_LPI)) | |
3615 | p->sys_lpi = cpuidle_cur_sys_lpi_us; | |
3616 | ||
05a2f07d PW |
3617 | if (!platform->has_per_core_rapl) { |
3618 | status = get_rapl_counters(cpu, p->package_id, c, p); | |
3619 | if (status != 0) | |
3620 | return status; | |
3316f99a | 3621 | } |
3e404846 | 3622 | |
812db3f7 | 3623 | if (DO_BIC(BIC_PkgTmp)) { |
889facbe LB |
3624 | if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr)) |
3625 | return -17; | |
55279aef | 3626 | p->pkg_temp_c = tj_max - ((msr >> 16) & 0x7F); |
889facbe | 3627 | } |
fdf676e5 | 3628 | |
a5c6d65d LB |
3629 | /* n.b. assume die0 uncore frequency applies to whole package */ |
3630 | if (DO_BIC(BIC_UNCORE_MHZ)) | |
3631 | p->uncore_mhz = get_uncore_mhz(p->package_id, 0); | |
3632 | ||
3bbb331c ZR |
3633 | if (DO_BIC(BIC_GFX_rc6)) |
3634 | p->gfx_rc6_ms = gfx_info[GFX_rc6].val_ull; | |
3635 | ||
812db3f7 | 3636 | if (DO_BIC(BIC_GFXMHz)) |
de39d38c | 3637 | p->gfx_mhz = gfx_info[GFX_MHz].val; |
27d47356 | 3638 | |
b4b91569 | 3639 | if (DO_BIC(BIC_GFXACTMHz)) |
de39d38c | 3640 | p->gfx_act_mhz = gfx_info[GFX_ACTMHz].val; |
b4b91569 | 3641 | |
3bbb331c ZR |
3642 | if (DO_BIC(BIC_SAM_mc6)) |
3643 | p->sam_mc6_ms = gfx_info[SAM_mc6].val_ull; | |
3644 | ||
3645 | if (DO_BIC(BIC_SAMMHz)) | |
3646 | p->sam_mhz = gfx_info[SAM_MHz].val; | |
3647 | ||
3648 | if (DO_BIC(BIC_SAMACTMHz)) | |
3649 | p->sam_act_mhz = gfx_info[SAM_ACTMHz].val; | |
3650 | ||
388e9c81 | 3651 | for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) { |
495c7654 | 3652 | if (get_mp(cpu, mp, &p->counter[i])) |
388e9c81 LB |
3653 | return -10; |
3654 | } | |
f4fdf2b4 LB |
3655 | done: |
3656 | gettimeofday(&t->tv_end, (struct timezone *)NULL); | |
388e9c81 | 3657 | |
15aaa346 | 3658 | return 0; |
103a8fea LB |
3659 | } |
3660 | ||
ee7e38e3 LB |
3661 | /* |
3662 | * MSR_PKG_CST_CONFIG_CONTROL decoding for pkg_cstate_limit: | |
3663 | * If you change the values, note they are used both in comparisons | |
3664 | * (>= PCL__7) and to index pkg_cstate_limit_strings[]. | |
3665 | */ | |
3666 | ||
1b439f01 LB |
3667 | #define PCLUKN 0 /* Unknown */ |
3668 | #define PCLRSV 1 /* Reserved */ | |
3669 | #define PCL__0 2 /* PC0 */ | |
3670 | #define PCL__1 3 /* PC1 */ | |
3671 | #define PCL__2 4 /* PC2 */ | |
3672 | #define PCL__3 5 /* PC3 */ | |
3673 | #define PCL__4 6 /* PC4 */ | |
3674 | #define PCL__6 7 /* PC6 */ | |
3675 | #define PCL_6N 8 /* PC6 No Retention */ | |
3676 | #define PCL_6R 9 /* PC6 Retention */ | |
3677 | #define PCL__7 10 /* PC7 */ | |
3678 | #define PCL_7S 11 /* PC7 Shrink */ | |
3679 | #define PCL__8 12 /* PC8 */ | |
3680 | #define PCL__9 13 /* PC9 */ | |
3681 | #define PCL_10 14 /* PC10 */ | |
3682 | #define PCLUNL 15 /* Unlimited */ | |
ee7e38e3 LB |
3683 | |
3684 | int pkg_cstate_limit = PCLUKN; | |
3685 | char *pkg_cstate_limit_strings[] = { "reserved", "unknown", "pc0", "pc1", "pc2", | |
1b439f01 LB |
3686 | "pc3", "pc4", "pc6", "pc6n", "pc6r", "pc7", "pc7s", "pc8", "pc9", "pc10", "unlimited" |
3687 | }; | |
a2b7b749 | 3688 | |
1b439f01 LB |
3689 | int nhm_pkg_cstate_limits[16] = |
3690 | { PCL__0, PCL__1, PCL__3, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, | |
38c6663a LB |
3691 | PCLRSV, PCLRSV |
3692 | }; | |
3693 | ||
1b439f01 LB |
3694 | int snb_pkg_cstate_limits[16] = |
3695 | { PCL__0, PCL__2, PCL_6N, PCL_6R, PCL__7, PCL_7S, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, | |
38c6663a LB |
3696 | PCLRSV, PCLRSV |
3697 | }; | |
3698 | ||
1b439f01 LB |
3699 | int hsw_pkg_cstate_limits[16] = |
3700 | { PCL__0, PCL__2, PCL__3, PCL__6, PCL__7, PCL_7S, PCL__8, PCL__9, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, | |
38c6663a LB |
3701 | PCLRSV, PCLRSV |
3702 | }; | |
3703 | ||
1b439f01 LB |
3704 | int slv_pkg_cstate_limits[16] = |
3705 | { PCL__0, PCL__1, PCLRSV, PCLRSV, PCL__4, PCLRSV, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, | |
38c6663a LB |
3706 | PCL__6, PCL__7 |
3707 | }; | |
3708 | ||
1b439f01 LB |
3709 | int amt_pkg_cstate_limits[16] = |
3710 | { PCLUNL, PCL__1, PCL__2, PCLRSV, PCLRSV, PCLRSV, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, | |
38c6663a LB |
3711 | PCLRSV, PCLRSV |
3712 | }; | |
3713 | ||
1b439f01 LB |
3714 | int phi_pkg_cstate_limits[16] = |
3715 | { PCL__0, PCL__2, PCL_6N, PCL_6R, PCLRSV, PCLRSV, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, | |
38c6663a LB |
3716 | PCLRSV, PCLRSV |
3717 | }; | |
3718 | ||
1b439f01 LB |
3719 | int glm_pkg_cstate_limits[16] = |
3720 | { PCLUNL, PCL__1, PCL__3, PCL__6, PCL__7, PCL_7S, PCL__8, PCL__9, PCL_10, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, | |
38c6663a LB |
3721 | PCLRSV, PCLRSV |
3722 | }; | |
3723 | ||
1b439f01 LB |
3724 | int skx_pkg_cstate_limits[16] = |
3725 | { PCL__0, PCL__2, PCL_6N, PCL_6R, PCLRSV, PCLRSV, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, | |
38c6663a LB |
3726 | PCLRSV, PCLRSV |
3727 | }; | |
3728 | ||
1b439f01 | 3729 | int icx_pkg_cstate_limits[16] = |
a1b6f487 | 3730 | { PCL__0, PCL__2, PCL__6, PCL__6, PCLRSV, PCLRSV, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, |
38c6663a LB |
3731 | PCLRSV, PCLRSV |
3732 | }; | |
1b439f01 | 3733 | |
3989fc89 ZR |
3734 | void probe_cst_limit(void) |
3735 | { | |
3736 | unsigned long long msr; | |
3737 | int *pkg_cstate_limits; | |
3738 | ||
3e404846 | 3739 | if (!platform->has_nhm_msrs || no_msr) |
3989fc89 ZR |
3740 | return; |
3741 | ||
3742 | switch (platform->cst_limit) { | |
3743 | case CST_LIMIT_NHM: | |
3744 | pkg_cstate_limits = nhm_pkg_cstate_limits; | |
3745 | break; | |
3746 | case CST_LIMIT_SNB: | |
3747 | pkg_cstate_limits = snb_pkg_cstate_limits; | |
3748 | break; | |
3749 | case CST_LIMIT_HSW: | |
3750 | pkg_cstate_limits = hsw_pkg_cstate_limits; | |
3751 | break; | |
3752 | case CST_LIMIT_SKX: | |
3753 | pkg_cstate_limits = skx_pkg_cstate_limits; | |
3754 | break; | |
3755 | case CST_LIMIT_ICX: | |
3756 | pkg_cstate_limits = icx_pkg_cstate_limits; | |
3757 | break; | |
3758 | case CST_LIMIT_SLV: | |
3759 | pkg_cstate_limits = slv_pkg_cstate_limits; | |
3760 | break; | |
3761 | case CST_LIMIT_AMT: | |
3762 | pkg_cstate_limits = amt_pkg_cstate_limits; | |
3763 | break; | |
3764 | case CST_LIMIT_KNL: | |
3765 | pkg_cstate_limits = phi_pkg_cstate_limits; | |
3766 | break; | |
3767 | case CST_LIMIT_GMT: | |
3768 | pkg_cstate_limits = glm_pkg_cstate_limits; | |
3769 | break; | |
3770 | default: | |
3771 | return; | |
3772 | } | |
3773 | ||
3774 | get_msr(base_cpu, MSR_PKG_CST_CONFIG_CONTROL, &msr); | |
3775 | pkg_cstate_limit = pkg_cstate_limits[msr & 0xF]; | |
3776 | } | |
3777 | ||
8b7199c0 | 3778 | static void dump_platform_info(void) |
103a8fea LB |
3779 | { |
3780 | unsigned long long msr; | |
3781 | unsigned int ratio; | |
3782 | ||
3e404846 | 3783 | if (!platform->has_nhm_msrs || no_msr) |
11cd9a09 ZR |
3784 | return; |
3785 | ||
ec0adc53 | 3786 | get_msr(base_cpu, MSR_PLATFORM_INFO, &msr); |
103a8fea | 3787 | |
b7d8c148 | 3788 | fprintf(outf, "cpu%d: MSR_PLATFORM_INFO: 0x%08llx\n", base_cpu, msr); |
6574a5d5 | 3789 | |
103a8fea | 3790 | ratio = (msr >> 40) & 0xFF; |
1b439f01 | 3791 | fprintf(outf, "%d * %.1f = %.1f MHz max efficiency frequency\n", ratio, bclk, ratio * bclk); |
103a8fea LB |
3792 | |
3793 | ratio = (msr >> 8) & 0xFF; | |
1b439f01 | 3794 | fprintf(outf, "%d * %.1f = %.1f MHz base frequency\n", ratio, bclk, ratio * bclk); |
045acf60 ZR |
3795 | } |
3796 | ||
3797 | static void dump_power_ctl(void) | |
3798 | { | |
3799 | unsigned long long msr; | |
3800 | ||
3e404846 | 3801 | if (!platform->has_nhm_msrs || no_msr) |
045acf60 | 3802 | return; |
103a8fea | 3803 | |
7ce7d5de | 3804 | get_msr(base_cpu, MSR_IA32_POWER_CTL, &msr); |
b7d8c148 | 3805 | fprintf(outf, "cpu%d: MSR_IA32_POWER_CTL: 0x%08llx (C1E auto-promotion: %sabled)\n", |
bfae2052 | 3806 | base_cpu, msr, msr & 0x2 ? "EN" : "DIS"); |
67920418 | 3807 | |
aeb01e6d | 3808 | /* C-state Pre-wake Disable (CSTATE_PREWAKE_DISABLE) */ |
7d0ebe6f | 3809 | if (platform->has_cst_prewake_bit) |
1b439f01 | 3810 | fprintf(outf, "C-state Pre-wake: %sabled\n", msr & 0x40000000 ? "DIS" : "EN"); |
aeb01e6d | 3811 | |
fcd17211 LB |
3812 | return; |
3813 | } | |
3814 | ||
a3943dea | 3815 | static void dump_turbo_ratio_limit2(void) |
fcd17211 LB |
3816 | { |
3817 | unsigned long long msr; | |
3818 | unsigned int ratio; | |
3819 | ||
7ce7d5de | 3820 | get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT2, &msr); |
fcd17211 | 3821 | |
b7d8c148 | 3822 | fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT2: 0x%08llx\n", base_cpu, msr); |
fcd17211 LB |
3823 | |
3824 | ratio = (msr >> 8) & 0xFF; | |
3825 | if (ratio) | |
1b439f01 | 3826 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo 18 active cores\n", ratio, bclk, ratio * bclk); |
fcd17211 LB |
3827 | |
3828 | ratio = (msr >> 0) & 0xFF; | |
3829 | if (ratio) | |
1b439f01 | 3830 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo 17 active cores\n", ratio, bclk, ratio * bclk); |
fcd17211 LB |
3831 | return; |
3832 | } | |
3833 | ||
a3943dea | 3834 | static void dump_turbo_ratio_limit1(void) |
fcd17211 LB |
3835 | { |
3836 | unsigned long long msr; | |
3837 | unsigned int ratio; | |
6574a5d5 | 3838 | |
7ce7d5de | 3839 | get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT1, &msr); |
6574a5d5 | 3840 | |
b7d8c148 | 3841 | fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT1: 0x%08llx\n", base_cpu, msr); |
6574a5d5 LB |
3842 | |
3843 | ratio = (msr >> 56) & 0xFF; | |
3844 | if (ratio) | |
1b439f01 | 3845 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo 16 active cores\n", ratio, bclk, ratio * bclk); |
6574a5d5 LB |
3846 | |
3847 | ratio = (msr >> 48) & 0xFF; | |
3848 | if (ratio) | |
1b439f01 | 3849 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo 15 active cores\n", ratio, bclk, ratio * bclk); |
6574a5d5 LB |
3850 | |
3851 | ratio = (msr >> 40) & 0xFF; | |
3852 | if (ratio) | |
1b439f01 | 3853 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo 14 active cores\n", ratio, bclk, ratio * bclk); |
6574a5d5 LB |
3854 | |
3855 | ratio = (msr >> 32) & 0xFF; | |
3856 | if (ratio) | |
1b439f01 | 3857 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo 13 active cores\n", ratio, bclk, ratio * bclk); |
6574a5d5 LB |
3858 | |
3859 | ratio = (msr >> 24) & 0xFF; | |
3860 | if (ratio) | |
1b439f01 | 3861 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo 12 active cores\n", ratio, bclk, ratio * bclk); |
6574a5d5 LB |
3862 | |
3863 | ratio = (msr >> 16) & 0xFF; | |
3864 | if (ratio) | |
1b439f01 | 3865 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo 11 active cores\n", ratio, bclk, ratio * bclk); |
6574a5d5 LB |
3866 | |
3867 | ratio = (msr >> 8) & 0xFF; | |
3868 | if (ratio) | |
1b439f01 | 3869 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo 10 active cores\n", ratio, bclk, ratio * bclk); |
6574a5d5 LB |
3870 | |
3871 | ratio = (msr >> 0) & 0xFF; | |
3872 | if (ratio) | |
1b439f01 | 3873 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo 9 active cores\n", ratio, bclk, ratio * bclk); |
fcd17211 LB |
3874 | return; |
3875 | } | |
1b439f01 | 3876 | |
10d85d85 | 3877 | static void dump_turbo_ratio_limits(int trl_msr_offset) |
fcd17211 | 3878 | { |
31e07522 | 3879 | unsigned long long msr, core_counts; |
5d622845 | 3880 | int shift; |
103a8fea | 3881 | |
4af184ee LB |
3882 | get_msr(base_cpu, trl_msr_offset, &msr); |
3883 | fprintf(outf, "cpu%d: MSR_%sTURBO_RATIO_LIMIT: 0x%08llx\n", | |
884a1f95 | 3884 | base_cpu, trl_msr_offset == MSR_SECONDARY_TURBO_RATIO_LIMIT ? "SECONDARY_" : "", msr); |
6574a5d5 | 3885 | |
10d85d85 | 3886 | if (platform->trl_msrs & TRL_CORECOUNT) { |
31e07522 LB |
3887 | get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT1, &core_counts); |
3888 | fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT1: 0x%08llx\n", base_cpu, core_counts); | |
3889 | } else { | |
3890 | core_counts = 0x0807060504030201; | |
3891 | } | |
3892 | ||
5d622845 LB |
3893 | for (shift = 56; shift >= 0; shift -= 8) { |
3894 | unsigned int ratio, group_size; | |
6574a5d5 | 3895 | |
5d622845 LB |
3896 | ratio = (msr >> shift) & 0xFF; |
3897 | group_size = (core_counts >> shift) & 0xFF; | |
3898 | if (ratio) | |
3899 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n", | |
3900 | ratio, bclk, ratio * bclk, group_size); | |
3901 | } | |
103a8fea | 3902 | |
fcd17211 LB |
3903 | return; |
3904 | } | |
3a9a941d | 3905 | |
1b439f01 | 3906 | static void dump_atom_turbo_ratio_limits(void) |
0f7887c4 LB |
3907 | { |
3908 | unsigned long long msr; | |
3909 | unsigned int ratio; | |
3910 | ||
3911 | get_msr(base_cpu, MSR_ATOM_CORE_RATIOS, &msr); | |
3912 | fprintf(outf, "cpu%d: MSR_ATOM_CORE_RATIOS: 0x%08llx\n", base_cpu, msr & 0xFFFFFFFF); | |
3913 | ||
3914 | ratio = (msr >> 0) & 0x3F; | |
3915 | if (ratio) | |
1b439f01 | 3916 | fprintf(outf, "%d * %.1f = %.1f MHz minimum operating frequency\n", ratio, bclk, ratio * bclk); |
0f7887c4 LB |
3917 | |
3918 | ratio = (msr >> 8) & 0x3F; | |
3919 | if (ratio) | |
1b439f01 | 3920 | fprintf(outf, "%d * %.1f = %.1f MHz low frequency mode (LFM)\n", ratio, bclk, ratio * bclk); |
0f7887c4 LB |
3921 | |
3922 | ratio = (msr >> 16) & 0x3F; | |
3923 | if (ratio) | |
1b439f01 | 3924 | fprintf(outf, "%d * %.1f = %.1f MHz base frequency\n", ratio, bclk, ratio * bclk); |
0f7887c4 LB |
3925 | |
3926 | get_msr(base_cpu, MSR_ATOM_CORE_TURBO_RATIOS, &msr); | |
3927 | fprintf(outf, "cpu%d: MSR_ATOM_CORE_TURBO_RATIOS: 0x%08llx\n", base_cpu, msr & 0xFFFFFFFF); | |
3928 | ||
3929 | ratio = (msr >> 24) & 0x3F; | |
3930 | if (ratio) | |
1b439f01 | 3931 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo 4 active cores\n", ratio, bclk, ratio * bclk); |
0f7887c4 LB |
3932 | |
3933 | ratio = (msr >> 16) & 0x3F; | |
3934 | if (ratio) | |
1b439f01 | 3935 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo 3 active cores\n", ratio, bclk, ratio * bclk); |
0f7887c4 LB |
3936 | |
3937 | ratio = (msr >> 8) & 0x3F; | |
3938 | if (ratio) | |
1b439f01 | 3939 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo 2 active cores\n", ratio, bclk, ratio * bclk); |
0f7887c4 LB |
3940 | |
3941 | ratio = (msr >> 0) & 0x3F; | |
3942 | if (ratio) | |
1b439f01 | 3943 | fprintf(outf, "%d * %.1f = %.1f MHz max turbo 1 active core\n", ratio, bclk, ratio * bclk); |
0f7887c4 LB |
3944 | } |
3945 | ||
1b439f01 | 3946 | static void dump_knl_turbo_ratio_limits(void) |
fb5d4327 | 3947 | { |
cbf97aba HC |
3948 | const unsigned int buckets_no = 7; |
3949 | ||
fb5d4327 | 3950 | unsigned long long msr; |
cbf97aba HC |
3951 | int delta_cores, delta_ratio; |
3952 | int i, b_nr; | |
3953 | unsigned int cores[buckets_no]; | |
3954 | unsigned int ratio[buckets_no]; | |
fb5d4327 | 3955 | |
ebf5926a | 3956 | get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT, &msr); |
fb5d4327 | 3957 | |
1b439f01 | 3958 | fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n", base_cpu, msr); |
fb5d4327 | 3959 | |
1e3ec5cd | 3960 | /* |
fb5d4327 | 3961 | * Turbo encoding in KNL is as follows: |
cbf97aba HC |
3962 | * [0] -- Reserved |
3963 | * [7:1] -- Base value of number of active cores of bucket 1. | |
fb5d4327 DC |
3964 | * [15:8] -- Base value of freq ratio of bucket 1. |
3965 | * [20:16] -- +ve delta of number of active cores of bucket 2. | |
3966 | * i.e. active cores of bucket 2 = | |
3967 | * active cores of bucket 1 + delta | |
3968 | * [23:21] -- Negative delta of freq ratio of bucket 2. | |
3969 | * i.e. freq ratio of bucket 2 = | |
3970 | * freq ratio of bucket 1 - delta | |
3971 | * [28:24]-- +ve delta of number of active cores of bucket 3. | |
3972 | * [31:29]-- -ve delta of freq ratio of bucket 3. | |
3973 | * [36:32]-- +ve delta of number of active cores of bucket 4. | |
3974 | * [39:37]-- -ve delta of freq ratio of bucket 4. | |
3975 | * [44:40]-- +ve delta of number of active cores of bucket 5. | |
3976 | * [47:45]-- -ve delta of freq ratio of bucket 5. | |
3977 | * [52:48]-- +ve delta of number of active cores of bucket 6. | |
3978 | * [55:53]-- -ve delta of freq ratio of bucket 6. | |
3979 | * [60:56]-- +ve delta of number of active cores of bucket 7. | |
3980 | * [63:61]-- -ve delta of freq ratio of bucket 7. | |
3981 | */ | |
cbf97aba HC |
3982 | |
3983 | b_nr = 0; | |
3984 | cores[b_nr] = (msr & 0xFF) >> 1; | |
3985 | ratio[b_nr] = (msr >> 8) & 0xFF; | |
3986 | ||
3987 | for (i = 16; i < 64; i += 8) { | |
fb5d4327 | 3988 | delta_cores = (msr >> i) & 0x1F; |
cbf97aba HC |
3989 | delta_ratio = (msr >> (i + 5)) & 0x7; |
3990 | ||
3991 | cores[b_nr + 1] = cores[b_nr] + delta_cores; | |
3992 | ratio[b_nr + 1] = ratio[b_nr] - delta_ratio; | |
3993 | b_nr++; | |
fb5d4327 | 3994 | } |
cbf97aba HC |
3995 | |
3996 | for (i = buckets_no - 1; i >= 0; i--) | |
3997 | if (i > 0 ? ratio[i] != ratio[i - 1] : 1) | |
b7d8c148 | 3998 | fprintf(outf, |
710f273b | 3999 | "%d * %.1f = %.1f MHz max turbo %d active cores\n", |
cbf97aba | 4000 | ratio[i], bclk, ratio[i] * bclk, cores[i]); |
fb5d4327 DC |
4001 | } |
4002 | ||
8b7199c0 | 4003 | static void dump_cst_cfg(void) |
fcd17211 LB |
4004 | { |
4005 | unsigned long long msr; | |
4006 | ||
3e404846 | 4007 | if (!platform->has_nhm_msrs || no_msr) |
045acf60 ZR |
4008 | return; |
4009 | ||
1df2e55a | 4010 | get_msr(base_cpu, MSR_PKG_CST_CONFIG_CONTROL, &msr); |
fcd17211 | 4011 | |
1df2e55a | 4012 | fprintf(outf, "cpu%d: MSR_PKG_CST_CONFIG_CONTROL: 0x%08llx", base_cpu, msr); |
fcd17211 | 4013 | |
3e8b62bf | 4014 | fprintf(outf, " (%s%s%s%s%slocked, pkg-cstate-limit=%d (%s)", |
fcd17211 LB |
4015 | (msr & SNB_C3_AUTO_UNDEMOTE) ? "UNdemote-C3, " : "", |
4016 | (msr & SNB_C1_AUTO_UNDEMOTE) ? "UNdemote-C1, " : "", | |
4017 | (msr & NHM_C3_AUTO_DEMOTE) ? "demote-C3, " : "", | |
4018 | (msr & NHM_C1_AUTO_DEMOTE) ? "demote-C1, " : "", | |
1b439f01 | 4019 | (msr & (1 << 15)) ? "" : "UN", (unsigned int)msr & 0xF, pkg_cstate_limit_strings[pkg_cstate_limit]); |
ac980e13 AB |
4020 | |
4021 | #define AUTOMATIC_CSTATE_CONVERSION (1UL << 16) | |
d90120bf | 4022 | if (platform->has_cst_auto_convension) { |
1b439f01 | 4023 | fprintf(outf, ", automatic c-state conversion=%s", (msr & AUTOMATIC_CSTATE_CONVERSION) ? "on" : "off"); |
ac980e13 AB |
4024 | } |
4025 | ||
4026 | fprintf(outf, ")\n"); | |
4027 | ||
fcd17211 | 4028 | return; |
103a8fea LB |
4029 | } |
4030 | ||
1b439f01 | 4031 | static void dump_config_tdp(void) |
6fb3143b LB |
4032 | { |
4033 | unsigned long long msr; | |
4034 | ||
4035 | get_msr(base_cpu, MSR_CONFIG_TDP_NOMINAL, &msr); | |
b7d8c148 | 4036 | fprintf(outf, "cpu%d: MSR_CONFIG_TDP_NOMINAL: 0x%08llx", base_cpu, msr); |
685b535b | 4037 | fprintf(outf, " (base_ratio=%d)\n", (unsigned int)msr & 0xFF); |
6fb3143b LB |
4038 | |
4039 | get_msr(base_cpu, MSR_CONFIG_TDP_LEVEL_1, &msr); | |
b7d8c148 | 4040 | fprintf(outf, "cpu%d: MSR_CONFIG_TDP_LEVEL_1: 0x%08llx (", base_cpu, msr); |
6fb3143b | 4041 | if (msr) { |
685b535b CY |
4042 | fprintf(outf, "PKG_MIN_PWR_LVL1=%d ", (unsigned int)(msr >> 48) & 0x7FFF); |
4043 | fprintf(outf, "PKG_MAX_PWR_LVL1=%d ", (unsigned int)(msr >> 32) & 0x7FFF); | |
4044 | fprintf(outf, "LVL1_RATIO=%d ", (unsigned int)(msr >> 16) & 0xFF); | |
4045 | fprintf(outf, "PKG_TDP_LVL1=%d", (unsigned int)(msr) & 0x7FFF); | |
6fb3143b | 4046 | } |
b7d8c148 | 4047 | fprintf(outf, ")\n"); |
6fb3143b LB |
4048 | |
4049 | get_msr(base_cpu, MSR_CONFIG_TDP_LEVEL_2, &msr); | |
b7d8c148 | 4050 | fprintf(outf, "cpu%d: MSR_CONFIG_TDP_LEVEL_2: 0x%08llx (", base_cpu, msr); |
6fb3143b | 4051 | if (msr) { |
685b535b CY |
4052 | fprintf(outf, "PKG_MIN_PWR_LVL2=%d ", (unsigned int)(msr >> 48) & 0x7FFF); |
4053 | fprintf(outf, "PKG_MAX_PWR_LVL2=%d ", (unsigned int)(msr >> 32) & 0x7FFF); | |
4054 | fprintf(outf, "LVL2_RATIO=%d ", (unsigned int)(msr >> 16) & 0xFF); | |
4055 | fprintf(outf, "PKG_TDP_LVL2=%d", (unsigned int)(msr) & 0x7FFF); | |
6fb3143b | 4056 | } |
b7d8c148 | 4057 | fprintf(outf, ")\n"); |
6fb3143b LB |
4058 | |
4059 | get_msr(base_cpu, MSR_CONFIG_TDP_CONTROL, &msr); | |
b7d8c148 | 4060 | fprintf(outf, "cpu%d: MSR_CONFIG_TDP_CONTROL: 0x%08llx (", base_cpu, msr); |
6fb3143b | 4061 | if ((msr) & 0x3) |
b7d8c148 LB |
4062 | fprintf(outf, "TDP_LEVEL=%d ", (unsigned int)(msr) & 0x3); |
4063 | fprintf(outf, " lock=%d", (unsigned int)(msr >> 31) & 1); | |
4064 | fprintf(outf, ")\n"); | |
36229897 | 4065 | |
6fb3143b | 4066 | get_msr(base_cpu, MSR_TURBO_ACTIVATION_RATIO, &msr); |
b7d8c148 | 4067 | fprintf(outf, "cpu%d: MSR_TURBO_ACTIVATION_RATIO: 0x%08llx (", base_cpu, msr); |
685b535b | 4068 | fprintf(outf, "MAX_NON_TURBO_RATIO=%d", (unsigned int)(msr) & 0xFF); |
b7d8c148 LB |
4069 | fprintf(outf, " lock=%d", (unsigned int)(msr >> 31) & 1); |
4070 | fprintf(outf, ")\n"); | |
6fb3143b | 4071 | } |
5a63426e | 4072 | |
1b439f01 | 4073 | unsigned int irtl_time_units[] = { 1, 32, 1024, 32768, 1048576, 33554432, 0, 0 }; |
5a63426e LB |
4074 | |
4075 | void print_irtl(void) | |
4076 | { | |
4077 | unsigned long long msr; | |
4078 | ||
3e404846 | 4079 | if (!platform->has_irtl_msrs || no_msr) |
148df4fd ZR |
4080 | return; |
4081 | ||
8c382f9e ZR |
4082 | if (platform->supported_cstates & PC3) { |
4083 | get_msr(base_cpu, MSR_PKGC3_IRTL, &msr); | |
4084 | fprintf(outf, "cpu%d: MSR_PKGC3_IRTL: 0x%08llx (", base_cpu, msr); | |
4085 | fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT", | |
4086 | (msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]); | |
4087 | } | |
5a63426e | 4088 | |
8c382f9e ZR |
4089 | if (platform->supported_cstates & PC6) { |
4090 | get_msr(base_cpu, MSR_PKGC6_IRTL, &msr); | |
4091 | fprintf(outf, "cpu%d: MSR_PKGC6_IRTL: 0x%08llx (", base_cpu, msr); | |
4092 | fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT", | |
4093 | (msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]); | |
4094 | } | |
5a63426e | 4095 | |
8c382f9e ZR |
4096 | if (platform->supported_cstates & PC7) { |
4097 | get_msr(base_cpu, MSR_PKGC7_IRTL, &msr); | |
4098 | fprintf(outf, "cpu%d: MSR_PKGC7_IRTL: 0x%08llx (", base_cpu, msr); | |
4099 | fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT", | |
4100 | (msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]); | |
4101 | } | |
5a63426e | 4102 | |
8c382f9e ZR |
4103 | if (platform->supported_cstates & PC8) { |
4104 | get_msr(base_cpu, MSR_PKGC8_IRTL, &msr); | |
4105 | fprintf(outf, "cpu%d: MSR_PKGC8_IRTL: 0x%08llx (", base_cpu, msr); | |
4106 | fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT", | |
4107 | (msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]); | |
4108 | } | |
5a63426e | 4109 | |
8c382f9e ZR |
4110 | if (platform->supported_cstates & PC9) { |
4111 | get_msr(base_cpu, MSR_PKGC9_IRTL, &msr); | |
4112 | fprintf(outf, "cpu%d: MSR_PKGC9_IRTL: 0x%08llx (", base_cpu, msr); | |
4113 | fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT", | |
4114 | (msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]); | |
4115 | } | |
5a63426e | 4116 | |
8c382f9e ZR |
4117 | if (platform->supported_cstates & PC10) { |
4118 | get_msr(base_cpu, MSR_PKGC10_IRTL, &msr); | |
4119 | fprintf(outf, "cpu%d: MSR_PKGC10_IRTL: 0x%08llx (", base_cpu, msr); | |
4120 | fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT", | |
4121 | (msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]); | |
4122 | } | |
5a63426e | 4123 | } |
1b439f01 | 4124 | |
36229897 LB |
4125 | void free_fd_percpu(void) |
4126 | { | |
4127 | int i; | |
4128 | ||
ebf8449c PW |
4129 | if (!fd_percpu) |
4130 | return; | |
4131 | ||
01a67adf | 4132 | for (i = 0; i < topo.max_cpu_num + 1; ++i) { |
36229897 LB |
4133 | if (fd_percpu[i] != 0) |
4134 | close(fd_percpu[i]); | |
4135 | } | |
4136 | ||
4137 | free(fd_percpu); | |
ebf8449c | 4138 | fd_percpu = NULL; |
6fb3143b LB |
4139 | } |
4140 | ||
e48934c9 PW |
4141 | void free_fd_amperf_percpu(void) |
4142 | { | |
4143 | int i; | |
4144 | ||
ebf8449c PW |
4145 | if (!fd_amperf_percpu) |
4146 | return; | |
4147 | ||
e48934c9 PW |
4148 | for (i = 0; i < topo.max_cpu_num + 1; ++i) { |
4149 | if (fd_amperf_percpu[i].mperf != 0) | |
4150 | close(fd_amperf_percpu[i].mperf); | |
4151 | ||
4152 | if (fd_amperf_percpu[i].aperf != 0) | |
4153 | close(fd_amperf_percpu[i].aperf); | |
4154 | } | |
4155 | ||
4156 | free(fd_amperf_percpu); | |
ebf8449c PW |
4157 | fd_amperf_percpu = NULL; |
4158 | } | |
4159 | ||
4160 | void free_fd_instr_count_percpu(void) | |
4161 | { | |
4162 | if (!fd_instr_count_percpu) | |
4163 | return; | |
4164 | ||
4165 | for (int i = 0; i < topo.max_cpu_num + 1; ++i) { | |
4166 | if (fd_instr_count_percpu[i] != 0) | |
4167 | close(fd_instr_count_percpu[i]); | |
4168 | } | |
4169 | ||
4170 | free(fd_instr_count_percpu); | |
4171 | fd_instr_count_percpu = NULL; | |
e48934c9 PW |
4172 | } |
4173 | ||
05a2f07d PW |
4174 | void free_fd_rapl_percpu(void) |
4175 | { | |
4176 | if (!rapl_counter_info_perdomain) | |
4177 | return; | |
4178 | ||
4179 | const int num_domains = platform->has_per_core_rapl ? topo.num_cores : topo.num_packages; | |
4180 | ||
4181 | for (int domain_id = 0; domain_id < num_domains; ++domain_id) { | |
4182 | if (rapl_counter_info_perdomain[domain_id].fd_perf != -1) | |
4183 | close(rapl_counter_info_perdomain[domain_id].fd_perf); | |
4184 | } | |
4185 | ||
4186 | free(rapl_counter_info_perdomain); | |
4187 | } | |
4188 | ||
c98d5d94 | 4189 | void free_all_buffers(void) |
103a8fea | 4190 | { |
0e2d8f05 LB |
4191 | int i; |
4192 | ||
c98d5d94 LB |
4193 | CPU_FREE(cpu_present_set); |
4194 | cpu_present_set = NULL; | |
36229897 | 4195 | cpu_present_setsize = 0; |
103a8fea | 4196 | |
f638858d ZR |
4197 | CPU_FREE(cpu_effective_set); |
4198 | cpu_effective_set = NULL; | |
4199 | cpu_effective_setsize = 0; | |
4200 | ||
71cfd1da ZR |
4201 | CPU_FREE(cpu_allowed_set); |
4202 | cpu_allowed_set = NULL; | |
4203 | cpu_allowed_setsize = 0; | |
4204 | ||
c98d5d94 LB |
4205 | CPU_FREE(cpu_affinity_set); |
4206 | cpu_affinity_set = NULL; | |
4207 | cpu_affinity_setsize = 0; | |
103a8fea | 4208 | |
c98d5d94 LB |
4209 | free(thread_even); |
4210 | free(core_even); | |
4211 | free(package_even); | |
103a8fea | 4212 | |
c98d5d94 LB |
4213 | thread_even = NULL; |
4214 | core_even = NULL; | |
4215 | package_even = NULL; | |
103a8fea | 4216 | |
c98d5d94 LB |
4217 | free(thread_odd); |
4218 | free(core_odd); | |
4219 | free(package_odd); | |
103a8fea | 4220 | |
c98d5d94 LB |
4221 | thread_odd = NULL; |
4222 | core_odd = NULL; | |
4223 | package_odd = NULL; | |
103a8fea | 4224 | |
c98d5d94 LB |
4225 | free(output_buffer); |
4226 | output_buffer = NULL; | |
4227 | outp = NULL; | |
36229897 LB |
4228 | |
4229 | free_fd_percpu(); | |
ebf8449c | 4230 | free_fd_instr_count_percpu(); |
e48934c9 | 4231 | free_fd_amperf_percpu(); |
05a2f07d | 4232 | free_fd_rapl_percpu(); |
562a2d37 LB |
4233 | |
4234 | free(irq_column_2_cpu); | |
4235 | free(irqs_per_cpu); | |
0e2d8f05 LB |
4236 | |
4237 | for (i = 0; i <= topo.max_cpu_num; ++i) { | |
4238 | if (cpus[i].put_ids) | |
4239 | CPU_FREE(cpus[i].put_ids); | |
4240 | } | |
4241 | free(cpus); | |
103a8fea LB |
4242 | } |
4243 | ||
c98d5d94 | 4244 | /* |
95aebc44 | 4245 | * Parse a file containing a single int. |
6de68fe1 LB |
4246 | * Return 0 if file can not be opened |
4247 | * Exit if file can be opened, but can not be parsed | |
c98d5d94 | 4248 | */ |
95aebc44 | 4249 | int parse_int_file(const char *fmt, ...) |
103a8fea | 4250 | { |
95aebc44 JT |
4251 | va_list args; |
4252 | char path[PATH_MAX]; | |
c98d5d94 | 4253 | FILE *filep; |
95aebc44 | 4254 | int value; |
103a8fea | 4255 | |
95aebc44 JT |
4256 | va_start(args, fmt); |
4257 | vsnprintf(path, sizeof(path), fmt, args); | |
4258 | va_end(args); | |
6de68fe1 LB |
4259 | filep = fopen(path, "r"); |
4260 | if (!filep) | |
4261 | return 0; | |
b2c95d90 JT |
4262 | if (fscanf(filep, "%d", &value) != 1) |
4263 | err(1, "%s: failed to parse number from file", path); | |
c98d5d94 | 4264 | fclose(filep); |
95aebc44 JT |
4265 | return value; |
4266 | } | |
4267 | ||
c98d5d94 LB |
4268 | /* |
4269 | * cpu_is_first_core_in_package(cpu) | |
4270 | * return 1 if given CPU is 1st core in package | |
4271 | */ | |
4272 | int cpu_is_first_core_in_package(int cpu) | |
103a8fea | 4273 | { |
95aebc44 | 4274 | return cpu == parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", cpu); |
103a8fea LB |
4275 | } |
4276 | ||
4277 | int get_physical_package_id(int cpu) | |
4278 | { | |
95aebc44 | 4279 | return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu); |
103a8fea LB |
4280 | } |
4281 | ||
6de68fe1 LB |
4282 | int get_die_id(int cpu) |
4283 | { | |
4284 | return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/die_id", cpu); | |
4285 | } | |
4286 | ||
103a8fea LB |
4287 | int get_core_id(int cpu) |
4288 | { | |
95aebc44 | 4289 | return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_id", cpu); |
103a8fea LB |
4290 | } |
4291 | ||
ef605741 PB |
4292 | void set_node_data(void) |
4293 | { | |
2ffbb224 PB |
4294 | int pkg, node, lnode, cpu, cpux; |
4295 | int cpu_count; | |
4296 | ||
4297 | /* initialize logical_node_id */ | |
4298 | for (cpu = 0; cpu <= topo.max_cpu_num; ++cpu) | |
4299 | cpus[cpu].logical_node_id = -1; | |
4300 | ||
4301 | cpu_count = 0; | |
4302 | for (pkg = 0; pkg < topo.num_packages; pkg++) { | |
4303 | lnode = 0; | |
4304 | for (cpu = 0; cpu <= topo.max_cpu_num; ++cpu) { | |
4305 | if (cpus[cpu].physical_package_id != pkg) | |
4306 | continue; | |
4307 | /* find a cpu with an unset logical_node_id */ | |
4308 | if (cpus[cpu].logical_node_id != -1) | |
4309 | continue; | |
4310 | cpus[cpu].logical_node_id = lnode; | |
4311 | node = cpus[cpu].physical_node_id; | |
4312 | cpu_count++; | |
4313 | /* | |
4314 | * find all matching cpus on this pkg and set | |
4315 | * the logical_node_id | |
4316 | */ | |
4317 | for (cpux = cpu; cpux <= topo.max_cpu_num; cpux++) { | |
1b439f01 | 4318 | if ((cpus[cpux].physical_package_id == pkg) && (cpus[cpux].physical_node_id == node)) { |
2ffbb224 PB |
4319 | cpus[cpux].logical_node_id = lnode; |
4320 | cpu_count++; | |
4321 | } | |
4322 | } | |
4323 | lnode++; | |
4324 | if (lnode > topo.nodes_per_pkg) | |
4325 | topo.nodes_per_pkg = lnode; | |
4326 | } | |
4327 | if (cpu_count >= topo.max_cpu_num) | |
4328 | break; | |
ef605741 | 4329 | } |
ef605741 PB |
4330 | } |
4331 | ||
4332 | int get_physical_node_id(struct cpu_topology *thiscpu) | |
c98d5d94 LB |
4333 | { |
4334 | char path[80]; | |
4335 | FILE *filep; | |
0e2d8f05 LB |
4336 | int i; |
4337 | int cpu = thiscpu->logical_cpu_id; | |
e275b388 | 4338 | |
0e2d8f05 | 4339 | for (i = 0; i <= topo.max_cpu_num; i++) { |
1b439f01 | 4340 | sprintf(path, "/sys/devices/system/cpu/cpu%d/node%i/cpulist", cpu, i); |
0e2d8f05 LB |
4341 | filep = fopen(path, "r"); |
4342 | if (!filep) | |
4343 | continue; | |
4344 | fclose(filep); | |
4345 | return i; | |
e275b388 | 4346 | } |
0e2d8f05 LB |
4347 | return -1; |
4348 | } | |
c98d5d94 | 4349 | |
8c3dd2c9 ZR |
4350 | static int parse_cpu_str(char *cpu_str, cpu_set_t *cpu_set, int cpu_set_size) |
4351 | { | |
4352 | unsigned int start, end; | |
4353 | char *next = cpu_str; | |
4354 | ||
4355 | while (next && *next) { | |
4356 | ||
4357 | if (*next == '-') /* no negative cpu numbers */ | |
4358 | return 1; | |
4359 | ||
4360 | start = strtoul(next, &next, 10); | |
4361 | ||
4362 | if (start >= CPU_SUBSET_MAXCPUS) | |
4363 | return 1; | |
4364 | CPU_SET_S(start, cpu_set_size, cpu_set); | |
4365 | ||
4366 | if (*next == '\0' || *next == '\n') | |
4367 | break; | |
4368 | ||
4369 | if (*next == ',') { | |
4370 | next += 1; | |
4371 | continue; | |
4372 | } | |
4373 | ||
4374 | if (*next == '-') { | |
4375 | next += 1; /* start range */ | |
4376 | } else if (*next == '.') { | |
4377 | next += 1; | |
4378 | if (*next == '.') | |
4379 | next += 1; /* start range */ | |
4380 | else | |
4381 | return 1; | |
4382 | } | |
4383 | ||
4384 | end = strtoul(next, &next, 10); | |
4385 | if (end <= start) | |
4386 | return 1; | |
4387 | ||
4388 | while (++start <= end) { | |
4389 | if (start >= CPU_SUBSET_MAXCPUS) | |
4390 | return 1; | |
4391 | CPU_SET_S(start, cpu_set_size, cpu_set); | |
4392 | } | |
4393 | ||
4394 | if (*next == ',') | |
4395 | next += 1; | |
4396 | else if (*next != '\0' && *next != '\n') | |
4397 | return 1; | |
4398 | } | |
4399 | ||
4400 | return 0; | |
4401 | } | |
4402 | ||
0e2d8f05 LB |
4403 | int get_thread_siblings(struct cpu_topology *thiscpu) |
4404 | { | |
4405 | char path[80], character; | |
4406 | FILE *filep; | |
4407 | unsigned long map; | |
8cb48b32 | 4408 | int so, shift, sib_core; |
0e2d8f05 LB |
4409 | int cpu = thiscpu->logical_cpu_id; |
4410 | int offset = topo.max_cpu_num + 1; | |
4411 | size_t size; | |
8cb48b32 | 4412 | int thread_id = 0; |
0e2d8f05 LB |
4413 | |
4414 | thiscpu->put_ids = CPU_ALLOC((topo.max_cpu_num + 1)); | |
8cb48b32 PB |
4415 | if (thiscpu->thread_id < 0) |
4416 | thiscpu->thread_id = thread_id++; | |
0e2d8f05 LB |
4417 | if (!thiscpu->put_ids) |
4418 | return -1; | |
4419 | ||
4420 | size = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); | |
4421 | CPU_ZERO_S(size, thiscpu->put_ids); | |
4422 | ||
1b439f01 | 4423 | sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings", cpu); |
3d7772ea LB |
4424 | filep = fopen(path, "r"); |
4425 | ||
4426 | if (!filep) { | |
4427 | warnx("%s: open failed", path); | |
4428 | return -1; | |
4429 | } | |
0e2d8f05 LB |
4430 | do { |
4431 | offset -= BITMASK_SIZE; | |
8173c336 BH |
4432 | if (fscanf(filep, "%lx%c", &map, &character) != 2) |
4433 | err(1, "%s: failed to parse file", path); | |
0e2d8f05 LB |
4434 | for (shift = 0; shift < BITMASK_SIZE; shift++) { |
4435 | if ((map >> shift) & 0x1) { | |
8cb48b32 PB |
4436 | so = shift + offset; |
4437 | sib_core = get_core_id(so); | |
4438 | if (sib_core == thiscpu->physical_core_id) { | |
4439 | CPU_SET_S(so, size, thiscpu->put_ids); | |
1b439f01 LB |
4440 | if ((so != cpu) && (cpus[so].thread_id < 0)) |
4441 | cpus[so].thread_id = thread_id++; | |
8cb48b32 | 4442 | } |
0e2d8f05 LB |
4443 | } |
4444 | } | |
e13da9a1 | 4445 | } while (character == ','); |
c98d5d94 | 4446 | fclose(filep); |
0e2d8f05 LB |
4447 | |
4448 | return CPU_COUNT_S(size, thiscpu->put_ids); | |
c98d5d94 LB |
4449 | } |
4450 | ||
103a8fea | 4451 | /* |
c98d5d94 LB |
4452 | * run func(thread, core, package) in topology order |
4453 | * skip non-present cpus | |
103a8fea LB |
4454 | */ |
4455 | ||
1b439f01 LB |
4456 | int for_all_cpus_2(int (func) (struct thread_data *, struct core_data *, |
4457 | struct pkg_data *, struct thread_data *, struct core_data *, | |
4458 | struct pkg_data *), struct thread_data *thread_base, | |
4459 | struct core_data *core_base, struct pkg_data *pkg_base, | |
4460 | struct thread_data *thread_base2, struct core_data *core_base2, struct pkg_data *pkg_base2) | |
c98d5d94 | 4461 | { |
40f5cfe7 | 4462 | int retval, pkg_no, node_no, core_no, thread_no; |
c98d5d94 LB |
4463 | |
4464 | for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) { | |
40f5cfe7 | 4465 | for (node_no = 0; node_no < topo.nodes_per_pkg; ++node_no) { |
1b439f01 LB |
4466 | for (core_no = 0; core_no < topo.cores_per_node; ++core_no) { |
4467 | for (thread_no = 0; thread_no < topo.threads_per_core; ++thread_no) { | |
40f5cfe7 PB |
4468 | struct thread_data *t, *t2; |
4469 | struct core_data *c, *c2; | |
4470 | struct pkg_data *p, *p2; | |
4471 | ||
1b439f01 | 4472 | t = GET_THREAD(thread_base, thread_no, core_no, node_no, pkg_no); |
40f5cfe7 | 4473 | |
4ede6d1c | 4474 | if (cpu_is_not_allowed(t->cpu_id)) |
40f5cfe7 PB |
4475 | continue; |
4476 | ||
1b439f01 | 4477 | t2 = GET_THREAD(thread_base2, thread_no, core_no, node_no, pkg_no); |
40f5cfe7 | 4478 | |
1b439f01 LB |
4479 | c = GET_CORE(core_base, core_no, node_no, pkg_no); |
4480 | c2 = GET_CORE(core_base2, core_no, node_no, pkg_no); | |
40f5cfe7 PB |
4481 | |
4482 | p = GET_PKG(pkg_base, pkg_no); | |
4483 | p2 = GET_PKG(pkg_base2, pkg_no); | |
4484 | ||
4485 | retval = func(t, c, p, t2, c2, p2); | |
4486 | if (retval) | |
4487 | return retval; | |
4488 | } | |
c98d5d94 LB |
4489 | } |
4490 | } | |
4491 | } | |
4492 | return 0; | |
4493 | } | |
4494 | ||
4495 | /* | |
4496 | * run func(cpu) on every cpu in /proc/stat | |
4497 | * return max_cpu number | |
4498 | */ | |
1b439f01 | 4499 | int for_all_proc_cpus(int (func) (int)) |
103a8fea LB |
4500 | { |
4501 | FILE *fp; | |
c98d5d94 | 4502 | int cpu_num; |
103a8fea LB |
4503 | int retval; |
4504 | ||
57a42a34 | 4505 | fp = fopen_or_die(proc_stat, "r"); |
103a8fea LB |
4506 | |
4507 | retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n"); | |
b2c95d90 JT |
4508 | if (retval != 0) |
4509 | err(1, "%s: failed to parse format", proc_stat); | |
103a8fea | 4510 | |
c98d5d94 LB |
4511 | while (1) { |
4512 | retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num); | |
103a8fea LB |
4513 | if (retval != 1) |
4514 | break; | |
4515 | ||
c98d5d94 LB |
4516 | retval = func(cpu_num); |
4517 | if (retval) { | |
4518 | fclose(fp); | |
1b439f01 | 4519 | return (retval); |
c98d5d94 | 4520 | } |
103a8fea LB |
4521 | } |
4522 | fclose(fp); | |
c98d5d94 | 4523 | return 0; |
103a8fea LB |
4524 | } |
4525 | ||
f638858d ZR |
4526 | #define PATH_EFFECTIVE_CPUS "/sys/fs/cgroup/cpuset.cpus.effective" |
4527 | ||
4528 | static char cpu_effective_str[1024]; | |
4529 | ||
4530 | static int update_effective_str(bool startup) | |
4531 | { | |
4532 | FILE *fp; | |
4533 | char *pos; | |
4534 | char buf[1024]; | |
4535 | int ret; | |
4536 | ||
4537 | if (cpu_effective_str[0] == '\0' && !startup) | |
4538 | return 0; | |
4539 | ||
4540 | fp = fopen(PATH_EFFECTIVE_CPUS, "r"); | |
4541 | if (!fp) | |
4542 | return 0; | |
4543 | ||
4544 | pos = fgets(buf, 1024, fp); | |
4545 | if (!pos) | |
4546 | err(1, "%s: file read failed\n", PATH_EFFECTIVE_CPUS); | |
4547 | ||
4548 | fclose(fp); | |
4549 | ||
4550 | ret = strncmp(cpu_effective_str, buf, 1024); | |
4551 | if (!ret) | |
4552 | return 0; | |
4553 | ||
4554 | strncpy(cpu_effective_str, buf, 1024); | |
4555 | return 1; | |
4556 | } | |
4557 | ||
4558 | static void update_effective_set(bool startup) | |
4559 | { | |
4560 | update_effective_str(startup); | |
4561 | ||
4562 | if (parse_cpu_str(cpu_effective_str, cpu_effective_set, cpu_effective_setsize)) | |
4563 | err(1, "%s: cpu str malformat %s\n", PATH_EFFECTIVE_CPUS, cpu_effective_str); | |
4564 | } | |
4565 | ||
ebf8449c | 4566 | void linux_perf_init(void); |
05a2f07d | 4567 | void rapl_perf_init(void); |
ebf8449c | 4568 | |
103a8fea LB |
4569 | void re_initialize(void) |
4570 | { | |
c98d5d94 | 4571 | free_all_buffers(); |
c25ef0e5 | 4572 | setup_all_buffers(false); |
ebf8449c | 4573 | linux_perf_init(); |
05a2f07d | 4574 | rapl_perf_init(); |
227ed18f CY |
4575 | fprintf(outf, "turbostat: re-initialized with num_cpus %d, allowed_cpus %d\n", topo.num_cpus, |
4576 | topo.allowed_cpus); | |
103a8fea LB |
4577 | } |
4578 | ||
843c5791 PB |
4579 | void set_max_cpu_num(void) |
4580 | { | |
4581 | FILE *filep; | |
8201a028 | 4582 | int base_cpu; |
843c5791 | 4583 | unsigned long dummy; |
8201a028 | 4584 | char pathname[64]; |
843c5791 | 4585 | |
8201a028 PB |
4586 | base_cpu = sched_getcpu(); |
4587 | if (base_cpu < 0) | |
4588 | err(1, "cannot find calling cpu ID"); | |
1b439f01 | 4589 | sprintf(pathname, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings", base_cpu); |
8201a028 PB |
4590 | |
4591 | filep = fopen_or_die(pathname, "r"); | |
843c5791 | 4592 | topo.max_cpu_num = 0; |
843c5791 | 4593 | while (fscanf(filep, "%lx,", &dummy) == 1) |
0e2d8f05 | 4594 | topo.max_cpu_num += BITMASK_SIZE; |
843c5791 | 4595 | fclose(filep); |
1b439f01 | 4596 | topo.max_cpu_num--; /* 0 based */ |
843c5791 | 4597 | } |
c98d5d94 | 4598 | |
103a8fea | 4599 | /* |
c98d5d94 LB |
4600 | * count_cpus() |
4601 | * remember the last one seen, it will be the max | |
103a8fea | 4602 | */ |
c98d5d94 | 4603 | int count_cpus(int cpu) |
103a8fea | 4604 | { |
9878bf7a LB |
4605 | UNUSED(cpu); |
4606 | ||
843c5791 | 4607 | topo.num_cpus++; |
c98d5d94 LB |
4608 | return 0; |
4609 | } | |
1b439f01 | 4610 | |
c98d5d94 LB |
4611 | int mark_cpu_present(int cpu) |
4612 | { | |
4613 | CPU_SET_S(cpu, cpu_present_setsize, cpu_present_set); | |
15aaa346 | 4614 | return 0; |
103a8fea LB |
4615 | } |
4616 | ||
8cb48b32 PB |
4617 | int init_thread_id(int cpu) |
4618 | { | |
4619 | cpus[cpu].thread_id = -1; | |
4620 | return 0; | |
4621 | } | |
4622 | ||
562a2d37 LB |
4623 | /* |
4624 | * snapshot_proc_interrupts() | |
4625 | * | |
4626 | * read and record summary of /proc/interrupts | |
4627 | * | |
4628 | * return 1 if config change requires a restart, else return 0 | |
4629 | */ | |
4630 | int snapshot_proc_interrupts(void) | |
4631 | { | |
4632 | static FILE *fp; | |
4633 | int column, retval; | |
4634 | ||
4635 | if (fp == NULL) | |
4636 | fp = fopen_or_die("/proc/interrupts", "r"); | |
4637 | else | |
4638 | rewind(fp); | |
4639 | ||
4640 | /* read 1st line of /proc/interrupts to get cpu* name for each column */ | |
4641 | for (column = 0; column < topo.num_cpus; ++column) { | |
4642 | int cpu_number; | |
4643 | ||
4644 | retval = fscanf(fp, " CPU%d", &cpu_number); | |
4645 | if (retval != 1) | |
4646 | break; | |
4647 | ||
4648 | if (cpu_number > topo.max_cpu_num) { | |
4649 | warn("/proc/interrupts: cpu%d: > %d", cpu_number, topo.max_cpu_num); | |
4650 | return 1; | |
4651 | } | |
4652 | ||
4653 | irq_column_2_cpu[column] = cpu_number; | |
4654 | irqs_per_cpu[cpu_number] = 0; | |
4655 | } | |
4656 | ||
4657 | /* read /proc/interrupt count lines and sum up irqs per cpu */ | |
4658 | while (1) { | |
4659 | int column; | |
4660 | char buf[64]; | |
4661 | ||
4662 | retval = fscanf(fp, " %s:", buf); /* flush irq# "N:" */ | |
4663 | if (retval != 1) | |
4664 | break; | |
4665 | ||
4666 | /* read the count per cpu */ | |
4667 | for (column = 0; column < topo.num_cpus; ++column) { | |
4668 | ||
4669 | int cpu_number, irq_count; | |
4670 | ||
4671 | retval = fscanf(fp, " %d", &irq_count); | |
4672 | if (retval != 1) | |
4673 | break; | |
4674 | ||
4675 | cpu_number = irq_column_2_cpu[column]; | |
4676 | irqs_per_cpu[cpu_number] += irq_count; | |
4677 | ||
4678 | } | |
4679 | ||
1b439f01 | 4680 | while (getc(fp) != '\n') ; /* flush interrupt description */ |
562a2d37 LB |
4681 | |
4682 | } | |
4683 | return 0; | |
4684 | } | |
1b439f01 | 4685 | |
fdf676e5 | 4686 | /* |
de39d38c | 4687 | * snapshot_graphics() |
fdf676e5 | 4688 | * |
de39d38c | 4689 | * record snapshot of specified graphics sysfs knob |
fdf676e5 LB |
4690 | * |
4691 | * return 1 if config change requires a restart, else return 0 | |
4692 | */ | |
de39d38c | 4693 | int snapshot_graphics(int idx) |
fdf676e5 LB |
4694 | { |
4695 | FILE *fp; | |
4696 | int retval; | |
4697 | ||
de39d38c ZR |
4698 | switch (idx) { |
4699 | case GFX_rc6: | |
3bbb331c | 4700 | case SAM_mc6: |
de39d38c ZR |
4701 | fp = fopen_or_die(gfx_info[idx].path, "r"); |
4702 | retval = fscanf(fp, "%lld", &gfx_info[idx].val_ull); | |
4703 | if (retval != 1) | |
4704 | err(1, "rc6"); | |
4705 | fclose(fp); | |
4706 | return 0; | |
4707 | case GFX_MHz: | |
4708 | case GFX_ACTMHz: | |
3bbb331c ZR |
4709 | case SAM_MHz: |
4710 | case SAM_ACTMHz: | |
de39d38c ZR |
4711 | if (gfx_info[idx].fp == NULL) { |
4712 | gfx_info[idx].fp = fopen_or_die(gfx_info[idx].path, "r"); | |
4713 | } else { | |
4714 | rewind(gfx_info[idx].fp); | |
4715 | fflush(gfx_info[idx].fp); | |
4716 | } | |
4717 | retval = fscanf(gfx_info[idx].fp, "%d", &gfx_info[idx].val); | |
4718 | if (retval != 1) | |
4719 | err(1, "MHz"); | |
4720 | return 0; | |
4721 | default: | |
4722 | return -EINVAL; | |
b4b91569 | 4723 | } |
b4b91569 RA |
4724 | } |
4725 | ||
be0e54c4 LB |
4726 | /* |
4727 | * snapshot_cpu_lpi() | |
4728 | * | |
4729 | * record snapshot of | |
4730 | * /sys/devices/system/cpu/cpuidle/low_power_idle_cpu_residency_us | |
be0e54c4 LB |
4731 | */ |
4732 | int snapshot_cpu_lpi_us(void) | |
4733 | { | |
4734 | FILE *fp; | |
4735 | int retval; | |
4736 | ||
4737 | fp = fopen_or_die("/sys/devices/system/cpu/cpuidle/low_power_idle_cpu_residency_us", "r"); | |
4738 | ||
4739 | retval = fscanf(fp, "%lld", &cpuidle_cur_cpu_lpi_us); | |
5ea7647b PB |
4740 | if (retval != 1) { |
4741 | fprintf(stderr, "Disabling Low Power Idle CPU output\n"); | |
4742 | BIC_NOT_PRESENT(BIC_CPU_LPI); | |
605736c6 | 4743 | fclose(fp); |
5ea7647b PB |
4744 | return -1; |
4745 | } | |
be0e54c4 LB |
4746 | |
4747 | fclose(fp); | |
4748 | ||
4749 | return 0; | |
4750 | } | |
1b439f01 | 4751 | |
be0e54c4 LB |
4752 | /* |
4753 | * snapshot_sys_lpi() | |
4754 | * | |
1f81c5ef | 4755 | * record snapshot of sys_lpi_file |
be0e54c4 LB |
4756 | */ |
4757 | int snapshot_sys_lpi_us(void) | |
4758 | { | |
4759 | FILE *fp; | |
4760 | int retval; | |
4761 | ||
1f81c5ef | 4762 | fp = fopen_or_die(sys_lpi_file, "r"); |
be0e54c4 LB |
4763 | |
4764 | retval = fscanf(fp, "%lld", &cpuidle_cur_sys_lpi_us); | |
5ea7647b PB |
4765 | if (retval != 1) { |
4766 | fprintf(stderr, "Disabling Low Power Idle System output\n"); | |
4767 | BIC_NOT_PRESENT(BIC_SYS_LPI); | |
15423b95 | 4768 | fclose(fp); |
5ea7647b PB |
4769 | return -1; |
4770 | } | |
be0e54c4 LB |
4771 | fclose(fp); |
4772 | ||
4773 | return 0; | |
4774 | } | |
1b439f01 | 4775 | |
562a2d37 LB |
4776 | /* |
4777 | * snapshot /proc and /sys files | |
4778 | * | |
4779 | * return 1 if configuration restart needed, else return 0 | |
4780 | */ | |
4781 | int snapshot_proc_sysfs_files(void) | |
4782 | { | |
218f0e8d LB |
4783 | if (DO_BIC(BIC_IRQ)) |
4784 | if (snapshot_proc_interrupts()) | |
4785 | return 1; | |
562a2d37 | 4786 | |
812db3f7 | 4787 | if (DO_BIC(BIC_GFX_rc6)) |
de39d38c | 4788 | snapshot_graphics(GFX_rc6); |
fdf676e5 | 4789 | |
812db3f7 | 4790 | if (DO_BIC(BIC_GFXMHz)) |
de39d38c | 4791 | snapshot_graphics(GFX_MHz); |
27d47356 | 4792 | |
b4b91569 | 4793 | if (DO_BIC(BIC_GFXACTMHz)) |
de39d38c | 4794 | snapshot_graphics(GFX_ACTMHz); |
b4b91569 | 4795 | |
3bbb331c ZR |
4796 | if (DO_BIC(BIC_SAM_mc6)) |
4797 | snapshot_graphics(SAM_mc6); | |
4798 | ||
4799 | if (DO_BIC(BIC_SAMMHz)) | |
4800 | snapshot_graphics(SAM_MHz); | |
4801 | ||
4802 | if (DO_BIC(BIC_SAMACTMHz)) | |
4803 | snapshot_graphics(SAM_ACTMHz); | |
4804 | ||
be0e54c4 LB |
4805 | if (DO_BIC(BIC_CPU_LPI)) |
4806 | snapshot_cpu_lpi_us(); | |
4807 | ||
4808 | if (DO_BIC(BIC_SYS_LPI)) | |
4809 | snapshot_sys_lpi_us(); | |
4810 | ||
562a2d37 LB |
4811 | return 0; |
4812 | } | |
4813 | ||
8aa2ed0b LB |
4814 | int exit_requested; |
4815 | ||
1b439f01 | 4816 | static void signal_handler(int signal) |
8aa2ed0b LB |
4817 | { |
4818 | switch (signal) { | |
4819 | case SIGINT: | |
4820 | exit_requested = 1; | |
4821 | if (debug) | |
4822 | fprintf(stderr, " SIGINT\n"); | |
4823 | break; | |
07211960 LB |
4824 | case SIGUSR1: |
4825 | if (debug > 1) | |
4826 | fprintf(stderr, "SIGUSR1\n"); | |
4827 | break; | |
8aa2ed0b LB |
4828 | } |
4829 | } | |
4830 | ||
4831 | void setup_signal_handler(void) | |
4832 | { | |
4833 | struct sigaction sa; | |
4834 | ||
4835 | memset(&sa, 0, sizeof(sa)); | |
4836 | ||
4837 | sa.sa_handler = &signal_handler; | |
4838 | ||
4839 | if (sigaction(SIGINT, &sa, NULL) < 0) | |
4840 | err(1, "sigaction SIGINT"); | |
07211960 LB |
4841 | if (sigaction(SIGUSR1, &sa, NULL) < 0) |
4842 | err(1, "sigaction SIGUSR1"); | |
8aa2ed0b | 4843 | } |
b9ad8ee0 | 4844 | |
47936f94 | 4845 | void do_sleep(void) |
b9ad8ee0 | 4846 | { |
c026c236 AB |
4847 | struct timeval tout; |
4848 | struct timespec rest; | |
b9ad8ee0 LB |
4849 | fd_set readfds; |
4850 | int retval; | |
4851 | ||
4852 | FD_ZERO(&readfds); | |
4853 | FD_SET(0, &readfds); | |
4854 | ||
c026c236 | 4855 | if (ignore_stdin) { |
47936f94 AB |
4856 | nanosleep(&interval_ts, NULL); |
4857 | return; | |
4858 | } | |
b9ad8ee0 | 4859 | |
c026c236 AB |
4860 | tout = interval_tv; |
4861 | retval = select(1, &readfds, NULL, NULL, &tout); | |
b9ad8ee0 LB |
4862 | |
4863 | if (retval == 1) { | |
b9ad8ee0 LB |
4864 | switch (getc(stdin)) { |
4865 | case 'q': | |
4866 | exit_requested = 1; | |
4867 | break; | |
c026c236 AB |
4868 | case EOF: |
4869 | /* | |
4870 | * 'stdin' is a pipe closed on the other end. There | |
4871 | * won't be any further input. | |
4872 | */ | |
4873 | ignore_stdin = 1; | |
4874 | /* Sleep the rest of the time */ | |
4875 | rest.tv_sec = (tout.tv_sec + tout.tv_usec / 1000000); | |
4876 | rest.tv_nsec = (tout.tv_usec % 1000000) * 1000; | |
4877 | nanosleep(&rest, NULL); | |
b9ad8ee0 | 4878 | } |
b9ad8ee0 | 4879 | } |
b9ad8ee0 | 4880 | } |
47936f94 | 4881 | |
87e15da9 CY |
4882 | int get_msr_sum(int cpu, off_t offset, unsigned long long *msr) |
4883 | { | |
4884 | int ret, idx; | |
4885 | unsigned long long msr_cur, msr_last; | |
4886 | ||
3e404846 PW |
4887 | assert(!no_msr); |
4888 | ||
87e15da9 CY |
4889 | if (!per_cpu_msr_sum) |
4890 | return 1; | |
4891 | ||
4892 | idx = offset_to_idx(offset); | |
4893 | if (idx < 0) | |
4894 | return idx; | |
4895 | /* get_msr_sum() = sum + (get_msr() - last) */ | |
4896 | ret = get_msr(cpu, offset, &msr_cur); | |
4897 | if (ret) | |
4898 | return ret; | |
4899 | msr_last = per_cpu_msr_sum[cpu].entries[idx].last; | |
4900 | DELTA_WRAP32(msr_cur, msr_last); | |
4901 | *msr = msr_last + per_cpu_msr_sum[cpu].entries[idx].sum; | |
4902 | ||
4903 | return 0; | |
4904 | } | |
4905 | ||
4906 | timer_t timerid; | |
4907 | ||
4908 | /* Timer callback, update the sum of MSRs periodically. */ | |
4909 | static int update_msr_sum(struct thread_data *t, struct core_data *c, struct pkg_data *p) | |
4910 | { | |
4911 | int i, ret; | |
4912 | int cpu = t->cpu_id; | |
4913 | ||
9878bf7a LB |
4914 | UNUSED(c); |
4915 | UNUSED(p); | |
4916 | ||
3e404846 PW |
4917 | assert(!no_msr); |
4918 | ||
87e15da9 CY |
4919 | for (i = IDX_PKG_ENERGY; i < IDX_COUNT; i++) { |
4920 | unsigned long long msr_cur, msr_last; | |
13a779de | 4921 | off_t offset; |
87e15da9 CY |
4922 | |
4923 | if (!idx_valid(i)) | |
4924 | continue; | |
4925 | offset = idx_to_offset(i); | |
4926 | if (offset < 0) | |
4927 | continue; | |
4928 | ret = get_msr(cpu, offset, &msr_cur); | |
4929 | if (ret) { | |
1b439f01 | 4930 | fprintf(outf, "Can not update msr(0x%llx)\n", (unsigned long long)offset); |
87e15da9 CY |
4931 | continue; |
4932 | } | |
4933 | ||
4934 | msr_last = per_cpu_msr_sum[cpu].entries[i].last; | |
4935 | per_cpu_msr_sum[cpu].entries[i].last = msr_cur & 0xffffffff; | |
4936 | ||
4937 | DELTA_WRAP32(msr_cur, msr_last); | |
4938 | per_cpu_msr_sum[cpu].entries[i].sum += msr_last; | |
4939 | } | |
4940 | return 0; | |
4941 | } | |
4942 | ||
1b439f01 | 4943 | static void msr_record_handler(union sigval v) |
87e15da9 | 4944 | { |
9878bf7a LB |
4945 | UNUSED(v); |
4946 | ||
87e15da9 CY |
4947 | for_all_cpus(update_msr_sum, EVEN_COUNTERS); |
4948 | } | |
4949 | ||
4950 | void msr_sum_record(void) | |
4951 | { | |
4952 | struct itimerspec its; | |
4953 | struct sigevent sev; | |
4954 | ||
4955 | per_cpu_msr_sum = calloc(topo.max_cpu_num + 1, sizeof(struct msr_sum_array)); | |
4956 | if (!per_cpu_msr_sum) { | |
4957 | fprintf(outf, "Can not allocate memory for long time MSR.\n"); | |
4958 | return; | |
4959 | } | |
4960 | /* | |
4961 | * Signal handler might be restricted, so use thread notifier instead. | |
4962 | */ | |
4963 | memset(&sev, 0, sizeof(struct sigevent)); | |
4964 | sev.sigev_notify = SIGEV_THREAD; | |
4965 | sev.sigev_notify_function = msr_record_handler; | |
4966 | ||
4967 | sev.sigev_value.sival_ptr = &timerid; | |
4968 | if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) { | |
4969 | fprintf(outf, "Can not create timer.\n"); | |
4970 | goto release_msr; | |
4971 | } | |
4972 | ||
4973 | its.it_value.tv_sec = 0; | |
4974 | its.it_value.tv_nsec = 1; | |
4975 | /* | |
4976 | * A wraparound time has been calculated early. | |
4977 | * Some sources state that the peak power for a | |
4978 | * microprocessor is usually 1.5 times the TDP rating, | |
4979 | * use 2 * TDP for safety. | |
4980 | */ | |
4981 | its.it_interval.tv_sec = rapl_joule_counter_range / 2; | |
4982 | its.it_interval.tv_nsec = 0; | |
4983 | ||
4984 | if (timer_settime(timerid, 0, &its, NULL) == -1) { | |
4985 | fprintf(outf, "Can not set timer.\n"); | |
4986 | goto release_timer; | |
4987 | } | |
4988 | return; | |
4989 | ||
1b439f01 | 4990 | release_timer: |
87e15da9 | 4991 | timer_delete(timerid); |
1b439f01 | 4992 | release_msr: |
87e15da9 CY |
4993 | free(per_cpu_msr_sum); |
4994 | } | |
4c2122d4 | 4995 | |
38c6663a LB |
4996 | /* |
4997 | * set_my_sched_priority(pri) | |
5088741e PW |
4998 | * return previous priority on success |
4999 | * return value < -20 on failure | |
38c6663a LB |
5000 | */ |
5001 | int set_my_sched_priority(int priority) | |
5002 | { | |
5003 | int retval; | |
5004 | int original_priority; | |
5005 | ||
5006 | errno = 0; | |
5007 | original_priority = getpriority(PRIO_PROCESS, 0); | |
5008 | if (errno && (original_priority == -1)) | |
5088741e | 5009 | return -21; |
38c6663a LB |
5010 | |
5011 | retval = setpriority(PRIO_PROCESS, 0, priority); | |
5012 | if (retval) | |
5088741e | 5013 | return -21; |
38c6663a LB |
5014 | |
5015 | errno = 0; | |
5016 | retval = getpriority(PRIO_PROCESS, 0); | |
5017 | if (retval != priority) | |
5088741e | 5018 | return -21; |
38c6663a LB |
5019 | |
5020 | return original_priority; | |
5021 | } | |
5022 | ||
103a8fea LB |
5023 | void turbostat_loop() |
5024 | { | |
c98d5d94 | 5025 | int retval; |
e52966c0 | 5026 | int restarted = 0; |
9878bf7a | 5027 | unsigned int done_iters = 0; |
c98d5d94 | 5028 | |
8aa2ed0b LB |
5029 | setup_signal_handler(); |
5030 | ||
38c6663a LB |
5031 | /* |
5032 | * elevate own priority for interval mode | |
5088741e PW |
5033 | * |
5034 | * ignore on error - we probably don't have permission to set it, but | |
5035 | * it's not a big deal | |
38c6663a LB |
5036 | */ |
5037 | set_my_sched_priority(-20); | |
5038 | ||
103a8fea | 5039 | restart: |
e52966c0 LB |
5040 | restarted++; |
5041 | ||
562a2d37 | 5042 | snapshot_proc_sysfs_files(); |
c98d5d94 | 5043 | retval = for_all_cpus(get_counters, EVEN_COUNTERS); |
4c2122d4 | 5044 | first_counter_read = 0; |
d91bb17c LB |
5045 | if (retval < -1) { |
5046 | exit(retval); | |
5047 | } else if (retval == -1) { | |
3d7772ea | 5048 | if (restarted > 10) { |
e52966c0 LB |
5049 | exit(retval); |
5050 | } | |
c98d5d94 LB |
5051 | re_initialize(); |
5052 | goto restart; | |
5053 | } | |
e52966c0 | 5054 | restarted = 0; |
023fe0ac | 5055 | done_iters = 0; |
103a8fea LB |
5056 | gettimeofday(&tv_even, (struct timezone *)NULL); |
5057 | ||
5058 | while (1) { | |
c98d5d94 | 5059 | if (for_all_proc_cpus(cpu_is_not_present)) { |
103a8fea LB |
5060 | re_initialize(); |
5061 | goto restart; | |
5062 | } | |
f638858d ZR |
5063 | if (update_effective_str(false)) { |
5064 | re_initialize(); | |
5065 | goto restart; | |
5066 | } | |
b9ad8ee0 | 5067 | do_sleep(); |
562a2d37 LB |
5068 | if (snapshot_proc_sysfs_files()) |
5069 | goto restart; | |
c98d5d94 | 5070 | retval = for_all_cpus(get_counters, ODD_COUNTERS); |
d91bb17c LB |
5071 | if (retval < -1) { |
5072 | exit(retval); | |
5073 | } else if (retval == -1) { | |
15aaa346 LB |
5074 | re_initialize(); |
5075 | goto restart; | |
5076 | } | |
103a8fea | 5077 | gettimeofday(&tv_odd, (struct timezone *)NULL); |
103a8fea | 5078 | timersub(&tv_odd, &tv_even, &tv_delta); |
ba3dec99 LB |
5079 | if (for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS)) { |
5080 | re_initialize(); | |
5081 | goto restart; | |
5082 | } | |
c98d5d94 LB |
5083 | compute_average(EVEN_COUNTERS); |
5084 | format_all_counters(EVEN_COUNTERS); | |
b7d8c148 | 5085 | flush_output_stdout(); |
8aa2ed0b LB |
5086 | if (exit_requested) |
5087 | break; | |
023fe0ac CY |
5088 | if (num_iterations && ++done_iters >= num_iterations) |
5089 | break; | |
b9ad8ee0 | 5090 | do_sleep(); |
562a2d37 LB |
5091 | if (snapshot_proc_sysfs_files()) |
5092 | goto restart; | |
c98d5d94 | 5093 | retval = for_all_cpus(get_counters, EVEN_COUNTERS); |
d91bb17c LB |
5094 | if (retval < -1) { |
5095 | exit(retval); | |
5096 | } else if (retval == -1) { | |
103a8fea LB |
5097 | re_initialize(); |
5098 | goto restart; | |
5099 | } | |
103a8fea | 5100 | gettimeofday(&tv_even, (struct timezone *)NULL); |
103a8fea | 5101 | timersub(&tv_even, &tv_odd, &tv_delta); |
ba3dec99 LB |
5102 | if (for_all_cpus_2(delta_cpu, EVEN_COUNTERS, ODD_COUNTERS)) { |
5103 | re_initialize(); | |
5104 | goto restart; | |
5105 | } | |
c98d5d94 LB |
5106 | compute_average(ODD_COUNTERS); |
5107 | format_all_counters(ODD_COUNTERS); | |
b7d8c148 | 5108 | flush_output_stdout(); |
8aa2ed0b LB |
5109 | if (exit_requested) |
5110 | break; | |
023fe0ac CY |
5111 | if (num_iterations && ++done_iters >= num_iterations) |
5112 | break; | |
103a8fea LB |
5113 | } |
5114 | } | |
5115 | ||
5116 | void check_dev_msr() | |
5117 | { | |
5118 | struct stat sb; | |
7ce7d5de | 5119 | char pathname[32]; |
103a8fea | 5120 | |
5088741e PW |
5121 | if (no_msr) |
5122 | return; | |
5123 | ||
7ce7d5de PB |
5124 | sprintf(pathname, "/dev/cpu/%d/msr", base_cpu); |
5125 | if (stat(pathname, &sb)) | |
1b439f01 | 5126 | if (system("/sbin/modprobe msr > /dev/null 2>&1")) |
5088741e | 5127 | no_msr = 1; |
103a8fea LB |
5128 | } |
5129 | ||
fcaa681c LB |
5130 | /* |
5131 | * check for CAP_SYS_RAWIO | |
5132 | * return 0 on success | |
5133 | * return 1 on fail | |
5134 | */ | |
5135 | int check_for_cap_sys_rawio(void) | |
103a8fea | 5136 | { |
fcaa681c LB |
5137 | cap_t caps; |
5138 | cap_flag_value_t cap_flag_value; | |
5088741e | 5139 | int ret = 0; |
98481e79 | 5140 | |
fcaa681c LB |
5141 | caps = cap_get_proc(); |
5142 | if (caps == NULL) | |
5088741e | 5143 | return 1; |
98481e79 | 5144 | |
5088741e PW |
5145 | if (cap_get_flag(caps, CAP_SYS_RAWIO, CAP_EFFECTIVE, &cap_flag_value)) { |
5146 | ret = 1; | |
5147 | goto free_and_exit; | |
5148 | } | |
fcaa681c LB |
5149 | |
5150 | if (cap_flag_value != CAP_SET) { | |
5088741e PW |
5151 | ret = 1; |
5152 | goto free_and_exit; | |
98481e79 LB |
5153 | } |
5154 | ||
5088741e | 5155 | free_and_exit: |
fcaa681c LB |
5156 | if (cap_free(caps) == -1) |
5157 | err(-6, "cap_free\n"); | |
5158 | ||
5088741e | 5159 | return ret; |
fcaa681c | 5160 | } |
1b439f01 | 5161 | |
5088741e | 5162 | void check_msr_permission(void) |
fcaa681c | 5163 | { |
5088741e | 5164 | int failed = 0; |
fcaa681c LB |
5165 | char pathname[32]; |
5166 | ||
5088741e PW |
5167 | if (no_msr) |
5168 | return; | |
5169 | ||
fcaa681c | 5170 | /* check for CAP_SYS_RAWIO */ |
5088741e | 5171 | failed += check_for_cap_sys_rawio(); |
fcaa681c | 5172 | |
98481e79 | 5173 | /* test file permissions */ |
7ce7d5de PB |
5174 | sprintf(pathname, "/dev/cpu/%d/msr", base_cpu); |
5175 | if (euidaccess(pathname, R_OK)) { | |
5088741e | 5176 | failed++; |
98481e79 LB |
5177 | } |
5178 | ||
5088741e PW |
5179 | if (failed) { |
5180 | warnx("Failed to access %s. Some of the counters may not be available\n" | |
5181 | "\tRun as root to enable them or use %s to disable the access explicitly", pathname, "--no-msr"); | |
5182 | no_msr = 1; | |
5183 | } | |
103a8fea LB |
5184 | } |
5185 | ||
71e84129 ZR |
5186 | void probe_bclk(void) |
5187 | { | |
5188 | unsigned long long msr; | |
5189 | unsigned int base_ratio; | |
5190 | ||
3e404846 | 5191 | if (!platform->has_nhm_msrs || no_msr) |
71e84129 ZR |
5192 | return; |
5193 | ||
5194 | if (platform->bclk_freq == BCLK_100MHZ) | |
5195 | bclk = 100.00; | |
5196 | else if (platform->bclk_freq == BCLK_133MHZ) | |
5197 | bclk = 133.33; | |
5198 | else if (platform->bclk_freq == BCLK_SLV) | |
5199 | bclk = slm_bclk(); | |
5200 | else | |
5201 | return; | |
5202 | ||
5203 | get_msr(base_cpu, MSR_PLATFORM_INFO, &msr); | |
5204 | base_ratio = (msr >> 8) & 0xFF; | |
5205 | ||
5206 | base_hz = base_ratio * bclk * 1000000; | |
5207 | has_base_hz = 1; | |
485a017c ZR |
5208 | |
5209 | if (platform->enable_tsc_tweak) | |
5210 | tsc_tweak = base_hz / tsc_hz; | |
71e84129 ZR |
5211 | } |
5212 | ||
1b439f01 | 5213 | static void remove_underbar(char *s) |
fecb3bc8 DA |
5214 | { |
5215 | char *to = s; | |
5216 | ||
5217 | while (*s) { | |
5218 | if (*s != '_') | |
5219 | *to++ = *s; | |
5220 | s++; | |
5221 | } | |
5222 | ||
5223 | *to = 0; | |
5224 | } | |
5225 | ||
a61c9cb4 | 5226 | static void dump_turbo_ratio_info(void) |
fcd17211 | 5227 | { |
3ea8e52e | 5228 | if (!has_turbo) |
fcd17211 LB |
5229 | return; |
5230 | ||
3e404846 | 5231 | if (!platform->has_nhm_msrs || no_msr) |
11cd9a09 ZR |
5232 | return; |
5233 | ||
10d85d85 | 5234 | if (platform->trl_msrs & TRL_LIMIT2) |
a3943dea | 5235 | dump_turbo_ratio_limit2(); |
fcd17211 | 5236 | |
10d85d85 | 5237 | if (platform->trl_msrs & TRL_LIMIT1) |
a3943dea | 5238 | dump_turbo_ratio_limit1(); |
fcd17211 | 5239 | |
10d85d85 ZR |
5240 | if (platform->trl_msrs & TRL_BASE) { |
5241 | dump_turbo_ratio_limits(MSR_TURBO_RATIO_LIMIT); | |
4af184ee LB |
5242 | |
5243 | if (is_hybrid) | |
10d85d85 | 5244 | dump_turbo_ratio_limits(MSR_SECONDARY_TURBO_RATIO_LIMIT); |
4af184ee | 5245 | } |
fcd17211 | 5246 | |
10d85d85 | 5247 | if (platform->trl_msrs & TRL_ATOM) |
0f7887c4 LB |
5248 | dump_atom_turbo_ratio_limits(); |
5249 | ||
10d85d85 | 5250 | if (platform->trl_msrs & TRL_KNL) |
fb5d4327 DC |
5251 | dump_knl_turbo_ratio_limits(); |
5252 | ||
a61c9cb4 | 5253 | if (platform->has_config_tdp) |
6fb3143b | 5254 | dump_config_tdp(); |
3ea8e52e | 5255 | } |
6fb3143b | 5256 | |
a5c6d65d LB |
5257 | static int read_sysfs_int(char *path) |
5258 | { | |
5259 | FILE *input; | |
5260 | int retval = -1; | |
5261 | ||
5262 | input = fopen(path, "r"); | |
5263 | if (input == NULL) { | |
5264 | if (debug) | |
5265 | fprintf(outf, "NSFOD %s\n", path); | |
5266 | return (-1); | |
5267 | } | |
5268 | if (fscanf(input, "%d", &retval) != 1) | |
5269 | err(1, "%s: failed to read int from file", path); | |
5270 | fclose(input); | |
5271 | ||
5272 | return (retval); | |
5273 | } | |
5274 | ||
abdcbdb2 LB |
5275 | static void dump_sysfs_file(char *path) |
5276 | { | |
5277 | FILE *input; | |
5278 | char cpuidle_buf[64]; | |
5279 | ||
5280 | input = fopen(path, "r"); | |
5281 | if (input == NULL) { | |
5282 | if (debug) | |
5283 | fprintf(outf, "NSFOD %s\n", path); | |
5284 | return; | |
5285 | } | |
5286 | if (!fgets(cpuidle_buf, sizeof(cpuidle_buf), input)) | |
5287 | err(1, "%s: failed to read file", path); | |
5288 | fclose(input); | |
5289 | ||
5290 | fprintf(outf, "%s: %s", strrchr(path, '/') + 1, cpuidle_buf); | |
5291 | } | |
1b439f01 | 5292 | |
622c8f23 | 5293 | static void probe_intel_uncore_frequency(void) |
a5c6d65d LB |
5294 | { |
5295 | int i, j; | |
bb6181fa | 5296 | char path[256]; |
a5c6d65d LB |
5297 | |
5298 | if (!genuine_intel) | |
5299 | return; | |
5300 | ||
bb6181fa LB |
5301 | if (access("/sys/devices/system/cpu/intel_uncore_frequency/package_00_die_00/current_freq_khz", R_OK)) |
5302 | goto probe_cluster; | |
4d182748 | 5303 | |
bb6181fa | 5304 | BIC_PRESENT(BIC_UNCORE_MHZ); |
a5c6d65d LB |
5305 | |
5306 | if (quiet) | |
5307 | return; | |
5308 | ||
5309 | for (i = 0; i < topo.num_packages; ++i) { | |
5310 | for (j = 0; j < topo.num_die; ++j) { | |
5311 | int k, l; | |
bb6181fa LB |
5312 | char path_base[128]; |
5313 | ||
5314 | sprintf(path_base, "/sys/devices/system/cpu/intel_uncore_frequency/package_%02d_die_%02d", i, | |
5315 | j); | |
a5c6d65d | 5316 | |
bb6181fa | 5317 | sprintf(path, "%s/min_freq_khz", path_base); |
a5c6d65d | 5318 | k = read_sysfs_int(path); |
bb6181fa | 5319 | sprintf(path, "%s/max_freq_khz", path_base); |
a5c6d65d | 5320 | l = read_sysfs_int(path); |
bb6181fa | 5321 | fprintf(outf, "Uncore Frequency package%d die%d: %d - %d MHz ", i, j, k / 1000, l / 1000); |
a5c6d65d | 5322 | |
bb6181fa | 5323 | sprintf(path, "%s/initial_min_freq_khz", path_base); |
a5c6d65d | 5324 | k = read_sysfs_int(path); |
bb6181fa | 5325 | sprintf(path, "%s/initial_max_freq_khz", path_base); |
a5c6d65d | 5326 | l = read_sysfs_int(path); |
bb6181fa LB |
5327 | fprintf(outf, "(%d - %d MHz)", k / 1000, l / 1000); |
5328 | ||
5329 | sprintf(path, "%s/current_freq_khz", path_base); | |
5330 | k = read_sysfs_int(path); | |
5331 | fprintf(outf, " %d MHz\n", k / 1000); | |
a5c6d65d LB |
5332 | } |
5333 | } | |
bb6181fa LB |
5334 | return; |
5335 | ||
5336 | probe_cluster: | |
5337 | if (access("/sys/devices/system/cpu/intel_uncore_frequency/uncore00/current_freq_khz", R_OK)) | |
5338 | return; | |
5339 | ||
5340 | if (quiet) | |
5341 | return; | |
5342 | ||
5343 | for (i = 0;; ++i) { | |
5344 | int k, l; | |
5345 | char path_base[128]; | |
5346 | int package_id, domain_id, cluster_id; | |
5347 | ||
5348 | sprintf(path_base, "/sys/devices/system/cpu/intel_uncore_frequency/uncore%02d", i); | |
5349 | ||
5350 | if (access(path_base, R_OK)) | |
5351 | break; | |
5352 | ||
5353 | sprintf(path, "%s/package_id", path_base); | |
5354 | package_id = read_sysfs_int(path); | |
5355 | ||
5356 | sprintf(path, "%s/domain_id", path_base); | |
5357 | domain_id = read_sysfs_int(path); | |
5358 | ||
5359 | sprintf(path, "%s/fabric_cluster_id", path_base); | |
5360 | cluster_id = read_sysfs_int(path); | |
5361 | ||
5362 | sprintf(path, "%s/min_freq_khz", path_base); | |
5363 | k = read_sysfs_int(path); | |
5364 | sprintf(path, "%s/max_freq_khz", path_base); | |
5365 | l = read_sysfs_int(path); | |
5366 | fprintf(outf, "Uncore Frequency package%d domain%d cluster%d: %d - %d MHz ", package_id, domain_id, | |
5367 | cluster_id, k / 1000, l / 1000); | |
5368 | ||
5369 | sprintf(path, "%s/initial_min_freq_khz", path_base); | |
5370 | k = read_sysfs_int(path); | |
5371 | sprintf(path, "%s/initial_max_freq_khz", path_base); | |
5372 | l = read_sysfs_int(path); | |
5373 | fprintf(outf, "(%d - %d MHz)", k / 1000, l / 1000); | |
5374 | ||
5375 | sprintf(path, "%s/current_freq_khz", path_base); | |
5376 | k = read_sysfs_int(path); | |
5377 | fprintf(outf, " %d MHz\n", k / 1000); | |
5378 | } | |
a5c6d65d LB |
5379 | } |
5380 | ||
2538d167 ZR |
5381 | static void probe_graphics(void) |
5382 | { | |
5383 | if (!access("/sys/class/drm/card0/power/rc6_residency_ms", R_OK)) | |
4e2bbbf7 | 5384 | gfx_info[GFX_rc6].path = "/sys/class/drm/card0/power/rc6_residency_ms"; |
2538d167 | 5385 | |
4e2bbbf7 ZR |
5386 | if (!access("/sys/class/drm/card0/gt_cur_freq_mhz", R_OK)) |
5387 | gfx_info[GFX_MHz].path = "/sys/class/drm/card0/gt_cur_freq_mhz"; | |
5388 | else if (!access("/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz", R_OK)) | |
5389 | gfx_info[GFX_MHz].path = "/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz"; | |
5390 | ||
5391 | ||
5392 | if (!access("/sys/class/drm/card0/gt_act_freq_mhz", R_OK)) | |
5393 | gfx_info[GFX_ACTMHz].path = "/sys/class/drm/card0/gt_act_freq_mhz"; | |
5394 | else if (!access("/sys/class/graphics/fb0/device/drm/card0/gt_act_freq_mhz", R_OK)) | |
5395 | gfx_info[GFX_ACTMHz].path = "/sys/class/graphics/fb0/device/drm/card0/gt_act_freq_mhz"; | |
2538d167 | 5396 | |
4e2bbbf7 ZR |
5397 | if (gfx_info[GFX_rc6].path) |
5398 | BIC_PRESENT(BIC_GFX_rc6); | |
5399 | if (gfx_info[GFX_MHz].path) | |
5400 | BIC_PRESENT(BIC_GFXMHz); | |
5401 | if (gfx_info[GFX_ACTMHz].path) | |
2538d167 | 5402 | BIC_PRESENT(BIC_GFXACTMHz); |
3bbb331c ZR |
5403 | if (gfx_info[SAM_mc6].path) |
5404 | BIC_PRESENT(BIC_SAM_mc6); | |
5405 | if (gfx_info[SAM_MHz].path) | |
5406 | BIC_PRESENT(BIC_SAMMHz); | |
5407 | if (gfx_info[SAM_ACTMHz].path) | |
5408 | BIC_PRESENT(BIC_SAMACTMHz); | |
2538d167 ZR |
5409 | } |
5410 | ||
1b439f01 | 5411 | static void dump_sysfs_cstate_config(void) |
41618e63 LB |
5412 | { |
5413 | char path[64]; | |
5414 | char name_buf[16]; | |
5415 | char desc[64]; | |
5416 | FILE *input; | |
5417 | int state; | |
5418 | char *sp; | |
5419 | ||
abdcbdb2 LB |
5420 | if (access("/sys/devices/system/cpu/cpuidle", R_OK)) { |
5421 | fprintf(outf, "cpuidle not loaded\n"); | |
5422 | return; | |
5423 | } | |
5424 | ||
5425 | dump_sysfs_file("/sys/devices/system/cpu/cpuidle/current_driver"); | |
5426 | dump_sysfs_file("/sys/devices/system/cpu/cpuidle/current_governor"); | |
5427 | dump_sysfs_file("/sys/devices/system/cpu/cpuidle/current_governor_ro"); | |
5428 | ||
41618e63 LB |
5429 | for (state = 0; state < 10; ++state) { |
5430 | ||
1b439f01 | 5431 | sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name", base_cpu, state); |
41618e63 LB |
5432 | input = fopen(path, "r"); |
5433 | if (input == NULL) | |
5434 | continue; | |
8173c336 BH |
5435 | if (!fgets(name_buf, sizeof(name_buf), input)) |
5436 | err(1, "%s: failed to read file", path); | |
41618e63 | 5437 | |
1b439f01 | 5438 | /* truncate "C1-HSW\n" to "C1", or truncate "C1\n" to "C1" */ |
41618e63 LB |
5439 | sp = strchr(name_buf, '-'); |
5440 | if (!sp) | |
5441 | sp = strchrnul(name_buf, '\n'); | |
5442 | *sp = '\0'; | |
41618e63 LB |
5443 | fclose(input); |
5444 | ||
fecb3bc8 DA |
5445 | remove_underbar(name_buf); |
5446 | ||
1b439f01 | 5447 | sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/desc", base_cpu, state); |
41618e63 LB |
5448 | input = fopen(path, "r"); |
5449 | if (input == NULL) | |
5450 | continue; | |
8173c336 BH |
5451 | if (!fgets(desc, sizeof(desc), input)) |
5452 | err(1, "%s: failed to read file", path); | |
41618e63 LB |
5453 | |
5454 | fprintf(outf, "cpu%d: %s: %s", base_cpu, name_buf, desc); | |
5455 | fclose(input); | |
5456 | } | |
5457 | } | |
1b439f01 LB |
5458 | |
5459 | static void dump_sysfs_pstate_config(void) | |
7293fccd LB |
5460 | { |
5461 | char path[64]; | |
5462 | char driver_buf[64]; | |
5463 | char governor_buf[64]; | |
5464 | FILE *input; | |
5465 | int turbo; | |
5466 | ||
1b439f01 | 5467 | sprintf(path, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_driver", base_cpu); |
7293fccd LB |
5468 | input = fopen(path, "r"); |
5469 | if (input == NULL) { | |
0a42d235 | 5470 | fprintf(outf, "NSFOD %s\n", path); |
7293fccd LB |
5471 | return; |
5472 | } | |
8173c336 BH |
5473 | if (!fgets(driver_buf, sizeof(driver_buf), input)) |
5474 | err(1, "%s: failed to read file", path); | |
7293fccd LB |
5475 | fclose(input); |
5476 | ||
1b439f01 | 5477 | sprintf(path, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", base_cpu); |
7293fccd LB |
5478 | input = fopen(path, "r"); |
5479 | if (input == NULL) { | |
0a42d235 | 5480 | fprintf(outf, "NSFOD %s\n", path); |
7293fccd LB |
5481 | return; |
5482 | } | |
8173c336 BH |
5483 | if (!fgets(governor_buf, sizeof(governor_buf), input)) |
5484 | err(1, "%s: failed to read file", path); | |
7293fccd LB |
5485 | fclose(input); |
5486 | ||
5487 | fprintf(outf, "cpu%d: cpufreq driver: %s", base_cpu, driver_buf); | |
5488 | fprintf(outf, "cpu%d: cpufreq governor: %s", base_cpu, governor_buf); | |
5489 | ||
5490 | sprintf(path, "/sys/devices/system/cpu/cpufreq/boost"); | |
5491 | input = fopen(path, "r"); | |
5492 | if (input != NULL) { | |
8173c336 BH |
5493 | if (fscanf(input, "%d", &turbo) != 1) |
5494 | err(1, "%s: failed to parse number from file", path); | |
7293fccd LB |
5495 | fprintf(outf, "cpufreq boost: %d\n", turbo); |
5496 | fclose(input); | |
5497 | } | |
5498 | ||
5499 | sprintf(path, "/sys/devices/system/cpu/intel_pstate/no_turbo"); | |
5500 | input = fopen(path, "r"); | |
5501 | if (input != NULL) { | |
8173c336 BH |
5502 | if (fscanf(input, "%d", &turbo) != 1) |
5503 | err(1, "%s: failed to parse number from file", path); | |
7293fccd LB |
5504 | fprintf(outf, "cpufreq intel_pstate no_turbo: %d\n", turbo); |
5505 | fclose(input); | |
5506 | } | |
5507 | } | |
41618e63 | 5508 | |
889facbe LB |
5509 | /* |
5510 | * print_epb() | |
5511 | * Decode the ENERGY_PERF_BIAS MSR | |
5512 | */ | |
5513 | int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p) | |
5514 | { | |
889facbe | 5515 | char *epb_string; |
6d6501d9 | 5516 | int cpu, epb; |
889facbe | 5517 | |
9878bf7a LB |
5518 | UNUSED(c); |
5519 | UNUSED(p); | |
5520 | ||
889facbe LB |
5521 | if (!has_epb) |
5522 | return 0; | |
5523 | ||
5524 | cpu = t->cpu_id; | |
5525 | ||
5526 | /* EPB is per-package */ | |
74318add | 5527 | if (!is_cpu_first_thread_in_package(t, c, p)) |
889facbe LB |
5528 | return 0; |
5529 | ||
5530 | if (cpu_migrate(cpu)) { | |
3d7772ea | 5531 | fprintf(outf, "print_epb: Could not migrate to CPU %d\n", cpu); |
889facbe LB |
5532 | return -1; |
5533 | } | |
5534 | ||
6d6501d9 BP |
5535 | epb = get_epb(cpu); |
5536 | if (epb < 0) | |
889facbe LB |
5537 | return 0; |
5538 | ||
6d6501d9 | 5539 | switch (epb) { |
889facbe LB |
5540 | case ENERGY_PERF_BIAS_PERFORMANCE: |
5541 | epb_string = "performance"; | |
5542 | break; | |
5543 | case ENERGY_PERF_BIAS_NORMAL: | |
5544 | epb_string = "balanced"; | |
5545 | break; | |
5546 | case ENERGY_PERF_BIAS_POWERSAVE: | |
5547 | epb_string = "powersave"; | |
5548 | break; | |
5549 | default: | |
5550 | epb_string = "custom"; | |
5551 | break; | |
5552 | } | |
6d6501d9 | 5553 | fprintf(outf, "cpu%d: EPB: %d (%s)\n", cpu, epb, epb_string); |
889facbe LB |
5554 | |
5555 | return 0; | |
5556 | } | |
1b439f01 | 5557 | |
7f5c258e LB |
5558 | /* |
5559 | * print_hwp() | |
5560 | * Decode the MSR_HWP_CAPABILITIES | |
5561 | */ | |
5562 | int print_hwp(struct thread_data *t, struct core_data *c, struct pkg_data *p) | |
5563 | { | |
5564 | unsigned long long msr; | |
5565 | int cpu; | |
5566 | ||
9878bf7a LB |
5567 | UNUSED(c); |
5568 | UNUSED(p); | |
5569 | ||
3e404846 PW |
5570 | if (no_msr) |
5571 | return 0; | |
5572 | ||
7f5c258e LB |
5573 | if (!has_hwp) |
5574 | return 0; | |
5575 | ||
5576 | cpu = t->cpu_id; | |
5577 | ||
5578 | /* MSR_HWP_CAPABILITIES is per-package */ | |
74318add | 5579 | if (!is_cpu_first_thread_in_package(t, c, p)) |
7f5c258e LB |
5580 | return 0; |
5581 | ||
5582 | if (cpu_migrate(cpu)) { | |
3d7772ea | 5583 | fprintf(outf, "print_hwp: Could not migrate to CPU %d\n", cpu); |
7f5c258e LB |
5584 | return -1; |
5585 | } | |
5586 | ||
5587 | if (get_msr(cpu, MSR_PM_ENABLE, &msr)) | |
5588 | return 0; | |
5589 | ||
1b439f01 | 5590 | fprintf(outf, "cpu%d: MSR_PM_ENABLE: 0x%08llx (%sHWP)\n", cpu, msr, (msr & (1 << 0)) ? "" : "No-"); |
7f5c258e LB |
5591 | |
5592 | /* MSR_PM_ENABLE[1] == 1 if HWP is enabled and MSRs visible */ | |
5593 | if ((msr & (1 << 0)) == 0) | |
5594 | return 0; | |
5595 | ||
5596 | if (get_msr(cpu, MSR_HWP_CAPABILITIES, &msr)) | |
5597 | return 0; | |
5598 | ||
b7d8c148 | 5599 | fprintf(outf, "cpu%d: MSR_HWP_CAPABILITIES: 0x%08llx " |
1b439f01 LB |
5600 | "(high %d guar %d eff %d low %d)\n", |
5601 | cpu, msr, | |
5602 | (unsigned int)HWP_HIGHEST_PERF(msr), | |
5603 | (unsigned int)HWP_GUARANTEED_PERF(msr), | |
5604 | (unsigned int)HWP_MOSTEFFICIENT_PERF(msr), (unsigned int)HWP_LOWEST_PERF(msr)); | |
7f5c258e LB |
5605 | |
5606 | if (get_msr(cpu, MSR_HWP_REQUEST, &msr)) | |
5607 | return 0; | |
5608 | ||
b7d8c148 | 5609 | fprintf(outf, "cpu%d: MSR_HWP_REQUEST: 0x%08llx " |
1b439f01 LB |
5610 | "(min %d max %d des %d epp 0x%x window 0x%x pkg 0x%x)\n", |
5611 | cpu, msr, | |
5612 | (unsigned int)(((msr) >> 0) & 0xff), | |
5613 | (unsigned int)(((msr) >> 8) & 0xff), | |
5614 | (unsigned int)(((msr) >> 16) & 0xff), | |
5615 | (unsigned int)(((msr) >> 24) & 0xff), | |
5616 | (unsigned int)(((msr) >> 32) & 0xff3), (unsigned int)(((msr) >> 42) & 0x1)); | |
7f5c258e LB |
5617 | |
5618 | if (has_hwp_pkg) { | |
5619 | if (get_msr(cpu, MSR_HWP_REQUEST_PKG, &msr)) | |
5620 | return 0; | |
5621 | ||
b7d8c148 | 5622 | fprintf(outf, "cpu%d: MSR_HWP_REQUEST_PKG: 0x%08llx " |
6dbd25a2 | 5623 | "(min %d max %d des %d epp 0x%x window 0x%x)\n", |
7f5c258e LB |
5624 | cpu, msr, |
5625 | (unsigned int)(((msr) >> 0) & 0xff), | |
5626 | (unsigned int)(((msr) >> 8) & 0xff), | |
5627 | (unsigned int)(((msr) >> 16) & 0xff), | |
1b439f01 | 5628 | (unsigned int)(((msr) >> 24) & 0xff), (unsigned int)(((msr) >> 32) & 0xff3)); |
7f5c258e LB |
5629 | } |
5630 | if (has_hwp_notify) { | |
5631 | if (get_msr(cpu, MSR_HWP_INTERRUPT, &msr)) | |
5632 | return 0; | |
5633 | ||
b7d8c148 | 5634 | fprintf(outf, "cpu%d: MSR_HWP_INTERRUPT: 0x%08llx " |
7f5c258e | 5635 | "(%s_Guaranteed_Perf_Change, %s_Excursion_Min)\n", |
1b439f01 | 5636 | cpu, msr, ((msr) & 0x1) ? "EN" : "Dis", ((msr) & 0x2) ? "EN" : "Dis"); |
7f5c258e LB |
5637 | } |
5638 | if (get_msr(cpu, MSR_HWP_STATUS, &msr)) | |
5639 | return 0; | |
5640 | ||
b7d8c148 | 5641 | fprintf(outf, "cpu%d: MSR_HWP_STATUS: 0x%08llx " |
1b439f01 | 5642 | "(%sGuaranteed_Perf_Change, %sExcursion_Min)\n", |
92c25393 | 5643 | cpu, msr, ((msr) & 0x1) ? "" : "No-", ((msr) & 0x4) ? "" : "No-"); |
889facbe LB |
5644 | |
5645 | return 0; | |
5646 | } | |
5647 | ||
3a9a941d LB |
5648 | /* |
5649 | * print_perf_limit() | |
5650 | */ | |
5651 | int print_perf_limit(struct thread_data *t, struct core_data *c, struct pkg_data *p) | |
5652 | { | |
5653 | unsigned long long msr; | |
5654 | int cpu; | |
5655 | ||
9878bf7a LB |
5656 | UNUSED(c); |
5657 | UNUSED(p); | |
5658 | ||
3e404846 PW |
5659 | if (no_msr) |
5660 | return 0; | |
5661 | ||
3a9a941d LB |
5662 | cpu = t->cpu_id; |
5663 | ||
5664 | /* per-package */ | |
74318add | 5665 | if (!is_cpu_first_thread_in_package(t, c, p)) |
3a9a941d LB |
5666 | return 0; |
5667 | ||
5668 | if (cpu_migrate(cpu)) { | |
3d7772ea | 5669 | fprintf(outf, "print_perf_limit: Could not migrate to CPU %d\n", cpu); |
3a9a941d LB |
5670 | return -1; |
5671 | } | |
5672 | ||
0c057cf7 | 5673 | if (platform->plr_msrs & PLR_CORE) { |
3a9a941d | 5674 | get_msr(cpu, MSR_CORE_PERF_LIMIT_REASONS, &msr); |
b7d8c148 LB |
5675 | fprintf(outf, "cpu%d: MSR_CORE_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr); |
5676 | fprintf(outf, " (Active: %s%s%s%s%s%s%s%s%s%s%s%s%s%s)", | |
e33cbe85 | 5677 | (msr & 1 << 15) ? "bit15, " : "", |
3a9a941d | 5678 | (msr & 1 << 14) ? "bit14, " : "", |
e33cbe85 LB |
5679 | (msr & 1 << 13) ? "Transitions, " : "", |
5680 | (msr & 1 << 12) ? "MultiCoreTurbo, " : "", | |
5681 | (msr & 1 << 11) ? "PkgPwrL2, " : "", | |
5682 | (msr & 1 << 10) ? "PkgPwrL1, " : "", | |
5683 | (msr & 1 << 9) ? "CorePwr, " : "", | |
5684 | (msr & 1 << 8) ? "Amps, " : "", | |
5685 | (msr & 1 << 6) ? "VR-Therm, " : "", | |
5686 | (msr & 1 << 5) ? "Auto-HWP, " : "", | |
5687 | (msr & 1 << 4) ? "Graphics, " : "", | |
5688 | (msr & 1 << 2) ? "bit2, " : "", | |
1b439f01 | 5689 | (msr & 1 << 1) ? "ThermStatus, " : "", (msr & 1 << 0) ? "PROCHOT, " : ""); |
b7d8c148 | 5690 | fprintf(outf, " (Logged: %s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n", |
e33cbe85 | 5691 | (msr & 1 << 31) ? "bit31, " : "", |
3a9a941d | 5692 | (msr & 1 << 30) ? "bit30, " : "", |
e33cbe85 LB |
5693 | (msr & 1 << 29) ? "Transitions, " : "", |
5694 | (msr & 1 << 28) ? "MultiCoreTurbo, " : "", | |
5695 | (msr & 1 << 27) ? "PkgPwrL2, " : "", | |
5696 | (msr & 1 << 26) ? "PkgPwrL1, " : "", | |
5697 | (msr & 1 << 25) ? "CorePwr, " : "", | |
5698 | (msr & 1 << 24) ? "Amps, " : "", | |
5699 | (msr & 1 << 22) ? "VR-Therm, " : "", | |
5700 | (msr & 1 << 21) ? "Auto-HWP, " : "", | |
5701 | (msr & 1 << 20) ? "Graphics, " : "", | |
5702 | (msr & 1 << 18) ? "bit18, " : "", | |
1b439f01 | 5703 | (msr & 1 << 17) ? "ThermStatus, " : "", (msr & 1 << 16) ? "PROCHOT, " : ""); |
3a9a941d LB |
5704 | |
5705 | } | |
0c057cf7 | 5706 | if (platform->plr_msrs & PLR_GFX) { |
3a9a941d | 5707 | get_msr(cpu, MSR_GFX_PERF_LIMIT_REASONS, &msr); |
b7d8c148 LB |
5708 | fprintf(outf, "cpu%d: MSR_GFX_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr); |
5709 | fprintf(outf, " (Active: %s%s%s%s%s%s%s%s)", | |
3a9a941d LB |
5710 | (msr & 1 << 0) ? "PROCHOT, " : "", |
5711 | (msr & 1 << 1) ? "ThermStatus, " : "", | |
5712 | (msr & 1 << 4) ? "Graphics, " : "", | |
5713 | (msr & 1 << 6) ? "VR-Therm, " : "", | |
5714 | (msr & 1 << 8) ? "Amps, " : "", | |
5715 | (msr & 1 << 9) ? "GFXPwr, " : "", | |
1b439f01 | 5716 | (msr & 1 << 10) ? "PkgPwrL1, " : "", (msr & 1 << 11) ? "PkgPwrL2, " : ""); |
b7d8c148 | 5717 | fprintf(outf, " (Logged: %s%s%s%s%s%s%s%s)\n", |
3a9a941d LB |
5718 | (msr & 1 << 16) ? "PROCHOT, " : "", |
5719 | (msr & 1 << 17) ? "ThermStatus, " : "", | |
5720 | (msr & 1 << 20) ? "Graphics, " : "", | |
5721 | (msr & 1 << 22) ? "VR-Therm, " : "", | |
5722 | (msr & 1 << 24) ? "Amps, " : "", | |
5723 | (msr & 1 << 25) ? "GFXPwr, " : "", | |
1b439f01 | 5724 | (msr & 1 << 26) ? "PkgPwrL1, " : "", (msr & 1 << 27) ? "PkgPwrL2, " : ""); |
3a9a941d | 5725 | } |
0c057cf7 | 5726 | if (platform->plr_msrs & PLR_RING) { |
3a9a941d | 5727 | get_msr(cpu, MSR_RING_PERF_LIMIT_REASONS, &msr); |
b7d8c148 LB |
5728 | fprintf(outf, "cpu%d: MSR_RING_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr); |
5729 | fprintf(outf, " (Active: %s%s%s%s%s%s)", | |
3a9a941d LB |
5730 | (msr & 1 << 0) ? "PROCHOT, " : "", |
5731 | (msr & 1 << 1) ? "ThermStatus, " : "", | |
5732 | (msr & 1 << 6) ? "VR-Therm, " : "", | |
5733 | (msr & 1 << 8) ? "Amps, " : "", | |
1b439f01 | 5734 | (msr & 1 << 10) ? "PkgPwrL1, " : "", (msr & 1 << 11) ? "PkgPwrL2, " : ""); |
b7d8c148 | 5735 | fprintf(outf, " (Logged: %s%s%s%s%s%s)\n", |
3a9a941d LB |
5736 | (msr & 1 << 16) ? "PROCHOT, " : "", |
5737 | (msr & 1 << 17) ? "ThermStatus, " : "", | |
5738 | (msr & 1 << 22) ? "VR-Therm, " : "", | |
5739 | (msr & 1 << 24) ? "Amps, " : "", | |
1b439f01 | 5740 | (msr & 1 << 26) ? "PkgPwrL1, " : "", (msr & 1 << 27) ? "PkgPwrL2, " : ""); |
3a9a941d LB |
5741 | } |
5742 | return 0; | |
5743 | } | |
5744 | ||
889facbe | 5745 | #define RAPL_POWER_GRANULARITY 0x7FFF /* 15 bit power granularity */ |
1b439f01 | 5746 | #define RAPL_TIME_GRANULARITY 0x3F /* 6 bit time granularity */ |
889facbe | 5747 | |
7c604093 ZR |
5748 | double get_quirk_tdp(void) |
5749 | { | |
5750 | if (platform->rapl_quirk_tdp) | |
5751 | return platform->rapl_quirk_tdp; | |
5752 | ||
5753 | return 135.0; | |
5754 | } | |
5755 | ||
bf1ad57c | 5756 | double get_tdp_intel(void) |
144b44b1 LB |
5757 | { |
5758 | unsigned long long msr; | |
5759 | ||
86ba263d | 5760 | if (platform->rapl_msrs & RAPL_PKG_POWER_INFO) |
7ce7d5de | 5761 | if (!get_msr(base_cpu, MSR_PKG_POWER_INFO, &msr)) |
144b44b1 | 5762 | return ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units; |
7c604093 | 5763 | return get_quirk_tdp(); |
144b44b1 LB |
5764 | } |
5765 | ||
bf1ad57c | 5766 | double get_tdp_amd(void) |
9392bd98 | 5767 | { |
7c604093 | 5768 | return get_quirk_tdp(); |
9392bd98 CW |
5769 | } |
5770 | ||
bf1ad57c | 5771 | void rapl_probe_intel(void) |
889facbe LB |
5772 | { |
5773 | unsigned long long msr; | |
144b44b1 | 5774 | unsigned int time_unit; |
889facbe | 5775 | double tdp; |
05a2f07d PW |
5776 | const unsigned long long bic_watt_bits = BIC_PkgWatt | BIC_CorWatt | BIC_RAMWatt | BIC_GFXWatt; |
5777 | const unsigned long long bic_joules_bits = BIC_Pkg_J | BIC_Cor_J | BIC_RAM_J | BIC_GFX_J; | |
889facbe | 5778 | |
05a2f07d PW |
5779 | if (rapl_joules) |
5780 | bic_enabled &= ~bic_watt_bits; | |
5781 | else | |
5782 | bic_enabled &= ~bic_joules_bits; | |
889facbe | 5783 | |
05a2f07d PW |
5784 | if (!(platform->rapl_msrs & RAPL_PKG_PERF_STATUS)) |
5785 | bic_enabled &= ~BIC_PKG__; | |
5786 | if (!(platform->rapl_msrs & RAPL_DRAM_PERF_STATUS)) | |
5787 | bic_enabled &= ~BIC_RAM__; | |
a98f8860 | 5788 | |
889facbe | 5789 | /* units on package 0, verify later other packages match */ |
7ce7d5de | 5790 | if (get_msr(base_cpu, MSR_RAPL_POWER_UNIT, &msr)) |
889facbe LB |
5791 | return; |
5792 | ||
5793 | rapl_power_units = 1.0 / (1 << (msr & 0xF)); | |
6d35b8c4 | 5794 | if (platform->has_rapl_divisor) |
144b44b1 LB |
5795 | rapl_energy_units = 1.0 * (1 << (msr >> 8 & 0x1F)) / 1000000; |
5796 | else | |
5797 | rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F)); | |
889facbe | 5798 | |
9e6f3515 ZR |
5799 | if (platform->has_fixed_rapl_unit) |
5800 | rapl_dram_energy_units = (15.3 / 1000000); | |
5801 | else | |
5802 | rapl_dram_energy_units = rapl_energy_units; | |
40ee8e3b | 5803 | |
144b44b1 LB |
5804 | time_unit = msr >> 16 & 0xF; |
5805 | if (time_unit == 0) | |
5806 | time_unit = 0xA; | |
889facbe | 5807 | |
144b44b1 | 5808 | rapl_time_units = 1.0 / (1 << (time_unit)); |
889facbe | 5809 | |
bf1ad57c | 5810 | tdp = get_tdp_intel(); |
889facbe | 5811 | |
144b44b1 | 5812 | rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp; |
96e47158 | 5813 | if (!quiet) |
b7d8c148 | 5814 | fprintf(outf, "RAPL: %.0f sec. Joule Counter Range, at %.0f Watts\n", rapl_joule_counter_range, tdp); |
9392bd98 | 5815 | } |
889facbe | 5816 | |
bf1ad57c | 5817 | void rapl_probe_amd(void) |
9392bd98 CW |
5818 | { |
5819 | unsigned long long msr; | |
9392bd98 | 5820 | double tdp; |
05a2f07d PW |
5821 | const unsigned long long bic_watt_bits = BIC_PkgWatt | BIC_CorWatt; |
5822 | const unsigned long long bic_joules_bits = BIC_Pkg_J | BIC_Cor_J; | |
9392bd98 | 5823 | |
05a2f07d PW |
5824 | if (rapl_joules) |
5825 | bic_enabled &= ~bic_watt_bits; | |
5826 | else | |
5827 | bic_enabled &= ~bic_joules_bits; | |
9392bd98 CW |
5828 | |
5829 | if (get_msr(base_cpu, MSR_RAPL_PWR_UNIT, &msr)) | |
5830 | return; | |
5831 | ||
5832 | rapl_time_units = ldexp(1.0, -(msr >> 16 & 0xf)); | |
5833 | rapl_energy_units = ldexp(1.0, -(msr >> 8 & 0x1f)); | |
5834 | rapl_power_units = ldexp(1.0, -(msr & 0xf)); | |
5835 | ||
bf1ad57c | 5836 | tdp = get_tdp_amd(); |
9392bd98 CW |
5837 | |
5838 | rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp; | |
5839 | if (!quiet) | |
5840 | fprintf(outf, "RAPL: %.0f sec. Joule Counter Range, at %.0f Watts\n", rapl_joule_counter_range, tdp); | |
5841 | } | |
5842 | ||
889facbe LB |
5843 | void print_power_limit_msr(int cpu, unsigned long long msr, char *label) |
5844 | { | |
6b398625 | 5845 | fprintf(outf, "cpu%d: %s: %sabled (%0.3f Watts, %f sec, clamp %sabled)\n", |
889facbe LB |
5846 | cpu, label, |
5847 | ((msr >> 15) & 1) ? "EN" : "DIS", | |
5848 | ((msr >> 0) & 0x7FFF) * rapl_power_units, | |
1b439f01 | 5849 | (1.0 + (((msr >> 22) & 0x3) / 4.0)) * (1 << ((msr >> 17) & 0x1F)) * rapl_time_units, |
889facbe LB |
5850 | (((msr >> 16) & 1) ? "EN" : "DIS")); |
5851 | ||
5852 | return; | |
5853 | } | |
5854 | ||
5855 | int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p) | |
5856 | { | |
5857 | unsigned long long msr; | |
9392bd98 | 5858 | const char *msr_name; |
889facbe | 5859 | int cpu; |
889facbe | 5860 | |
9878bf7a LB |
5861 | UNUSED(c); |
5862 | UNUSED(p); | |
5863 | ||
86ba263d | 5864 | if (!platform->rapl_msrs) |
889facbe LB |
5865 | return 0; |
5866 | ||
5867 | /* RAPL counters are per package, so print only for 1st thread/package */ | |
74318add | 5868 | if (!is_cpu_first_thread_in_package(t, c, p)) |
889facbe LB |
5869 | return 0; |
5870 | ||
5871 | cpu = t->cpu_id; | |
5872 | if (cpu_migrate(cpu)) { | |
3d7772ea | 5873 | fprintf(outf, "print_rapl: Could not migrate to CPU %d\n", cpu); |
889facbe LB |
5874 | return -1; |
5875 | } | |
5876 | ||
86ba263d | 5877 | if (platform->rapl_msrs & RAPL_AMD_F17H) { |
9392bd98 CW |
5878 | msr_name = "MSR_RAPL_PWR_UNIT"; |
5879 | if (get_msr(cpu, MSR_RAPL_PWR_UNIT, &msr)) | |
5880 | return -1; | |
5881 | } else { | |
5882 | msr_name = "MSR_RAPL_POWER_UNIT"; | |
5883 | if (get_msr(cpu, MSR_RAPL_POWER_UNIT, &msr)) | |
5884 | return -1; | |
5885 | } | |
889facbe | 5886 | |
9392bd98 | 5887 | fprintf(outf, "cpu%d: %s: 0x%08llx (%f Watts, %f Joules, %f sec.)\n", cpu, msr_name, msr, |
96e47158 LB |
5888 | rapl_power_units, rapl_energy_units, rapl_time_units); |
5889 | ||
86ba263d | 5890 | if (platform->rapl_msrs & RAPL_PKG_POWER_INFO) { |
144b44b1 | 5891 | |
889facbe | 5892 | if (get_msr(cpu, MSR_PKG_POWER_INFO, &msr)) |
1b439f01 | 5893 | return -5; |
889facbe | 5894 | |
b7d8c148 | 5895 | fprintf(outf, "cpu%d: MSR_PKG_POWER_INFO: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n", |
889facbe | 5896 | cpu, msr, |
1b439f01 | 5897 | ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units, |
889facbe LB |
5898 | ((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units, |
5899 | ((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units, | |
5900 | ((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units); | |
5901 | ||
144b44b1 | 5902 | } |
86ba263d | 5903 | if (platform->rapl_msrs & RAPL_PKG) { |
144b44b1 | 5904 | |
889facbe LB |
5905 | if (get_msr(cpu, MSR_PKG_POWER_LIMIT, &msr)) |
5906 | return -9; | |
5907 | ||
b7d8c148 | 5908 | fprintf(outf, "cpu%d: MSR_PKG_POWER_LIMIT: 0x%08llx (%slocked)\n", |
96e47158 | 5909 | cpu, msr, (msr >> 63) & 1 ? "" : "UN"); |
889facbe LB |
5910 | |
5911 | print_power_limit_msr(cpu, msr, "PKG Limit #1"); | |
6b398625 | 5912 | fprintf(outf, "cpu%d: PKG Limit #2: %sabled (%0.3f Watts, %f* sec, clamp %sabled)\n", |
889facbe LB |
5913 | cpu, |
5914 | ((msr >> 47) & 1) ? "EN" : "DIS", | |
5915 | ((msr >> 32) & 0x7FFF) * rapl_power_units, | |
1b439f01 | 5916 | (1.0 + (((msr >> 54) & 0x3) / 4.0)) * (1 << ((msr >> 49) & 0x1F)) * rapl_time_units, |
889facbe | 5917 | ((msr >> 48) & 1) ? "EN" : "DIS"); |
f52ba931 SP |
5918 | |
5919 | if (get_msr(cpu, MSR_VR_CURRENT_CONFIG, &msr)) | |
5920 | return -9; | |
5921 | ||
5922 | fprintf(outf, "cpu%d: MSR_VR_CURRENT_CONFIG: 0x%08llx\n", cpu, msr); | |
5923 | fprintf(outf, "cpu%d: PKG Limit #4: %f Watts (%slocked)\n", | |
164d7a96 | 5924 | cpu, ((msr >> 0) & 0x1FFF) * rapl_power_units, (msr >> 31) & 1 ? "" : "UN"); |
889facbe LB |
5925 | } |
5926 | ||
86ba263d | 5927 | if (platform->rapl_msrs & RAPL_DRAM_POWER_INFO) { |
889facbe | 5928 | if (get_msr(cpu, MSR_DRAM_POWER_INFO, &msr)) |
1b439f01 | 5929 | return -6; |
889facbe | 5930 | |
b7d8c148 | 5931 | fprintf(outf, "cpu%d: MSR_DRAM_POWER_INFO,: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n", |
889facbe | 5932 | cpu, msr, |
1b439f01 | 5933 | ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units, |
889facbe LB |
5934 | ((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units, |
5935 | ((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units, | |
5936 | ((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units); | |
0b2bb692 | 5937 | } |
86ba263d | 5938 | if (platform->rapl_msrs & RAPL_DRAM) { |
889facbe LB |
5939 | if (get_msr(cpu, MSR_DRAM_POWER_LIMIT, &msr)) |
5940 | return -9; | |
b7d8c148 | 5941 | fprintf(outf, "cpu%d: MSR_DRAM_POWER_LIMIT: 0x%08llx (%slocked)\n", |
1b439f01 | 5942 | cpu, msr, (msr >> 31) & 1 ? "" : "UN"); |
889facbe LB |
5943 | |
5944 | print_power_limit_msr(cpu, msr, "DRAM Limit"); | |
5945 | } | |
86ba263d | 5946 | if (platform->rapl_msrs & RAPL_CORE_POLICY) { |
96e47158 LB |
5947 | if (get_msr(cpu, MSR_PP0_POLICY, &msr)) |
5948 | return -7; | |
889facbe | 5949 | |
96e47158 | 5950 | fprintf(outf, "cpu%d: MSR_PP0_POLICY: %lld\n", cpu, msr & 0xF); |
144b44b1 | 5951 | } |
86ba263d | 5952 | if (platform->rapl_msrs & RAPL_CORE_POWER_LIMIT) { |
96e47158 LB |
5953 | if (get_msr(cpu, MSR_PP0_POWER_LIMIT, &msr)) |
5954 | return -9; | |
5955 | fprintf(outf, "cpu%d: MSR_PP0_POWER_LIMIT: 0x%08llx (%slocked)\n", | |
1b439f01 | 5956 | cpu, msr, (msr >> 31) & 1 ? "" : "UN"); |
96e47158 | 5957 | print_power_limit_msr(cpu, msr, "Cores Limit"); |
889facbe | 5958 | } |
86ba263d | 5959 | if (platform->rapl_msrs & RAPL_GFX) { |
96e47158 LB |
5960 | if (get_msr(cpu, MSR_PP1_POLICY, &msr)) |
5961 | return -8; | |
889facbe | 5962 | |
96e47158 | 5963 | fprintf(outf, "cpu%d: MSR_PP1_POLICY: %lld\n", cpu, msr & 0xF); |
889facbe | 5964 | |
96e47158 LB |
5965 | if (get_msr(cpu, MSR_PP1_POWER_LIMIT, &msr)) |
5966 | return -9; | |
5967 | fprintf(outf, "cpu%d: MSR_PP1_POWER_LIMIT: 0x%08llx (%slocked)\n", | |
1b439f01 | 5968 | cpu, msr, (msr >> 31) & 1 ? "" : "UN"); |
96e47158 | 5969 | print_power_limit_msr(cpu, msr, "GFX Limit"); |
889facbe LB |
5970 | } |
5971 | return 0; | |
5972 | } | |
5973 | ||
ce7a32c2 ZR |
5974 | /* |
5975 | * probe_rapl() | |
5976 | * | |
5977 | * sets rapl_power_units, rapl_energy_units, rapl_time_units | |
5978 | */ | |
5979 | void probe_rapl(void) | |
7ab5ff49 | 5980 | { |
3e404846 | 5981 | if (!platform->rapl_msrs || no_msr) |
ce7a32c2 | 5982 | return; |
7ab5ff49 | 5983 | |
ce7a32c2 ZR |
5984 | if (genuine_intel) |
5985 | rapl_probe_intel(); | |
5986 | if (authentic_amd || hygon_genuine) | |
5987 | rapl_probe_amd(); | |
5612b2c8 ZR |
5988 | |
5989 | if (quiet) | |
5990 | return; | |
5991 | ||
5992 | for_all_cpus(print_rapl, ODD_COUNTERS); | |
7ab5ff49 ZR |
5993 | } |
5994 | ||
889facbe LB |
5995 | /* |
5996 | * MSR_IA32_TEMPERATURE_TARGET indicates the temperature where | |
5997 | * the Thermal Control Circuit (TCC) activates. | |
5998 | * This is usually equal to tjMax. | |
5999 | * | |
6000 | * Older processors do not have this MSR, so there we guess, | |
6001 | * but also allow cmdline over-ride with -T. | |
6002 | * | |
6003 | * Several MSR temperature values are in units of degrees-C | |
6004 | * below this value, including the Digital Thermal Sensor (DTS), | |
6005 | * Package Thermal Management Sensor (PTM), and thermal event thresholds. | |
6006 | */ | |
b2b94be7 | 6007 | int set_temperature_target(struct thread_data *t, struct core_data *c, struct pkg_data *p) |
889facbe LB |
6008 | { |
6009 | unsigned long long msr; | |
55279aef | 6010 | unsigned int tcc_default, tcc_offset; |
b2b94be7 | 6011 | int cpu; |
6ff7cb37 | 6012 | |
9878bf7a LB |
6013 | UNUSED(c); |
6014 | UNUSED(p); | |
6015 | ||
55279aef | 6016 | /* tj_max is used only for dts or ptm */ |
889facbe LB |
6017 | if (!(do_dts || do_ptm)) |
6018 | return 0; | |
6019 | ||
6020 | /* this is a per-package concept */ | |
74318add | 6021 | if (!is_cpu_first_thread_in_package(t, c, p)) |
889facbe LB |
6022 | return 0; |
6023 | ||
b2b94be7 LB |
6024 | cpu = t->cpu_id; |
6025 | if (cpu_migrate(cpu)) { | |
6026 | fprintf(outf, "Could not migrate to CPU %d\n", cpu); | |
6027 | return -1; | |
6028 | } | |
6029 | ||
55279aef ZR |
6030 | if (tj_max_override != 0) { |
6031 | tj_max = tj_max_override; | |
1b439f01 | 6032 | fprintf(outf, "cpu%d: Using cmdline TCC Target (%d C)\n", cpu, tj_max); |
889facbe LB |
6033 | return 0; |
6034 | } | |
6035 | ||
b2b94be7 | 6036 | /* Temperature Target MSR is Nehalem and newer only */ |
3e404846 | 6037 | if (!platform->has_nhm_msrs || no_msr) |
b2b94be7 LB |
6038 | goto guess; |
6039 | ||
6040 | if (get_msr(base_cpu, MSR_IA32_TEMPERATURE_TARGET, &msr)) | |
6041 | goto guess; | |
6042 | ||
55279aef | 6043 | tcc_default = (msr >> 16) & 0xFF; |
b2b94be7 | 6044 | |
0b9a0b9b | 6045 | if (!quiet) { |
d8e1623b ZR |
6046 | int bits = platform->tcc_offset_bits; |
6047 | unsigned long long enabled = 0; | |
6048 | ||
6049 | if (bits && !get_msr(base_cpu, MSR_PLATFORM_INFO, &enabled)) | |
6050 | enabled = (enabled >> 30) & 1; | |
6051 | ||
6052 | if (bits && enabled) { | |
6053 | tcc_offset = (msr >> 24) & GENMASK(bits - 1, 0); | |
0b9a0b9b | 6054 | fprintf(outf, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C) (%d default - %d offset)\n", |
1b439f01 | 6055 | cpu, msr, tcc_default - tcc_offset, tcc_default, tcc_offset); |
d8e1623b | 6056 | } else { |
1b439f01 | 6057 | fprintf(outf, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C)\n", cpu, msr, tcc_default); |
0b9a0b9b ZR |
6058 | } |
6059 | } | |
b2b94be7 | 6060 | |
55279aef | 6061 | if (!tcc_default) |
b2b94be7 LB |
6062 | goto guess; |
6063 | ||
55279aef | 6064 | tj_max = tcc_default; |
b2b94be7 LB |
6065 | |
6066 | return 0; | |
889facbe | 6067 | |
b2b94be7 | 6068 | guess: |
55279aef | 6069 | tj_max = TJMAX_DEFAULT; |
1b439f01 | 6070 | fprintf(outf, "cpu%d: Guessing tjMax %d C, Please use -T to specify\n", cpu, tj_max); |
889facbe LB |
6071 | |
6072 | return 0; | |
6073 | } | |
69807a63 | 6074 | |
ce7a32c2 ZR |
6075 | int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p) |
6076 | { | |
6077 | unsigned long long msr; | |
6078 | unsigned int dts, dts2; | |
6079 | int cpu; | |
6080 | ||
6081 | UNUSED(c); | |
6082 | UNUSED(p); | |
6083 | ||
3e404846 PW |
6084 | if (no_msr) |
6085 | return 0; | |
6086 | ||
ce7a32c2 ZR |
6087 | if (!(do_dts || do_ptm)) |
6088 | return 0; | |
6089 | ||
6090 | cpu = t->cpu_id; | |
6091 | ||
6092 | /* DTS is per-core, no need to print for each thread */ | |
74318add | 6093 | if (!is_cpu_first_thread_in_core(t, c, p)) |
ce7a32c2 ZR |
6094 | return 0; |
6095 | ||
6096 | if (cpu_migrate(cpu)) { | |
6097 | fprintf(outf, "print_thermal: Could not migrate to CPU %d\n", cpu); | |
6098 | return -1; | |
6099 | } | |
6100 | ||
74318add | 6101 | if (do_ptm && is_cpu_first_core_in_package(t, c, p)) { |
ce7a32c2 ZR |
6102 | if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr)) |
6103 | return 0; | |
6104 | ||
6105 | dts = (msr >> 16) & 0x7F; | |
6106 | fprintf(outf, "cpu%d: MSR_IA32_PACKAGE_THERM_STATUS: 0x%08llx (%d C)\n", cpu, msr, tj_max - dts); | |
6107 | ||
6108 | if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &msr)) | |
6109 | return 0; | |
6110 | ||
6111 | dts = (msr >> 16) & 0x7F; | |
6112 | dts2 = (msr >> 8) & 0x7F; | |
6113 | fprintf(outf, "cpu%d: MSR_IA32_PACKAGE_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n", | |
6114 | cpu, msr, tj_max - dts, tj_max - dts2); | |
6115 | } | |
6116 | ||
6117 | if (do_dts && debug) { | |
6118 | unsigned int resolution; | |
6119 | ||
6120 | if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr)) | |
6121 | return 0; | |
6122 | ||
6123 | dts = (msr >> 16) & 0x7F; | |
6124 | resolution = (msr >> 27) & 0xF; | |
6125 | fprintf(outf, "cpu%d: MSR_IA32_THERM_STATUS: 0x%08llx (%d C +/- %d)\n", | |
6126 | cpu, msr, tj_max - dts, resolution); | |
6127 | ||
6128 | if (get_msr(cpu, MSR_IA32_THERM_INTERRUPT, &msr)) | |
6129 | return 0; | |
6130 | ||
6131 | dts = (msr >> 16) & 0x7F; | |
6132 | dts2 = (msr >> 8) & 0x7F; | |
6133 | fprintf(outf, "cpu%d: MSR_IA32_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n", | |
6134 | cpu, msr, tj_max - dts, tj_max - dts2); | |
6135 | } | |
6136 | ||
6137 | return 0; | |
6138 | } | |
6139 | ||
6140 | void probe_thermal(void) | |
6141 | { | |
6142 | if (!access("/sys/devices/system/cpu/cpu0/thermal_throttle/core_throttle_count", R_OK)) | |
6143 | BIC_PRESENT(BIC_CORE_THROT_CNT); | |
6144 | else | |
6145 | BIC_NOT_PRESENT(BIC_CORE_THROT_CNT); | |
5612b2c8 ZR |
6146 | |
6147 | for_all_cpus(set_temperature_target, ODD_COUNTERS); | |
6148 | ||
6149 | if (quiet) | |
6150 | return; | |
6151 | ||
6152 | for_all_cpus(print_thermal, ODD_COUNTERS); | |
ce7a32c2 ZR |
6153 | } |
6154 | ||
6155 | int get_cpu_type(struct thread_data *t, struct core_data *c, struct pkg_data *p) | |
6156 | { | |
6157 | unsigned int eax, ebx, ecx, edx; | |
6158 | ||
6159 | UNUSED(c); | |
6160 | UNUSED(p); | |
6161 | ||
6162 | if (!genuine_intel) | |
6163 | return 0; | |
6164 | ||
6165 | if (cpu_migrate(t->cpu_id)) { | |
6166 | fprintf(outf, "Could not migrate to CPU %d\n", t->cpu_id); | |
6167 | return -1; | |
6168 | } | |
6169 | ||
6170 | if (max_level < 0x1a) | |
6171 | return 0; | |
6172 | ||
6173 | __cpuid(0x1a, eax, ebx, ecx, edx); | |
6174 | eax = (eax >> 24) & 0xFF; | |
6175 | if (eax == 0x20) | |
6176 | t->is_atom = true; | |
6177 | return 0; | |
6178 | } | |
6179 | ||
aa8d8cc7 LB |
6180 | void decode_feature_control_msr(void) |
6181 | { | |
6182 | unsigned long long msr; | |
6183 | ||
3e404846 PW |
6184 | if (no_msr) |
6185 | return; | |
6186 | ||
f6505c88 | 6187 | if (!get_msr(base_cpu, MSR_IA32_FEAT_CTL, &msr)) |
aa8d8cc7 | 6188 | fprintf(outf, "cpu%d: MSR_IA32_FEATURE_CONTROL: 0x%08llx (%sLocked %s)\n", |
1b439f01 | 6189 | base_cpu, msr, msr & FEAT_CTL_LOCKED ? "" : "UN-", msr & (1 << 18) ? "SGX" : ""); |
aa8d8cc7 LB |
6190 | } |
6191 | ||
69807a63 LB |
6192 | void decode_misc_enable_msr(void) |
6193 | { | |
6194 | unsigned long long msr; | |
6195 | ||
3e404846 PW |
6196 | if (no_msr) |
6197 | return; | |
6198 | ||
f26b1519 LB |
6199 | if (!genuine_intel) |
6200 | return; | |
6201 | ||
69807a63 | 6202 | if (!get_msr(base_cpu, MSR_IA32_MISC_ENABLE, &msr)) |
e6512624 | 6203 | fprintf(outf, "cpu%d: MSR_IA32_MISC_ENABLE: 0x%08llx (%sTCC %sEIST %sMWAIT %sPREFETCH %sTURBO)\n", |
69807a63 | 6204 | base_cpu, msr, |
e6512624 LB |
6205 | msr & MSR_IA32_MISC_ENABLE_TM1 ? "" : "No-", |
6206 | msr & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP ? "" : "No-", | |
fd3933ca | 6207 | msr & MSR_IA32_MISC_ENABLE_MWAIT ? "" : "No-", |
e6512624 LB |
6208 | msr & MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE ? "No-" : "", |
6209 | msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE ? "No-" : ""); | |
69807a63 LB |
6210 | } |
6211 | ||
33148d67 LB |
6212 | void decode_misc_feature_control(void) |
6213 | { | |
6214 | unsigned long long msr; | |
6215 | ||
3e404846 PW |
6216 | if (no_msr) |
6217 | return; | |
6218 | ||
778fc34a | 6219 | if (!platform->has_msr_misc_feature_control) |
33148d67 LB |
6220 | return; |
6221 | ||
6222 | if (!get_msr(base_cpu, MSR_MISC_FEATURE_CONTROL, &msr)) | |
1b439f01 LB |
6223 | fprintf(outf, |
6224 | "cpu%d: MSR_MISC_FEATURE_CONTROL: 0x%08llx (%sL2-Prefetch %sL2-Prefetch-pair %sL1-Prefetch %sL1-IP-Prefetch)\n", | |
6225 | base_cpu, msr, msr & (0 << 0) ? "No-" : "", msr & (1 << 0) ? "No-" : "", | |
6226 | msr & (2 << 0) ? "No-" : "", msr & (3 << 0) ? "No-" : ""); | |
33148d67 | 6227 | } |
1b439f01 | 6228 | |
f0057310 LB |
6229 | /* |
6230 | * Decode MSR_MISC_PWR_MGMT | |
6231 | * | |
6232 | * Decode the bits according to the Nehalem documentation | |
6233 | * bit[0] seems to continue to have same meaning going forward | |
6234 | * bit[1] less so... | |
6235 | */ | |
6236 | void decode_misc_pwr_mgmt_msr(void) | |
6237 | { | |
6238 | unsigned long long msr; | |
6239 | ||
3e404846 PW |
6240 | if (no_msr) |
6241 | return; | |
6242 | ||
3dd0e754 | 6243 | if (!platform->has_msr_misc_pwr_mgmt) |
cf4cbe53 LB |
6244 | return; |
6245 | ||
f0057310 | 6246 | if (!get_msr(base_cpu, MSR_MISC_PWR_MGMT, &msr)) |
ddadb8ad | 6247 | fprintf(outf, "cpu%d: MSR_MISC_PWR_MGMT: 0x%08llx (%sable-EIST_Coordination %sable-EPB %sable-OOB)\n", |
f0057310 | 6248 | base_cpu, msr, |
1b439f01 | 6249 | msr & (1 << 0) ? "DIS" : "EN", msr & (1 << 1) ? "EN" : "DIS", msr & (1 << 8) ? "EN" : "DIS"); |
f0057310 | 6250 | } |
1b439f01 | 6251 | |
71616c8e LB |
6252 | /* |
6253 | * Decode MSR_CC6_DEMOTION_POLICY_CONFIG, MSR_MC6_DEMOTION_POLICY_CONFIG | |
6254 | * | |
6255 | * This MSRs are present on Silvermont processors, | |
6256 | * Intel Atom processor E3000 series (Baytrail), and friends. | |
6257 | */ | |
6258 | void decode_c6_demotion_policy_msr(void) | |
6259 | { | |
6260 | unsigned long long msr; | |
6261 | ||
3e404846 PW |
6262 | if (no_msr) |
6263 | return; | |
6264 | ||
6c36882e ZR |
6265 | if (!platform->has_msr_c6_demotion_policy_config) |
6266 | return; | |
6267 | ||
71616c8e LB |
6268 | if (!get_msr(base_cpu, MSR_CC6_DEMOTION_POLICY_CONFIG, &msr)) |
6269 | fprintf(outf, "cpu%d: MSR_CC6_DEMOTION_POLICY_CONFIG: 0x%08llx (%sable-CC6-Demotion)\n", | |
6270 | base_cpu, msr, msr & (1 << 0) ? "EN" : "DIS"); | |
6271 | ||
6272 | if (!get_msr(base_cpu, MSR_MC6_DEMOTION_POLICY_CONFIG, &msr)) | |
6273 | fprintf(outf, "cpu%d: MSR_MC6_DEMOTION_POLICY_CONFIG: 0x%08llx (%sable-MC6-Demotion)\n", | |
6274 | base_cpu, msr, msr & (1 << 0) ? "EN" : "DIS"); | |
6275 | } | |
7f5c258e | 6276 | |
d76bb7a0 LB |
6277 | void print_dev_latency(void) |
6278 | { | |
6279 | char *path = "/dev/cpu_dma_latency"; | |
6280 | int fd; | |
6281 | int value; | |
6282 | int retval; | |
6283 | ||
6284 | fd = open(path, O_RDONLY); | |
6285 | if (fd < 0) { | |
b6fe9383 LB |
6286 | if (debug) |
6287 | warnx("Read %s failed", path); | |
d76bb7a0 LB |
6288 | return; |
6289 | } | |
6290 | ||
6291 | retval = read(fd, (void *)&value, sizeof(int)); | |
6292 | if (retval != sizeof(int)) { | |
6cbfedc7 | 6293 | warn("read failed %s", path); |
d76bb7a0 LB |
6294 | close(fd); |
6295 | return; | |
6296 | } | |
1b439f01 | 6297 | fprintf(outf, "/dev/cpu_dma_latency: %d usec (%s)\n", value, value == 2000000000 ? "default" : "constrained"); |
d76bb7a0 LB |
6298 | |
6299 | close(fd); | |
6300 | } | |
6301 | ||
5088741e PW |
6302 | static int has_instr_count_access(void) |
6303 | { | |
6304 | int fd; | |
6305 | int has_access; | |
6306 | ||
6307 | if (no_perf) | |
6308 | return 0; | |
6309 | ||
6310 | fd = open_perf_counter(base_cpu, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS, -1, 0); | |
6311 | has_access = fd != -1; | |
6312 | ||
6313 | if (fd != -1) | |
6314 | close(fd); | |
6315 | ||
6316 | if (!has_access) | |
6317 | warnx("Failed to access %s. Some of the counters may not be available\n" | |
6318 | "\tRun as root to enable them or use %s to disable the access explicitly", | |
6319 | "instructions retired perf counter", "--no-perf"); | |
6320 | ||
6321 | return has_access; | |
6322 | } | |
6323 | ||
aed48c48 PW |
6324 | bool is_aperf_access_required(void) |
6325 | { | |
6326 | return BIC_IS_ENABLED(BIC_Avg_MHz) | |
6327 | || BIC_IS_ENABLED(BIC_Busy) | |
6328 | || BIC_IS_ENABLED(BIC_Bzy_MHz) | |
6329 | || BIC_IS_ENABLED(BIC_IPC); | |
6330 | } | |
6331 | ||
05a2f07d PW |
6332 | int add_rapl_perf_counter_(int cpu, struct rapl_counter_info_t *rci, const struct rapl_counter_arch_info *cai, |
6333 | double *scale_, enum rapl_unit *unit_) | |
6334 | { | |
6335 | if (no_perf) | |
6336 | return -1; | |
6337 | ||
6338 | const double scale = read_perf_rapl_scale(cai->perf_subsys, cai->perf_name); | |
6339 | if (scale == 0.0) | |
6340 | return -1; | |
6341 | ||
6342 | const enum rapl_unit unit = read_perf_rapl_unit(cai->perf_subsys, cai->perf_name); | |
6343 | if (unit == RAPL_UNIT_INVALID) | |
6344 | return -1; | |
6345 | ||
6346 | const unsigned rapl_type = read_perf_type(cai->perf_subsys); | |
6347 | const unsigned rapl_energy_pkg_config = read_rapl_config(cai->perf_subsys, cai->perf_name); | |
6348 | ||
6349 | const int fd_counter = | |
6350 | open_perf_counter(cpu, rapl_type, rapl_energy_pkg_config, rci->fd_perf, PERF_FORMAT_GROUP); | |
6351 | if (fd_counter == -1) | |
6352 | return -1; | |
6353 | ||
6354 | /* If it's the first counter opened, make it a group descriptor */ | |
6355 | if (rci->fd_perf == -1) | |
6356 | rci->fd_perf = fd_counter; | |
6357 | ||
6358 | *scale_ = scale; | |
6359 | *unit_ = unit; | |
6360 | return fd_counter; | |
6361 | } | |
6362 | ||
6363 | int add_rapl_perf_counter(int cpu, struct rapl_counter_info_t *rci, const struct rapl_counter_arch_info *cai, | |
6364 | double *scale, enum rapl_unit *unit) | |
6365 | { | |
6366 | int ret = add_rapl_perf_counter_(cpu, rci, cai, scale, unit); | |
6367 | ||
6368 | if (debug) | |
6369 | fprintf(stderr, "add_rapl_perf_counter: %d (cpu: %d)\n", ret, cpu); | |
6370 | ||
6371 | return ret; | |
6372 | } | |
6373 | ||
2af4f9b8 | 6374 | /* |
2db0e5eb | 6375 | * Linux-perf manages the HW instructions-retired counter |
2af4f9b8 LB |
6376 | * by enabling when requested, and hiding rollover |
6377 | */ | |
6378 | void linux_perf_init(void) | |
6379 | { | |
2af4f9b8 LB |
6380 | if (access("/proc/sys/kernel/perf_event_paranoid", F_OK)) |
6381 | return; | |
6382 | ||
e48934c9 PW |
6383 | if (BIC_IS_ENABLED(BIC_IPC) && has_aperf) { |
6384 | fd_instr_count_percpu = calloc(topo.max_cpu_num + 1, sizeof(int)); | |
6385 | if (fd_instr_count_percpu == NULL) | |
6386 | err(-1, "calloc fd_instr_count_percpu"); | |
6387 | } | |
6388 | ||
aed48c48 | 6389 | const bool aperf_required = is_aperf_access_required(); |
e48934c9 PW |
6390 | if (aperf_required && has_aperf && amperf_source == AMPERF_SOURCE_PERF) { |
6391 | fd_amperf_percpu = calloc(topo.max_cpu_num + 1, sizeof(*fd_amperf_percpu)); | |
6392 | if (fd_amperf_percpu == NULL) | |
6393 | err(-1, "calloc fd_amperf_percpu"); | |
6394 | } | |
6395 | } | |
6396 | ||
05a2f07d | 6397 | void rapl_perf_init(void) |
e48934c9 | 6398 | { |
05a2f07d PW |
6399 | const int num_domains = platform->has_per_core_rapl ? topo.num_cores : topo.num_packages; |
6400 | bool *domain_visited = calloc(num_domains, sizeof(bool)); | |
6401 | ||
6402 | rapl_counter_info_perdomain = calloc(num_domains, sizeof(*rapl_counter_info_perdomain)); | |
6403 | if (rapl_counter_info_perdomain == NULL) | |
6404 | err(-1, "calloc rapl_counter_info_percpu"); | |
e48934c9 | 6405 | |
05a2f07d PW |
6406 | /* |
6407 | * Initialize rapl_counter_info_percpu | |
6408 | */ | |
6409 | for (int domain_id = 0; domain_id < num_domains; ++domain_id) { | |
6410 | struct rapl_counter_info_t *rci = &rapl_counter_info_perdomain[domain_id]; | |
6411 | rci->fd_perf = -1; | |
6412 | for (size_t i = 0; i < NUM_RAPL_COUNTERS; ++i) { | |
6413 | rci->data[i] = 0; | |
6414 | rci->source[i] = RAPL_SOURCE_NONE; | |
6415 | } | |
6416 | } | |
6417 | ||
6418 | /* | |
6419 | * Open/probe the counters | |
6420 | * If can't get it via perf, fallback to MSR | |
6421 | */ | |
6422 | for (size_t i = 0; i < ARRAY_SIZE(rapl_counter_arch_infos); ++i) { | |
6423 | ||
6424 | const struct rapl_counter_arch_info *const cai = &rapl_counter_arch_infos[i]; | |
6425 | bool has_counter = 0; | |
6426 | double scale; | |
6427 | enum rapl_unit unit; | |
6428 | int next_domain; | |
6429 | ||
6430 | memset(domain_visited, 0, num_domains * sizeof(*domain_visited)); | |
6431 | ||
6432 | for (int cpu = 0; cpu < topo.max_cpu_num + 1; ++cpu) { | |
6433 | ||
6434 | if (cpu_is_not_allowed(cpu)) | |
6435 | continue; | |
6436 | ||
6437 | /* Skip already seen and handled RAPL domains */ | |
6438 | next_domain = | |
6439 | platform->has_per_core_rapl ? cpus[cpu].physical_core_id : cpus[cpu].physical_package_id; | |
6440 | ||
6441 | if (domain_visited[next_domain]) | |
6442 | continue; | |
6443 | ||
6444 | domain_visited[next_domain] = 1; | |
6445 | ||
6446 | struct rapl_counter_info_t *rci = &rapl_counter_info_perdomain[next_domain]; | |
6447 | ||
6448 | /* Check if the counter is enabled and accessible */ | |
6449 | if (BIC_IS_ENABLED(cai->bic) && (platform->rapl_msrs & cai->feature_mask)) { | |
6450 | ||
6451 | /* Use perf API for this counter */ | |
6452 | if (!no_perf && cai->perf_name | |
6453 | && add_rapl_perf_counter(cpu, rci, cai, &scale, &unit) != -1) { | |
6454 | rci->source[cai->rci_index] = RAPL_SOURCE_PERF; | |
6455 | rci->scale[cai->rci_index] = scale * cai->compat_scale; | |
6456 | rci->unit[cai->rci_index] = unit; | |
6457 | rci->flags[cai->rci_index] = cai->flags; | |
6458 | ||
6459 | /* Use MSR for this counter */ | |
6460 | } else if (!no_msr && cai->msr && probe_msr(cpu, cai->msr) == 0) { | |
6461 | rci->source[cai->rci_index] = RAPL_SOURCE_MSR; | |
6462 | rci->msr[cai->rci_index] = cai->msr; | |
6463 | rci->msr_mask[cai->rci_index] = cai->msr_mask; | |
6464 | rci->msr_shift[cai->rci_index] = cai->msr_shift; | |
6465 | rci->unit[cai->rci_index] = RAPL_UNIT_JOULES; | |
6466 | rci->scale[cai->rci_index] = *cai->platform_rapl_msr_scale * cai->compat_scale; | |
6467 | rci->flags[cai->rci_index] = cai->flags; | |
6468 | } | |
6469 | } | |
6470 | ||
6471 | if (rci->source[cai->rci_index] != RAPL_SOURCE_NONE) | |
6472 | has_counter = 1; | |
6473 | } | |
6474 | ||
6475 | /* If any CPU has access to the counter, make it present */ | |
6476 | if (has_counter) | |
6477 | BIC_PRESENT(cai->bic); | |
6478 | } | |
6479 | ||
6480 | free(domain_visited); | |
6481 | } | |
6482 | ||
6483 | static int has_amperf_access_via_msr(void) | |
6484 | { | |
5088741e PW |
6485 | if (no_msr) |
6486 | return 0; | |
6487 | ||
05a2f07d | 6488 | if (probe_msr(base_cpu, MSR_IA32_APERF)) |
e48934c9 PW |
6489 | return 0; |
6490 | ||
05a2f07d | 6491 | if (probe_msr(base_cpu, MSR_IA32_MPERF)) |
e48934c9 PW |
6492 | return 0; |
6493 | ||
6494 | return 1; | |
6495 | } | |
6496 | ||
6497 | static int has_amperf_access_via_perf(void) | |
6498 | { | |
5088741e | 6499 | struct amperf_group_fd fds; |
e48934c9 | 6500 | |
5088741e PW |
6501 | /* |
6502 | * Cache the last result, so we don't warn the user multiple times | |
6503 | * | |
6504 | * Negative means cached, no access | |
6505 | * Zero means not cached | |
6506 | * Positive means cached, has access | |
6507 | */ | |
6508 | static int has_access_cached; | |
e48934c9 | 6509 | |
5088741e | 6510 | if (no_perf) |
e48934c9 PW |
6511 | return 0; |
6512 | ||
5088741e PW |
6513 | if (has_access_cached != 0) |
6514 | return has_access_cached > 0; | |
6515 | ||
6516 | fds = open_amperf_fd(base_cpu); | |
6517 | has_access_cached = (fds.aperf != -1) && (fds.mperf != -1); | |
6518 | ||
6519 | if (fds.aperf == -1) | |
6520 | warnx("Failed to access %s. Some of the counters may not be available\n" | |
6521 | "\tRun as root to enable them or use %s to disable the access explicitly", | |
6522 | "APERF perf counter", "--no-perf"); | |
6523 | else | |
6524 | close(fds.aperf); | |
6525 | ||
6526 | if (fds.mperf == -1) | |
6527 | warnx("Failed to access %s. Some of the counters may not be available\n" | |
6528 | "\tRun as root to enable them or use %s to disable the access explicitly", | |
6529 | "MPERF perf counter", "--no-perf"); | |
6530 | else | |
6531 | close(fds.mperf); | |
6532 | ||
6533 | if (has_access_cached == 0) | |
6534 | has_access_cached = -1; | |
6535 | ||
6536 | return has_access_cached > 0; | |
e48934c9 PW |
6537 | } |
6538 | ||
6539 | /* Check if we can access APERF and MPERF */ | |
6540 | static int has_amperf_access(void) | |
6541 | { | |
aed48c48 PW |
6542 | if (!is_aperf_access_required()) |
6543 | return 0; | |
6544 | ||
e48934c9 PW |
6545 | if (!no_msr && has_amperf_access_via_msr()) |
6546 | return 1; | |
2af4f9b8 | 6547 | |
e48934c9 PW |
6548 | if (!no_perf && has_amperf_access_via_perf()) |
6549 | return 1; | |
6550 | ||
6551 | return 0; | |
2af4f9b8 LB |
6552 | } |
6553 | ||
3c6a17b8 ZR |
6554 | void probe_cstates(void) |
6555 | { | |
6556 | probe_cst_limit(); | |
6557 | ||
6558 | if (platform->supported_cstates & CC1) | |
6559 | BIC_PRESENT(BIC_CPU_c1); | |
6560 | ||
6561 | if (platform->supported_cstates & CC3) | |
6562 | BIC_PRESENT(BIC_CPU_c3); | |
6563 | ||
6564 | if (platform->supported_cstates & CC6) | |
6565 | BIC_PRESENT(BIC_CPU_c6); | |
6566 | ||
6567 | if (platform->supported_cstates & CC7) | |
6568 | BIC_PRESENT(BIC_CPU_c7); | |
6569 | ||
6570 | if (platform->supported_cstates & PC2 && (pkg_cstate_limit >= PCL__2)) | |
6571 | BIC_PRESENT(BIC_Pkgpc2); | |
6572 | ||
6573 | if (platform->supported_cstates & PC3 && (pkg_cstate_limit >= PCL__3)) | |
6574 | BIC_PRESENT(BIC_Pkgpc3); | |
6575 | ||
6576 | if (platform->supported_cstates & PC6 && (pkg_cstate_limit >= PCL__6)) | |
6577 | BIC_PRESENT(BIC_Pkgpc6); | |
6578 | ||
6579 | if (platform->supported_cstates & PC7 && (pkg_cstate_limit >= PCL__7)) | |
6580 | BIC_PRESENT(BIC_Pkgpc7); | |
6581 | ||
6582 | if (platform->supported_cstates & PC8 && (pkg_cstate_limit >= PCL__8)) | |
6583 | BIC_PRESENT(BIC_Pkgpc8); | |
6584 | ||
6585 | if (platform->supported_cstates & PC9 && (pkg_cstate_limit >= PCL__9)) | |
6586 | BIC_PRESENT(BIC_Pkgpc9); | |
6587 | ||
6588 | if (platform->supported_cstates & PC10 && (pkg_cstate_limit >= PCL_10)) | |
6589 | BIC_PRESENT(BIC_Pkgpc10); | |
045acf60 ZR |
6590 | |
6591 | if (platform->has_msr_module_c6_res_ms) | |
6592 | BIC_PRESENT(BIC_Mod_c6); | |
6593 | ||
3e404846 | 6594 | if (platform->has_ext_cst_msrs && !no_msr) { |
045acf60 ZR |
6595 | BIC_PRESENT(BIC_Totl_c0); |
6596 | BIC_PRESENT(BIC_Any_c0); | |
6597 | BIC_PRESENT(BIC_GFX_c0); | |
6598 | BIC_PRESENT(BIC_CPUGFX); | |
6599 | } | |
6600 | ||
6601 | if (quiet) | |
6602 | return; | |
6603 | ||
6604 | dump_power_ctl(); | |
6605 | dump_cst_cfg(); | |
6606 | decode_c6_demotion_policy_msr(); | |
6607 | print_dev_latency(); | |
6608 | dump_sysfs_cstate_config(); | |
5612b2c8 | 6609 | print_irtl(); |
3c6a17b8 ZR |
6610 | } |
6611 | ||
e7d7b82d ZR |
6612 | void probe_lpi(void) |
6613 | { | |
6614 | if (!access("/sys/devices/system/cpu/cpuidle/low_power_idle_cpu_residency_us", R_OK)) | |
6615 | BIC_PRESENT(BIC_CPU_LPI); | |
6616 | else | |
6617 | BIC_NOT_PRESENT(BIC_CPU_LPI); | |
6618 | ||
6619 | if (!access(sys_lpi_file_sysfs, R_OK)) { | |
6620 | sys_lpi_file = sys_lpi_file_sysfs; | |
6621 | BIC_PRESENT(BIC_SYS_LPI); | |
6622 | } else if (!access(sys_lpi_file_debugfs, R_OK)) { | |
6623 | sys_lpi_file = sys_lpi_file_debugfs; | |
6624 | BIC_PRESENT(BIC_SYS_LPI); | |
6625 | } else { | |
6626 | sys_lpi_file_sysfs = NULL; | |
6627 | BIC_NOT_PRESENT(BIC_SYS_LPI); | |
6628 | } | |
6629 | ||
6630 | } | |
6631 | ||
11cd9a09 ZR |
6632 | void probe_pstates(void) |
6633 | { | |
6634 | probe_bclk(); | |
6635 | ||
6636 | if (quiet) | |
6637 | return; | |
6638 | ||
6639 | dump_platform_info(); | |
6640 | dump_turbo_ratio_info(); | |
6641 | dump_sysfs_pstate_config(); | |
6642 | decode_misc_pwr_mgmt_msr(); | |
5612b2c8 ZR |
6643 | |
6644 | for_all_cpus(print_hwp, ODD_COUNTERS); | |
6645 | for_all_cpus(print_epb, ODD_COUNTERS); | |
6646 | for_all_cpus(print_perf_limit, ODD_COUNTERS); | |
11cd9a09 ZR |
6647 | } |
6648 | ||
fcd17211 | 6649 | void process_cpuid() |
103a8fea | 6650 | { |
34041551 LB |
6651 | unsigned int eax, ebx, ecx, edx; |
6652 | unsigned int fms, family, model, stepping, ecx_flags, edx_flags; | |
ed0757b8 | 6653 | unsigned long long ucode_patch = 0; |
fb5ceca0 | 6654 | bool ucode_patch_valid = false; |
103a8fea LB |
6655 | |
6656 | eax = ebx = ecx = edx = 0; | |
6657 | ||
5aea2f7f | 6658 | __cpuid(0, max_level, ebx, ecx, edx); |
103a8fea | 6659 | |
34041551 | 6660 | if (ebx == 0x756e6547 && ecx == 0x6c65746e && edx == 0x49656e69) |
103a8fea | 6661 | genuine_intel = 1; |
34041551 LB |
6662 | else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65) |
6663 | authentic_amd = 1; | |
c1c10cc7 PW |
6664 | else if (ebx == 0x6f677948 && ecx == 0x656e6975 && edx == 0x6e65476e) |
6665 | hygon_genuine = 1; | |
103a8fea | 6666 | |
96e47158 | 6667 | if (!quiet) |
ed0757b8 LB |
6668 | fprintf(outf, "CPUID(0): %.4s%.4s%.4s 0x%x CPUID levels\n", |
6669 | (char *)&ebx, (char *)&edx, (char *)&ecx, max_level); | |
103a8fea | 6670 | |
5aea2f7f | 6671 | __cpuid(1, fms, ebx, ecx, edx); |
103a8fea LB |
6672 | family = (fms >> 8) & 0xf; |
6673 | model = (fms >> 4) & 0xf; | |
6674 | stepping = fms & 0xf; | |
5aa3d1a2 CW |
6675 | if (family == 0xf) |
6676 | family += (fms >> 20) & 0xff; | |
6677 | if (family >= 6) | |
103a8fea | 6678 | model += ((fms >> 16) & 0xf) << 4; |
34041551 LB |
6679 | ecx_flags = ecx; |
6680 | edx_flags = edx; | |
103a8fea | 6681 | |
3e404846 PW |
6682 | if (!no_msr) { |
6683 | if (get_msr(sched_getcpu(), MSR_IA32_UCODE_REV, &ucode_patch)) | |
6684 | warnx("get_msr(UCODE)"); | |
6685 | else | |
6686 | ucode_patch_valid = true; | |
6687 | } | |
ed0757b8 | 6688 | |
103a8fea LB |
6689 | /* |
6690 | * check max extended function levels of CPUID. | |
6691 | * This is needed to check for invariant TSC. | |
6692 | * This check is valid for both Intel and AMD. | |
6693 | */ | |
6694 | ebx = ecx = edx = 0; | |
5aea2f7f | 6695 | __cpuid(0x80000000, max_extended_level, ebx, ecx, edx); |
103a8fea | 6696 | |
34041551 | 6697 | if (!quiet) { |
fb5ceca0 PW |
6698 | fprintf(outf, "CPUID(1): family:model:stepping 0x%x:%x:%x (%d:%d:%d)", |
6699 | family, model, stepping, family, model, stepping); | |
6700 | if (ucode_patch_valid) | |
6701 | fprintf(outf, " microcode 0x%x", (unsigned int)((ucode_patch >> 32) & 0xFFFFFFFF)); | |
6702 | fputc('\n', outf); | |
6703 | ||
ed0757b8 | 6704 | fprintf(outf, "CPUID(0x80000000): max_extended_levels: 0x%x\n", max_extended_level); |
34041551 LB |
6705 | fprintf(outf, "CPUID(1): %s %s %s %s %s %s %s %s %s %s\n", |
6706 | ecx_flags & (1 << 0) ? "SSE3" : "-", | |
6707 | ecx_flags & (1 << 3) ? "MONITOR" : "-", | |
6708 | ecx_flags & (1 << 6) ? "SMX" : "-", | |
6709 | ecx_flags & (1 << 7) ? "EIST" : "-", | |
6710 | ecx_flags & (1 << 8) ? "TM2" : "-", | |
6711 | edx_flags & (1 << 4) ? "TSC" : "-", | |
6712 | edx_flags & (1 << 5) ? "MSR" : "-", | |
6713 | edx_flags & (1 << 22) ? "ACPI-TM" : "-", | |
1b439f01 | 6714 | edx_flags & (1 << 28) ? "HT" : "-", edx_flags & (1 << 29) ? "TM" : "-"); |
34041551 | 6715 | } |
b98a6d78 | 6716 | |
45232ab1 | 6717 | probe_platform_features(family, model); |
34041551 LB |
6718 | |
6719 | if (!(edx_flags & (1 << 5))) | |
6720 | errx(1, "CPUID: no MSR"); | |
6721 | ||
61a87ba7 | 6722 | if (max_extended_level >= 0x80000007) { |
103a8fea | 6723 | |
d7899447 LB |
6724 | /* |
6725 | * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8 | |
6726 | * this check is valid for both Intel and AMD | |
6727 | */ | |
5aea2f7f | 6728 | __cpuid(0x80000007, eax, ebx, ecx, edx); |
d7899447 LB |
6729 | has_invariant_tsc = edx & (1 << 8); |
6730 | } | |
103a8fea LB |
6731 | |
6732 | /* | |
6733 | * APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0 | |
6734 | * this check is valid for both Intel and AMD | |
6735 | */ | |
6736 | ||
5aea2f7f | 6737 | __cpuid(0x6, eax, ebx, ecx, edx); |
8209e054 | 6738 | has_aperf = ecx & (1 << 0); |
e48934c9 | 6739 | if (has_aperf && has_amperf_access()) { |
812db3f7 LB |
6740 | BIC_PRESENT(BIC_Avg_MHz); |
6741 | BIC_PRESENT(BIC_Busy); | |
6742 | BIC_PRESENT(BIC_Bzy_MHz); | |
e48934c9 | 6743 | BIC_PRESENT(BIC_IPC); |
812db3f7 | 6744 | } |
889facbe | 6745 | do_dts = eax & (1 << 0); |
812db3f7 LB |
6746 | if (do_dts) |
6747 | BIC_PRESENT(BIC_CoreTmp); | |
b3a34e93 | 6748 | has_turbo = eax & (1 << 1); |
889facbe | 6749 | do_ptm = eax & (1 << 6); |
812db3f7 LB |
6750 | if (do_ptm) |
6751 | BIC_PRESENT(BIC_PkgTmp); | |
7f5c258e LB |
6752 | has_hwp = eax & (1 << 7); |
6753 | has_hwp_notify = eax & (1 << 8); | |
6754 | has_hwp_activity_window = eax & (1 << 9); | |
6755 | has_hwp_epp = eax & (1 << 10); | |
6756 | has_hwp_pkg = eax & (1 << 11); | |
889facbe LB |
6757 | has_epb = ecx & (1 << 3); |
6758 | ||
96e47158 | 6759 | if (!quiet) |
b3a34e93 | 6760 | fprintf(outf, "CPUID(6): %sAPERF, %sTURBO, %sDTS, %sPTM, %sHWP, " |
7f5c258e LB |
6761 | "%sHWPnotify, %sHWPwindow, %sHWPepp, %sHWPpkg, %sEPB\n", |
6762 | has_aperf ? "" : "No-", | |
b3a34e93 | 6763 | has_turbo ? "" : "No-", |
7f5c258e LB |
6764 | do_dts ? "" : "No-", |
6765 | do_ptm ? "" : "No-", | |
6766 | has_hwp ? "" : "No-", | |
6767 | has_hwp_notify ? "" : "No-", | |
6768 | has_hwp_activity_window ? "" : "No-", | |
1b439f01 | 6769 | has_hwp_epp ? "" : "No-", has_hwp_pkg ? "" : "No-", has_epb ? "" : "No-"); |
103a8fea | 6770 | |
96e47158 | 6771 | if (!quiet) |
69807a63 LB |
6772 | decode_misc_enable_msr(); |
6773 | ||
96e47158 | 6774 | if (max_level >= 0x7 && !quiet) { |
aa8d8cc7 | 6775 | int has_sgx; |
103a8fea | 6776 | |
aa8d8cc7 LB |
6777 | ecx = 0; |
6778 | ||
6779 | __cpuid_count(0x7, 0, eax, ebx, ecx, edx); | |
6780 | ||
6781 | has_sgx = ebx & (1 << 2); | |
774627c5 LB |
6782 | |
6783 | is_hybrid = edx & (1 << 15); | |
6784 | ||
6785 | fprintf(outf, "CPUID(7): %sSGX %sHybrid\n", has_sgx ? "" : "No-", is_hybrid ? "" : "No-"); | |
aa8d8cc7 LB |
6786 | |
6787 | if (has_sgx) | |
6788 | decode_feature_control_msr(); | |
6789 | } | |
6790 | ||
61a87ba7 | 6791 | if (max_level >= 0x15) { |
8a5bdf41 LB |
6792 | unsigned int eax_crystal; |
6793 | unsigned int ebx_tsc; | |
6794 | ||
6795 | /* | |
6796 | * CPUID 15H TSC/Crystal ratio, possibly Crystal Hz | |
6797 | */ | |
6798 | eax_crystal = ebx_tsc = crystal_hz = edx = 0; | |
5aea2f7f | 6799 | __cpuid(0x15, eax_crystal, ebx_tsc, crystal_hz, edx); |
8a5bdf41 LB |
6800 | |
6801 | if (ebx_tsc != 0) { | |
96e47158 | 6802 | if (!quiet && (ebx != 0)) |
b7d8c148 | 6803 | fprintf(outf, "CPUID(0x15): eax_crystal: %d ebx_tsc: %d ecx_crystal_hz: %d\n", |
8a5bdf41 LB |
6804 | eax_crystal, ebx_tsc, crystal_hz); |
6805 | ||
6806 | if (crystal_hz == 0) | |
a5d1ab93 | 6807 | crystal_hz = platform->crystal_freq; |
8a5bdf41 LB |
6808 | |
6809 | if (crystal_hz) { | |
1b439f01 | 6810 | tsc_hz = (unsigned long long)crystal_hz *ebx_tsc / eax_crystal; |
96e47158 | 6811 | if (!quiet) |
b7d8c148 | 6812 | fprintf(outf, "TSC: %lld MHz (%d Hz * %d / %d / 1000000)\n", |
1b439f01 | 6813 | tsc_hz / 1000000, crystal_hz, ebx_tsc, eax_crystal); |
8a5bdf41 LB |
6814 | } |
6815 | } | |
6816 | } | |
61a87ba7 LB |
6817 | if (max_level >= 0x16) { |
6818 | unsigned int base_mhz, max_mhz, bus_mhz, edx; | |
6819 | ||
6820 | /* | |
6821 | * CPUID 16H Base MHz, Max MHz, Bus MHz | |
6822 | */ | |
6823 | base_mhz = max_mhz = bus_mhz = edx = 0; | |
6824 | ||
5aea2f7f | 6825 | __cpuid(0x16, base_mhz, max_mhz, bus_mhz, edx); |
538d505f PW |
6826 | |
6827 | bclk = bus_mhz; | |
6828 | ||
6829 | base_hz = base_mhz * 1000000; | |
6830 | has_base_hz = 1; | |
6831 | ||
6832 | if (platform->enable_tsc_tweak) | |
6833 | tsc_tweak = base_hz / tsc_hz; | |
6834 | ||
96e47158 | 6835 | if (!quiet) |
b7d8c148 | 6836 | fprintf(outf, "CPUID(0x16): base_mhz: %d max_mhz: %d bus_mhz: %d\n", |
61a87ba7 LB |
6837 | base_mhz, max_mhz, bus_mhz); |
6838 | } | |
8a5bdf41 | 6839 | |
b2b34dfe | 6840 | if (has_aperf) |
ed43247b | 6841 | aperf_mperf_multiplier = platform->need_perf_multiplier ? 1024 : 1; |
b2b34dfe | 6842 | |
812db3f7 LB |
6843 | BIC_PRESENT(BIC_IRQ); |
6844 | BIC_PRESENT(BIC_TSC_MHz); | |
7ee39d8d | 6845 | } |
812db3f7 | 6846 | |
7ee39d8d ZR |
6847 | void probe_pm_features(void) |
6848 | { | |
11cd9a09 ZR |
6849 | probe_pstates(); |
6850 | ||
3c6a17b8 ZR |
6851 | probe_cstates(); |
6852 | ||
e7d7b82d ZR |
6853 | probe_lpi(); |
6854 | ||
622c8f23 ZR |
6855 | probe_intel_uncore_frequency(); |
6856 | ||
2538d167 ZR |
6857 | probe_graphics(); |
6858 | ||
6cb13609 ZR |
6859 | probe_rapl(); |
6860 | ||
db735f8b ZR |
6861 | probe_thermal(); |
6862 | ||
3e404846 | 6863 | if (platform->has_nhm_msrs && !no_msr) |
812db3f7 | 6864 | BIC_PRESENT(BIC_SMI); |
f0057310 | 6865 | |
96e47158 | 6866 | if (!quiet) |
33148d67 | 6867 | decode_misc_feature_control(); |
103a8fea LB |
6868 | } |
6869 | ||
103a8fea LB |
6870 | /* |
6871 | * in /dev/cpu/ return success for names that are numbers | |
6872 | * ie. filter out ".", "..", "microcode". | |
6873 | */ | |
6874 | int dir_filter(const struct dirent *dirp) | |
6875 | { | |
6876 | if (isdigit(dirp->d_name[0])) | |
6877 | return 1; | |
6878 | else | |
6879 | return 0; | |
6880 | } | |
6881 | ||
c25ef0e5 | 6882 | void topology_probe(bool startup) |
c98d5d94 LB |
6883 | { |
6884 | int i; | |
6885 | int max_core_id = 0; | |
6886 | int max_package_id = 0; | |
6de68fe1 | 6887 | int max_die_id = 0; |
c98d5d94 | 6888 | int max_siblings = 0; |
c98d5d94 LB |
6889 | |
6890 | /* Initialize num_cpus, max_cpu_num */ | |
843c5791 | 6891 | set_max_cpu_num(); |
c98d5d94 | 6892 | topo.num_cpus = 0; |
c98d5d94 LB |
6893 | for_all_proc_cpus(count_cpus); |
6894 | if (!summary_only && topo.num_cpus > 1) | |
812db3f7 | 6895 | BIC_PRESENT(BIC_CPU); |
c98d5d94 | 6896 | |
d8af6f5f | 6897 | if (debug > 1) |
b7d8c148 | 6898 | fprintf(outf, "num_cpus %d max_cpu_num %d\n", topo.num_cpus, topo.max_cpu_num); |
c98d5d94 | 6899 | |
1b439f01 | 6900 | cpus = calloc(1, (topo.max_cpu_num + 1) * sizeof(struct cpu_topology)); |
b2c95d90 JT |
6901 | if (cpus == NULL) |
6902 | err(1, "calloc cpus"); | |
c98d5d94 LB |
6903 | |
6904 | /* | |
6905 | * Allocate and initialize cpu_present_set | |
6906 | */ | |
6907 | cpu_present_set = CPU_ALLOC((topo.max_cpu_num + 1)); | |
b2c95d90 JT |
6908 | if (cpu_present_set == NULL) |
6909 | err(3, "CPU_ALLOC"); | |
c98d5d94 LB |
6910 | cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); |
6911 | CPU_ZERO_S(cpu_present_setsize, cpu_present_set); | |
6912 | for_all_proc_cpus(mark_cpu_present); | |
6913 | ||
f638858d ZR |
6914 | /* |
6915 | * Allocate and initialize cpu_effective_set | |
6916 | */ | |
6917 | cpu_effective_set = CPU_ALLOC((topo.max_cpu_num + 1)); | |
6918 | if (cpu_effective_set == NULL) | |
6919 | err(3, "CPU_ALLOC"); | |
6920 | cpu_effective_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); | |
6921 | CPU_ZERO_S(cpu_effective_setsize, cpu_effective_set); | |
6922 | update_effective_set(startup); | |
6923 | ||
71cfd1da ZR |
6924 | /* |
6925 | * Allocate and initialize cpu_allowed_set | |
6926 | */ | |
6927 | cpu_allowed_set = CPU_ALLOC((topo.max_cpu_num + 1)); | |
6928 | if (cpu_allowed_set == NULL) | |
6929 | err(3, "CPU_ALLOC"); | |
6930 | cpu_allowed_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); | |
6931 | CPU_ZERO_S(cpu_allowed_setsize, cpu_allowed_set); | |
6932 | ||
1ef7d21a | 6933 | /* |
f638858d | 6934 | * Validate and update cpu_allowed_set. |
c25ef0e5 | 6935 | * |
f638858d ZR |
6936 | * Make sure all cpus in cpu_subset are also in cpu_present_set during startup. |
6937 | * Give a warning when cpus in cpu_subset become unavailable at runtime. | |
6938 | * Give a warning when cpus are not effective because of cgroup setting. | |
c25ef0e5 | 6939 | * |
f638858d | 6940 | * cpu_allowed_set is the intersection of cpu_present_set/cpu_effective_set/cpu_subset. |
1ef7d21a LB |
6941 | */ |
6942 | for (i = 0; i < CPU_SUBSET_MAXCPUS; ++i) { | |
f638858d | 6943 | if (cpu_subset && !CPU_ISSET_S(i, cpu_subset_size, cpu_subset)) |
71cfd1da | 6944 | continue; |
f638858d ZR |
6945 | |
6946 | if (!CPU_ISSET_S(i, cpu_present_setsize, cpu_present_set)) { | |
6947 | if (cpu_subset) { | |
6948 | /* cpus in cpu_subset must be in cpu_present_set during startup */ | |
c25ef0e5 ZR |
6949 | if (startup) |
6950 | err(1, "cpu%d not present", i); | |
6951 | else | |
6952 | fprintf(stderr, "cpu%d not present\n", i); | |
c25ef0e5 | 6953 | } |
f638858d | 6954 | continue; |
71cfd1da | 6955 | } |
f638858d ZR |
6956 | |
6957 | if (CPU_COUNT_S(cpu_effective_setsize, cpu_effective_set)) { | |
6958 | if (!CPU_ISSET_S(i, cpu_effective_setsize, cpu_effective_set)) { | |
6959 | fprintf(stderr, "cpu%d not effective\n", i); | |
6960 | continue; | |
6961 | } | |
6962 | } | |
6963 | ||
6964 | CPU_SET_S(i, cpu_allowed_setsize, cpu_allowed_set); | |
1ef7d21a LB |
6965 | } |
6966 | ||
7bb3fe27 ZR |
6967 | if (!CPU_COUNT_S(cpu_allowed_setsize, cpu_allowed_set)) |
6968 | err(-ENODEV, "No valid cpus found"); | |
6969 | sched_setaffinity(0, cpu_allowed_setsize, cpu_allowed_set); | |
6970 | ||
c98d5d94 LB |
6971 | /* |
6972 | * Allocate and initialize cpu_affinity_set | |
6973 | */ | |
6974 | cpu_affinity_set = CPU_ALLOC((topo.max_cpu_num + 1)); | |
b2c95d90 JT |
6975 | if (cpu_affinity_set == NULL) |
6976 | err(3, "CPU_ALLOC"); | |
c98d5d94 LB |
6977 | cpu_affinity_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); |
6978 | CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set); | |
6979 | ||
8cb48b32 | 6980 | for_all_proc_cpus(init_thread_id); |
c98d5d94 LB |
6981 | |
6982 | /* | |
6983 | * For online cpus | |
6984 | * find max_core_id, max_package_id | |
6985 | */ | |
6986 | for (i = 0; i <= topo.max_cpu_num; ++i) { | |
6987 | int siblings; | |
6988 | ||
6989 | if (cpu_is_not_present(i)) { | |
d8af6f5f | 6990 | if (debug > 1) |
b7d8c148 | 6991 | fprintf(outf, "cpu%d NOT PRESENT\n", i); |
c98d5d94 LB |
6992 | continue; |
6993 | } | |
c98d5d94 | 6994 | |
0e2d8f05 LB |
6995 | cpus[i].logical_cpu_id = i; |
6996 | ||
6997 | /* get package information */ | |
c98d5d94 LB |
6998 | cpus[i].physical_package_id = get_physical_package_id(i); |
6999 | if (cpus[i].physical_package_id > max_package_id) | |
7000 | max_package_id = cpus[i].physical_package_id; | |
7001 | ||
6de68fe1 LB |
7002 | /* get die information */ |
7003 | cpus[i].die_id = get_die_id(i); | |
7004 | if (cpus[i].die_id > max_die_id) | |
7005 | max_die_id = cpus[i].die_id; | |
7006 | ||
0e2d8f05 | 7007 | /* get numa node information */ |
ef605741 PB |
7008 | cpus[i].physical_node_id = get_physical_node_id(&cpus[i]); |
7009 | if (cpus[i].physical_node_id > topo.max_node_num) | |
7010 | topo.max_node_num = cpus[i].physical_node_id; | |
0e2d8f05 LB |
7011 | |
7012 | /* get core information */ | |
7013 | cpus[i].physical_core_id = get_core_id(i); | |
7014 | if (cpus[i].physical_core_id > max_core_id) | |
7015 | max_core_id = cpus[i].physical_core_id; | |
7016 | ||
7017 | /* get thread information */ | |
7018 | siblings = get_thread_siblings(&cpus[i]); | |
c98d5d94 LB |
7019 | if (siblings > max_siblings) |
7020 | max_siblings = siblings; | |
4f206a0f | 7021 | if (cpus[i].thread_id == 0) |
8cb48b32 | 7022 | topo.num_cores++; |
c98d5d94 | 7023 | } |
ef605741 | 7024 | |
70a9c6e8 | 7025 | topo.cores_per_node = max_core_id + 1; |
d8af6f5f | 7026 | if (debug > 1) |
1b439f01 | 7027 | fprintf(outf, "max_core_id %d, sizing for %d cores per package\n", max_core_id, topo.cores_per_node); |
70a9c6e8 | 7028 | if (!summary_only && topo.cores_per_node > 1) |
812db3f7 | 7029 | BIC_PRESENT(BIC_Core); |
c98d5d94 | 7030 | |
6de68fe1 LB |
7031 | topo.num_die = max_die_id + 1; |
7032 | if (debug > 1) | |
1b439f01 | 7033 | fprintf(outf, "max_die_id %d, sizing for %d die\n", max_die_id, topo.num_die); |
6de68fe1 LB |
7034 | if (!summary_only && topo.num_die > 1) |
7035 | BIC_PRESENT(BIC_Die); | |
7036 | ||
c98d5d94 | 7037 | topo.num_packages = max_package_id + 1; |
d8af6f5f | 7038 | if (debug > 1) |
1b439f01 | 7039 | fprintf(outf, "max_package_id %d, sizing for %d packages\n", max_package_id, topo.num_packages); |
7da6e3e2 | 7040 | if (!summary_only && topo.num_packages > 1) |
812db3f7 | 7041 | BIC_PRESENT(BIC_Package); |
c98d5d94 | 7042 | |
ef605741 PB |
7043 | set_node_data(); |
7044 | if (debug > 1) | |
70a9c6e8 | 7045 | fprintf(outf, "nodes_per_pkg %d\n", topo.nodes_per_pkg); |
01235041 PB |
7046 | if (!summary_only && topo.nodes_per_pkg > 1) |
7047 | BIC_PRESENT(BIC_Node); | |
ef605741 | 7048 | |
70a9c6e8 | 7049 | topo.threads_per_core = max_siblings; |
d8af6f5f | 7050 | if (debug > 1) |
b7d8c148 | 7051 | fprintf(outf, "max_siblings %d\n", max_siblings); |
2ffbb224 PB |
7052 | |
7053 | if (debug < 1) | |
7054 | return; | |
7055 | ||
7056 | for (i = 0; i <= topo.max_cpu_num; ++i) { | |
0ec712e3 LB |
7057 | if (cpu_is_not_present(i)) |
7058 | continue; | |
2ffbb224 | 7059 | fprintf(outf, |
6de68fe1 LB |
7060 | "cpu %d pkg %d die %d node %d lnode %d core %d thread %d\n", |
7061 | i, cpus[i].physical_package_id, cpus[i].die_id, | |
1b439f01 | 7062 | cpus[i].physical_node_id, cpus[i].logical_node_id, cpus[i].physical_core_id, cpus[i].thread_id); |
2ffbb224 PB |
7063 | } |
7064 | ||
c98d5d94 LB |
7065 | } |
7066 | ||
1b439f01 | 7067 | void allocate_counters(struct thread_data **t, struct core_data **c, struct pkg_data **p) |
c98d5d94 LB |
7068 | { |
7069 | int i; | |
1b439f01 | 7070 | int num_cores = topo.cores_per_node * topo.nodes_per_pkg * topo.num_packages; |
40f5cfe7 | 7071 | int num_threads = topo.threads_per_core * num_cores; |
c98d5d94 | 7072 | |
40f5cfe7 | 7073 | *t = calloc(num_threads, sizeof(struct thread_data)); |
c98d5d94 LB |
7074 | if (*t == NULL) |
7075 | goto error; | |
7076 | ||
40f5cfe7 | 7077 | for (i = 0; i < num_threads; i++) |
c98d5d94 LB |
7078 | (*t)[i].cpu_id = -1; |
7079 | ||
40f5cfe7 | 7080 | *c = calloc(num_cores, sizeof(struct core_data)); |
c98d5d94 LB |
7081 | if (*c == NULL) |
7082 | goto error; | |
7083 | ||
ccf8a052 | 7084 | for (i = 0; i < num_cores; i++) { |
c98d5d94 | 7085 | (*c)[i].core_id = -1; |
ccf8a052 ZR |
7086 | (*c)[i].base_cpu = -1; |
7087 | } | |
c98d5d94 | 7088 | |
678a3bd1 | 7089 | *p = calloc(topo.num_packages, sizeof(struct pkg_data)); |
c98d5d94 LB |
7090 | if (*p == NULL) |
7091 | goto error; | |
7092 | ||
ccf8a052 | 7093 | for (i = 0; i < topo.num_packages; i++) { |
c98d5d94 | 7094 | (*p)[i].package_id = i; |
ccf8a052 ZR |
7095 | (*p)[i].base_cpu = -1; |
7096 | } | |
c98d5d94 LB |
7097 | |
7098 | return; | |
7099 | error: | |
b2c95d90 | 7100 | err(1, "calloc counters"); |
c98d5d94 | 7101 | } |
1b439f01 | 7102 | |
c98d5d94 LB |
7103 | /* |
7104 | * init_counter() | |
7105 | * | |
c98d5d94 | 7106 | * set FIRST_THREAD_IN_CORE and FIRST_CORE_IN_PACKAGE |
c98d5d94 | 7107 | */ |
1b439f01 | 7108 | void init_counter(struct thread_data *thread_base, struct core_data *core_base, struct pkg_data *pkg_base, int cpu_id) |
c98d5d94 | 7109 | { |
8cb48b32 | 7110 | int pkg_id = cpus[cpu_id].physical_package_id; |
40f5cfe7 | 7111 | int node_id = cpus[cpu_id].logical_node_id; |
8cb48b32 PB |
7112 | int core_id = cpus[cpu_id].physical_core_id; |
7113 | int thread_id = cpus[cpu_id].thread_id; | |
c98d5d94 LB |
7114 | struct thread_data *t; |
7115 | struct core_data *c; | |
7116 | struct pkg_data *p; | |
7117 | ||
42dd4520 NC |
7118 | /* Workaround for systems where physical_node_id==-1 |
7119 | * and logical_node_id==(-1 - topo.num_cpus) | |
7120 | */ | |
7121 | if (node_id < 0) | |
7122 | node_id = 0; | |
7123 | ||
40f5cfe7 PB |
7124 | t = GET_THREAD(thread_base, thread_id, core_id, node_id, pkg_id); |
7125 | c = GET_CORE(core_base, core_id, node_id, pkg_id); | |
8cb48b32 | 7126 | p = GET_PKG(pkg_base, pkg_id); |
c98d5d94 LB |
7127 | |
7128 | t->cpu_id = cpu_id; | |
ccf8a052 ZR |
7129 | if (!cpu_is_not_allowed(cpu_id)) { |
7130 | if (c->base_cpu < 0) | |
7131 | c->base_cpu = t->cpu_id; | |
7132 | if (p->base_cpu < 0) | |
7133 | p->base_cpu = t->cpu_id; | |
c98d5d94 LB |
7134 | } |
7135 | ||
8cb48b32 PB |
7136 | c->core_id = core_id; |
7137 | p->package_id = pkg_id; | |
c98d5d94 LB |
7138 | } |
7139 | ||
c98d5d94 LB |
7140 | int initialize_counters(int cpu_id) |
7141 | { | |
8cb48b32 PB |
7142 | init_counter(EVEN_COUNTERS, cpu_id); |
7143 | init_counter(ODD_COUNTERS, cpu_id); | |
c98d5d94 LB |
7144 | return 0; |
7145 | } | |
7146 | ||
7147 | void allocate_output_buffer() | |
7148 | { | |
eeb71c95 | 7149 | output_buffer = calloc(1, (1 + topo.num_cpus) * 2048); |
c98d5d94 | 7150 | outp = output_buffer; |
b2c95d90 JT |
7151 | if (outp == NULL) |
7152 | err(-1, "calloc output buffer"); | |
c98d5d94 | 7153 | } |
1b439f01 | 7154 | |
36229897 LB |
7155 | void allocate_fd_percpu(void) |
7156 | { | |
01a67adf | 7157 | fd_percpu = calloc(topo.max_cpu_num + 1, sizeof(int)); |
36229897 LB |
7158 | if (fd_percpu == NULL) |
7159 | err(-1, "calloc fd_percpu"); | |
7160 | } | |
1b439f01 | 7161 | |
562a2d37 LB |
7162 | void allocate_irq_buffers(void) |
7163 | { | |
7164 | irq_column_2_cpu = calloc(topo.num_cpus, sizeof(int)); | |
7165 | if (irq_column_2_cpu == NULL) | |
7166 | err(-1, "calloc %d", topo.num_cpus); | |
c98d5d94 | 7167 | |
01a67adf | 7168 | irqs_per_cpu = calloc(topo.max_cpu_num + 1, sizeof(int)); |
562a2d37 | 7169 | if (irqs_per_cpu == NULL) |
01a67adf | 7170 | err(-1, "calloc %d", topo.max_cpu_num + 1); |
562a2d37 | 7171 | } |
1b439f01 | 7172 | |
0fe37529 ZR |
7173 | int update_topo(struct thread_data *t, struct core_data *c, struct pkg_data *p) |
7174 | { | |
7175 | topo.allowed_cpus++; | |
7176 | if ((int)t->cpu_id == c->base_cpu) | |
7177 | topo.allowed_cores++; | |
7178 | if ((int)t->cpu_id == p->base_cpu) | |
7179 | topo.allowed_packages++; | |
7180 | ||
7181 | return 0; | |
7182 | } | |
7183 | ||
7184 | void topology_update(void) | |
7185 | { | |
7186 | topo.allowed_cpus = 0; | |
7187 | topo.allowed_cores = 0; | |
7188 | topo.allowed_packages = 0; | |
7189 | for_all_cpus(update_topo, ODD_COUNTERS); | |
7190 | } | |
227ed18f | 7191 | |
c25ef0e5 | 7192 | void setup_all_buffers(bool startup) |
c98d5d94 | 7193 | { |
c25ef0e5 | 7194 | topology_probe(startup); |
562a2d37 | 7195 | allocate_irq_buffers(); |
36229897 | 7196 | allocate_fd_percpu(); |
c98d5d94 LB |
7197 | allocate_counters(&thread_even, &core_even, &package_even); |
7198 | allocate_counters(&thread_odd, &core_odd, &package_odd); | |
7199 | allocate_output_buffer(); | |
7200 | for_all_proc_cpus(initialize_counters); | |
0fe37529 | 7201 | topology_update(); |
c98d5d94 | 7202 | } |
3b4d5c7f | 7203 | |
7ce7d5de PB |
7204 | void set_base_cpu(void) |
7205 | { | |
7bb3fe27 | 7206 | int i; |
7ce7d5de | 7207 | |
7bb3fe27 ZR |
7208 | for (i = 0; i < topo.max_cpu_num + 1; ++i) { |
7209 | if (cpu_is_not_allowed(i)) | |
7210 | continue; | |
7211 | base_cpu = i; | |
7212 | if (debug > 1) | |
7213 | fprintf(outf, "base_cpu = %d\n", base_cpu); | |
7214 | return; | |
7215 | } | |
7216 | err(-ENODEV, "No valid cpus found"); | |
7ce7d5de PB |
7217 | } |
7218 | ||
e48934c9 PW |
7219 | static void set_amperf_source(void) |
7220 | { | |
7221 | amperf_source = AMPERF_SOURCE_PERF; | |
7222 | ||
aed48c48 PW |
7223 | const bool aperf_required = is_aperf_access_required(); |
7224 | if (no_perf || !aperf_required || !has_amperf_access_via_perf()) | |
e48934c9 PW |
7225 | amperf_source = AMPERF_SOURCE_MSR; |
7226 | ||
7227 | if (quiet || !debug) | |
7228 | return; | |
7229 | ||
7230 | fprintf(outf, "aperf/mperf source preference: %s\n", amperf_source == AMPERF_SOURCE_MSR ? "msr" : "perf"); | |
7231 | } | |
7232 | ||
4a1bb4da PW |
7233 | bool has_added_counters(void) |
7234 | { | |
7235 | /* | |
7236 | * It only makes sense to call this after the command line is parsed, | |
7237 | * otherwise sys structure is not populated. | |
7238 | */ | |
7239 | ||
7240 | return sys.added_core_counters | sys.added_thread_counters | sys.added_package_counters; | |
7241 | } | |
7242 | ||
aed48c48 PW |
7243 | bool is_msr_access_required(void) |
7244 | { | |
aed48c48 PW |
7245 | if (no_msr) |
7246 | return false; | |
7247 | ||
4a1bb4da PW |
7248 | if (has_added_counters()) |
7249 | return true; | |
7250 | ||
aed48c48 PW |
7251 | return BIC_IS_ENABLED(BIC_SMI) |
7252 | || BIC_IS_ENABLED(BIC_CPU_c1) | |
7253 | || BIC_IS_ENABLED(BIC_CPU_c3) | |
7254 | || BIC_IS_ENABLED(BIC_CPU_c6) | |
7255 | || BIC_IS_ENABLED(BIC_CPU_c7) | |
7256 | || BIC_IS_ENABLED(BIC_Mod_c6) | |
7257 | || BIC_IS_ENABLED(BIC_CoreTmp) | |
7258 | || BIC_IS_ENABLED(BIC_Totl_c0) | |
7259 | || BIC_IS_ENABLED(BIC_Any_c0) | |
7260 | || BIC_IS_ENABLED(BIC_GFX_c0) | |
7261 | || BIC_IS_ENABLED(BIC_CPUGFX) | |
7262 | || BIC_IS_ENABLED(BIC_Pkgpc3) | |
7263 | || BIC_IS_ENABLED(BIC_Pkgpc6) | |
7264 | || BIC_IS_ENABLED(BIC_Pkgpc2) | |
7265 | || BIC_IS_ENABLED(BIC_Pkgpc7) | |
7266 | || BIC_IS_ENABLED(BIC_Pkgpc8) | |
7267 | || BIC_IS_ENABLED(BIC_Pkgpc9) | |
7268 | || BIC_IS_ENABLED(BIC_Pkgpc10) | |
05a2f07d | 7269 | /* TODO: Multiplex access with perf */ |
aed48c48 PW |
7270 | || BIC_IS_ENABLED(BIC_CorWatt) |
7271 | || BIC_IS_ENABLED(BIC_Cor_J) | |
7272 | || BIC_IS_ENABLED(BIC_PkgWatt) | |
7273 | || BIC_IS_ENABLED(BIC_CorWatt) | |
7274 | || BIC_IS_ENABLED(BIC_GFXWatt) | |
7275 | || BIC_IS_ENABLED(BIC_RAMWatt) | |
7276 | || BIC_IS_ENABLED(BIC_Pkg_J) | |
7277 | || BIC_IS_ENABLED(BIC_Cor_J) | |
7278 | || BIC_IS_ENABLED(BIC_GFX_J) | |
7279 | || BIC_IS_ENABLED(BIC_RAM_J) | |
7280 | || BIC_IS_ENABLED(BIC_PKG__) | |
7281 | || BIC_IS_ENABLED(BIC_RAM__) | |
7282 | || BIC_IS_ENABLED(BIC_PkgTmp) | |
7283 | || (is_aperf_access_required() && !has_amperf_access_via_perf()); | |
7284 | } | |
7285 | ||
5088741e PW |
7286 | void check_msr_access(void) |
7287 | { | |
aed48c48 PW |
7288 | if (!is_msr_access_required()) |
7289 | no_msr = 1; | |
7290 | ||
5088741e PW |
7291 | check_dev_msr(); |
7292 | check_msr_permission(); | |
7293 | ||
7294 | if (no_msr) | |
7295 | bic_disable_msr_access(); | |
7296 | } | |
7297 | ||
7298 | void check_perf_access(void) | |
7299 | { | |
aed48c48 PW |
7300 | const bool intrcount_required = BIC_IS_ENABLED(BIC_IPC); |
7301 | if (no_perf || !intrcount_required || !has_instr_count_access()) | |
5088741e PW |
7302 | bic_enabled &= ~BIC_IPC; |
7303 | ||
aed48c48 PW |
7304 | const bool aperf_required = is_aperf_access_required(); |
7305 | if (!aperf_required || !has_amperf_access()) { | |
5088741e PW |
7306 | bic_enabled &= ~BIC_Avg_MHz; |
7307 | bic_enabled &= ~BIC_Busy; | |
7308 | bic_enabled &= ~BIC_Bzy_MHz; | |
7309 | bic_enabled &= ~BIC_IPC; | |
7310 | } | |
7311 | } | |
7312 | ||
103a8fea LB |
7313 | void turbostat_init() |
7314 | { | |
c25ef0e5 | 7315 | setup_all_buffers(true); |
7ce7d5de | 7316 | set_base_cpu(); |
5088741e PW |
7317 | check_msr_access(); |
7318 | check_perf_access(); | |
fcd17211 | 7319 | process_cpuid(); |
7ee39d8d | 7320 | probe_pm_features(); |
e48934c9 | 7321 | set_amperf_source(); |
2af4f9b8 | 7322 | linux_perf_init(); |
05a2f07d | 7323 | rapl_perf_init(); |
103a8fea | 7324 | |
7ab5ff49 ZR |
7325 | for_all_cpus(get_cpu_type, ODD_COUNTERS); |
7326 | for_all_cpus(get_cpu_type, EVEN_COUNTERS); | |
7327 | ||
164d7a96 LB |
7328 | if (DO_BIC(BIC_IPC)) |
7329 | (void)get_instr_count_fd(base_cpu); | |
e48934c9 PW |
7330 | |
7331 | /* | |
7332 | * If TSC tweak is needed, but couldn't get it, | |
7333 | * disable more BICs, since it can't be reported accurately. | |
7334 | */ | |
7335 | if (platform->enable_tsc_tweak && !has_base_hz) { | |
7336 | bic_enabled &= ~BIC_Busy; | |
7337 | bic_enabled &= ~BIC_Bzy_MHz; | |
7338 | } | |
103a8fea LB |
7339 | } |
7340 | ||
7341 | int fork_it(char **argv) | |
7342 | { | |
103a8fea | 7343 | pid_t child_pid; |
d91bb17c | 7344 | int status; |
d15cf7c1 | 7345 | |
218f0e8d | 7346 | snapshot_proc_sysfs_files(); |
d91bb17c | 7347 | status = for_all_cpus(get_counters, EVEN_COUNTERS); |
4c2122d4 | 7348 | first_counter_read = 0; |
d91bb17c LB |
7349 | if (status) |
7350 | exit(status); | |
103a8fea LB |
7351 | gettimeofday(&tv_even, (struct timezone *)NULL); |
7352 | ||
7353 | child_pid = fork(); | |
7354 | if (!child_pid) { | |
7355 | /* child */ | |
7356 | execvp(argv[0], argv); | |
0815a3d0 | 7357 | err(errno, "exec %s", argv[0]); |
103a8fea | 7358 | } else { |
103a8fea LB |
7359 | |
7360 | /* parent */ | |
b2c95d90 JT |
7361 | if (child_pid == -1) |
7362 | err(1, "fork"); | |
103a8fea LB |
7363 | |
7364 | signal(SIGINT, SIG_IGN); | |
7365 | signal(SIGQUIT, SIG_IGN); | |
b2c95d90 JT |
7366 | if (waitpid(child_pid, &status, 0) == -1) |
7367 | err(status, "waitpid"); | |
2a954966 DA |
7368 | |
7369 | if (WIFEXITED(status)) | |
7370 | status = WEXITSTATUS(status); | |
103a8fea | 7371 | } |
c98d5d94 LB |
7372 | /* |
7373 | * n.b. fork_it() does not check for errors from for_all_cpus() | |
7374 | * because re-starting is problematic when forking | |
7375 | */ | |
218f0e8d | 7376 | snapshot_proc_sysfs_files(); |
c98d5d94 | 7377 | for_all_cpus(get_counters, ODD_COUNTERS); |
103a8fea | 7378 | gettimeofday(&tv_odd, (struct timezone *)NULL); |
103a8fea | 7379 | timersub(&tv_odd, &tv_even, &tv_delta); |
ba3dec99 LB |
7380 | if (for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS)) |
7381 | fprintf(outf, "%s: Counter reset detected\n", progname); | |
7382 | else { | |
7383 | compute_average(EVEN_COUNTERS); | |
7384 | format_all_counters(EVEN_COUNTERS); | |
7385 | } | |
103a8fea | 7386 | |
1b439f01 | 7387 | fprintf(outf, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec / 1000000.0); |
b7d8c148 LB |
7388 | |
7389 | flush_output_stderr(); | |
103a8fea | 7390 | |
d91bb17c | 7391 | return status; |
103a8fea LB |
7392 | } |
7393 | ||
3b4d5c7f AS |
7394 | int get_and_dump_counters(void) |
7395 | { | |
7396 | int status; | |
7397 | ||
218f0e8d | 7398 | snapshot_proc_sysfs_files(); |
3b4d5c7f AS |
7399 | status = for_all_cpus(get_counters, ODD_COUNTERS); |
7400 | if (status) | |
7401 | return status; | |
7402 | ||
7403 | status = for_all_cpus(dump_counters, ODD_COUNTERS); | |
7404 | if (status) | |
7405 | return status; | |
7406 | ||
b7d8c148 | 7407 | flush_output_stdout(); |
3b4d5c7f AS |
7408 | |
7409 | return status; | |
7410 | } | |
7411 | ||
1b439f01 LB |
7412 | void print_version() |
7413 | { | |
b8337e6a | 7414 | fprintf(outf, "turbostat version 2023.11.07 - Len Brown <lenb@kernel.org>\n"); |
d8af6f5f LB |
7415 | } |
7416 | ||
03331233 CY |
7417 | #define COMMAND_LINE_SIZE 2048 |
7418 | ||
7419 | void print_bootcmd(void) | |
7420 | { | |
7421 | char bootcmd[COMMAND_LINE_SIZE]; | |
7422 | FILE *fp; | |
7423 | int ret; | |
7424 | ||
7425 | memset(bootcmd, 0, COMMAND_LINE_SIZE); | |
7426 | fp = fopen("/proc/cmdline", "r"); | |
7427 | if (!fp) | |
7428 | return; | |
7429 | ||
7430 | ret = fread(bootcmd, sizeof(char), COMMAND_LINE_SIZE - 1, fp); | |
7431 | if (ret) { | |
7432 | bootcmd[ret] = '\0'; | |
7433 | /* the last character is already '\n' */ | |
7434 | fprintf(outf, "Kernel command line: %s", bootcmd); | |
7435 | } | |
7436 | ||
7437 | fclose(fp); | |
7438 | } | |
7439 | ||
495c7654 | 7440 | int add_counter(unsigned int msr_num, char *path, char *name, |
1b439f01 LB |
7441 | unsigned int width, enum counter_scope scope, |
7442 | enum counter_type type, enum counter_format format, int flags) | |
388e9c81 LB |
7443 | { |
7444 | struct msr_counter *msrp; | |
7445 | ||
3e404846 PW |
7446 | if (no_msr && msr_num) |
7447 | errx(1, "Requested MSR counter 0x%x, but in --no-msr mode", msr_num); | |
7448 | ||
388e9c81 LB |
7449 | msrp = calloc(1, sizeof(struct msr_counter)); |
7450 | if (msrp == NULL) { | |
7451 | perror("calloc"); | |
7452 | exit(1); | |
7453 | } | |
7454 | ||
7455 | msrp->msr_num = msr_num; | |
d8d005ba | 7456 | strncpy(msrp->name, name, NAME_BYTES - 1); |
495c7654 | 7457 | if (path) |
d8d005ba | 7458 | strncpy(msrp->path, path, PATH_BYTES - 1); |
388e9c81 LB |
7459 | msrp->width = width; |
7460 | msrp->type = type; | |
7461 | msrp->format = format; | |
41618e63 | 7462 | msrp->flags = flags; |
388e9c81 LB |
7463 | |
7464 | switch (scope) { | |
7465 | ||
7466 | case SCOPE_CPU: | |
388e9c81 LB |
7467 | msrp->next = sys.tp; |
7468 | sys.tp = msrp; | |
678a3bd1 | 7469 | sys.added_thread_counters++; |
0748eaf0 | 7470 | if (sys.added_thread_counters > MAX_ADDED_THREAD_COUNTERS) { |
1b439f01 | 7471 | fprintf(stderr, "exceeded max %d added thread counters\n", MAX_ADDED_COUNTERS); |
678a3bd1 LB |
7472 | exit(-1); |
7473 | } | |
388e9c81 LB |
7474 | break; |
7475 | ||
7476 | case SCOPE_CORE: | |
388e9c81 LB |
7477 | msrp->next = sys.cp; |
7478 | sys.cp = msrp; | |
678a3bd1 LB |
7479 | sys.added_core_counters++; |
7480 | if (sys.added_core_counters > MAX_ADDED_COUNTERS) { | |
1b439f01 | 7481 | fprintf(stderr, "exceeded max %d added core counters\n", MAX_ADDED_COUNTERS); |
678a3bd1 LB |
7482 | exit(-1); |
7483 | } | |
388e9c81 LB |
7484 | break; |
7485 | ||
7486 | case SCOPE_PACKAGE: | |
388e9c81 LB |
7487 | msrp->next = sys.pp; |
7488 | sys.pp = msrp; | |
678a3bd1 LB |
7489 | sys.added_package_counters++; |
7490 | if (sys.added_package_counters > MAX_ADDED_COUNTERS) { | |
1b439f01 | 7491 | fprintf(stderr, "exceeded max %d added package counters\n", MAX_ADDED_COUNTERS); |
678a3bd1 LB |
7492 | exit(-1); |
7493 | } | |
388e9c81 LB |
7494 | break; |
7495 | } | |
7496 | ||
7497 | return 0; | |
7498 | } | |
7499 | ||
7500 | void parse_add_command(char *add_command) | |
7501 | { | |
7502 | int msr_num = 0; | |
495c7654 | 7503 | char *path = NULL; |
0f47c08d | 7504 | char name_buffer[NAME_BYTES] = ""; |
388e9c81 LB |
7505 | int width = 64; |
7506 | int fail = 0; | |
7507 | enum counter_scope scope = SCOPE_CPU; | |
7508 | enum counter_type type = COUNTER_CYCLES; | |
7509 | enum counter_format format = FORMAT_DELTA; | |
7510 | ||
7511 | while (add_command) { | |
7512 | ||
7513 | if (sscanf(add_command, "msr0x%x", &msr_num) == 1) | |
7514 | goto next; | |
7515 | ||
7516 | if (sscanf(add_command, "msr%d", &msr_num) == 1) | |
7517 | goto next; | |
7518 | ||
495c7654 LB |
7519 | if (*add_command == '/') { |
7520 | path = add_command; | |
7521 | goto next; | |
7522 | } | |
7523 | ||
388e9c81 LB |
7524 | if (sscanf(add_command, "u%d", &width) == 1) { |
7525 | if ((width == 32) || (width == 64)) | |
7526 | goto next; | |
7527 | width = 64; | |
7528 | } | |
7529 | if (!strncmp(add_command, "cpu", strlen("cpu"))) { | |
7530 | scope = SCOPE_CPU; | |
7531 | goto next; | |
7532 | } | |
7533 | if (!strncmp(add_command, "core", strlen("core"))) { | |
7534 | scope = SCOPE_CORE; | |
7535 | goto next; | |
7536 | } | |
7537 | if (!strncmp(add_command, "package", strlen("package"))) { | |
7538 | scope = SCOPE_PACKAGE; | |
7539 | goto next; | |
7540 | } | |
7541 | if (!strncmp(add_command, "cycles", strlen("cycles"))) { | |
7542 | type = COUNTER_CYCLES; | |
7543 | goto next; | |
7544 | } | |
7545 | if (!strncmp(add_command, "seconds", strlen("seconds"))) { | |
7546 | type = COUNTER_SECONDS; | |
7547 | goto next; | |
7548 | } | |
41618e63 LB |
7549 | if (!strncmp(add_command, "usec", strlen("usec"))) { |
7550 | type = COUNTER_USEC; | |
7551 | goto next; | |
7552 | } | |
388e9c81 LB |
7553 | if (!strncmp(add_command, "raw", strlen("raw"))) { |
7554 | format = FORMAT_RAW; | |
7555 | goto next; | |
7556 | } | |
7557 | if (!strncmp(add_command, "delta", strlen("delta"))) { | |
7558 | format = FORMAT_DELTA; | |
7559 | goto next; | |
7560 | } | |
7561 | if (!strncmp(add_command, "percent", strlen("percent"))) { | |
7562 | format = FORMAT_PERCENT; | |
7563 | goto next; | |
7564 | } | |
7565 | ||
7566 | if (sscanf(add_command, "%18s,%*s", name_buffer) == 1) { /* 18 < NAME_BYTES */ | |
7567 | char *eos; | |
7568 | ||
7569 | eos = strchr(name_buffer, ','); | |
7570 | if (eos) | |
7571 | *eos = '\0'; | |
7572 | goto next; | |
7573 | } | |
7574 | ||
7575 | next: | |
7576 | add_command = strchr(add_command, ','); | |
495c7654 LB |
7577 | if (add_command) { |
7578 | *add_command = '\0'; | |
388e9c81 | 7579 | add_command++; |
495c7654 | 7580 | } |
388e9c81 LB |
7581 | |
7582 | } | |
495c7654 LB |
7583 | if ((msr_num == 0) && (path == NULL)) { |
7584 | fprintf(stderr, "--add: (msrDDD | msr0xXXX | /path_to_counter ) required\n"); | |
388e9c81 LB |
7585 | fail++; |
7586 | } | |
7587 | ||
7588 | /* generate default column header */ | |
7589 | if (*name_buffer == '\0') { | |
5f3aea57 LB |
7590 | if (width == 32) |
7591 | sprintf(name_buffer, "M0x%x%s", msr_num, format == FORMAT_PERCENT ? "%" : ""); | |
7592 | else | |
7593 | sprintf(name_buffer, "M0X%x%s", msr_num, format == FORMAT_PERCENT ? "%" : ""); | |
388e9c81 LB |
7594 | } |
7595 | ||
41618e63 | 7596 | if (add_counter(msr_num, path, name_buffer, width, scope, type, format, 0)) |
388e9c81 LB |
7597 | fail++; |
7598 | ||
7599 | if (fail) { | |
7600 | help(); | |
7601 | exit(1); | |
7602 | } | |
7603 | } | |
41618e63 | 7604 | |
0fc521bc ZLCH |
7605 | int is_deferred_add(char *name) |
7606 | { | |
7607 | int i; | |
7608 | ||
7609 | for (i = 0; i < deferred_add_index; ++i) | |
7610 | if (!strcmp(name, deferred_add_names[i])) | |
7611 | return 1; | |
7612 | return 0; | |
7613 | } | |
7614 | ||
dd778a5e LB |
7615 | int is_deferred_skip(char *name) |
7616 | { | |
7617 | int i; | |
7618 | ||
7619 | for (i = 0; i < deferred_skip_index; ++i) | |
7620 | if (!strcmp(name, deferred_skip_names[i])) | |
7621 | return 1; | |
7622 | return 0; | |
7623 | } | |
7624 | ||
41618e63 LB |
7625 | void probe_sysfs(void) |
7626 | { | |
7627 | char path[64]; | |
7628 | char name_buf[16]; | |
7629 | FILE *input; | |
7630 | int state; | |
7631 | char *sp; | |
7632 | ||
0748eaf0 | 7633 | for (state = 10; state >= 0; --state) { |
41618e63 | 7634 | |
1b439f01 | 7635 | sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name", base_cpu, state); |
41618e63 LB |
7636 | input = fopen(path, "r"); |
7637 | if (input == NULL) | |
7638 | continue; | |
8173c336 BH |
7639 | if (!fgets(name_buf, sizeof(name_buf), input)) |
7640 | err(1, "%s: failed to read file", path); | |
41618e63 | 7641 | |
1b439f01 | 7642 | /* truncate "C1-HSW\n" to "C1", or truncate "C1\n" to "C1" */ |
41618e63 LB |
7643 | sp = strchr(name_buf, '-'); |
7644 | if (!sp) | |
7645 | sp = strchrnul(name_buf, '\n'); | |
7646 | *sp = '%'; | |
7647 | *(sp + 1) = '\0'; | |
7648 | ||
fecb3bc8 DA |
7649 | remove_underbar(name_buf); |
7650 | ||
41618e63 LB |
7651 | fclose(input); |
7652 | ||
7653 | sprintf(path, "cpuidle/state%d/time", state); | |
7654 | ||
0fc521bc ZLCH |
7655 | if (!DO_BIC(BIC_sysfs) && !is_deferred_add(name_buf)) |
7656 | continue; | |
7657 | ||
dd778a5e LB |
7658 | if (is_deferred_skip(name_buf)) |
7659 | continue; | |
7660 | ||
1b439f01 | 7661 | add_counter(0, path, name_buf, 64, SCOPE_CPU, COUNTER_USEC, FORMAT_PERCENT, SYSFS_PERCPU); |
41618e63 LB |
7662 | } |
7663 | ||
0748eaf0 | 7664 | for (state = 10; state >= 0; --state) { |
41618e63 | 7665 | |
1b439f01 | 7666 | sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name", base_cpu, state); |
41618e63 LB |
7667 | input = fopen(path, "r"); |
7668 | if (input == NULL) | |
7669 | continue; | |
8173c336 BH |
7670 | if (!fgets(name_buf, sizeof(name_buf), input)) |
7671 | err(1, "%s: failed to read file", path); | |
1b439f01 | 7672 | /* truncate "C1-HSW\n" to "C1", or truncate "C1\n" to "C1" */ |
41618e63 LB |
7673 | sp = strchr(name_buf, '-'); |
7674 | if (!sp) | |
7675 | sp = strchrnul(name_buf, '\n'); | |
7676 | *sp = '\0'; | |
7677 | fclose(input); | |
fecb3bc8 DA |
7678 | |
7679 | remove_underbar(name_buf); | |
41618e63 LB |
7680 | |
7681 | sprintf(path, "cpuidle/state%d/usage", state); | |
7682 | ||
0fc521bc ZLCH |
7683 | if (!DO_BIC(BIC_sysfs) && !is_deferred_add(name_buf)) |
7684 | continue; | |
7685 | ||
dd778a5e LB |
7686 | if (is_deferred_skip(name_buf)) |
7687 | continue; | |
7688 | ||
1b439f01 | 7689 | add_counter(0, path, name_buf, 64, SCOPE_CPU, COUNTER_ITEMS, FORMAT_DELTA, SYSFS_PERCPU); |
41618e63 LB |
7690 | } |
7691 | ||
7692 | } | |
7693 | ||
1ef7d21a LB |
7694 | /* |
7695 | * parse cpuset with following syntax | |
7696 | * 1,2,4..6,8-10 and set bits in cpu_subset | |
7697 | */ | |
7698 | void parse_cpu_command(char *optarg) | |
7699 | { | |
4e4e1e7c LB |
7700 | if (!strcmp(optarg, "core")) { |
7701 | if (cpu_subset) | |
7702 | goto error; | |
7703 | show_core_only++; | |
7704 | return; | |
7705 | } | |
7706 | if (!strcmp(optarg, "package")) { | |
7707 | if (cpu_subset) | |
7708 | goto error; | |
7709 | show_pkg_only++; | |
7710 | return; | |
7711 | } | |
7712 | if (show_core_only || show_pkg_only) | |
7713 | goto error; | |
7714 | ||
1ef7d21a LB |
7715 | cpu_subset = CPU_ALLOC(CPU_SUBSET_MAXCPUS); |
7716 | if (cpu_subset == NULL) | |
7717 | err(3, "CPU_ALLOC"); | |
7718 | cpu_subset_size = CPU_ALLOC_SIZE(CPU_SUBSET_MAXCPUS); | |
7719 | ||
7720 | CPU_ZERO_S(cpu_subset_size, cpu_subset); | |
7721 | ||
8c3dd2c9 ZR |
7722 | if (parse_cpu_str(optarg, cpu_subset, cpu_subset_size)) |
7723 | goto error; | |
1ef7d21a LB |
7724 | |
7725 | return; | |
7726 | ||
7727 | error: | |
4e4e1e7c LB |
7728 | fprintf(stderr, "\"--cpu %s\" malformed\n", optarg); |
7729 | help(); | |
1ef7d21a LB |
7730 | exit(-1); |
7731 | } | |
7732 | ||
103a8fea LB |
7733 | void cmdline(int argc, char **argv) |
7734 | { | |
7735 | int opt; | |
d8af6f5f LB |
7736 | int option_index = 0; |
7737 | static struct option long_options[] = { | |
1b439f01 LB |
7738 | { "add", required_argument, 0, 'a' }, |
7739 | { "cpu", required_argument, 0, 'c' }, | |
7740 | { "Dump", no_argument, 0, 'D' }, | |
7741 | { "debug", no_argument, 0, 'd' }, /* internal, not documented */ | |
7742 | { "enable", required_argument, 0, 'e' }, | |
7743 | { "interval", required_argument, 0, 'i' }, | |
7744 | { "IPC", no_argument, 0, 'I' }, | |
7745 | { "num_iterations", required_argument, 0, 'n' }, | |
c7e399f8 | 7746 | { "header_iterations", required_argument, 0, 'N' }, |
1b439f01 LB |
7747 | { "help", no_argument, 0, 'h' }, |
7748 | { "hide", required_argument, 0, 'H' }, // meh, -h taken by --help | |
7749 | { "Joules", no_argument, 0, 'J' }, | |
7750 | { "list", no_argument, 0, 'l' }, | |
7751 | { "out", required_argument, 0, 'o' }, | |
7752 | { "quiet", no_argument, 0, 'q' }, | |
3e404846 | 7753 | { "no-msr", no_argument, 0, 'M' }, |
a0e86c90 | 7754 | { "no-perf", no_argument, 0, 'P' }, |
1b439f01 LB |
7755 | { "show", required_argument, 0, 's' }, |
7756 | { "Summary", no_argument, 0, 'S' }, | |
7757 | { "TCC", required_argument, 0, 'T' }, | |
7758 | { "version", no_argument, 0, 'v' }, | |
7759 | { 0, 0, 0, 0 } | |
d8af6f5f | 7760 | }; |
103a8fea LB |
7761 | |
7762 | progname = argv[0]; | |
7763 | ||
3e404846 PW |
7764 | /* |
7765 | * Parse some options early, because they may make other options invalid, | |
7766 | * like adding the MSR counter with --add and at the same time using --no-msr. | |
7767 | */ | |
a0e86c90 | 7768 | while ((opt = getopt_long_only(argc, argv, "MP", long_options, &option_index)) != -1) { |
3e404846 PW |
7769 | switch (opt) { |
7770 | case 'M': | |
7771 | no_msr = 1; | |
7772 | break; | |
a0e86c90 PW |
7773 | case 'P': |
7774 | no_perf = 1; | |
7775 | break; | |
3e404846 PW |
7776 | default: |
7777 | break; | |
7778 | } | |
7779 | } | |
7780 | optind = 0; | |
7781 | ||
7782 | while ((opt = getopt_long_only(argc, argv, "+C:c:Dde:hi:Jn:o:qMST:v", long_options, &option_index)) != -1) { | |
103a8fea | 7783 | switch (opt) { |
388e9c81 LB |
7784 | case 'a': |
7785 | parse_add_command(optarg); | |
7786 | break; | |
1ef7d21a LB |
7787 | case 'c': |
7788 | parse_cpu_command(optarg); | |
7789 | break; | |
d8af6f5f | 7790 | case 'D': |
3b4d5c7f AS |
7791 | dump_only++; |
7792 | break; | |
3f44a5c6 LB |
7793 | case 'e': |
7794 | /* --enable specified counter */ | |
4c2122d4 | 7795 | bic_enabled = bic_enabled | bic_lookup(optarg, SHOW_LIST); |
3f44a5c6 | 7796 | break; |
d8af6f5f LB |
7797 | case 'd': |
7798 | debug++; | |
3f44a5c6 | 7799 | ENABLE_BIC(BIC_DISABLED_BY_DEFAULT); |
103a8fea | 7800 | break; |
812db3f7 | 7801 | case 'H': |
3f44a5c6 LB |
7802 | /* |
7803 | * --hide: do not show those specified | |
7804 | * multiple invocations simply clear more bits in enabled mask | |
7805 | */ | |
7806 | bic_enabled &= ~bic_lookup(optarg, HIDE_LIST); | |
812db3f7 | 7807 | break; |
d8af6f5f LB |
7808 | case 'h': |
7809 | default: | |
7810 | help(); | |
7811 | exit(1); | |
103a8fea | 7812 | case 'i': |
2a0609c0 LB |
7813 | { |
7814 | double interval = strtod(optarg, NULL); | |
7815 | ||
7816 | if (interval < 0.001) { | |
1b439f01 | 7817 | fprintf(outf, "interval %f seconds is too small\n", interval); |
2a0609c0 LB |
7818 | exit(2); |
7819 | } | |
7820 | ||
47936f94 | 7821 | interval_tv.tv_sec = interval_ts.tv_sec = interval; |
b9ad8ee0 | 7822 | interval_tv.tv_usec = (interval - interval_tv.tv_sec) * 1000000; |
47936f94 | 7823 | interval_ts.tv_nsec = (interval - interval_ts.tv_sec) * 1000000000; |
2a0609c0 | 7824 | } |
103a8fea | 7825 | break; |
d8af6f5f LB |
7826 | case 'J': |
7827 | rapl_joules++; | |
8e180f3c | 7828 | break; |
c8ade361 | 7829 | case 'l': |
3f44a5c6 | 7830 | ENABLE_BIC(BIC_DISABLED_BY_DEFAULT); |
c8ade361 LB |
7831 | list_header_only++; |
7832 | quiet++; | |
7833 | break; | |
b7d8c148 LB |
7834 | case 'o': |
7835 | outf = fopen_or_die(optarg, "w"); | |
7836 | break; | |
96e47158 LB |
7837 | case 'q': |
7838 | quiet = 1; | |
7839 | break; | |
3e404846 | 7840 | case 'M': |
a0e86c90 | 7841 | case 'P': |
3e404846 PW |
7842 | /* Parsed earlier */ |
7843 | break; | |
023fe0ac CY |
7844 | case 'n': |
7845 | num_iterations = strtod(optarg, NULL); | |
7846 | ||
7847 | if (num_iterations <= 0) { | |
1b439f01 | 7848 | fprintf(outf, "iterations %d should be positive number\n", num_iterations); |
023fe0ac CY |
7849 | exit(2); |
7850 | } | |
7851 | break; | |
c7e399f8 ZLCH |
7852 | case 'N': |
7853 | header_iterations = strtod(optarg, NULL); | |
7854 | ||
7855 | if (header_iterations <= 0) { | |
164d7a96 | 7856 | fprintf(outf, "iterations %d should be positive number\n", header_iterations); |
c7e399f8 | 7857 | exit(2); |
023fe0ac CY |
7858 | } |
7859 | break; | |
812db3f7 | 7860 | case 's': |
3f44a5c6 LB |
7861 | /* |
7862 | * --show: show only those specified | |
7863 | * The 1st invocation will clear and replace the enabled mask | |
7864 | * subsequent invocations can add to it. | |
7865 | */ | |
7866 | if (shown == 0) | |
7867 | bic_enabled = bic_lookup(optarg, SHOW_LIST); | |
7868 | else | |
7869 | bic_enabled |= bic_lookup(optarg, SHOW_LIST); | |
7870 | shown = 1; | |
812db3f7 | 7871 | break; |
d8af6f5f LB |
7872 | case 'S': |
7873 | summary_only++; | |
889facbe LB |
7874 | break; |
7875 | case 'T': | |
55279aef | 7876 | tj_max_override = atoi(optarg); |
889facbe | 7877 | break; |
d8af6f5f LB |
7878 | case 'v': |
7879 | print_version(); | |
7880 | exit(0); | |
5c56be9a | 7881 | break; |
103a8fea LB |
7882 | } |
7883 | } | |
7884 | } | |
7885 | ||
3ac1d14d WK |
7886 | void set_rlimit(void) |
7887 | { | |
7888 | struct rlimit limit; | |
7889 | ||
7890 | if (getrlimit(RLIMIT_NOFILE, &limit) < 0) | |
7891 | err(1, "Failed to get rlimit"); | |
7892 | ||
7893 | if (limit.rlim_max < MAX_NOFILE) | |
7894 | limit.rlim_max = MAX_NOFILE; | |
7895 | if (limit.rlim_cur < MAX_NOFILE) | |
7896 | limit.rlim_cur = MAX_NOFILE; | |
7897 | ||
7898 | if (setrlimit(RLIMIT_NOFILE, &limit) < 0) | |
7899 | err(1, "Failed to set rlimit"); | |
7900 | } | |
7901 | ||
103a8fea LB |
7902 | int main(int argc, char **argv) |
7903 | { | |
37f68a29 SP |
7904 | int fd, ret; |
7905 | ||
7906 | fd = open("/sys/fs/cgroup/cgroup.procs", O_WRONLY); | |
7907 | if (fd < 0) | |
7908 | goto skip_cgroup_setting; | |
7909 | ||
7910 | ret = write(fd, "0\n", 2); | |
7911 | if (ret == -1) | |
7912 | perror("Can't update cgroup\n"); | |
7913 | ||
7914 | close(fd); | |
7915 | ||
7916 | skip_cgroup_setting: | |
b7d8c148 | 7917 | outf = stderr; |
103a8fea LB |
7918 | cmdline(argc, argv); |
7919 | ||
03331233 | 7920 | if (!quiet) { |
d8af6f5f | 7921 | print_version(); |
03331233 CY |
7922 | print_bootcmd(); |
7923 | } | |
103a8fea | 7924 | |
41618e63 LB |
7925 | probe_sysfs(); |
7926 | ||
3ac1d14d WK |
7927 | if (!getuid()) |
7928 | set_rlimit(); | |
7929 | ||
103a8fea LB |
7930 | turbostat_init(); |
7931 | ||
3e404846 PW |
7932 | if (!no_msr) |
7933 | msr_sum_record(); | |
6799ba84 | 7934 | |
3b4d5c7f AS |
7935 | /* dump counters and exit */ |
7936 | if (dump_only) | |
7937 | return get_and_dump_counters(); | |
7938 | ||
c8ade361 LB |
7939 | /* list header and exit */ |
7940 | if (list_header_only) { | |
7941 | print_header(","); | |
7942 | flush_output_stdout(); | |
7943 | return 0; | |
7944 | } | |
7945 | ||
103a8fea LB |
7946 | /* |
7947 | * if any params left, it must be a command to fork | |
7948 | */ | |
7949 | if (argc - optind) | |
7950 | return fork_it(argv + optind); | |
7951 | else | |
7952 | turbostat_loop(); | |
7953 | ||
7954 | return 0; | |
7955 | } |