xref: /openbmc/linux/tools/power/x86/turbostat/turbostat.c (revision 388e9c8134be6bbc3751ba7072f5fa9bc8ecbe01)
1103a8feaSLen Brown /*
2103a8feaSLen Brown  * turbostat -- show CPU frequency and C-state residency
3103a8feaSLen Brown  * on modern Intel turbo-capable processors.
4103a8feaSLen Brown  *
5144b44b1SLen Brown  * Copyright (c) 2013 Intel Corporation.
6103a8feaSLen Brown  * Len Brown <len.brown@intel.com>
7103a8feaSLen Brown  *
8103a8feaSLen Brown  * This program is free software; you can redistribute it and/or modify it
9103a8feaSLen Brown  * under the terms and conditions of the GNU General Public License,
10103a8feaSLen Brown  * version 2, as published by the Free Software Foundation.
11103a8feaSLen Brown  *
12103a8feaSLen Brown  * This program is distributed in the hope it will be useful, but WITHOUT
13103a8feaSLen Brown  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14103a8feaSLen Brown  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15103a8feaSLen Brown  * more details.
16103a8feaSLen Brown  *
17103a8feaSLen Brown  * You should have received a copy of the GNU General Public License along with
18103a8feaSLen Brown  * this program; if not, write to the Free Software Foundation, Inc.,
19103a8feaSLen Brown  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20103a8feaSLen Brown  */
21103a8feaSLen Brown 
2288c3281fSLen Brown #define _GNU_SOURCE
23b731f311SJosh Triplett #include MSRHEADER
24869ce69eSLen Brown #include INTEL_FAMILY_HEADER
2595aebc44SJosh Triplett #include <stdarg.h>
26103a8feaSLen Brown #include <stdio.h>
27b2c95d90SJosh Triplett #include <err.h>
28103a8feaSLen Brown #include <unistd.h>
29103a8feaSLen Brown #include <sys/types.h>
30103a8feaSLen Brown #include <sys/wait.h>
31103a8feaSLen Brown #include <sys/stat.h>
32103a8feaSLen Brown #include <sys/resource.h>
33103a8feaSLen Brown #include <fcntl.h>
34103a8feaSLen Brown #include <signal.h>
35103a8feaSLen Brown #include <sys/time.h>
36103a8feaSLen Brown #include <stdlib.h>
37d8af6f5fSLen Brown #include <getopt.h>
38103a8feaSLen Brown #include <dirent.h>
39103a8feaSLen Brown #include <string.h>
40103a8feaSLen Brown #include <ctype.h>
4188c3281fSLen Brown #include <sched.h>
422a0609c0SLen Brown #include <time.h>
432b92865eSJosh Triplett #include <cpuid.h>
4498481e79SLen Brown #include <linux/capability.h>
4598481e79SLen Brown #include <errno.h>
46103a8feaSLen Brown 
47103a8feaSLen Brown char *proc_stat = "/proc/stat";
48b7d8c148SLen Brown FILE *outf;
4936229897SLen Brown int *fd_percpu;
502a0609c0SLen Brown struct timespec interval_ts = {5, 0};
51d8af6f5fSLen Brown unsigned int debug;
52d8af6f5fSLen Brown unsigned int rapl_joules;
53d8af6f5fSLen Brown unsigned int summary_only;
54d8af6f5fSLen Brown unsigned int dump_only;
55103a8feaSLen Brown unsigned int do_nhm_cstates;
56103a8feaSLen Brown unsigned int do_snb_cstates;
57fb5d4327SDasaratharaman Chandramouli unsigned int do_knl_cstates;
58ee7e38e3SLen Brown unsigned int do_pc2;
59ee7e38e3SLen Brown unsigned int do_pc3;
60ee7e38e3SLen Brown unsigned int do_pc6;
61ee7e38e3SLen Brown unsigned int do_pc7;
62ca58710fSKristen Carlson Accardi unsigned int do_c8_c9_c10;
630b2bb692SLen Brown unsigned int do_skl_residency;
64144b44b1SLen Brown unsigned int do_slm_cstates;
65144b44b1SLen Brown unsigned int use_c1_residency_msr;
66103a8feaSLen Brown unsigned int has_aperf;
67889facbeSLen Brown unsigned int has_epb;
685a63426eSLen Brown unsigned int do_irtl_snb;
695a63426eSLen Brown unsigned int do_irtl_hsw;
70fc04cc67SLen Brown unsigned int units = 1000000;	/* MHz etc */
71103a8feaSLen Brown unsigned int genuine_intel;
72103a8feaSLen Brown unsigned int has_invariant_tsc;
73d7899447SLen Brown unsigned int do_nhm_platform_info;
742f32edf1SLen Brown unsigned int extra_msr_offset32;
752f32edf1SLen Brown unsigned int extra_msr_offset64;
768e180f3cSLen Brown unsigned int extra_delta_offset32;
778e180f3cSLen Brown unsigned int extra_delta_offset64;
78b2b34dfeSHubert Chrzaniuk unsigned int aperf_mperf_multiplier = 1;
79562a2d37SLen Brown int do_irq = 1;
801ed51011SLen Brown int do_smi;
81103a8feaSLen Brown double bclk;
82a2b7b749SLen Brown double base_hz;
8321ed5574SLen Brown unsigned int has_base_hz;
84a2b7b749SLen Brown double tsc_tweak = 1.0;
85103a8feaSLen Brown unsigned int show_pkg;
86103a8feaSLen Brown unsigned int show_core;
87103a8feaSLen Brown unsigned int show_cpu;
88c98d5d94SLen Brown unsigned int show_pkg_only;
89c98d5d94SLen Brown unsigned int show_core_only;
90c98d5d94SLen Brown char *output_buffer, *outp;
91889facbeSLen Brown unsigned int do_rapl;
92889facbeSLen Brown unsigned int do_dts;
93889facbeSLen Brown unsigned int do_ptm;
94fdf676e5SLen Brown unsigned int do_gfx_rc6_ms;
95fdf676e5SLen Brown unsigned long long  gfx_cur_rc6_ms;
9627d47356SLen Brown unsigned int do_gfx_mhz;
9727d47356SLen Brown unsigned int gfx_cur_mhz;
98889facbeSLen Brown unsigned int tcc_activation_temp;
99889facbeSLen Brown unsigned int tcc_activation_temp_override;
10040ee8e3bSAndrey Semin double rapl_power_units, rapl_time_units;
10140ee8e3bSAndrey Semin double rapl_dram_energy_units, rapl_energy_units;
102889facbeSLen Brown double rapl_joule_counter_range;
1033a9a941dSLen Brown unsigned int do_core_perf_limit_reasons;
1043a9a941dSLen Brown unsigned int do_gfx_perf_limit_reasons;
1053a9a941dSLen Brown unsigned int do_ring_perf_limit_reasons;
1068a5bdf41SLen Brown unsigned int crystal_hz;
1078a5bdf41SLen Brown unsigned long long tsc_hz;
1087ce7d5deSPrarit Bhargava int base_cpu;
10921ed5574SLen Brown double discover_bclk(unsigned int family, unsigned int model);
1107f5c258eSLen Brown unsigned int has_hwp;	/* IA32_PM_ENABLE, IA32_HWP_CAPABILITIES */
1117f5c258eSLen Brown 			/* IA32_HWP_REQUEST, IA32_HWP_STATUS */
1127f5c258eSLen Brown unsigned int has_hwp_notify;		/* IA32_HWP_INTERRUPT */
1137f5c258eSLen Brown unsigned int has_hwp_activity_window;	/* IA32_HWP_REQUEST[bits 41:32] */
1147f5c258eSLen Brown unsigned int has_hwp_epp;		/* IA32_HWP_REQUEST[bits 31:24] */
1157f5c258eSLen Brown unsigned int has_hwp_pkg;		/* IA32_HWP_REQUEST_PKG */
116889facbeSLen Brown 
117889facbeSLen Brown #define RAPL_PKG		(1 << 0)
118e6f9bb3cSLen Brown 					/* 0x610 MSR_PKG_POWER_LIMIT */
119e6f9bb3cSLen Brown 					/* 0x611 MSR_PKG_ENERGY_STATUS */
120e6f9bb3cSLen Brown #define RAPL_PKG_PERF_STATUS	(1 << 1)
121e6f9bb3cSLen Brown 					/* 0x613 MSR_PKG_PERF_STATUS */
122e6f9bb3cSLen Brown #define RAPL_PKG_POWER_INFO	(1 << 2)
123e6f9bb3cSLen Brown 					/* 0x614 MSR_PKG_POWER_INFO */
124e6f9bb3cSLen Brown 
125889facbeSLen Brown #define RAPL_DRAM		(1 << 3)
126e6f9bb3cSLen Brown 					/* 0x618 MSR_DRAM_POWER_LIMIT */
127e6f9bb3cSLen Brown 					/* 0x619 MSR_DRAM_ENERGY_STATUS */
128e6f9bb3cSLen Brown #define RAPL_DRAM_PERF_STATUS	(1 << 4)
129e6f9bb3cSLen Brown 					/* 0x61b MSR_DRAM_PERF_STATUS */
1300b2bb692SLen Brown #define RAPL_DRAM_POWER_INFO	(1 << 5)
1310b2bb692SLen Brown 					/* 0x61c MSR_DRAM_POWER_INFO */
132e6f9bb3cSLen Brown 
1339148494cSJacob Pan #define RAPL_CORES_POWER_LIMIT	(1 << 6)
134e6f9bb3cSLen Brown 					/* 0x638 MSR_PP0_POWER_LIMIT */
1350b2bb692SLen Brown #define RAPL_CORE_POLICY	(1 << 7)
136e6f9bb3cSLen Brown 					/* 0x63a MSR_PP0_POLICY */
137e6f9bb3cSLen Brown 
1380b2bb692SLen Brown #define RAPL_GFX		(1 << 8)
139e6f9bb3cSLen Brown 					/* 0x640 MSR_PP1_POWER_LIMIT */
140e6f9bb3cSLen Brown 					/* 0x641 MSR_PP1_ENERGY_STATUS */
141e6f9bb3cSLen Brown 					/* 0x642 MSR_PP1_POLICY */
1429148494cSJacob Pan 
1439148494cSJacob Pan #define RAPL_CORES_ENERGY_STATUS	(1 << 9)
1449148494cSJacob Pan 					/* 0x639 MSR_PP0_ENERGY_STATUS */
1459148494cSJacob Pan #define RAPL_CORES (RAPL_CORES_ENERGY_STATUS | RAPL_CORES_POWER_LIMIT)
146889facbeSLen Brown #define	TJMAX_DEFAULT	100
147889facbeSLen Brown 
148889facbeSLen Brown #define MAX(a, b) ((a) > (b) ? (a) : (b))
149103a8feaSLen Brown 
150*388e9c81SLen Brown /*
151*388e9c81SLen Brown  * buffer size used by sscanf() for added column names
152*388e9c81SLen Brown  * Usually truncated to 7 characters, but also handles 18 columns for raw 64-bit counters
153*388e9c81SLen Brown  */
154*388e9c81SLen Brown #define	NAME_BYTES 20
155*388e9c81SLen Brown 
156103a8feaSLen Brown int backwards_count;
157103a8feaSLen Brown char *progname;
158103a8feaSLen Brown 
159c98d5d94SLen Brown cpu_set_t *cpu_present_set, *cpu_affinity_set;
160c98d5d94SLen Brown size_t cpu_present_setsize, cpu_affinity_setsize;
161c98d5d94SLen Brown 
162c98d5d94SLen Brown struct thread_data {
163c98d5d94SLen Brown 	unsigned long long tsc;
164c98d5d94SLen Brown 	unsigned long long aperf;
165c98d5d94SLen Brown 	unsigned long long mperf;
166144b44b1SLen Brown 	unsigned long long c1;
1672f32edf1SLen Brown 	unsigned long long extra_msr64;
1688e180f3cSLen Brown 	unsigned long long extra_delta64;
1698e180f3cSLen Brown 	unsigned long long extra_msr32;
1708e180f3cSLen Brown 	unsigned long long extra_delta32;
171562a2d37SLen Brown 	unsigned int irq_count;
1721ed51011SLen Brown 	unsigned int smi_count;
173c98d5d94SLen Brown 	unsigned int cpu_id;
174c98d5d94SLen Brown 	unsigned int flags;
175c98d5d94SLen Brown #define CPU_IS_FIRST_THREAD_IN_CORE	0x2
176c98d5d94SLen Brown #define CPU_IS_FIRST_CORE_IN_PACKAGE	0x4
177*388e9c81SLen Brown 	unsigned long long counter[1];
178c98d5d94SLen Brown } *thread_even, *thread_odd;
179c98d5d94SLen Brown 
180c98d5d94SLen Brown struct core_data {
181c98d5d94SLen Brown 	unsigned long long c3;
182c98d5d94SLen Brown 	unsigned long long c6;
183c98d5d94SLen Brown 	unsigned long long c7;
184889facbeSLen Brown 	unsigned int core_temp_c;
185c98d5d94SLen Brown 	unsigned int core_id;
186*388e9c81SLen Brown 	unsigned long long counter[1];
187c98d5d94SLen Brown } *core_even, *core_odd;
188c98d5d94SLen Brown 
189c98d5d94SLen Brown struct pkg_data {
190c98d5d94SLen Brown 	unsigned long long pc2;
191c98d5d94SLen Brown 	unsigned long long pc3;
192c98d5d94SLen Brown 	unsigned long long pc6;
193c98d5d94SLen Brown 	unsigned long long pc7;
194ca58710fSKristen Carlson Accardi 	unsigned long long pc8;
195ca58710fSKristen Carlson Accardi 	unsigned long long pc9;
196ca58710fSKristen Carlson Accardi 	unsigned long long pc10;
1970b2bb692SLen Brown 	unsigned long long pkg_wtd_core_c0;
1980b2bb692SLen Brown 	unsigned long long pkg_any_core_c0;
1990b2bb692SLen Brown 	unsigned long long pkg_any_gfxe_c0;
2000b2bb692SLen Brown 	unsigned long long pkg_both_core_gfxe_c0;
2019185e988SLen Brown 	long long gfx_rc6_ms;
20227d47356SLen Brown 	unsigned int gfx_mhz;
203c98d5d94SLen Brown 	unsigned int package_id;
204889facbeSLen Brown 	unsigned int energy_pkg;	/* MSR_PKG_ENERGY_STATUS */
205889facbeSLen Brown 	unsigned int energy_dram;	/* MSR_DRAM_ENERGY_STATUS */
206889facbeSLen Brown 	unsigned int energy_cores;	/* MSR_PP0_ENERGY_STATUS */
207889facbeSLen Brown 	unsigned int energy_gfx;	/* MSR_PP1_ENERGY_STATUS */
208889facbeSLen Brown 	unsigned int rapl_pkg_perf_status;	/* MSR_PKG_PERF_STATUS */
209889facbeSLen Brown 	unsigned int rapl_dram_perf_status;	/* MSR_DRAM_PERF_STATUS */
210889facbeSLen Brown 	unsigned int pkg_temp_c;
211*388e9c81SLen Brown 	unsigned long long counter[1];
212c98d5d94SLen Brown } *package_even, *package_odd;
213c98d5d94SLen Brown 
214c98d5d94SLen Brown #define ODD_COUNTERS thread_odd, core_odd, package_odd
215c98d5d94SLen Brown #define EVEN_COUNTERS thread_even, core_even, package_even
216c98d5d94SLen Brown 
217c98d5d94SLen Brown #define GET_THREAD(thread_base, thread_no, core_no, pkg_no) \
218c98d5d94SLen Brown 	(thread_base + (pkg_no) * topo.num_cores_per_pkg * \
219c98d5d94SLen Brown 		topo.num_threads_per_core + \
220c98d5d94SLen Brown 		(core_no) * topo.num_threads_per_core + (thread_no))
221c98d5d94SLen Brown #define GET_CORE(core_base, core_no, pkg_no) \
222c98d5d94SLen Brown 	(core_base + (pkg_no) * topo.num_cores_per_pkg + (core_no))
223c98d5d94SLen Brown #define GET_PKG(pkg_base, pkg_no) (pkg_base + pkg_no)
224c98d5d94SLen Brown 
225*388e9c81SLen Brown enum counter_scope {SCOPE_CPU, SCOPE_CORE, SCOPE_PACKAGE};
226*388e9c81SLen Brown enum counter_type {COUNTER_CYCLES, COUNTER_SECONDS};
227*388e9c81SLen Brown enum counter_format {FORMAT_RAW, FORMAT_DELTA, FORMAT_PERCENT};
228*388e9c81SLen Brown 
229*388e9c81SLen Brown struct msr_counter {
230*388e9c81SLen Brown 	unsigned int msr_num;
231*388e9c81SLen Brown 	char name[NAME_BYTES];
232*388e9c81SLen Brown 	unsigned int width;
233*388e9c81SLen Brown 	enum counter_type type;
234*388e9c81SLen Brown 	enum counter_format format;
235*388e9c81SLen Brown 	struct msr_counter *next;
236*388e9c81SLen Brown };
237*388e9c81SLen Brown 
238*388e9c81SLen Brown struct sys_counters {
239*388e9c81SLen Brown 	unsigned int thread_counter_bytes;
240*388e9c81SLen Brown 	unsigned int core_counter_bytes;
241*388e9c81SLen Brown 	unsigned int package_counter_bytes;
242*388e9c81SLen Brown 	struct msr_counter *tp;
243*388e9c81SLen Brown 	struct msr_counter *cp;
244*388e9c81SLen Brown 	struct msr_counter *pp;
245*388e9c81SLen Brown } sys;
246*388e9c81SLen Brown 
247c98d5d94SLen Brown struct system_summary {
248c98d5d94SLen Brown 	struct thread_data threads;
249c98d5d94SLen Brown 	struct core_data cores;
250c98d5d94SLen Brown 	struct pkg_data packages;
251*388e9c81SLen Brown } average;
252c98d5d94SLen Brown 
253c98d5d94SLen Brown 
254c98d5d94SLen Brown struct topo_params {
255c98d5d94SLen Brown 	int num_packages;
256103a8feaSLen Brown 	int num_cpus;
257c98d5d94SLen Brown 	int num_cores;
258c98d5d94SLen Brown 	int max_cpu_num;
259c98d5d94SLen Brown 	int num_cores_per_pkg;
260c98d5d94SLen Brown 	int num_threads_per_core;
261c98d5d94SLen Brown } topo;
262103a8feaSLen Brown 
263c98d5d94SLen Brown struct timeval tv_even, tv_odd, tv_delta;
264103a8feaSLen Brown 
265562a2d37SLen Brown int *irq_column_2_cpu;	/* /proc/interrupts column numbers */
266562a2d37SLen Brown int *irqs_per_cpu;		/* indexed by cpu_num */
267562a2d37SLen Brown 
268c98d5d94SLen Brown void setup_all_buffers(void);
269103a8feaSLen Brown 
270c98d5d94SLen Brown int cpu_is_not_present(int cpu)
271d15cf7c1SLen Brown {
272c98d5d94SLen Brown 	return !CPU_ISSET_S(cpu, cpu_present_setsize, cpu_present_set);
273c98d5d94SLen Brown }
274c98d5d94SLen Brown /*
275c98d5d94SLen Brown  * run func(thread, core, package) in topology order
276c98d5d94SLen Brown  * skip non-present cpus
277c98d5d94SLen Brown  */
278c98d5d94SLen Brown 
279c98d5d94SLen Brown int for_all_cpus(int (func)(struct thread_data *, struct core_data *, struct pkg_data *),
280c98d5d94SLen Brown 	struct thread_data *thread_base, struct core_data *core_base, struct pkg_data *pkg_base)
281c98d5d94SLen Brown {
282c98d5d94SLen Brown 	int retval, pkg_no, core_no, thread_no;
283c98d5d94SLen Brown 
284c98d5d94SLen Brown 	for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) {
285c98d5d94SLen Brown 		for (core_no = 0; core_no < topo.num_cores_per_pkg; ++core_no) {
286c98d5d94SLen Brown 			for (thread_no = 0; thread_no <
287c98d5d94SLen Brown 				topo.num_threads_per_core; ++thread_no) {
288c98d5d94SLen Brown 				struct thread_data *t;
289c98d5d94SLen Brown 				struct core_data *c;
290c98d5d94SLen Brown 				struct pkg_data *p;
291c98d5d94SLen Brown 
292c98d5d94SLen Brown 				t = GET_THREAD(thread_base, thread_no, core_no, pkg_no);
293c98d5d94SLen Brown 
294c98d5d94SLen Brown 				if (cpu_is_not_present(t->cpu_id))
295c98d5d94SLen Brown 					continue;
296c98d5d94SLen Brown 
297c98d5d94SLen Brown 				c = GET_CORE(core_base, core_no, pkg_no);
298c98d5d94SLen Brown 				p = GET_PKG(pkg_base, pkg_no);
299c98d5d94SLen Brown 
300c98d5d94SLen Brown 				retval = func(t, c, p);
301c98d5d94SLen Brown 				if (retval)
302c98d5d94SLen Brown 					return retval;
303c98d5d94SLen Brown 			}
304c98d5d94SLen Brown 		}
305c98d5d94SLen Brown 	}
306d15cf7c1SLen Brown 	return 0;
307d15cf7c1SLen Brown }
308d15cf7c1SLen Brown 
30988c3281fSLen Brown int cpu_migrate(int cpu)
31088c3281fSLen Brown {
311c98d5d94SLen Brown 	CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set);
312c98d5d94SLen Brown 	CPU_SET_S(cpu, cpu_affinity_setsize, cpu_affinity_set);
313c98d5d94SLen Brown 	if (sched_setaffinity(0, cpu_affinity_setsize, cpu_affinity_set) == -1)
31488c3281fSLen Brown 		return -1;
31588c3281fSLen Brown 	else
31688c3281fSLen Brown 		return 0;
31788c3281fSLen Brown }
31836229897SLen Brown int get_msr_fd(int cpu)
319103a8feaSLen Brown {
320103a8feaSLen Brown 	char pathname[32];
321103a8feaSLen Brown 	int fd;
322103a8feaSLen Brown 
32336229897SLen Brown 	fd = fd_percpu[cpu];
32436229897SLen Brown 
32536229897SLen Brown 	if (fd)
32636229897SLen Brown 		return fd;
32736229897SLen Brown 
328103a8feaSLen Brown 	sprintf(pathname, "/dev/cpu/%d/msr", cpu);
329103a8feaSLen Brown 	fd = open(pathname, O_RDONLY);
33015aaa346SLen Brown 	if (fd < 0)
33198481e79SLen Brown 		err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname);
332103a8feaSLen Brown 
33336229897SLen Brown 	fd_percpu[cpu] = fd;
33436229897SLen Brown 
33536229897SLen Brown 	return fd;
33636229897SLen Brown }
33736229897SLen Brown 
33836229897SLen Brown int get_msr(int cpu, off_t offset, unsigned long long *msr)
33936229897SLen Brown {
34036229897SLen Brown 	ssize_t retval;
34136229897SLen Brown 
34236229897SLen Brown 	retval = pread(get_msr_fd(cpu), msr, sizeof(*msr), offset);
34315aaa346SLen Brown 
34498481e79SLen Brown 	if (retval != sizeof *msr)
34536229897SLen Brown 		err(-1, "msr %d offset 0x%llx read failed", cpu, (unsigned long long)offset);
34615aaa346SLen Brown 
34715aaa346SLen Brown 	return 0;
348103a8feaSLen Brown }
349103a8feaSLen Brown 
350fc04cc67SLen Brown /*
351fc04cc67SLen Brown  * Example Format w/ field column widths:
352fc04cc67SLen Brown  *
353*388e9c81SLen Brown  *  Package    Core     CPU Avg_MHz Bzy_MHz TSC_MHz     IRQ   SMI   Busy% CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 ThreadC CoreTmp  CoreCnt PkgTmp  GFXMHz Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt PkgCnt
354562a2d37SLen Brown  * 12345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678
355fc04cc67SLen Brown  */
356fc04cc67SLen Brown 
357a829eb4dSLen Brown void print_header(void)
358103a8feaSLen Brown {
359*388e9c81SLen Brown 	struct msr_counter *mp;
360*388e9c81SLen Brown 
361103a8feaSLen Brown 	if (show_pkg)
3623d109de2SLen Brown 		outp += sprintf(outp, "\tPackage");
363103a8feaSLen Brown 	if (show_core)
3643d109de2SLen Brown 		outp += sprintf(outp, "\tCore");
365103a8feaSLen Brown 	if (show_cpu)
3663d109de2SLen Brown 		outp += sprintf(outp, "\tCPU");
367103a8feaSLen Brown 	if (has_aperf)
3683d109de2SLen Brown 		outp += sprintf(outp, "\tAvg_MHz");
369d7899447SLen Brown 	if (has_aperf)
3703d109de2SLen Brown 		outp += sprintf(outp, "\tBusy%%");
371fc04cc67SLen Brown 	if (has_aperf)
3723d109de2SLen Brown 		outp += sprintf(outp, "\tBzy_MHz");
3733d109de2SLen Brown 	outp += sprintf(outp, "\tTSC_MHz");
3741cc21f7bSLen Brown 
3758e180f3cSLen Brown 	if (extra_delta_offset32)
3763d109de2SLen Brown 		outp += sprintf(outp, "\tcount 0x%03X", extra_delta_offset32);
3778e180f3cSLen Brown 	if (extra_delta_offset64)
3783d109de2SLen Brown 		outp += sprintf(outp, "\tCOUNT 0x%03X", extra_delta_offset64);
3792f32edf1SLen Brown 	if (extra_msr_offset32)
3803d109de2SLen Brown 		outp += sprintf(outp, "\t         MSR 0x%03X", extra_msr_offset32);
3812f32edf1SLen Brown 	if (extra_msr_offset64)
3823d109de2SLen Brown 		outp += sprintf(outp, "\tMSR 0x%03X", extra_msr_offset64);
3831cc21f7bSLen Brown 
3841cc21f7bSLen Brown 	if (!debug)
3851cc21f7bSLen Brown 		goto done;
3861cc21f7bSLen Brown 
387562a2d37SLen Brown 	if (do_irq)
3883d109de2SLen Brown 		outp += sprintf(outp, "\tIRQ");
3891cc21f7bSLen Brown 	if (do_smi)
3903d109de2SLen Brown 		outp += sprintf(outp, "\tSMI");
3911cc21f7bSLen Brown 
392103a8feaSLen Brown 	if (do_nhm_cstates)
3933d109de2SLen Brown 		outp += sprintf(outp, "\tCPU%%c1");
394fb5d4327SDasaratharaman Chandramouli 	if (do_nhm_cstates && !do_slm_cstates && !do_knl_cstates)
3953d109de2SLen Brown 		outp += sprintf(outp, "\tCPU%%c3");
396103a8feaSLen Brown 	if (do_nhm_cstates)
3973d109de2SLen Brown 		outp += sprintf(outp, "\tCPU%%c6");
398103a8feaSLen Brown 	if (do_snb_cstates)
3993d109de2SLen Brown 		outp += sprintf(outp, "\tCPU%%c7");
400889facbeSLen Brown 
401*388e9c81SLen Brown 	for (mp = sys.tp; mp; mp = mp->next) {
402*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW) {
403*388e9c81SLen Brown 			if (mp->width == 64)
404*388e9c81SLen Brown 				outp += sprintf(outp, "\t%18.18s", mp->name);
405*388e9c81SLen Brown 			else
406*388e9c81SLen Brown 				outp += sprintf(outp, "\t%10.10s", mp->name);
407*388e9c81SLen Brown 		} else {
408*388e9c81SLen Brown 			outp += sprintf(outp, "\t%-7.7s", mp->name);
409*388e9c81SLen Brown 		}
410*388e9c81SLen Brown 	}
411*388e9c81SLen Brown 
412889facbeSLen Brown 	if (do_dts)
4133d109de2SLen Brown 		outp += sprintf(outp, "\tCoreTmp");
414*388e9c81SLen Brown 
415*388e9c81SLen Brown 	for (mp = sys.cp; mp; mp = mp->next) {
416*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW) {
417*388e9c81SLen Brown 			if (mp->width == 64)
418*388e9c81SLen Brown 				outp += sprintf(outp, "\t%18.18s", mp->name);
419*388e9c81SLen Brown 			else
420*388e9c81SLen Brown 				outp += sprintf(outp, "\t%10.10s", mp->name);
421*388e9c81SLen Brown 		} else {
422*388e9c81SLen Brown 			outp += sprintf(outp, "\t%-7.7s", mp->name);
423*388e9c81SLen Brown 		}
424*388e9c81SLen Brown 	}
425*388e9c81SLen Brown 
426889facbeSLen Brown 	if (do_ptm)
4273d109de2SLen Brown 		outp += sprintf(outp, "\tPkgTmp");
428889facbeSLen Brown 
429fdf676e5SLen Brown 	if (do_gfx_rc6_ms)
4303d109de2SLen Brown 		outp += sprintf(outp, "\tGFX%%rc6");
431fdf676e5SLen Brown 
43227d47356SLen Brown 	if (do_gfx_mhz)
4333d109de2SLen Brown 		outp += sprintf(outp, "\tGFXMHz");
43427d47356SLen Brown 
4350b2bb692SLen Brown 	if (do_skl_residency) {
4363d109de2SLen Brown 		outp += sprintf(outp, "\tTotl%%C0");
4373d109de2SLen Brown 		outp += sprintf(outp, "\tAny%%C0");
4383d109de2SLen Brown 		outp += sprintf(outp, "\tGFX%%C0");
4393d109de2SLen Brown 		outp += sprintf(outp, "\tCPUGFX%%");
4400b2bb692SLen Brown 	}
4410b2bb692SLen Brown 
442ee7e38e3SLen Brown 	if (do_pc2)
4433d109de2SLen Brown 		outp += sprintf(outp, "\tPkg%%pc2");
444ee7e38e3SLen Brown 	if (do_pc3)
4453d109de2SLen Brown 		outp += sprintf(outp, "\tPkg%%pc3");
446ee7e38e3SLen Brown 	if (do_pc6)
4473d109de2SLen Brown 		outp += sprintf(outp, "\tPkg%%pc6");
448ee7e38e3SLen Brown 	if (do_pc7)
4493d109de2SLen Brown 		outp += sprintf(outp, "\tPkg%%pc7");
450ca58710fSKristen Carlson Accardi 	if (do_c8_c9_c10) {
4513d109de2SLen Brown 		outp += sprintf(outp, "\tPkg%%pc8");
4523d109de2SLen Brown 		outp += sprintf(outp, "\tPkg%%pc9");
4533d109de2SLen Brown 		outp += sprintf(outp, "\tPk%%pc10");
454ca58710fSKristen Carlson Accardi 	}
455103a8feaSLen Brown 
4565c56be9aSDirk Brandewie 	if (do_rapl && !rapl_joules) {
457889facbeSLen Brown 		if (do_rapl & RAPL_PKG)
4583d109de2SLen Brown 			outp += sprintf(outp, "\tPkgWatt");
4599148494cSJacob Pan 		if (do_rapl & RAPL_CORES_ENERGY_STATUS)
4603d109de2SLen Brown 			outp += sprintf(outp, "\tCorWatt");
461889facbeSLen Brown 		if (do_rapl & RAPL_GFX)
4623d109de2SLen Brown 			outp += sprintf(outp, "\tGFXWatt");
463889facbeSLen Brown 		if (do_rapl & RAPL_DRAM)
4643d109de2SLen Brown 			outp += sprintf(outp, "\tRAMWatt");
465889facbeSLen Brown 		if (do_rapl & RAPL_PKG_PERF_STATUS)
4663d109de2SLen Brown 			outp += sprintf(outp, "\tPKG_%%");
467889facbeSLen Brown 		if (do_rapl & RAPL_DRAM_PERF_STATUS)
4683d109de2SLen Brown 			outp += sprintf(outp, "\tRAM_%%");
469d7899447SLen Brown 	} else if (do_rapl && rapl_joules) {
4705c56be9aSDirk Brandewie 		if (do_rapl & RAPL_PKG)
4713d109de2SLen Brown 			outp += sprintf(outp, "\tPkg_J");
4729148494cSJacob Pan 		if (do_rapl & RAPL_CORES_ENERGY_STATUS)
4733d109de2SLen Brown 			outp += sprintf(outp, "\tCor_J");
4745c56be9aSDirk Brandewie 		if (do_rapl & RAPL_GFX)
4753d109de2SLen Brown 			outp += sprintf(outp, "\tGFX_J");
4765c56be9aSDirk Brandewie 		if (do_rapl & RAPL_DRAM)
4773d109de2SLen Brown 			outp += sprintf(outp, "\tRAM_J");
4785c56be9aSDirk Brandewie 		if (do_rapl & RAPL_PKG_PERF_STATUS)
4793d109de2SLen Brown 			outp += sprintf(outp, "\tPKG_%%");
4805c56be9aSDirk Brandewie 		if (do_rapl & RAPL_DRAM_PERF_STATUS)
4813d109de2SLen Brown 			outp += sprintf(outp, "\tRAM_%%");
4825c56be9aSDirk Brandewie 	}
483*388e9c81SLen Brown 	for (mp = sys.pp; mp; mp = mp->next) {
484*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW) {
485*388e9c81SLen Brown 			if (mp->width == 64)
486*388e9c81SLen Brown 				outp += sprintf(outp, "\t%18.18s", mp->name);
487*388e9c81SLen Brown 			else
488*388e9c81SLen Brown 				outp += sprintf(outp, "\t%10.10s", mp->name);
489*388e9c81SLen Brown 		} else {
490*388e9c81SLen Brown 			outp += sprintf(outp, "\t%-7.7s", mp->name);
491*388e9c81SLen Brown 		}
492*388e9c81SLen Brown 	}
493*388e9c81SLen Brown 
4941cc21f7bSLen Brown done:
495c98d5d94SLen Brown 	outp += sprintf(outp, "\n");
496103a8feaSLen Brown }
497103a8feaSLen Brown 
498c98d5d94SLen Brown int dump_counters(struct thread_data *t, struct core_data *c,
499c98d5d94SLen Brown 	struct pkg_data *p)
500103a8feaSLen Brown {
501*388e9c81SLen Brown 	int i;
502*388e9c81SLen Brown 	struct msr_counter *mp;
503*388e9c81SLen Brown 
5043b4d5c7fSAndy Shevchenko 	outp += sprintf(outp, "t %p, c %p, p %p\n", t, c, p);
505c98d5d94SLen Brown 
506c98d5d94SLen Brown 	if (t) {
5073b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "CPU: %d flags 0x%x\n",
5083b4d5c7fSAndy Shevchenko 			t->cpu_id, t->flags);
5093b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "TSC: %016llX\n", t->tsc);
5103b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "aperf: %016llX\n", t->aperf);
5113b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "mperf: %016llX\n", t->mperf);
5123b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "c1: %016llX\n", t->c1);
5133b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "msr0x%x: %08llX\n",
5148e180f3cSLen Brown 			extra_delta_offset32, t->extra_delta32);
5153b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "msr0x%x: %016llX\n",
5168e180f3cSLen Brown 			extra_delta_offset64, t->extra_delta64);
5173b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "msr0x%x: %08llX\n",
5182f32edf1SLen Brown 			extra_msr_offset32, t->extra_msr32);
5193b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "msr0x%x: %016llX\n",
5202f32edf1SLen Brown 			extra_msr_offset64, t->extra_msr64);
521562a2d37SLen Brown 		if (do_irq)
522562a2d37SLen Brown 			outp += sprintf(outp, "IRQ: %08X\n", t->irq_count);
5231ed51011SLen Brown 		if (do_smi)
5243b4d5c7fSAndy Shevchenko 			outp += sprintf(outp, "SMI: %08X\n", t->smi_count);
525*388e9c81SLen Brown 
526*388e9c81SLen Brown 		for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
527*388e9c81SLen Brown 			outp += sprintf(outp, "tADDED [%d] msr0x%x: %08llX\n",
528*388e9c81SLen Brown 				i, mp->msr_num, t->counter[i]);
529*388e9c81SLen Brown 		}
530103a8feaSLen Brown 	}
531103a8feaSLen Brown 
532c98d5d94SLen Brown 	if (c) {
5333b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "core: %d\n", c->core_id);
5343b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "c3: %016llX\n", c->c3);
5353b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "c6: %016llX\n", c->c6);
5363b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "c7: %016llX\n", c->c7);
5373b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "DTS: %dC\n", c->core_temp_c);
538*388e9c81SLen Brown 
539*388e9c81SLen Brown 		for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
540*388e9c81SLen Brown 			outp += sprintf(outp, "cADDED [%d] msr0x%x: %08llX\n",
541*388e9c81SLen Brown 				i, mp->msr_num, c->counter[i]);
542*388e9c81SLen Brown 		}
543c98d5d94SLen Brown 	}
544103a8feaSLen Brown 
545c98d5d94SLen Brown 	if (p) {
5463b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "package: %d\n", p->package_id);
5470b2bb692SLen Brown 
5480b2bb692SLen Brown 		outp += sprintf(outp, "Weighted cores: %016llX\n", p->pkg_wtd_core_c0);
5490b2bb692SLen Brown 		outp += sprintf(outp, "Any cores: %016llX\n", p->pkg_any_core_c0);
5500b2bb692SLen Brown 		outp += sprintf(outp, "Any GFX: %016llX\n", p->pkg_any_gfxe_c0);
5510b2bb692SLen Brown 		outp += sprintf(outp, "CPU + GFX: %016llX\n", p->pkg_both_core_gfxe_c0);
5520b2bb692SLen Brown 
5533b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "pc2: %016llX\n", p->pc2);
554ee7e38e3SLen Brown 		if (do_pc3)
5553b4d5c7fSAndy Shevchenko 			outp += sprintf(outp, "pc3: %016llX\n", p->pc3);
556ee7e38e3SLen Brown 		if (do_pc6)
5573b4d5c7fSAndy Shevchenko 			outp += sprintf(outp, "pc6: %016llX\n", p->pc6);
558ee7e38e3SLen Brown 		if (do_pc7)
5593b4d5c7fSAndy Shevchenko 			outp += sprintf(outp, "pc7: %016llX\n", p->pc7);
5603b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "pc8: %016llX\n", p->pc8);
5613b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "pc9: %016llX\n", p->pc9);
5623b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "pc10: %016llX\n", p->pc10);
5633b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "Joules PKG: %0X\n", p->energy_pkg);
5643b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "Joules COR: %0X\n", p->energy_cores);
5653b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "Joules GFX: %0X\n", p->energy_gfx);
5663b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "Joules RAM: %0X\n", p->energy_dram);
5673b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "Throttle PKG: %0X\n",
5683b4d5c7fSAndy Shevchenko 			p->rapl_pkg_perf_status);
5693b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "Throttle RAM: %0X\n",
5703b4d5c7fSAndy Shevchenko 			p->rapl_dram_perf_status);
5713b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "PTM: %dC\n", p->pkg_temp_c);
572*388e9c81SLen Brown 
573*388e9c81SLen Brown 		for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
574*388e9c81SLen Brown 			outp += sprintf(outp, "pADDED [%d] msr0x%x: %08llX\n",
575*388e9c81SLen Brown 				i, mp->msr_num, p->counter[i]);
576*388e9c81SLen Brown 		}
577c98d5d94SLen Brown 	}
5783b4d5c7fSAndy Shevchenko 
5793b4d5c7fSAndy Shevchenko 	outp += sprintf(outp, "\n");
5803b4d5c7fSAndy Shevchenko 
581c98d5d94SLen Brown 	return 0;
582103a8feaSLen Brown }
583103a8feaSLen Brown 
584e23da037SLen Brown /*
585e23da037SLen Brown  * column formatting convention & formats
586e23da037SLen Brown  */
587c98d5d94SLen Brown int format_counters(struct thread_data *t, struct core_data *c,
588c98d5d94SLen Brown 	struct pkg_data *p)
589103a8feaSLen Brown {
590103a8feaSLen Brown 	double interval_float;
591fc04cc67SLen Brown 	char *fmt8;
592*388e9c81SLen Brown 	int i;
593*388e9c81SLen Brown 	struct msr_counter *mp;
594103a8feaSLen Brown 
595c98d5d94SLen Brown 	 /* if showing only 1st thread in core and this isn't one, bail out */
596c98d5d94SLen Brown 	if (show_core_only && !(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
597c98d5d94SLen Brown 		return 0;
598c98d5d94SLen Brown 
599c98d5d94SLen Brown 	 /* if showing only 1st thread in pkg and this isn't one, bail out */
600c98d5d94SLen Brown 	if (show_pkg_only && !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
601c98d5d94SLen Brown 		return 0;
602c98d5d94SLen Brown 
603103a8feaSLen Brown 	interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;
604103a8feaSLen Brown 
605c98d5d94SLen Brown 	/* topo columns, print blanks on 1st (average) line */
606c98d5d94SLen Brown 	if (t == &average.threads) {
607103a8feaSLen Brown 		if (show_pkg)
6083d109de2SLen Brown 			outp += sprintf(outp, "\t-");
609103a8feaSLen Brown 		if (show_core)
6103d109de2SLen Brown 			outp += sprintf(outp, "\t-");
611103a8feaSLen Brown 		if (show_cpu)
6123d109de2SLen Brown 			outp += sprintf(outp, "\t-");
613103a8feaSLen Brown 	} else {
614c98d5d94SLen Brown 		if (show_pkg) {
615c98d5d94SLen Brown 			if (p)
6163d109de2SLen Brown 				outp += sprintf(outp, "\t%d", p->package_id);
617c98d5d94SLen Brown 			else
6183d109de2SLen Brown 				outp += sprintf(outp, "\t-");
619c98d5d94SLen Brown 		}
620c98d5d94SLen Brown 		if (show_core) {
621c98d5d94SLen Brown 			if (c)
6223d109de2SLen Brown 				outp += sprintf(outp, "\t%d", c->core_id);
623c98d5d94SLen Brown 			else
6243d109de2SLen Brown 				outp += sprintf(outp, "\t-");
625c98d5d94SLen Brown 		}
626103a8feaSLen Brown 		if (show_cpu)
6273d109de2SLen Brown 			outp += sprintf(outp, "\t%d", t->cpu_id);
628103a8feaSLen Brown 	}
629fc04cc67SLen Brown 
630d7899447SLen Brown 	/* Avg_MHz */
631fc04cc67SLen Brown 	if (has_aperf)
6323d109de2SLen Brown 		outp += sprintf(outp, "\t%.0f",
633fc04cc67SLen Brown 			1.0 / units * t->aperf / interval_float);
634fc04cc67SLen Brown 
63575d2e44eSLen Brown 	/* Busy% */
636ba3dec99SLen Brown 	if (has_aperf)
6373d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * t->mperf/t->tsc/tsc_tweak);
638103a8feaSLen Brown 
639d7899447SLen Brown 	/* Bzy_MHz */
64021ed5574SLen Brown 	if (has_aperf) {
64121ed5574SLen Brown 		if (has_base_hz)
6423d109de2SLen Brown 			outp += sprintf(outp, "\t%.0f", base_hz / units * t->aperf / t->mperf);
64321ed5574SLen Brown 		else
6443d109de2SLen Brown 			outp += sprintf(outp, "\t%.0f",
64521ed5574SLen Brown 				1.0 * t->tsc / units * t->aperf / t->mperf / interval_float);
64621ed5574SLen Brown 	}
647103a8feaSLen Brown 
648d7899447SLen Brown 	/* TSC_MHz */
6493d109de2SLen Brown 	outp += sprintf(outp, "\t%.0f", 1.0 * t->tsc/units/interval_float);
650103a8feaSLen Brown 
6518e180f3cSLen Brown 	/* delta */
6528e180f3cSLen Brown 	if (extra_delta_offset32)
6533d109de2SLen Brown 		outp += sprintf(outp, "\t%11llu", t->extra_delta32);
6548e180f3cSLen Brown 
6558e180f3cSLen Brown 	/* DELTA */
6568e180f3cSLen Brown 	if (extra_delta_offset64)
6573d109de2SLen Brown 		outp += sprintf(outp, "\t%11llu", t->extra_delta64);
6582f32edf1SLen Brown 	/* msr */
6592f32edf1SLen Brown 	if (extra_msr_offset32)
6603d109de2SLen Brown 		outp += sprintf(outp, "\t0x%08llx", t->extra_msr32);
6612f32edf1SLen Brown 
662130ff304SLen Brown 	/* MSR */
6632f32edf1SLen Brown 	if (extra_msr_offset64)
6643d109de2SLen Brown 		outp += sprintf(outp, "\t0x%016llx", t->extra_msr64);
665130ff304SLen Brown 
6661cc21f7bSLen Brown 	if (!debug)
6671cc21f7bSLen Brown 		goto done;
6681cc21f7bSLen Brown 
669562a2d37SLen Brown 	/* IRQ */
670562a2d37SLen Brown 	if (do_irq)
6713d109de2SLen Brown 		outp += sprintf(outp, "\t%d", t->irq_count);
672562a2d37SLen Brown 
6731cc21f7bSLen Brown 	/* SMI */
6741cc21f7bSLen Brown 	if (do_smi)
6753d109de2SLen Brown 		outp += sprintf(outp, "\t%d", t->smi_count);
6761cc21f7bSLen Brown 
677ba3dec99SLen Brown 	if (do_nhm_cstates)
6783d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * t->c1/t->tsc);
679c98d5d94SLen Brown 
680c98d5d94SLen Brown 	/* print per-core data only for 1st thread in core */
681c98d5d94SLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
682c98d5d94SLen Brown 		goto done;
683c98d5d94SLen Brown 
684fb5d4327SDasaratharaman Chandramouli 	if (do_nhm_cstates && !do_slm_cstates && !do_knl_cstates)
6853d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * c->c3/t->tsc);
686103a8feaSLen Brown 	if (do_nhm_cstates)
6873d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * c->c6/t->tsc);
688103a8feaSLen Brown 	if (do_snb_cstates)
6893d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * c->c7/t->tsc);
690c98d5d94SLen Brown 
691*388e9c81SLen Brown 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
692*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW) {
693*388e9c81SLen Brown 			if (mp->width == 32)
694*388e9c81SLen Brown 				outp += sprintf(outp, "\t0x%08lx", (unsigned long) t->counter[i]);
695*388e9c81SLen Brown 			else
696*388e9c81SLen Brown 				outp += sprintf(outp, "\t0x%016llx", t->counter[i]);
697*388e9c81SLen Brown 		} else if (mp->format == FORMAT_DELTA) {
698*388e9c81SLen Brown 			outp += sprintf(outp, "\t%8lld", t->counter[i]);
699*388e9c81SLen Brown 		} else if (mp->format == FORMAT_PERCENT) {
700*388e9c81SLen Brown 			outp += sprintf(outp, "\t%.2f", 100.0 * t->counter[i]/t->tsc);
701*388e9c81SLen Brown 		}
702*388e9c81SLen Brown 	}
703*388e9c81SLen Brown 
704*388e9c81SLen Brown 
705889facbeSLen Brown 	if (do_dts)
7063d109de2SLen Brown 		outp += sprintf(outp, "\t%d", c->core_temp_c);
707889facbeSLen Brown 
708*388e9c81SLen Brown 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
709*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW) {
710*388e9c81SLen Brown 			if (mp->width == 32)
711*388e9c81SLen Brown 				outp += sprintf(outp, "\t0x%08lx", (unsigned long) c->counter[i]);
712*388e9c81SLen Brown 			else
713*388e9c81SLen Brown 				outp += sprintf(outp, "\t0x%016llx", c->counter[i]);
714*388e9c81SLen Brown 		} else if (mp->format == FORMAT_DELTA) {
715*388e9c81SLen Brown 			outp += sprintf(outp, "\t%8lld", c->counter[i]);
716*388e9c81SLen Brown 		} else if (mp->format == FORMAT_PERCENT) {
717*388e9c81SLen Brown 			outp += sprintf(outp, "\t%.2f", 100.0 * c->counter[i]/t->tsc);
718*388e9c81SLen Brown 		}
719*388e9c81SLen Brown 	}
720*388e9c81SLen Brown 
721c98d5d94SLen Brown 	/* print per-package data only for 1st core in package */
722c98d5d94SLen Brown 	if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
723c98d5d94SLen Brown 		goto done;
724c98d5d94SLen Brown 
7250b2bb692SLen Brown 	/* PkgTmp */
726889facbeSLen Brown 	if (do_ptm)
7273d109de2SLen Brown 		outp += sprintf(outp, "\t%d", p->pkg_temp_c);
728889facbeSLen Brown 
729fdf676e5SLen Brown 	/* GFXrc6 */
7309185e988SLen Brown 	if (do_gfx_rc6_ms) {
731ba3dec99SLen Brown 		if (p->gfx_rc6_ms == -1) {	/* detect GFX counter reset */
7323d109de2SLen Brown 			outp += sprintf(outp, "\t**.**");
7339185e988SLen Brown 		} else {
7343d109de2SLen Brown 			outp += sprintf(outp, "\t%.2f",
7359185e988SLen Brown 				p->gfx_rc6_ms / 10.0 / interval_float);
7369185e988SLen Brown 		}
7379185e988SLen Brown 	}
738fdf676e5SLen Brown 
73927d47356SLen Brown 	/* GFXMHz */
74027d47356SLen Brown 	if (do_gfx_mhz)
7413d109de2SLen Brown 		outp += sprintf(outp, "\t%d", p->gfx_mhz);
74227d47356SLen Brown 
7430b2bb692SLen Brown 	/* Totl%C0, Any%C0 GFX%C0 CPUGFX% */
7440b2bb692SLen Brown 	if (do_skl_residency) {
7453d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * p->pkg_wtd_core_c0/t->tsc);
7463d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * p->pkg_any_core_c0/t->tsc);
7473d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * p->pkg_any_gfxe_c0/t->tsc);
7483d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * p->pkg_both_core_gfxe_c0/t->tsc);
7490b2bb692SLen Brown 	}
7500b2bb692SLen Brown 
751ee7e38e3SLen Brown 	if (do_pc2)
7523d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * p->pc2/t->tsc);
753ee7e38e3SLen Brown 	if (do_pc3)
7543d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * p->pc3/t->tsc);
755ee7e38e3SLen Brown 	if (do_pc6)
7563d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * p->pc6/t->tsc);
757ee7e38e3SLen Brown 	if (do_pc7)
7583d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * p->pc7/t->tsc);
759ca58710fSKristen Carlson Accardi 	if (do_c8_c9_c10) {
7603d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * p->pc8/t->tsc);
7613d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * p->pc9/t->tsc);
7623d109de2SLen Brown 		outp += sprintf(outp, "\t%.2f", 100.0 * p->pc10/t->tsc);
763ca58710fSKristen Carlson Accardi 	}
764889facbeSLen Brown 
765889facbeSLen Brown 	/*
766889facbeSLen Brown  	 * If measurement interval exceeds minimum RAPL Joule Counter range,
767889facbeSLen Brown  	 * indicate that results are suspect by printing "**" in fraction place.
768889facbeSLen Brown  	 */
769fc04cc67SLen Brown 	if (interval_float < rapl_joule_counter_range)
7703d109de2SLen Brown 		fmt8 = "\t%.2f";
771fc04cc67SLen Brown 	else
772fc04cc67SLen Brown 		fmt8 = "%6.0f**";
773889facbeSLen Brown 
7745c56be9aSDirk Brandewie 	if (do_rapl && !rapl_joules) {
775889facbeSLen Brown 		if (do_rapl & RAPL_PKG)
776fc04cc67SLen Brown 			outp += sprintf(outp, fmt8, p->energy_pkg * rapl_energy_units / interval_float);
7779148494cSJacob Pan 		if (do_rapl & RAPL_CORES_ENERGY_STATUS)
778fc04cc67SLen Brown 			outp += sprintf(outp, fmt8, p->energy_cores * rapl_energy_units / interval_float);
779889facbeSLen Brown 		if (do_rapl & RAPL_GFX)
780fc04cc67SLen Brown 			outp += sprintf(outp, fmt8, p->energy_gfx * rapl_energy_units / interval_float);
781889facbeSLen Brown 		if (do_rapl & RAPL_DRAM)
78240ee8e3bSAndrey Semin 			outp += sprintf(outp, fmt8, p->energy_dram * rapl_dram_energy_units / interval_float);
783889facbeSLen Brown 		if (do_rapl & RAPL_PKG_PERF_STATUS)
784fc04cc67SLen Brown 			outp += sprintf(outp, fmt8, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float);
785889facbeSLen Brown 		if (do_rapl & RAPL_DRAM_PERF_STATUS)
786fc04cc67SLen Brown 			outp += sprintf(outp, fmt8, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float);
787d7899447SLen Brown 	} else if (do_rapl && rapl_joules) {
7885c56be9aSDirk Brandewie 		if (do_rapl & RAPL_PKG)
789fc04cc67SLen Brown 			outp += sprintf(outp, fmt8,
7905c56be9aSDirk Brandewie 					p->energy_pkg * rapl_energy_units);
7915c56be9aSDirk Brandewie 		if (do_rapl & RAPL_CORES)
792fc04cc67SLen Brown 			outp += sprintf(outp, fmt8,
7935c56be9aSDirk Brandewie 					p->energy_cores * rapl_energy_units);
7945c56be9aSDirk Brandewie 		if (do_rapl & RAPL_GFX)
795fc04cc67SLen Brown 			outp += sprintf(outp, fmt8,
7965c56be9aSDirk Brandewie 					p->energy_gfx * rapl_energy_units);
7975c56be9aSDirk Brandewie 		if (do_rapl & RAPL_DRAM)
798fc04cc67SLen Brown 			outp += sprintf(outp, fmt8,
79940ee8e3bSAndrey Semin 					p->energy_dram * rapl_dram_energy_units);
8005c56be9aSDirk Brandewie 		if (do_rapl & RAPL_PKG_PERF_STATUS)
801fc04cc67SLen Brown 			outp += sprintf(outp, fmt8, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float);
8025c56be9aSDirk Brandewie 		if (do_rapl & RAPL_DRAM_PERF_STATUS)
803fc04cc67SLen Brown 			outp += sprintf(outp, fmt8, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float);
8045c56be9aSDirk Brandewie 	}
805*388e9c81SLen Brown 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
806*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW) {
807*388e9c81SLen Brown 			if (mp->width == 32)
808*388e9c81SLen Brown 				outp += sprintf(outp, "\t0x%08lx", (unsigned long) p->counter[i]);
809*388e9c81SLen Brown 			else
810*388e9c81SLen Brown 				outp += sprintf(outp, "\t0x%016llx", p->counter[i]);
811*388e9c81SLen Brown 		} else if (mp->format == FORMAT_DELTA) {
812*388e9c81SLen Brown 			outp += sprintf(outp, "\t%8lld", p->counter[i]);
813*388e9c81SLen Brown 		} else if (mp->format == FORMAT_PERCENT) {
814*388e9c81SLen Brown 			outp += sprintf(outp, "\t%.2f", 100.0 * p->counter[i]/t->tsc);
815*388e9c81SLen Brown 		}
816*388e9c81SLen Brown 	}
817*388e9c81SLen Brown 
818c98d5d94SLen Brown done:
819c98d5d94SLen Brown 	outp += sprintf(outp, "\n");
820c98d5d94SLen Brown 
821c98d5d94SLen Brown 	return 0;
822103a8feaSLen Brown }
823103a8feaSLen Brown 
824b7d8c148SLen Brown void flush_output_stdout(void)
825103a8feaSLen Brown {
826b7d8c148SLen Brown 	FILE *filep;
827b7d8c148SLen Brown 
828b7d8c148SLen Brown 	if (outf == stderr)
829b7d8c148SLen Brown 		filep = stdout;
830b7d8c148SLen Brown 	else
831b7d8c148SLen Brown 		filep = outf;
832b7d8c148SLen Brown 
833b7d8c148SLen Brown 	fputs(output_buffer, filep);
834b7d8c148SLen Brown 	fflush(filep);
835b7d8c148SLen Brown 
836c98d5d94SLen Brown 	outp = output_buffer;
837c98d5d94SLen Brown }
838b7d8c148SLen Brown void flush_output_stderr(void)
839c98d5d94SLen Brown {
840b7d8c148SLen Brown 	fputs(output_buffer, outf);
841b7d8c148SLen Brown 	fflush(outf);
842c98d5d94SLen Brown 	outp = output_buffer;
843c98d5d94SLen Brown }
844c98d5d94SLen Brown void format_all_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
845c98d5d94SLen Brown {
846e23da037SLen Brown 	static int printed;
847103a8feaSLen Brown 
848e23da037SLen Brown 	if (!printed || !summary_only)
849103a8feaSLen Brown 		print_header();
850103a8feaSLen Brown 
851c98d5d94SLen Brown 	if (topo.num_cpus > 1)
852c98d5d94SLen Brown 		format_counters(&average.threads, &average.cores,
853c98d5d94SLen Brown 			&average.packages);
854103a8feaSLen Brown 
855e23da037SLen Brown 	printed = 1;
856e23da037SLen Brown 
857e23da037SLen Brown 	if (summary_only)
858e23da037SLen Brown 		return;
859e23da037SLen Brown 
860c98d5d94SLen Brown 	for_all_cpus(format_counters, t, c, p);
861103a8feaSLen Brown }
862103a8feaSLen Brown 
863889facbeSLen Brown #define DELTA_WRAP32(new, old)			\
864889facbeSLen Brown 	if (new > old) {			\
865889facbeSLen Brown 		old = new - old;		\
866889facbeSLen Brown 	} else {				\
867889facbeSLen Brown 		old = 0x100000000 + new - old;	\
868889facbeSLen Brown 	}
869889facbeSLen Brown 
870ba3dec99SLen Brown int
871c98d5d94SLen Brown delta_package(struct pkg_data *new, struct pkg_data *old)
872103a8feaSLen Brown {
873*388e9c81SLen Brown 	int i;
874*388e9c81SLen Brown 	struct msr_counter *mp;
8750b2bb692SLen Brown 
8760b2bb692SLen Brown 	if (do_skl_residency) {
8770b2bb692SLen Brown 		old->pkg_wtd_core_c0 = new->pkg_wtd_core_c0 - old->pkg_wtd_core_c0;
8780b2bb692SLen Brown 		old->pkg_any_core_c0 = new->pkg_any_core_c0 - old->pkg_any_core_c0;
8790b2bb692SLen Brown 		old->pkg_any_gfxe_c0 = new->pkg_any_gfxe_c0 - old->pkg_any_gfxe_c0;
8800b2bb692SLen Brown 		old->pkg_both_core_gfxe_c0 = new->pkg_both_core_gfxe_c0 - old->pkg_both_core_gfxe_c0;
8810b2bb692SLen Brown 	}
882c98d5d94SLen Brown 	old->pc2 = new->pc2 - old->pc2;
883ee7e38e3SLen Brown 	if (do_pc3)
884c98d5d94SLen Brown 		old->pc3 = new->pc3 - old->pc3;
885ee7e38e3SLen Brown 	if (do_pc6)
886c98d5d94SLen Brown 		old->pc6 = new->pc6 - old->pc6;
887ee7e38e3SLen Brown 	if (do_pc7)
888c98d5d94SLen Brown 		old->pc7 = new->pc7 - old->pc7;
889ca58710fSKristen Carlson Accardi 	old->pc8 = new->pc8 - old->pc8;
890ca58710fSKristen Carlson Accardi 	old->pc9 = new->pc9 - old->pc9;
891ca58710fSKristen Carlson Accardi 	old->pc10 = new->pc10 - old->pc10;
892889facbeSLen Brown 	old->pkg_temp_c = new->pkg_temp_c;
893889facbeSLen Brown 
8949185e988SLen Brown 	/* flag an error when rc6 counter resets/wraps */
8959185e988SLen Brown 	if (old->gfx_rc6_ms >  new->gfx_rc6_ms)
8969185e988SLen Brown 		old->gfx_rc6_ms = -1;
8979185e988SLen Brown 	else
898fdf676e5SLen Brown 		old->gfx_rc6_ms = new->gfx_rc6_ms - old->gfx_rc6_ms;
8999185e988SLen Brown 
90027d47356SLen Brown 	old->gfx_mhz = new->gfx_mhz;
90127d47356SLen Brown 
902889facbeSLen Brown 	DELTA_WRAP32(new->energy_pkg, old->energy_pkg);
903889facbeSLen Brown 	DELTA_WRAP32(new->energy_cores, old->energy_cores);
904889facbeSLen Brown 	DELTA_WRAP32(new->energy_gfx, old->energy_gfx);
905889facbeSLen Brown 	DELTA_WRAP32(new->energy_dram, old->energy_dram);
906889facbeSLen Brown 	DELTA_WRAP32(new->rapl_pkg_perf_status, old->rapl_pkg_perf_status);
907889facbeSLen Brown 	DELTA_WRAP32(new->rapl_dram_perf_status, old->rapl_dram_perf_status);
908ba3dec99SLen Brown 
909*388e9c81SLen Brown 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
910*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
911*388e9c81SLen Brown 			old->counter[i] = new->counter[i];
912*388e9c81SLen Brown 		else
913*388e9c81SLen Brown 			old->counter[i] = new->counter[i] - old->counter[i];
914*388e9c81SLen Brown 	}
915*388e9c81SLen Brown 
916ba3dec99SLen Brown 	return 0;
917103a8feaSLen Brown }
918103a8feaSLen Brown 
919c98d5d94SLen Brown void
920c98d5d94SLen Brown delta_core(struct core_data *new, struct core_data *old)
921c98d5d94SLen Brown {
922*388e9c81SLen Brown 	int i;
923*388e9c81SLen Brown 	struct msr_counter *mp;
924*388e9c81SLen Brown 
925c98d5d94SLen Brown 	old->c3 = new->c3 - old->c3;
926c98d5d94SLen Brown 	old->c6 = new->c6 - old->c6;
927c98d5d94SLen Brown 	old->c7 = new->c7 - old->c7;
928889facbeSLen Brown 	old->core_temp_c = new->core_temp_c;
929*388e9c81SLen Brown 
930*388e9c81SLen Brown 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
931*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
932*388e9c81SLen Brown 			old->counter[i] = new->counter[i];
933*388e9c81SLen Brown 		else
934*388e9c81SLen Brown 			old->counter[i] = new->counter[i] - old->counter[i];
935*388e9c81SLen Brown 	}
936103a8feaSLen Brown }
937c98d5d94SLen Brown 
938c3ae331dSLen Brown /*
939c3ae331dSLen Brown  * old = new - old
940c3ae331dSLen Brown  */
941ba3dec99SLen Brown int
942c98d5d94SLen Brown delta_thread(struct thread_data *new, struct thread_data *old,
943c98d5d94SLen Brown 	struct core_data *core_delta)
944c98d5d94SLen Brown {
945*388e9c81SLen Brown 	int i;
946*388e9c81SLen Brown 	struct msr_counter *mp;
947*388e9c81SLen Brown 
948c98d5d94SLen Brown 	old->tsc = new->tsc - old->tsc;
949c98d5d94SLen Brown 
950103a8feaSLen Brown 	/* check for TSC < 1 Mcycles over interval */
951b2c95d90SJosh Triplett 	if (old->tsc < (1000 * 1000))
952b2c95d90SJosh Triplett 		errx(-3, "Insanely slow TSC rate, TSC stops in idle?\n"
953b2c95d90SJosh Triplett 		     "You can disable all c-states by booting with \"idle=poll\"\n"
954b2c95d90SJosh Triplett 		     "or just the deep ones with \"processor.max_cstate=1\"");
955103a8feaSLen Brown 
956c98d5d94SLen Brown 	old->c1 = new->c1 - old->c1;
957c98d5d94SLen Brown 
958a729617cSLen Brown 	if (has_aperf) {
959c98d5d94SLen Brown 		if ((new->aperf > old->aperf) && (new->mperf > old->mperf)) {
960c98d5d94SLen Brown 			old->aperf = new->aperf - old->aperf;
961c98d5d94SLen Brown 			old->mperf = new->mperf - old->mperf;
962c98d5d94SLen Brown 		} else {
963ba3dec99SLen Brown 			return -1;
964103a8feaSLen Brown 		}
965a729617cSLen Brown 	}
966103a8feaSLen Brown 
967c98d5d94SLen Brown 
968144b44b1SLen Brown 	if (use_c1_residency_msr) {
969144b44b1SLen Brown 		/*
970144b44b1SLen Brown 		 * Some models have a dedicated C1 residency MSR,
971144b44b1SLen Brown 		 * which should be more accurate than the derivation below.
972144b44b1SLen Brown 		 */
973144b44b1SLen Brown 	} else {
974103a8feaSLen Brown 		/*
975c3ae331dSLen Brown 		 * As counter collection is not atomic,
976c3ae331dSLen Brown 		 * it is possible for mperf's non-halted cycles + idle states
977103a8feaSLen Brown 		 * to exceed TSC's all cycles: show c1 = 0% in that case.
978103a8feaSLen Brown 		 */
979c3ae331dSLen Brown 		if ((old->mperf + core_delta->c3 + core_delta->c6 + core_delta->c7) > old->tsc)
980c98d5d94SLen Brown 			old->c1 = 0;
981c98d5d94SLen Brown 		else {
982c98d5d94SLen Brown 			/* normal case, derive c1 */
983c98d5d94SLen Brown 			old->c1 = old->tsc - old->mperf - core_delta->c3
984c98d5d94SLen Brown 				- core_delta->c6 - core_delta->c7;
985c98d5d94SLen Brown 		}
986144b44b1SLen Brown 	}
987c3ae331dSLen Brown 
988c98d5d94SLen Brown 	if (old->mperf == 0) {
989b7d8c148SLen Brown 		if (debug > 1)
990b7d8c148SLen Brown 			fprintf(outf, "cpu%d MPERF 0!\n", old->cpu_id);
991c98d5d94SLen Brown 		old->mperf = 1;	/* divide by 0 protection */
992c98d5d94SLen Brown 	}
993103a8feaSLen Brown 
9948e180f3cSLen Brown 	old->extra_delta32 = new->extra_delta32 - old->extra_delta32;
9958e180f3cSLen Brown 	old->extra_delta32 &= 0xFFFFFFFF;
9968e180f3cSLen Brown 
9978e180f3cSLen Brown 	old->extra_delta64 = new->extra_delta64 - old->extra_delta64;
9988e180f3cSLen Brown 
999103a8feaSLen Brown 	/*
10008e180f3cSLen Brown 	 * Extra MSR is just a snapshot, simply copy latest w/o subtracting
1001103a8feaSLen Brown 	 */
10022f32edf1SLen Brown 	old->extra_msr32 = new->extra_msr32;
10032f32edf1SLen Brown 	old->extra_msr64 = new->extra_msr64;
10041ed51011SLen Brown 
1005562a2d37SLen Brown 	if (do_irq)
1006562a2d37SLen Brown 		old->irq_count = new->irq_count - old->irq_count;
1007562a2d37SLen Brown 
10081ed51011SLen Brown 	if (do_smi)
10091ed51011SLen Brown 		old->smi_count = new->smi_count - old->smi_count;
1010ba3dec99SLen Brown 
1011*388e9c81SLen Brown 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
1012*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1013*388e9c81SLen Brown 			old->counter[i] = new->counter[i];
1014*388e9c81SLen Brown 		else
1015*388e9c81SLen Brown 			old->counter[i] = new->counter[i] - old->counter[i];
1016*388e9c81SLen Brown 	}
1017ba3dec99SLen Brown 	return 0;
1018103a8feaSLen Brown }
1019c98d5d94SLen Brown 
1020c98d5d94SLen Brown int delta_cpu(struct thread_data *t, struct core_data *c,
1021c98d5d94SLen Brown 	struct pkg_data *p, struct thread_data *t2,
1022c98d5d94SLen Brown 	struct core_data *c2, struct pkg_data *p2)
1023c98d5d94SLen Brown {
1024ba3dec99SLen Brown 	int retval = 0;
1025ba3dec99SLen Brown 
1026c98d5d94SLen Brown 	/* calculate core delta only for 1st thread in core */
1027c98d5d94SLen Brown 	if (t->flags & CPU_IS_FIRST_THREAD_IN_CORE)
1028c98d5d94SLen Brown 		delta_core(c, c2);
1029c98d5d94SLen Brown 
1030c98d5d94SLen Brown 	/* always calculate thread delta */
1031ba3dec99SLen Brown 	retval = delta_thread(t, t2, c2);	/* c2 is core delta */
1032ba3dec99SLen Brown 	if (retval)
1033ba3dec99SLen Brown 		return retval;
1034c98d5d94SLen Brown 
1035c98d5d94SLen Brown 	/* calculate package delta only for 1st core in package */
1036c98d5d94SLen Brown 	if (t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)
1037ba3dec99SLen Brown 		retval = delta_package(p, p2);
1038c98d5d94SLen Brown 
1039ba3dec99SLen Brown 	return retval;
1040103a8feaSLen Brown }
1041103a8feaSLen Brown 
1042c98d5d94SLen Brown void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1043103a8feaSLen Brown {
1044*388e9c81SLen Brown 	int i;
1045*388e9c81SLen Brown 	struct msr_counter  *mp;
1046*388e9c81SLen Brown 
1047c98d5d94SLen Brown 	t->tsc = 0;
1048c98d5d94SLen Brown 	t->aperf = 0;
1049c98d5d94SLen Brown 	t->mperf = 0;
1050c98d5d94SLen Brown 	t->c1 = 0;
1051103a8feaSLen Brown 
10528e180f3cSLen Brown 	t->extra_delta32 = 0;
10538e180f3cSLen Brown 	t->extra_delta64 = 0;
10548e180f3cSLen Brown 
1055562a2d37SLen Brown 	t->irq_count = 0;
1056562a2d37SLen Brown 	t->smi_count = 0;
1057562a2d37SLen Brown 
1058c98d5d94SLen Brown 	/* tells format_counters to dump all fields from this set */
1059c98d5d94SLen Brown 	t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE;
1060c98d5d94SLen Brown 
1061c98d5d94SLen Brown 	c->c3 = 0;
1062c98d5d94SLen Brown 	c->c6 = 0;
1063c98d5d94SLen Brown 	c->c7 = 0;
1064889facbeSLen Brown 	c->core_temp_c = 0;
1065c98d5d94SLen Brown 
10660b2bb692SLen Brown 	p->pkg_wtd_core_c0 = 0;
10670b2bb692SLen Brown 	p->pkg_any_core_c0 = 0;
10680b2bb692SLen Brown 	p->pkg_any_gfxe_c0 = 0;
10690b2bb692SLen Brown 	p->pkg_both_core_gfxe_c0 = 0;
10700b2bb692SLen Brown 
1071c98d5d94SLen Brown 	p->pc2 = 0;
1072ee7e38e3SLen Brown 	if (do_pc3)
1073c98d5d94SLen Brown 		p->pc3 = 0;
1074ee7e38e3SLen Brown 	if (do_pc6)
1075c98d5d94SLen Brown 		p->pc6 = 0;
1076ee7e38e3SLen Brown 	if (do_pc7)
1077c98d5d94SLen Brown 		p->pc7 = 0;
1078ca58710fSKristen Carlson Accardi 	p->pc8 = 0;
1079ca58710fSKristen Carlson Accardi 	p->pc9 = 0;
1080ca58710fSKristen Carlson Accardi 	p->pc10 = 0;
1081889facbeSLen Brown 
1082889facbeSLen Brown 	p->energy_pkg = 0;
1083889facbeSLen Brown 	p->energy_dram = 0;
1084889facbeSLen Brown 	p->energy_cores = 0;
1085889facbeSLen Brown 	p->energy_gfx = 0;
1086889facbeSLen Brown 	p->rapl_pkg_perf_status = 0;
1087889facbeSLen Brown 	p->rapl_dram_perf_status = 0;
1088889facbeSLen Brown 	p->pkg_temp_c = 0;
108927d47356SLen Brown 
1090fdf676e5SLen Brown 	p->gfx_rc6_ms = 0;
109127d47356SLen Brown 	p->gfx_mhz = 0;
1092*388e9c81SLen Brown 
1093*388e9c81SLen Brown 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next)
1094*388e9c81SLen Brown 		t->counter[i] = 0;
1095*388e9c81SLen Brown 
1096*388e9c81SLen Brown 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next)
1097*388e9c81SLen Brown 		c->counter[i] = 0;
1098*388e9c81SLen Brown 
1099*388e9c81SLen Brown 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next)
1100*388e9c81SLen Brown 		p->counter[i] = 0;
1101103a8feaSLen Brown }
1102c98d5d94SLen Brown int sum_counters(struct thread_data *t, struct core_data *c,
1103c98d5d94SLen Brown 	struct pkg_data *p)
1104103a8feaSLen Brown {
1105*388e9c81SLen Brown 	int i;
1106*388e9c81SLen Brown 	struct msr_counter *mp;
1107*388e9c81SLen Brown 
1108c98d5d94SLen Brown 	average.threads.tsc += t->tsc;
1109c98d5d94SLen Brown 	average.threads.aperf += t->aperf;
1110c98d5d94SLen Brown 	average.threads.mperf += t->mperf;
1111c98d5d94SLen Brown 	average.threads.c1 += t->c1;
111215aaa346SLen Brown 
11138e180f3cSLen Brown 	average.threads.extra_delta32 += t->extra_delta32;
11148e180f3cSLen Brown 	average.threads.extra_delta64 += t->extra_delta64;
11158e180f3cSLen Brown 
1116562a2d37SLen Brown 	average.threads.irq_count += t->irq_count;
1117562a2d37SLen Brown 	average.threads.smi_count += t->smi_count;
1118562a2d37SLen Brown 
1119*388e9c81SLen Brown 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
1120*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1121*388e9c81SLen Brown 			continue;
1122*388e9c81SLen Brown 		average.threads.counter[i] += t->counter[i];
1123*388e9c81SLen Brown 	}
1124*388e9c81SLen Brown 
1125c98d5d94SLen Brown 	/* sum per-core values only for 1st thread in core */
1126c98d5d94SLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
1127c98d5d94SLen Brown 		return 0;
1128c98d5d94SLen Brown 
1129c98d5d94SLen Brown 	average.cores.c3 += c->c3;
1130c98d5d94SLen Brown 	average.cores.c6 += c->c6;
1131c98d5d94SLen Brown 	average.cores.c7 += c->c7;
1132c98d5d94SLen Brown 
1133889facbeSLen Brown 	average.cores.core_temp_c = MAX(average.cores.core_temp_c, c->core_temp_c);
1134889facbeSLen Brown 
1135*388e9c81SLen Brown 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
1136*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1137*388e9c81SLen Brown 			continue;
1138*388e9c81SLen Brown 		average.cores.counter[i] += c->counter[i];
1139*388e9c81SLen Brown 	}
1140*388e9c81SLen Brown 
1141c98d5d94SLen Brown 	/* sum per-pkg values only for 1st core in pkg */
1142c98d5d94SLen Brown 	if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
1143c98d5d94SLen Brown 		return 0;
1144c98d5d94SLen Brown 
11450b2bb692SLen Brown 	if (do_skl_residency) {
11460b2bb692SLen Brown 		average.packages.pkg_wtd_core_c0 += p->pkg_wtd_core_c0;
11470b2bb692SLen Brown 		average.packages.pkg_any_core_c0 += p->pkg_any_core_c0;
11480b2bb692SLen Brown 		average.packages.pkg_any_gfxe_c0 += p->pkg_any_gfxe_c0;
11490b2bb692SLen Brown 		average.packages.pkg_both_core_gfxe_c0 += p->pkg_both_core_gfxe_c0;
11500b2bb692SLen Brown 	}
11510b2bb692SLen Brown 
1152c98d5d94SLen Brown 	average.packages.pc2 += p->pc2;
1153ee7e38e3SLen Brown 	if (do_pc3)
1154c98d5d94SLen Brown 		average.packages.pc3 += p->pc3;
1155ee7e38e3SLen Brown 	if (do_pc6)
1156c98d5d94SLen Brown 		average.packages.pc6 += p->pc6;
1157ee7e38e3SLen Brown 	if (do_pc7)
1158c98d5d94SLen Brown 		average.packages.pc7 += p->pc7;
1159ca58710fSKristen Carlson Accardi 	average.packages.pc8 += p->pc8;
1160ca58710fSKristen Carlson Accardi 	average.packages.pc9 += p->pc9;
1161ca58710fSKristen Carlson Accardi 	average.packages.pc10 += p->pc10;
1162c98d5d94SLen Brown 
1163889facbeSLen Brown 	average.packages.energy_pkg += p->energy_pkg;
1164889facbeSLen Brown 	average.packages.energy_dram += p->energy_dram;
1165889facbeSLen Brown 	average.packages.energy_cores += p->energy_cores;
1166889facbeSLen Brown 	average.packages.energy_gfx += p->energy_gfx;
1167889facbeSLen Brown 
1168fdf676e5SLen Brown 	average.packages.gfx_rc6_ms = p->gfx_rc6_ms;
116927d47356SLen Brown 	average.packages.gfx_mhz = p->gfx_mhz;
117027d47356SLen Brown 
1171889facbeSLen Brown 	average.packages.pkg_temp_c = MAX(average.packages.pkg_temp_c, p->pkg_temp_c);
1172889facbeSLen Brown 
1173889facbeSLen Brown 	average.packages.rapl_pkg_perf_status += p->rapl_pkg_perf_status;
1174889facbeSLen Brown 	average.packages.rapl_dram_perf_status += p->rapl_dram_perf_status;
1175*388e9c81SLen Brown 
1176*388e9c81SLen Brown 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
1177*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1178*388e9c81SLen Brown 			continue;
1179*388e9c81SLen Brown 		average.packages.counter[i] += p->counter[i];
1180*388e9c81SLen Brown 	}
1181c98d5d94SLen Brown 	return 0;
1182c98d5d94SLen Brown }
1183c98d5d94SLen Brown /*
1184c98d5d94SLen Brown  * sum the counters for all cpus in the system
1185c98d5d94SLen Brown  * compute the weighted average
1186c98d5d94SLen Brown  */
1187c98d5d94SLen Brown void compute_average(struct thread_data *t, struct core_data *c,
1188c98d5d94SLen Brown 	struct pkg_data *p)
1189c98d5d94SLen Brown {
1190*388e9c81SLen Brown 	int i;
1191*388e9c81SLen Brown 	struct msr_counter *mp;
1192*388e9c81SLen Brown 
1193c98d5d94SLen Brown 	clear_counters(&average.threads, &average.cores, &average.packages);
1194c98d5d94SLen Brown 
1195c98d5d94SLen Brown 	for_all_cpus(sum_counters, t, c, p);
1196c98d5d94SLen Brown 
1197c98d5d94SLen Brown 	average.threads.tsc /= topo.num_cpus;
1198c98d5d94SLen Brown 	average.threads.aperf /= topo.num_cpus;
1199c98d5d94SLen Brown 	average.threads.mperf /= topo.num_cpus;
1200c98d5d94SLen Brown 	average.threads.c1 /= topo.num_cpus;
1201c98d5d94SLen Brown 
12028e180f3cSLen Brown 	average.threads.extra_delta32 /= topo.num_cpus;
12038e180f3cSLen Brown 	average.threads.extra_delta32 &= 0xFFFFFFFF;
12048e180f3cSLen Brown 
12058e180f3cSLen Brown 	average.threads.extra_delta64 /= topo.num_cpus;
12068e180f3cSLen Brown 
1207c98d5d94SLen Brown 	average.cores.c3 /= topo.num_cores;
1208c98d5d94SLen Brown 	average.cores.c6 /= topo.num_cores;
1209c98d5d94SLen Brown 	average.cores.c7 /= topo.num_cores;
1210c98d5d94SLen Brown 
12110b2bb692SLen Brown 	if (do_skl_residency) {
12120b2bb692SLen Brown 		average.packages.pkg_wtd_core_c0 /= topo.num_packages;
12130b2bb692SLen Brown 		average.packages.pkg_any_core_c0 /= topo.num_packages;
12140b2bb692SLen Brown 		average.packages.pkg_any_gfxe_c0 /= topo.num_packages;
12150b2bb692SLen Brown 		average.packages.pkg_both_core_gfxe_c0 /= topo.num_packages;
12160b2bb692SLen Brown 	}
12170b2bb692SLen Brown 
1218c98d5d94SLen Brown 	average.packages.pc2 /= topo.num_packages;
1219ee7e38e3SLen Brown 	if (do_pc3)
1220c98d5d94SLen Brown 		average.packages.pc3 /= topo.num_packages;
1221ee7e38e3SLen Brown 	if (do_pc6)
1222c98d5d94SLen Brown 		average.packages.pc6 /= topo.num_packages;
1223ee7e38e3SLen Brown 	if (do_pc7)
1224c98d5d94SLen Brown 		average.packages.pc7 /= topo.num_packages;
1225ca58710fSKristen Carlson Accardi 
1226ca58710fSKristen Carlson Accardi 	average.packages.pc8 /= topo.num_packages;
1227ca58710fSKristen Carlson Accardi 	average.packages.pc9 /= topo.num_packages;
1228ca58710fSKristen Carlson Accardi 	average.packages.pc10 /= topo.num_packages;
1229*388e9c81SLen Brown 
1230*388e9c81SLen Brown 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
1231*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1232*388e9c81SLen Brown 			continue;
1233*388e9c81SLen Brown 		average.threads.counter[i] /= topo.num_cpus;
1234*388e9c81SLen Brown 	}
1235*388e9c81SLen Brown 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
1236*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1237*388e9c81SLen Brown 			continue;
1238*388e9c81SLen Brown 		average.cores.counter[i] /= topo.num_cores;
1239*388e9c81SLen Brown 	}
1240*388e9c81SLen Brown 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
1241*388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1242*388e9c81SLen Brown 			continue;
1243*388e9c81SLen Brown 		average.packages.counter[i] /= topo.num_packages;
1244*388e9c81SLen Brown 	}
1245c98d5d94SLen Brown }
1246c98d5d94SLen Brown 
1247c98d5d94SLen Brown static unsigned long long rdtsc(void)
1248c98d5d94SLen Brown {
1249c98d5d94SLen Brown 	unsigned int low, high;
1250c98d5d94SLen Brown 
1251c98d5d94SLen Brown 	asm volatile("rdtsc" : "=a" (low), "=d" (high));
1252c98d5d94SLen Brown 
1253c98d5d94SLen Brown 	return low | ((unsigned long long)high) << 32;
1254c98d5d94SLen Brown }
1255c98d5d94SLen Brown 
1256c98d5d94SLen Brown /*
1257c98d5d94SLen Brown  * get_counters(...)
1258c98d5d94SLen Brown  * migrate to cpu
1259c98d5d94SLen Brown  * acquire and record local counters for that cpu
1260c98d5d94SLen Brown  */
1261c98d5d94SLen Brown int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1262c98d5d94SLen Brown {
1263c98d5d94SLen Brown 	int cpu = t->cpu_id;
1264889facbeSLen Brown 	unsigned long long msr;
12650102b067SLen Brown 	int aperf_mperf_retry_count = 0;
1266*388e9c81SLen Brown 	struct msr_counter *mp;
1267*388e9c81SLen Brown 	int i;
1268c98d5d94SLen Brown 
1269e52966c0SLen Brown 	if (cpu_migrate(cpu)) {
1270b7d8c148SLen Brown 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
127115aaa346SLen Brown 		return -1;
1272e52966c0SLen Brown 	}
127315aaa346SLen Brown 
12740102b067SLen Brown retry:
1275c98d5d94SLen Brown 	t->tsc = rdtsc();	/* we are running on local CPU of interest */
127615aaa346SLen Brown 
127715aaa346SLen Brown 	if (has_aperf) {
12780102b067SLen Brown 		unsigned long long tsc_before, tsc_between, tsc_after, aperf_time, mperf_time;
12790102b067SLen Brown 
12800102b067SLen Brown 		/*
12810102b067SLen Brown 		 * The TSC, APERF and MPERF must be read together for
12820102b067SLen Brown 		 * APERF/MPERF and MPERF/TSC to give accurate results.
12830102b067SLen Brown 		 *
12840102b067SLen Brown 		 * Unfortunately, APERF and MPERF are read by
12850102b067SLen Brown 		 * individual system call, so delays may occur
12860102b067SLen Brown 		 * between them.  If the time to read them
12870102b067SLen Brown 		 * varies by a large amount, we re-read them.
12880102b067SLen Brown 		 */
12890102b067SLen Brown 
12900102b067SLen Brown 		/*
12910102b067SLen Brown 		 * This initial dummy APERF read has been seen to
12920102b067SLen Brown 		 * reduce jitter in the subsequent reads.
12930102b067SLen Brown 		 */
12940102b067SLen Brown 
12959c63a650SLen Brown 		if (get_msr(cpu, MSR_IA32_APERF, &t->aperf))
1296c98d5d94SLen Brown 			return -3;
12970102b067SLen Brown 
12980102b067SLen Brown 		t->tsc = rdtsc();	/* re-read close to APERF */
12990102b067SLen Brown 
13000102b067SLen Brown 		tsc_before = t->tsc;
13010102b067SLen Brown 
13020102b067SLen Brown 		if (get_msr(cpu, MSR_IA32_APERF, &t->aperf))
13030102b067SLen Brown 			return -3;
13040102b067SLen Brown 
13050102b067SLen Brown 		tsc_between = rdtsc();
13060102b067SLen Brown 
13079c63a650SLen Brown 		if (get_msr(cpu, MSR_IA32_MPERF, &t->mperf))
1308c98d5d94SLen Brown 			return -4;
13090102b067SLen Brown 
13100102b067SLen Brown 		tsc_after = rdtsc();
13110102b067SLen Brown 
13120102b067SLen Brown 		aperf_time = tsc_between - tsc_before;
13130102b067SLen Brown 		mperf_time = tsc_after - tsc_between;
13140102b067SLen Brown 
13150102b067SLen Brown 		/*
13160102b067SLen Brown 		 * If the system call latency to read APERF and MPERF
13170102b067SLen Brown 		 * differ by more than 2x, then try again.
13180102b067SLen Brown 		 */
13190102b067SLen Brown 		if ((aperf_time > (2 * mperf_time)) || (mperf_time > (2 * aperf_time))) {
13200102b067SLen Brown 			aperf_mperf_retry_count++;
13210102b067SLen Brown 			if (aperf_mperf_retry_count < 5)
13220102b067SLen Brown 				goto retry;
13230102b067SLen Brown 			else
13240102b067SLen Brown 				warnx("cpu%d jitter %lld %lld",
13250102b067SLen Brown 					cpu, aperf_time, mperf_time);
13260102b067SLen Brown 		}
13270102b067SLen Brown 		aperf_mperf_retry_count = 0;
13280102b067SLen Brown 
1329b2b34dfeSHubert Chrzaniuk 		t->aperf = t->aperf * aperf_mperf_multiplier;
1330b2b34dfeSHubert Chrzaniuk 		t->mperf = t->mperf * aperf_mperf_multiplier;
133188c3281fSLen Brown 	}
133288c3281fSLen Brown 
1333562a2d37SLen Brown 	if (do_irq)
1334562a2d37SLen Brown 		t->irq_count = irqs_per_cpu[cpu];
13351ed51011SLen Brown 	if (do_smi) {
13361ed51011SLen Brown 		if (get_msr(cpu, MSR_SMI_COUNT, &msr))
13371ed51011SLen Brown 			return -5;
13381ed51011SLen Brown 		t->smi_count = msr & 0xFFFFFFFF;
13391ed51011SLen Brown 	}
13408e180f3cSLen Brown 	if (extra_delta_offset32) {
1341889facbeSLen Brown 		if (get_msr(cpu, extra_delta_offset32, &msr))
13422f32edf1SLen Brown 			return -5;
1343889facbeSLen Brown 		t->extra_delta32 = msr & 0xFFFFFFFF;
13448e180f3cSLen Brown 	}
13458e180f3cSLen Brown 
13468e180f3cSLen Brown 	if (extra_delta_offset64)
13478e180f3cSLen Brown 		if (get_msr(cpu, extra_delta_offset64, &t->extra_delta64))
13488e180f3cSLen Brown 			return -5;
13498e180f3cSLen Brown 
13508e180f3cSLen Brown 	if (extra_msr_offset32) {
1351889facbeSLen Brown 		if (get_msr(cpu, extra_msr_offset32, &msr))
13528e180f3cSLen Brown 			return -5;
1353889facbeSLen Brown 		t->extra_msr32 = msr & 0xFFFFFFFF;
13548e180f3cSLen Brown 	}
13552f32edf1SLen Brown 
13562f32edf1SLen Brown 	if (extra_msr_offset64)
13572f32edf1SLen Brown 		if (get_msr(cpu, extra_msr_offset64, &t->extra_msr64))
1358c98d5d94SLen Brown 			return -5;
1359c98d5d94SLen Brown 
1360144b44b1SLen Brown 	if (use_c1_residency_msr) {
1361144b44b1SLen Brown 		if (get_msr(cpu, MSR_CORE_C1_RES, &t->c1))
1362144b44b1SLen Brown 			return -6;
1363144b44b1SLen Brown 	}
1364144b44b1SLen Brown 
1365*388e9c81SLen Brown 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
1366*388e9c81SLen Brown 		if (get_msr(cpu, mp->msr_num, &t->counter[i]))
1367*388e9c81SLen Brown 			return -10;
1368*388e9c81SLen Brown 	}
1369*388e9c81SLen Brown 
1370*388e9c81SLen Brown 
1371c98d5d94SLen Brown 	/* collect core counters only for 1st thread in core */
1372c98d5d94SLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
1373c98d5d94SLen Brown 		return 0;
1374c98d5d94SLen Brown 
1375fb5d4327SDasaratharaman Chandramouli 	if (do_nhm_cstates && !do_slm_cstates && !do_knl_cstates) {
1376c98d5d94SLen Brown 		if (get_msr(cpu, MSR_CORE_C3_RESIDENCY, &c->c3))
1377c98d5d94SLen Brown 			return -6;
1378144b44b1SLen Brown 	}
1379144b44b1SLen Brown 
1380fb5d4327SDasaratharaman Chandramouli 	if (do_nhm_cstates && !do_knl_cstates) {
1381c98d5d94SLen Brown 		if (get_msr(cpu, MSR_CORE_C6_RESIDENCY, &c->c6))
1382c98d5d94SLen Brown 			return -7;
1383fb5d4327SDasaratharaman Chandramouli 	} else if (do_knl_cstates) {
1384fb5d4327SDasaratharaman Chandramouli 		if (get_msr(cpu, MSR_KNL_CORE_C6_RESIDENCY, &c->c6))
1385fb5d4327SDasaratharaman Chandramouli 			return -7;
1386103a8feaSLen Brown 	}
138715aaa346SLen Brown 
138815aaa346SLen Brown 	if (do_snb_cstates)
1389c98d5d94SLen Brown 		if (get_msr(cpu, MSR_CORE_C7_RESIDENCY, &c->c7))
1390c98d5d94SLen Brown 			return -8;
1391c98d5d94SLen Brown 
1392889facbeSLen Brown 	if (do_dts) {
1393889facbeSLen Brown 		if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr))
1394889facbeSLen Brown 			return -9;
1395889facbeSLen Brown 		c->core_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F);
1396889facbeSLen Brown 	}
1397889facbeSLen Brown 
1398*388e9c81SLen Brown 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
1399*388e9c81SLen Brown 		if (get_msr(cpu, mp->msr_num, &c->counter[i]))
1400*388e9c81SLen Brown 			return -10;
1401*388e9c81SLen Brown 	}
1402889facbeSLen Brown 
1403c98d5d94SLen Brown 	/* collect package counters only for 1st core in package */
1404c98d5d94SLen Brown 	if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
1405c98d5d94SLen Brown 		return 0;
140615aaa346SLen Brown 
14070b2bb692SLen Brown 	if (do_skl_residency) {
14080b2bb692SLen Brown 		if (get_msr(cpu, MSR_PKG_WEIGHTED_CORE_C0_RES, &p->pkg_wtd_core_c0))
14090b2bb692SLen Brown 			return -10;
14100b2bb692SLen Brown 		if (get_msr(cpu, MSR_PKG_ANY_CORE_C0_RES, &p->pkg_any_core_c0))
14110b2bb692SLen Brown 			return -11;
14120b2bb692SLen Brown 		if (get_msr(cpu, MSR_PKG_ANY_GFXE_C0_RES, &p->pkg_any_gfxe_c0))
14130b2bb692SLen Brown 			return -12;
14140b2bb692SLen Brown 		if (get_msr(cpu, MSR_PKG_BOTH_CORE_GFXE_C0_RES, &p->pkg_both_core_gfxe_c0))
14150b2bb692SLen Brown 			return -13;
14160b2bb692SLen Brown 	}
1417ee7e38e3SLen Brown 	if (do_pc3)
1418c98d5d94SLen Brown 		if (get_msr(cpu, MSR_PKG_C3_RESIDENCY, &p->pc3))
1419c98d5d94SLen Brown 			return -9;
1420ee7e38e3SLen Brown 	if (do_pc6)
1421c98d5d94SLen Brown 		if (get_msr(cpu, MSR_PKG_C6_RESIDENCY, &p->pc6))
1422c98d5d94SLen Brown 			return -10;
1423ee7e38e3SLen Brown 	if (do_pc2)
1424c98d5d94SLen Brown 		if (get_msr(cpu, MSR_PKG_C2_RESIDENCY, &p->pc2))
1425c98d5d94SLen Brown 			return -11;
1426ee7e38e3SLen Brown 	if (do_pc7)
1427c98d5d94SLen Brown 		if (get_msr(cpu, MSR_PKG_C7_RESIDENCY, &p->pc7))
1428c98d5d94SLen Brown 			return -12;
1429ca58710fSKristen Carlson Accardi 	if (do_c8_c9_c10) {
1430ca58710fSKristen Carlson Accardi 		if (get_msr(cpu, MSR_PKG_C8_RESIDENCY, &p->pc8))
1431ca58710fSKristen Carlson Accardi 			return -13;
1432ca58710fSKristen Carlson Accardi 		if (get_msr(cpu, MSR_PKG_C9_RESIDENCY, &p->pc9))
1433ca58710fSKristen Carlson Accardi 			return -13;
1434ca58710fSKristen Carlson Accardi 		if (get_msr(cpu, MSR_PKG_C10_RESIDENCY, &p->pc10))
1435ca58710fSKristen Carlson Accardi 			return -13;
1436ca58710fSKristen Carlson Accardi 	}
1437889facbeSLen Brown 	if (do_rapl & RAPL_PKG) {
1438889facbeSLen Brown 		if (get_msr(cpu, MSR_PKG_ENERGY_STATUS, &msr))
1439889facbeSLen Brown 			return -13;
1440889facbeSLen Brown 		p->energy_pkg = msr & 0xFFFFFFFF;
1441889facbeSLen Brown 	}
14429148494cSJacob Pan 	if (do_rapl & RAPL_CORES_ENERGY_STATUS) {
1443889facbeSLen Brown 		if (get_msr(cpu, MSR_PP0_ENERGY_STATUS, &msr))
1444889facbeSLen Brown 			return -14;
1445889facbeSLen Brown 		p->energy_cores = msr & 0xFFFFFFFF;
1446889facbeSLen Brown 	}
1447889facbeSLen Brown 	if (do_rapl & RAPL_DRAM) {
1448889facbeSLen Brown 		if (get_msr(cpu, MSR_DRAM_ENERGY_STATUS, &msr))
1449889facbeSLen Brown 			return -15;
1450889facbeSLen Brown 		p->energy_dram = msr & 0xFFFFFFFF;
1451889facbeSLen Brown 	}
1452889facbeSLen Brown 	if (do_rapl & RAPL_GFX) {
1453889facbeSLen Brown 		if (get_msr(cpu, MSR_PP1_ENERGY_STATUS, &msr))
1454889facbeSLen Brown 			return -16;
1455889facbeSLen Brown 		p->energy_gfx = msr & 0xFFFFFFFF;
1456889facbeSLen Brown 	}
1457889facbeSLen Brown 	if (do_rapl & RAPL_PKG_PERF_STATUS) {
1458889facbeSLen Brown 		if (get_msr(cpu, MSR_PKG_PERF_STATUS, &msr))
1459889facbeSLen Brown 			return -16;
1460889facbeSLen Brown 		p->rapl_pkg_perf_status = msr & 0xFFFFFFFF;
1461889facbeSLen Brown 	}
1462889facbeSLen Brown 	if (do_rapl & RAPL_DRAM_PERF_STATUS) {
1463889facbeSLen Brown 		if (get_msr(cpu, MSR_DRAM_PERF_STATUS, &msr))
1464889facbeSLen Brown 			return -16;
1465889facbeSLen Brown 		p->rapl_dram_perf_status = msr & 0xFFFFFFFF;
1466889facbeSLen Brown 	}
1467889facbeSLen Brown 	if (do_ptm) {
1468889facbeSLen Brown 		if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr))
1469889facbeSLen Brown 			return -17;
1470889facbeSLen Brown 		p->pkg_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F);
1471889facbeSLen Brown 	}
1472fdf676e5SLen Brown 
1473fdf676e5SLen Brown 	if (do_gfx_rc6_ms)
1474fdf676e5SLen Brown 		p->gfx_rc6_ms = gfx_cur_rc6_ms;
1475fdf676e5SLen Brown 
147627d47356SLen Brown 	if (do_gfx_mhz)
147727d47356SLen Brown 		p->gfx_mhz = gfx_cur_mhz;
147827d47356SLen Brown 
1479*388e9c81SLen Brown 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
1480*388e9c81SLen Brown 		if (get_msr(cpu, mp->msr_num, &p->counter[i]))
1481*388e9c81SLen Brown 			return -10;
1482*388e9c81SLen Brown 	}
1483*388e9c81SLen Brown 
148415aaa346SLen Brown 	return 0;
1485103a8feaSLen Brown }
1486103a8feaSLen Brown 
1487ee7e38e3SLen Brown /*
1488ee7e38e3SLen Brown  * MSR_PKG_CST_CONFIG_CONTROL decoding for pkg_cstate_limit:
1489ee7e38e3SLen Brown  * If you change the values, note they are used both in comparisons
1490ee7e38e3SLen Brown  * (>= PCL__7) and to index pkg_cstate_limit_strings[].
1491ee7e38e3SLen Brown  */
1492ee7e38e3SLen Brown 
1493ee7e38e3SLen Brown #define PCLUKN 0 /* Unknown */
1494ee7e38e3SLen Brown #define PCLRSV 1 /* Reserved */
1495ee7e38e3SLen Brown #define PCL__0 2 /* PC0 */
1496ee7e38e3SLen Brown #define PCL__1 3 /* PC1 */
1497ee7e38e3SLen Brown #define PCL__2 4 /* PC2 */
1498ee7e38e3SLen Brown #define PCL__3 5 /* PC3 */
1499ee7e38e3SLen Brown #define PCL__4 6 /* PC4 */
1500ee7e38e3SLen Brown #define PCL__6 7 /* PC6 */
1501ee7e38e3SLen Brown #define PCL_6N 8 /* PC6 No Retention */
1502ee7e38e3SLen Brown #define PCL_6R 9 /* PC6 Retention */
1503ee7e38e3SLen Brown #define PCL__7 10 /* PC7 */
1504ee7e38e3SLen Brown #define PCL_7S 11 /* PC7 Shrink */
15050b2bb692SLen Brown #define PCL__8 12 /* PC8 */
15060b2bb692SLen Brown #define PCL__9 13 /* PC9 */
15070b2bb692SLen Brown #define PCLUNL 14 /* Unlimited */
1508ee7e38e3SLen Brown 
1509ee7e38e3SLen Brown int pkg_cstate_limit = PCLUKN;
1510ee7e38e3SLen Brown char *pkg_cstate_limit_strings[] = { "reserved", "unknown", "pc0", "pc1", "pc2",
15110b2bb692SLen Brown 	"pc3", "pc4", "pc6", "pc6n", "pc6r", "pc7", "pc7s", "pc8", "pc9", "unlimited"};
1512ee7e38e3SLen Brown 
1513e9257f5fSLen Brown int nhm_pkg_cstate_limits[16] = {PCL__0, PCL__1, PCL__3, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
1514e9257f5fSLen Brown int snb_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL_6N, PCL_6R, PCL__7, PCL_7S, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
1515e9257f5fSLen Brown int hsw_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL__3, PCL__6, PCL__7, PCL_7S, PCL__8, PCL__9, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
1516e9257f5fSLen Brown int slv_pkg_cstate_limits[16] = {PCL__0, PCL__1, PCLRSV, PCLRSV, PCL__4, PCLRSV, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
1517e9257f5fSLen Brown int amt_pkg_cstate_limits[16] = {PCL__0, PCL__1, PCL__2, PCLRSV, PCLRSV, PCLRSV, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
1518e9257f5fSLen Brown int phi_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL_6N, PCL_6R, PCLRSV, PCLRSV, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
1519e4085d54SLen Brown int bxt_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
1520d8ebb442SLen Brown int skx_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL_6N, PCL_6R, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
1521ee7e38e3SLen Brown 
1522a2b7b749SLen Brown 
1523a2b7b749SLen Brown static void
1524a2b7b749SLen Brown calculate_tsc_tweak()
1525a2b7b749SLen Brown {
1526a2b7b749SLen Brown 	tsc_tweak = base_hz / tsc_hz;
1527a2b7b749SLen Brown }
1528a2b7b749SLen Brown 
1529fcd17211SLen Brown static void
1530fcd17211SLen Brown dump_nhm_platform_info(void)
1531103a8feaSLen Brown {
1532103a8feaSLen Brown 	unsigned long long msr;
1533103a8feaSLen Brown 	unsigned int ratio;
1534103a8feaSLen Brown 
1535ec0adc53SLen Brown 	get_msr(base_cpu, MSR_PLATFORM_INFO, &msr);
1536103a8feaSLen Brown 
1537b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_PLATFORM_INFO: 0x%08llx\n", base_cpu, msr);
15386574a5d5SLen Brown 
1539103a8feaSLen Brown 	ratio = (msr >> 40) & 0xFF;
1540b7d8c148SLen Brown 	fprintf(outf, "%d * %.0f = %.0f MHz max efficiency frequency\n",
1541103a8feaSLen Brown 		ratio, bclk, ratio * bclk);
1542103a8feaSLen Brown 
1543103a8feaSLen Brown 	ratio = (msr >> 8) & 0xFF;
1544b7d8c148SLen Brown 	fprintf(outf, "%d * %.0f = %.0f MHz base frequency\n",
1545103a8feaSLen Brown 		ratio, bclk, ratio * bclk);
1546103a8feaSLen Brown 
15477ce7d5deSPrarit Bhargava 	get_msr(base_cpu, MSR_IA32_POWER_CTL, &msr);
1548b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_IA32_POWER_CTL: 0x%08llx (C1E auto-promotion: %sabled)\n",
1549bfae2052SLen Brown 		base_cpu, msr, msr & 0x2 ? "EN" : "DIS");
155067920418SLen Brown 
1551fcd17211SLen Brown 	return;
1552fcd17211SLen Brown }
1553fcd17211SLen Brown 
1554fcd17211SLen Brown static void
1555fcd17211SLen Brown dump_hsw_turbo_ratio_limits(void)
1556fcd17211SLen Brown {
1557fcd17211SLen Brown 	unsigned long long msr;
1558fcd17211SLen Brown 	unsigned int ratio;
1559fcd17211SLen Brown 
15607ce7d5deSPrarit Bhargava 	get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT2, &msr);
1561fcd17211SLen Brown 
1562b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT2: 0x%08llx\n", base_cpu, msr);
1563fcd17211SLen Brown 
1564fcd17211SLen Brown 	ratio = (msr >> 8) & 0xFF;
1565fcd17211SLen Brown 	if (ratio)
1566b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 18 active cores\n",
1567fcd17211SLen Brown 			ratio, bclk, ratio * bclk);
1568fcd17211SLen Brown 
1569fcd17211SLen Brown 	ratio = (msr >> 0) & 0xFF;
1570fcd17211SLen Brown 	if (ratio)
1571b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 17 active cores\n",
1572fcd17211SLen Brown 			ratio, bclk, ratio * bclk);
1573fcd17211SLen Brown 	return;
1574fcd17211SLen Brown }
1575fcd17211SLen Brown 
1576fcd17211SLen Brown static void
1577fcd17211SLen Brown dump_ivt_turbo_ratio_limits(void)
1578fcd17211SLen Brown {
1579fcd17211SLen Brown 	unsigned long long msr;
1580fcd17211SLen Brown 	unsigned int ratio;
15816574a5d5SLen Brown 
15827ce7d5deSPrarit Bhargava 	get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT1, &msr);
15836574a5d5SLen Brown 
1584b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT1: 0x%08llx\n", base_cpu, msr);
15856574a5d5SLen Brown 
15866574a5d5SLen Brown 	ratio = (msr >> 56) & 0xFF;
15876574a5d5SLen Brown 	if (ratio)
1588b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 16 active cores\n",
15896574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
15906574a5d5SLen Brown 
15916574a5d5SLen Brown 	ratio = (msr >> 48) & 0xFF;
15926574a5d5SLen Brown 	if (ratio)
1593b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 15 active cores\n",
15946574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
15956574a5d5SLen Brown 
15966574a5d5SLen Brown 	ratio = (msr >> 40) & 0xFF;
15976574a5d5SLen Brown 	if (ratio)
1598b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 14 active cores\n",
15996574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
16006574a5d5SLen Brown 
16016574a5d5SLen Brown 	ratio = (msr >> 32) & 0xFF;
16026574a5d5SLen Brown 	if (ratio)
1603b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 13 active cores\n",
16046574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
16056574a5d5SLen Brown 
16066574a5d5SLen Brown 	ratio = (msr >> 24) & 0xFF;
16076574a5d5SLen Brown 	if (ratio)
1608b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 12 active cores\n",
16096574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
16106574a5d5SLen Brown 
16116574a5d5SLen Brown 	ratio = (msr >> 16) & 0xFF;
16126574a5d5SLen Brown 	if (ratio)
1613b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 11 active cores\n",
16146574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
16156574a5d5SLen Brown 
16166574a5d5SLen Brown 	ratio = (msr >> 8) & 0xFF;
16176574a5d5SLen Brown 	if (ratio)
1618b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 10 active cores\n",
16196574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
16206574a5d5SLen Brown 
16216574a5d5SLen Brown 	ratio = (msr >> 0) & 0xFF;
16226574a5d5SLen Brown 	if (ratio)
1623b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 9 active cores\n",
16246574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
1625103a8feaSLen Brown 	return;
1626fcd17211SLen Brown }
1627fcd17211SLen Brown 
1628fcd17211SLen Brown static void
1629fcd17211SLen Brown dump_nhm_turbo_ratio_limits(void)
1630fcd17211SLen Brown {
1631fcd17211SLen Brown 	unsigned long long msr;
1632fcd17211SLen Brown 	unsigned int ratio;
1633103a8feaSLen Brown 
16347ce7d5deSPrarit Bhargava 	get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT, &msr);
1635103a8feaSLen Brown 
1636b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n", base_cpu, msr);
16376574a5d5SLen Brown 
16386574a5d5SLen Brown 	ratio = (msr >> 56) & 0xFF;
16396574a5d5SLen Brown 	if (ratio)
1640b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 8 active cores\n",
16416574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
16426574a5d5SLen Brown 
16436574a5d5SLen Brown 	ratio = (msr >> 48) & 0xFF;
16446574a5d5SLen Brown 	if (ratio)
1645b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 7 active cores\n",
16466574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
16476574a5d5SLen Brown 
16486574a5d5SLen Brown 	ratio = (msr >> 40) & 0xFF;
16496574a5d5SLen Brown 	if (ratio)
1650b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 6 active cores\n",
16516574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
16526574a5d5SLen Brown 
16536574a5d5SLen Brown 	ratio = (msr >> 32) & 0xFF;
16546574a5d5SLen Brown 	if (ratio)
1655b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 5 active cores\n",
16566574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
16576574a5d5SLen Brown 
1658103a8feaSLen Brown 	ratio = (msr >> 24) & 0xFF;
1659103a8feaSLen Brown 	if (ratio)
1660b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 4 active cores\n",
1661103a8feaSLen Brown 			ratio, bclk, ratio * bclk);
1662103a8feaSLen Brown 
1663103a8feaSLen Brown 	ratio = (msr >> 16) & 0xFF;
1664103a8feaSLen Brown 	if (ratio)
1665b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 3 active cores\n",
1666103a8feaSLen Brown 			ratio, bclk, ratio * bclk);
1667103a8feaSLen Brown 
1668103a8feaSLen Brown 	ratio = (msr >> 8) & 0xFF;
1669103a8feaSLen Brown 	if (ratio)
1670b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 2 active cores\n",
1671103a8feaSLen Brown 			ratio, bclk, ratio * bclk);
1672103a8feaSLen Brown 
1673103a8feaSLen Brown 	ratio = (msr >> 0) & 0xFF;
1674103a8feaSLen Brown 	if (ratio)
1675b7d8c148SLen Brown 		fprintf(outf, "%d * %.0f = %.0f MHz max turbo 1 active cores\n",
1676103a8feaSLen Brown 			ratio, bclk, ratio * bclk);
1677fcd17211SLen Brown 	return;
1678fcd17211SLen Brown }
16793a9a941dSLen Brown 
1680fcd17211SLen Brown static void
1681fb5d4327SDasaratharaman Chandramouli dump_knl_turbo_ratio_limits(void)
1682fb5d4327SDasaratharaman Chandramouli {
1683cbf97abaSHubert Chrzaniuk 	const unsigned int buckets_no = 7;
1684cbf97abaSHubert Chrzaniuk 
1685fb5d4327SDasaratharaman Chandramouli 	unsigned long long msr;
1686cbf97abaSHubert Chrzaniuk 	int delta_cores, delta_ratio;
1687cbf97abaSHubert Chrzaniuk 	int i, b_nr;
1688cbf97abaSHubert Chrzaniuk 	unsigned int cores[buckets_no];
1689cbf97abaSHubert Chrzaniuk 	unsigned int ratio[buckets_no];
1690fb5d4327SDasaratharaman Chandramouli 
1691ebf5926aSSrinivas Pandruvada 	get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT, &msr);
1692fb5d4327SDasaratharaman Chandramouli 
1693b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n",
1694bfae2052SLen Brown 		base_cpu, msr);
1695fb5d4327SDasaratharaman Chandramouli 
1696fb5d4327SDasaratharaman Chandramouli 	/**
1697fb5d4327SDasaratharaman Chandramouli 	 * Turbo encoding in KNL is as follows:
1698cbf97abaSHubert Chrzaniuk 	 * [0] -- Reserved
1699cbf97abaSHubert Chrzaniuk 	 * [7:1] -- Base value of number of active cores of bucket 1.
1700fb5d4327SDasaratharaman Chandramouli 	 * [15:8] -- Base value of freq ratio of bucket 1.
1701fb5d4327SDasaratharaman Chandramouli 	 * [20:16] -- +ve delta of number of active cores of bucket 2.
1702fb5d4327SDasaratharaman Chandramouli 	 * i.e. active cores of bucket 2 =
1703fb5d4327SDasaratharaman Chandramouli 	 * active cores of bucket 1 + delta
1704fb5d4327SDasaratharaman Chandramouli 	 * [23:21] -- Negative delta of freq ratio of bucket 2.
1705fb5d4327SDasaratharaman Chandramouli 	 * i.e. freq ratio of bucket 2 =
1706fb5d4327SDasaratharaman Chandramouli 	 * freq ratio of bucket 1 - delta
1707fb5d4327SDasaratharaman Chandramouli 	 * [28:24]-- +ve delta of number of active cores of bucket 3.
1708fb5d4327SDasaratharaman Chandramouli 	 * [31:29]-- -ve delta of freq ratio of bucket 3.
1709fb5d4327SDasaratharaman Chandramouli 	 * [36:32]-- +ve delta of number of active cores of bucket 4.
1710fb5d4327SDasaratharaman Chandramouli 	 * [39:37]-- -ve delta of freq ratio of bucket 4.
1711fb5d4327SDasaratharaman Chandramouli 	 * [44:40]-- +ve delta of number of active cores of bucket 5.
1712fb5d4327SDasaratharaman Chandramouli 	 * [47:45]-- -ve delta of freq ratio of bucket 5.
1713fb5d4327SDasaratharaman Chandramouli 	 * [52:48]-- +ve delta of number of active cores of bucket 6.
1714fb5d4327SDasaratharaman Chandramouli 	 * [55:53]-- -ve delta of freq ratio of bucket 6.
1715fb5d4327SDasaratharaman Chandramouli 	 * [60:56]-- +ve delta of number of active cores of bucket 7.
1716fb5d4327SDasaratharaman Chandramouli 	 * [63:61]-- -ve delta of freq ratio of bucket 7.
1717fb5d4327SDasaratharaman Chandramouli 	 */
1718fb5d4327SDasaratharaman Chandramouli 
1719cbf97abaSHubert Chrzaniuk 	b_nr = 0;
1720cbf97abaSHubert Chrzaniuk 	cores[b_nr] = (msr & 0xFF) >> 1;
1721cbf97abaSHubert Chrzaniuk 	ratio[b_nr] = (msr >> 8) & 0xFF;
1722cbf97abaSHubert Chrzaniuk 
1723cbf97abaSHubert Chrzaniuk 	for (i = 16; i < 64; i += 8) {
1724fb5d4327SDasaratharaman Chandramouli 		delta_cores = (msr >> i) & 0x1F;
1725cbf97abaSHubert Chrzaniuk 		delta_ratio = (msr >> (i + 5)) & 0x7;
1726fb5d4327SDasaratharaman Chandramouli 
1727cbf97abaSHubert Chrzaniuk 		cores[b_nr + 1] = cores[b_nr] + delta_cores;
1728cbf97abaSHubert Chrzaniuk 		ratio[b_nr + 1] = ratio[b_nr] - delta_ratio;
1729cbf97abaSHubert Chrzaniuk 		b_nr++;
1730fb5d4327SDasaratharaman Chandramouli 	}
1731cbf97abaSHubert Chrzaniuk 
1732cbf97abaSHubert Chrzaniuk 	for (i = buckets_no - 1; i >= 0; i--)
1733cbf97abaSHubert Chrzaniuk 		if (i > 0 ? ratio[i] != ratio[i - 1] : 1)
1734b7d8c148SLen Brown 			fprintf(outf,
1735fb5d4327SDasaratharaman Chandramouli 				"%d * %.0f = %.0f MHz max turbo %d active cores\n",
1736cbf97abaSHubert Chrzaniuk 				ratio[i], bclk, ratio[i] * bclk, cores[i]);
1737fb5d4327SDasaratharaman Chandramouli }
1738fb5d4327SDasaratharaman Chandramouli 
1739fb5d4327SDasaratharaman Chandramouli static void
1740fcd17211SLen Brown dump_nhm_cst_cfg(void)
1741fcd17211SLen Brown {
1742fcd17211SLen Brown 	unsigned long long msr;
1743fcd17211SLen Brown 
17447ce7d5deSPrarit Bhargava 	get_msr(base_cpu, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr);
1745fcd17211SLen Brown 
1746fcd17211SLen Brown #define SNB_C1_AUTO_UNDEMOTE              (1UL << 27)
1747fcd17211SLen Brown #define SNB_C3_AUTO_UNDEMOTE              (1UL << 28)
1748fcd17211SLen Brown 
1749b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x%08llx", base_cpu, msr);
1750fcd17211SLen Brown 
1751b7d8c148SLen Brown 	fprintf(outf, " (%s%s%s%s%slocked: pkg-cstate-limit=%d: %s)\n",
1752fcd17211SLen Brown 		(msr & SNB_C3_AUTO_UNDEMOTE) ? "UNdemote-C3, " : "",
1753fcd17211SLen Brown 		(msr & SNB_C1_AUTO_UNDEMOTE) ? "UNdemote-C1, " : "",
1754fcd17211SLen Brown 		(msr & NHM_C3_AUTO_DEMOTE) ? "demote-C3, " : "",
1755fcd17211SLen Brown 		(msr & NHM_C1_AUTO_DEMOTE) ? "demote-C1, " : "",
1756fcd17211SLen Brown 		(msr & (1 << 15)) ? "" : "UN",
17576c34f160SLen Brown 		(unsigned int)msr & 0xF,
1758fcd17211SLen Brown 		pkg_cstate_limit_strings[pkg_cstate_limit]);
1759fcd17211SLen Brown 	return;
1760103a8feaSLen Brown }
1761103a8feaSLen Brown 
17626fb3143bSLen Brown static void
17636fb3143bSLen Brown dump_config_tdp(void)
17646fb3143bSLen Brown {
17656fb3143bSLen Brown 	unsigned long long msr;
17666fb3143bSLen Brown 
17676fb3143bSLen Brown 	get_msr(base_cpu, MSR_CONFIG_TDP_NOMINAL, &msr);
1768b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_CONFIG_TDP_NOMINAL: 0x%08llx", base_cpu, msr);
1769685b535bSChen Yu 	fprintf(outf, " (base_ratio=%d)\n", (unsigned int)msr & 0xFF);
17706fb3143bSLen Brown 
17716fb3143bSLen Brown 	get_msr(base_cpu, MSR_CONFIG_TDP_LEVEL_1, &msr);
1772b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_CONFIG_TDP_LEVEL_1: 0x%08llx (", base_cpu, msr);
17736fb3143bSLen Brown 	if (msr) {
1774685b535bSChen Yu 		fprintf(outf, "PKG_MIN_PWR_LVL1=%d ", (unsigned int)(msr >> 48) & 0x7FFF);
1775685b535bSChen Yu 		fprintf(outf, "PKG_MAX_PWR_LVL1=%d ", (unsigned int)(msr >> 32) & 0x7FFF);
1776685b535bSChen Yu 		fprintf(outf, "LVL1_RATIO=%d ", (unsigned int)(msr >> 16) & 0xFF);
1777685b535bSChen Yu 		fprintf(outf, "PKG_TDP_LVL1=%d", (unsigned int)(msr) & 0x7FFF);
17786fb3143bSLen Brown 	}
1779b7d8c148SLen Brown 	fprintf(outf, ")\n");
17806fb3143bSLen Brown 
17816fb3143bSLen Brown 	get_msr(base_cpu, MSR_CONFIG_TDP_LEVEL_2, &msr);
1782b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_CONFIG_TDP_LEVEL_2: 0x%08llx (", base_cpu, msr);
17836fb3143bSLen Brown 	if (msr) {
1784685b535bSChen Yu 		fprintf(outf, "PKG_MIN_PWR_LVL2=%d ", (unsigned int)(msr >> 48) & 0x7FFF);
1785685b535bSChen Yu 		fprintf(outf, "PKG_MAX_PWR_LVL2=%d ", (unsigned int)(msr >> 32) & 0x7FFF);
1786685b535bSChen Yu 		fprintf(outf, "LVL2_RATIO=%d ", (unsigned int)(msr >> 16) & 0xFF);
1787685b535bSChen Yu 		fprintf(outf, "PKG_TDP_LVL2=%d", (unsigned int)(msr) & 0x7FFF);
17886fb3143bSLen Brown 	}
1789b7d8c148SLen Brown 	fprintf(outf, ")\n");
17906fb3143bSLen Brown 
17916fb3143bSLen Brown 	get_msr(base_cpu, MSR_CONFIG_TDP_CONTROL, &msr);
1792b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_CONFIG_TDP_CONTROL: 0x%08llx (", base_cpu, msr);
17936fb3143bSLen Brown 	if ((msr) & 0x3)
1794b7d8c148SLen Brown 		fprintf(outf, "TDP_LEVEL=%d ", (unsigned int)(msr) & 0x3);
1795b7d8c148SLen Brown 	fprintf(outf, " lock=%d", (unsigned int)(msr >> 31) & 1);
1796b7d8c148SLen Brown 	fprintf(outf, ")\n");
17976fb3143bSLen Brown 
17986fb3143bSLen Brown 	get_msr(base_cpu, MSR_TURBO_ACTIVATION_RATIO, &msr);
1799b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_TURBO_ACTIVATION_RATIO: 0x%08llx (", base_cpu, msr);
1800685b535bSChen Yu 	fprintf(outf, "MAX_NON_TURBO_RATIO=%d", (unsigned int)(msr) & 0xFF);
1801b7d8c148SLen Brown 	fprintf(outf, " lock=%d", (unsigned int)(msr >> 31) & 1);
1802b7d8c148SLen Brown 	fprintf(outf, ")\n");
18036fb3143bSLen Brown }
18045a63426eSLen Brown 
18055a63426eSLen Brown unsigned int irtl_time_units[] = {1, 32, 1024, 32768, 1048576, 33554432, 0, 0 };
18065a63426eSLen Brown 
18075a63426eSLen Brown void print_irtl(void)
18085a63426eSLen Brown {
18095a63426eSLen Brown 	unsigned long long msr;
18105a63426eSLen Brown 
18115a63426eSLen Brown 	get_msr(base_cpu, MSR_PKGC3_IRTL, &msr);
18125a63426eSLen Brown 	fprintf(outf, "cpu%d: MSR_PKGC3_IRTL: 0x%08llx (", base_cpu, msr);
18135a63426eSLen Brown 	fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
18145a63426eSLen Brown 		(msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
18155a63426eSLen Brown 
18165a63426eSLen Brown 	get_msr(base_cpu, MSR_PKGC6_IRTL, &msr);
18175a63426eSLen Brown 	fprintf(outf, "cpu%d: MSR_PKGC6_IRTL: 0x%08llx (", base_cpu, msr);
18185a63426eSLen Brown 	fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
18195a63426eSLen Brown 		(msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
18205a63426eSLen Brown 
18215a63426eSLen Brown 	get_msr(base_cpu, MSR_PKGC7_IRTL, &msr);
18225a63426eSLen Brown 	fprintf(outf, "cpu%d: MSR_PKGC7_IRTL: 0x%08llx (", base_cpu, msr);
18235a63426eSLen Brown 	fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
18245a63426eSLen Brown 		(msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
18255a63426eSLen Brown 
18265a63426eSLen Brown 	if (!do_irtl_hsw)
18275a63426eSLen Brown 		return;
18285a63426eSLen Brown 
18295a63426eSLen Brown 	get_msr(base_cpu, MSR_PKGC8_IRTL, &msr);
18305a63426eSLen Brown 	fprintf(outf, "cpu%d: MSR_PKGC8_IRTL: 0x%08llx (", base_cpu, msr);
18315a63426eSLen Brown 	fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
18325a63426eSLen Brown 		(msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
18335a63426eSLen Brown 
18345a63426eSLen Brown 	get_msr(base_cpu, MSR_PKGC9_IRTL, &msr);
18355a63426eSLen Brown 	fprintf(outf, "cpu%d: MSR_PKGC9_IRTL: 0x%08llx (", base_cpu, msr);
18365a63426eSLen Brown 	fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
18375a63426eSLen Brown 		(msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
18385a63426eSLen Brown 
18395a63426eSLen Brown 	get_msr(base_cpu, MSR_PKGC10_IRTL, &msr);
18405a63426eSLen Brown 	fprintf(outf, "cpu%d: MSR_PKGC10_IRTL: 0x%08llx (", base_cpu, msr);
18415a63426eSLen Brown 	fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
18425a63426eSLen Brown 		(msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
18435a63426eSLen Brown 
18445a63426eSLen Brown }
184536229897SLen Brown void free_fd_percpu(void)
184636229897SLen Brown {
184736229897SLen Brown 	int i;
184836229897SLen Brown 
184901a67adfSMika Westerberg 	for (i = 0; i < topo.max_cpu_num + 1; ++i) {
185036229897SLen Brown 		if (fd_percpu[i] != 0)
185136229897SLen Brown 			close(fd_percpu[i]);
185236229897SLen Brown 	}
185336229897SLen Brown 
185436229897SLen Brown 	free(fd_percpu);
18556fb3143bSLen Brown }
18566fb3143bSLen Brown 
1857c98d5d94SLen Brown void free_all_buffers(void)
1858103a8feaSLen Brown {
1859c98d5d94SLen Brown 	CPU_FREE(cpu_present_set);
1860c98d5d94SLen Brown 	cpu_present_set = NULL;
186136229897SLen Brown 	cpu_present_setsize = 0;
1862103a8feaSLen Brown 
1863c98d5d94SLen Brown 	CPU_FREE(cpu_affinity_set);
1864c98d5d94SLen Brown 	cpu_affinity_set = NULL;
1865c98d5d94SLen Brown 	cpu_affinity_setsize = 0;
1866103a8feaSLen Brown 
1867c98d5d94SLen Brown 	free(thread_even);
1868c98d5d94SLen Brown 	free(core_even);
1869c98d5d94SLen Brown 	free(package_even);
1870103a8feaSLen Brown 
1871c98d5d94SLen Brown 	thread_even = NULL;
1872c98d5d94SLen Brown 	core_even = NULL;
1873c98d5d94SLen Brown 	package_even = NULL;
1874103a8feaSLen Brown 
1875c98d5d94SLen Brown 	free(thread_odd);
1876c98d5d94SLen Brown 	free(core_odd);
1877c98d5d94SLen Brown 	free(package_odd);
1878103a8feaSLen Brown 
1879c98d5d94SLen Brown 	thread_odd = NULL;
1880c98d5d94SLen Brown 	core_odd = NULL;
1881c98d5d94SLen Brown 	package_odd = NULL;
1882103a8feaSLen Brown 
1883c98d5d94SLen Brown 	free(output_buffer);
1884c98d5d94SLen Brown 	output_buffer = NULL;
1885c98d5d94SLen Brown 	outp = NULL;
188636229897SLen Brown 
188736229897SLen Brown 	free_fd_percpu();
1888562a2d37SLen Brown 
1889562a2d37SLen Brown 	free(irq_column_2_cpu);
1890562a2d37SLen Brown 	free(irqs_per_cpu);
1891103a8feaSLen Brown }
1892103a8feaSLen Brown 
1893103a8feaSLen Brown /*
189457a42a34SJosh Triplett  * Open a file, and exit on failure
189557a42a34SJosh Triplett  */
189657a42a34SJosh Triplett FILE *fopen_or_die(const char *path, const char *mode)
189757a42a34SJosh Triplett {
1898b7d8c148SLen Brown 	FILE *filep = fopen(path, mode);
1899b2c95d90SJosh Triplett 	if (!filep)
1900b2c95d90SJosh Triplett 		err(1, "%s: open failed", path);
190157a42a34SJosh Triplett 	return filep;
190257a42a34SJosh Triplett }
190357a42a34SJosh Triplett 
190457a42a34SJosh Triplett /*
190595aebc44SJosh Triplett  * Parse a file containing a single int.
190695aebc44SJosh Triplett  */
190795aebc44SJosh Triplett int parse_int_file(const char *fmt, ...)
190895aebc44SJosh Triplett {
190995aebc44SJosh Triplett 	va_list args;
191095aebc44SJosh Triplett 	char path[PATH_MAX];
191195aebc44SJosh Triplett 	FILE *filep;
191295aebc44SJosh Triplett 	int value;
191395aebc44SJosh Triplett 
191495aebc44SJosh Triplett 	va_start(args, fmt);
191595aebc44SJosh Triplett 	vsnprintf(path, sizeof(path), fmt, args);
191695aebc44SJosh Triplett 	va_end(args);
191757a42a34SJosh Triplett 	filep = fopen_or_die(path, "r");
1918b2c95d90SJosh Triplett 	if (fscanf(filep, "%d", &value) != 1)
1919b2c95d90SJosh Triplett 		err(1, "%s: failed to parse number from file", path);
192095aebc44SJosh Triplett 	fclose(filep);
192195aebc44SJosh Triplett 	return value;
192295aebc44SJosh Triplett }
192395aebc44SJosh Triplett 
192495aebc44SJosh Triplett /*
1925e275b388SDasaratharaman Chandramouli  * get_cpu_position_in_core(cpu)
1926e275b388SDasaratharaman Chandramouli  * return the position of the CPU among its HT siblings in the core
1927e275b388SDasaratharaman Chandramouli  * return -1 if the sibling is not in list
1928103a8feaSLen Brown  */
1929e275b388SDasaratharaman Chandramouli int get_cpu_position_in_core(int cpu)
1930103a8feaSLen Brown {
1931e275b388SDasaratharaman Chandramouli 	char path[64];
1932e275b388SDasaratharaman Chandramouli 	FILE *filep;
1933e275b388SDasaratharaman Chandramouli 	int this_cpu;
1934e275b388SDasaratharaman Chandramouli 	char character;
1935e275b388SDasaratharaman Chandramouli 	int i;
1936e275b388SDasaratharaman Chandramouli 
1937e275b388SDasaratharaman Chandramouli 	sprintf(path,
1938e275b388SDasaratharaman Chandramouli 		"/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list",
1939e275b388SDasaratharaman Chandramouli 		cpu);
1940e275b388SDasaratharaman Chandramouli 	filep = fopen(path, "r");
1941e275b388SDasaratharaman Chandramouli 	if (filep == NULL) {
1942e275b388SDasaratharaman Chandramouli 		perror(path);
1943e275b388SDasaratharaman Chandramouli 		exit(1);
1944e275b388SDasaratharaman Chandramouli 	}
1945e275b388SDasaratharaman Chandramouli 
1946e275b388SDasaratharaman Chandramouli 	for (i = 0; i < topo.num_threads_per_core; i++) {
1947e275b388SDasaratharaman Chandramouli 		fscanf(filep, "%d", &this_cpu);
1948e275b388SDasaratharaman Chandramouli 		if (this_cpu == cpu) {
1949e275b388SDasaratharaman Chandramouli 			fclose(filep);
1950e275b388SDasaratharaman Chandramouli 			return i;
1951e275b388SDasaratharaman Chandramouli 		}
1952e275b388SDasaratharaman Chandramouli 
1953e275b388SDasaratharaman Chandramouli 		/* Account for no separator after last thread*/
1954e275b388SDasaratharaman Chandramouli 		if (i != (topo.num_threads_per_core - 1))
1955e275b388SDasaratharaman Chandramouli 			fscanf(filep, "%c", &character);
1956e275b388SDasaratharaman Chandramouli 	}
1957e275b388SDasaratharaman Chandramouli 
1958e275b388SDasaratharaman Chandramouli 	fclose(filep);
1959e275b388SDasaratharaman Chandramouli 	return -1;
1960c98d5d94SLen Brown }
1961103a8feaSLen Brown 
1962c98d5d94SLen Brown /*
1963c98d5d94SLen Brown  * cpu_is_first_core_in_package(cpu)
1964c98d5d94SLen Brown  * return 1 if given CPU is 1st core in package
1965c98d5d94SLen Brown  */
1966c98d5d94SLen Brown int cpu_is_first_core_in_package(int cpu)
1967c98d5d94SLen Brown {
196895aebc44SJosh Triplett 	return cpu == parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", cpu);
1969103a8feaSLen Brown }
1970103a8feaSLen Brown 
1971103a8feaSLen Brown int get_physical_package_id(int cpu)
1972103a8feaSLen Brown {
197395aebc44SJosh Triplett 	return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu);
1974103a8feaSLen Brown }
1975103a8feaSLen Brown 
1976103a8feaSLen Brown int get_core_id(int cpu)
1977103a8feaSLen Brown {
197895aebc44SJosh Triplett 	return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_id", cpu);
1979103a8feaSLen Brown }
1980103a8feaSLen Brown 
1981c98d5d94SLen Brown int get_num_ht_siblings(int cpu)
1982c98d5d94SLen Brown {
1983c98d5d94SLen Brown 	char path[80];
1984c98d5d94SLen Brown 	FILE *filep;
1985e275b388SDasaratharaman Chandramouli 	int sib1;
1986e275b388SDasaratharaman Chandramouli 	int matches = 0;
1987c98d5d94SLen Brown 	char character;
1988e275b388SDasaratharaman Chandramouli 	char str[100];
1989e275b388SDasaratharaman Chandramouli 	char *ch;
1990c98d5d94SLen Brown 
1991c98d5d94SLen Brown 	sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu);
199257a42a34SJosh Triplett 	filep = fopen_or_die(path, "r");
1993e275b388SDasaratharaman Chandramouli 
1994103a8feaSLen Brown 	/*
1995c98d5d94SLen Brown 	 * file format:
1996e275b388SDasaratharaman Chandramouli 	 * A ',' separated or '-' separated set of numbers
1997e275b388SDasaratharaman Chandramouli 	 * (eg 1-2 or 1,3,4,5)
1998c98d5d94SLen Brown 	 */
1999e275b388SDasaratharaman Chandramouli 	fscanf(filep, "%d%c\n", &sib1, &character);
2000e275b388SDasaratharaman Chandramouli 	fseek(filep, 0, SEEK_SET);
2001e275b388SDasaratharaman Chandramouli 	fgets(str, 100, filep);
2002e275b388SDasaratharaman Chandramouli 	ch = strchr(str, character);
2003e275b388SDasaratharaman Chandramouli 	while (ch != NULL) {
2004e275b388SDasaratharaman Chandramouli 		matches++;
2005e275b388SDasaratharaman Chandramouli 		ch = strchr(ch+1, character);
2006e275b388SDasaratharaman Chandramouli 	}
2007c98d5d94SLen Brown 
2008c98d5d94SLen Brown 	fclose(filep);
2009e275b388SDasaratharaman Chandramouli 	return matches+1;
2010c98d5d94SLen Brown }
2011c98d5d94SLen Brown 
2012c98d5d94SLen Brown /*
2013c98d5d94SLen Brown  * run func(thread, core, package) in topology order
2014c98d5d94SLen Brown  * skip non-present cpus
2015103a8feaSLen Brown  */
2016103a8feaSLen Brown 
2017c98d5d94SLen Brown int for_all_cpus_2(int (func)(struct thread_data *, struct core_data *,
2018c98d5d94SLen Brown 	struct pkg_data *, struct thread_data *, struct core_data *,
2019c98d5d94SLen Brown 	struct pkg_data *), struct thread_data *thread_base,
2020c98d5d94SLen Brown 	struct core_data *core_base, struct pkg_data *pkg_base,
2021c98d5d94SLen Brown 	struct thread_data *thread_base2, struct core_data *core_base2,
2022c98d5d94SLen Brown 	struct pkg_data *pkg_base2)
2023c98d5d94SLen Brown {
2024c98d5d94SLen Brown 	int retval, pkg_no, core_no, thread_no;
2025c98d5d94SLen Brown 
2026c98d5d94SLen Brown 	for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) {
2027c98d5d94SLen Brown 		for (core_no = 0; core_no < topo.num_cores_per_pkg; ++core_no) {
2028c98d5d94SLen Brown 			for (thread_no = 0; thread_no <
2029c98d5d94SLen Brown 				topo.num_threads_per_core; ++thread_no) {
2030c98d5d94SLen Brown 				struct thread_data *t, *t2;
2031c98d5d94SLen Brown 				struct core_data *c, *c2;
2032c98d5d94SLen Brown 				struct pkg_data *p, *p2;
2033c98d5d94SLen Brown 
2034c98d5d94SLen Brown 				t = GET_THREAD(thread_base, thread_no, core_no, pkg_no);
2035c98d5d94SLen Brown 
2036c98d5d94SLen Brown 				if (cpu_is_not_present(t->cpu_id))
2037c98d5d94SLen Brown 					continue;
2038c98d5d94SLen Brown 
2039c98d5d94SLen Brown 				t2 = GET_THREAD(thread_base2, thread_no, core_no, pkg_no);
2040c98d5d94SLen Brown 
2041c98d5d94SLen Brown 				c = GET_CORE(core_base, core_no, pkg_no);
2042c98d5d94SLen Brown 				c2 = GET_CORE(core_base2, core_no, pkg_no);
2043c98d5d94SLen Brown 
2044c98d5d94SLen Brown 				p = GET_PKG(pkg_base, pkg_no);
2045c98d5d94SLen Brown 				p2 = GET_PKG(pkg_base2, pkg_no);
2046c98d5d94SLen Brown 
2047c98d5d94SLen Brown 				retval = func(t, c, p, t2, c2, p2);
2048c98d5d94SLen Brown 				if (retval)
2049c98d5d94SLen Brown 					return retval;
2050c98d5d94SLen Brown 			}
2051c98d5d94SLen Brown 		}
2052c98d5d94SLen Brown 	}
2053c98d5d94SLen Brown 	return 0;
2054c98d5d94SLen Brown }
2055c98d5d94SLen Brown 
2056c98d5d94SLen Brown /*
2057c98d5d94SLen Brown  * run func(cpu) on every cpu in /proc/stat
2058c98d5d94SLen Brown  * return max_cpu number
2059c98d5d94SLen Brown  */
2060c98d5d94SLen Brown int for_all_proc_cpus(int (func)(int))
2061103a8feaSLen Brown {
2062103a8feaSLen Brown 	FILE *fp;
2063c98d5d94SLen Brown 	int cpu_num;
2064103a8feaSLen Brown 	int retval;
2065103a8feaSLen Brown 
206657a42a34SJosh Triplett 	fp = fopen_or_die(proc_stat, "r");
2067103a8feaSLen Brown 
2068103a8feaSLen Brown 	retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n");
2069b2c95d90SJosh Triplett 	if (retval != 0)
2070b2c95d90SJosh Triplett 		err(1, "%s: failed to parse format", proc_stat);
2071103a8feaSLen Brown 
2072c98d5d94SLen Brown 	while (1) {
2073c98d5d94SLen Brown 		retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num);
2074103a8feaSLen Brown 		if (retval != 1)
2075103a8feaSLen Brown 			break;
2076103a8feaSLen Brown 
2077c98d5d94SLen Brown 		retval = func(cpu_num);
2078c98d5d94SLen Brown 		if (retval) {
2079c98d5d94SLen Brown 			fclose(fp);
2080c98d5d94SLen Brown 			return(retval);
2081c98d5d94SLen Brown 		}
2082103a8feaSLen Brown 	}
2083103a8feaSLen Brown 	fclose(fp);
2084c98d5d94SLen Brown 	return 0;
2085103a8feaSLen Brown }
2086103a8feaSLen Brown 
2087103a8feaSLen Brown void re_initialize(void)
2088103a8feaSLen Brown {
2089c98d5d94SLen Brown 	free_all_buffers();
2090c98d5d94SLen Brown 	setup_all_buffers();
2091c98d5d94SLen Brown 	printf("turbostat: re-initialized with num_cpus %d\n", topo.num_cpus);
2092103a8feaSLen Brown }
2093103a8feaSLen Brown 
2094c98d5d94SLen Brown 
2095103a8feaSLen Brown /*
2096c98d5d94SLen Brown  * count_cpus()
2097c98d5d94SLen Brown  * remember the last one seen, it will be the max
2098103a8feaSLen Brown  */
2099c98d5d94SLen Brown int count_cpus(int cpu)
2100103a8feaSLen Brown {
2101c98d5d94SLen Brown 	if (topo.max_cpu_num < cpu)
2102c98d5d94SLen Brown 		topo.max_cpu_num = cpu;
2103103a8feaSLen Brown 
2104c98d5d94SLen Brown 	topo.num_cpus += 1;
2105c98d5d94SLen Brown 	return 0;
2106103a8feaSLen Brown }
2107c98d5d94SLen Brown int mark_cpu_present(int cpu)
2108c98d5d94SLen Brown {
2109c98d5d94SLen Brown 	CPU_SET_S(cpu, cpu_present_setsize, cpu_present_set);
211015aaa346SLen Brown 	return 0;
2111103a8feaSLen Brown }
2112103a8feaSLen Brown 
2113562a2d37SLen Brown /*
2114562a2d37SLen Brown  * snapshot_proc_interrupts()
2115562a2d37SLen Brown  *
2116562a2d37SLen Brown  * read and record summary of /proc/interrupts
2117562a2d37SLen Brown  *
2118562a2d37SLen Brown  * return 1 if config change requires a restart, else return 0
2119562a2d37SLen Brown  */
2120562a2d37SLen Brown int snapshot_proc_interrupts(void)
2121562a2d37SLen Brown {
2122562a2d37SLen Brown 	static FILE *fp;
2123562a2d37SLen Brown 	int column, retval;
2124562a2d37SLen Brown 
2125562a2d37SLen Brown 	if (fp == NULL)
2126562a2d37SLen Brown 		fp = fopen_or_die("/proc/interrupts", "r");
2127562a2d37SLen Brown 	else
2128562a2d37SLen Brown 		rewind(fp);
2129562a2d37SLen Brown 
2130562a2d37SLen Brown 	/* read 1st line of /proc/interrupts to get cpu* name for each column */
2131562a2d37SLen Brown 	for (column = 0; column < topo.num_cpus; ++column) {
2132562a2d37SLen Brown 		int cpu_number;
2133562a2d37SLen Brown 
2134562a2d37SLen Brown 		retval = fscanf(fp, " CPU%d", &cpu_number);
2135562a2d37SLen Brown 		if (retval != 1)
2136562a2d37SLen Brown 			break;
2137562a2d37SLen Brown 
2138562a2d37SLen Brown 		if (cpu_number > topo.max_cpu_num) {
2139562a2d37SLen Brown 			warn("/proc/interrupts: cpu%d: > %d", cpu_number, topo.max_cpu_num);
2140562a2d37SLen Brown 			return 1;
2141562a2d37SLen Brown 		}
2142562a2d37SLen Brown 
2143562a2d37SLen Brown 		irq_column_2_cpu[column] = cpu_number;
2144562a2d37SLen Brown 		irqs_per_cpu[cpu_number] = 0;
2145562a2d37SLen Brown 	}
2146562a2d37SLen Brown 
2147562a2d37SLen Brown 	/* read /proc/interrupt count lines and sum up irqs per cpu */
2148562a2d37SLen Brown 	while (1) {
2149562a2d37SLen Brown 		int column;
2150562a2d37SLen Brown 		char buf[64];
2151562a2d37SLen Brown 
2152562a2d37SLen Brown 		retval = fscanf(fp, " %s:", buf);	/* flush irq# "N:" */
2153562a2d37SLen Brown 		if (retval != 1)
2154562a2d37SLen Brown 			break;
2155562a2d37SLen Brown 
2156562a2d37SLen Brown 		/* read the count per cpu */
2157562a2d37SLen Brown 		for (column = 0; column < topo.num_cpus; ++column) {
2158562a2d37SLen Brown 
2159562a2d37SLen Brown 			int cpu_number, irq_count;
2160562a2d37SLen Brown 
2161562a2d37SLen Brown 			retval = fscanf(fp, " %d", &irq_count);
2162562a2d37SLen Brown 			if (retval != 1)
2163562a2d37SLen Brown 				break;
2164562a2d37SLen Brown 
2165562a2d37SLen Brown 			cpu_number = irq_column_2_cpu[column];
2166562a2d37SLen Brown 			irqs_per_cpu[cpu_number] += irq_count;
2167562a2d37SLen Brown 
2168562a2d37SLen Brown 		}
2169562a2d37SLen Brown 
2170562a2d37SLen Brown 		while (getc(fp) != '\n')
2171562a2d37SLen Brown 			;	/* flush interrupt description */
2172562a2d37SLen Brown 
2173562a2d37SLen Brown 	}
2174562a2d37SLen Brown 	return 0;
2175562a2d37SLen Brown }
217627d47356SLen Brown /*
2177fdf676e5SLen Brown  * snapshot_gfx_rc6_ms()
2178fdf676e5SLen Brown  *
2179fdf676e5SLen Brown  * record snapshot of
2180fdf676e5SLen Brown  * /sys/class/drm/card0/power/rc6_residency_ms
2181fdf676e5SLen Brown  *
2182fdf676e5SLen Brown  * return 1 if config change requires a restart, else return 0
2183fdf676e5SLen Brown  */
2184fdf676e5SLen Brown int snapshot_gfx_rc6_ms(void)
2185fdf676e5SLen Brown {
2186fdf676e5SLen Brown 	FILE *fp;
2187fdf676e5SLen Brown 	int retval;
2188fdf676e5SLen Brown 
2189fdf676e5SLen Brown 	fp = fopen_or_die("/sys/class/drm/card0/power/rc6_residency_ms", "r");
2190fdf676e5SLen Brown 
2191fdf676e5SLen Brown 	retval = fscanf(fp, "%lld", &gfx_cur_rc6_ms);
2192fdf676e5SLen Brown 	if (retval != 1)
2193fdf676e5SLen Brown 		err(1, "GFX rc6");
2194fdf676e5SLen Brown 
2195fdf676e5SLen Brown 	fclose(fp);
2196fdf676e5SLen Brown 
2197fdf676e5SLen Brown 	return 0;
2198fdf676e5SLen Brown }
2199fdf676e5SLen Brown /*
220027d47356SLen Brown  * snapshot_gfx_mhz()
220127d47356SLen Brown  *
220227d47356SLen Brown  * record snapshot of
220327d47356SLen Brown  * /sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz
220427d47356SLen Brown  *
220527d47356SLen Brown  * return 1 if config change requires a restart, else return 0
220627d47356SLen Brown  */
220727d47356SLen Brown int snapshot_gfx_mhz(void)
220827d47356SLen Brown {
220927d47356SLen Brown 	static FILE *fp;
221027d47356SLen Brown 	int retval;
221127d47356SLen Brown 
221227d47356SLen Brown 	if (fp == NULL)
221327d47356SLen Brown 		fp = fopen_or_die("/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz", "r");
221427d47356SLen Brown 	else
221527d47356SLen Brown 		rewind(fp);
221627d47356SLen Brown 
221727d47356SLen Brown 	retval = fscanf(fp, "%d", &gfx_cur_mhz);
221827d47356SLen Brown 	if (retval != 1)
221927d47356SLen Brown 		err(1, "GFX MHz");
222027d47356SLen Brown 
222127d47356SLen Brown 	return 0;
222227d47356SLen Brown }
2223562a2d37SLen Brown 
2224562a2d37SLen Brown /*
2225562a2d37SLen Brown  * snapshot /proc and /sys files
2226562a2d37SLen Brown  *
2227562a2d37SLen Brown  * return 1 if configuration restart needed, else return 0
2228562a2d37SLen Brown  */
2229562a2d37SLen Brown int snapshot_proc_sysfs_files(void)
2230562a2d37SLen Brown {
2231562a2d37SLen Brown 	if (snapshot_proc_interrupts())
2232562a2d37SLen Brown 		return 1;
2233562a2d37SLen Brown 
2234fdf676e5SLen Brown 	if (do_gfx_rc6_ms)
2235fdf676e5SLen Brown 		snapshot_gfx_rc6_ms();
2236fdf676e5SLen Brown 
223727d47356SLen Brown 	if (do_gfx_mhz)
223827d47356SLen Brown 		snapshot_gfx_mhz();
223927d47356SLen Brown 
2240562a2d37SLen Brown 	return 0;
2241562a2d37SLen Brown }
2242562a2d37SLen Brown 
2243103a8feaSLen Brown void turbostat_loop()
2244103a8feaSLen Brown {
2245c98d5d94SLen Brown 	int retval;
2246e52966c0SLen Brown 	int restarted = 0;
2247c98d5d94SLen Brown 
2248103a8feaSLen Brown restart:
2249e52966c0SLen Brown 	restarted++;
2250e52966c0SLen Brown 
2251562a2d37SLen Brown 	snapshot_proc_sysfs_files();
2252c98d5d94SLen Brown 	retval = for_all_cpus(get_counters, EVEN_COUNTERS);
2253d91bb17cSLen Brown 	if (retval < -1) {
2254d91bb17cSLen Brown 		exit(retval);
2255d91bb17cSLen Brown 	} else if (retval == -1) {
2256e52966c0SLen Brown 		if (restarted > 1) {
2257e52966c0SLen Brown 			exit(retval);
2258e52966c0SLen Brown 		}
2259c98d5d94SLen Brown 		re_initialize();
2260c98d5d94SLen Brown 		goto restart;
2261c98d5d94SLen Brown 	}
2262e52966c0SLen Brown 	restarted = 0;
2263103a8feaSLen Brown 	gettimeofday(&tv_even, (struct timezone *)NULL);
2264103a8feaSLen Brown 
2265103a8feaSLen Brown 	while (1) {
2266c98d5d94SLen Brown 		if (for_all_proc_cpus(cpu_is_not_present)) {
2267103a8feaSLen Brown 			re_initialize();
2268103a8feaSLen Brown 			goto restart;
2269103a8feaSLen Brown 		}
22702a0609c0SLen Brown 		nanosleep(&interval_ts, NULL);
2271562a2d37SLen Brown 		if (snapshot_proc_sysfs_files())
2272562a2d37SLen Brown 			goto restart;
2273c98d5d94SLen Brown 		retval = for_all_cpus(get_counters, ODD_COUNTERS);
2274d91bb17cSLen Brown 		if (retval < -1) {
2275d91bb17cSLen Brown 			exit(retval);
2276d91bb17cSLen Brown 		} else if (retval == -1) {
227715aaa346SLen Brown 			re_initialize();
227815aaa346SLen Brown 			goto restart;
227915aaa346SLen Brown 		}
2280103a8feaSLen Brown 		gettimeofday(&tv_odd, (struct timezone *)NULL);
2281103a8feaSLen Brown 		timersub(&tv_odd, &tv_even, &tv_delta);
2282ba3dec99SLen Brown 		if (for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS)) {
2283ba3dec99SLen Brown 			re_initialize();
2284ba3dec99SLen Brown 			goto restart;
2285ba3dec99SLen Brown 		}
2286c98d5d94SLen Brown 		compute_average(EVEN_COUNTERS);
2287c98d5d94SLen Brown 		format_all_counters(EVEN_COUNTERS);
2288b7d8c148SLen Brown 		flush_output_stdout();
22892a0609c0SLen Brown 		nanosleep(&interval_ts, NULL);
2290562a2d37SLen Brown 		if (snapshot_proc_sysfs_files())
2291562a2d37SLen Brown 			goto restart;
2292c98d5d94SLen Brown 		retval = for_all_cpus(get_counters, EVEN_COUNTERS);
2293d91bb17cSLen Brown 		if (retval < -1) {
2294d91bb17cSLen Brown 			exit(retval);
2295d91bb17cSLen Brown 		} else if (retval == -1) {
2296103a8feaSLen Brown 			re_initialize();
2297103a8feaSLen Brown 			goto restart;
2298103a8feaSLen Brown 		}
2299103a8feaSLen Brown 		gettimeofday(&tv_even, (struct timezone *)NULL);
2300103a8feaSLen Brown 		timersub(&tv_even, &tv_odd, &tv_delta);
2301ba3dec99SLen Brown 		if (for_all_cpus_2(delta_cpu, EVEN_COUNTERS, ODD_COUNTERS)) {
2302ba3dec99SLen Brown 			re_initialize();
2303ba3dec99SLen Brown 			goto restart;
2304ba3dec99SLen Brown 		}
2305c98d5d94SLen Brown 		compute_average(ODD_COUNTERS);
2306c98d5d94SLen Brown 		format_all_counters(ODD_COUNTERS);
2307b7d8c148SLen Brown 		flush_output_stdout();
2308103a8feaSLen Brown 	}
2309103a8feaSLen Brown }
2310103a8feaSLen Brown 
2311103a8feaSLen Brown void check_dev_msr()
2312103a8feaSLen Brown {
2313103a8feaSLen Brown 	struct stat sb;
23147ce7d5deSPrarit Bhargava 	char pathname[32];
2315103a8feaSLen Brown 
23167ce7d5deSPrarit Bhargava 	sprintf(pathname, "/dev/cpu/%d/msr", base_cpu);
23177ce7d5deSPrarit Bhargava 	if (stat(pathname, &sb))
2318a21d38c8SLen Brown  		if (system("/sbin/modprobe msr > /dev/null 2>&1"))
2319d7899447SLen Brown 			err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" ");
2320103a8feaSLen Brown }
2321103a8feaSLen Brown 
232298481e79SLen Brown void check_permissions()
2323103a8feaSLen Brown {
232498481e79SLen Brown 	struct __user_cap_header_struct cap_header_data;
232598481e79SLen Brown 	cap_user_header_t cap_header = &cap_header_data;
232698481e79SLen Brown 	struct __user_cap_data_struct cap_data_data;
232798481e79SLen Brown 	cap_user_data_t cap_data = &cap_data_data;
232898481e79SLen Brown 	extern int capget(cap_user_header_t hdrp, cap_user_data_t datap);
232998481e79SLen Brown 	int do_exit = 0;
23307ce7d5deSPrarit Bhargava 	char pathname[32];
233198481e79SLen Brown 
233298481e79SLen Brown 	/* check for CAP_SYS_RAWIO */
233398481e79SLen Brown 	cap_header->pid = getpid();
233498481e79SLen Brown 	cap_header->version = _LINUX_CAPABILITY_VERSION;
233598481e79SLen Brown 	if (capget(cap_header, cap_data) < 0)
233698481e79SLen Brown 		err(-6, "capget(2) failed");
233798481e79SLen Brown 
233898481e79SLen Brown 	if ((cap_data->effective & (1 << CAP_SYS_RAWIO)) == 0) {
233998481e79SLen Brown 		do_exit++;
234098481e79SLen Brown 		warnx("capget(CAP_SYS_RAWIO) failed,"
234198481e79SLen Brown 			" try \"# setcap cap_sys_rawio=ep %s\"", progname);
234298481e79SLen Brown 	}
234398481e79SLen Brown 
234498481e79SLen Brown 	/* test file permissions */
23457ce7d5deSPrarit Bhargava 	sprintf(pathname, "/dev/cpu/%d/msr", base_cpu);
23467ce7d5deSPrarit Bhargava 	if (euidaccess(pathname, R_OK)) {
234798481e79SLen Brown 		do_exit++;
234898481e79SLen Brown 		warn("/dev/cpu/0/msr open failed, try chown or chmod +r /dev/cpu/*/msr");
234998481e79SLen Brown 	}
235098481e79SLen Brown 
235198481e79SLen Brown 	/* if all else fails, thell them to be root */
235298481e79SLen Brown 	if (do_exit)
2353b2c95d90SJosh Triplett 		if (getuid() != 0)
2354d7899447SLen Brown 			warnx("... or simply run as root");
235598481e79SLen Brown 
235698481e79SLen Brown 	if (do_exit)
235798481e79SLen Brown 		exit(-6);
2358103a8feaSLen Brown }
2359103a8feaSLen Brown 
2360d7899447SLen Brown /*
2361d7899447SLen Brown  * NHM adds support for additional MSRs:
2362d7899447SLen Brown  *
2363d7899447SLen Brown  * MSR_SMI_COUNT                   0x00000034
2364d7899447SLen Brown  *
2365ec0adc53SLen Brown  * MSR_PLATFORM_INFO               0x000000ce
2366d7899447SLen Brown  * MSR_NHM_SNB_PKG_CST_CFG_CTL     0x000000e2
2367d7899447SLen Brown  *
2368d7899447SLen Brown  * MSR_PKG_C3_RESIDENCY            0x000003f8
2369d7899447SLen Brown  * MSR_PKG_C6_RESIDENCY            0x000003f9
2370d7899447SLen Brown  * MSR_CORE_C3_RESIDENCY           0x000003fc
2371d7899447SLen Brown  * MSR_CORE_C6_RESIDENCY           0x000003fd
2372d7899447SLen Brown  *
2373ee7e38e3SLen Brown  * Side effect:
2374ee7e38e3SLen Brown  * sets global pkg_cstate_limit to decode MSR_NHM_SNB_PKG_CST_CFG_CTL
2375d7899447SLen Brown  */
2376ee7e38e3SLen Brown int probe_nhm_msrs(unsigned int family, unsigned int model)
2377103a8feaSLen Brown {
2378ee7e38e3SLen Brown 	unsigned long long msr;
237921ed5574SLen Brown 	unsigned int base_ratio;
2380ee7e38e3SLen Brown 	int *pkg_cstate_limits;
2381ee7e38e3SLen Brown 
2382103a8feaSLen Brown 	if (!genuine_intel)
2383103a8feaSLen Brown 		return 0;
2384103a8feaSLen Brown 
2385103a8feaSLen Brown 	if (family != 6)
2386103a8feaSLen Brown 		return 0;
2387103a8feaSLen Brown 
238821ed5574SLen Brown 	bclk = discover_bclk(family, model);
238921ed5574SLen Brown 
2390103a8feaSLen Brown 	switch (model) {
2391869ce69eSLen Brown 	case INTEL_FAM6_NEHALEM_EP:	/* Core i7, Xeon 5500 series - Bloomfield, Gainstown NHM-EP */
2392869ce69eSLen Brown 	case INTEL_FAM6_NEHALEM:	/* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */
2393103a8feaSLen Brown 	case 0x1F:	/* Core i7 and i5 Processor - Nehalem */
2394869ce69eSLen Brown 	case INTEL_FAM6_WESTMERE:	/* Westmere Client - Clarkdale, Arrandale */
2395869ce69eSLen Brown 	case INTEL_FAM6_WESTMERE_EP:	/* Westmere EP - Gulftown */
2396869ce69eSLen Brown 	case INTEL_FAM6_NEHALEM_EX:	/* Nehalem-EX Xeon - Beckton */
2397869ce69eSLen Brown 	case INTEL_FAM6_WESTMERE_EX:	/* Westmere-EX Xeon - Eagleton */
2398ee7e38e3SLen Brown 		pkg_cstate_limits = nhm_pkg_cstate_limits;
2399ee7e38e3SLen Brown 		break;
2400869ce69eSLen Brown 	case INTEL_FAM6_SANDYBRIDGE:	/* SNB */
2401869ce69eSLen Brown 	case INTEL_FAM6_SANDYBRIDGE_X:	/* SNB Xeon */
2402869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE:	/* IVB */
2403869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE_X:	/* IVB Xeon */
2404ee7e38e3SLen Brown 		pkg_cstate_limits = snb_pkg_cstate_limits;
2405ee7e38e3SLen Brown 		break;
2406869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
2407869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSX */
2408869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
2409869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
2410869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
2411869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_GT3E:	/* BDW */
2412869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_X:	/* BDX */
2413869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
2414869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
2415869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
2416869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
2417869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
2418ee7e38e3SLen Brown 		pkg_cstate_limits = hsw_pkg_cstate_limits;
2419ee7e38e3SLen Brown 		break;
2420d8ebb442SLen Brown 	case INTEL_FAM6_SKYLAKE_X:	/* SKX */
2421d8ebb442SLen Brown 		pkg_cstate_limits = skx_pkg_cstate_limits;
2422d8ebb442SLen Brown 		break;
2423869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT1:	/* BYT */
2424869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT2:	/* AVN */
2425ee7e38e3SLen Brown 		pkg_cstate_limits = slv_pkg_cstate_limits;
2426ee7e38e3SLen Brown 		break;
2427869ce69eSLen Brown 	case INTEL_FAM6_ATOM_AIRMONT:	/* AMT */
2428ee7e38e3SLen Brown 		pkg_cstate_limits = amt_pkg_cstate_limits;
2429ee7e38e3SLen Brown 		break;
2430869ce69eSLen Brown 	case INTEL_FAM6_XEON_PHI_KNL:	/* PHI */
2431005c82d6SLen Brown 	case INTEL_FAM6_XEON_PHI_KNM:
2432ee7e38e3SLen Brown 		pkg_cstate_limits = phi_pkg_cstate_limits;
2433ee7e38e3SLen Brown 		break;
2434869ce69eSLen Brown 	case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
2435869ce69eSLen Brown 	case INTEL_FAM6_ATOM_DENVERTON:	/* DNV */
2436e4085d54SLen Brown 		pkg_cstate_limits = bxt_pkg_cstate_limits;
2437e4085d54SLen Brown 		break;
2438103a8feaSLen Brown 	default:
2439103a8feaSLen Brown 		return 0;
2440103a8feaSLen Brown 	}
24417ce7d5deSPrarit Bhargava 	get_msr(base_cpu, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr);
2442e9257f5fSLen Brown 	pkg_cstate_limit = pkg_cstate_limits[msr & 0xF];
2443ee7e38e3SLen Brown 
2444ec0adc53SLen Brown 	get_msr(base_cpu, MSR_PLATFORM_INFO, &msr);
244521ed5574SLen Brown 	base_ratio = (msr >> 8) & 0xFF;
244621ed5574SLen Brown 
244721ed5574SLen Brown 	base_hz = base_ratio * bclk * 1000000;
244821ed5574SLen Brown 	has_base_hz = 1;
2449ee7e38e3SLen Brown 	return 1;
2450103a8feaSLen Brown }
2451d7899447SLen Brown int has_nhm_turbo_ratio_limit(unsigned int family, unsigned int model)
2452d7899447SLen Brown {
2453d7899447SLen Brown 	switch (model) {
2454d7899447SLen Brown 	/* Nehalem compatible, but do not include turbo-ratio limit support */
2455869ce69eSLen Brown 	case INTEL_FAM6_NEHALEM_EX:	/* Nehalem-EX Xeon - Beckton */
2456869ce69eSLen Brown 	case INTEL_FAM6_WESTMERE_EX:	/* Westmere-EX Xeon - Eagleton */
2457869ce69eSLen Brown 	case INTEL_FAM6_XEON_PHI_KNL:	/* PHI - Knights Landing (different MSR definition) */
2458005c82d6SLen Brown 	case INTEL_FAM6_XEON_PHI_KNM:
2459d7899447SLen Brown 		return 0;
2460d7899447SLen Brown 	default:
2461d7899447SLen Brown 		return 1;
2462d7899447SLen Brown 	}
2463d7899447SLen Brown }
24646574a5d5SLen Brown int has_ivt_turbo_ratio_limit(unsigned int family, unsigned int model)
24656574a5d5SLen Brown {
24666574a5d5SLen Brown 	if (!genuine_intel)
24676574a5d5SLen Brown 		return 0;
24686574a5d5SLen Brown 
24696574a5d5SLen Brown 	if (family != 6)
24706574a5d5SLen Brown 		return 0;
24716574a5d5SLen Brown 
24726574a5d5SLen Brown 	switch (model) {
2473869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE_X:	/* IVB Xeon */
2474869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSW Xeon */
24756574a5d5SLen Brown 		return 1;
24766574a5d5SLen Brown 	default:
24776574a5d5SLen Brown 		return 0;
24786574a5d5SLen Brown 	}
24796574a5d5SLen Brown }
2480fcd17211SLen Brown int has_hsw_turbo_ratio_limit(unsigned int family, unsigned int model)
2481fcd17211SLen Brown {
2482fcd17211SLen Brown 	if (!genuine_intel)
2483fcd17211SLen Brown 		return 0;
2484fcd17211SLen Brown 
2485fcd17211SLen Brown 	if (family != 6)
2486fcd17211SLen Brown 		return 0;
2487fcd17211SLen Brown 
2488fcd17211SLen Brown 	switch (model) {
2489869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSW Xeon */
2490fcd17211SLen Brown 		return 1;
2491fcd17211SLen Brown 	default:
2492fcd17211SLen Brown 		return 0;
2493fcd17211SLen Brown 	}
2494fcd17211SLen Brown }
2495fcd17211SLen Brown 
2496fb5d4327SDasaratharaman Chandramouli int has_knl_turbo_ratio_limit(unsigned int family, unsigned int model)
2497fb5d4327SDasaratharaman Chandramouli {
2498fb5d4327SDasaratharaman Chandramouli 	if (!genuine_intel)
2499fb5d4327SDasaratharaman Chandramouli 		return 0;
2500fb5d4327SDasaratharaman Chandramouli 
2501fb5d4327SDasaratharaman Chandramouli 	if (family != 6)
2502fb5d4327SDasaratharaman Chandramouli 		return 0;
2503fb5d4327SDasaratharaman Chandramouli 
2504fb5d4327SDasaratharaman Chandramouli 	switch (model) {
2505869ce69eSLen Brown 	case INTEL_FAM6_XEON_PHI_KNL:	/* Knights Landing */
2506005c82d6SLen Brown 	case INTEL_FAM6_XEON_PHI_KNM:
2507fb5d4327SDasaratharaman Chandramouli 		return 1;
2508fb5d4327SDasaratharaman Chandramouli 	default:
2509fb5d4327SDasaratharaman Chandramouli 		return 0;
2510fb5d4327SDasaratharaman Chandramouli 	}
2511fb5d4327SDasaratharaman Chandramouli }
25126fb3143bSLen Brown int has_config_tdp(unsigned int family, unsigned int model)
25136fb3143bSLen Brown {
25146fb3143bSLen Brown 	if (!genuine_intel)
25156fb3143bSLen Brown 		return 0;
25166fb3143bSLen Brown 
25176fb3143bSLen Brown 	if (family != 6)
25186fb3143bSLen Brown 		return 0;
25196fb3143bSLen Brown 
25206fb3143bSLen Brown 	switch (model) {
2521869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE:	/* IVB */
2522869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
2523869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSX */
2524869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
2525869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
2526869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
2527869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_GT3E:	/* BDW */
2528869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_X:	/* BDX */
2529869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
2530869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
2531869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
2532869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
2533869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
2534869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_X:	/* SKX */
25356fb3143bSLen Brown 
2536869ce69eSLen Brown 	case INTEL_FAM6_XEON_PHI_KNL:	/* Knights Landing */
2537005c82d6SLen Brown 	case INTEL_FAM6_XEON_PHI_KNM:
25386fb3143bSLen Brown 		return 1;
25396fb3143bSLen Brown 	default:
25406fb3143bSLen Brown 		return 0;
25416fb3143bSLen Brown 	}
25426fb3143bSLen Brown }
25436fb3143bSLen Brown 
2544fcd17211SLen Brown static void
25451b69317dSColin Ian King dump_cstate_pstate_config_info(unsigned int family, unsigned int model)
2546fcd17211SLen Brown {
2547fcd17211SLen Brown 	if (!do_nhm_platform_info)
2548fcd17211SLen Brown 		return;
2549fcd17211SLen Brown 
2550fcd17211SLen Brown 	dump_nhm_platform_info();
2551fcd17211SLen Brown 
2552fcd17211SLen Brown 	if (has_hsw_turbo_ratio_limit(family, model))
2553fcd17211SLen Brown 		dump_hsw_turbo_ratio_limits();
2554fcd17211SLen Brown 
2555fcd17211SLen Brown 	if (has_ivt_turbo_ratio_limit(family, model))
2556fcd17211SLen Brown 		dump_ivt_turbo_ratio_limits();
2557fcd17211SLen Brown 
2558fcd17211SLen Brown 	if (has_nhm_turbo_ratio_limit(family, model))
2559fcd17211SLen Brown 		dump_nhm_turbo_ratio_limits();
2560fcd17211SLen Brown 
2561fb5d4327SDasaratharaman Chandramouli 	if (has_knl_turbo_ratio_limit(family, model))
2562fb5d4327SDasaratharaman Chandramouli 		dump_knl_turbo_ratio_limits();
2563fb5d4327SDasaratharaman Chandramouli 
25646fb3143bSLen Brown 	if (has_config_tdp(family, model))
25656fb3143bSLen Brown 		dump_config_tdp();
25666fb3143bSLen Brown 
2567fcd17211SLen Brown 	dump_nhm_cst_cfg();
2568fcd17211SLen Brown }
2569fcd17211SLen Brown 
25706574a5d5SLen Brown 
2571889facbeSLen Brown /*
2572889facbeSLen Brown  * print_epb()
2573889facbeSLen Brown  * Decode the ENERGY_PERF_BIAS MSR
2574889facbeSLen Brown  */
2575889facbeSLen Brown int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p)
2576889facbeSLen Brown {
2577889facbeSLen Brown 	unsigned long long msr;
2578889facbeSLen Brown 	char *epb_string;
2579889facbeSLen Brown 	int cpu;
2580889facbeSLen Brown 
2581889facbeSLen Brown 	if (!has_epb)
2582889facbeSLen Brown 		return 0;
2583889facbeSLen Brown 
2584889facbeSLen Brown 	cpu = t->cpu_id;
2585889facbeSLen Brown 
2586889facbeSLen Brown 	/* EPB is per-package */
2587889facbeSLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
2588889facbeSLen Brown 		return 0;
2589889facbeSLen Brown 
2590889facbeSLen Brown 	if (cpu_migrate(cpu)) {
2591b7d8c148SLen Brown 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
2592889facbeSLen Brown 		return -1;
2593889facbeSLen Brown 	}
2594889facbeSLen Brown 
2595889facbeSLen Brown 	if (get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr))
2596889facbeSLen Brown 		return 0;
2597889facbeSLen Brown 
2598e9be7dd6SLen Brown 	switch (msr & 0xF) {
2599889facbeSLen Brown 	case ENERGY_PERF_BIAS_PERFORMANCE:
2600889facbeSLen Brown 		epb_string = "performance";
2601889facbeSLen Brown 		break;
2602889facbeSLen Brown 	case ENERGY_PERF_BIAS_NORMAL:
2603889facbeSLen Brown 		epb_string = "balanced";
2604889facbeSLen Brown 		break;
2605889facbeSLen Brown 	case ENERGY_PERF_BIAS_POWERSAVE:
2606889facbeSLen Brown 		epb_string = "powersave";
2607889facbeSLen Brown 		break;
2608889facbeSLen Brown 	default:
2609889facbeSLen Brown 		epb_string = "custom";
2610889facbeSLen Brown 		break;
2611889facbeSLen Brown 	}
2612b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_IA32_ENERGY_PERF_BIAS: 0x%08llx (%s)\n", cpu, msr, epb_string);
2613889facbeSLen Brown 
2614889facbeSLen Brown 	return 0;
2615889facbeSLen Brown }
26167f5c258eSLen Brown /*
26177f5c258eSLen Brown  * print_hwp()
26187f5c258eSLen Brown  * Decode the MSR_HWP_CAPABILITIES
26197f5c258eSLen Brown  */
26207f5c258eSLen Brown int print_hwp(struct thread_data *t, struct core_data *c, struct pkg_data *p)
26217f5c258eSLen Brown {
26227f5c258eSLen Brown 	unsigned long long msr;
26237f5c258eSLen Brown 	int cpu;
26247f5c258eSLen Brown 
26257f5c258eSLen Brown 	if (!has_hwp)
26267f5c258eSLen Brown 		return 0;
26277f5c258eSLen Brown 
26287f5c258eSLen Brown 	cpu = t->cpu_id;
26297f5c258eSLen Brown 
26307f5c258eSLen Brown 	/* MSR_HWP_CAPABILITIES is per-package */
26317f5c258eSLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
26327f5c258eSLen Brown 		return 0;
26337f5c258eSLen Brown 
26347f5c258eSLen Brown 	if (cpu_migrate(cpu)) {
2635b7d8c148SLen Brown 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
26367f5c258eSLen Brown 		return -1;
26377f5c258eSLen Brown 	}
26387f5c258eSLen Brown 
26397f5c258eSLen Brown 	if (get_msr(cpu, MSR_PM_ENABLE, &msr))
26407f5c258eSLen Brown 		return 0;
26417f5c258eSLen Brown 
2642b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_PM_ENABLE: 0x%08llx (%sHWP)\n",
26437f5c258eSLen Brown 		cpu, msr, (msr & (1 << 0)) ? "" : "No-");
26447f5c258eSLen Brown 
26457f5c258eSLen Brown 	/* MSR_PM_ENABLE[1] == 1 if HWP is enabled and MSRs visible */
26467f5c258eSLen Brown 	if ((msr & (1 << 0)) == 0)
26477f5c258eSLen Brown 		return 0;
26487f5c258eSLen Brown 
26497f5c258eSLen Brown 	if (get_msr(cpu, MSR_HWP_CAPABILITIES, &msr))
26507f5c258eSLen Brown 		return 0;
26517f5c258eSLen Brown 
2652b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_HWP_CAPABILITIES: 0x%08llx "
26537f5c258eSLen Brown 			"(high 0x%x guar 0x%x eff 0x%x low 0x%x)\n",
26547f5c258eSLen Brown 			cpu, msr,
26557f5c258eSLen Brown 			(unsigned int)HWP_HIGHEST_PERF(msr),
26567f5c258eSLen Brown 			(unsigned int)HWP_GUARANTEED_PERF(msr),
26577f5c258eSLen Brown 			(unsigned int)HWP_MOSTEFFICIENT_PERF(msr),
26587f5c258eSLen Brown 			(unsigned int)HWP_LOWEST_PERF(msr));
26597f5c258eSLen Brown 
26607f5c258eSLen Brown 	if (get_msr(cpu, MSR_HWP_REQUEST, &msr))
26617f5c258eSLen Brown 		return 0;
26627f5c258eSLen Brown 
2663b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_HWP_REQUEST: 0x%08llx "
26647f5c258eSLen Brown 			"(min 0x%x max 0x%x des 0x%x epp 0x%x window 0x%x pkg 0x%x)\n",
26657f5c258eSLen Brown 			cpu, msr,
26667f5c258eSLen Brown 			(unsigned int)(((msr) >> 0) & 0xff),
26677f5c258eSLen Brown 			(unsigned int)(((msr) >> 8) & 0xff),
26687f5c258eSLen Brown 			(unsigned int)(((msr) >> 16) & 0xff),
26697f5c258eSLen Brown 			(unsigned int)(((msr) >> 24) & 0xff),
26707f5c258eSLen Brown 			(unsigned int)(((msr) >> 32) & 0xff3),
26717f5c258eSLen Brown 			(unsigned int)(((msr) >> 42) & 0x1));
26727f5c258eSLen Brown 
26737f5c258eSLen Brown 	if (has_hwp_pkg) {
26747f5c258eSLen Brown 		if (get_msr(cpu, MSR_HWP_REQUEST_PKG, &msr))
26757f5c258eSLen Brown 			return 0;
26767f5c258eSLen Brown 
2677b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_HWP_REQUEST_PKG: 0x%08llx "
26787f5c258eSLen Brown 			"(min 0x%x max 0x%x des 0x%x epp 0x%x window 0x%x)\n",
26797f5c258eSLen Brown 			cpu, msr,
26807f5c258eSLen Brown 			(unsigned int)(((msr) >> 0) & 0xff),
26817f5c258eSLen Brown 			(unsigned int)(((msr) >> 8) & 0xff),
26827f5c258eSLen Brown 			(unsigned int)(((msr) >> 16) & 0xff),
26837f5c258eSLen Brown 			(unsigned int)(((msr) >> 24) & 0xff),
26847f5c258eSLen Brown 			(unsigned int)(((msr) >> 32) & 0xff3));
26857f5c258eSLen Brown 	}
26867f5c258eSLen Brown 	if (has_hwp_notify) {
26877f5c258eSLen Brown 		if (get_msr(cpu, MSR_HWP_INTERRUPT, &msr))
26887f5c258eSLen Brown 			return 0;
26897f5c258eSLen Brown 
2690b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_HWP_INTERRUPT: 0x%08llx "
26917f5c258eSLen Brown 			"(%s_Guaranteed_Perf_Change, %s_Excursion_Min)\n",
26927f5c258eSLen Brown 			cpu, msr,
26937f5c258eSLen Brown 			((msr) & 0x1) ? "EN" : "Dis",
26947f5c258eSLen Brown 			((msr) & 0x2) ? "EN" : "Dis");
26957f5c258eSLen Brown 	}
26967f5c258eSLen Brown 	if (get_msr(cpu, MSR_HWP_STATUS, &msr))
26977f5c258eSLen Brown 		return 0;
26987f5c258eSLen Brown 
2699b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_HWP_STATUS: 0x%08llx "
27007f5c258eSLen Brown 			"(%sGuaranteed_Perf_Change, %sExcursion_Min)\n",
27017f5c258eSLen Brown 			cpu, msr,
27027f5c258eSLen Brown 			((msr) & 0x1) ? "" : "No-",
27037f5c258eSLen Brown 			((msr) & 0x2) ? "" : "No-");
2704889facbeSLen Brown 
2705889facbeSLen Brown 	return 0;
2706889facbeSLen Brown }
2707889facbeSLen Brown 
27083a9a941dSLen Brown /*
27093a9a941dSLen Brown  * print_perf_limit()
27103a9a941dSLen Brown  */
27113a9a941dSLen Brown int print_perf_limit(struct thread_data *t, struct core_data *c, struct pkg_data *p)
27123a9a941dSLen Brown {
27133a9a941dSLen Brown 	unsigned long long msr;
27143a9a941dSLen Brown 	int cpu;
27153a9a941dSLen Brown 
27163a9a941dSLen Brown 	cpu = t->cpu_id;
27173a9a941dSLen Brown 
27183a9a941dSLen Brown 	/* per-package */
27193a9a941dSLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
27203a9a941dSLen Brown 		return 0;
27213a9a941dSLen Brown 
27223a9a941dSLen Brown 	if (cpu_migrate(cpu)) {
2723b7d8c148SLen Brown 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
27243a9a941dSLen Brown 		return -1;
27253a9a941dSLen Brown 	}
27263a9a941dSLen Brown 
27273a9a941dSLen Brown 	if (do_core_perf_limit_reasons) {
27283a9a941dSLen Brown 		get_msr(cpu, MSR_CORE_PERF_LIMIT_REASONS, &msr);
2729b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_CORE_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
2730b7d8c148SLen Brown 		fprintf(outf, " (Active: %s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
2731e33cbe85SLen Brown 			(msr & 1 << 15) ? "bit15, " : "",
27323a9a941dSLen Brown 			(msr & 1 << 14) ? "bit14, " : "",
2733e33cbe85SLen Brown 			(msr & 1 << 13) ? "Transitions, " : "",
2734e33cbe85SLen Brown 			(msr & 1 << 12) ? "MultiCoreTurbo, " : "",
2735e33cbe85SLen Brown 			(msr & 1 << 11) ? "PkgPwrL2, " : "",
2736e33cbe85SLen Brown 			(msr & 1 << 10) ? "PkgPwrL1, " : "",
2737e33cbe85SLen Brown 			(msr & 1 << 9) ? "CorePwr, " : "",
2738e33cbe85SLen Brown 			(msr & 1 << 8) ? "Amps, " : "",
2739e33cbe85SLen Brown 			(msr & 1 << 6) ? "VR-Therm, " : "",
2740e33cbe85SLen Brown 			(msr & 1 << 5) ? "Auto-HWP, " : "",
2741e33cbe85SLen Brown 			(msr & 1 << 4) ? "Graphics, " : "",
2742e33cbe85SLen Brown 			(msr & 1 << 2) ? "bit2, " : "",
2743e33cbe85SLen Brown 			(msr & 1 << 1) ? "ThermStatus, " : "",
2744e33cbe85SLen Brown 			(msr & 1 << 0) ? "PROCHOT, " : "");
2745b7d8c148SLen Brown 		fprintf(outf, " (Logged: %s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n",
2746e33cbe85SLen Brown 			(msr & 1 << 31) ? "bit31, " : "",
27473a9a941dSLen Brown 			(msr & 1 << 30) ? "bit30, " : "",
2748e33cbe85SLen Brown 			(msr & 1 << 29) ? "Transitions, " : "",
2749e33cbe85SLen Brown 			(msr & 1 << 28) ? "MultiCoreTurbo, " : "",
2750e33cbe85SLen Brown 			(msr & 1 << 27) ? "PkgPwrL2, " : "",
2751e33cbe85SLen Brown 			(msr & 1 << 26) ? "PkgPwrL1, " : "",
2752e33cbe85SLen Brown 			(msr & 1 << 25) ? "CorePwr, " : "",
2753e33cbe85SLen Brown 			(msr & 1 << 24) ? "Amps, " : "",
2754e33cbe85SLen Brown 			(msr & 1 << 22) ? "VR-Therm, " : "",
2755e33cbe85SLen Brown 			(msr & 1 << 21) ? "Auto-HWP, " : "",
2756e33cbe85SLen Brown 			(msr & 1 << 20) ? "Graphics, " : "",
2757e33cbe85SLen Brown 			(msr & 1 << 18) ? "bit18, " : "",
2758e33cbe85SLen Brown 			(msr & 1 << 17) ? "ThermStatus, " : "",
2759e33cbe85SLen Brown 			(msr & 1 << 16) ? "PROCHOT, " : "");
27603a9a941dSLen Brown 
27613a9a941dSLen Brown 	}
27623a9a941dSLen Brown 	if (do_gfx_perf_limit_reasons) {
27633a9a941dSLen Brown 		get_msr(cpu, MSR_GFX_PERF_LIMIT_REASONS, &msr);
2764b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_GFX_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
2765b7d8c148SLen Brown 		fprintf(outf, " (Active: %s%s%s%s%s%s%s%s)",
27663a9a941dSLen Brown 			(msr & 1 << 0) ? "PROCHOT, " : "",
27673a9a941dSLen Brown 			(msr & 1 << 1) ? "ThermStatus, " : "",
27683a9a941dSLen Brown 			(msr & 1 << 4) ? "Graphics, " : "",
27693a9a941dSLen Brown 			(msr & 1 << 6) ? "VR-Therm, " : "",
27703a9a941dSLen Brown 			(msr & 1 << 8) ? "Amps, " : "",
27713a9a941dSLen Brown 			(msr & 1 << 9) ? "GFXPwr, " : "",
27723a9a941dSLen Brown 			(msr & 1 << 10) ? "PkgPwrL1, " : "",
27733a9a941dSLen Brown 			(msr & 1 << 11) ? "PkgPwrL2, " : "");
2774b7d8c148SLen Brown 		fprintf(outf, " (Logged: %s%s%s%s%s%s%s%s)\n",
27753a9a941dSLen Brown 			(msr & 1 << 16) ? "PROCHOT, " : "",
27763a9a941dSLen Brown 			(msr & 1 << 17) ? "ThermStatus, " : "",
27773a9a941dSLen Brown 			(msr & 1 << 20) ? "Graphics, " : "",
27783a9a941dSLen Brown 			(msr & 1 << 22) ? "VR-Therm, " : "",
27793a9a941dSLen Brown 			(msr & 1 << 24) ? "Amps, " : "",
27803a9a941dSLen Brown 			(msr & 1 << 25) ? "GFXPwr, " : "",
27813a9a941dSLen Brown 			(msr & 1 << 26) ? "PkgPwrL1, " : "",
27823a9a941dSLen Brown 			(msr & 1 << 27) ? "PkgPwrL2, " : "");
27833a9a941dSLen Brown 	}
27843a9a941dSLen Brown 	if (do_ring_perf_limit_reasons) {
27853a9a941dSLen Brown 		get_msr(cpu, MSR_RING_PERF_LIMIT_REASONS, &msr);
2786b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_RING_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
2787b7d8c148SLen Brown 		fprintf(outf, " (Active: %s%s%s%s%s%s)",
27883a9a941dSLen Brown 			(msr & 1 << 0) ? "PROCHOT, " : "",
27893a9a941dSLen Brown 			(msr & 1 << 1) ? "ThermStatus, " : "",
27903a9a941dSLen Brown 			(msr & 1 << 6) ? "VR-Therm, " : "",
27913a9a941dSLen Brown 			(msr & 1 << 8) ? "Amps, " : "",
27923a9a941dSLen Brown 			(msr & 1 << 10) ? "PkgPwrL1, " : "",
27933a9a941dSLen Brown 			(msr & 1 << 11) ? "PkgPwrL2, " : "");
2794b7d8c148SLen Brown 		fprintf(outf, " (Logged: %s%s%s%s%s%s)\n",
27953a9a941dSLen Brown 			(msr & 1 << 16) ? "PROCHOT, " : "",
27963a9a941dSLen Brown 			(msr & 1 << 17) ? "ThermStatus, " : "",
27973a9a941dSLen Brown 			(msr & 1 << 22) ? "VR-Therm, " : "",
27983a9a941dSLen Brown 			(msr & 1 << 24) ? "Amps, " : "",
27993a9a941dSLen Brown 			(msr & 1 << 26) ? "PkgPwrL1, " : "",
28003a9a941dSLen Brown 			(msr & 1 << 27) ? "PkgPwrL2, " : "");
28013a9a941dSLen Brown 	}
28023a9a941dSLen Brown 	return 0;
28033a9a941dSLen Brown }
28043a9a941dSLen Brown 
2805889facbeSLen Brown #define	RAPL_POWER_GRANULARITY	0x7FFF	/* 15 bit power granularity */
2806889facbeSLen Brown #define	RAPL_TIME_GRANULARITY	0x3F /* 6 bit time granularity */
2807889facbeSLen Brown 
28081b69317dSColin Ian King double get_tdp(unsigned int model)
2809144b44b1SLen Brown {
2810144b44b1SLen Brown 	unsigned long long msr;
2811144b44b1SLen Brown 
2812144b44b1SLen Brown 	if (do_rapl & RAPL_PKG_POWER_INFO)
28137ce7d5deSPrarit Bhargava 		if (!get_msr(base_cpu, MSR_PKG_POWER_INFO, &msr))
2814144b44b1SLen Brown 			return ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units;
2815144b44b1SLen Brown 
2816144b44b1SLen Brown 	switch (model) {
2817869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT1:
2818869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT2:
2819144b44b1SLen Brown 		return 30.0;
2820144b44b1SLen Brown 	default:
2821144b44b1SLen Brown 		return 135.0;
2822144b44b1SLen Brown 	}
2823144b44b1SLen Brown }
2824144b44b1SLen Brown 
282540ee8e3bSAndrey Semin /*
282640ee8e3bSAndrey Semin  * rapl_dram_energy_units_probe()
282740ee8e3bSAndrey Semin  * Energy units are either hard-coded, or come from RAPL Energy Unit MSR.
282840ee8e3bSAndrey Semin  */
282940ee8e3bSAndrey Semin static double
283040ee8e3bSAndrey Semin rapl_dram_energy_units_probe(int  model, double rapl_energy_units)
283140ee8e3bSAndrey Semin {
283240ee8e3bSAndrey Semin 	/* only called for genuine_intel, family 6 */
283340ee8e3bSAndrey Semin 
283440ee8e3bSAndrey Semin 	switch (model) {
2835869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSX */
2836869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_X:	/* BDX */
2837869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
2838869ce69eSLen Brown 	case INTEL_FAM6_XEON_PHI_KNL:	/* KNL */
2839005c82d6SLen Brown 	case INTEL_FAM6_XEON_PHI_KNM:
284040ee8e3bSAndrey Semin 		return (rapl_dram_energy_units = 15.3 / 1000000);
284140ee8e3bSAndrey Semin 	default:
284240ee8e3bSAndrey Semin 		return (rapl_energy_units);
284340ee8e3bSAndrey Semin 	}
284440ee8e3bSAndrey Semin }
284540ee8e3bSAndrey Semin 
2846144b44b1SLen Brown 
2847889facbeSLen Brown /*
2848889facbeSLen Brown  * rapl_probe()
2849889facbeSLen Brown  *
2850144b44b1SLen Brown  * sets do_rapl, rapl_power_units, rapl_energy_units, rapl_time_units
2851889facbeSLen Brown  */
2852889facbeSLen Brown void rapl_probe(unsigned int family, unsigned int model)
2853889facbeSLen Brown {
2854889facbeSLen Brown 	unsigned long long msr;
2855144b44b1SLen Brown 	unsigned int time_unit;
2856889facbeSLen Brown 	double tdp;
2857889facbeSLen Brown 
2858889facbeSLen Brown 	if (!genuine_intel)
2859889facbeSLen Brown 		return;
2860889facbeSLen Brown 
2861889facbeSLen Brown 	if (family != 6)
2862889facbeSLen Brown 		return;
2863889facbeSLen Brown 
2864889facbeSLen Brown 	switch (model) {
2865869ce69eSLen Brown 	case INTEL_FAM6_SANDYBRIDGE:
2866869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE:
2867869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
2868869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
2869869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
2870869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
2871869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_GT3E:	/* BDW */
2872144b44b1SLen Brown 		do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_GFX | RAPL_PKG_POWER_INFO;
2873889facbeSLen Brown 		break;
2874869ce69eSLen Brown 	case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
2875e4085d54SLen Brown 		do_rapl = RAPL_PKG | RAPL_PKG_POWER_INFO;
2876e4085d54SLen Brown 		break;
2877869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
2878869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
2879869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
2880869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
28810b2bb692SLen Brown 		do_rapl = RAPL_PKG | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO;
28820b2bb692SLen Brown 		break;
2883869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSX */
2884869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_X:	/* BDX */
2885869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
2886869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_X:	/* SKX */
2887869ce69eSLen Brown 	case INTEL_FAM6_XEON_PHI_KNL:	/* KNL */
2888005c82d6SLen Brown 	case INTEL_FAM6_XEON_PHI_KNM:
28890b2bb692SLen Brown 		do_rapl = RAPL_PKG | RAPL_DRAM | RAPL_DRAM_POWER_INFO | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO;
2890e6f9bb3cSLen Brown 		break;
2891869ce69eSLen Brown 	case INTEL_FAM6_SANDYBRIDGE_X:
2892869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE_X:
28930b2bb692SLen Brown 		do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_DRAM | RAPL_DRAM_POWER_INFO | RAPL_PKG_PERF_STATUS | RAPL_DRAM_PERF_STATUS | RAPL_PKG_POWER_INFO;
2894144b44b1SLen Brown 		break;
2895869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT1:	/* BYT */
2896869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT2:	/* AVN */
2897144b44b1SLen Brown 		do_rapl = RAPL_PKG | RAPL_CORES;
2898889facbeSLen Brown 		break;
2899869ce69eSLen Brown 	case INTEL_FAM6_ATOM_DENVERTON:	/* DNV */
29000f644909SJacob Pan 		do_rapl = RAPL_PKG | RAPL_DRAM | RAPL_DRAM_POWER_INFO | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO | RAPL_CORES_ENERGY_STATUS;
29010f644909SJacob Pan 		break;
2902889facbeSLen Brown 	default:
2903889facbeSLen Brown 		return;
2904889facbeSLen Brown 	}
2905889facbeSLen Brown 
2906889facbeSLen Brown 	/* units on package 0, verify later other packages match */
29077ce7d5deSPrarit Bhargava 	if (get_msr(base_cpu, MSR_RAPL_POWER_UNIT, &msr))
2908889facbeSLen Brown 		return;
2909889facbeSLen Brown 
2910889facbeSLen Brown 	rapl_power_units = 1.0 / (1 << (msr & 0xF));
2911869ce69eSLen Brown 	if (model == INTEL_FAM6_ATOM_SILVERMONT1)
2912144b44b1SLen Brown 		rapl_energy_units = 1.0 * (1 << (msr >> 8 & 0x1F)) / 1000000;
2913144b44b1SLen Brown 	else
2914889facbeSLen Brown 		rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F));
2915889facbeSLen Brown 
291640ee8e3bSAndrey Semin 	rapl_dram_energy_units = rapl_dram_energy_units_probe(model, rapl_energy_units);
291740ee8e3bSAndrey Semin 
2918144b44b1SLen Brown 	time_unit = msr >> 16 & 0xF;
2919144b44b1SLen Brown 	if (time_unit == 0)
2920144b44b1SLen Brown 		time_unit = 0xA;
2921889facbeSLen Brown 
2922144b44b1SLen Brown 	rapl_time_units = 1.0 / (1 << (time_unit));
2923144b44b1SLen Brown 
2924144b44b1SLen Brown 	tdp = get_tdp(model);
2925889facbeSLen Brown 
2926889facbeSLen Brown 	rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp;
2927d8af6f5fSLen Brown 	if (debug)
2928b7d8c148SLen Brown 		fprintf(outf, "RAPL: %.0f sec. Joule Counter Range, at %.0f Watts\n", rapl_joule_counter_range, tdp);
2929889facbeSLen Brown 
2930889facbeSLen Brown 	return;
2931889facbeSLen Brown }
2932889facbeSLen Brown 
29331b69317dSColin Ian King void perf_limit_reasons_probe(unsigned int family, unsigned int model)
29343a9a941dSLen Brown {
29353a9a941dSLen Brown 	if (!genuine_intel)
29363a9a941dSLen Brown 		return;
29373a9a941dSLen Brown 
29383a9a941dSLen Brown 	if (family != 6)
29393a9a941dSLen Brown 		return;
29403a9a941dSLen Brown 
29413a9a941dSLen Brown 	switch (model) {
2942869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
2943869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
2944869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
29453a9a941dSLen Brown 		do_gfx_perf_limit_reasons = 1;
2946869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSX */
29473a9a941dSLen Brown 		do_core_perf_limit_reasons = 1;
29483a9a941dSLen Brown 		do_ring_perf_limit_reasons = 1;
29493a9a941dSLen Brown 	default:
29503a9a941dSLen Brown 		return;
29513a9a941dSLen Brown 	}
29523a9a941dSLen Brown }
29533a9a941dSLen Brown 
2954889facbeSLen Brown int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p)
2955889facbeSLen Brown {
2956889facbeSLen Brown 	unsigned long long msr;
2957889facbeSLen Brown 	unsigned int dts;
2958889facbeSLen Brown 	int cpu;
2959889facbeSLen Brown 
2960889facbeSLen Brown 	if (!(do_dts || do_ptm))
2961889facbeSLen Brown 		return 0;
2962889facbeSLen Brown 
2963889facbeSLen Brown 	cpu = t->cpu_id;
2964889facbeSLen Brown 
2965889facbeSLen Brown 	/* DTS is per-core, no need to print for each thread */
2966889facbeSLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
2967889facbeSLen Brown 		return 0;
2968889facbeSLen Brown 
2969889facbeSLen Brown 	if (cpu_migrate(cpu)) {
2970b7d8c148SLen Brown 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
2971889facbeSLen Brown 		return -1;
2972889facbeSLen Brown 	}
2973889facbeSLen Brown 
2974889facbeSLen Brown 	if (do_ptm && (t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) {
2975889facbeSLen Brown 		if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr))
2976889facbeSLen Brown 			return 0;
2977889facbeSLen Brown 
2978889facbeSLen Brown 		dts = (msr >> 16) & 0x7F;
2979b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_IA32_PACKAGE_THERM_STATUS: 0x%08llx (%d C)\n",
2980889facbeSLen Brown 			cpu, msr, tcc_activation_temp - dts);
2981889facbeSLen Brown 
2982889facbeSLen Brown #ifdef	THERM_DEBUG
2983889facbeSLen Brown 		if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &msr))
2984889facbeSLen Brown 			return 0;
2985889facbeSLen Brown 
2986889facbeSLen Brown 		dts = (msr >> 16) & 0x7F;
2987889facbeSLen Brown 		dts2 = (msr >> 8) & 0x7F;
2988b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_IA32_PACKAGE_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
2989889facbeSLen Brown 			cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2);
2990889facbeSLen Brown #endif
2991889facbeSLen Brown 	}
2992889facbeSLen Brown 
2993889facbeSLen Brown 
2994889facbeSLen Brown 	if (do_dts) {
2995889facbeSLen Brown 		unsigned int resolution;
2996889facbeSLen Brown 
2997889facbeSLen Brown 		if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr))
2998889facbeSLen Brown 			return 0;
2999889facbeSLen Brown 
3000889facbeSLen Brown 		dts = (msr >> 16) & 0x7F;
3001889facbeSLen Brown 		resolution = (msr >> 27) & 0xF;
3002b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_IA32_THERM_STATUS: 0x%08llx (%d C +/- %d)\n",
3003889facbeSLen Brown 			cpu, msr, tcc_activation_temp - dts, resolution);
3004889facbeSLen Brown 
3005889facbeSLen Brown #ifdef THERM_DEBUG
3006889facbeSLen Brown 		if (get_msr(cpu, MSR_IA32_THERM_INTERRUPT, &msr))
3007889facbeSLen Brown 			return 0;
3008889facbeSLen Brown 
3009889facbeSLen Brown 		dts = (msr >> 16) & 0x7F;
3010889facbeSLen Brown 		dts2 = (msr >> 8) & 0x7F;
3011b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_IA32_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
3012889facbeSLen Brown 			cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2);
3013889facbeSLen Brown #endif
3014889facbeSLen Brown 	}
3015889facbeSLen Brown 
3016889facbeSLen Brown 	return 0;
3017889facbeSLen Brown }
3018889facbeSLen Brown 
3019889facbeSLen Brown void print_power_limit_msr(int cpu, unsigned long long msr, char *label)
3020889facbeSLen Brown {
3021b7d8c148SLen Brown 	fprintf(outf, "cpu%d: %s: %sabled (%f Watts, %f sec, clamp %sabled)\n",
3022889facbeSLen Brown 		cpu, label,
3023889facbeSLen Brown 		((msr >> 15) & 1) ? "EN" : "DIS",
3024889facbeSLen Brown 		((msr >> 0) & 0x7FFF) * rapl_power_units,
3025889facbeSLen Brown 		(1.0 + (((msr >> 22) & 0x3)/4.0)) * (1 << ((msr >> 17) & 0x1F)) * rapl_time_units,
3026889facbeSLen Brown 		(((msr >> 16) & 1) ? "EN" : "DIS"));
3027889facbeSLen Brown 
3028889facbeSLen Brown 	return;
3029889facbeSLen Brown }
3030889facbeSLen Brown 
3031889facbeSLen Brown int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
3032889facbeSLen Brown {
3033889facbeSLen Brown 	unsigned long long msr;
3034889facbeSLen Brown 	int cpu;
3035889facbeSLen Brown 
3036889facbeSLen Brown 	if (!do_rapl)
3037889facbeSLen Brown 		return 0;
3038889facbeSLen Brown 
3039889facbeSLen Brown 	/* RAPL counters are per package, so print only for 1st thread/package */
3040889facbeSLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
3041889facbeSLen Brown 		return 0;
3042889facbeSLen Brown 
3043889facbeSLen Brown 	cpu = t->cpu_id;
3044889facbeSLen Brown 	if (cpu_migrate(cpu)) {
3045b7d8c148SLen Brown 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
3046889facbeSLen Brown 		return -1;
3047889facbeSLen Brown 	}
3048889facbeSLen Brown 
3049889facbeSLen Brown 	if (get_msr(cpu, MSR_RAPL_POWER_UNIT, &msr))
3050889facbeSLen Brown 		return -1;
3051889facbeSLen Brown 
3052d8af6f5fSLen Brown 	if (debug) {
3053b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_RAPL_POWER_UNIT: 0x%08llx "
3054889facbeSLen Brown 			"(%f Watts, %f Joules, %f sec.)\n", cpu, msr,
3055144b44b1SLen Brown 			rapl_power_units, rapl_energy_units, rapl_time_units);
3056889facbeSLen Brown 	}
3057144b44b1SLen Brown 	if (do_rapl & RAPL_PKG_POWER_INFO) {
3058144b44b1SLen Brown 
3059889facbeSLen Brown 		if (get_msr(cpu, MSR_PKG_POWER_INFO, &msr))
3060889facbeSLen Brown                 	return -5;
3061889facbeSLen Brown 
3062889facbeSLen Brown 
3063b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_PKG_POWER_INFO: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n",
3064889facbeSLen Brown 			cpu, msr,
3065889facbeSLen Brown 			((msr >>  0) & RAPL_POWER_GRANULARITY) * rapl_power_units,
3066889facbeSLen Brown 			((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units,
3067889facbeSLen Brown 			((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units,
3068889facbeSLen Brown 			((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units);
3069889facbeSLen Brown 
3070144b44b1SLen Brown 	}
3071144b44b1SLen Brown 	if (do_rapl & RAPL_PKG) {
3072144b44b1SLen Brown 
3073889facbeSLen Brown 		if (get_msr(cpu, MSR_PKG_POWER_LIMIT, &msr))
3074889facbeSLen Brown 			return -9;
3075889facbeSLen Brown 
3076b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_PKG_POWER_LIMIT: 0x%08llx (%slocked)\n",
3077889facbeSLen Brown 			cpu, msr, (msr >> 63) & 1 ? "": "UN");
3078889facbeSLen Brown 
3079889facbeSLen Brown 		print_power_limit_msr(cpu, msr, "PKG Limit #1");
3080b7d8c148SLen Brown 		fprintf(outf, "cpu%d: PKG Limit #2: %sabled (%f Watts, %f* sec, clamp %sabled)\n",
3081889facbeSLen Brown 			cpu,
3082889facbeSLen Brown 			((msr >> 47) & 1) ? "EN" : "DIS",
3083889facbeSLen Brown 			((msr >> 32) & 0x7FFF) * rapl_power_units,
3084889facbeSLen Brown 			(1.0 + (((msr >> 54) & 0x3)/4.0)) * (1 << ((msr >> 49) & 0x1F)) * rapl_time_units,
3085889facbeSLen Brown 			((msr >> 48) & 1) ? "EN" : "DIS");
3086889facbeSLen Brown 	}
3087889facbeSLen Brown 
30880b2bb692SLen Brown 	if (do_rapl & RAPL_DRAM_POWER_INFO) {
3089889facbeSLen Brown 		if (get_msr(cpu, MSR_DRAM_POWER_INFO, &msr))
3090889facbeSLen Brown                 	return -6;
3091889facbeSLen Brown 
3092b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_DRAM_POWER_INFO,: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n",
3093889facbeSLen Brown 			cpu, msr,
3094889facbeSLen Brown 			((msr >>  0) & RAPL_POWER_GRANULARITY) * rapl_power_units,
3095889facbeSLen Brown 			((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units,
3096889facbeSLen Brown 			((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units,
3097889facbeSLen Brown 			((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units);
30980b2bb692SLen Brown 	}
30990b2bb692SLen Brown 	if (do_rapl & RAPL_DRAM) {
3100889facbeSLen Brown 		if (get_msr(cpu, MSR_DRAM_POWER_LIMIT, &msr))
3101889facbeSLen Brown 			return -9;
3102b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_DRAM_POWER_LIMIT: 0x%08llx (%slocked)\n",
3103889facbeSLen Brown 				cpu, msr, (msr >> 31) & 1 ? "": "UN");
3104889facbeSLen Brown 
3105889facbeSLen Brown 		print_power_limit_msr(cpu, msr, "DRAM Limit");
3106889facbeSLen Brown 	}
3107144b44b1SLen Brown 	if (do_rapl & RAPL_CORE_POLICY) {
3108d8af6f5fSLen Brown 		if (debug) {
3109889facbeSLen Brown 			if (get_msr(cpu, MSR_PP0_POLICY, &msr))
3110889facbeSLen Brown 				return -7;
3111889facbeSLen Brown 
3112b7d8c148SLen Brown 			fprintf(outf, "cpu%d: MSR_PP0_POLICY: %lld\n", cpu, msr & 0xF);
3113144b44b1SLen Brown 		}
3114144b44b1SLen Brown 	}
31159148494cSJacob Pan 	if (do_rapl & RAPL_CORES_POWER_LIMIT) {
3116d8af6f5fSLen Brown 		if (debug) {
3117889facbeSLen Brown 			if (get_msr(cpu, MSR_PP0_POWER_LIMIT, &msr))
3118889facbeSLen Brown 				return -9;
3119b7d8c148SLen Brown 			fprintf(outf, "cpu%d: MSR_PP0_POWER_LIMIT: 0x%08llx (%slocked)\n",
3120889facbeSLen Brown 					cpu, msr, (msr >> 31) & 1 ? "": "UN");
3121889facbeSLen Brown 			print_power_limit_msr(cpu, msr, "Cores Limit");
3122889facbeSLen Brown 		}
3123889facbeSLen Brown 	}
3124889facbeSLen Brown 	if (do_rapl & RAPL_GFX) {
3125d8af6f5fSLen Brown 		if (debug) {
3126889facbeSLen Brown 			if (get_msr(cpu, MSR_PP1_POLICY, &msr))
3127889facbeSLen Brown 				return -8;
3128889facbeSLen Brown 
3129b7d8c148SLen Brown 			fprintf(outf, "cpu%d: MSR_PP1_POLICY: %lld\n", cpu, msr & 0xF);
3130889facbeSLen Brown 
3131889facbeSLen Brown 			if (get_msr(cpu, MSR_PP1_POWER_LIMIT, &msr))
3132889facbeSLen Brown 				return -9;
3133b7d8c148SLen Brown 			fprintf(outf, "cpu%d: MSR_PP1_POWER_LIMIT: 0x%08llx (%slocked)\n",
3134889facbeSLen Brown 					cpu, msr, (msr >> 31) & 1 ? "": "UN");
3135889facbeSLen Brown 			print_power_limit_msr(cpu, msr, "GFX Limit");
3136889facbeSLen Brown 		}
3137889facbeSLen Brown 	}
3138889facbeSLen Brown 	return 0;
3139889facbeSLen Brown }
3140889facbeSLen Brown 
3141d7899447SLen Brown /*
3142d7899447SLen Brown  * SNB adds support for additional MSRs:
3143d7899447SLen Brown  *
3144d7899447SLen Brown  * MSR_PKG_C7_RESIDENCY            0x000003fa
3145d7899447SLen Brown  * MSR_CORE_C7_RESIDENCY           0x000003fe
3146d7899447SLen Brown  * MSR_PKG_C2_RESIDENCY            0x0000060d
3147d7899447SLen Brown  */
3148103a8feaSLen Brown 
3149d7899447SLen Brown int has_snb_msrs(unsigned int family, unsigned int model)
3150103a8feaSLen Brown {
3151103a8feaSLen Brown 	if (!genuine_intel)
3152103a8feaSLen Brown 		return 0;
3153103a8feaSLen Brown 
3154103a8feaSLen Brown 	switch (model) {
3155869ce69eSLen Brown 	case INTEL_FAM6_SANDYBRIDGE:
3156869ce69eSLen Brown 	case INTEL_FAM6_SANDYBRIDGE_X:
3157869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE:	/* IVB */
3158869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE_X:	/* IVB Xeon */
3159869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
3160869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSW */
3161869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
3162869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
3163869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
3164869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_GT3E:	/* BDW */
3165869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_X:	/* BDX */
3166869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
3167869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
3168869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
3169869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
3170869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
3171869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_X:	/* SKX */
3172869ce69eSLen Brown 	case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
31735bbac26eSXiaolong Wang 	case INTEL_FAM6_ATOM_DENVERTON:	/* DNV */
3174103a8feaSLen Brown 		return 1;
3175103a8feaSLen Brown 	}
3176103a8feaSLen Brown 	return 0;
3177103a8feaSLen Brown }
3178103a8feaSLen Brown 
3179d7899447SLen Brown /*
3180d7899447SLen Brown  * HSW adds support for additional MSRs:
3181d7899447SLen Brown  *
3182d7899447SLen Brown  * MSR_PKG_C8_RESIDENCY		0x00000630
3183d7899447SLen Brown  * MSR_PKG_C9_RESIDENCY		0x00000631
3184d7899447SLen Brown  * MSR_PKG_C10_RESIDENCY	0x00000632
31855a63426eSLen Brown  *
31865a63426eSLen Brown  * MSR_PKGC8_IRTL		0x00000633
31875a63426eSLen Brown  * MSR_PKGC9_IRTL		0x00000634
31885a63426eSLen Brown  * MSR_PKGC10_IRTL		0x00000635
31895a63426eSLen Brown  *
3190d7899447SLen Brown  */
3191d7899447SLen Brown int has_hsw_msrs(unsigned int family, unsigned int model)
3192ca58710fSKristen Carlson Accardi {
3193ca58710fSKristen Carlson Accardi 	if (!genuine_intel)
3194ca58710fSKristen Carlson Accardi 		return 0;
3195ca58710fSKristen Carlson Accardi 
3196ca58710fSKristen Carlson Accardi 	switch (model) {
3197869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
3198869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
3199869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
3200869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
3201869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
3202869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
3203869ce69eSLen Brown 	case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
3204ca58710fSKristen Carlson Accardi 		return 1;
3205ca58710fSKristen Carlson Accardi 	}
3206ca58710fSKristen Carlson Accardi 	return 0;
3207ca58710fSKristen Carlson Accardi }
3208ca58710fSKristen Carlson Accardi 
32090b2bb692SLen Brown /*
32100b2bb692SLen Brown  * SKL adds support for additional MSRS:
32110b2bb692SLen Brown  *
32120b2bb692SLen Brown  * MSR_PKG_WEIGHTED_CORE_C0_RES    0x00000658
32130b2bb692SLen Brown  * MSR_PKG_ANY_CORE_C0_RES         0x00000659
32140b2bb692SLen Brown  * MSR_PKG_ANY_GFXE_C0_RES         0x0000065A
32150b2bb692SLen Brown  * MSR_PKG_BOTH_CORE_GFXE_C0_RES   0x0000065B
32160b2bb692SLen Brown  */
32170b2bb692SLen Brown int has_skl_msrs(unsigned int family, unsigned int model)
32180b2bb692SLen Brown {
32190b2bb692SLen Brown 	if (!genuine_intel)
32200b2bb692SLen Brown 		return 0;
32210b2bb692SLen Brown 
32220b2bb692SLen Brown 	switch (model) {
3223869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
3224869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
3225869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
3226869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
32270b2bb692SLen Brown 		return 1;
32280b2bb692SLen Brown 	}
32290b2bb692SLen Brown 	return 0;
32300b2bb692SLen Brown }
32310b2bb692SLen Brown 
32320b2bb692SLen Brown 
3233ca58710fSKristen Carlson Accardi 
3234144b44b1SLen Brown int is_slm(unsigned int family, unsigned int model)
3235144b44b1SLen Brown {
3236144b44b1SLen Brown 	if (!genuine_intel)
3237144b44b1SLen Brown 		return 0;
3238144b44b1SLen Brown 	switch (model) {
3239869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT1:	/* BYT */
3240869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT2:	/* AVN */
3241144b44b1SLen Brown 		return 1;
3242144b44b1SLen Brown 	}
3243144b44b1SLen Brown 	return 0;
3244144b44b1SLen Brown }
3245144b44b1SLen Brown 
3246fb5d4327SDasaratharaman Chandramouli int is_knl(unsigned int family, unsigned int model)
3247fb5d4327SDasaratharaman Chandramouli {
3248fb5d4327SDasaratharaman Chandramouli 	if (!genuine_intel)
3249fb5d4327SDasaratharaman Chandramouli 		return 0;
3250fb5d4327SDasaratharaman Chandramouli 	switch (model) {
3251869ce69eSLen Brown 	case INTEL_FAM6_XEON_PHI_KNL:	/* KNL */
3252005c82d6SLen Brown 	case INTEL_FAM6_XEON_PHI_KNM:
3253fb5d4327SDasaratharaman Chandramouli 		return 1;
3254fb5d4327SDasaratharaman Chandramouli 	}
3255fb5d4327SDasaratharaman Chandramouli 	return 0;
3256fb5d4327SDasaratharaman Chandramouli }
3257fb5d4327SDasaratharaman Chandramouli 
3258b2b34dfeSHubert Chrzaniuk unsigned int get_aperf_mperf_multiplier(unsigned int family, unsigned int model)
3259b2b34dfeSHubert Chrzaniuk {
3260b2b34dfeSHubert Chrzaniuk 	if (is_knl(family, model))
3261b2b34dfeSHubert Chrzaniuk 		return 1024;
3262b2b34dfeSHubert Chrzaniuk 	return 1;
3263b2b34dfeSHubert Chrzaniuk }
3264b2b34dfeSHubert Chrzaniuk 
3265144b44b1SLen Brown #define SLM_BCLK_FREQS 5
3266144b44b1SLen Brown double slm_freq_table[SLM_BCLK_FREQS] = { 83.3, 100.0, 133.3, 116.7, 80.0};
3267144b44b1SLen Brown 
3268144b44b1SLen Brown double slm_bclk(void)
3269144b44b1SLen Brown {
3270144b44b1SLen Brown 	unsigned long long msr = 3;
3271144b44b1SLen Brown 	unsigned int i;
3272144b44b1SLen Brown 	double freq;
3273144b44b1SLen Brown 
32747ce7d5deSPrarit Bhargava 	if (get_msr(base_cpu, MSR_FSB_FREQ, &msr))
3275b7d8c148SLen Brown 		fprintf(outf, "SLM BCLK: unknown\n");
3276144b44b1SLen Brown 
3277144b44b1SLen Brown 	i = msr & 0xf;
3278144b44b1SLen Brown 	if (i >= SLM_BCLK_FREQS) {
3279b7d8c148SLen Brown 		fprintf(outf, "SLM BCLK[%d] invalid\n", i);
32800a91e551SColin Ian King 		i = 3;
3281144b44b1SLen Brown 	}
3282144b44b1SLen Brown 	freq = slm_freq_table[i];
3283144b44b1SLen Brown 
3284b7d8c148SLen Brown 	fprintf(outf, "SLM BCLK: %.1f Mhz\n", freq);
3285144b44b1SLen Brown 
3286144b44b1SLen Brown 	return freq;
3287144b44b1SLen Brown }
3288144b44b1SLen Brown 
3289103a8feaSLen Brown double discover_bclk(unsigned int family, unsigned int model)
3290103a8feaSLen Brown {
3291121b48bbSChrzaniuk, Hubert 	if (has_snb_msrs(family, model) || is_knl(family, model))
3292103a8feaSLen Brown 		return 100.00;
3293144b44b1SLen Brown 	else if (is_slm(family, model))
3294144b44b1SLen Brown 		return slm_bclk();
3295103a8feaSLen Brown 	else
3296103a8feaSLen Brown 		return 133.33;
3297103a8feaSLen Brown }
3298103a8feaSLen Brown 
3299889facbeSLen Brown /*
3300889facbeSLen Brown  * MSR_IA32_TEMPERATURE_TARGET indicates the temperature where
3301889facbeSLen Brown  * the Thermal Control Circuit (TCC) activates.
3302889facbeSLen Brown  * This is usually equal to tjMax.
3303889facbeSLen Brown  *
3304889facbeSLen Brown  * Older processors do not have this MSR, so there we guess,
3305889facbeSLen Brown  * but also allow cmdline over-ride with -T.
3306889facbeSLen Brown  *
3307889facbeSLen Brown  * Several MSR temperature values are in units of degrees-C
3308889facbeSLen Brown  * below this value, including the Digital Thermal Sensor (DTS),
3309889facbeSLen Brown  * Package Thermal Management Sensor (PTM), and thermal event thresholds.
3310889facbeSLen Brown  */
3311889facbeSLen Brown int set_temperature_target(struct thread_data *t, struct core_data *c, struct pkg_data *p)
3312889facbeSLen Brown {
3313889facbeSLen Brown 	unsigned long long msr;
3314889facbeSLen Brown 	unsigned int target_c_local;
3315889facbeSLen Brown 	int cpu;
3316889facbeSLen Brown 
3317889facbeSLen Brown 	/* tcc_activation_temp is used only for dts or ptm */
3318889facbeSLen Brown 	if (!(do_dts || do_ptm))
3319889facbeSLen Brown 		return 0;
3320889facbeSLen Brown 
3321889facbeSLen Brown 	/* this is a per-package concept */
3322889facbeSLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
3323889facbeSLen Brown 		return 0;
3324889facbeSLen Brown 
3325889facbeSLen Brown 	cpu = t->cpu_id;
3326889facbeSLen Brown 	if (cpu_migrate(cpu)) {
3327b7d8c148SLen Brown 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
3328889facbeSLen Brown 		return -1;
3329889facbeSLen Brown 	}
3330889facbeSLen Brown 
3331889facbeSLen Brown 	if (tcc_activation_temp_override != 0) {
3332889facbeSLen Brown 		tcc_activation_temp = tcc_activation_temp_override;
3333b7d8c148SLen Brown 		fprintf(outf, "cpu%d: Using cmdline TCC Target (%d C)\n",
3334889facbeSLen Brown 			cpu, tcc_activation_temp);
3335889facbeSLen Brown 		return 0;
3336889facbeSLen Brown 	}
3337889facbeSLen Brown 
3338889facbeSLen Brown 	/* Temperature Target MSR is Nehalem and newer only */
3339d7899447SLen Brown 	if (!do_nhm_platform_info)
3340889facbeSLen Brown 		goto guess;
3341889facbeSLen Brown 
33427ce7d5deSPrarit Bhargava 	if (get_msr(base_cpu, MSR_IA32_TEMPERATURE_TARGET, &msr))
3343889facbeSLen Brown 		goto guess;
3344889facbeSLen Brown 
33453482124aSJean Delvare 	target_c_local = (msr >> 16) & 0xFF;
3346889facbeSLen Brown 
3347d8af6f5fSLen Brown 	if (debug)
3348b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C)\n",
3349889facbeSLen Brown 			cpu, msr, target_c_local);
3350889facbeSLen Brown 
33513482124aSJean Delvare 	if (!target_c_local)
3352889facbeSLen Brown 		goto guess;
3353889facbeSLen Brown 
3354889facbeSLen Brown 	tcc_activation_temp = target_c_local;
3355889facbeSLen Brown 
3356889facbeSLen Brown 	return 0;
3357889facbeSLen Brown 
3358889facbeSLen Brown guess:
3359889facbeSLen Brown 	tcc_activation_temp = TJMAX_DEFAULT;
3360b7d8c148SLen Brown 	fprintf(outf, "cpu%d: Guessing tjMax %d C, Please use -T to specify\n",
3361889facbeSLen Brown 		cpu, tcc_activation_temp);
3362889facbeSLen Brown 
3363889facbeSLen Brown 	return 0;
3364889facbeSLen Brown }
336569807a63SLen Brown 
3366aa8d8cc7SLen Brown void decode_feature_control_msr(void)
3367aa8d8cc7SLen Brown {
3368aa8d8cc7SLen Brown 	unsigned long long msr;
3369aa8d8cc7SLen Brown 
3370aa8d8cc7SLen Brown 	if (!get_msr(base_cpu, MSR_IA32_FEATURE_CONTROL, &msr))
3371aa8d8cc7SLen Brown 		fprintf(outf, "cpu%d: MSR_IA32_FEATURE_CONTROL: 0x%08llx (%sLocked %s)\n",
3372aa8d8cc7SLen Brown 			base_cpu, msr,
3373aa8d8cc7SLen Brown 			msr & FEATURE_CONTROL_LOCKED ? "" : "UN-",
3374aa8d8cc7SLen Brown 			msr & (1 << 18) ? "SGX" : "");
3375aa8d8cc7SLen Brown }
3376aa8d8cc7SLen Brown 
337769807a63SLen Brown void decode_misc_enable_msr(void)
337869807a63SLen Brown {
337969807a63SLen Brown 	unsigned long long msr;
338069807a63SLen Brown 
338169807a63SLen Brown 	if (!get_msr(base_cpu, MSR_IA32_MISC_ENABLE, &msr))
3382b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_IA32_MISC_ENABLE: 0x%08llx (%s %s %s)\n",
338369807a63SLen Brown 			base_cpu, msr,
338469807a63SLen Brown 			msr & (1 << 3) ? "TCC" : "",
338569807a63SLen Brown 			msr & (1 << 16) ? "EIST" : "",
338669807a63SLen Brown 			msr & (1 << 18) ? "MONITOR" : "");
338769807a63SLen Brown }
338869807a63SLen Brown 
3389f0057310SLen Brown /*
3390f0057310SLen Brown  * Decode MSR_MISC_PWR_MGMT
3391f0057310SLen Brown  *
3392f0057310SLen Brown  * Decode the bits according to the Nehalem documentation
3393f0057310SLen Brown  * bit[0] seems to continue to have same meaning going forward
3394f0057310SLen Brown  * bit[1] less so...
3395f0057310SLen Brown  */
3396f0057310SLen Brown void decode_misc_pwr_mgmt_msr(void)
3397f0057310SLen Brown {
3398f0057310SLen Brown 	unsigned long long msr;
3399f0057310SLen Brown 
3400f0057310SLen Brown 	if (!do_nhm_platform_info)
3401f0057310SLen Brown 		return;
3402f0057310SLen Brown 
3403f0057310SLen Brown 	if (!get_msr(base_cpu, MSR_MISC_PWR_MGMT, &msr))
3404ddadb8adSSrinivas Pandruvada 		fprintf(outf, "cpu%d: MSR_MISC_PWR_MGMT: 0x%08llx (%sable-EIST_Coordination %sable-EPB %sable-OOB)\n",
3405f0057310SLen Brown 			base_cpu, msr,
3406f0057310SLen Brown 			msr & (1 << 0) ? "DIS" : "EN",
3407ddadb8adSSrinivas Pandruvada 			msr & (1 << 1) ? "EN" : "DIS",
3408ddadb8adSSrinivas Pandruvada 			msr & (1 << 8) ? "EN" : "DIS");
3409f0057310SLen Brown }
34107f5c258eSLen Brown 
3411fcd17211SLen Brown void process_cpuid()
3412103a8feaSLen Brown {
341361a87ba7SLen Brown 	unsigned int eax, ebx, ecx, edx, max_level, max_extended_level;
3414103a8feaSLen Brown 	unsigned int fms, family, model, stepping;
3415103a8feaSLen Brown 
3416103a8feaSLen Brown 	eax = ebx = ecx = edx = 0;
3417103a8feaSLen Brown 
34185aea2f7fSLen Brown 	__cpuid(0, max_level, ebx, ecx, edx);
3419103a8feaSLen Brown 
3420103a8feaSLen Brown 	if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)
3421103a8feaSLen Brown 		genuine_intel = 1;
3422103a8feaSLen Brown 
3423d8af6f5fSLen Brown 	if (debug)
3424b7d8c148SLen Brown 		fprintf(outf, "CPUID(0): %.4s%.4s%.4s ",
3425103a8feaSLen Brown 			(char *)&ebx, (char *)&edx, (char *)&ecx);
3426103a8feaSLen Brown 
34275aea2f7fSLen Brown 	__cpuid(1, fms, ebx, ecx, edx);
3428103a8feaSLen Brown 	family = (fms >> 8) & 0xf;
3429103a8feaSLen Brown 	model = (fms >> 4) & 0xf;
3430103a8feaSLen Brown 	stepping = fms & 0xf;
3431103a8feaSLen Brown 	if (family == 6 || family == 0xf)
3432103a8feaSLen Brown 		model += ((fms >> 16) & 0xf) << 4;
3433103a8feaSLen Brown 
343469807a63SLen Brown 	if (debug) {
3435b7d8c148SLen Brown 		fprintf(outf, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n",
3436103a8feaSLen Brown 			max_level, family, model, stepping, family, model, stepping);
3437aa8d8cc7SLen Brown 		fprintf(outf, "CPUID(1): %s %s %s %s %s %s %s %s %s\n",
343869807a63SLen Brown 			ecx & (1 << 0) ? "SSE3" : "-",
343969807a63SLen Brown 			ecx & (1 << 3) ? "MONITOR" : "-",
3440aa8d8cc7SLen Brown 			ecx & (1 << 6) ? "SMX" : "-",
344169807a63SLen Brown 			ecx & (1 << 7) ? "EIST" : "-",
344269807a63SLen Brown 			ecx & (1 << 8) ? "TM2" : "-",
344369807a63SLen Brown 			edx & (1 << 4) ? "TSC" : "-",
344469807a63SLen Brown 			edx & (1 << 5) ? "MSR" : "-",
344569807a63SLen Brown 			edx & (1 << 22) ? "ACPI-TM" : "-",
344669807a63SLen Brown 			edx & (1 << 29) ? "TM" : "-");
344769807a63SLen Brown 	}
3448103a8feaSLen Brown 
3449b2c95d90SJosh Triplett 	if (!(edx & (1 << 5)))
3450b2c95d90SJosh Triplett 		errx(1, "CPUID: no MSR");
3451103a8feaSLen Brown 
3452103a8feaSLen Brown 	/*
3453103a8feaSLen Brown 	 * check max extended function levels of CPUID.
3454103a8feaSLen Brown 	 * This is needed to check for invariant TSC.
3455103a8feaSLen Brown 	 * This check is valid for both Intel and AMD.
3456103a8feaSLen Brown 	 */
3457103a8feaSLen Brown 	ebx = ecx = edx = 0;
34585aea2f7fSLen Brown 	__cpuid(0x80000000, max_extended_level, ebx, ecx, edx);
3459103a8feaSLen Brown 
346061a87ba7SLen Brown 	if (max_extended_level >= 0x80000007) {
3461103a8feaSLen Brown 
3462103a8feaSLen Brown 		/*
3463103a8feaSLen Brown 		 * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8
3464103a8feaSLen Brown 		 * this check is valid for both Intel and AMD
3465103a8feaSLen Brown 		 */
34665aea2f7fSLen Brown 		__cpuid(0x80000007, eax, ebx, ecx, edx);
34678209e054SThomas Renninger 		has_invariant_tsc = edx & (1 << 8);
3468d7899447SLen Brown 	}
3469103a8feaSLen Brown 
3470103a8feaSLen Brown 	/*
3471103a8feaSLen Brown 	 * APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0
3472103a8feaSLen Brown 	 * this check is valid for both Intel and AMD
3473103a8feaSLen Brown 	 */
3474103a8feaSLen Brown 
34755aea2f7fSLen Brown 	__cpuid(0x6, eax, ebx, ecx, edx);
34768209e054SThomas Renninger 	has_aperf = ecx & (1 << 0);
3477889facbeSLen Brown 	do_dts = eax & (1 << 0);
3478889facbeSLen Brown 	do_ptm = eax & (1 << 6);
34797f5c258eSLen Brown 	has_hwp = eax & (1 << 7);
34807f5c258eSLen Brown 	has_hwp_notify = eax & (1 << 8);
34817f5c258eSLen Brown 	has_hwp_activity_window = eax & (1 << 9);
34827f5c258eSLen Brown 	has_hwp_epp = eax & (1 << 10);
34837f5c258eSLen Brown 	has_hwp_pkg = eax & (1 << 11);
3484889facbeSLen Brown 	has_epb = ecx & (1 << 3);
3485889facbeSLen Brown 
3486d8af6f5fSLen Brown 	if (debug)
3487b7d8c148SLen Brown 		fprintf(outf, "CPUID(6): %sAPERF, %sDTS, %sPTM, %sHWP, "
34887f5c258eSLen Brown 			"%sHWPnotify, %sHWPwindow, %sHWPepp, %sHWPpkg, %sEPB\n",
34897f5c258eSLen Brown 			has_aperf ? "" : "No-",
34907f5c258eSLen Brown 			do_dts ? "" : "No-",
34917f5c258eSLen Brown 			do_ptm ? "" : "No-",
34927f5c258eSLen Brown 			has_hwp ? "" : "No-",
34937f5c258eSLen Brown 			has_hwp_notify ? "" : "No-",
34947f5c258eSLen Brown 			has_hwp_activity_window ? "" : "No-",
34957f5c258eSLen Brown 			has_hwp_epp ? "" : "No-",
34967f5c258eSLen Brown 			has_hwp_pkg ? "" : "No-",
34977f5c258eSLen Brown 			has_epb ? "" : "No-");
3498103a8feaSLen Brown 
349969807a63SLen Brown 	if (debug)
350069807a63SLen Brown 		decode_misc_enable_msr();
350169807a63SLen Brown 
35028ae72255SLen Brown 	if (max_level >= 0x7 && debug) {
3503aa8d8cc7SLen Brown 		int has_sgx;
3504aa8d8cc7SLen Brown 
3505aa8d8cc7SLen Brown 		ecx = 0;
3506aa8d8cc7SLen Brown 
3507aa8d8cc7SLen Brown 		__cpuid_count(0x7, 0, eax, ebx, ecx, edx);
3508aa8d8cc7SLen Brown 
3509aa8d8cc7SLen Brown 		has_sgx = ebx & (1 << 2);
3510aa8d8cc7SLen Brown 		fprintf(outf, "CPUID(7): %sSGX\n", has_sgx ? "" : "No-");
3511aa8d8cc7SLen Brown 
3512aa8d8cc7SLen Brown 		if (has_sgx)
3513aa8d8cc7SLen Brown 			decode_feature_control_msr();
3514aa8d8cc7SLen Brown 	}
3515aa8d8cc7SLen Brown 
351661a87ba7SLen Brown 	if (max_level >= 0x15) {
35178a5bdf41SLen Brown 		unsigned int eax_crystal;
35188a5bdf41SLen Brown 		unsigned int ebx_tsc;
35198a5bdf41SLen Brown 
35208a5bdf41SLen Brown 		/*
35218a5bdf41SLen Brown 		 * CPUID 15H TSC/Crystal ratio, possibly Crystal Hz
35228a5bdf41SLen Brown 		 */
35238a5bdf41SLen Brown 		eax_crystal = ebx_tsc = crystal_hz = edx = 0;
35245aea2f7fSLen Brown 		__cpuid(0x15, eax_crystal, ebx_tsc, crystal_hz, edx);
35258a5bdf41SLen Brown 
35268a5bdf41SLen Brown 		if (ebx_tsc != 0) {
35278a5bdf41SLen Brown 
35288a5bdf41SLen Brown 			if (debug && (ebx != 0))
3529b7d8c148SLen Brown 				fprintf(outf, "CPUID(0x15): eax_crystal: %d ebx_tsc: %d ecx_crystal_hz: %d\n",
35308a5bdf41SLen Brown 					eax_crystal, ebx_tsc, crystal_hz);
35318a5bdf41SLen Brown 
35328a5bdf41SLen Brown 			if (crystal_hz == 0)
35338a5bdf41SLen Brown 				switch(model) {
3534869ce69eSLen Brown 				case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
3535869ce69eSLen Brown 				case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
3536869ce69eSLen Brown 				case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
3537869ce69eSLen Brown 				case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
3538e8efbc80SLen Brown 					crystal_hz = 24000000;	/* 24.0 MHz */
3539e8efbc80SLen Brown 					break;
3540869ce69eSLen Brown 				case INTEL_FAM6_SKYLAKE_X:	/* SKX */
35417268d407SLen Brown 				case INTEL_FAM6_ATOM_DENVERTON:	/* DNV */
3542ec53e594SLen Brown 					crystal_hz = 25000000;	/* 25.0 MHz */
3543ec53e594SLen Brown 					break;
3544869ce69eSLen Brown 				case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
3545e8efbc80SLen Brown 					crystal_hz = 19200000;	/* 19.2 MHz */
35468a5bdf41SLen Brown 					break;
35478a5bdf41SLen Brown 				default:
35488a5bdf41SLen Brown 					crystal_hz = 0;
35498a5bdf41SLen Brown 			}
35508a5bdf41SLen Brown 
35518a5bdf41SLen Brown 			if (crystal_hz) {
35528a5bdf41SLen Brown 				tsc_hz =  (unsigned long long) crystal_hz * ebx_tsc / eax_crystal;
35538a5bdf41SLen Brown 				if (debug)
3554b7d8c148SLen Brown 					fprintf(outf, "TSC: %lld MHz (%d Hz * %d / %d / 1000000)\n",
35558a5bdf41SLen Brown 						tsc_hz / 1000000, crystal_hz, ebx_tsc,  eax_crystal);
35568a5bdf41SLen Brown 			}
35578a5bdf41SLen Brown 		}
35588a5bdf41SLen Brown 	}
355961a87ba7SLen Brown 	if (max_level >= 0x16) {
356061a87ba7SLen Brown 		unsigned int base_mhz, max_mhz, bus_mhz, edx;
356161a87ba7SLen Brown 
356261a87ba7SLen Brown 		/*
356361a87ba7SLen Brown 		 * CPUID 16H Base MHz, Max MHz, Bus MHz
356461a87ba7SLen Brown 		 */
356561a87ba7SLen Brown 		base_mhz = max_mhz = bus_mhz = edx = 0;
356661a87ba7SLen Brown 
35675aea2f7fSLen Brown 		__cpuid(0x16, base_mhz, max_mhz, bus_mhz, edx);
356861a87ba7SLen Brown 		if (debug)
3569b7d8c148SLen Brown 			fprintf(outf, "CPUID(0x16): base_mhz: %d max_mhz: %d bus_mhz: %d\n",
357061a87ba7SLen Brown 				base_mhz, max_mhz, bus_mhz);
357161a87ba7SLen Brown 	}
35728a5bdf41SLen Brown 
3573b2b34dfeSHubert Chrzaniuk 	if (has_aperf)
3574b2b34dfeSHubert Chrzaniuk 		aperf_mperf_multiplier = get_aperf_mperf_multiplier(family, model);
3575b2b34dfeSHubert Chrzaniuk 
3576ee7e38e3SLen Brown 	do_nhm_platform_info = do_nhm_cstates = do_smi = probe_nhm_msrs(family, model);
3577d7899447SLen Brown 	do_snb_cstates = has_snb_msrs(family, model);
35785a63426eSLen Brown 	do_irtl_snb = has_snb_msrs(family, model);
3579ee7e38e3SLen Brown 	do_pc2 = do_snb_cstates && (pkg_cstate_limit >= PCL__2);
3580ee7e38e3SLen Brown 	do_pc3 = (pkg_cstate_limit >= PCL__3);
3581ee7e38e3SLen Brown 	do_pc6 = (pkg_cstate_limit >= PCL__6);
3582ee7e38e3SLen Brown 	do_pc7 = do_snb_cstates && (pkg_cstate_limit >= PCL__7);
3583d7899447SLen Brown 	do_c8_c9_c10 = has_hsw_msrs(family, model);
35845a63426eSLen Brown 	do_irtl_hsw = has_hsw_msrs(family, model);
35850b2bb692SLen Brown 	do_skl_residency = has_skl_msrs(family, model);
3586144b44b1SLen Brown 	do_slm_cstates = is_slm(family, model);
3587fb5d4327SDasaratharaman Chandramouli 	do_knl_cstates  = is_knl(family, model);
3588103a8feaSLen Brown 
3589f0057310SLen Brown 	if (debug)
3590f0057310SLen Brown 		decode_misc_pwr_mgmt_msr();
3591f0057310SLen Brown 
3592889facbeSLen Brown 	rapl_probe(family, model);
35933a9a941dSLen Brown 	perf_limit_reasons_probe(family, model);
3594889facbeSLen Brown 
3595fcd17211SLen Brown 	if (debug)
35961b69317dSColin Ian King 		dump_cstate_pstate_config_info(family, model);
3597fcd17211SLen Brown 
3598a2b7b749SLen Brown 	if (has_skl_msrs(family, model))
3599a2b7b749SLen Brown 		calculate_tsc_tweak();
3600a2b7b749SLen Brown 
3601fdf676e5SLen Brown 	do_gfx_rc6_ms = !access("/sys/class/drm/card0/power/rc6_residency_ms", R_OK);
3602fdf676e5SLen Brown 
360327d47356SLen Brown 	do_gfx_mhz = !access("/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz", R_OK);
360427d47356SLen Brown 
3605889facbeSLen Brown 	return;
3606103a8feaSLen Brown }
3607103a8feaSLen Brown 
3608d8af6f5fSLen Brown void help()
3609103a8feaSLen Brown {
3610b7d8c148SLen Brown 	fprintf(outf,
3611d8af6f5fSLen Brown 	"Usage: turbostat [OPTIONS][(--interval seconds) | COMMAND ...]\n"
3612d8af6f5fSLen Brown 	"\n"
3613d8af6f5fSLen Brown 	"Turbostat forks the specified COMMAND and prints statistics\n"
3614d8af6f5fSLen Brown 	"when COMMAND completes.\n"
3615d8af6f5fSLen Brown 	"If no COMMAND is specified, turbostat wakes every 5-seconds\n"
3616d8af6f5fSLen Brown 	"to print statistics, until interrupted.\n"
3617*388e9c81SLen Brown 	"--add		add a counter\n"
3618*388e9c81SLen Brown 	"		eg. --add msr0x10,u64,cpu,delta,MY_TSC\n"
3619d8af6f5fSLen Brown 	"--debug	run in \"debug\" mode\n"
3620d8af6f5fSLen Brown 	"--interval sec	Override default 5-second measurement interval\n"
3621d8af6f5fSLen Brown 	"--help		print this help message\n"
3622d8af6f5fSLen Brown 	"--counter msr	print 32-bit counter at address \"msr\"\n"
3623d8af6f5fSLen Brown 	"--Counter msr	print 64-bit Counter at address \"msr\"\n"
3624b7d8c148SLen Brown 	"--out file	create or truncate \"file\" for all output\n"
3625d8af6f5fSLen Brown 	"--msr msr	print 32-bit value at address \"msr\"\n"
3626d8af6f5fSLen Brown 	"--MSR msr	print 64-bit Value at address \"msr\"\n"
3627d8af6f5fSLen Brown 	"--version	print version information\n"
3628d8af6f5fSLen Brown 	"\n"
3629d8af6f5fSLen Brown 	"For more help, run \"man turbostat\"\n");
3630103a8feaSLen Brown }
3631103a8feaSLen Brown 
3632103a8feaSLen Brown 
3633103a8feaSLen Brown /*
3634103a8feaSLen Brown  * in /dev/cpu/ return success for names that are numbers
3635103a8feaSLen Brown  * ie. filter out ".", "..", "microcode".
3636103a8feaSLen Brown  */
3637103a8feaSLen Brown int dir_filter(const struct dirent *dirp)
3638103a8feaSLen Brown {
3639103a8feaSLen Brown 	if (isdigit(dirp->d_name[0]))
3640103a8feaSLen Brown 		return 1;
3641103a8feaSLen Brown 	else
3642103a8feaSLen Brown 		return 0;
3643103a8feaSLen Brown }
3644103a8feaSLen Brown 
3645103a8feaSLen Brown int open_dev_cpu_msr(int dummy1)
3646103a8feaSLen Brown {
3647103a8feaSLen Brown 	return 0;
3648103a8feaSLen Brown }
3649103a8feaSLen Brown 
3650c98d5d94SLen Brown void topology_probe()
3651c98d5d94SLen Brown {
3652c98d5d94SLen Brown 	int i;
3653c98d5d94SLen Brown 	int max_core_id = 0;
3654c98d5d94SLen Brown 	int max_package_id = 0;
3655c98d5d94SLen Brown 	int max_siblings = 0;
3656c98d5d94SLen Brown 	struct cpu_topology {
3657c98d5d94SLen Brown 		int core_id;
3658c98d5d94SLen Brown 		int physical_package_id;
3659c98d5d94SLen Brown 	} *cpus;
3660c98d5d94SLen Brown 
3661c98d5d94SLen Brown 	/* Initialize num_cpus, max_cpu_num */
3662c98d5d94SLen Brown 	topo.num_cpus = 0;
3663c98d5d94SLen Brown 	topo.max_cpu_num = 0;
3664c98d5d94SLen Brown 	for_all_proc_cpus(count_cpus);
3665c98d5d94SLen Brown 	if (!summary_only && topo.num_cpus > 1)
3666c98d5d94SLen Brown 		show_cpu = 1;
3667c98d5d94SLen Brown 
3668d8af6f5fSLen Brown 	if (debug > 1)
3669b7d8c148SLen Brown 		fprintf(outf, "num_cpus %d max_cpu_num %d\n", topo.num_cpus, topo.max_cpu_num);
3670c98d5d94SLen Brown 
3671c98d5d94SLen Brown 	cpus = calloc(1, (topo.max_cpu_num  + 1) * sizeof(struct cpu_topology));
3672b2c95d90SJosh Triplett 	if (cpus == NULL)
3673b2c95d90SJosh Triplett 		err(1, "calloc cpus");
3674c98d5d94SLen Brown 
3675c98d5d94SLen Brown 	/*
3676c98d5d94SLen Brown 	 * Allocate and initialize cpu_present_set
3677c98d5d94SLen Brown 	 */
3678c98d5d94SLen Brown 	cpu_present_set = CPU_ALLOC((topo.max_cpu_num + 1));
3679b2c95d90SJosh Triplett 	if (cpu_present_set == NULL)
3680b2c95d90SJosh Triplett 		err(3, "CPU_ALLOC");
3681c98d5d94SLen Brown 	cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
3682c98d5d94SLen Brown 	CPU_ZERO_S(cpu_present_setsize, cpu_present_set);
3683c98d5d94SLen Brown 	for_all_proc_cpus(mark_cpu_present);
3684c98d5d94SLen Brown 
3685c98d5d94SLen Brown 	/*
3686c98d5d94SLen Brown 	 * Allocate and initialize cpu_affinity_set
3687c98d5d94SLen Brown 	 */
3688c98d5d94SLen Brown 	cpu_affinity_set = CPU_ALLOC((topo.max_cpu_num + 1));
3689b2c95d90SJosh Triplett 	if (cpu_affinity_set == NULL)
3690b2c95d90SJosh Triplett 		err(3, "CPU_ALLOC");
3691c98d5d94SLen Brown 	cpu_affinity_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
3692c98d5d94SLen Brown 	CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set);
3693c98d5d94SLen Brown 
3694c98d5d94SLen Brown 
3695c98d5d94SLen Brown 	/*
3696c98d5d94SLen Brown 	 * For online cpus
3697c98d5d94SLen Brown 	 * find max_core_id, max_package_id
3698c98d5d94SLen Brown 	 */
3699c98d5d94SLen Brown 	for (i = 0; i <= topo.max_cpu_num; ++i) {
3700c98d5d94SLen Brown 		int siblings;
3701c98d5d94SLen Brown 
3702c98d5d94SLen Brown 		if (cpu_is_not_present(i)) {
3703d8af6f5fSLen Brown 			if (debug > 1)
3704b7d8c148SLen Brown 				fprintf(outf, "cpu%d NOT PRESENT\n", i);
3705c98d5d94SLen Brown 			continue;
3706c98d5d94SLen Brown 		}
3707c98d5d94SLen Brown 		cpus[i].core_id = get_core_id(i);
3708c98d5d94SLen Brown 		if (cpus[i].core_id > max_core_id)
3709c98d5d94SLen Brown 			max_core_id = cpus[i].core_id;
3710c98d5d94SLen Brown 
3711c98d5d94SLen Brown 		cpus[i].physical_package_id = get_physical_package_id(i);
3712c98d5d94SLen Brown 		if (cpus[i].physical_package_id > max_package_id)
3713c98d5d94SLen Brown 			max_package_id = cpus[i].physical_package_id;
3714c98d5d94SLen Brown 
3715c98d5d94SLen Brown 		siblings = get_num_ht_siblings(i);
3716c98d5d94SLen Brown 		if (siblings > max_siblings)
3717c98d5d94SLen Brown 			max_siblings = siblings;
3718d8af6f5fSLen Brown 		if (debug > 1)
3719b7d8c148SLen Brown 			fprintf(outf, "cpu %d pkg %d core %d\n",
3720c98d5d94SLen Brown 				i, cpus[i].physical_package_id, cpus[i].core_id);
3721c98d5d94SLen Brown 	}
3722c98d5d94SLen Brown 	topo.num_cores_per_pkg = max_core_id + 1;
3723d8af6f5fSLen Brown 	if (debug > 1)
3724b7d8c148SLen Brown 		fprintf(outf, "max_core_id %d, sizing for %d cores per package\n",
3725c98d5d94SLen Brown 			max_core_id, topo.num_cores_per_pkg);
37261cc21f7bSLen Brown 	if (debug && !summary_only && topo.num_cores_per_pkg > 1)
3727c98d5d94SLen Brown 		show_core = 1;
3728c98d5d94SLen Brown 
3729c98d5d94SLen Brown 	topo.num_packages = max_package_id + 1;
3730d8af6f5fSLen Brown 	if (debug > 1)
3731b7d8c148SLen Brown 		fprintf(outf, "max_package_id %d, sizing for %d packages\n",
3732c98d5d94SLen Brown 			max_package_id, topo.num_packages);
37331cc21f7bSLen Brown 	if (debug && !summary_only && topo.num_packages > 1)
3734c98d5d94SLen Brown 		show_pkg = 1;
3735c98d5d94SLen Brown 
3736c98d5d94SLen Brown 	topo.num_threads_per_core = max_siblings;
3737d8af6f5fSLen Brown 	if (debug > 1)
3738b7d8c148SLen Brown 		fprintf(outf, "max_siblings %d\n", max_siblings);
3739c98d5d94SLen Brown 
3740c98d5d94SLen Brown 	free(cpus);
3741c98d5d94SLen Brown }
3742c98d5d94SLen Brown 
3743c98d5d94SLen Brown void
3744c98d5d94SLen Brown allocate_counters(struct thread_data **t, struct core_data **c, struct pkg_data **p)
3745c98d5d94SLen Brown {
3746c98d5d94SLen Brown 	int i;
3747c98d5d94SLen Brown 
3748c98d5d94SLen Brown 	*t = calloc(topo.num_threads_per_core * topo.num_cores_per_pkg *
3749*388e9c81SLen Brown 		topo.num_packages, sizeof(struct thread_data) + sys.thread_counter_bytes);
3750c98d5d94SLen Brown 	if (*t == NULL)
3751c98d5d94SLen Brown 		goto error;
3752c98d5d94SLen Brown 
3753c98d5d94SLen Brown 	for (i = 0; i < topo.num_threads_per_core *
3754c98d5d94SLen Brown 		topo.num_cores_per_pkg * topo.num_packages; i++)
3755c98d5d94SLen Brown 		(*t)[i].cpu_id = -1;
3756c98d5d94SLen Brown 
3757c98d5d94SLen Brown 	*c = calloc(topo.num_cores_per_pkg * topo.num_packages,
3758*388e9c81SLen Brown 		sizeof(struct core_data) + sys.core_counter_bytes);
3759c98d5d94SLen Brown 	if (*c == NULL)
3760c98d5d94SLen Brown 		goto error;
3761c98d5d94SLen Brown 
3762c98d5d94SLen Brown 	for (i = 0; i < topo.num_cores_per_pkg * topo.num_packages; i++)
3763c98d5d94SLen Brown 		(*c)[i].core_id = -1;
3764c98d5d94SLen Brown 
3765*388e9c81SLen Brown 	*p = calloc(topo.num_packages, sizeof(struct pkg_data) + sys.package_counter_bytes);
3766c98d5d94SLen Brown 	if (*p == NULL)
3767c98d5d94SLen Brown 		goto error;
3768c98d5d94SLen Brown 
3769c98d5d94SLen Brown 	for (i = 0; i < topo.num_packages; i++)
3770c98d5d94SLen Brown 		(*p)[i].package_id = i;
3771c98d5d94SLen Brown 
3772c98d5d94SLen Brown 	return;
3773c98d5d94SLen Brown error:
3774b2c95d90SJosh Triplett 	err(1, "calloc counters");
3775c98d5d94SLen Brown }
3776c98d5d94SLen Brown /*
3777c98d5d94SLen Brown  * init_counter()
3778c98d5d94SLen Brown  *
3779c98d5d94SLen Brown  * set cpu_id, core_num, pkg_num
3780c98d5d94SLen Brown  * set FIRST_THREAD_IN_CORE and FIRST_CORE_IN_PACKAGE
3781c98d5d94SLen Brown  *
3782c98d5d94SLen Brown  * increment topo.num_cores when 1st core in pkg seen
3783c98d5d94SLen Brown  */
3784c98d5d94SLen Brown void init_counter(struct thread_data *thread_base, struct core_data *core_base,
3785c98d5d94SLen Brown 	struct pkg_data *pkg_base, int thread_num, int core_num,
3786c98d5d94SLen Brown 	int pkg_num, int cpu_id)
3787c98d5d94SLen Brown {
3788c98d5d94SLen Brown 	struct thread_data *t;
3789c98d5d94SLen Brown 	struct core_data *c;
3790c98d5d94SLen Brown 	struct pkg_data *p;
3791c98d5d94SLen Brown 
3792c98d5d94SLen Brown 	t = GET_THREAD(thread_base, thread_num, core_num, pkg_num);
3793c98d5d94SLen Brown 	c = GET_CORE(core_base, core_num, pkg_num);
3794c98d5d94SLen Brown 	p = GET_PKG(pkg_base, pkg_num);
3795c98d5d94SLen Brown 
3796c98d5d94SLen Brown 	t->cpu_id = cpu_id;
3797c98d5d94SLen Brown 	if (thread_num == 0) {
3798c98d5d94SLen Brown 		t->flags |= CPU_IS_FIRST_THREAD_IN_CORE;
3799c98d5d94SLen Brown 		if (cpu_is_first_core_in_package(cpu_id))
3800c98d5d94SLen Brown 			t->flags |= CPU_IS_FIRST_CORE_IN_PACKAGE;
3801c98d5d94SLen Brown 	}
3802c98d5d94SLen Brown 
3803c98d5d94SLen Brown 	c->core_id = core_num;
3804c98d5d94SLen Brown 	p->package_id = pkg_num;
3805c98d5d94SLen Brown }
3806c98d5d94SLen Brown 
3807c98d5d94SLen Brown 
3808c98d5d94SLen Brown int initialize_counters(int cpu_id)
3809c98d5d94SLen Brown {
3810c98d5d94SLen Brown 	int my_thread_id, my_core_id, my_package_id;
3811c98d5d94SLen Brown 
3812c98d5d94SLen Brown 	my_package_id = get_physical_package_id(cpu_id);
3813c98d5d94SLen Brown 	my_core_id = get_core_id(cpu_id);
3814e275b388SDasaratharaman Chandramouli 	my_thread_id = get_cpu_position_in_core(cpu_id);
3815e275b388SDasaratharaman Chandramouli 	if (!my_thread_id)
3816c98d5d94SLen Brown 		topo.num_cores++;
3817c98d5d94SLen Brown 
3818c98d5d94SLen Brown 	init_counter(EVEN_COUNTERS, my_thread_id, my_core_id, my_package_id, cpu_id);
3819c98d5d94SLen Brown 	init_counter(ODD_COUNTERS, my_thread_id, my_core_id, my_package_id, cpu_id);
3820c98d5d94SLen Brown 	return 0;
3821c98d5d94SLen Brown }
3822c98d5d94SLen Brown 
3823c98d5d94SLen Brown void allocate_output_buffer()
3824c98d5d94SLen Brown {
38253b4d5c7fSAndy Shevchenko 	output_buffer = calloc(1, (1 + topo.num_cpus) * 1024);
3826c98d5d94SLen Brown 	outp = output_buffer;
3827b2c95d90SJosh Triplett 	if (outp == NULL)
3828b2c95d90SJosh Triplett 		err(-1, "calloc output buffer");
3829c98d5d94SLen Brown }
383036229897SLen Brown void allocate_fd_percpu(void)
383136229897SLen Brown {
383201a67adfSMika Westerberg 	fd_percpu = calloc(topo.max_cpu_num + 1, sizeof(int));
383336229897SLen Brown 	if (fd_percpu == NULL)
383436229897SLen Brown 		err(-1, "calloc fd_percpu");
383536229897SLen Brown }
3836562a2d37SLen Brown void allocate_irq_buffers(void)
3837562a2d37SLen Brown {
3838562a2d37SLen Brown 	irq_column_2_cpu = calloc(topo.num_cpus, sizeof(int));
3839562a2d37SLen Brown 	if (irq_column_2_cpu == NULL)
3840562a2d37SLen Brown 		err(-1, "calloc %d", topo.num_cpus);
3841c98d5d94SLen Brown 
384201a67adfSMika Westerberg 	irqs_per_cpu = calloc(topo.max_cpu_num + 1, sizeof(int));
3843562a2d37SLen Brown 	if (irqs_per_cpu == NULL)
384401a67adfSMika Westerberg 		err(-1, "calloc %d", topo.max_cpu_num + 1);
3845562a2d37SLen Brown }
3846c98d5d94SLen Brown void setup_all_buffers(void)
3847c98d5d94SLen Brown {
3848c98d5d94SLen Brown 	topology_probe();
3849562a2d37SLen Brown 	allocate_irq_buffers();
385036229897SLen Brown 	allocate_fd_percpu();
3851c98d5d94SLen Brown 	allocate_counters(&thread_even, &core_even, &package_even);
3852c98d5d94SLen Brown 	allocate_counters(&thread_odd, &core_odd, &package_odd);
3853c98d5d94SLen Brown 	allocate_output_buffer();
3854c98d5d94SLen Brown 	for_all_proc_cpus(initialize_counters);
3855c98d5d94SLen Brown }
38563b4d5c7fSAndy Shevchenko 
38577ce7d5deSPrarit Bhargava void set_base_cpu(void)
38587ce7d5deSPrarit Bhargava {
38597ce7d5deSPrarit Bhargava 	base_cpu = sched_getcpu();
38607ce7d5deSPrarit Bhargava 	if (base_cpu < 0)
38617ce7d5deSPrarit Bhargava 		err(-ENODEV, "No valid cpus found");
38627ce7d5deSPrarit Bhargava 
38637ce7d5deSPrarit Bhargava 	if (debug > 1)
3864b7d8c148SLen Brown 		fprintf(outf, "base_cpu = %d\n", base_cpu);
38657ce7d5deSPrarit Bhargava }
38667ce7d5deSPrarit Bhargava 
3867103a8feaSLen Brown void turbostat_init()
3868103a8feaSLen Brown {
38697ce7d5deSPrarit Bhargava 	setup_all_buffers();
38707ce7d5deSPrarit Bhargava 	set_base_cpu();
3871103a8feaSLen Brown 	check_dev_msr();
387298481e79SLen Brown 	check_permissions();
3873fcd17211SLen Brown 	process_cpuid();
3874103a8feaSLen Brown 
3875103a8feaSLen Brown 
3876d8af6f5fSLen Brown 	if (debug)
38777f5c258eSLen Brown 		for_all_cpus(print_hwp, ODD_COUNTERS);
38787f5c258eSLen Brown 
38797f5c258eSLen Brown 	if (debug)
3880889facbeSLen Brown 		for_all_cpus(print_epb, ODD_COUNTERS);
3881889facbeSLen Brown 
3882d8af6f5fSLen Brown 	if (debug)
38833a9a941dSLen Brown 		for_all_cpus(print_perf_limit, ODD_COUNTERS);
38843a9a941dSLen Brown 
3885d8af6f5fSLen Brown 	if (debug)
3886889facbeSLen Brown 		for_all_cpus(print_rapl, ODD_COUNTERS);
3887889facbeSLen Brown 
3888889facbeSLen Brown 	for_all_cpus(set_temperature_target, ODD_COUNTERS);
3889889facbeSLen Brown 
3890d8af6f5fSLen Brown 	if (debug)
3891889facbeSLen Brown 		for_all_cpus(print_thermal, ODD_COUNTERS);
38925a63426eSLen Brown 
38935a63426eSLen Brown 	if (debug && do_irtl_snb)
38945a63426eSLen Brown 		print_irtl();
3895103a8feaSLen Brown }
3896103a8feaSLen Brown 
3897103a8feaSLen Brown int fork_it(char **argv)
3898103a8feaSLen Brown {
3899103a8feaSLen Brown 	pid_t child_pid;
3900d91bb17cSLen Brown 	int status;
3901d15cf7c1SLen Brown 
3902d91bb17cSLen Brown 	status = for_all_cpus(get_counters, EVEN_COUNTERS);
3903d91bb17cSLen Brown 	if (status)
3904d91bb17cSLen Brown 		exit(status);
3905d15cf7c1SLen Brown 	/* clear affinity side-effect of get_counters() */
3906d15cf7c1SLen Brown 	sched_setaffinity(0, cpu_present_setsize, cpu_present_set);
3907103a8feaSLen Brown 	gettimeofday(&tv_even, (struct timezone *)NULL);
3908103a8feaSLen Brown 
3909103a8feaSLen Brown 	child_pid = fork();
3910103a8feaSLen Brown 	if (!child_pid) {
3911103a8feaSLen Brown 		/* child */
3912103a8feaSLen Brown 		execvp(argv[0], argv);
3913103a8feaSLen Brown 	} else {
3914103a8feaSLen Brown 
3915103a8feaSLen Brown 		/* parent */
3916b2c95d90SJosh Triplett 		if (child_pid == -1)
3917b2c95d90SJosh Triplett 			err(1, "fork");
3918103a8feaSLen Brown 
3919103a8feaSLen Brown 		signal(SIGINT, SIG_IGN);
3920103a8feaSLen Brown 		signal(SIGQUIT, SIG_IGN);
3921b2c95d90SJosh Triplett 		if (waitpid(child_pid, &status, 0) == -1)
3922b2c95d90SJosh Triplett 			err(status, "waitpid");
3923103a8feaSLen Brown 	}
3924c98d5d94SLen Brown 	/*
3925c98d5d94SLen Brown 	 * n.b. fork_it() does not check for errors from for_all_cpus()
3926c98d5d94SLen Brown 	 * because re-starting is problematic when forking
3927c98d5d94SLen Brown 	 */
3928c98d5d94SLen Brown 	for_all_cpus(get_counters, ODD_COUNTERS);
3929103a8feaSLen Brown 	gettimeofday(&tv_odd, (struct timezone *)NULL);
3930103a8feaSLen Brown 	timersub(&tv_odd, &tv_even, &tv_delta);
3931ba3dec99SLen Brown 	if (for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS))
3932ba3dec99SLen Brown 		fprintf(outf, "%s: Counter reset detected\n", progname);
3933ba3dec99SLen Brown 	else {
3934c98d5d94SLen Brown 		compute_average(EVEN_COUNTERS);
3935c98d5d94SLen Brown 		format_all_counters(EVEN_COUNTERS);
3936ba3dec99SLen Brown 	}
3937103a8feaSLen Brown 
3938b7d8c148SLen Brown 	fprintf(outf, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);
3939b7d8c148SLen Brown 
3940b7d8c148SLen Brown 	flush_output_stderr();
3941103a8feaSLen Brown 
3942d91bb17cSLen Brown 	return status;
3943103a8feaSLen Brown }
3944103a8feaSLen Brown 
39453b4d5c7fSAndy Shevchenko int get_and_dump_counters(void)
39463b4d5c7fSAndy Shevchenko {
39473b4d5c7fSAndy Shevchenko 	int status;
39483b4d5c7fSAndy Shevchenko 
39493b4d5c7fSAndy Shevchenko 	status = for_all_cpus(get_counters, ODD_COUNTERS);
39503b4d5c7fSAndy Shevchenko 	if (status)
39513b4d5c7fSAndy Shevchenko 		return status;
39523b4d5c7fSAndy Shevchenko 
39533b4d5c7fSAndy Shevchenko 	status = for_all_cpus(dump_counters, ODD_COUNTERS);
39543b4d5c7fSAndy Shevchenko 	if (status)
39553b4d5c7fSAndy Shevchenko 		return status;
39563b4d5c7fSAndy Shevchenko 
3957b7d8c148SLen Brown 	flush_output_stdout();
39583b4d5c7fSAndy Shevchenko 
39593b4d5c7fSAndy Shevchenko 	return status;
39603b4d5c7fSAndy Shevchenko }
39613b4d5c7fSAndy Shevchenko 
3962d8af6f5fSLen Brown void print_version() {
3963*388e9c81SLen Brown 	fprintf(outf, "turbostat version 4.15 21 Dec 2016"
3964d8af6f5fSLen Brown 		" - Len Brown <lenb@kernel.org>\n");
3965d8af6f5fSLen Brown }
3966d8af6f5fSLen Brown 
3967*388e9c81SLen Brown int add_counter(unsigned int msr_num, char *name, unsigned int width,
3968*388e9c81SLen Brown 	enum counter_scope scope, enum counter_type type,
3969*388e9c81SLen Brown 	enum counter_format format)
3970*388e9c81SLen Brown {
3971*388e9c81SLen Brown 	struct msr_counter *msrp;
3972*388e9c81SLen Brown 
3973*388e9c81SLen Brown 	msrp = calloc(1, sizeof(struct msr_counter));
3974*388e9c81SLen Brown 	if (msrp == NULL) {
3975*388e9c81SLen Brown 		perror("calloc");
3976*388e9c81SLen Brown 		exit(1);
3977*388e9c81SLen Brown 	}
3978*388e9c81SLen Brown 
3979*388e9c81SLen Brown 	msrp->msr_num = msr_num;
3980*388e9c81SLen Brown 	strncpy(msrp->name, name, NAME_BYTES);
3981*388e9c81SLen Brown 	msrp->width = width;
3982*388e9c81SLen Brown 	msrp->type = type;
3983*388e9c81SLen Brown 	msrp->format = format;
3984*388e9c81SLen Brown 
3985*388e9c81SLen Brown 	switch (scope) {
3986*388e9c81SLen Brown 
3987*388e9c81SLen Brown 	case SCOPE_CPU:
3988*388e9c81SLen Brown 		sys.thread_counter_bytes += 64;
3989*388e9c81SLen Brown 		msrp->next = sys.tp;
3990*388e9c81SLen Brown 		sys.tp = msrp;
3991*388e9c81SLen Brown 		sys.thread_counter_bytes += sizeof(unsigned long long);
3992*388e9c81SLen Brown 		break;
3993*388e9c81SLen Brown 
3994*388e9c81SLen Brown 	case SCOPE_CORE:
3995*388e9c81SLen Brown 		sys.core_counter_bytes += 64;
3996*388e9c81SLen Brown 		msrp->next = sys.cp;
3997*388e9c81SLen Brown 		sys.cp = msrp;
3998*388e9c81SLen Brown 		sys.core_counter_bytes += sizeof(unsigned long long);
3999*388e9c81SLen Brown 		break;
4000*388e9c81SLen Brown 
4001*388e9c81SLen Brown 	case SCOPE_PACKAGE:
4002*388e9c81SLen Brown 		sys.package_counter_bytes += 64;
4003*388e9c81SLen Brown 		msrp->next = sys.pp;
4004*388e9c81SLen Brown 		sys.pp = msrp;
4005*388e9c81SLen Brown 		sys.package_counter_bytes += sizeof(unsigned long long);
4006*388e9c81SLen Brown 		break;
4007*388e9c81SLen Brown 	}
4008*388e9c81SLen Brown 
4009*388e9c81SLen Brown 	return 0;
4010*388e9c81SLen Brown }
4011*388e9c81SLen Brown 
4012*388e9c81SLen Brown void parse_add_command(char *add_command)
4013*388e9c81SLen Brown {
4014*388e9c81SLen Brown 	int msr_num = 0;
4015*388e9c81SLen Brown 	char name_buffer[NAME_BYTES];
4016*388e9c81SLen Brown 	int width = 64;
4017*388e9c81SLen Brown 	int fail = 0;
4018*388e9c81SLen Brown 	enum counter_scope scope = SCOPE_CPU;
4019*388e9c81SLen Brown 	enum counter_type type = COUNTER_CYCLES;
4020*388e9c81SLen Brown 	enum counter_format format = FORMAT_DELTA;
4021*388e9c81SLen Brown 
4022*388e9c81SLen Brown 	while (add_command) {
4023*388e9c81SLen Brown 
4024*388e9c81SLen Brown 		if (sscanf(add_command, "msr0x%x", &msr_num) == 1)
4025*388e9c81SLen Brown 			goto next;
4026*388e9c81SLen Brown 
4027*388e9c81SLen Brown 		if (sscanf(add_command, "msr%d", &msr_num) == 1)
4028*388e9c81SLen Brown 			goto next;
4029*388e9c81SLen Brown 
4030*388e9c81SLen Brown 		if (sscanf(add_command, "u%d", &width) == 1) {
4031*388e9c81SLen Brown 			if ((width == 32) || (width == 64))
4032*388e9c81SLen Brown 				goto next;
4033*388e9c81SLen Brown 			width = 64;
4034*388e9c81SLen Brown 		}
4035*388e9c81SLen Brown 		if (!strncmp(add_command, "cpu", strlen("cpu"))) {
4036*388e9c81SLen Brown 			scope = SCOPE_CPU;
4037*388e9c81SLen Brown 			goto next;
4038*388e9c81SLen Brown 		}
4039*388e9c81SLen Brown 		if (!strncmp(add_command, "core", strlen("core"))) {
4040*388e9c81SLen Brown 			scope = SCOPE_CORE;
4041*388e9c81SLen Brown 			goto next;
4042*388e9c81SLen Brown 		}
4043*388e9c81SLen Brown 		if (!strncmp(add_command, "package", strlen("package"))) {
4044*388e9c81SLen Brown 			scope = SCOPE_PACKAGE;
4045*388e9c81SLen Brown 			goto next;
4046*388e9c81SLen Brown 		}
4047*388e9c81SLen Brown 		if (!strncmp(add_command, "cycles", strlen("cycles"))) {
4048*388e9c81SLen Brown 			type = COUNTER_CYCLES;
4049*388e9c81SLen Brown 			goto next;
4050*388e9c81SLen Brown 		}
4051*388e9c81SLen Brown 		if (!strncmp(add_command, "seconds", strlen("seconds"))) {
4052*388e9c81SLen Brown 			type = COUNTER_SECONDS;
4053*388e9c81SLen Brown 			goto next;
4054*388e9c81SLen Brown 		}
4055*388e9c81SLen Brown 		if (!strncmp(add_command, "raw", strlen("raw"))) {
4056*388e9c81SLen Brown 			format = FORMAT_RAW;
4057*388e9c81SLen Brown 			goto next;
4058*388e9c81SLen Brown 		}
4059*388e9c81SLen Brown 		if (!strncmp(add_command, "delta", strlen("delta"))) {
4060*388e9c81SLen Brown 			format = FORMAT_DELTA;
4061*388e9c81SLen Brown 			goto next;
4062*388e9c81SLen Brown 		}
4063*388e9c81SLen Brown 		if (!strncmp(add_command, "percent", strlen("percent"))) {
4064*388e9c81SLen Brown 			format = FORMAT_PERCENT;
4065*388e9c81SLen Brown 			goto next;
4066*388e9c81SLen Brown 		}
4067*388e9c81SLen Brown 
4068*388e9c81SLen Brown 		if (sscanf(add_command, "%18s,%*s", name_buffer) == 1) {	/* 18 < NAME_BYTES */
4069*388e9c81SLen Brown 			char *eos;
4070*388e9c81SLen Brown 
4071*388e9c81SLen Brown 			eos = strchr(name_buffer, ',');
4072*388e9c81SLen Brown 			if (eos)
4073*388e9c81SLen Brown 				*eos = '\0';
4074*388e9c81SLen Brown 			goto next;
4075*388e9c81SLen Brown 		}
4076*388e9c81SLen Brown 
4077*388e9c81SLen Brown next:
4078*388e9c81SLen Brown 		add_command = strchr(add_command, ',');
4079*388e9c81SLen Brown 		if (add_command)
4080*388e9c81SLen Brown 			add_command++;
4081*388e9c81SLen Brown 
4082*388e9c81SLen Brown 	}
4083*388e9c81SLen Brown 	if (msr_num == 0) {
4084*388e9c81SLen Brown 		fprintf(stderr, "--add: (msrDDD | msr0xXXX) required\n");
4085*388e9c81SLen Brown 		fail++;
4086*388e9c81SLen Brown 	}
4087*388e9c81SLen Brown 
4088*388e9c81SLen Brown 	/* generate default column header */
4089*388e9c81SLen Brown 	if (*name_buffer == '\0') {
4090*388e9c81SLen Brown 		if (format == FORMAT_RAW) {
4091*388e9c81SLen Brown 			if (width == 32)
4092*388e9c81SLen Brown 				sprintf(name_buffer, "msr%d", msr_num);
4093*388e9c81SLen Brown 			else
4094*388e9c81SLen Brown 				sprintf(name_buffer, "MSR%d", msr_num);
4095*388e9c81SLen Brown 		} else if (format == FORMAT_DELTA) {
4096*388e9c81SLen Brown 			if (width == 32)
4097*388e9c81SLen Brown 				sprintf(name_buffer, "cnt%d", msr_num);
4098*388e9c81SLen Brown 			else
4099*388e9c81SLen Brown 				sprintf(name_buffer, "CNT%d", msr_num);
4100*388e9c81SLen Brown 		} else if (format == FORMAT_PERCENT) {
4101*388e9c81SLen Brown 			if (width == 32)
4102*388e9c81SLen Brown 				sprintf(name_buffer, "msr%d%%", msr_num);
4103*388e9c81SLen Brown 			else
4104*388e9c81SLen Brown 				sprintf(name_buffer, "MSR%d%%", msr_num);
4105*388e9c81SLen Brown 		}
4106*388e9c81SLen Brown 	}
4107*388e9c81SLen Brown 
4108*388e9c81SLen Brown 	if (add_counter(msr_num, name_buffer, width, scope, type, format))
4109*388e9c81SLen Brown 		fail++;
4110*388e9c81SLen Brown 
4111*388e9c81SLen Brown 	if (fail) {
4112*388e9c81SLen Brown 		help();
4113*388e9c81SLen Brown 		exit(1);
4114*388e9c81SLen Brown 	}
4115*388e9c81SLen Brown }
4116103a8feaSLen Brown void cmdline(int argc, char **argv)
4117103a8feaSLen Brown {
4118103a8feaSLen Brown 	int opt;
4119d8af6f5fSLen Brown 	int option_index = 0;
4120d8af6f5fSLen Brown 	static struct option long_options[] = {
4121*388e9c81SLen Brown 		{"add",		required_argument,	0, 'a'},
4122d8af6f5fSLen Brown 		{"Counter",	required_argument,	0, 'C'},
4123d8af6f5fSLen Brown 		{"counter",	required_argument,	0, 'c'},
4124d8af6f5fSLen Brown 		{"Dump",	no_argument,		0, 'D'},
4125d8af6f5fSLen Brown 		{"debug",	no_argument,		0, 'd'},
4126d8af6f5fSLen Brown 		{"interval",	required_argument,	0, 'i'},
4127d8af6f5fSLen Brown 		{"help",	no_argument,		0, 'h'},
4128d8af6f5fSLen Brown 		{"Joules",	no_argument,		0, 'J'},
4129d8af6f5fSLen Brown 		{"MSR",		required_argument,	0, 'M'},
4130d8af6f5fSLen Brown 		{"msr",		required_argument,	0, 'm'},
4131b7d8c148SLen Brown 		{"out",		required_argument,	0, 'o'},
4132d8af6f5fSLen Brown 		{"Package",	no_argument,		0, 'p'},
4133d8af6f5fSLen Brown 		{"processor",	no_argument,		0, 'p'},
4134d8af6f5fSLen Brown 		{"Summary",	no_argument,		0, 'S'},
4135d8af6f5fSLen Brown 		{"TCC",		required_argument,	0, 'T'},
4136d8af6f5fSLen Brown 		{"version",	no_argument,		0, 'v' },
4137d8af6f5fSLen Brown 		{0,		0,			0,  0 }
4138d8af6f5fSLen Brown 	};
4139103a8feaSLen Brown 
4140103a8feaSLen Brown 	progname = argv[0];
4141103a8feaSLen Brown 
4142b7d8c148SLen Brown 	while ((opt = getopt_long_only(argc, argv, "+C:c:Ddhi:JM:m:o:PpST:v",
4143d8af6f5fSLen Brown 				long_options, &option_index)) != -1) {
4144103a8feaSLen Brown 		switch (opt) {
4145*388e9c81SLen Brown 		case 'a':
4146*388e9c81SLen Brown 			parse_add_command(optarg);
4147*388e9c81SLen Brown 			break;
4148d8af6f5fSLen Brown 		case 'C':
4149d8af6f5fSLen Brown 			sscanf(optarg, "%x", &extra_delta_offset64);
4150103a8feaSLen Brown 			break;
4151f9240813SLen Brown 		case 'c':
41528e180f3cSLen Brown 			sscanf(optarg, "%x", &extra_delta_offset32);
41538e180f3cSLen Brown 			break;
4154d8af6f5fSLen Brown 		case 'D':
4155d8af6f5fSLen Brown 			dump_only++;
41568e180f3cSLen Brown 			break;
4157d8af6f5fSLen Brown 		case 'd':
4158d8af6f5fSLen Brown 			debug++;
41592f32edf1SLen Brown 			break;
4160d8af6f5fSLen Brown 		case 'h':
4161d8af6f5fSLen Brown 		default:
4162d8af6f5fSLen Brown 			help();
4163d8af6f5fSLen Brown 			exit(1);
4164d8af6f5fSLen Brown 		case 'i':
41652a0609c0SLen Brown 			{
41662a0609c0SLen Brown 				double interval = strtod(optarg, NULL);
41672a0609c0SLen Brown 
41682a0609c0SLen Brown 				if (interval < 0.001) {
4169b7d8c148SLen Brown 					fprintf(outf, "interval %f seconds is too small\n",
41702a0609c0SLen Brown 						interval);
41712a0609c0SLen Brown 					exit(2);
41722a0609c0SLen Brown 				}
41732a0609c0SLen Brown 
41742a0609c0SLen Brown 				interval_ts.tv_sec = interval;
41752a0609c0SLen Brown 				interval_ts.tv_nsec = (interval - interval_ts.tv_sec) * 1000000000;
41762a0609c0SLen Brown 			}
4177889facbeSLen Brown 			break;
41785c56be9aSDirk Brandewie 		case 'J':
41795c56be9aSDirk Brandewie 			rapl_joules++;
41805c56be9aSDirk Brandewie 			break;
4181d8af6f5fSLen Brown 		case 'M':
4182d8af6f5fSLen Brown 			sscanf(optarg, "%x", &extra_msr_offset64);
4183d8af6f5fSLen Brown 			break;
4184d8af6f5fSLen Brown 		case 'm':
4185d8af6f5fSLen Brown 			sscanf(optarg, "%x", &extra_msr_offset32);
4186d8af6f5fSLen Brown 			break;
4187b7d8c148SLen Brown 		case 'o':
4188b7d8c148SLen Brown 			outf = fopen_or_die(optarg, "w");
4189b7d8c148SLen Brown 			break;
4190d8af6f5fSLen Brown 		case 'P':
4191d8af6f5fSLen Brown 			show_pkg_only++;
4192d8af6f5fSLen Brown 			break;
4193d8af6f5fSLen Brown 		case 'p':
4194d8af6f5fSLen Brown 			show_core_only++;
4195d8af6f5fSLen Brown 			break;
4196d8af6f5fSLen Brown 		case 'S':
4197d8af6f5fSLen Brown 			summary_only++;
4198d8af6f5fSLen Brown 			break;
4199d8af6f5fSLen Brown 		case 'T':
4200d8af6f5fSLen Brown 			tcc_activation_temp_override = atoi(optarg);
4201d8af6f5fSLen Brown 			break;
4202d8af6f5fSLen Brown 		case 'v':
4203d8af6f5fSLen Brown 			print_version();
4204d8af6f5fSLen Brown 			exit(0);
4205d8af6f5fSLen Brown 			break;
4206103a8feaSLen Brown 		}
4207103a8feaSLen Brown 	}
4208103a8feaSLen Brown }
4209103a8feaSLen Brown 
4210103a8feaSLen Brown int main(int argc, char **argv)
4211103a8feaSLen Brown {
4212b7d8c148SLen Brown 	outf = stderr;
4213b7d8c148SLen Brown 
4214103a8feaSLen Brown 	cmdline(argc, argv);
4215103a8feaSLen Brown 
4216d8af6f5fSLen Brown 	if (debug)
4217d8af6f5fSLen Brown 		print_version();
4218103a8feaSLen Brown 
4219103a8feaSLen Brown 	turbostat_init();
4220103a8feaSLen Brown 
42213b4d5c7fSAndy Shevchenko 	/* dump counters and exit */
42223b4d5c7fSAndy Shevchenko 	if (dump_only)
42233b4d5c7fSAndy Shevchenko 		return get_and_dump_counters();
42243b4d5c7fSAndy Shevchenko 
4225103a8feaSLen Brown 	/*
4226103a8feaSLen Brown 	 * if any params left, it must be a command to fork
4227103a8feaSLen Brown 	 */
4228103a8feaSLen Brown 	if (argc - optind)
4229103a8feaSLen Brown 		return fork_it(argv + optind);
4230103a8feaSLen Brown 	else
4231103a8feaSLen Brown 		turbostat_loop();
4232103a8feaSLen Brown 
4233103a8feaSLen Brown 	return 0;
4234103a8feaSLen Brown }
4235