xref: /openbmc/linux/tools/power/x86/turbostat/turbostat.c (revision a99d87306f83d2a97c8c7e854b6583c4037ecf75)
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;
5296e47158SLen Brown unsigned int quiet;
530de6c0dfSLen Brown unsigned int sums_need_wide_columns;
54d8af6f5fSLen Brown unsigned int rapl_joules;
55d8af6f5fSLen Brown unsigned int summary_only;
56c8ade361SLen Brown unsigned int list_header_only;
57d8af6f5fSLen Brown unsigned int dump_only;
58103a8feaSLen Brown unsigned int do_snb_cstates;
59fb5d4327SDasaratharaman Chandramouli unsigned int do_knl_cstates;
60144b44b1SLen Brown unsigned int do_slm_cstates;
61144b44b1SLen Brown unsigned int use_c1_residency_msr;
62103a8feaSLen Brown unsigned int has_aperf;
63889facbeSLen Brown unsigned int has_epb;
645a63426eSLen Brown unsigned int do_irtl_snb;
655a63426eSLen Brown unsigned int do_irtl_hsw;
66fc04cc67SLen Brown unsigned int units = 1000000;	/* MHz etc */
67103a8feaSLen Brown unsigned int genuine_intel;
68103a8feaSLen Brown unsigned int has_invariant_tsc;
69d7899447SLen Brown unsigned int do_nhm_platform_info;
70cf4cbe53SLen Brown unsigned int no_MSR_MISC_PWR_MGMT;
71b2b34dfeSHubert Chrzaniuk unsigned int aperf_mperf_multiplier = 1;
72103a8feaSLen Brown double bclk;
73a2b7b749SLen Brown double base_hz;
7421ed5574SLen Brown unsigned int has_base_hz;
75a2b7b749SLen Brown double tsc_tweak = 1.0;
76c98d5d94SLen Brown unsigned int show_pkg_only;
77c98d5d94SLen Brown unsigned int show_core_only;
78c98d5d94SLen Brown char *output_buffer, *outp;
79889facbeSLen Brown unsigned int do_rapl;
80889facbeSLen Brown unsigned int do_dts;
81889facbeSLen Brown unsigned int do_ptm;
82fdf676e5SLen Brown unsigned long long  gfx_cur_rc6_ms;
8327d47356SLen Brown unsigned int gfx_cur_mhz;
84889facbeSLen Brown unsigned int tcc_activation_temp;
85889facbeSLen Brown unsigned int tcc_activation_temp_override;
8640ee8e3bSAndrey Semin double rapl_power_units, rapl_time_units;
8740ee8e3bSAndrey Semin double rapl_dram_energy_units, rapl_energy_units;
88889facbeSLen Brown double rapl_joule_counter_range;
893a9a941dSLen Brown unsigned int do_core_perf_limit_reasons;
903a9a941dSLen Brown unsigned int do_gfx_perf_limit_reasons;
913a9a941dSLen Brown unsigned int do_ring_perf_limit_reasons;
928a5bdf41SLen Brown unsigned int crystal_hz;
938a5bdf41SLen Brown unsigned long long tsc_hz;
947ce7d5deSPrarit Bhargava int base_cpu;
9521ed5574SLen Brown double discover_bclk(unsigned int family, unsigned int model);
967f5c258eSLen Brown unsigned int has_hwp;	/* IA32_PM_ENABLE, IA32_HWP_CAPABILITIES */
977f5c258eSLen Brown 			/* IA32_HWP_REQUEST, IA32_HWP_STATUS */
987f5c258eSLen Brown unsigned int has_hwp_notify;		/* IA32_HWP_INTERRUPT */
997f5c258eSLen Brown unsigned int has_hwp_activity_window;	/* IA32_HWP_REQUEST[bits 41:32] */
1007f5c258eSLen Brown unsigned int has_hwp_epp;		/* IA32_HWP_REQUEST[bits 31:24] */
1017f5c258eSLen Brown unsigned int has_hwp_pkg;		/* IA32_HWP_REQUEST_PKG */
10233148d67SLen Brown unsigned int has_misc_feature_control;
103889facbeSLen Brown 
104889facbeSLen Brown #define RAPL_PKG		(1 << 0)
105e6f9bb3cSLen Brown 					/* 0x610 MSR_PKG_POWER_LIMIT */
106e6f9bb3cSLen Brown 					/* 0x611 MSR_PKG_ENERGY_STATUS */
107e6f9bb3cSLen Brown #define RAPL_PKG_PERF_STATUS	(1 << 1)
108e6f9bb3cSLen Brown 					/* 0x613 MSR_PKG_PERF_STATUS */
109e6f9bb3cSLen Brown #define RAPL_PKG_POWER_INFO	(1 << 2)
110e6f9bb3cSLen Brown 					/* 0x614 MSR_PKG_POWER_INFO */
111e6f9bb3cSLen Brown 
112889facbeSLen Brown #define RAPL_DRAM		(1 << 3)
113e6f9bb3cSLen Brown 					/* 0x618 MSR_DRAM_POWER_LIMIT */
114e6f9bb3cSLen Brown 					/* 0x619 MSR_DRAM_ENERGY_STATUS */
115e6f9bb3cSLen Brown #define RAPL_DRAM_PERF_STATUS	(1 << 4)
116e6f9bb3cSLen Brown 					/* 0x61b MSR_DRAM_PERF_STATUS */
1170b2bb692SLen Brown #define RAPL_DRAM_POWER_INFO	(1 << 5)
1180b2bb692SLen Brown 					/* 0x61c MSR_DRAM_POWER_INFO */
119e6f9bb3cSLen Brown 
1209148494cSJacob Pan #define RAPL_CORES_POWER_LIMIT	(1 << 6)
121e6f9bb3cSLen Brown 					/* 0x638 MSR_PP0_POWER_LIMIT */
1220b2bb692SLen Brown #define RAPL_CORE_POLICY	(1 << 7)
123e6f9bb3cSLen Brown 					/* 0x63a MSR_PP0_POLICY */
124e6f9bb3cSLen Brown 
1250b2bb692SLen Brown #define RAPL_GFX		(1 << 8)
126e6f9bb3cSLen Brown 					/* 0x640 MSR_PP1_POWER_LIMIT */
127e6f9bb3cSLen Brown 					/* 0x641 MSR_PP1_ENERGY_STATUS */
128e6f9bb3cSLen Brown 					/* 0x642 MSR_PP1_POLICY */
1299148494cSJacob Pan 
1309148494cSJacob Pan #define RAPL_CORES_ENERGY_STATUS	(1 << 9)
1319148494cSJacob Pan 					/* 0x639 MSR_PP0_ENERGY_STATUS */
1329148494cSJacob Pan #define RAPL_CORES (RAPL_CORES_ENERGY_STATUS | RAPL_CORES_POWER_LIMIT)
133889facbeSLen Brown #define	TJMAX_DEFAULT	100
134889facbeSLen Brown 
135889facbeSLen Brown #define MAX(a, b) ((a) > (b) ? (a) : (b))
136103a8feaSLen Brown 
137388e9c81SLen Brown /*
138388e9c81SLen Brown  * buffer size used by sscanf() for added column names
139388e9c81SLen Brown  * Usually truncated to 7 characters, but also handles 18 columns for raw 64-bit counters
140388e9c81SLen Brown  */
141388e9c81SLen Brown #define	NAME_BYTES 20
142495c7654SLen Brown #define PATH_BYTES 128
143388e9c81SLen Brown 
144103a8feaSLen Brown int backwards_count;
145103a8feaSLen Brown char *progname;
146103a8feaSLen Brown 
1471ef7d21aSLen Brown #define CPU_SUBSET_MAXCPUS	1024	/* need to use before probe... */
1481ef7d21aSLen Brown cpu_set_t *cpu_present_set, *cpu_affinity_set, *cpu_subset;
1491ef7d21aSLen Brown size_t cpu_present_setsize, cpu_affinity_setsize, cpu_subset_size;
150678a3bd1SLen Brown #define MAX_ADDED_COUNTERS 16
151c98d5d94SLen Brown 
152c98d5d94SLen Brown struct thread_data {
153c98d5d94SLen Brown 	unsigned long long tsc;
154c98d5d94SLen Brown 	unsigned long long aperf;
155c98d5d94SLen Brown 	unsigned long long mperf;
156144b44b1SLen Brown 	unsigned long long c1;
1570de6c0dfSLen Brown 	unsigned long long  irq_count;
1581ed51011SLen Brown 	unsigned int smi_count;
159c98d5d94SLen Brown 	unsigned int cpu_id;
160c98d5d94SLen Brown 	unsigned int flags;
161c98d5d94SLen Brown #define CPU_IS_FIRST_THREAD_IN_CORE	0x2
162c98d5d94SLen Brown #define CPU_IS_FIRST_CORE_IN_PACKAGE	0x4
163678a3bd1SLen Brown 	unsigned long long counter[MAX_ADDED_COUNTERS];
164c98d5d94SLen Brown } *thread_even, *thread_odd;
165c98d5d94SLen Brown 
166c98d5d94SLen Brown struct core_data {
167c98d5d94SLen Brown 	unsigned long long c3;
168c98d5d94SLen Brown 	unsigned long long c6;
169c98d5d94SLen Brown 	unsigned long long c7;
1700539ba11SLen Brown 	unsigned long long mc6_us;	/* duplicate as per-core for now, even though per module */
171889facbeSLen Brown 	unsigned int core_temp_c;
172c98d5d94SLen Brown 	unsigned int core_id;
173678a3bd1SLen Brown 	unsigned long long counter[MAX_ADDED_COUNTERS];
174c98d5d94SLen Brown } *core_even, *core_odd;
175c98d5d94SLen Brown 
176c98d5d94SLen Brown struct pkg_data {
177c98d5d94SLen Brown 	unsigned long long pc2;
178c98d5d94SLen Brown 	unsigned long long pc3;
179c98d5d94SLen Brown 	unsigned long long pc6;
180c98d5d94SLen Brown 	unsigned long long pc7;
181ca58710fSKristen Carlson Accardi 	unsigned long long pc8;
182ca58710fSKristen Carlson Accardi 	unsigned long long pc9;
183ca58710fSKristen Carlson Accardi 	unsigned long long pc10;
1840b2bb692SLen Brown 	unsigned long long pkg_wtd_core_c0;
1850b2bb692SLen Brown 	unsigned long long pkg_any_core_c0;
1860b2bb692SLen Brown 	unsigned long long pkg_any_gfxe_c0;
1870b2bb692SLen Brown 	unsigned long long pkg_both_core_gfxe_c0;
1889185e988SLen Brown 	long long gfx_rc6_ms;
18927d47356SLen Brown 	unsigned int gfx_mhz;
190c98d5d94SLen Brown 	unsigned int package_id;
191889facbeSLen Brown 	unsigned int energy_pkg;	/* MSR_PKG_ENERGY_STATUS */
192889facbeSLen Brown 	unsigned int energy_dram;	/* MSR_DRAM_ENERGY_STATUS */
193889facbeSLen Brown 	unsigned int energy_cores;	/* MSR_PP0_ENERGY_STATUS */
194889facbeSLen Brown 	unsigned int energy_gfx;	/* MSR_PP1_ENERGY_STATUS */
195889facbeSLen Brown 	unsigned int rapl_pkg_perf_status;	/* MSR_PKG_PERF_STATUS */
196889facbeSLen Brown 	unsigned int rapl_dram_perf_status;	/* MSR_DRAM_PERF_STATUS */
197889facbeSLen Brown 	unsigned int pkg_temp_c;
198678a3bd1SLen Brown 	unsigned long long counter[MAX_ADDED_COUNTERS];
199c98d5d94SLen Brown } *package_even, *package_odd;
200c98d5d94SLen Brown 
201c98d5d94SLen Brown #define ODD_COUNTERS thread_odd, core_odd, package_odd
202c98d5d94SLen Brown #define EVEN_COUNTERS thread_even, core_even, package_even
203c98d5d94SLen Brown 
204c98d5d94SLen Brown #define GET_THREAD(thread_base, thread_no, core_no, pkg_no) \
205c98d5d94SLen Brown 	(thread_base + (pkg_no) * topo.num_cores_per_pkg * \
206c98d5d94SLen Brown 		topo.num_threads_per_core + \
207c98d5d94SLen Brown 		(core_no) * topo.num_threads_per_core + (thread_no))
208c98d5d94SLen Brown #define GET_CORE(core_base, core_no, pkg_no) \
209c98d5d94SLen Brown 	(core_base + (pkg_no) * topo.num_cores_per_pkg + (core_no))
210c98d5d94SLen Brown #define GET_PKG(pkg_base, pkg_no) (pkg_base + pkg_no)
211c98d5d94SLen Brown 
212388e9c81SLen Brown enum counter_scope {SCOPE_CPU, SCOPE_CORE, SCOPE_PACKAGE};
21341618e63SLen Brown enum counter_type {COUNTER_ITEMS, COUNTER_CYCLES, COUNTER_SECONDS, COUNTER_USEC};
214388e9c81SLen Brown enum counter_format {FORMAT_RAW, FORMAT_DELTA, FORMAT_PERCENT};
215388e9c81SLen Brown 
216388e9c81SLen Brown struct msr_counter {
217388e9c81SLen Brown 	unsigned int msr_num;
218388e9c81SLen Brown 	char name[NAME_BYTES];
219495c7654SLen Brown 	char path[PATH_BYTES];
220388e9c81SLen Brown 	unsigned int width;
221388e9c81SLen Brown 	enum counter_type type;
222388e9c81SLen Brown 	enum counter_format format;
223388e9c81SLen Brown 	struct msr_counter *next;
224812db3f7SLen Brown 	unsigned int flags;
225812db3f7SLen Brown #define	FLAGS_HIDE	(1 << 0)
226812db3f7SLen Brown #define	FLAGS_SHOW	(1 << 1)
22741618e63SLen Brown #define	SYSFS_PERCPU	(1 << 1)
228388e9c81SLen Brown };
229388e9c81SLen Brown 
230388e9c81SLen Brown struct sys_counters {
231678a3bd1SLen Brown 	unsigned int added_thread_counters;
232678a3bd1SLen Brown 	unsigned int added_core_counters;
233678a3bd1SLen Brown 	unsigned int added_package_counters;
234388e9c81SLen Brown 	struct msr_counter *tp;
235388e9c81SLen Brown 	struct msr_counter *cp;
236388e9c81SLen Brown 	struct msr_counter *pp;
237388e9c81SLen Brown } sys;
238388e9c81SLen Brown 
239c98d5d94SLen Brown struct system_summary {
240c98d5d94SLen Brown 	struct thread_data threads;
241c98d5d94SLen Brown 	struct core_data cores;
242c98d5d94SLen Brown 	struct pkg_data packages;
243388e9c81SLen Brown } average;
244c98d5d94SLen Brown 
245c98d5d94SLen Brown 
246c98d5d94SLen Brown struct topo_params {
247c98d5d94SLen Brown 	int num_packages;
248103a8feaSLen Brown 	int num_cpus;
249c98d5d94SLen Brown 	int num_cores;
250c98d5d94SLen Brown 	int max_cpu_num;
251c98d5d94SLen Brown 	int num_cores_per_pkg;
252c98d5d94SLen Brown 	int num_threads_per_core;
253c98d5d94SLen Brown } topo;
254103a8feaSLen Brown 
255c98d5d94SLen Brown struct timeval tv_even, tv_odd, tv_delta;
256103a8feaSLen Brown 
257562a2d37SLen Brown int *irq_column_2_cpu;	/* /proc/interrupts column numbers */
258562a2d37SLen Brown int *irqs_per_cpu;		/* indexed by cpu_num */
259562a2d37SLen Brown 
260c98d5d94SLen Brown void setup_all_buffers(void);
261103a8feaSLen Brown 
262c98d5d94SLen Brown int cpu_is_not_present(int cpu)
263d15cf7c1SLen Brown {
264c98d5d94SLen Brown 	return !CPU_ISSET_S(cpu, cpu_present_setsize, cpu_present_set);
265c98d5d94SLen Brown }
266c98d5d94SLen Brown /*
267c98d5d94SLen Brown  * run func(thread, core, package) in topology order
268c98d5d94SLen Brown  * skip non-present cpus
269c98d5d94SLen Brown  */
270c98d5d94SLen Brown 
271c98d5d94SLen Brown int for_all_cpus(int (func)(struct thread_data *, struct core_data *, struct pkg_data *),
272c98d5d94SLen Brown 	struct thread_data *thread_base, struct core_data *core_base, struct pkg_data *pkg_base)
273c98d5d94SLen Brown {
274c98d5d94SLen Brown 	int retval, pkg_no, core_no, thread_no;
275c98d5d94SLen Brown 
276c98d5d94SLen Brown 	for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) {
277c98d5d94SLen Brown 		for (core_no = 0; core_no < topo.num_cores_per_pkg; ++core_no) {
278c98d5d94SLen Brown 			for (thread_no = 0; thread_no <
279c98d5d94SLen Brown 				topo.num_threads_per_core; ++thread_no) {
280c98d5d94SLen Brown 				struct thread_data *t;
281c98d5d94SLen Brown 				struct core_data *c;
282c98d5d94SLen Brown 				struct pkg_data *p;
283c98d5d94SLen Brown 
284c98d5d94SLen Brown 				t = GET_THREAD(thread_base, thread_no, core_no, pkg_no);
285c98d5d94SLen Brown 
286c98d5d94SLen Brown 				if (cpu_is_not_present(t->cpu_id))
287c98d5d94SLen Brown 					continue;
288c98d5d94SLen Brown 
289c98d5d94SLen Brown 				c = GET_CORE(core_base, core_no, pkg_no);
290c98d5d94SLen Brown 				p = GET_PKG(pkg_base, pkg_no);
291c98d5d94SLen Brown 
292c98d5d94SLen Brown 				retval = func(t, c, p);
293c98d5d94SLen Brown 				if (retval)
294c98d5d94SLen Brown 					return retval;
295c98d5d94SLen Brown 			}
296c98d5d94SLen Brown 		}
297c98d5d94SLen Brown 	}
298d15cf7c1SLen Brown 	return 0;
299d15cf7c1SLen Brown }
300d15cf7c1SLen Brown 
30188c3281fSLen Brown int cpu_migrate(int cpu)
30288c3281fSLen Brown {
303c98d5d94SLen Brown 	CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set);
304c98d5d94SLen Brown 	CPU_SET_S(cpu, cpu_affinity_setsize, cpu_affinity_set);
305c98d5d94SLen Brown 	if (sched_setaffinity(0, cpu_affinity_setsize, cpu_affinity_set) == -1)
30688c3281fSLen Brown 		return -1;
30788c3281fSLen Brown 	else
30888c3281fSLen Brown 		return 0;
30988c3281fSLen Brown }
31036229897SLen Brown int get_msr_fd(int cpu)
311103a8feaSLen Brown {
312103a8feaSLen Brown 	char pathname[32];
313103a8feaSLen Brown 	int fd;
314103a8feaSLen Brown 
31536229897SLen Brown 	fd = fd_percpu[cpu];
31636229897SLen Brown 
31736229897SLen Brown 	if (fd)
31836229897SLen Brown 		return fd;
31936229897SLen Brown 
320103a8feaSLen Brown 	sprintf(pathname, "/dev/cpu/%d/msr", cpu);
321103a8feaSLen Brown 	fd = open(pathname, O_RDONLY);
32215aaa346SLen Brown 	if (fd < 0)
32398481e79SLen Brown 		err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname);
324103a8feaSLen Brown 
32536229897SLen Brown 	fd_percpu[cpu] = fd;
32636229897SLen Brown 
32736229897SLen Brown 	return fd;
32836229897SLen Brown }
32936229897SLen Brown 
33036229897SLen Brown int get_msr(int cpu, off_t offset, unsigned long long *msr)
33136229897SLen Brown {
33236229897SLen Brown 	ssize_t retval;
33336229897SLen Brown 
33436229897SLen Brown 	retval = pread(get_msr_fd(cpu), msr, sizeof(*msr), offset);
33515aaa346SLen Brown 
33698481e79SLen Brown 	if (retval != sizeof *msr)
337cf4cbe53SLen Brown 		err(-1, "cpu%d: msr offset 0x%llx read failed", cpu, (unsigned long long)offset);
33815aaa346SLen Brown 
33915aaa346SLen Brown 	return 0;
340103a8feaSLen Brown }
341103a8feaSLen Brown 
342fc04cc67SLen Brown /*
343812db3f7SLen Brown  * Each string in this array is compared in --show and --hide cmdline.
344812db3f7SLen Brown  * Thus, strings that are proper sub-sets must follow their more specific peers.
345fc04cc67SLen Brown  */
346812db3f7SLen Brown struct msr_counter bic[] = {
347812db3f7SLen Brown 	{ 0x0, "Package" },
348812db3f7SLen Brown 	{ 0x0, "Avg_MHz" },
349812db3f7SLen Brown 	{ 0x0, "Bzy_MHz" },
350812db3f7SLen Brown 	{ 0x0, "TSC_MHz" },
351812db3f7SLen Brown 	{ 0x0, "IRQ" },
352495c7654SLen Brown 	{ 0x0, "SMI", "", 32, 0, FORMAT_DELTA, NULL},
353812db3f7SLen Brown 	{ 0x0, "Busy%" },
354812db3f7SLen Brown 	{ 0x0, "CPU%c1" },
355812db3f7SLen Brown 	{ 0x0, "CPU%c3" },
356812db3f7SLen Brown 	{ 0x0, "CPU%c6" },
357812db3f7SLen Brown 	{ 0x0, "CPU%c7" },
358812db3f7SLen Brown 	{ 0x0, "ThreadC" },
359812db3f7SLen Brown 	{ 0x0, "CoreTmp" },
360812db3f7SLen Brown 	{ 0x0, "CoreCnt" },
361812db3f7SLen Brown 	{ 0x0, "PkgTmp" },
362812db3f7SLen Brown 	{ 0x0, "GFX%rc6" },
363812db3f7SLen Brown 	{ 0x0, "GFXMHz" },
364812db3f7SLen Brown 	{ 0x0, "Pkg%pc2" },
365812db3f7SLen Brown 	{ 0x0, "Pkg%pc3" },
366812db3f7SLen Brown 	{ 0x0, "Pkg%pc6" },
367812db3f7SLen Brown 	{ 0x0, "Pkg%pc7" },
3680f47c08dSLen Brown 	{ 0x0, "Pkg%pc8" },
3690f47c08dSLen Brown 	{ 0x0, "Pkg%pc9" },
3700f47c08dSLen Brown 	{ 0x0, "Pkg%pc10" },
371812db3f7SLen Brown 	{ 0x0, "PkgWatt" },
372812db3f7SLen Brown 	{ 0x0, "CorWatt" },
373812db3f7SLen Brown 	{ 0x0, "GFXWatt" },
374812db3f7SLen Brown 	{ 0x0, "PkgCnt" },
375812db3f7SLen Brown 	{ 0x0, "RAMWatt" },
376812db3f7SLen Brown 	{ 0x0, "PKG_%" },
377812db3f7SLen Brown 	{ 0x0, "RAM_%" },
378812db3f7SLen Brown 	{ 0x0, "Pkg_J" },
379812db3f7SLen Brown 	{ 0x0, "Cor_J" },
380812db3f7SLen Brown 	{ 0x0, "GFX_J" },
381812db3f7SLen Brown 	{ 0x0, "RAM_J" },
382812db3f7SLen Brown 	{ 0x0, "Core" },
383812db3f7SLen Brown 	{ 0x0, "CPU" },
3840539ba11SLen Brown 	{ 0x0, "Mod%c6" },
38541618e63SLen Brown 	{ 0x0, "sysfs" },
386*a99d8730SLen Brown 	{ 0x0, "Totl%C0" },
387*a99d8730SLen Brown 	{ 0x0, "Any%C0" },
388*a99d8730SLen Brown 	{ 0x0, "GFX%C0" },
389*a99d8730SLen Brown 	{ 0x0, "CPUGFX%" },
390812db3f7SLen Brown };
391812db3f7SLen Brown 
392*a99d8730SLen Brown 
393*a99d8730SLen Brown 
394812db3f7SLen Brown #define MAX_BIC (sizeof(bic) / sizeof(struct msr_counter))
395812db3f7SLen Brown #define	BIC_Package	(1ULL << 0)
396812db3f7SLen Brown #define	BIC_Avg_MHz	(1ULL << 1)
397812db3f7SLen Brown #define	BIC_Bzy_MHz	(1ULL << 2)
398812db3f7SLen Brown #define	BIC_TSC_MHz	(1ULL << 3)
399812db3f7SLen Brown #define	BIC_IRQ		(1ULL << 4)
400812db3f7SLen Brown #define	BIC_SMI		(1ULL << 5)
401812db3f7SLen Brown #define	BIC_Busy	(1ULL << 6)
402812db3f7SLen Brown #define	BIC_CPU_c1	(1ULL << 7)
403812db3f7SLen Brown #define	BIC_CPU_c3	(1ULL << 8)
404812db3f7SLen Brown #define	BIC_CPU_c6	(1ULL << 9)
405812db3f7SLen Brown #define	BIC_CPU_c7	(1ULL << 10)
406812db3f7SLen Brown #define	BIC_ThreadC	(1ULL << 11)
407812db3f7SLen Brown #define	BIC_CoreTmp	(1ULL << 12)
408812db3f7SLen Brown #define	BIC_CoreCnt	(1ULL << 13)
409812db3f7SLen Brown #define	BIC_PkgTmp	(1ULL << 14)
410812db3f7SLen Brown #define	BIC_GFX_rc6	(1ULL << 15)
411812db3f7SLen Brown #define	BIC_GFXMHz	(1ULL << 16)
412812db3f7SLen Brown #define	BIC_Pkgpc2	(1ULL << 17)
413812db3f7SLen Brown #define	BIC_Pkgpc3	(1ULL << 18)
414812db3f7SLen Brown #define	BIC_Pkgpc6	(1ULL << 19)
415812db3f7SLen Brown #define	BIC_Pkgpc7	(1ULL << 20)
4160f47c08dSLen Brown #define	BIC_Pkgpc8	(1ULL << 21)
4170f47c08dSLen Brown #define	BIC_Pkgpc9	(1ULL << 22)
4180f47c08dSLen Brown #define	BIC_Pkgpc10	(1ULL << 23)
4190f47c08dSLen Brown #define	BIC_PkgWatt	(1ULL << 24)
4200f47c08dSLen Brown #define	BIC_CorWatt	(1ULL << 25)
4210f47c08dSLen Brown #define	BIC_GFXWatt	(1ULL << 26)
4220f47c08dSLen Brown #define	BIC_PkgCnt	(1ULL << 27)
4230f47c08dSLen Brown #define	BIC_RAMWatt	(1ULL << 28)
4240f47c08dSLen Brown #define	BIC_PKG__	(1ULL << 29)
4250f47c08dSLen Brown #define	BIC_RAM__	(1ULL << 30)
4260f47c08dSLen Brown #define	BIC_Pkg_J	(1ULL << 31)
4270f47c08dSLen Brown #define	BIC_Cor_J	(1ULL << 32)
4280f47c08dSLen Brown #define	BIC_GFX_J	(1ULL << 33)
4290f47c08dSLen Brown #define	BIC_RAM_J	(1ULL << 34)
4300f47c08dSLen Brown #define	BIC_Core	(1ULL << 35)
4310f47c08dSLen Brown #define	BIC_CPU		(1ULL << 36)
4320f47c08dSLen Brown #define	BIC_Mod_c6	(1ULL << 37)
43341618e63SLen Brown #define	BIC_sysfs	(1ULL << 38)
434*a99d8730SLen Brown #define	BIC_Totl_c0	(1ULL << 39)
435*a99d8730SLen Brown #define	BIC_Any_c0	(1ULL << 40)
436*a99d8730SLen Brown #define	BIC_GFX_c0	(1ULL << 41)
437*a99d8730SLen Brown #define	BIC_CPUGFX	(1ULL << 42)
438812db3f7SLen Brown 
439812db3f7SLen Brown unsigned long long bic_enabled = 0xFFFFFFFFFFFFFFFFULL;
44041618e63SLen Brown unsigned long long bic_present = BIC_sysfs;
441812db3f7SLen Brown 
442812db3f7SLen Brown #define DO_BIC(COUNTER_NAME) (bic_enabled & bic_present & COUNTER_NAME)
443812db3f7SLen Brown #define BIC_PRESENT(COUNTER_BIT) (bic_present |= COUNTER_BIT)
4440f47c08dSLen Brown #define BIC_NOT_PRESENT(COUNTER_BIT) (bic_present &= ~COUNTER_BIT)
445812db3f7SLen Brown 
446dd778a5eSLen Brown #define MAX_DEFERRED 16
447dd778a5eSLen Brown char *deferred_skip_names[MAX_DEFERRED];
448dd778a5eSLen Brown int deferred_skip_index;
449dd778a5eSLen Brown 
450dd778a5eSLen Brown /*
451dd778a5eSLen Brown  * HIDE_LIST - hide this list of counters, show the rest [default]
452dd778a5eSLen Brown  * SHOW_LIST - show this list of counters, hide the rest
453dd778a5eSLen Brown  */
454dd778a5eSLen Brown enum show_hide_mode { SHOW_LIST, HIDE_LIST } global_show_hide_mode = HIDE_LIST;
455dd778a5eSLen Brown 
456dd778a5eSLen Brown void help(void)
457dd778a5eSLen Brown {
458dd778a5eSLen Brown 	fprintf(outf,
459dd778a5eSLen Brown 	"Usage: turbostat [OPTIONS][(--interval seconds) | COMMAND ...]\n"
460dd778a5eSLen Brown 	"\n"
461dd778a5eSLen Brown 	"Turbostat forks the specified COMMAND and prints statistics\n"
462dd778a5eSLen Brown 	"when COMMAND completes.\n"
463dd778a5eSLen Brown 	"If no COMMAND is specified, turbostat wakes every 5-seconds\n"
464dd778a5eSLen Brown 	"to print statistics, until interrupted.\n"
465dd778a5eSLen Brown 	"--add		add a counter\n"
466dd778a5eSLen Brown 	"		eg. --add msr0x10,u64,cpu,delta,MY_TSC\n"
467dd778a5eSLen Brown 	"--cpu	cpu-set	limit output to summary plus cpu-set:\n"
468dd778a5eSLen Brown 	"		{core | package | j,k,l..m,n-p }\n"
469dd778a5eSLen Brown 	"--quiet	skip decoding system configuration header\n"
470dd778a5eSLen Brown 	"--interval sec	Override default 5-second measurement interval\n"
471dd778a5eSLen Brown 	"--help		print this help message\n"
472dd778a5eSLen Brown 	"--list		list column headers only\n"
473dd778a5eSLen Brown 	"--out file	create or truncate \"file\" for all output\n"
474dd778a5eSLen Brown 	"--version	print version information\n"
475dd778a5eSLen Brown 	"\n"
476dd778a5eSLen Brown 	"For more help, run \"man turbostat\"\n");
477dd778a5eSLen Brown }
478dd778a5eSLen Brown 
479812db3f7SLen Brown /*
480812db3f7SLen Brown  * bic_lookup
481812db3f7SLen Brown  * for all the strings in comma separate name_list,
482812db3f7SLen Brown  * set the approprate bit in return value.
483812db3f7SLen Brown  */
484dd778a5eSLen Brown unsigned long long bic_lookup(char *name_list, enum show_hide_mode mode)
485812db3f7SLen Brown {
486812db3f7SLen Brown 	int i;
487812db3f7SLen Brown 	unsigned long long retval = 0;
488812db3f7SLen Brown 
489812db3f7SLen Brown 	while (name_list) {
490812db3f7SLen Brown 		char *comma;
491812db3f7SLen Brown 
492812db3f7SLen Brown 		comma = strchr(name_list, ',');
493812db3f7SLen Brown 
494812db3f7SLen Brown 		if (comma)
495812db3f7SLen Brown 			*comma = '\0';
496812db3f7SLen Brown 
497812db3f7SLen Brown 		for (i = 0; i < MAX_BIC; ++i) {
498812db3f7SLen Brown 			if (!strcmp(name_list, bic[i].name)) {
499812db3f7SLen Brown 				retval |= (1ULL << i);
500812db3f7SLen Brown 				break;
501812db3f7SLen Brown 			}
502812db3f7SLen Brown 		}
503812db3f7SLen Brown 		if (i == MAX_BIC) {
504dd778a5eSLen Brown 			if (mode == SHOW_LIST) {
505812db3f7SLen Brown 				fprintf(stderr, "Invalid counter name: %s\n", name_list);
506812db3f7SLen Brown 				exit(-1);
507812db3f7SLen Brown 			}
508dd778a5eSLen Brown 			deferred_skip_names[deferred_skip_index++] = name_list;
509dd778a5eSLen Brown 			if (debug)
510dd778a5eSLen Brown 				fprintf(stderr, "deferred \"%s\"\n", name_list);
511dd778a5eSLen Brown 			if (deferred_skip_index >= MAX_DEFERRED) {
512dd778a5eSLen Brown 				fprintf(stderr, "More than max %d un-recognized --skip options '%s'\n",
513dd778a5eSLen Brown 					MAX_DEFERRED, name_list);
514dd778a5eSLen Brown 				help();
515dd778a5eSLen Brown 				exit(1);
516dd778a5eSLen Brown 			}
517dd778a5eSLen Brown 		}
518812db3f7SLen Brown 
519812db3f7SLen Brown 		name_list = comma;
520812db3f7SLen Brown 		if (name_list)
521812db3f7SLen Brown 			name_list++;
522812db3f7SLen Brown 
523812db3f7SLen Brown 	}
524812db3f7SLen Brown 	return retval;
525812db3f7SLen Brown }
526fc04cc67SLen Brown 
527dd778a5eSLen Brown 
528c8ade361SLen Brown void print_header(char *delim)
529103a8feaSLen Brown {
530388e9c81SLen Brown 	struct msr_counter *mp;
5316168c2e0SLen Brown 	int printed = 0;
532388e9c81SLen Brown 
533812db3f7SLen Brown 	if (DO_BIC(BIC_Package))
5346168c2e0SLen Brown 		outp += sprintf(outp, "%sPackage", (printed++ ? delim : ""));
535812db3f7SLen Brown 	if (DO_BIC(BIC_Core))
5366168c2e0SLen Brown 		outp += sprintf(outp, "%sCore", (printed++ ? delim : ""));
537812db3f7SLen Brown 	if (DO_BIC(BIC_CPU))
5386168c2e0SLen Brown 		outp += sprintf(outp, "%sCPU", (printed++ ? delim : ""));
539812db3f7SLen Brown 	if (DO_BIC(BIC_Avg_MHz))
5406168c2e0SLen Brown 		outp += sprintf(outp, "%sAvg_MHz", (printed++ ? delim : ""));
541812db3f7SLen Brown 	if (DO_BIC(BIC_Busy))
5426168c2e0SLen Brown 		outp += sprintf(outp, "%sBusy%%", (printed++ ? delim : ""));
543812db3f7SLen Brown 	if (DO_BIC(BIC_Bzy_MHz))
5446168c2e0SLen Brown 		outp += sprintf(outp, "%sBzy_MHz", (printed++ ? delim : ""));
545812db3f7SLen Brown 	if (DO_BIC(BIC_TSC_MHz))
5466168c2e0SLen Brown 		outp += sprintf(outp, "%sTSC_MHz", (printed++ ? delim : ""));
5471cc21f7bSLen Brown 
5480de6c0dfSLen Brown 	if (DO_BIC(BIC_IRQ)) {
5490de6c0dfSLen Brown 		if (sums_need_wide_columns)
5506168c2e0SLen Brown 			outp += sprintf(outp, "%s     IRQ", (printed++ ? delim : ""));
5510de6c0dfSLen Brown 		else
5526168c2e0SLen Brown 			outp += sprintf(outp, "%sIRQ", (printed++ ? delim : ""));
5530de6c0dfSLen Brown 	}
5540de6c0dfSLen Brown 
555812db3f7SLen Brown 	if (DO_BIC(BIC_SMI))
5566168c2e0SLen Brown 		outp += sprintf(outp, "%sSMI", (printed++ ? delim : ""));
5571cc21f7bSLen Brown 
558388e9c81SLen Brown 	for (mp = sys.tp; mp; mp = mp->next) {
559dd778a5eSLen Brown 
560388e9c81SLen Brown 		if (mp->format == FORMAT_RAW) {
561388e9c81SLen Brown 			if (mp->width == 64)
562dd778a5eSLen Brown 				outp += sprintf(outp, "%s%18.18s", (printed++ ? delim : ""), mp->name);
563388e9c81SLen Brown 			else
564dd778a5eSLen Brown 				outp += sprintf(outp, "%s%10.10s", (printed++ ? delim : ""), mp->name);
565388e9c81SLen Brown 		} else {
5660de6c0dfSLen Brown 			if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns)
567dd778a5eSLen Brown 				outp += sprintf(outp, "%s%8s", (printed++ ? delim : ""), mp->name);
5680de6c0dfSLen Brown 			else
569dd778a5eSLen Brown 				outp += sprintf(outp, "%s%s", (printed++ ? delim : ""), mp->name);
570388e9c81SLen Brown 		}
571388e9c81SLen Brown 	}
572388e9c81SLen Brown 
57341618e63SLen Brown 	if (DO_BIC(BIC_CPU_c1))
5746168c2e0SLen Brown 		outp += sprintf(outp, "%sCPU%%c1", (printed++ ? delim : ""));
575812db3f7SLen Brown 	if (DO_BIC(BIC_CPU_c3) && !do_slm_cstates && !do_knl_cstates)
5766168c2e0SLen Brown 		outp += sprintf(outp, "%sCPU%%c3", (printed++ ? delim : ""));
577812db3f7SLen Brown 	if (DO_BIC(BIC_CPU_c6))
5786168c2e0SLen Brown 		outp += sprintf(outp, "%sCPU%%c6", (printed++ ? delim : ""));
579812db3f7SLen Brown 	if (DO_BIC(BIC_CPU_c7))
5806168c2e0SLen Brown 		outp += sprintf(outp, "%sCPU%%c7", (printed++ ? delim : ""));
581678a3bd1SLen Brown 
5820539ba11SLen Brown 	if (DO_BIC(BIC_Mod_c6))
5836168c2e0SLen Brown 		outp += sprintf(outp, "%sMod%%c6", (printed++ ? delim : ""));
584678a3bd1SLen Brown 
585812db3f7SLen Brown 	if (DO_BIC(BIC_CoreTmp))
5866168c2e0SLen Brown 		outp += sprintf(outp, "%sCoreTmp", (printed++ ? delim : ""));
587388e9c81SLen Brown 
588388e9c81SLen Brown 	for (mp = sys.cp; mp; mp = mp->next) {
589388e9c81SLen Brown 		if (mp->format == FORMAT_RAW) {
590388e9c81SLen Brown 			if (mp->width == 64)
591c8ade361SLen Brown 				outp += sprintf(outp, "%s%18.18s", delim, mp->name);
592388e9c81SLen Brown 			else
593c8ade361SLen Brown 				outp += sprintf(outp, "%s%10.10s", delim, mp->name);
594388e9c81SLen Brown 		} else {
5950de6c0dfSLen Brown 			if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns)
5960de6c0dfSLen Brown 				outp += sprintf(outp, "%s%8s", delim, mp->name);
5970de6c0dfSLen Brown 			else
598c8ade361SLen Brown 				outp += sprintf(outp, "%s%s", delim, mp->name);
599388e9c81SLen Brown 		}
600388e9c81SLen Brown 	}
601388e9c81SLen Brown 
602812db3f7SLen Brown 	if (DO_BIC(BIC_PkgTmp))
6036168c2e0SLen Brown 		outp += sprintf(outp, "%sPkgTmp", (printed++ ? delim : ""));
604889facbeSLen Brown 
605812db3f7SLen Brown 	if (DO_BIC(BIC_GFX_rc6))
6066168c2e0SLen Brown 		outp += sprintf(outp, "%sGFX%%rc6", (printed++ ? delim : ""));
607fdf676e5SLen Brown 
608812db3f7SLen Brown 	if (DO_BIC(BIC_GFXMHz))
6096168c2e0SLen Brown 		outp += sprintf(outp, "%sGFXMHz", (printed++ ? delim : ""));
61027d47356SLen Brown 
611*a99d8730SLen Brown 	if (DO_BIC(BIC_Totl_c0))
6126168c2e0SLen Brown 		outp += sprintf(outp, "%sTotl%%C0", (printed++ ? delim : ""));
613*a99d8730SLen Brown 	if (DO_BIC(BIC_Any_c0))
6146168c2e0SLen Brown 		outp += sprintf(outp, "%sAny%%C0", (printed++ ? delim : ""));
615*a99d8730SLen Brown 	if (DO_BIC(BIC_GFX_c0))
6166168c2e0SLen Brown 		outp += sprintf(outp, "%sGFX%%C0", (printed++ ? delim : ""));
617*a99d8730SLen Brown 	if (DO_BIC(BIC_CPUGFX))
6186168c2e0SLen Brown 		outp += sprintf(outp, "%sCPUGFX%%", (printed++ ? delim : ""));
6190b2bb692SLen Brown 
6200f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc2))
6216168c2e0SLen Brown 		outp += sprintf(outp, "%sPkg%%pc2", (printed++ ? delim : ""));
6220f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc3))
6236168c2e0SLen Brown 		outp += sprintf(outp, "%sPkg%%pc3", (printed++ ? delim : ""));
6240f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc6))
6256168c2e0SLen Brown 		outp += sprintf(outp, "%sPkg%%pc6", (printed++ ? delim : ""));
6260f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc7))
6276168c2e0SLen Brown 		outp += sprintf(outp, "%sPkg%%pc7", (printed++ ? delim : ""));
6280f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc8))
6296168c2e0SLen Brown 		outp += sprintf(outp, "%sPkg%%pc8", (printed++ ? delim : ""));
6300f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc9))
6316168c2e0SLen Brown 		outp += sprintf(outp, "%sPkg%%pc9", (printed++ ? delim : ""));
6320f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc10))
6336168c2e0SLen Brown 		outp += sprintf(outp, "%sPk%%pc10", (printed++ ? delim : ""));
634103a8feaSLen Brown 
6355c56be9aSDirk Brandewie 	if (do_rapl && !rapl_joules) {
636812db3f7SLen Brown 		if (DO_BIC(BIC_PkgWatt))
6376168c2e0SLen Brown 			outp += sprintf(outp, "%sPkgWatt", (printed++ ? delim : ""));
638812db3f7SLen Brown 		if (DO_BIC(BIC_CorWatt))
6396168c2e0SLen Brown 			outp += sprintf(outp, "%sCorWatt", (printed++ ? delim : ""));
640812db3f7SLen Brown 		if (DO_BIC(BIC_GFXWatt))
6416168c2e0SLen Brown 			outp += sprintf(outp, "%sGFXWatt", (printed++ ? delim : ""));
642812db3f7SLen Brown 		if (DO_BIC(BIC_RAMWatt))
6436168c2e0SLen Brown 			outp += sprintf(outp, "%sRAMWatt", (printed++ ? delim : ""));
644812db3f7SLen Brown 		if (DO_BIC(BIC_PKG__))
6456168c2e0SLen Brown 			outp += sprintf(outp, "%sPKG_%%", (printed++ ? delim : ""));
646812db3f7SLen Brown 		if (DO_BIC(BIC_RAM__))
6476168c2e0SLen Brown 			outp += sprintf(outp, "%sRAM_%%", (printed++ ? delim : ""));
648d7899447SLen Brown 	} else if (do_rapl && rapl_joules) {
649812db3f7SLen Brown 		if (DO_BIC(BIC_Pkg_J))
6506168c2e0SLen Brown 			outp += sprintf(outp, "%sPkg_J", (printed++ ? delim : ""));
651812db3f7SLen Brown 		if (DO_BIC(BIC_Cor_J))
6526168c2e0SLen Brown 			outp += sprintf(outp, "%sCor_J", (printed++ ? delim : ""));
653812db3f7SLen Brown 		if (DO_BIC(BIC_GFX_J))
6546168c2e0SLen Brown 			outp += sprintf(outp, "%sGFX_J", (printed++ ? delim : ""));
655812db3f7SLen Brown 		if (DO_BIC(BIC_RAM_J))
6566168c2e0SLen Brown 			outp += sprintf(outp, "%sRAM_J", (printed++ ? delim : ""));
657812db3f7SLen Brown 		if (DO_BIC(BIC_PKG__))
6586168c2e0SLen Brown 			outp += sprintf(outp, "%sPKG_%%", (printed++ ? delim : ""));
659812db3f7SLen Brown 		if (DO_BIC(BIC_RAM__))
6606168c2e0SLen Brown 			outp += sprintf(outp, "%sRAM_%%", (printed++ ? delim : ""));
6615c56be9aSDirk Brandewie 	}
662388e9c81SLen Brown 	for (mp = sys.pp; mp; mp = mp->next) {
663388e9c81SLen Brown 		if (mp->format == FORMAT_RAW) {
664388e9c81SLen Brown 			if (mp->width == 64)
665c8ade361SLen Brown 				outp += sprintf(outp, "%s%18.18s", delim, mp->name);
666388e9c81SLen Brown 			else
667c8ade361SLen Brown 				outp += sprintf(outp, "%s%10.10s", delim, mp->name);
668388e9c81SLen Brown 		} else {
6690de6c0dfSLen Brown 			if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns)
6700de6c0dfSLen Brown 				outp += sprintf(outp, "%s%8s", delim, mp->name);
6710de6c0dfSLen Brown 			else
672c8ade361SLen Brown 				outp += sprintf(outp, "%s%s", delim, mp->name);
673388e9c81SLen Brown 		}
674388e9c81SLen Brown 	}
675388e9c81SLen Brown 
676c98d5d94SLen Brown 	outp += sprintf(outp, "\n");
677103a8feaSLen Brown }
678103a8feaSLen Brown 
679c98d5d94SLen Brown int dump_counters(struct thread_data *t, struct core_data *c,
680c98d5d94SLen Brown 	struct pkg_data *p)
681103a8feaSLen Brown {
682388e9c81SLen Brown 	int i;
683388e9c81SLen Brown 	struct msr_counter *mp;
684388e9c81SLen Brown 
6853b4d5c7fSAndy Shevchenko 	outp += sprintf(outp, "t %p, c %p, p %p\n", t, c, p);
686c98d5d94SLen Brown 
687c98d5d94SLen Brown 	if (t) {
6883b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "CPU: %d flags 0x%x\n",
6893b4d5c7fSAndy Shevchenko 			t->cpu_id, t->flags);
6903b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "TSC: %016llX\n", t->tsc);
6913b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "aperf: %016llX\n", t->aperf);
6923b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "mperf: %016llX\n", t->mperf);
6933b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "c1: %016llX\n", t->c1);
6946886fee4SLen Brown 
695812db3f7SLen Brown 		if (DO_BIC(BIC_IRQ))
6960de6c0dfSLen Brown 			outp += sprintf(outp, "IRQ: %lld\n", t->irq_count);
697812db3f7SLen Brown 		if (DO_BIC(BIC_SMI))
698218f0e8dSLen Brown 			outp += sprintf(outp, "SMI: %d\n", t->smi_count);
699388e9c81SLen Brown 
700388e9c81SLen Brown 		for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
701388e9c81SLen Brown 			outp += sprintf(outp, "tADDED [%d] msr0x%x: %08llX\n",
702388e9c81SLen Brown 				i, mp->msr_num, t->counter[i]);
703388e9c81SLen Brown 		}
704103a8feaSLen Brown 	}
705103a8feaSLen Brown 
706c98d5d94SLen Brown 	if (c) {
7073b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "core: %d\n", c->core_id);
7083b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "c3: %016llX\n", c->c3);
7093b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "c6: %016llX\n", c->c6);
7103b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "c7: %016llX\n", c->c7);
7113b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "DTS: %dC\n", c->core_temp_c);
712388e9c81SLen Brown 
713388e9c81SLen Brown 		for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
714388e9c81SLen Brown 			outp += sprintf(outp, "cADDED [%d] msr0x%x: %08llX\n",
715388e9c81SLen Brown 				i, mp->msr_num, c->counter[i]);
716388e9c81SLen Brown 		}
7170539ba11SLen Brown 		outp += sprintf(outp, "mc6_us: %016llX\n", c->mc6_us);
718c98d5d94SLen Brown 	}
719103a8feaSLen Brown 
720c98d5d94SLen Brown 	if (p) {
7213b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "package: %d\n", p->package_id);
7220b2bb692SLen Brown 
7230b2bb692SLen Brown 		outp += sprintf(outp, "Weighted cores: %016llX\n", p->pkg_wtd_core_c0);
7240b2bb692SLen Brown 		outp += sprintf(outp, "Any cores: %016llX\n", p->pkg_any_core_c0);
7250b2bb692SLen Brown 		outp += sprintf(outp, "Any GFX: %016llX\n", p->pkg_any_gfxe_c0);
7260b2bb692SLen Brown 		outp += sprintf(outp, "CPU + GFX: %016llX\n", p->pkg_both_core_gfxe_c0);
7270b2bb692SLen Brown 
7283b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "pc2: %016llX\n", p->pc2);
7290f47c08dSLen Brown 		if (DO_BIC(BIC_Pkgpc3))
7303b4d5c7fSAndy Shevchenko 			outp += sprintf(outp, "pc3: %016llX\n", p->pc3);
7310f47c08dSLen Brown 		if (DO_BIC(BIC_Pkgpc6))
7323b4d5c7fSAndy Shevchenko 			outp += sprintf(outp, "pc6: %016llX\n", p->pc6);
7330f47c08dSLen Brown 		if (DO_BIC(BIC_Pkgpc7))
7343b4d5c7fSAndy Shevchenko 			outp += sprintf(outp, "pc7: %016llX\n", p->pc7);
7353b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "pc8: %016llX\n", p->pc8);
7363b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "pc9: %016llX\n", p->pc9);
7373b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "pc10: %016llX\n", p->pc10);
7383b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "Joules PKG: %0X\n", p->energy_pkg);
7393b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "Joules COR: %0X\n", p->energy_cores);
7403b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "Joules GFX: %0X\n", p->energy_gfx);
7413b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "Joules RAM: %0X\n", p->energy_dram);
7423b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "Throttle PKG: %0X\n",
7433b4d5c7fSAndy Shevchenko 			p->rapl_pkg_perf_status);
7443b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "Throttle RAM: %0X\n",
7453b4d5c7fSAndy Shevchenko 			p->rapl_dram_perf_status);
7463b4d5c7fSAndy Shevchenko 		outp += sprintf(outp, "PTM: %dC\n", p->pkg_temp_c);
747388e9c81SLen Brown 
748388e9c81SLen Brown 		for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
749388e9c81SLen Brown 			outp += sprintf(outp, "pADDED [%d] msr0x%x: %08llX\n",
750388e9c81SLen Brown 				i, mp->msr_num, p->counter[i]);
751388e9c81SLen Brown 		}
752c98d5d94SLen Brown 	}
7533b4d5c7fSAndy Shevchenko 
7543b4d5c7fSAndy Shevchenko 	outp += sprintf(outp, "\n");
7553b4d5c7fSAndy Shevchenko 
756c98d5d94SLen Brown 	return 0;
757103a8feaSLen Brown }
758103a8feaSLen Brown 
759e23da037SLen Brown /*
760e23da037SLen Brown  * column formatting convention & formats
761e23da037SLen Brown  */
762c98d5d94SLen Brown int format_counters(struct thread_data *t, struct core_data *c,
763c98d5d94SLen Brown 	struct pkg_data *p)
764103a8feaSLen Brown {
765008d396eSLen Brown 	double interval_float, tsc;
766fc04cc67SLen Brown 	char *fmt8;
767388e9c81SLen Brown 	int i;
768388e9c81SLen Brown 	struct msr_counter *mp;
7696168c2e0SLen Brown 	char *delim = "\t";
7706168c2e0SLen Brown 	int printed = 0;
771103a8feaSLen Brown 
772c98d5d94SLen Brown 	 /* if showing only 1st thread in core and this isn't one, bail out */
773c98d5d94SLen Brown 	if (show_core_only && !(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
774c98d5d94SLen Brown 		return 0;
775c98d5d94SLen Brown 
776c98d5d94SLen Brown 	 /* if showing only 1st thread in pkg and this isn't one, bail out */
777c98d5d94SLen Brown 	if (show_pkg_only && !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
778c98d5d94SLen Brown 		return 0;
779c98d5d94SLen Brown 
7801ef7d21aSLen Brown 	/*if not summary line and --cpu is used */
7811ef7d21aSLen Brown 	if ((t != &average.threads) &&
7821ef7d21aSLen Brown 		(cpu_subset && !CPU_ISSET_S(t->cpu_id, cpu_subset_size, cpu_subset)))
7831ef7d21aSLen Brown 		return 0;
7841ef7d21aSLen Brown 
785103a8feaSLen Brown 	interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;
786103a8feaSLen Brown 
787008d396eSLen Brown 	tsc = t->tsc * tsc_tweak;
788008d396eSLen Brown 
789c98d5d94SLen Brown 	/* topo columns, print blanks on 1st (average) line */
790c98d5d94SLen Brown 	if (t == &average.threads) {
791812db3f7SLen Brown 		if (DO_BIC(BIC_Package))
7926168c2e0SLen Brown 			outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
793812db3f7SLen Brown 		if (DO_BIC(BIC_Core))
7946168c2e0SLen Brown 			outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
795812db3f7SLen Brown 		if (DO_BIC(BIC_CPU))
7966168c2e0SLen Brown 			outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
797103a8feaSLen Brown 	} else {
798812db3f7SLen Brown 		if (DO_BIC(BIC_Package)) {
799c98d5d94SLen Brown 			if (p)
8006168c2e0SLen Brown 				outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->package_id);
801c98d5d94SLen Brown 			else
8026168c2e0SLen Brown 				outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
803c98d5d94SLen Brown 		}
804812db3f7SLen Brown 		if (DO_BIC(BIC_Core)) {
805c98d5d94SLen Brown 			if (c)
8066168c2e0SLen Brown 				outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), c->core_id);
807c98d5d94SLen Brown 			else
8086168c2e0SLen Brown 				outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
809c98d5d94SLen Brown 		}
810812db3f7SLen Brown 		if (DO_BIC(BIC_CPU))
8116168c2e0SLen Brown 			outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->cpu_id);
812103a8feaSLen Brown 	}
813fc04cc67SLen Brown 
814812db3f7SLen Brown 	if (DO_BIC(BIC_Avg_MHz))
8156168c2e0SLen Brown 		outp += sprintf(outp, "%s%.0f", (printed++ ? delim : ""),
816fc04cc67SLen Brown 			1.0 / units * t->aperf / interval_float);
817fc04cc67SLen Brown 
818812db3f7SLen Brown 	if (DO_BIC(BIC_Busy))
8196168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * t->mperf/tsc);
820103a8feaSLen Brown 
821812db3f7SLen Brown 	if (DO_BIC(BIC_Bzy_MHz)) {
82221ed5574SLen Brown 		if (has_base_hz)
8236168c2e0SLen Brown 			outp += sprintf(outp, "%s%.0f", (printed++ ? delim : ""), base_hz / units * t->aperf / t->mperf);
82421ed5574SLen Brown 		else
8256168c2e0SLen Brown 			outp += sprintf(outp, "%s%.0f", (printed++ ? delim : ""),
826008d396eSLen Brown 				tsc / units * t->aperf / t->mperf / interval_float);
82721ed5574SLen Brown 	}
828103a8feaSLen Brown 
829812db3f7SLen Brown 	if (DO_BIC(BIC_TSC_MHz))
8306168c2e0SLen Brown 		outp += sprintf(outp, "%s%.0f", (printed++ ? delim : ""), 1.0 * t->tsc/units/interval_float);
831103a8feaSLen Brown 
832562a2d37SLen Brown 	/* IRQ */
8330de6c0dfSLen Brown 	if (DO_BIC(BIC_IRQ)) {
8340de6c0dfSLen Brown 		if (sums_need_wide_columns)
8356168c2e0SLen Brown 			outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), t->irq_count);
8360de6c0dfSLen Brown 		else
8376168c2e0SLen Brown 			outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), t->irq_count);
8380de6c0dfSLen Brown 	}
839562a2d37SLen Brown 
8401cc21f7bSLen Brown 	/* SMI */
841812db3f7SLen Brown 	if (DO_BIC(BIC_SMI))
8426168c2e0SLen Brown 		outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->smi_count);
8431cc21f7bSLen Brown 
844678a3bd1SLen Brown 	/* Added counters */
845678a3bd1SLen Brown 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
846678a3bd1SLen Brown 		if (mp->format == FORMAT_RAW) {
847678a3bd1SLen Brown 			if (mp->width == 32)
8485f3aea57SLen Brown 				outp += sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int) t->counter[i]);
849678a3bd1SLen Brown 			else
8506168c2e0SLen Brown 				outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), t->counter[i]);
851678a3bd1SLen Brown 		} else if (mp->format == FORMAT_DELTA) {
8520de6c0dfSLen Brown 			if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns)
8536168c2e0SLen Brown 				outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), t->counter[i]);
8540de6c0dfSLen Brown 			else
8556168c2e0SLen Brown 				outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), t->counter[i]);
856678a3bd1SLen Brown 		} else if (mp->format == FORMAT_PERCENT) {
85741618e63SLen Brown 			if (mp->type == COUNTER_USEC)
8586168c2e0SLen Brown 				outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), t->counter[i]/interval_float/10000);
85941618e63SLen Brown 			else
8606168c2e0SLen Brown 				outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * t->counter[i]/tsc);
861678a3bd1SLen Brown 		}
862678a3bd1SLen Brown 	}
863678a3bd1SLen Brown 
86441618e63SLen Brown 	/* C1 */
86541618e63SLen Brown 	if (DO_BIC(BIC_CPU_c1))
8666168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * t->c1/tsc);
86741618e63SLen Brown 
86841618e63SLen Brown 
869c98d5d94SLen Brown 	/* print per-core data only for 1st thread in core */
870c98d5d94SLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
871c98d5d94SLen Brown 		goto done;
872c98d5d94SLen Brown 
873812db3f7SLen Brown 	if (DO_BIC(BIC_CPU_c3) && !do_slm_cstates && !do_knl_cstates)
8746168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->c3/tsc);
875812db3f7SLen Brown 	if (DO_BIC(BIC_CPU_c6))
8766168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->c6/tsc);
877812db3f7SLen Brown 	if (DO_BIC(BIC_CPU_c7))
8786168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->c7/tsc);
879c98d5d94SLen Brown 
8800539ba11SLen Brown 	/* Mod%c6 */
8810539ba11SLen Brown 	if (DO_BIC(BIC_Mod_c6))
8826168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->mc6_us / tsc);
8830539ba11SLen Brown 
884812db3f7SLen Brown 	if (DO_BIC(BIC_CoreTmp))
8856168c2e0SLen Brown 		outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), c->core_temp_c);
886889facbeSLen Brown 
887388e9c81SLen Brown 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
888388e9c81SLen Brown 		if (mp->format == FORMAT_RAW) {
889388e9c81SLen Brown 			if (mp->width == 32)
8905f3aea57SLen Brown 				outp += sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int) c->counter[i]);
891388e9c81SLen Brown 			else
8926168c2e0SLen Brown 				outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), c->counter[i]);
893388e9c81SLen Brown 		} else if (mp->format == FORMAT_DELTA) {
8940de6c0dfSLen Brown 			if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns)
8956168c2e0SLen Brown 				outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), c->counter[i]);
8960de6c0dfSLen Brown 			else
8976168c2e0SLen Brown 				outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), c->counter[i]);
898388e9c81SLen Brown 		} else if (mp->format == FORMAT_PERCENT) {
8996168c2e0SLen Brown 			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->counter[i]/tsc);
900388e9c81SLen Brown 		}
901388e9c81SLen Brown 	}
902388e9c81SLen Brown 
903c98d5d94SLen Brown 	/* print per-package data only for 1st core in package */
904c98d5d94SLen Brown 	if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
905c98d5d94SLen Brown 		goto done;
906c98d5d94SLen Brown 
9070b2bb692SLen Brown 	/* PkgTmp */
908812db3f7SLen Brown 	if (DO_BIC(BIC_PkgTmp))
9096168c2e0SLen Brown 		outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->pkg_temp_c);
910889facbeSLen Brown 
911fdf676e5SLen Brown 	/* GFXrc6 */
912812db3f7SLen Brown 	if (DO_BIC(BIC_GFX_rc6)) {
913ba3dec99SLen Brown 		if (p->gfx_rc6_ms == -1) {	/* detect GFX counter reset */
9146168c2e0SLen Brown 			outp += sprintf(outp, "%s**.**", (printed++ ? delim : ""));
9159185e988SLen Brown 		} else {
9166168c2e0SLen Brown 			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""),
9179185e988SLen Brown 				p->gfx_rc6_ms / 10.0 / interval_float);
9189185e988SLen Brown 		}
9199185e988SLen Brown 	}
920fdf676e5SLen Brown 
92127d47356SLen Brown 	/* GFXMHz */
922812db3f7SLen Brown 	if (DO_BIC(BIC_GFXMHz))
9236168c2e0SLen Brown 		outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->gfx_mhz);
92427d47356SLen Brown 
9250b2bb692SLen Brown 	/* Totl%C0, Any%C0 GFX%C0 CPUGFX% */
926*a99d8730SLen Brown 	if (DO_BIC(BIC_Totl_c0))
9276168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_wtd_core_c0/tsc);
928*a99d8730SLen Brown 	if (DO_BIC(BIC_Any_c0))
9296168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_any_core_c0/tsc);
930*a99d8730SLen Brown 	if (DO_BIC(BIC_GFX_c0))
9316168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_any_gfxe_c0/tsc);
932*a99d8730SLen Brown 	if (DO_BIC(BIC_CPUGFX))
9336168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_both_core_gfxe_c0/tsc);
9340b2bb692SLen Brown 
9350f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc2))
9366168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc2/tsc);
9370f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc3))
9386168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc3/tsc);
9390f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc6))
9406168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc6/tsc);
9410f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc7))
9426168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc7/tsc);
9430f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc8))
9446168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc8/tsc);
9450f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc9))
9466168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc9/tsc);
9470f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc10))
9486168c2e0SLen Brown 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc10/tsc);
949889facbeSLen Brown 
950889facbeSLen Brown 	/*
951889facbeSLen Brown  	 * If measurement interval exceeds minimum RAPL Joule Counter range,
952889facbeSLen Brown  	 * indicate that results are suspect by printing "**" in fraction place.
953889facbeSLen Brown  	 */
954fc04cc67SLen Brown 	if (interval_float < rapl_joule_counter_range)
9556168c2e0SLen Brown 		fmt8 = "%s%.2f";
956fc04cc67SLen Brown 	else
957fc04cc67SLen Brown 		fmt8 = "%6.0f**";
958889facbeSLen Brown 
959812db3f7SLen Brown 	if (DO_BIC(BIC_PkgWatt))
9606168c2e0SLen Brown 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_pkg * rapl_energy_units / interval_float);
961812db3f7SLen Brown 	if (DO_BIC(BIC_CorWatt))
9626168c2e0SLen Brown 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_cores * rapl_energy_units / interval_float);
963812db3f7SLen Brown 	if (DO_BIC(BIC_GFXWatt))
9646168c2e0SLen Brown 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_gfx * rapl_energy_units / interval_float);
965812db3f7SLen Brown 	if (DO_BIC(BIC_RAMWatt))
9666168c2e0SLen Brown 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_dram * rapl_dram_energy_units / interval_float);
967812db3f7SLen Brown 	if (DO_BIC(BIC_Pkg_J))
9686168c2e0SLen Brown 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_pkg * rapl_energy_units);
969812db3f7SLen Brown 	if (DO_BIC(BIC_Cor_J))
9706168c2e0SLen Brown 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_cores * rapl_energy_units);
971812db3f7SLen Brown 	if (DO_BIC(BIC_GFX_J))
9726168c2e0SLen Brown 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_gfx * rapl_energy_units);
973812db3f7SLen Brown 	if (DO_BIC(BIC_RAM_J))
9746168c2e0SLen Brown 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_dram * rapl_dram_energy_units);
975812db3f7SLen Brown 	if (DO_BIC(BIC_PKG__))
9766168c2e0SLen Brown 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float);
977812db3f7SLen Brown 	if (DO_BIC(BIC_RAM__))
9786168c2e0SLen Brown 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float);
979812db3f7SLen Brown 
980388e9c81SLen Brown 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
981388e9c81SLen Brown 		if (mp->format == FORMAT_RAW) {
982388e9c81SLen Brown 			if (mp->width == 32)
9835f3aea57SLen Brown 				outp += sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int) p->counter[i]);
984388e9c81SLen Brown 			else
9856168c2e0SLen Brown 				outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), p->counter[i]);
986388e9c81SLen Brown 		} else if (mp->format == FORMAT_DELTA) {
9870de6c0dfSLen Brown 			if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns)
9886168c2e0SLen Brown 				outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), p->counter[i]);
9890de6c0dfSLen Brown 			else
9906168c2e0SLen Brown 				outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), p->counter[i]);
991388e9c81SLen Brown 		} else if (mp->format == FORMAT_PERCENT) {
9926168c2e0SLen Brown 			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->counter[i]/tsc);
993388e9c81SLen Brown 		}
994388e9c81SLen Brown 	}
995388e9c81SLen Brown 
996c98d5d94SLen Brown done:
997c98d5d94SLen Brown 	outp += sprintf(outp, "\n");
998c98d5d94SLen Brown 
999c98d5d94SLen Brown 	return 0;
1000103a8feaSLen Brown }
1001103a8feaSLen Brown 
1002b7d8c148SLen Brown void flush_output_stdout(void)
1003103a8feaSLen Brown {
1004b7d8c148SLen Brown 	FILE *filep;
1005b7d8c148SLen Brown 
1006b7d8c148SLen Brown 	if (outf == stderr)
1007b7d8c148SLen Brown 		filep = stdout;
1008b7d8c148SLen Brown 	else
1009b7d8c148SLen Brown 		filep = outf;
1010b7d8c148SLen Brown 
1011b7d8c148SLen Brown 	fputs(output_buffer, filep);
1012b7d8c148SLen Brown 	fflush(filep);
1013b7d8c148SLen Brown 
1014c98d5d94SLen Brown 	outp = output_buffer;
1015c98d5d94SLen Brown }
1016b7d8c148SLen Brown void flush_output_stderr(void)
1017c98d5d94SLen Brown {
1018b7d8c148SLen Brown 	fputs(output_buffer, outf);
1019b7d8c148SLen Brown 	fflush(outf);
1020c98d5d94SLen Brown 	outp = output_buffer;
1021c98d5d94SLen Brown }
1022c98d5d94SLen Brown void format_all_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1023c98d5d94SLen Brown {
1024e23da037SLen Brown 	static int printed;
1025103a8feaSLen Brown 
1026e23da037SLen Brown 	if (!printed || !summary_only)
1027c8ade361SLen Brown 		print_header("\t");
1028103a8feaSLen Brown 
1029c98d5d94SLen Brown 	if (topo.num_cpus > 1)
1030c98d5d94SLen Brown 		format_counters(&average.threads, &average.cores,
1031c98d5d94SLen Brown 			&average.packages);
1032103a8feaSLen Brown 
1033e23da037SLen Brown 	printed = 1;
1034e23da037SLen Brown 
1035e23da037SLen Brown 	if (summary_only)
1036e23da037SLen Brown 		return;
1037e23da037SLen Brown 
1038c98d5d94SLen Brown 	for_all_cpus(format_counters, t, c, p);
1039103a8feaSLen Brown }
1040103a8feaSLen Brown 
1041889facbeSLen Brown #define DELTA_WRAP32(new, old)			\
1042889facbeSLen Brown 	if (new > old) {			\
1043889facbeSLen Brown 		old = new - old;		\
1044889facbeSLen Brown 	} else {				\
1045889facbeSLen Brown 		old = 0x100000000 + new - old;	\
1046889facbeSLen Brown 	}
1047889facbeSLen Brown 
1048ba3dec99SLen Brown int
1049c98d5d94SLen Brown delta_package(struct pkg_data *new, struct pkg_data *old)
1050103a8feaSLen Brown {
1051388e9c81SLen Brown 	int i;
1052388e9c81SLen Brown 	struct msr_counter *mp;
10530b2bb692SLen Brown 
1054*a99d8730SLen Brown 
1055*a99d8730SLen Brown 	if (DO_BIC(BIC_Totl_c0))
10560b2bb692SLen Brown 		old->pkg_wtd_core_c0 = new->pkg_wtd_core_c0 - old->pkg_wtd_core_c0;
1057*a99d8730SLen Brown 	if (DO_BIC(BIC_Any_c0))
10580b2bb692SLen Brown 		old->pkg_any_core_c0 = new->pkg_any_core_c0 - old->pkg_any_core_c0;
1059*a99d8730SLen Brown 	if (DO_BIC(BIC_GFX_c0))
10600b2bb692SLen Brown 		old->pkg_any_gfxe_c0 = new->pkg_any_gfxe_c0 - old->pkg_any_gfxe_c0;
1061*a99d8730SLen Brown 	if (DO_BIC(BIC_CPUGFX))
10620b2bb692SLen Brown 		old->pkg_both_core_gfxe_c0 = new->pkg_both_core_gfxe_c0 - old->pkg_both_core_gfxe_c0;
1063*a99d8730SLen Brown 
1064c98d5d94SLen Brown 	old->pc2 = new->pc2 - old->pc2;
10650f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc3))
1066c98d5d94SLen Brown 		old->pc3 = new->pc3 - old->pc3;
10670f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc6))
1068c98d5d94SLen Brown 		old->pc6 = new->pc6 - old->pc6;
10690f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc7))
1070c98d5d94SLen Brown 		old->pc7 = new->pc7 - old->pc7;
1071ca58710fSKristen Carlson Accardi 	old->pc8 = new->pc8 - old->pc8;
1072ca58710fSKristen Carlson Accardi 	old->pc9 = new->pc9 - old->pc9;
1073ca58710fSKristen Carlson Accardi 	old->pc10 = new->pc10 - old->pc10;
1074889facbeSLen Brown 	old->pkg_temp_c = new->pkg_temp_c;
1075889facbeSLen Brown 
10769185e988SLen Brown 	/* flag an error when rc6 counter resets/wraps */
10779185e988SLen Brown 	if (old->gfx_rc6_ms >  new->gfx_rc6_ms)
10789185e988SLen Brown 		old->gfx_rc6_ms = -1;
10799185e988SLen Brown 	else
1080fdf676e5SLen Brown 		old->gfx_rc6_ms = new->gfx_rc6_ms - old->gfx_rc6_ms;
10819185e988SLen Brown 
108227d47356SLen Brown 	old->gfx_mhz = new->gfx_mhz;
108327d47356SLen Brown 
1084889facbeSLen Brown 	DELTA_WRAP32(new->energy_pkg, old->energy_pkg);
1085889facbeSLen Brown 	DELTA_WRAP32(new->energy_cores, old->energy_cores);
1086889facbeSLen Brown 	DELTA_WRAP32(new->energy_gfx, old->energy_gfx);
1087889facbeSLen Brown 	DELTA_WRAP32(new->energy_dram, old->energy_dram);
1088889facbeSLen Brown 	DELTA_WRAP32(new->rapl_pkg_perf_status, old->rapl_pkg_perf_status);
1089889facbeSLen Brown 	DELTA_WRAP32(new->rapl_dram_perf_status, old->rapl_dram_perf_status);
1090ba3dec99SLen Brown 
1091388e9c81SLen Brown 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
1092388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1093388e9c81SLen Brown 			old->counter[i] = new->counter[i];
1094388e9c81SLen Brown 		else
1095388e9c81SLen Brown 			old->counter[i] = new->counter[i] - old->counter[i];
1096388e9c81SLen Brown 	}
1097388e9c81SLen Brown 
1098ba3dec99SLen Brown 	return 0;
1099103a8feaSLen Brown }
1100103a8feaSLen Brown 
1101c98d5d94SLen Brown void
1102c98d5d94SLen Brown delta_core(struct core_data *new, struct core_data *old)
1103c98d5d94SLen Brown {
1104388e9c81SLen Brown 	int i;
1105388e9c81SLen Brown 	struct msr_counter *mp;
1106388e9c81SLen Brown 
1107c98d5d94SLen Brown 	old->c3 = new->c3 - old->c3;
1108c98d5d94SLen Brown 	old->c6 = new->c6 - old->c6;
1109c98d5d94SLen Brown 	old->c7 = new->c7 - old->c7;
1110889facbeSLen Brown 	old->core_temp_c = new->core_temp_c;
11110539ba11SLen Brown 	old->mc6_us = new->mc6_us - old->mc6_us;
1112388e9c81SLen Brown 
1113388e9c81SLen Brown 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
1114388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1115388e9c81SLen Brown 			old->counter[i] = new->counter[i];
1116388e9c81SLen Brown 		else
1117388e9c81SLen Brown 			old->counter[i] = new->counter[i] - old->counter[i];
1118388e9c81SLen Brown 	}
1119103a8feaSLen Brown }
1120c98d5d94SLen Brown 
1121c3ae331dSLen Brown /*
1122c3ae331dSLen Brown  * old = new - old
1123c3ae331dSLen Brown  */
1124ba3dec99SLen Brown int
1125c98d5d94SLen Brown delta_thread(struct thread_data *new, struct thread_data *old,
1126c98d5d94SLen Brown 	struct core_data *core_delta)
1127c98d5d94SLen Brown {
1128388e9c81SLen Brown 	int i;
1129388e9c81SLen Brown 	struct msr_counter *mp;
1130388e9c81SLen Brown 
1131c98d5d94SLen Brown 	old->tsc = new->tsc - old->tsc;
1132c98d5d94SLen Brown 
1133103a8feaSLen Brown 	/* check for TSC < 1 Mcycles over interval */
1134b2c95d90SJosh Triplett 	if (old->tsc < (1000 * 1000))
1135b2c95d90SJosh Triplett 		errx(-3, "Insanely slow TSC rate, TSC stops in idle?\n"
1136b2c95d90SJosh Triplett 		     "You can disable all c-states by booting with \"idle=poll\"\n"
1137b2c95d90SJosh Triplett 		     "or just the deep ones with \"processor.max_cstate=1\"");
1138103a8feaSLen Brown 
1139c98d5d94SLen Brown 	old->c1 = new->c1 - old->c1;
1140c98d5d94SLen Brown 
1141812db3f7SLen Brown 	if (DO_BIC(BIC_Avg_MHz) || DO_BIC(BIC_Busy) || DO_BIC(BIC_Bzy_MHz)) {
1142c98d5d94SLen Brown 		if ((new->aperf > old->aperf) && (new->mperf > old->mperf)) {
1143c98d5d94SLen Brown 			old->aperf = new->aperf - old->aperf;
1144c98d5d94SLen Brown 			old->mperf = new->mperf - old->mperf;
1145c98d5d94SLen Brown 		} else {
1146ba3dec99SLen Brown 			return -1;
1147103a8feaSLen Brown 		}
1148a729617cSLen Brown 	}
1149103a8feaSLen Brown 
1150c98d5d94SLen Brown 
1151144b44b1SLen Brown 	if (use_c1_residency_msr) {
1152144b44b1SLen Brown 		/*
1153144b44b1SLen Brown 		 * Some models have a dedicated C1 residency MSR,
1154144b44b1SLen Brown 		 * which should be more accurate than the derivation below.
1155144b44b1SLen Brown 		 */
1156144b44b1SLen Brown 	} else {
1157103a8feaSLen Brown 		/*
1158c3ae331dSLen Brown 		 * As counter collection is not atomic,
1159c3ae331dSLen Brown 		 * it is possible for mperf's non-halted cycles + idle states
1160103a8feaSLen Brown 		 * to exceed TSC's all cycles: show c1 = 0% in that case.
1161103a8feaSLen Brown 		 */
116295149369SLen Brown 		if ((old->mperf + core_delta->c3 + core_delta->c6 + core_delta->c7) > (old->tsc * tsc_tweak))
1163c98d5d94SLen Brown 			old->c1 = 0;
1164c98d5d94SLen Brown 		else {
1165c98d5d94SLen Brown 			/* normal case, derive c1 */
1166008d396eSLen Brown 			old->c1 = (old->tsc * tsc_tweak) - old->mperf - core_delta->c3
1167c98d5d94SLen Brown 				- core_delta->c6 - core_delta->c7;
1168c98d5d94SLen Brown 		}
1169144b44b1SLen Brown 	}
1170c3ae331dSLen Brown 
1171c98d5d94SLen Brown 	if (old->mperf == 0) {
1172b7d8c148SLen Brown 		if (debug > 1)
1173b7d8c148SLen Brown 			fprintf(outf, "cpu%d MPERF 0!\n", old->cpu_id);
1174c98d5d94SLen Brown 		old->mperf = 1;	/* divide by 0 protection */
1175c98d5d94SLen Brown 	}
1176103a8feaSLen Brown 
1177812db3f7SLen Brown 	if (DO_BIC(BIC_IRQ))
1178562a2d37SLen Brown 		old->irq_count = new->irq_count - old->irq_count;
1179562a2d37SLen Brown 
1180812db3f7SLen Brown 	if (DO_BIC(BIC_SMI))
11811ed51011SLen Brown 		old->smi_count = new->smi_count - old->smi_count;
1182ba3dec99SLen Brown 
1183388e9c81SLen Brown 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
1184388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1185388e9c81SLen Brown 			old->counter[i] = new->counter[i];
1186388e9c81SLen Brown 		else
1187388e9c81SLen Brown 			old->counter[i] = new->counter[i] - old->counter[i];
1188388e9c81SLen Brown 	}
1189ba3dec99SLen Brown 	return 0;
1190103a8feaSLen Brown }
1191c98d5d94SLen Brown 
1192c98d5d94SLen Brown int delta_cpu(struct thread_data *t, struct core_data *c,
1193c98d5d94SLen Brown 	struct pkg_data *p, struct thread_data *t2,
1194c98d5d94SLen Brown 	struct core_data *c2, struct pkg_data *p2)
1195c98d5d94SLen Brown {
1196ba3dec99SLen Brown 	int retval = 0;
1197ba3dec99SLen Brown 
1198c98d5d94SLen Brown 	/* calculate core delta only for 1st thread in core */
1199c98d5d94SLen Brown 	if (t->flags & CPU_IS_FIRST_THREAD_IN_CORE)
1200c98d5d94SLen Brown 		delta_core(c, c2);
1201c98d5d94SLen Brown 
1202c98d5d94SLen Brown 	/* always calculate thread delta */
1203ba3dec99SLen Brown 	retval = delta_thread(t, t2, c2);	/* c2 is core delta */
1204ba3dec99SLen Brown 	if (retval)
1205ba3dec99SLen Brown 		return retval;
1206c98d5d94SLen Brown 
1207c98d5d94SLen Brown 	/* calculate package delta only for 1st core in package */
1208c98d5d94SLen Brown 	if (t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)
1209ba3dec99SLen Brown 		retval = delta_package(p, p2);
1210c98d5d94SLen Brown 
1211ba3dec99SLen Brown 	return retval;
1212103a8feaSLen Brown }
1213103a8feaSLen Brown 
1214c98d5d94SLen Brown void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1215103a8feaSLen Brown {
1216388e9c81SLen Brown 	int i;
1217388e9c81SLen Brown 	struct msr_counter  *mp;
1218388e9c81SLen Brown 
1219c98d5d94SLen Brown 	t->tsc = 0;
1220c98d5d94SLen Brown 	t->aperf = 0;
1221c98d5d94SLen Brown 	t->mperf = 0;
1222c98d5d94SLen Brown 	t->c1 = 0;
1223103a8feaSLen Brown 
1224562a2d37SLen Brown 	t->irq_count = 0;
1225562a2d37SLen Brown 	t->smi_count = 0;
1226562a2d37SLen Brown 
1227c98d5d94SLen Brown 	/* tells format_counters to dump all fields from this set */
1228c98d5d94SLen Brown 	t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE;
1229c98d5d94SLen Brown 
1230c98d5d94SLen Brown 	c->c3 = 0;
1231c98d5d94SLen Brown 	c->c6 = 0;
1232c98d5d94SLen Brown 	c->c7 = 0;
12330539ba11SLen Brown 	c->mc6_us = 0;
1234889facbeSLen Brown 	c->core_temp_c = 0;
1235c98d5d94SLen Brown 
12360b2bb692SLen Brown 	p->pkg_wtd_core_c0 = 0;
12370b2bb692SLen Brown 	p->pkg_any_core_c0 = 0;
12380b2bb692SLen Brown 	p->pkg_any_gfxe_c0 = 0;
12390b2bb692SLen Brown 	p->pkg_both_core_gfxe_c0 = 0;
12400b2bb692SLen Brown 
1241c98d5d94SLen Brown 	p->pc2 = 0;
12420f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc3))
1243c98d5d94SLen Brown 		p->pc3 = 0;
12440f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc6))
1245c98d5d94SLen Brown 		p->pc6 = 0;
12460f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc7))
1247c98d5d94SLen Brown 		p->pc7 = 0;
1248ca58710fSKristen Carlson Accardi 	p->pc8 = 0;
1249ca58710fSKristen Carlson Accardi 	p->pc9 = 0;
1250ca58710fSKristen Carlson Accardi 	p->pc10 = 0;
1251889facbeSLen Brown 
1252889facbeSLen Brown 	p->energy_pkg = 0;
1253889facbeSLen Brown 	p->energy_dram = 0;
1254889facbeSLen Brown 	p->energy_cores = 0;
1255889facbeSLen Brown 	p->energy_gfx = 0;
1256889facbeSLen Brown 	p->rapl_pkg_perf_status = 0;
1257889facbeSLen Brown 	p->rapl_dram_perf_status = 0;
1258889facbeSLen Brown 	p->pkg_temp_c = 0;
125927d47356SLen Brown 
1260fdf676e5SLen Brown 	p->gfx_rc6_ms = 0;
126127d47356SLen Brown 	p->gfx_mhz = 0;
1262388e9c81SLen Brown 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next)
1263388e9c81SLen Brown 		t->counter[i] = 0;
1264388e9c81SLen Brown 
1265388e9c81SLen Brown 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next)
1266388e9c81SLen Brown 		c->counter[i] = 0;
1267388e9c81SLen Brown 
1268388e9c81SLen Brown 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next)
1269388e9c81SLen Brown 		p->counter[i] = 0;
1270103a8feaSLen Brown }
1271c98d5d94SLen Brown int sum_counters(struct thread_data *t, struct core_data *c,
1272c98d5d94SLen Brown 	struct pkg_data *p)
1273103a8feaSLen Brown {
1274388e9c81SLen Brown 	int i;
1275388e9c81SLen Brown 	struct msr_counter *mp;
1276388e9c81SLen Brown 
1277c98d5d94SLen Brown 	average.threads.tsc += t->tsc;
1278c98d5d94SLen Brown 	average.threads.aperf += t->aperf;
1279c98d5d94SLen Brown 	average.threads.mperf += t->mperf;
1280c98d5d94SLen Brown 	average.threads.c1 += t->c1;
128115aaa346SLen Brown 
1282562a2d37SLen Brown 	average.threads.irq_count += t->irq_count;
1283562a2d37SLen Brown 	average.threads.smi_count += t->smi_count;
1284562a2d37SLen Brown 
1285388e9c81SLen Brown 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
1286388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1287388e9c81SLen Brown 			continue;
1288388e9c81SLen Brown 		average.threads.counter[i] += t->counter[i];
1289388e9c81SLen Brown 	}
1290388e9c81SLen Brown 
1291c98d5d94SLen Brown 	/* sum per-core values only for 1st thread in core */
1292c98d5d94SLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
1293c98d5d94SLen Brown 		return 0;
1294c98d5d94SLen Brown 
1295c98d5d94SLen Brown 	average.cores.c3 += c->c3;
1296c98d5d94SLen Brown 	average.cores.c6 += c->c6;
1297c98d5d94SLen Brown 	average.cores.c7 += c->c7;
12980539ba11SLen Brown 	average.cores.mc6_us += c->mc6_us;
1299c98d5d94SLen Brown 
1300889facbeSLen Brown 	average.cores.core_temp_c = MAX(average.cores.core_temp_c, c->core_temp_c);
1301889facbeSLen Brown 
1302388e9c81SLen Brown 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
1303388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1304388e9c81SLen Brown 			continue;
1305388e9c81SLen Brown 		average.cores.counter[i] += c->counter[i];
1306388e9c81SLen Brown 	}
1307388e9c81SLen Brown 
1308c98d5d94SLen Brown 	/* sum per-pkg values only for 1st core in pkg */
1309c98d5d94SLen Brown 	if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
1310c98d5d94SLen Brown 		return 0;
1311c98d5d94SLen Brown 
1312*a99d8730SLen Brown 	if (DO_BIC(BIC_Totl_c0))
13130b2bb692SLen Brown 		average.packages.pkg_wtd_core_c0 += p->pkg_wtd_core_c0;
1314*a99d8730SLen Brown 	if (DO_BIC(BIC_Any_c0))
13150b2bb692SLen Brown 		average.packages.pkg_any_core_c0 += p->pkg_any_core_c0;
1316*a99d8730SLen Brown 	if (DO_BIC(BIC_GFX_c0))
13170b2bb692SLen Brown 		average.packages.pkg_any_gfxe_c0 += p->pkg_any_gfxe_c0;
1318*a99d8730SLen Brown 	if (DO_BIC(BIC_CPUGFX))
13190b2bb692SLen Brown 		average.packages.pkg_both_core_gfxe_c0 += p->pkg_both_core_gfxe_c0;
13200b2bb692SLen Brown 
1321c98d5d94SLen Brown 	average.packages.pc2 += p->pc2;
13220f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc3))
1323c98d5d94SLen Brown 		average.packages.pc3 += p->pc3;
13240f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc6))
1325c98d5d94SLen Brown 		average.packages.pc6 += p->pc6;
13260f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc7))
1327c98d5d94SLen Brown 		average.packages.pc7 += p->pc7;
1328ca58710fSKristen Carlson Accardi 	average.packages.pc8 += p->pc8;
1329ca58710fSKristen Carlson Accardi 	average.packages.pc9 += p->pc9;
1330ca58710fSKristen Carlson Accardi 	average.packages.pc10 += p->pc10;
1331c98d5d94SLen Brown 
1332889facbeSLen Brown 	average.packages.energy_pkg += p->energy_pkg;
1333889facbeSLen Brown 	average.packages.energy_dram += p->energy_dram;
1334889facbeSLen Brown 	average.packages.energy_cores += p->energy_cores;
1335889facbeSLen Brown 	average.packages.energy_gfx += p->energy_gfx;
1336889facbeSLen Brown 
1337fdf676e5SLen Brown 	average.packages.gfx_rc6_ms = p->gfx_rc6_ms;
133827d47356SLen Brown 	average.packages.gfx_mhz = p->gfx_mhz;
133927d47356SLen Brown 
1340889facbeSLen Brown 	average.packages.pkg_temp_c = MAX(average.packages.pkg_temp_c, p->pkg_temp_c);
1341889facbeSLen Brown 
1342889facbeSLen Brown 	average.packages.rapl_pkg_perf_status += p->rapl_pkg_perf_status;
1343889facbeSLen Brown 	average.packages.rapl_dram_perf_status += p->rapl_dram_perf_status;
1344388e9c81SLen Brown 
1345388e9c81SLen Brown 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
1346388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1347388e9c81SLen Brown 			continue;
1348388e9c81SLen Brown 		average.packages.counter[i] += p->counter[i];
1349388e9c81SLen Brown 	}
1350c98d5d94SLen Brown 	return 0;
1351c98d5d94SLen Brown }
1352c98d5d94SLen Brown /*
1353c98d5d94SLen Brown  * sum the counters for all cpus in the system
1354c98d5d94SLen Brown  * compute the weighted average
1355c98d5d94SLen Brown  */
1356c98d5d94SLen Brown void compute_average(struct thread_data *t, struct core_data *c,
1357c98d5d94SLen Brown 	struct pkg_data *p)
1358c98d5d94SLen Brown {
1359388e9c81SLen Brown 	int i;
1360388e9c81SLen Brown 	struct msr_counter *mp;
1361388e9c81SLen Brown 
1362c98d5d94SLen Brown 	clear_counters(&average.threads, &average.cores, &average.packages);
1363c98d5d94SLen Brown 
1364c98d5d94SLen Brown 	for_all_cpus(sum_counters, t, c, p);
1365c98d5d94SLen Brown 
1366c98d5d94SLen Brown 	average.threads.tsc /= topo.num_cpus;
1367c98d5d94SLen Brown 	average.threads.aperf /= topo.num_cpus;
1368c98d5d94SLen Brown 	average.threads.mperf /= topo.num_cpus;
1369c98d5d94SLen Brown 	average.threads.c1 /= topo.num_cpus;
1370c98d5d94SLen Brown 
13710de6c0dfSLen Brown 	if (average.threads.irq_count > 9999999)
13720de6c0dfSLen Brown 		sums_need_wide_columns = 1;
13730de6c0dfSLen Brown 
1374c98d5d94SLen Brown 	average.cores.c3 /= topo.num_cores;
1375c98d5d94SLen Brown 	average.cores.c6 /= topo.num_cores;
1376c98d5d94SLen Brown 	average.cores.c7 /= topo.num_cores;
13770539ba11SLen Brown 	average.cores.mc6_us /= topo.num_cores;
1378c98d5d94SLen Brown 
1379*a99d8730SLen Brown 	if (DO_BIC(BIC_Totl_c0))
13800b2bb692SLen Brown 		average.packages.pkg_wtd_core_c0 /= topo.num_packages;
1381*a99d8730SLen Brown 	if (DO_BIC(BIC_Any_c0))
13820b2bb692SLen Brown 		average.packages.pkg_any_core_c0 /= topo.num_packages;
1383*a99d8730SLen Brown 	if (DO_BIC(BIC_GFX_c0))
13840b2bb692SLen Brown 		average.packages.pkg_any_gfxe_c0 /= topo.num_packages;
1385*a99d8730SLen Brown 	if (DO_BIC(BIC_CPUGFX))
13860b2bb692SLen Brown 		average.packages.pkg_both_core_gfxe_c0 /= topo.num_packages;
13870b2bb692SLen Brown 
1388c98d5d94SLen Brown 	average.packages.pc2 /= topo.num_packages;
13890f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc3))
1390c98d5d94SLen Brown 		average.packages.pc3 /= topo.num_packages;
13910f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc6))
1392c98d5d94SLen Brown 		average.packages.pc6 /= topo.num_packages;
13930f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc7))
1394c98d5d94SLen Brown 		average.packages.pc7 /= topo.num_packages;
1395ca58710fSKristen Carlson Accardi 
1396ca58710fSKristen Carlson Accardi 	average.packages.pc8 /= topo.num_packages;
1397ca58710fSKristen Carlson Accardi 	average.packages.pc9 /= topo.num_packages;
1398ca58710fSKristen Carlson Accardi 	average.packages.pc10 /= topo.num_packages;
1399388e9c81SLen Brown 
1400388e9c81SLen Brown 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
1401388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1402388e9c81SLen Brown 			continue;
14030de6c0dfSLen Brown 		if (mp->type == COUNTER_ITEMS) {
14040de6c0dfSLen Brown 			if (average.threads.counter[i] > 9999999)
14050de6c0dfSLen Brown 				sums_need_wide_columns = 1;
140641618e63SLen Brown 			continue;
14070de6c0dfSLen Brown 		}
1408388e9c81SLen Brown 		average.threads.counter[i] /= topo.num_cpus;
1409388e9c81SLen Brown 	}
1410388e9c81SLen Brown 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
1411388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1412388e9c81SLen Brown 			continue;
14130de6c0dfSLen Brown 		if (mp->type == COUNTER_ITEMS) {
14140de6c0dfSLen Brown 			if (average.cores.counter[i] > 9999999)
14150de6c0dfSLen Brown 				sums_need_wide_columns = 1;
14160de6c0dfSLen Brown 		}
1417388e9c81SLen Brown 		average.cores.counter[i] /= topo.num_cores;
1418388e9c81SLen Brown 	}
1419388e9c81SLen Brown 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
1420388e9c81SLen Brown 		if (mp->format == FORMAT_RAW)
1421388e9c81SLen Brown 			continue;
14220de6c0dfSLen Brown 		if (mp->type == COUNTER_ITEMS) {
14230de6c0dfSLen Brown 			if (average.packages.counter[i] > 9999999)
14240de6c0dfSLen Brown 				sums_need_wide_columns = 1;
14250de6c0dfSLen Brown 		}
1426388e9c81SLen Brown 		average.packages.counter[i] /= topo.num_packages;
1427388e9c81SLen Brown 	}
1428c98d5d94SLen Brown }
1429c98d5d94SLen Brown 
1430c98d5d94SLen Brown static unsigned long long rdtsc(void)
1431c98d5d94SLen Brown {
1432c98d5d94SLen Brown 	unsigned int low, high;
1433c98d5d94SLen Brown 
1434c98d5d94SLen Brown 	asm volatile("rdtsc" : "=a" (low), "=d" (high));
1435c98d5d94SLen Brown 
1436c98d5d94SLen Brown 	return low | ((unsigned long long)high) << 32;
1437c98d5d94SLen Brown }
1438c98d5d94SLen Brown 
1439c98d5d94SLen Brown /*
1440495c7654SLen Brown  * Open a file, and exit on failure
1441495c7654SLen Brown  */
1442495c7654SLen Brown FILE *fopen_or_die(const char *path, const char *mode)
1443495c7654SLen Brown {
1444495c7654SLen Brown 	FILE *filep = fopen(path, mode);
1445495c7654SLen Brown 
1446495c7654SLen Brown 	if (!filep)
1447495c7654SLen Brown 		err(1, "%s: open failed", path);
1448495c7654SLen Brown 	return filep;
1449495c7654SLen Brown }
1450495c7654SLen Brown /*
1451495c7654SLen Brown  * snapshot_sysfs_counter()
1452495c7654SLen Brown  *
1453495c7654SLen Brown  * return snapshot of given counter
1454495c7654SLen Brown  */
1455495c7654SLen Brown unsigned long long snapshot_sysfs_counter(char *path)
1456495c7654SLen Brown {
1457495c7654SLen Brown 	FILE *fp;
1458495c7654SLen Brown 	int retval;
1459495c7654SLen Brown 	unsigned long long counter;
1460495c7654SLen Brown 
1461495c7654SLen Brown 	fp = fopen_or_die(path, "r");
1462495c7654SLen Brown 
1463495c7654SLen Brown 	retval = fscanf(fp, "%lld", &counter);
1464495c7654SLen Brown 	if (retval != 1)
1465495c7654SLen Brown 		err(1, "snapshot_sysfs_counter(%s)", path);
1466495c7654SLen Brown 
1467495c7654SLen Brown 	fclose(fp);
1468495c7654SLen Brown 
1469495c7654SLen Brown 	return counter;
1470495c7654SLen Brown }
1471495c7654SLen Brown 
1472495c7654SLen Brown int get_mp(int cpu, struct msr_counter *mp, unsigned long long *counterp)
1473495c7654SLen Brown {
1474495c7654SLen Brown 	if (mp->msr_num != 0) {
1475495c7654SLen Brown 		if (get_msr(cpu, mp->msr_num, counterp))
1476495c7654SLen Brown 			return -1;
1477495c7654SLen Brown 	} else {
147841618e63SLen Brown 		char path[128];
147941618e63SLen Brown 
148041618e63SLen Brown 		if (mp->flags & SYSFS_PERCPU) {
148141618e63SLen Brown 			sprintf(path, "/sys/devices/system/cpu/cpu%d/%s",
148241618e63SLen Brown 				 cpu, mp->path);
148341618e63SLen Brown 
148441618e63SLen Brown 			*counterp = snapshot_sysfs_counter(path);
148541618e63SLen Brown 		} else {
1486495c7654SLen Brown 			*counterp = snapshot_sysfs_counter(mp->path);
1487495c7654SLen Brown 		}
148841618e63SLen Brown 	}
1489495c7654SLen Brown 
1490495c7654SLen Brown 	return 0;
1491495c7654SLen Brown }
1492495c7654SLen Brown 
1493495c7654SLen Brown /*
1494c98d5d94SLen Brown  * get_counters(...)
1495c98d5d94SLen Brown  * migrate to cpu
1496c98d5d94SLen Brown  * acquire and record local counters for that cpu
1497c98d5d94SLen Brown  */
1498c98d5d94SLen Brown int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1499c98d5d94SLen Brown {
1500c98d5d94SLen Brown 	int cpu = t->cpu_id;
1501889facbeSLen Brown 	unsigned long long msr;
15020102b067SLen Brown 	int aperf_mperf_retry_count = 0;
1503388e9c81SLen Brown 	struct msr_counter *mp;
1504388e9c81SLen Brown 	int i;
1505c98d5d94SLen Brown 
1506e52966c0SLen Brown 	if (cpu_migrate(cpu)) {
1507b7d8c148SLen Brown 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
150815aaa346SLen Brown 		return -1;
1509e52966c0SLen Brown 	}
151015aaa346SLen Brown 
15110102b067SLen Brown retry:
1512c98d5d94SLen Brown 	t->tsc = rdtsc();	/* we are running on local CPU of interest */
151315aaa346SLen Brown 
1514812db3f7SLen Brown 	if (DO_BIC(BIC_Avg_MHz) || DO_BIC(BIC_Busy) || DO_BIC(BIC_Bzy_MHz)) {
15150102b067SLen Brown 		unsigned long long tsc_before, tsc_between, tsc_after, aperf_time, mperf_time;
15160102b067SLen Brown 
15170102b067SLen Brown 		/*
15180102b067SLen Brown 		 * The TSC, APERF and MPERF must be read together for
15190102b067SLen Brown 		 * APERF/MPERF and MPERF/TSC to give accurate results.
15200102b067SLen Brown 		 *
15210102b067SLen Brown 		 * Unfortunately, APERF and MPERF are read by
15220102b067SLen Brown 		 * individual system call, so delays may occur
15230102b067SLen Brown 		 * between them.  If the time to read them
15240102b067SLen Brown 		 * varies by a large amount, we re-read them.
15250102b067SLen Brown 		 */
15260102b067SLen Brown 
15270102b067SLen Brown 		/*
15280102b067SLen Brown 		 * This initial dummy APERF read has been seen to
15290102b067SLen Brown 		 * reduce jitter in the subsequent reads.
15300102b067SLen Brown 		 */
15310102b067SLen Brown 
15329c63a650SLen Brown 		if (get_msr(cpu, MSR_IA32_APERF, &t->aperf))
1533c98d5d94SLen Brown 			return -3;
15340102b067SLen Brown 
15350102b067SLen Brown 		t->tsc = rdtsc();	/* re-read close to APERF */
15360102b067SLen Brown 
15370102b067SLen Brown 		tsc_before = t->tsc;
15380102b067SLen Brown 
15390102b067SLen Brown 		if (get_msr(cpu, MSR_IA32_APERF, &t->aperf))
15400102b067SLen Brown 			return -3;
15410102b067SLen Brown 
15420102b067SLen Brown 		tsc_between = rdtsc();
15430102b067SLen Brown 
15449c63a650SLen Brown 		if (get_msr(cpu, MSR_IA32_MPERF, &t->mperf))
1545c98d5d94SLen Brown 			return -4;
15460102b067SLen Brown 
15470102b067SLen Brown 		tsc_after = rdtsc();
15480102b067SLen Brown 
15490102b067SLen Brown 		aperf_time = tsc_between - tsc_before;
15500102b067SLen Brown 		mperf_time = tsc_after - tsc_between;
15510102b067SLen Brown 
15520102b067SLen Brown 		/*
15530102b067SLen Brown 		 * If the system call latency to read APERF and MPERF
15540102b067SLen Brown 		 * differ by more than 2x, then try again.
15550102b067SLen Brown 		 */
15560102b067SLen Brown 		if ((aperf_time > (2 * mperf_time)) || (mperf_time > (2 * aperf_time))) {
15570102b067SLen Brown 			aperf_mperf_retry_count++;
15580102b067SLen Brown 			if (aperf_mperf_retry_count < 5)
15590102b067SLen Brown 				goto retry;
15600102b067SLen Brown 			else
15610102b067SLen Brown 				warnx("cpu%d jitter %lld %lld",
15620102b067SLen Brown 					cpu, aperf_time, mperf_time);
15630102b067SLen Brown 		}
15640102b067SLen Brown 		aperf_mperf_retry_count = 0;
15650102b067SLen Brown 
1566b2b34dfeSHubert Chrzaniuk 		t->aperf = t->aperf * aperf_mperf_multiplier;
1567b2b34dfeSHubert Chrzaniuk 		t->mperf = t->mperf * aperf_mperf_multiplier;
156888c3281fSLen Brown 	}
156988c3281fSLen Brown 
1570812db3f7SLen Brown 	if (DO_BIC(BIC_IRQ))
1571562a2d37SLen Brown 		t->irq_count = irqs_per_cpu[cpu];
1572812db3f7SLen Brown 	if (DO_BIC(BIC_SMI)) {
15731ed51011SLen Brown 		if (get_msr(cpu, MSR_SMI_COUNT, &msr))
15741ed51011SLen Brown 			return -5;
15751ed51011SLen Brown 		t->smi_count = msr & 0xFFFFFFFF;
15761ed51011SLen Brown 	}
15770539ba11SLen Brown 	if (DO_BIC(BIC_CPU_c1) && use_c1_residency_msr) {
1578144b44b1SLen Brown 		if (get_msr(cpu, MSR_CORE_C1_RES, &t->c1))
1579144b44b1SLen Brown 			return -6;
1580144b44b1SLen Brown 	}
1581144b44b1SLen Brown 
1582388e9c81SLen Brown 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
1583495c7654SLen Brown 		if (get_mp(cpu, mp, &t->counter[i]))
1584388e9c81SLen Brown 			return -10;
1585388e9c81SLen Brown 	}
1586388e9c81SLen Brown 
1587c98d5d94SLen Brown 	/* collect core counters only for 1st thread in core */
1588c98d5d94SLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
1589c98d5d94SLen Brown 		return 0;
1590c98d5d94SLen Brown 
1591812db3f7SLen Brown 	if (DO_BIC(BIC_CPU_c3) && !do_slm_cstates && !do_knl_cstates) {
1592c98d5d94SLen Brown 		if (get_msr(cpu, MSR_CORE_C3_RESIDENCY, &c->c3))
1593c98d5d94SLen Brown 			return -6;
1594144b44b1SLen Brown 	}
1595144b44b1SLen Brown 
1596812db3f7SLen Brown 	if (DO_BIC(BIC_CPU_c6) && !do_knl_cstates) {
1597c98d5d94SLen Brown 		if (get_msr(cpu, MSR_CORE_C6_RESIDENCY, &c->c6))
1598c98d5d94SLen Brown 			return -7;
1599fb5d4327SDasaratharaman Chandramouli 	} else if (do_knl_cstates) {
1600fb5d4327SDasaratharaman Chandramouli 		if (get_msr(cpu, MSR_KNL_CORE_C6_RESIDENCY, &c->c6))
1601fb5d4327SDasaratharaman Chandramouli 			return -7;
1602103a8feaSLen Brown 	}
160315aaa346SLen Brown 
1604812db3f7SLen Brown 	if (DO_BIC(BIC_CPU_c7))
1605c98d5d94SLen Brown 		if (get_msr(cpu, MSR_CORE_C7_RESIDENCY, &c->c7))
1606c98d5d94SLen Brown 			return -8;
1607c98d5d94SLen Brown 
16080539ba11SLen Brown 	if (DO_BIC(BIC_Mod_c6))
16090539ba11SLen Brown 		if (get_msr(cpu, MSR_MODULE_C6_RES_MS, &c->mc6_us))
16100539ba11SLen Brown 			return -8;
16110539ba11SLen Brown 
1612812db3f7SLen Brown 	if (DO_BIC(BIC_CoreTmp)) {
1613889facbeSLen Brown 		if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr))
1614889facbeSLen Brown 			return -9;
1615889facbeSLen Brown 		c->core_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F);
1616889facbeSLen Brown 	}
1617889facbeSLen Brown 
1618388e9c81SLen Brown 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
1619495c7654SLen Brown 		if (get_mp(cpu, mp, &c->counter[i]))
1620388e9c81SLen Brown 			return -10;
1621388e9c81SLen Brown 	}
1622889facbeSLen Brown 
1623c98d5d94SLen Brown 	/* collect package counters only for 1st core in package */
1624c98d5d94SLen Brown 	if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
1625c98d5d94SLen Brown 		return 0;
162615aaa346SLen Brown 
1627*a99d8730SLen Brown 	if (DO_BIC(BIC_Totl_c0)) {
16280b2bb692SLen Brown 		if (get_msr(cpu, MSR_PKG_WEIGHTED_CORE_C0_RES, &p->pkg_wtd_core_c0))
16290b2bb692SLen Brown 			return -10;
1630*a99d8730SLen Brown 	}
1631*a99d8730SLen Brown 	if (DO_BIC(BIC_Any_c0)) {
16320b2bb692SLen Brown 		if (get_msr(cpu, MSR_PKG_ANY_CORE_C0_RES, &p->pkg_any_core_c0))
16330b2bb692SLen Brown 			return -11;
1634*a99d8730SLen Brown 	}
1635*a99d8730SLen Brown 	if (DO_BIC(BIC_GFX_c0)) {
16360b2bb692SLen Brown 		if (get_msr(cpu, MSR_PKG_ANY_GFXE_C0_RES, &p->pkg_any_gfxe_c0))
16370b2bb692SLen Brown 			return -12;
1638*a99d8730SLen Brown 	}
1639*a99d8730SLen Brown 	if (DO_BIC(BIC_CPUGFX)) {
16400b2bb692SLen Brown 		if (get_msr(cpu, MSR_PKG_BOTH_CORE_GFXE_C0_RES, &p->pkg_both_core_gfxe_c0))
16410b2bb692SLen Brown 			return -13;
16420b2bb692SLen Brown 	}
16430f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc3))
1644c98d5d94SLen Brown 		if (get_msr(cpu, MSR_PKG_C3_RESIDENCY, &p->pc3))
1645c98d5d94SLen Brown 			return -9;
16460f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc6)) {
16470539ba11SLen Brown 		if (do_slm_cstates) {
16480539ba11SLen Brown 			if (get_msr(cpu, MSR_ATOM_PKG_C6_RESIDENCY, &p->pc6))
16490539ba11SLen Brown 				return -10;
16500539ba11SLen Brown 		} else {
1651c98d5d94SLen Brown 			if (get_msr(cpu, MSR_PKG_C6_RESIDENCY, &p->pc6))
1652c98d5d94SLen Brown 				return -10;
16530539ba11SLen Brown 		}
16540539ba11SLen Brown 	}
16550539ba11SLen Brown 
16560f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc2))
1657c98d5d94SLen Brown 		if (get_msr(cpu, MSR_PKG_C2_RESIDENCY, &p->pc2))
1658c98d5d94SLen Brown 			return -11;
16590f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc7))
1660c98d5d94SLen Brown 		if (get_msr(cpu, MSR_PKG_C7_RESIDENCY, &p->pc7))
1661c98d5d94SLen Brown 			return -12;
16620f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc8))
1663ca58710fSKristen Carlson Accardi 		if (get_msr(cpu, MSR_PKG_C8_RESIDENCY, &p->pc8))
1664ca58710fSKristen Carlson Accardi 			return -13;
16650f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc9))
1666ca58710fSKristen Carlson Accardi 		if (get_msr(cpu, MSR_PKG_C9_RESIDENCY, &p->pc9))
1667ca58710fSKristen Carlson Accardi 			return -13;
16680f47c08dSLen Brown 	if (DO_BIC(BIC_Pkgpc10))
1669ca58710fSKristen Carlson Accardi 		if (get_msr(cpu, MSR_PKG_C10_RESIDENCY, &p->pc10))
1670ca58710fSKristen Carlson Accardi 			return -13;
16710f47c08dSLen Brown 
1672889facbeSLen Brown 	if (do_rapl & RAPL_PKG) {
1673889facbeSLen Brown 		if (get_msr(cpu, MSR_PKG_ENERGY_STATUS, &msr))
1674889facbeSLen Brown 			return -13;
1675889facbeSLen Brown 		p->energy_pkg = msr & 0xFFFFFFFF;
1676889facbeSLen Brown 	}
16779148494cSJacob Pan 	if (do_rapl & RAPL_CORES_ENERGY_STATUS) {
1678889facbeSLen Brown 		if (get_msr(cpu, MSR_PP0_ENERGY_STATUS, &msr))
1679889facbeSLen Brown 			return -14;
1680889facbeSLen Brown 		p->energy_cores = msr & 0xFFFFFFFF;
1681889facbeSLen Brown 	}
1682889facbeSLen Brown 	if (do_rapl & RAPL_DRAM) {
1683889facbeSLen Brown 		if (get_msr(cpu, MSR_DRAM_ENERGY_STATUS, &msr))
1684889facbeSLen Brown 			return -15;
1685889facbeSLen Brown 		p->energy_dram = msr & 0xFFFFFFFF;
1686889facbeSLen Brown 	}
1687889facbeSLen Brown 	if (do_rapl & RAPL_GFX) {
1688889facbeSLen Brown 		if (get_msr(cpu, MSR_PP1_ENERGY_STATUS, &msr))
1689889facbeSLen Brown 			return -16;
1690889facbeSLen Brown 		p->energy_gfx = msr & 0xFFFFFFFF;
1691889facbeSLen Brown 	}
1692889facbeSLen Brown 	if (do_rapl & RAPL_PKG_PERF_STATUS) {
1693889facbeSLen Brown 		if (get_msr(cpu, MSR_PKG_PERF_STATUS, &msr))
1694889facbeSLen Brown 			return -16;
1695889facbeSLen Brown 		p->rapl_pkg_perf_status = msr & 0xFFFFFFFF;
1696889facbeSLen Brown 	}
1697889facbeSLen Brown 	if (do_rapl & RAPL_DRAM_PERF_STATUS) {
1698889facbeSLen Brown 		if (get_msr(cpu, MSR_DRAM_PERF_STATUS, &msr))
1699889facbeSLen Brown 			return -16;
1700889facbeSLen Brown 		p->rapl_dram_perf_status = msr & 0xFFFFFFFF;
1701889facbeSLen Brown 	}
1702812db3f7SLen Brown 	if (DO_BIC(BIC_PkgTmp)) {
1703889facbeSLen Brown 		if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr))
1704889facbeSLen Brown 			return -17;
1705889facbeSLen Brown 		p->pkg_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F);
1706889facbeSLen Brown 	}
1707fdf676e5SLen Brown 
1708812db3f7SLen Brown 	if (DO_BIC(BIC_GFX_rc6))
1709fdf676e5SLen Brown 		p->gfx_rc6_ms = gfx_cur_rc6_ms;
1710fdf676e5SLen Brown 
1711812db3f7SLen Brown 	if (DO_BIC(BIC_GFXMHz))
171227d47356SLen Brown 		p->gfx_mhz = gfx_cur_mhz;
171327d47356SLen Brown 
1714388e9c81SLen Brown 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
1715495c7654SLen Brown 		if (get_mp(cpu, mp, &p->counter[i]))
1716388e9c81SLen Brown 			return -10;
1717388e9c81SLen Brown 	}
1718388e9c81SLen Brown 
171915aaa346SLen Brown 	return 0;
1720103a8feaSLen Brown }
1721103a8feaSLen Brown 
1722ee7e38e3SLen Brown /*
1723ee7e38e3SLen Brown  * MSR_PKG_CST_CONFIG_CONTROL decoding for pkg_cstate_limit:
1724ee7e38e3SLen Brown  * If you change the values, note they are used both in comparisons
1725ee7e38e3SLen Brown  * (>= PCL__7) and to index pkg_cstate_limit_strings[].
1726ee7e38e3SLen Brown  */
1727ee7e38e3SLen Brown 
1728ee7e38e3SLen Brown #define PCLUKN 0 /* Unknown */
1729ee7e38e3SLen Brown #define PCLRSV 1 /* Reserved */
1730ee7e38e3SLen Brown #define PCL__0 2 /* PC0 */
1731ee7e38e3SLen Brown #define PCL__1 3 /* PC1 */
1732ee7e38e3SLen Brown #define PCL__2 4 /* PC2 */
1733ee7e38e3SLen Brown #define PCL__3 5 /* PC3 */
1734ee7e38e3SLen Brown #define PCL__4 6 /* PC4 */
1735ee7e38e3SLen Brown #define PCL__6 7 /* PC6 */
1736ee7e38e3SLen Brown #define PCL_6N 8 /* PC6 No Retention */
1737ee7e38e3SLen Brown #define PCL_6R 9 /* PC6 Retention */
1738ee7e38e3SLen Brown #define PCL__7 10 /* PC7 */
1739ee7e38e3SLen Brown #define PCL_7S 11 /* PC7 Shrink */
17400b2bb692SLen Brown #define PCL__8 12 /* PC8 */
17410b2bb692SLen Brown #define PCL__9 13 /* PC9 */
17420b2bb692SLen Brown #define PCLUNL 14 /* Unlimited */
1743ee7e38e3SLen Brown 
1744ee7e38e3SLen Brown int pkg_cstate_limit = PCLUKN;
1745ee7e38e3SLen Brown char *pkg_cstate_limit_strings[] = { "reserved", "unknown", "pc0", "pc1", "pc2",
17460b2bb692SLen Brown 	"pc3", "pc4", "pc6", "pc6n", "pc6r", "pc7", "pc7s", "pc8", "pc9", "unlimited"};
1747ee7e38e3SLen Brown 
1748e9257f5fSLen 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};
1749e9257f5fSLen 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};
1750e9257f5fSLen 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};
17510539ba11SLen 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, PCL__6, PCL__7};
1752f2642888SLen Brown int amt_pkg_cstate_limits[16] = {PCLUNL, PCL__1, PCL__2, PCLRSV, PCLRSV, PCLRSV, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
1753e9257f5fSLen 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};
1754e4085d54SLen 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};
1755d8ebb442SLen 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};
1756ee7e38e3SLen Brown 
1757a2b7b749SLen Brown 
1758a2b7b749SLen Brown static void
1759a2b7b749SLen Brown calculate_tsc_tweak()
1760a2b7b749SLen Brown {
1761a2b7b749SLen Brown 	tsc_tweak = base_hz / tsc_hz;
1762a2b7b749SLen Brown }
1763a2b7b749SLen Brown 
1764fcd17211SLen Brown static void
1765fcd17211SLen Brown dump_nhm_platform_info(void)
1766103a8feaSLen Brown {
1767103a8feaSLen Brown 	unsigned long long msr;
1768103a8feaSLen Brown 	unsigned int ratio;
1769103a8feaSLen Brown 
1770ec0adc53SLen Brown 	get_msr(base_cpu, MSR_PLATFORM_INFO, &msr);
1771103a8feaSLen Brown 
1772b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_PLATFORM_INFO: 0x%08llx\n", base_cpu, msr);
17736574a5d5SLen Brown 
1774103a8feaSLen Brown 	ratio = (msr >> 40) & 0xFF;
1775710f273bSLen Brown 	fprintf(outf, "%d * %.1f = %.1f MHz max efficiency frequency\n",
1776103a8feaSLen Brown 		ratio, bclk, ratio * bclk);
1777103a8feaSLen Brown 
1778103a8feaSLen Brown 	ratio = (msr >> 8) & 0xFF;
1779710f273bSLen Brown 	fprintf(outf, "%d * %.1f = %.1f MHz base frequency\n",
1780103a8feaSLen Brown 		ratio, bclk, ratio * bclk);
1781103a8feaSLen Brown 
17827ce7d5deSPrarit Bhargava 	get_msr(base_cpu, MSR_IA32_POWER_CTL, &msr);
1783b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_IA32_POWER_CTL: 0x%08llx (C1E auto-promotion: %sabled)\n",
1784bfae2052SLen Brown 		base_cpu, msr, msr & 0x2 ? "EN" : "DIS");
178567920418SLen Brown 
1786fcd17211SLen Brown 	return;
1787fcd17211SLen Brown }
1788fcd17211SLen Brown 
1789fcd17211SLen Brown static void
1790fcd17211SLen Brown dump_hsw_turbo_ratio_limits(void)
1791fcd17211SLen Brown {
1792fcd17211SLen Brown 	unsigned long long msr;
1793fcd17211SLen Brown 	unsigned int ratio;
1794fcd17211SLen Brown 
17957ce7d5deSPrarit Bhargava 	get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT2, &msr);
1796fcd17211SLen Brown 
1797b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT2: 0x%08llx\n", base_cpu, msr);
1798fcd17211SLen Brown 
1799fcd17211SLen Brown 	ratio = (msr >> 8) & 0xFF;
1800fcd17211SLen Brown 	if (ratio)
1801710f273bSLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo 18 active cores\n",
1802fcd17211SLen Brown 			ratio, bclk, ratio * bclk);
1803fcd17211SLen Brown 
1804fcd17211SLen Brown 	ratio = (msr >> 0) & 0xFF;
1805fcd17211SLen Brown 	if (ratio)
1806710f273bSLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo 17 active cores\n",
1807fcd17211SLen Brown 			ratio, bclk, ratio * bclk);
1808fcd17211SLen Brown 	return;
1809fcd17211SLen Brown }
1810fcd17211SLen Brown 
1811fcd17211SLen Brown static void
1812fcd17211SLen Brown dump_ivt_turbo_ratio_limits(void)
1813fcd17211SLen Brown {
1814fcd17211SLen Brown 	unsigned long long msr;
1815fcd17211SLen Brown 	unsigned int ratio;
18166574a5d5SLen Brown 
18177ce7d5deSPrarit Bhargava 	get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT1, &msr);
18186574a5d5SLen Brown 
1819b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT1: 0x%08llx\n", base_cpu, msr);
18206574a5d5SLen Brown 
18216574a5d5SLen Brown 	ratio = (msr >> 56) & 0xFF;
18226574a5d5SLen Brown 	if (ratio)
1823710f273bSLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo 16 active cores\n",
18246574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
18256574a5d5SLen Brown 
18266574a5d5SLen Brown 	ratio = (msr >> 48) & 0xFF;
18276574a5d5SLen Brown 	if (ratio)
1828710f273bSLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo 15 active cores\n",
18296574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
18306574a5d5SLen Brown 
18316574a5d5SLen Brown 	ratio = (msr >> 40) & 0xFF;
18326574a5d5SLen Brown 	if (ratio)
1833710f273bSLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo 14 active cores\n",
18346574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
18356574a5d5SLen Brown 
18366574a5d5SLen Brown 	ratio = (msr >> 32) & 0xFF;
18376574a5d5SLen Brown 	if (ratio)
1838710f273bSLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo 13 active cores\n",
18396574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
18406574a5d5SLen Brown 
18416574a5d5SLen Brown 	ratio = (msr >> 24) & 0xFF;
18426574a5d5SLen Brown 	if (ratio)
1843710f273bSLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo 12 active cores\n",
18446574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
18456574a5d5SLen Brown 
18466574a5d5SLen Brown 	ratio = (msr >> 16) & 0xFF;
18476574a5d5SLen Brown 	if (ratio)
1848710f273bSLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo 11 active cores\n",
18496574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
18506574a5d5SLen Brown 
18516574a5d5SLen Brown 	ratio = (msr >> 8) & 0xFF;
18526574a5d5SLen Brown 	if (ratio)
1853710f273bSLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo 10 active cores\n",
18546574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
18556574a5d5SLen Brown 
18566574a5d5SLen Brown 	ratio = (msr >> 0) & 0xFF;
18576574a5d5SLen Brown 	if (ratio)
1858710f273bSLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo 9 active cores\n",
18596574a5d5SLen Brown 			ratio, bclk, ratio * bclk);
1860103a8feaSLen Brown 	return;
1861fcd17211SLen Brown }
186231e07522SLen Brown int has_turbo_ratio_group_limits(int family, int model)
186331e07522SLen Brown {
186431e07522SLen Brown 
186531e07522SLen Brown 	if (!genuine_intel)
186631e07522SLen Brown 		return 0;
186731e07522SLen Brown 
186831e07522SLen Brown 	switch (model) {
186931e07522SLen Brown 	case INTEL_FAM6_ATOM_GOLDMONT:
187031e07522SLen Brown 	case INTEL_FAM6_SKYLAKE_X:
187131e07522SLen Brown 	case INTEL_FAM6_ATOM_DENVERTON:
187231e07522SLen Brown 		return 1;
187331e07522SLen Brown 	}
187431e07522SLen Brown 	return 0;
187531e07522SLen Brown }
1876fcd17211SLen Brown 
1877fcd17211SLen Brown static void
187831e07522SLen Brown dump_turbo_ratio_limits(int family, int model)
1879fcd17211SLen Brown {
188031e07522SLen Brown 	unsigned long long msr, core_counts;
188131e07522SLen Brown 	unsigned int ratio, group_size;
1882103a8feaSLen Brown 
18837ce7d5deSPrarit Bhargava 	get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT, &msr);
1884b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n", base_cpu, msr);
18856574a5d5SLen Brown 
188631e07522SLen Brown 	if (has_turbo_ratio_group_limits(family, model)) {
188731e07522SLen Brown 		get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT1, &core_counts);
188831e07522SLen Brown 		fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT1: 0x%08llx\n", base_cpu, core_counts);
188931e07522SLen Brown 	} else {
189031e07522SLen Brown 		core_counts = 0x0807060504030201;
189131e07522SLen Brown 	}
189231e07522SLen Brown 
18936574a5d5SLen Brown 	ratio = (msr >> 56) & 0xFF;
189431e07522SLen Brown 	group_size = (core_counts >> 56) & 0xFF;
18956574a5d5SLen Brown 	if (ratio)
189631e07522SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
189731e07522SLen Brown 			ratio, bclk, ratio * bclk, group_size);
18986574a5d5SLen Brown 
18996574a5d5SLen Brown 	ratio = (msr >> 48) & 0xFF;
190031e07522SLen Brown 	group_size = (core_counts >> 48) & 0xFF;
19016574a5d5SLen Brown 	if (ratio)
190231e07522SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
190331e07522SLen Brown 			ratio, bclk, ratio * bclk, group_size);
19046574a5d5SLen Brown 
19056574a5d5SLen Brown 	ratio = (msr >> 40) & 0xFF;
190631e07522SLen Brown 	group_size = (core_counts >> 40) & 0xFF;
19076574a5d5SLen Brown 	if (ratio)
190831e07522SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
190931e07522SLen Brown 			ratio, bclk, ratio * bclk, group_size);
19106574a5d5SLen Brown 
19116574a5d5SLen Brown 	ratio = (msr >> 32) & 0xFF;
191231e07522SLen Brown 	group_size = (core_counts >> 32) & 0xFF;
19136574a5d5SLen Brown 	if (ratio)
191431e07522SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
191531e07522SLen Brown 			ratio, bclk, ratio * bclk, group_size);
19166574a5d5SLen Brown 
1917103a8feaSLen Brown 	ratio = (msr >> 24) & 0xFF;
191831e07522SLen Brown 	group_size = (core_counts >> 24) & 0xFF;
1919103a8feaSLen Brown 	if (ratio)
192031e07522SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
192131e07522SLen Brown 			ratio, bclk, ratio * bclk, group_size);
1922103a8feaSLen Brown 
1923103a8feaSLen Brown 	ratio = (msr >> 16) & 0xFF;
192431e07522SLen Brown 	group_size = (core_counts >> 16) & 0xFF;
1925103a8feaSLen Brown 	if (ratio)
192631e07522SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
192731e07522SLen Brown 			ratio, bclk, ratio * bclk, group_size);
1928103a8feaSLen Brown 
1929103a8feaSLen Brown 	ratio = (msr >> 8) & 0xFF;
193031e07522SLen Brown 	group_size = (core_counts >> 8) & 0xFF;
1931103a8feaSLen Brown 	if (ratio)
193231e07522SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
193331e07522SLen Brown 			ratio, bclk, ratio * bclk, group_size);
1934103a8feaSLen Brown 
1935103a8feaSLen Brown 	ratio = (msr >> 0) & 0xFF;
193631e07522SLen Brown 	group_size = (core_counts >> 0) & 0xFF;
1937103a8feaSLen Brown 	if (ratio)
193831e07522SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
193931e07522SLen Brown 			ratio, bclk, ratio * bclk, group_size);
1940fcd17211SLen Brown 	return;
1941fcd17211SLen Brown }
19423a9a941dSLen Brown 
1943fcd17211SLen Brown static void
19440f7887c4SLen Brown dump_atom_turbo_ratio_limits(void)
19450f7887c4SLen Brown {
19460f7887c4SLen Brown 	unsigned long long msr;
19470f7887c4SLen Brown 	unsigned int ratio;
19480f7887c4SLen Brown 
19490f7887c4SLen Brown 	get_msr(base_cpu, MSR_ATOM_CORE_RATIOS, &msr);
19500f7887c4SLen Brown 	fprintf(outf, "cpu%d: MSR_ATOM_CORE_RATIOS: 0x%08llx\n", base_cpu, msr & 0xFFFFFFFF);
19510f7887c4SLen Brown 
19520f7887c4SLen Brown 	ratio = (msr >> 0) & 0x3F;
19530f7887c4SLen Brown 	if (ratio)
19540f7887c4SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz minimum operating frequency\n",
19550f7887c4SLen Brown 			ratio, bclk, ratio * bclk);
19560f7887c4SLen Brown 
19570f7887c4SLen Brown 	ratio = (msr >> 8) & 0x3F;
19580f7887c4SLen Brown 	if (ratio)
19590f7887c4SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz low frequency mode (LFM)\n",
19600f7887c4SLen Brown 			ratio, bclk, ratio * bclk);
19610f7887c4SLen Brown 
19620f7887c4SLen Brown 	ratio = (msr >> 16) & 0x3F;
19630f7887c4SLen Brown 	if (ratio)
19640f7887c4SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz base frequency\n",
19650f7887c4SLen Brown 			ratio, bclk, ratio * bclk);
19660f7887c4SLen Brown 
19670f7887c4SLen Brown 	get_msr(base_cpu, MSR_ATOM_CORE_TURBO_RATIOS, &msr);
19680f7887c4SLen Brown 	fprintf(outf, "cpu%d: MSR_ATOM_CORE_TURBO_RATIOS: 0x%08llx\n", base_cpu, msr & 0xFFFFFFFF);
19690f7887c4SLen Brown 
19700f7887c4SLen Brown 	ratio = (msr >> 24) & 0x3F;
19710f7887c4SLen Brown 	if (ratio)
19720f7887c4SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo 4 active cores\n",
19730f7887c4SLen Brown 			ratio, bclk, ratio * bclk);
19740f7887c4SLen Brown 
19750f7887c4SLen Brown 	ratio = (msr >> 16) & 0x3F;
19760f7887c4SLen Brown 	if (ratio)
19770f7887c4SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo 3 active cores\n",
19780f7887c4SLen Brown 			ratio, bclk, ratio * bclk);
19790f7887c4SLen Brown 
19800f7887c4SLen Brown 	ratio = (msr >> 8) & 0x3F;
19810f7887c4SLen Brown 	if (ratio)
19820f7887c4SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo 2 active cores\n",
19830f7887c4SLen Brown 			ratio, bclk, ratio * bclk);
19840f7887c4SLen Brown 
19850f7887c4SLen Brown 	ratio = (msr >> 0) & 0x3F;
19860f7887c4SLen Brown 	if (ratio)
19870f7887c4SLen Brown 		fprintf(outf, "%d * %.1f = %.1f MHz max turbo 1 active core\n",
19880f7887c4SLen Brown 			ratio, bclk, ratio * bclk);
19890f7887c4SLen Brown }
19900f7887c4SLen Brown 
19910f7887c4SLen Brown static void
1992fb5d4327SDasaratharaman Chandramouli dump_knl_turbo_ratio_limits(void)
1993fb5d4327SDasaratharaman Chandramouli {
1994cbf97abaSHubert Chrzaniuk 	const unsigned int buckets_no = 7;
1995cbf97abaSHubert Chrzaniuk 
1996fb5d4327SDasaratharaman Chandramouli 	unsigned long long msr;
1997cbf97abaSHubert Chrzaniuk 	int delta_cores, delta_ratio;
1998cbf97abaSHubert Chrzaniuk 	int i, b_nr;
1999cbf97abaSHubert Chrzaniuk 	unsigned int cores[buckets_no];
2000cbf97abaSHubert Chrzaniuk 	unsigned int ratio[buckets_no];
2001fb5d4327SDasaratharaman Chandramouli 
2002ebf5926aSSrinivas Pandruvada 	get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT, &msr);
2003fb5d4327SDasaratharaman Chandramouli 
2004b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n",
2005bfae2052SLen Brown 		base_cpu, msr);
2006fb5d4327SDasaratharaman Chandramouli 
2007fb5d4327SDasaratharaman Chandramouli 	/**
2008fb5d4327SDasaratharaman Chandramouli 	 * Turbo encoding in KNL is as follows:
2009cbf97abaSHubert Chrzaniuk 	 * [0] -- Reserved
2010cbf97abaSHubert Chrzaniuk 	 * [7:1] -- Base value of number of active cores of bucket 1.
2011fb5d4327SDasaratharaman Chandramouli 	 * [15:8] -- Base value of freq ratio of bucket 1.
2012fb5d4327SDasaratharaman Chandramouli 	 * [20:16] -- +ve delta of number of active cores of bucket 2.
2013fb5d4327SDasaratharaman Chandramouli 	 * i.e. active cores of bucket 2 =
2014fb5d4327SDasaratharaman Chandramouli 	 * active cores of bucket 1 + delta
2015fb5d4327SDasaratharaman Chandramouli 	 * [23:21] -- Negative delta of freq ratio of bucket 2.
2016fb5d4327SDasaratharaman Chandramouli 	 * i.e. freq ratio of bucket 2 =
2017fb5d4327SDasaratharaman Chandramouli 	 * freq ratio of bucket 1 - delta
2018fb5d4327SDasaratharaman Chandramouli 	 * [28:24]-- +ve delta of number of active cores of bucket 3.
2019fb5d4327SDasaratharaman Chandramouli 	 * [31:29]-- -ve delta of freq ratio of bucket 3.
2020fb5d4327SDasaratharaman Chandramouli 	 * [36:32]-- +ve delta of number of active cores of bucket 4.
2021fb5d4327SDasaratharaman Chandramouli 	 * [39:37]-- -ve delta of freq ratio of bucket 4.
2022fb5d4327SDasaratharaman Chandramouli 	 * [44:40]-- +ve delta of number of active cores of bucket 5.
2023fb5d4327SDasaratharaman Chandramouli 	 * [47:45]-- -ve delta of freq ratio of bucket 5.
2024fb5d4327SDasaratharaman Chandramouli 	 * [52:48]-- +ve delta of number of active cores of bucket 6.
2025fb5d4327SDasaratharaman Chandramouli 	 * [55:53]-- -ve delta of freq ratio of bucket 6.
2026fb5d4327SDasaratharaman Chandramouli 	 * [60:56]-- +ve delta of number of active cores of bucket 7.
2027fb5d4327SDasaratharaman Chandramouli 	 * [63:61]-- -ve delta of freq ratio of bucket 7.
2028fb5d4327SDasaratharaman Chandramouli 	 */
2029fb5d4327SDasaratharaman Chandramouli 
2030cbf97abaSHubert Chrzaniuk 	b_nr = 0;
2031cbf97abaSHubert Chrzaniuk 	cores[b_nr] = (msr & 0xFF) >> 1;
2032cbf97abaSHubert Chrzaniuk 	ratio[b_nr] = (msr >> 8) & 0xFF;
2033cbf97abaSHubert Chrzaniuk 
2034cbf97abaSHubert Chrzaniuk 	for (i = 16; i < 64; i += 8) {
2035fb5d4327SDasaratharaman Chandramouli 		delta_cores = (msr >> i) & 0x1F;
2036cbf97abaSHubert Chrzaniuk 		delta_ratio = (msr >> (i + 5)) & 0x7;
2037fb5d4327SDasaratharaman Chandramouli 
2038cbf97abaSHubert Chrzaniuk 		cores[b_nr + 1] = cores[b_nr] + delta_cores;
2039cbf97abaSHubert Chrzaniuk 		ratio[b_nr + 1] = ratio[b_nr] - delta_ratio;
2040cbf97abaSHubert Chrzaniuk 		b_nr++;
2041fb5d4327SDasaratharaman Chandramouli 	}
2042cbf97abaSHubert Chrzaniuk 
2043cbf97abaSHubert Chrzaniuk 	for (i = buckets_no - 1; i >= 0; i--)
2044cbf97abaSHubert Chrzaniuk 		if (i > 0 ? ratio[i] != ratio[i - 1] : 1)
2045b7d8c148SLen Brown 			fprintf(outf,
2046710f273bSLen Brown 				"%d * %.1f = %.1f MHz max turbo %d active cores\n",
2047cbf97abaSHubert Chrzaniuk 				ratio[i], bclk, ratio[i] * bclk, cores[i]);
2048fb5d4327SDasaratharaman Chandramouli }
2049fb5d4327SDasaratharaman Chandramouli 
2050fb5d4327SDasaratharaman Chandramouli static void
2051fcd17211SLen Brown dump_nhm_cst_cfg(void)
2052fcd17211SLen Brown {
2053fcd17211SLen Brown 	unsigned long long msr;
2054fcd17211SLen Brown 
20551df2e55aSLen Brown 	get_msr(base_cpu, MSR_PKG_CST_CONFIG_CONTROL, &msr);
2056fcd17211SLen Brown 
2057fcd17211SLen Brown #define SNB_C1_AUTO_UNDEMOTE              (1UL << 27)
2058fcd17211SLen Brown #define SNB_C3_AUTO_UNDEMOTE              (1UL << 28)
2059fcd17211SLen Brown 
20601df2e55aSLen Brown 	fprintf(outf, "cpu%d: MSR_PKG_CST_CONFIG_CONTROL: 0x%08llx", base_cpu, msr);
2061fcd17211SLen Brown 
2062b7d8c148SLen Brown 	fprintf(outf, " (%s%s%s%s%slocked: pkg-cstate-limit=%d: %s)\n",
2063fcd17211SLen Brown 		(msr & SNB_C3_AUTO_UNDEMOTE) ? "UNdemote-C3, " : "",
2064fcd17211SLen Brown 		(msr & SNB_C1_AUTO_UNDEMOTE) ? "UNdemote-C1, " : "",
2065fcd17211SLen Brown 		(msr & NHM_C3_AUTO_DEMOTE) ? "demote-C3, " : "",
2066fcd17211SLen Brown 		(msr & NHM_C1_AUTO_DEMOTE) ? "demote-C1, " : "",
2067fcd17211SLen Brown 		(msr & (1 << 15)) ? "" : "UN",
20686c34f160SLen Brown 		(unsigned int)msr & 0xF,
2069fcd17211SLen Brown 		pkg_cstate_limit_strings[pkg_cstate_limit]);
2070fcd17211SLen Brown 	return;
2071103a8feaSLen Brown }
2072103a8feaSLen Brown 
20736fb3143bSLen Brown static void
20746fb3143bSLen Brown dump_config_tdp(void)
20756fb3143bSLen Brown {
20766fb3143bSLen Brown 	unsigned long long msr;
20776fb3143bSLen Brown 
20786fb3143bSLen Brown 	get_msr(base_cpu, MSR_CONFIG_TDP_NOMINAL, &msr);
2079b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_CONFIG_TDP_NOMINAL: 0x%08llx", base_cpu, msr);
2080685b535bSChen Yu 	fprintf(outf, " (base_ratio=%d)\n", (unsigned int)msr & 0xFF);
20816fb3143bSLen Brown 
20826fb3143bSLen Brown 	get_msr(base_cpu, MSR_CONFIG_TDP_LEVEL_1, &msr);
2083b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_CONFIG_TDP_LEVEL_1: 0x%08llx (", base_cpu, msr);
20846fb3143bSLen Brown 	if (msr) {
2085685b535bSChen Yu 		fprintf(outf, "PKG_MIN_PWR_LVL1=%d ", (unsigned int)(msr >> 48) & 0x7FFF);
2086685b535bSChen Yu 		fprintf(outf, "PKG_MAX_PWR_LVL1=%d ", (unsigned int)(msr >> 32) & 0x7FFF);
2087685b535bSChen Yu 		fprintf(outf, "LVL1_RATIO=%d ", (unsigned int)(msr >> 16) & 0xFF);
2088685b535bSChen Yu 		fprintf(outf, "PKG_TDP_LVL1=%d", (unsigned int)(msr) & 0x7FFF);
20896fb3143bSLen Brown 	}
2090b7d8c148SLen Brown 	fprintf(outf, ")\n");
20916fb3143bSLen Brown 
20926fb3143bSLen Brown 	get_msr(base_cpu, MSR_CONFIG_TDP_LEVEL_2, &msr);
2093b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_CONFIG_TDP_LEVEL_2: 0x%08llx (", base_cpu, msr);
20946fb3143bSLen Brown 	if (msr) {
2095685b535bSChen Yu 		fprintf(outf, "PKG_MIN_PWR_LVL2=%d ", (unsigned int)(msr >> 48) & 0x7FFF);
2096685b535bSChen Yu 		fprintf(outf, "PKG_MAX_PWR_LVL2=%d ", (unsigned int)(msr >> 32) & 0x7FFF);
2097685b535bSChen Yu 		fprintf(outf, "LVL2_RATIO=%d ", (unsigned int)(msr >> 16) & 0xFF);
2098685b535bSChen Yu 		fprintf(outf, "PKG_TDP_LVL2=%d", (unsigned int)(msr) & 0x7FFF);
20996fb3143bSLen Brown 	}
2100b7d8c148SLen Brown 	fprintf(outf, ")\n");
21016fb3143bSLen Brown 
21026fb3143bSLen Brown 	get_msr(base_cpu, MSR_CONFIG_TDP_CONTROL, &msr);
2103b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_CONFIG_TDP_CONTROL: 0x%08llx (", base_cpu, msr);
21046fb3143bSLen Brown 	if ((msr) & 0x3)
2105b7d8c148SLen Brown 		fprintf(outf, "TDP_LEVEL=%d ", (unsigned int)(msr) & 0x3);
2106b7d8c148SLen Brown 	fprintf(outf, " lock=%d", (unsigned int)(msr >> 31) & 1);
2107b7d8c148SLen Brown 	fprintf(outf, ")\n");
21086fb3143bSLen Brown 
21096fb3143bSLen Brown 	get_msr(base_cpu, MSR_TURBO_ACTIVATION_RATIO, &msr);
2110b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_TURBO_ACTIVATION_RATIO: 0x%08llx (", base_cpu, msr);
2111685b535bSChen Yu 	fprintf(outf, "MAX_NON_TURBO_RATIO=%d", (unsigned int)(msr) & 0xFF);
2112b7d8c148SLen Brown 	fprintf(outf, " lock=%d", (unsigned int)(msr >> 31) & 1);
2113b7d8c148SLen Brown 	fprintf(outf, ")\n");
21146fb3143bSLen Brown }
21155a63426eSLen Brown 
21165a63426eSLen Brown unsigned int irtl_time_units[] = {1, 32, 1024, 32768, 1048576, 33554432, 0, 0 };
21175a63426eSLen Brown 
21185a63426eSLen Brown void print_irtl(void)
21195a63426eSLen Brown {
21205a63426eSLen Brown 	unsigned long long msr;
21215a63426eSLen Brown 
21225a63426eSLen Brown 	get_msr(base_cpu, MSR_PKGC3_IRTL, &msr);
21235a63426eSLen Brown 	fprintf(outf, "cpu%d: MSR_PKGC3_IRTL: 0x%08llx (", base_cpu, msr);
21245a63426eSLen Brown 	fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
21255a63426eSLen Brown 		(msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
21265a63426eSLen Brown 
21275a63426eSLen Brown 	get_msr(base_cpu, MSR_PKGC6_IRTL, &msr);
21285a63426eSLen Brown 	fprintf(outf, "cpu%d: MSR_PKGC6_IRTL: 0x%08llx (", base_cpu, msr);
21295a63426eSLen Brown 	fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
21305a63426eSLen Brown 		(msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
21315a63426eSLen Brown 
21325a63426eSLen Brown 	get_msr(base_cpu, MSR_PKGC7_IRTL, &msr);
21335a63426eSLen Brown 	fprintf(outf, "cpu%d: MSR_PKGC7_IRTL: 0x%08llx (", base_cpu, msr);
21345a63426eSLen Brown 	fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
21355a63426eSLen Brown 		(msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
21365a63426eSLen Brown 
21375a63426eSLen Brown 	if (!do_irtl_hsw)
21385a63426eSLen Brown 		return;
21395a63426eSLen Brown 
21405a63426eSLen Brown 	get_msr(base_cpu, MSR_PKGC8_IRTL, &msr);
21415a63426eSLen Brown 	fprintf(outf, "cpu%d: MSR_PKGC8_IRTL: 0x%08llx (", base_cpu, msr);
21425a63426eSLen Brown 	fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
21435a63426eSLen Brown 		(msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
21445a63426eSLen Brown 
21455a63426eSLen Brown 	get_msr(base_cpu, MSR_PKGC9_IRTL, &msr);
21465a63426eSLen Brown 	fprintf(outf, "cpu%d: MSR_PKGC9_IRTL: 0x%08llx (", base_cpu, msr);
21475a63426eSLen Brown 	fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
21485a63426eSLen Brown 		(msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
21495a63426eSLen Brown 
21505a63426eSLen Brown 	get_msr(base_cpu, MSR_PKGC10_IRTL, &msr);
21515a63426eSLen Brown 	fprintf(outf, "cpu%d: MSR_PKGC10_IRTL: 0x%08llx (", base_cpu, msr);
21525a63426eSLen Brown 	fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
21535a63426eSLen Brown 		(msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
21545a63426eSLen Brown 
21555a63426eSLen Brown }
215636229897SLen Brown void free_fd_percpu(void)
215736229897SLen Brown {
215836229897SLen Brown 	int i;
215936229897SLen Brown 
216001a67adfSMika Westerberg 	for (i = 0; i < topo.max_cpu_num + 1; ++i) {
216136229897SLen Brown 		if (fd_percpu[i] != 0)
216236229897SLen Brown 			close(fd_percpu[i]);
216336229897SLen Brown 	}
216436229897SLen Brown 
216536229897SLen Brown 	free(fd_percpu);
21666fb3143bSLen Brown }
21676fb3143bSLen Brown 
2168c98d5d94SLen Brown void free_all_buffers(void)
2169103a8feaSLen Brown {
2170c98d5d94SLen Brown 	CPU_FREE(cpu_present_set);
2171c98d5d94SLen Brown 	cpu_present_set = NULL;
217236229897SLen Brown 	cpu_present_setsize = 0;
2173103a8feaSLen Brown 
2174c98d5d94SLen Brown 	CPU_FREE(cpu_affinity_set);
2175c98d5d94SLen Brown 	cpu_affinity_set = NULL;
2176c98d5d94SLen Brown 	cpu_affinity_setsize = 0;
2177103a8feaSLen Brown 
2178c98d5d94SLen Brown 	free(thread_even);
2179c98d5d94SLen Brown 	free(core_even);
2180c98d5d94SLen Brown 	free(package_even);
2181103a8feaSLen Brown 
2182c98d5d94SLen Brown 	thread_even = NULL;
2183c98d5d94SLen Brown 	core_even = NULL;
2184c98d5d94SLen Brown 	package_even = NULL;
2185103a8feaSLen Brown 
2186c98d5d94SLen Brown 	free(thread_odd);
2187c98d5d94SLen Brown 	free(core_odd);
2188c98d5d94SLen Brown 	free(package_odd);
2189103a8feaSLen Brown 
2190c98d5d94SLen Brown 	thread_odd = NULL;
2191c98d5d94SLen Brown 	core_odd = NULL;
2192c98d5d94SLen Brown 	package_odd = NULL;
2193103a8feaSLen Brown 
2194c98d5d94SLen Brown 	free(output_buffer);
2195c98d5d94SLen Brown 	output_buffer = NULL;
2196c98d5d94SLen Brown 	outp = NULL;
219736229897SLen Brown 
219836229897SLen Brown 	free_fd_percpu();
2199562a2d37SLen Brown 
2200562a2d37SLen Brown 	free(irq_column_2_cpu);
2201562a2d37SLen Brown 	free(irqs_per_cpu);
2202103a8feaSLen Brown }
2203103a8feaSLen Brown 
220457a42a34SJosh Triplett 
220557a42a34SJosh Triplett /*
220695aebc44SJosh Triplett  * Parse a file containing a single int.
220795aebc44SJosh Triplett  */
220895aebc44SJosh Triplett int parse_int_file(const char *fmt, ...)
220995aebc44SJosh Triplett {
221095aebc44SJosh Triplett 	va_list args;
221195aebc44SJosh Triplett 	char path[PATH_MAX];
221295aebc44SJosh Triplett 	FILE *filep;
221395aebc44SJosh Triplett 	int value;
221495aebc44SJosh Triplett 
221595aebc44SJosh Triplett 	va_start(args, fmt);
221695aebc44SJosh Triplett 	vsnprintf(path, sizeof(path), fmt, args);
221795aebc44SJosh Triplett 	va_end(args);
221857a42a34SJosh Triplett 	filep = fopen_or_die(path, "r");
2219b2c95d90SJosh Triplett 	if (fscanf(filep, "%d", &value) != 1)
2220b2c95d90SJosh Triplett 		err(1, "%s: failed to parse number from file", path);
222195aebc44SJosh Triplett 	fclose(filep);
222295aebc44SJosh Triplett 	return value;
222395aebc44SJosh Triplett }
222495aebc44SJosh Triplett 
222595aebc44SJosh Triplett /*
2226e275b388SDasaratharaman Chandramouli  * get_cpu_position_in_core(cpu)
2227e275b388SDasaratharaman Chandramouli  * return the position of the CPU among its HT siblings in the core
2228e275b388SDasaratharaman Chandramouli  * return -1 if the sibling is not in list
2229103a8feaSLen Brown  */
2230e275b388SDasaratharaman Chandramouli int get_cpu_position_in_core(int cpu)
2231103a8feaSLen Brown {
2232e275b388SDasaratharaman Chandramouli 	char path[64];
2233e275b388SDasaratharaman Chandramouli 	FILE *filep;
2234e275b388SDasaratharaman Chandramouli 	int this_cpu;
2235e275b388SDasaratharaman Chandramouli 	char character;
2236e275b388SDasaratharaman Chandramouli 	int i;
2237e275b388SDasaratharaman Chandramouli 
2238e275b388SDasaratharaman Chandramouli 	sprintf(path,
2239e275b388SDasaratharaman Chandramouli 		"/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list",
2240e275b388SDasaratharaman Chandramouli 		cpu);
2241e275b388SDasaratharaman Chandramouli 	filep = fopen(path, "r");
2242e275b388SDasaratharaman Chandramouli 	if (filep == NULL) {
2243e275b388SDasaratharaman Chandramouli 		perror(path);
2244e275b388SDasaratharaman Chandramouli 		exit(1);
2245e275b388SDasaratharaman Chandramouli 	}
2246e275b388SDasaratharaman Chandramouli 
2247e275b388SDasaratharaman Chandramouli 	for (i = 0; i < topo.num_threads_per_core; i++) {
2248e275b388SDasaratharaman Chandramouli 		fscanf(filep, "%d", &this_cpu);
2249e275b388SDasaratharaman Chandramouli 		if (this_cpu == cpu) {
2250e275b388SDasaratharaman Chandramouli 			fclose(filep);
2251e275b388SDasaratharaman Chandramouli 			return i;
2252e275b388SDasaratharaman Chandramouli 		}
2253e275b388SDasaratharaman Chandramouli 
2254e275b388SDasaratharaman Chandramouli 		/* Account for no separator after last thread*/
2255e275b388SDasaratharaman Chandramouli 		if (i != (topo.num_threads_per_core - 1))
2256e275b388SDasaratharaman Chandramouli 			fscanf(filep, "%c", &character);
2257e275b388SDasaratharaman Chandramouli 	}
2258e275b388SDasaratharaman Chandramouli 
2259e275b388SDasaratharaman Chandramouli 	fclose(filep);
2260e275b388SDasaratharaman Chandramouli 	return -1;
2261c98d5d94SLen Brown }
2262103a8feaSLen Brown 
2263c98d5d94SLen Brown /*
2264c98d5d94SLen Brown  * cpu_is_first_core_in_package(cpu)
2265c98d5d94SLen Brown  * return 1 if given CPU is 1st core in package
2266c98d5d94SLen Brown  */
2267c98d5d94SLen Brown int cpu_is_first_core_in_package(int cpu)
2268c98d5d94SLen Brown {
226995aebc44SJosh Triplett 	return cpu == parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", cpu);
2270103a8feaSLen Brown }
2271103a8feaSLen Brown 
2272103a8feaSLen Brown int get_physical_package_id(int cpu)
2273103a8feaSLen Brown {
227495aebc44SJosh Triplett 	return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu);
2275103a8feaSLen Brown }
2276103a8feaSLen Brown 
2277103a8feaSLen Brown int get_core_id(int cpu)
2278103a8feaSLen Brown {
227995aebc44SJosh Triplett 	return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_id", cpu);
2280103a8feaSLen Brown }
2281103a8feaSLen Brown 
2282c98d5d94SLen Brown int get_num_ht_siblings(int cpu)
2283c98d5d94SLen Brown {
2284c98d5d94SLen Brown 	char path[80];
2285c98d5d94SLen Brown 	FILE *filep;
2286e275b388SDasaratharaman Chandramouli 	int sib1;
2287e275b388SDasaratharaman Chandramouli 	int matches = 0;
2288c98d5d94SLen Brown 	char character;
2289e275b388SDasaratharaman Chandramouli 	char str[100];
2290e275b388SDasaratharaman Chandramouli 	char *ch;
2291c98d5d94SLen Brown 
2292c98d5d94SLen Brown 	sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu);
229357a42a34SJosh Triplett 	filep = fopen_or_die(path, "r");
2294e275b388SDasaratharaman Chandramouli 
2295103a8feaSLen Brown 	/*
2296c98d5d94SLen Brown 	 * file format:
2297e275b388SDasaratharaman Chandramouli 	 * A ',' separated or '-' separated set of numbers
2298e275b388SDasaratharaman Chandramouli 	 * (eg 1-2 or 1,3,4,5)
2299c98d5d94SLen Brown 	 */
2300e275b388SDasaratharaman Chandramouli 	fscanf(filep, "%d%c\n", &sib1, &character);
2301e275b388SDasaratharaman Chandramouli 	fseek(filep, 0, SEEK_SET);
2302e275b388SDasaratharaman Chandramouli 	fgets(str, 100, filep);
2303e275b388SDasaratharaman Chandramouli 	ch = strchr(str, character);
2304e275b388SDasaratharaman Chandramouli 	while (ch != NULL) {
2305e275b388SDasaratharaman Chandramouli 		matches++;
2306e275b388SDasaratharaman Chandramouli 		ch = strchr(ch+1, character);
2307e275b388SDasaratharaman Chandramouli 	}
2308c98d5d94SLen Brown 
2309c98d5d94SLen Brown 	fclose(filep);
2310e275b388SDasaratharaman Chandramouli 	return matches+1;
2311c98d5d94SLen Brown }
2312c98d5d94SLen Brown 
2313c98d5d94SLen Brown /*
2314c98d5d94SLen Brown  * run func(thread, core, package) in topology order
2315c98d5d94SLen Brown  * skip non-present cpus
2316103a8feaSLen Brown  */
2317103a8feaSLen Brown 
2318c98d5d94SLen Brown int for_all_cpus_2(int (func)(struct thread_data *, struct core_data *,
2319c98d5d94SLen Brown 	struct pkg_data *, struct thread_data *, struct core_data *,
2320c98d5d94SLen Brown 	struct pkg_data *), struct thread_data *thread_base,
2321c98d5d94SLen Brown 	struct core_data *core_base, struct pkg_data *pkg_base,
2322c98d5d94SLen Brown 	struct thread_data *thread_base2, struct core_data *core_base2,
2323c98d5d94SLen Brown 	struct pkg_data *pkg_base2)
2324c98d5d94SLen Brown {
2325c98d5d94SLen Brown 	int retval, pkg_no, core_no, thread_no;
2326c98d5d94SLen Brown 
2327c98d5d94SLen Brown 	for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) {
2328c98d5d94SLen Brown 		for (core_no = 0; core_no < topo.num_cores_per_pkg; ++core_no) {
2329c98d5d94SLen Brown 			for (thread_no = 0; thread_no <
2330c98d5d94SLen Brown 				topo.num_threads_per_core; ++thread_no) {
2331c98d5d94SLen Brown 				struct thread_data *t, *t2;
2332c98d5d94SLen Brown 				struct core_data *c, *c2;
2333c98d5d94SLen Brown 				struct pkg_data *p, *p2;
2334c98d5d94SLen Brown 
2335c98d5d94SLen Brown 				t = GET_THREAD(thread_base, thread_no, core_no, pkg_no);
2336c98d5d94SLen Brown 
2337c98d5d94SLen Brown 				if (cpu_is_not_present(t->cpu_id))
2338c98d5d94SLen Brown 					continue;
2339c98d5d94SLen Brown 
2340c98d5d94SLen Brown 				t2 = GET_THREAD(thread_base2, thread_no, core_no, pkg_no);
2341c98d5d94SLen Brown 
2342c98d5d94SLen Brown 				c = GET_CORE(core_base, core_no, pkg_no);
2343c98d5d94SLen Brown 				c2 = GET_CORE(core_base2, core_no, pkg_no);
2344c98d5d94SLen Brown 
2345c98d5d94SLen Brown 				p = GET_PKG(pkg_base, pkg_no);
2346c98d5d94SLen Brown 				p2 = GET_PKG(pkg_base2, pkg_no);
2347c98d5d94SLen Brown 
2348c98d5d94SLen Brown 				retval = func(t, c, p, t2, c2, p2);
2349c98d5d94SLen Brown 				if (retval)
2350c98d5d94SLen Brown 					return retval;
2351c98d5d94SLen Brown 			}
2352c98d5d94SLen Brown 		}
2353c98d5d94SLen Brown 	}
2354c98d5d94SLen Brown 	return 0;
2355c98d5d94SLen Brown }
2356c98d5d94SLen Brown 
2357c98d5d94SLen Brown /*
2358c98d5d94SLen Brown  * run func(cpu) on every cpu in /proc/stat
2359c98d5d94SLen Brown  * return max_cpu number
2360c98d5d94SLen Brown  */
2361c98d5d94SLen Brown int for_all_proc_cpus(int (func)(int))
2362103a8feaSLen Brown {
2363103a8feaSLen Brown 	FILE *fp;
2364c98d5d94SLen Brown 	int cpu_num;
2365103a8feaSLen Brown 	int retval;
2366103a8feaSLen Brown 
236757a42a34SJosh Triplett 	fp = fopen_or_die(proc_stat, "r");
2368103a8feaSLen Brown 
2369103a8feaSLen Brown 	retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n");
2370b2c95d90SJosh Triplett 	if (retval != 0)
2371b2c95d90SJosh Triplett 		err(1, "%s: failed to parse format", proc_stat);
2372103a8feaSLen Brown 
2373c98d5d94SLen Brown 	while (1) {
2374c98d5d94SLen Brown 		retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num);
2375103a8feaSLen Brown 		if (retval != 1)
2376103a8feaSLen Brown 			break;
2377103a8feaSLen Brown 
2378c98d5d94SLen Brown 		retval = func(cpu_num);
2379c98d5d94SLen Brown 		if (retval) {
2380c98d5d94SLen Brown 			fclose(fp);
2381c98d5d94SLen Brown 			return(retval);
2382c98d5d94SLen Brown 		}
2383103a8feaSLen Brown 	}
2384103a8feaSLen Brown 	fclose(fp);
2385c98d5d94SLen Brown 	return 0;
2386103a8feaSLen Brown }
2387103a8feaSLen Brown 
2388103a8feaSLen Brown void re_initialize(void)
2389103a8feaSLen Brown {
2390c98d5d94SLen Brown 	free_all_buffers();
2391c98d5d94SLen Brown 	setup_all_buffers();
2392c98d5d94SLen Brown 	printf("turbostat: re-initialized with num_cpus %d\n", topo.num_cpus);
2393103a8feaSLen Brown }
2394103a8feaSLen Brown 
2395c98d5d94SLen Brown 
2396103a8feaSLen Brown /*
2397c98d5d94SLen Brown  * count_cpus()
2398c98d5d94SLen Brown  * remember the last one seen, it will be the max
2399103a8feaSLen Brown  */
2400c98d5d94SLen Brown int count_cpus(int cpu)
2401103a8feaSLen Brown {
2402c98d5d94SLen Brown 	if (topo.max_cpu_num < cpu)
2403c98d5d94SLen Brown 		topo.max_cpu_num = cpu;
2404103a8feaSLen Brown 
2405c98d5d94SLen Brown 	topo.num_cpus += 1;
2406c98d5d94SLen Brown 	return 0;
2407103a8feaSLen Brown }
2408c98d5d94SLen Brown int mark_cpu_present(int cpu)
2409c98d5d94SLen Brown {
2410c98d5d94SLen Brown 	CPU_SET_S(cpu, cpu_present_setsize, cpu_present_set);
241115aaa346SLen Brown 	return 0;
2412103a8feaSLen Brown }
2413103a8feaSLen Brown 
2414562a2d37SLen Brown /*
2415562a2d37SLen Brown  * snapshot_proc_interrupts()
2416562a2d37SLen Brown  *
2417562a2d37SLen Brown  * read and record summary of /proc/interrupts
2418562a2d37SLen Brown  *
2419562a2d37SLen Brown  * return 1 if config change requires a restart, else return 0
2420562a2d37SLen Brown  */
2421562a2d37SLen Brown int snapshot_proc_interrupts(void)
2422562a2d37SLen Brown {
2423562a2d37SLen Brown 	static FILE *fp;
2424562a2d37SLen Brown 	int column, retval;
2425562a2d37SLen Brown 
2426562a2d37SLen Brown 	if (fp == NULL)
2427562a2d37SLen Brown 		fp = fopen_or_die("/proc/interrupts", "r");
2428562a2d37SLen Brown 	else
2429562a2d37SLen Brown 		rewind(fp);
2430562a2d37SLen Brown 
2431562a2d37SLen Brown 	/* read 1st line of /proc/interrupts to get cpu* name for each column */
2432562a2d37SLen Brown 	for (column = 0; column < topo.num_cpus; ++column) {
2433562a2d37SLen Brown 		int cpu_number;
2434562a2d37SLen Brown 
2435562a2d37SLen Brown 		retval = fscanf(fp, " CPU%d", &cpu_number);
2436562a2d37SLen Brown 		if (retval != 1)
2437562a2d37SLen Brown 			break;
2438562a2d37SLen Brown 
2439562a2d37SLen Brown 		if (cpu_number > topo.max_cpu_num) {
2440562a2d37SLen Brown 			warn("/proc/interrupts: cpu%d: > %d", cpu_number, topo.max_cpu_num);
2441562a2d37SLen Brown 			return 1;
2442562a2d37SLen Brown 		}
2443562a2d37SLen Brown 
2444562a2d37SLen Brown 		irq_column_2_cpu[column] = cpu_number;
2445562a2d37SLen Brown 		irqs_per_cpu[cpu_number] = 0;
2446562a2d37SLen Brown 	}
2447562a2d37SLen Brown 
2448562a2d37SLen Brown 	/* read /proc/interrupt count lines and sum up irqs per cpu */
2449562a2d37SLen Brown 	while (1) {
2450562a2d37SLen Brown 		int column;
2451562a2d37SLen Brown 		char buf[64];
2452562a2d37SLen Brown 
2453562a2d37SLen Brown 		retval = fscanf(fp, " %s:", buf);	/* flush irq# "N:" */
2454562a2d37SLen Brown 		if (retval != 1)
2455562a2d37SLen Brown 			break;
2456562a2d37SLen Brown 
2457562a2d37SLen Brown 		/* read the count per cpu */
2458562a2d37SLen Brown 		for (column = 0; column < topo.num_cpus; ++column) {
2459562a2d37SLen Brown 
2460562a2d37SLen Brown 			int cpu_number, irq_count;
2461562a2d37SLen Brown 
2462562a2d37SLen Brown 			retval = fscanf(fp, " %d", &irq_count);
2463562a2d37SLen Brown 			if (retval != 1)
2464562a2d37SLen Brown 				break;
2465562a2d37SLen Brown 
2466562a2d37SLen Brown 			cpu_number = irq_column_2_cpu[column];
2467562a2d37SLen Brown 			irqs_per_cpu[cpu_number] += irq_count;
2468562a2d37SLen Brown 
2469562a2d37SLen Brown 		}
2470562a2d37SLen Brown 
2471562a2d37SLen Brown 		while (getc(fp) != '\n')
2472562a2d37SLen Brown 			;	/* flush interrupt description */
2473562a2d37SLen Brown 
2474562a2d37SLen Brown 	}
2475562a2d37SLen Brown 	return 0;
2476562a2d37SLen Brown }
247727d47356SLen Brown /*
2478fdf676e5SLen Brown  * snapshot_gfx_rc6_ms()
2479fdf676e5SLen Brown  *
2480fdf676e5SLen Brown  * record snapshot of
2481fdf676e5SLen Brown  * /sys/class/drm/card0/power/rc6_residency_ms
2482fdf676e5SLen Brown  *
2483fdf676e5SLen Brown  * return 1 if config change requires a restart, else return 0
2484fdf676e5SLen Brown  */
2485fdf676e5SLen Brown int snapshot_gfx_rc6_ms(void)
2486fdf676e5SLen Brown {
2487fdf676e5SLen Brown 	FILE *fp;
2488fdf676e5SLen Brown 	int retval;
2489fdf676e5SLen Brown 
2490fdf676e5SLen Brown 	fp = fopen_or_die("/sys/class/drm/card0/power/rc6_residency_ms", "r");
2491fdf676e5SLen Brown 
2492fdf676e5SLen Brown 	retval = fscanf(fp, "%lld", &gfx_cur_rc6_ms);
2493fdf676e5SLen Brown 	if (retval != 1)
2494fdf676e5SLen Brown 		err(1, "GFX rc6");
2495fdf676e5SLen Brown 
2496fdf676e5SLen Brown 	fclose(fp);
2497fdf676e5SLen Brown 
2498fdf676e5SLen Brown 	return 0;
2499fdf676e5SLen Brown }
2500fdf676e5SLen Brown /*
250127d47356SLen Brown  * snapshot_gfx_mhz()
250227d47356SLen Brown  *
250327d47356SLen Brown  * record snapshot of
250427d47356SLen Brown  * /sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz
250527d47356SLen Brown  *
250627d47356SLen Brown  * return 1 if config change requires a restart, else return 0
250727d47356SLen Brown  */
250827d47356SLen Brown int snapshot_gfx_mhz(void)
250927d47356SLen Brown {
251027d47356SLen Brown 	static FILE *fp;
251127d47356SLen Brown 	int retval;
251227d47356SLen Brown 
251327d47356SLen Brown 	if (fp == NULL)
251427d47356SLen Brown 		fp = fopen_or_die("/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz", "r");
251522048c54SLen Brown 	else {
251627d47356SLen Brown 		rewind(fp);
251722048c54SLen Brown 		fflush(fp);
251822048c54SLen Brown 	}
251927d47356SLen Brown 
252027d47356SLen Brown 	retval = fscanf(fp, "%d", &gfx_cur_mhz);
252127d47356SLen Brown 	if (retval != 1)
252227d47356SLen Brown 		err(1, "GFX MHz");
252327d47356SLen Brown 
252427d47356SLen Brown 	return 0;
252527d47356SLen Brown }
2526562a2d37SLen Brown 
2527562a2d37SLen Brown /*
2528562a2d37SLen Brown  * snapshot /proc and /sys files
2529562a2d37SLen Brown  *
2530562a2d37SLen Brown  * return 1 if configuration restart needed, else return 0
2531562a2d37SLen Brown  */
2532562a2d37SLen Brown int snapshot_proc_sysfs_files(void)
2533562a2d37SLen Brown {
2534218f0e8dSLen Brown 	if (DO_BIC(BIC_IRQ))
2535562a2d37SLen Brown 		if (snapshot_proc_interrupts())
2536562a2d37SLen Brown 			return 1;
2537562a2d37SLen Brown 
2538812db3f7SLen Brown 	if (DO_BIC(BIC_GFX_rc6))
2539fdf676e5SLen Brown 		snapshot_gfx_rc6_ms();
2540fdf676e5SLen Brown 
2541812db3f7SLen Brown 	if (DO_BIC(BIC_GFXMHz))
254227d47356SLen Brown 		snapshot_gfx_mhz();
254327d47356SLen Brown 
2544562a2d37SLen Brown 	return 0;
2545562a2d37SLen Brown }
2546562a2d37SLen Brown 
2547103a8feaSLen Brown void turbostat_loop()
2548103a8feaSLen Brown {
2549c98d5d94SLen Brown 	int retval;
2550e52966c0SLen Brown 	int restarted = 0;
2551c98d5d94SLen Brown 
2552103a8feaSLen Brown restart:
2553e52966c0SLen Brown 	restarted++;
2554e52966c0SLen Brown 
2555562a2d37SLen Brown 	snapshot_proc_sysfs_files();
2556c98d5d94SLen Brown 	retval = for_all_cpus(get_counters, EVEN_COUNTERS);
2557d91bb17cSLen Brown 	if (retval < -1) {
2558d91bb17cSLen Brown 		exit(retval);
2559d91bb17cSLen Brown 	} else if (retval == -1) {
2560e52966c0SLen Brown 		if (restarted > 1) {
2561e52966c0SLen Brown 			exit(retval);
2562e52966c0SLen Brown 		}
2563c98d5d94SLen Brown 		re_initialize();
2564c98d5d94SLen Brown 		goto restart;
2565c98d5d94SLen Brown 	}
2566e52966c0SLen Brown 	restarted = 0;
2567103a8feaSLen Brown 	gettimeofday(&tv_even, (struct timezone *)NULL);
2568103a8feaSLen Brown 
2569103a8feaSLen Brown 	while (1) {
2570c98d5d94SLen Brown 		if (for_all_proc_cpus(cpu_is_not_present)) {
2571103a8feaSLen Brown 			re_initialize();
2572103a8feaSLen Brown 			goto restart;
2573103a8feaSLen Brown 		}
25742a0609c0SLen Brown 		nanosleep(&interval_ts, NULL);
2575562a2d37SLen Brown 		if (snapshot_proc_sysfs_files())
2576562a2d37SLen Brown 			goto restart;
2577c98d5d94SLen Brown 		retval = for_all_cpus(get_counters, ODD_COUNTERS);
2578d91bb17cSLen Brown 		if (retval < -1) {
2579d91bb17cSLen Brown 			exit(retval);
2580d91bb17cSLen Brown 		} else if (retval == -1) {
258115aaa346SLen Brown 			re_initialize();
258215aaa346SLen Brown 			goto restart;
258315aaa346SLen Brown 		}
2584103a8feaSLen Brown 		gettimeofday(&tv_odd, (struct timezone *)NULL);
2585103a8feaSLen Brown 		timersub(&tv_odd, &tv_even, &tv_delta);
2586ba3dec99SLen Brown 		if (for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS)) {
2587ba3dec99SLen Brown 			re_initialize();
2588ba3dec99SLen Brown 			goto restart;
2589ba3dec99SLen Brown 		}
2590c98d5d94SLen Brown 		compute_average(EVEN_COUNTERS);
2591c98d5d94SLen Brown 		format_all_counters(EVEN_COUNTERS);
2592b7d8c148SLen Brown 		flush_output_stdout();
25932a0609c0SLen Brown 		nanosleep(&interval_ts, NULL);
2594562a2d37SLen Brown 		if (snapshot_proc_sysfs_files())
2595562a2d37SLen Brown 			goto restart;
2596c98d5d94SLen Brown 		retval = for_all_cpus(get_counters, EVEN_COUNTERS);
2597d91bb17cSLen Brown 		if (retval < -1) {
2598d91bb17cSLen Brown 			exit(retval);
2599d91bb17cSLen Brown 		} else if (retval == -1) {
2600103a8feaSLen Brown 			re_initialize();
2601103a8feaSLen Brown 			goto restart;
2602103a8feaSLen Brown 		}
2603103a8feaSLen Brown 		gettimeofday(&tv_even, (struct timezone *)NULL);
2604103a8feaSLen Brown 		timersub(&tv_even, &tv_odd, &tv_delta);
2605ba3dec99SLen Brown 		if (for_all_cpus_2(delta_cpu, EVEN_COUNTERS, ODD_COUNTERS)) {
2606ba3dec99SLen Brown 			re_initialize();
2607ba3dec99SLen Brown 			goto restart;
2608ba3dec99SLen Brown 		}
2609c98d5d94SLen Brown 		compute_average(ODD_COUNTERS);
2610c98d5d94SLen Brown 		format_all_counters(ODD_COUNTERS);
2611b7d8c148SLen Brown 		flush_output_stdout();
2612103a8feaSLen Brown 	}
2613103a8feaSLen Brown }
2614103a8feaSLen Brown 
2615103a8feaSLen Brown void check_dev_msr()
2616103a8feaSLen Brown {
2617103a8feaSLen Brown 	struct stat sb;
26187ce7d5deSPrarit Bhargava 	char pathname[32];
2619103a8feaSLen Brown 
26207ce7d5deSPrarit Bhargava 	sprintf(pathname, "/dev/cpu/%d/msr", base_cpu);
26217ce7d5deSPrarit Bhargava 	if (stat(pathname, &sb))
2622a21d38c8SLen Brown  		if (system("/sbin/modprobe msr > /dev/null 2>&1"))
2623d7899447SLen Brown 			err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" ");
2624103a8feaSLen Brown }
2625103a8feaSLen Brown 
262698481e79SLen Brown void check_permissions()
2627103a8feaSLen Brown {
262898481e79SLen Brown 	struct __user_cap_header_struct cap_header_data;
262998481e79SLen Brown 	cap_user_header_t cap_header = &cap_header_data;
263098481e79SLen Brown 	struct __user_cap_data_struct cap_data_data;
263198481e79SLen Brown 	cap_user_data_t cap_data = &cap_data_data;
263298481e79SLen Brown 	extern int capget(cap_user_header_t hdrp, cap_user_data_t datap);
263398481e79SLen Brown 	int do_exit = 0;
26347ce7d5deSPrarit Bhargava 	char pathname[32];
263598481e79SLen Brown 
263698481e79SLen Brown 	/* check for CAP_SYS_RAWIO */
263798481e79SLen Brown 	cap_header->pid = getpid();
263898481e79SLen Brown 	cap_header->version = _LINUX_CAPABILITY_VERSION;
263998481e79SLen Brown 	if (capget(cap_header, cap_data) < 0)
264098481e79SLen Brown 		err(-6, "capget(2) failed");
264198481e79SLen Brown 
264298481e79SLen Brown 	if ((cap_data->effective & (1 << CAP_SYS_RAWIO)) == 0) {
264398481e79SLen Brown 		do_exit++;
264498481e79SLen Brown 		warnx("capget(CAP_SYS_RAWIO) failed,"
264598481e79SLen Brown 			" try \"# setcap cap_sys_rawio=ep %s\"", progname);
264698481e79SLen Brown 	}
264798481e79SLen Brown 
264898481e79SLen Brown 	/* test file permissions */
26497ce7d5deSPrarit Bhargava 	sprintf(pathname, "/dev/cpu/%d/msr", base_cpu);
26507ce7d5deSPrarit Bhargava 	if (euidaccess(pathname, R_OK)) {
265198481e79SLen Brown 		do_exit++;
265298481e79SLen Brown 		warn("/dev/cpu/0/msr open failed, try chown or chmod +r /dev/cpu/*/msr");
265398481e79SLen Brown 	}
265498481e79SLen Brown 
265598481e79SLen Brown 	/* if all else fails, thell them to be root */
265698481e79SLen Brown 	if (do_exit)
2657b2c95d90SJosh Triplett 		if (getuid() != 0)
2658d7899447SLen Brown 			warnx("... or simply run as root");
265998481e79SLen Brown 
266098481e79SLen Brown 	if (do_exit)
266198481e79SLen Brown 		exit(-6);
2662103a8feaSLen Brown }
2663103a8feaSLen Brown 
2664d7899447SLen Brown /*
2665d7899447SLen Brown  * NHM adds support for additional MSRs:
2666d7899447SLen Brown  *
2667d7899447SLen Brown  * MSR_SMI_COUNT                   0x00000034
2668d7899447SLen Brown  *
2669ec0adc53SLen Brown  * MSR_PLATFORM_INFO               0x000000ce
26701df2e55aSLen Brown  * MSR_PKG_CST_CONFIG_CONTROL     0x000000e2
2671d7899447SLen Brown  *
2672cf4cbe53SLen Brown  * MSR_MISC_PWR_MGMT               0x000001aa
2673cf4cbe53SLen Brown  *
2674d7899447SLen Brown  * MSR_PKG_C3_RESIDENCY            0x000003f8
2675d7899447SLen Brown  * MSR_PKG_C6_RESIDENCY            0x000003f9
2676d7899447SLen Brown  * MSR_CORE_C3_RESIDENCY           0x000003fc
2677d7899447SLen Brown  * MSR_CORE_C6_RESIDENCY           0x000003fd
2678d7899447SLen Brown  *
2679ee7e38e3SLen Brown  * Side effect:
26801df2e55aSLen Brown  * sets global pkg_cstate_limit to decode MSR_PKG_CST_CONFIG_CONTROL
268133148d67SLen Brown  * sets has_misc_feature_control
2682d7899447SLen Brown  */
2683ee7e38e3SLen Brown int probe_nhm_msrs(unsigned int family, unsigned int model)
2684103a8feaSLen Brown {
2685ee7e38e3SLen Brown 	unsigned long long msr;
268621ed5574SLen Brown 	unsigned int base_ratio;
2687ee7e38e3SLen Brown 	int *pkg_cstate_limits;
2688ee7e38e3SLen Brown 
2689103a8feaSLen Brown 	if (!genuine_intel)
2690103a8feaSLen Brown 		return 0;
2691103a8feaSLen Brown 
2692103a8feaSLen Brown 	if (family != 6)
2693103a8feaSLen Brown 		return 0;
2694103a8feaSLen Brown 
269521ed5574SLen Brown 	bclk = discover_bclk(family, model);
269621ed5574SLen Brown 
2697103a8feaSLen Brown 	switch (model) {
2698869ce69eSLen Brown 	case INTEL_FAM6_NEHALEM_EP:	/* Core i7, Xeon 5500 series - Bloomfield, Gainstown NHM-EP */
2699869ce69eSLen Brown 	case INTEL_FAM6_NEHALEM:	/* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */
2700103a8feaSLen Brown 	case 0x1F:	/* Core i7 and i5 Processor - Nehalem */
2701869ce69eSLen Brown 	case INTEL_FAM6_WESTMERE:	/* Westmere Client - Clarkdale, Arrandale */
2702869ce69eSLen Brown 	case INTEL_FAM6_WESTMERE_EP:	/* Westmere EP - Gulftown */
2703869ce69eSLen Brown 	case INTEL_FAM6_NEHALEM_EX:	/* Nehalem-EX Xeon - Beckton */
2704869ce69eSLen Brown 	case INTEL_FAM6_WESTMERE_EX:	/* Westmere-EX Xeon - Eagleton */
2705ee7e38e3SLen Brown 		pkg_cstate_limits = nhm_pkg_cstate_limits;
2706ee7e38e3SLen Brown 		break;
2707869ce69eSLen Brown 	case INTEL_FAM6_SANDYBRIDGE:	/* SNB */
2708869ce69eSLen Brown 	case INTEL_FAM6_SANDYBRIDGE_X:	/* SNB Xeon */
2709869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE:	/* IVB */
2710869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE_X:	/* IVB Xeon */
2711ee7e38e3SLen Brown 		pkg_cstate_limits = snb_pkg_cstate_limits;
271233148d67SLen Brown 		has_misc_feature_control = 1;
2713ee7e38e3SLen Brown 		break;
2714869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
2715869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSX */
2716869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
2717869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
2718869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
2719869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_GT3E:	/* BDW */
2720869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_X:	/* BDX */
2721869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
2722869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
2723869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
2724869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
2725869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
2726ee7e38e3SLen Brown 		pkg_cstate_limits = hsw_pkg_cstate_limits;
272733148d67SLen Brown 		has_misc_feature_control = 1;
2728ee7e38e3SLen Brown 		break;
2729d8ebb442SLen Brown 	case INTEL_FAM6_SKYLAKE_X:	/* SKX */
2730d8ebb442SLen Brown 		pkg_cstate_limits = skx_pkg_cstate_limits;
273133148d67SLen Brown 		has_misc_feature_control = 1;
2732d8ebb442SLen Brown 		break;
2733869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT1:	/* BYT */
2734cf4cbe53SLen Brown 		no_MSR_MISC_PWR_MGMT = 1;
2735869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT2:	/* AVN */
2736ee7e38e3SLen Brown 		pkg_cstate_limits = slv_pkg_cstate_limits;
2737ee7e38e3SLen Brown 		break;
2738869ce69eSLen Brown 	case INTEL_FAM6_ATOM_AIRMONT:	/* AMT */
2739ee7e38e3SLen Brown 		pkg_cstate_limits = amt_pkg_cstate_limits;
2740cf4cbe53SLen Brown 		no_MSR_MISC_PWR_MGMT = 1;
2741ee7e38e3SLen Brown 		break;
2742869ce69eSLen Brown 	case INTEL_FAM6_XEON_PHI_KNL:	/* PHI */
2743005c82d6SLen Brown 	case INTEL_FAM6_XEON_PHI_KNM:
2744ee7e38e3SLen Brown 		pkg_cstate_limits = phi_pkg_cstate_limits;
2745ee7e38e3SLen Brown 		break;
2746869ce69eSLen Brown 	case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
2747ac01ac13SLen Brown 	case INTEL_FAM6_ATOM_GEMINI_LAKE:
2748869ce69eSLen Brown 	case INTEL_FAM6_ATOM_DENVERTON:	/* DNV */
2749e4085d54SLen Brown 		pkg_cstate_limits = bxt_pkg_cstate_limits;
2750e4085d54SLen Brown 		break;
2751103a8feaSLen Brown 	default:
2752103a8feaSLen Brown 		return 0;
2753103a8feaSLen Brown 	}
27541df2e55aSLen Brown 	get_msr(base_cpu, MSR_PKG_CST_CONFIG_CONTROL, &msr);
2755e9257f5fSLen Brown 	pkg_cstate_limit = pkg_cstate_limits[msr & 0xF];
2756ee7e38e3SLen Brown 
2757ec0adc53SLen Brown 	get_msr(base_cpu, MSR_PLATFORM_INFO, &msr);
275821ed5574SLen Brown 	base_ratio = (msr >> 8) & 0xFF;
275921ed5574SLen Brown 
276021ed5574SLen Brown 	base_hz = base_ratio * bclk * 1000000;
276121ed5574SLen Brown 	has_base_hz = 1;
2762ee7e38e3SLen Brown 	return 1;
2763103a8feaSLen Brown }
27640f7887c4SLen Brown /*
2765495c7654SLen Brown  * SLV client has support for unique MSRs:
27660f7887c4SLen Brown  *
27670f7887c4SLen Brown  * MSR_CC6_DEMOTION_POLICY_CONFIG
27680f7887c4SLen Brown  * MSR_MC6_DEMOTION_POLICY_CONFIG
27690f7887c4SLen Brown  */
27700f7887c4SLen Brown 
27710f7887c4SLen Brown int has_slv_msrs(unsigned int family, unsigned int model)
27720f7887c4SLen Brown {
27730f7887c4SLen Brown 	if (!genuine_intel)
27740f7887c4SLen Brown 		return 0;
27750f7887c4SLen Brown 
27760f7887c4SLen Brown 	switch (model) {
27770f7887c4SLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT1:
27780f7887c4SLen Brown 	case INTEL_FAM6_ATOM_MERRIFIELD:
27790f7887c4SLen Brown 	case INTEL_FAM6_ATOM_MOOREFIELD:
27800f7887c4SLen Brown 		return 1;
27810f7887c4SLen Brown 	}
27820f7887c4SLen Brown 	return 0;
27830f7887c4SLen Brown }
27847170a374SLen Brown int is_dnv(unsigned int family, unsigned int model)
27857170a374SLen Brown {
27867170a374SLen Brown 
27877170a374SLen Brown 	if (!genuine_intel)
27887170a374SLen Brown 		return 0;
27897170a374SLen Brown 
27907170a374SLen Brown 	switch (model) {
27917170a374SLen Brown 	case INTEL_FAM6_ATOM_DENVERTON:
27927170a374SLen Brown 		return 1;
27937170a374SLen Brown 	}
27947170a374SLen Brown 	return 0;
27957170a374SLen Brown }
2796ade0ebacSLen Brown int is_bdx(unsigned int family, unsigned int model)
2797ade0ebacSLen Brown {
2798ade0ebacSLen Brown 
2799ade0ebacSLen Brown 	if (!genuine_intel)
2800ade0ebacSLen Brown 		return 0;
2801ade0ebacSLen Brown 
2802ade0ebacSLen Brown 	switch (model) {
2803ade0ebacSLen Brown 	case INTEL_FAM6_BROADWELL_X:
2804ade0ebacSLen Brown 	case INTEL_FAM6_BROADWELL_XEON_D:
2805ade0ebacSLen Brown 		return 1;
2806ade0ebacSLen Brown 	}
2807ade0ebacSLen Brown 	return 0;
2808ade0ebacSLen Brown }
280934c76197SLen Brown int is_skx(unsigned int family, unsigned int model)
281034c76197SLen Brown {
281134c76197SLen Brown 
281234c76197SLen Brown 	if (!genuine_intel)
281334c76197SLen Brown 		return 0;
281434c76197SLen Brown 
281534c76197SLen Brown 	switch (model) {
281634c76197SLen Brown 	case INTEL_FAM6_SKYLAKE_X:
281734c76197SLen Brown 		return 1;
281834c76197SLen Brown 	}
281934c76197SLen Brown 	return 0;
282034c76197SLen Brown }
28210f7887c4SLen Brown 
282231e07522SLen Brown int has_turbo_ratio_limit(unsigned int family, unsigned int model)
2823d7899447SLen Brown {
28240f7887c4SLen Brown 	if (has_slv_msrs(family, model))
28250f7887c4SLen Brown 		return 0;
28260f7887c4SLen Brown 
2827d7899447SLen Brown 	switch (model) {
2828d7899447SLen Brown 	/* Nehalem compatible, but do not include turbo-ratio limit support */
2829869ce69eSLen Brown 	case INTEL_FAM6_NEHALEM_EX:	/* Nehalem-EX Xeon - Beckton */
2830869ce69eSLen Brown 	case INTEL_FAM6_WESTMERE_EX:	/* Westmere-EX Xeon - Eagleton */
2831869ce69eSLen Brown 	case INTEL_FAM6_XEON_PHI_KNL:	/* PHI - Knights Landing (different MSR definition) */
2832005c82d6SLen Brown 	case INTEL_FAM6_XEON_PHI_KNM:
2833d7899447SLen Brown 		return 0;
2834d7899447SLen Brown 	default:
2835d7899447SLen Brown 		return 1;
2836d7899447SLen Brown 	}
2837d7899447SLen Brown }
28380f7887c4SLen Brown int has_atom_turbo_ratio_limit(unsigned int family, unsigned int model)
28390f7887c4SLen Brown {
28400f7887c4SLen Brown 	if (has_slv_msrs(family, model))
28410f7887c4SLen Brown 		return 1;
28420f7887c4SLen Brown 
28430f7887c4SLen Brown 	return 0;
28440f7887c4SLen Brown }
28456574a5d5SLen Brown int has_ivt_turbo_ratio_limit(unsigned int family, unsigned int model)
28466574a5d5SLen Brown {
28476574a5d5SLen Brown 	if (!genuine_intel)
28486574a5d5SLen Brown 		return 0;
28496574a5d5SLen Brown 
28506574a5d5SLen Brown 	if (family != 6)
28516574a5d5SLen Brown 		return 0;
28526574a5d5SLen Brown 
28536574a5d5SLen Brown 	switch (model) {
2854869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE_X:	/* IVB Xeon */
2855869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSW Xeon */
28566574a5d5SLen Brown 		return 1;
28576574a5d5SLen Brown 	default:
28586574a5d5SLen Brown 		return 0;
28596574a5d5SLen Brown 	}
28606574a5d5SLen Brown }
2861fcd17211SLen Brown int has_hsw_turbo_ratio_limit(unsigned int family, unsigned int model)
2862fcd17211SLen Brown {
2863fcd17211SLen Brown 	if (!genuine_intel)
2864fcd17211SLen Brown 		return 0;
2865fcd17211SLen Brown 
2866fcd17211SLen Brown 	if (family != 6)
2867fcd17211SLen Brown 		return 0;
2868fcd17211SLen Brown 
2869fcd17211SLen Brown 	switch (model) {
2870869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSW Xeon */
2871fcd17211SLen Brown 		return 1;
2872fcd17211SLen Brown 	default:
2873fcd17211SLen Brown 		return 0;
2874fcd17211SLen Brown 	}
2875fcd17211SLen Brown }
2876fcd17211SLen Brown 
2877fb5d4327SDasaratharaman Chandramouli int has_knl_turbo_ratio_limit(unsigned int family, unsigned int model)
2878fb5d4327SDasaratharaman Chandramouli {
2879fb5d4327SDasaratharaman Chandramouli 	if (!genuine_intel)
2880fb5d4327SDasaratharaman Chandramouli 		return 0;
2881fb5d4327SDasaratharaman Chandramouli 
2882fb5d4327SDasaratharaman Chandramouli 	if (family != 6)
2883fb5d4327SDasaratharaman Chandramouli 		return 0;
2884fb5d4327SDasaratharaman Chandramouli 
2885fb5d4327SDasaratharaman Chandramouli 	switch (model) {
2886869ce69eSLen Brown 	case INTEL_FAM6_XEON_PHI_KNL:	/* Knights Landing */
2887005c82d6SLen Brown 	case INTEL_FAM6_XEON_PHI_KNM:
2888fb5d4327SDasaratharaman Chandramouli 		return 1;
2889fb5d4327SDasaratharaman Chandramouli 	default:
2890fb5d4327SDasaratharaman Chandramouli 		return 0;
2891fb5d4327SDasaratharaman Chandramouli 	}
2892fb5d4327SDasaratharaman Chandramouli }
289331e07522SLen Brown int has_glm_turbo_ratio_limit(unsigned int family, unsigned int model)
289431e07522SLen Brown {
289531e07522SLen Brown 	if (!genuine_intel)
289631e07522SLen Brown 		return 0;
289731e07522SLen Brown 
289831e07522SLen Brown 	if (family != 6)
289931e07522SLen Brown 		return 0;
290031e07522SLen Brown 
290131e07522SLen Brown 	switch (model) {
290231e07522SLen Brown 	case INTEL_FAM6_ATOM_GOLDMONT:
290331e07522SLen Brown 	case INTEL_FAM6_SKYLAKE_X:
290431e07522SLen Brown 		return 1;
290531e07522SLen Brown 	default:
290631e07522SLen Brown 		return 0;
290731e07522SLen Brown 	}
290831e07522SLen Brown }
29096fb3143bSLen Brown int has_config_tdp(unsigned int family, unsigned int model)
29106fb3143bSLen Brown {
29116fb3143bSLen Brown 	if (!genuine_intel)
29126fb3143bSLen Brown 		return 0;
29136fb3143bSLen Brown 
29146fb3143bSLen Brown 	if (family != 6)
29156fb3143bSLen Brown 		return 0;
29166fb3143bSLen Brown 
29176fb3143bSLen Brown 	switch (model) {
2918869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE:	/* IVB */
2919869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
2920869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSX */
2921869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
2922869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
2923869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
2924869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_GT3E:	/* BDW */
2925869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_X:	/* BDX */
2926869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
2927869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
2928869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
2929869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
2930869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
2931869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_X:	/* SKX */
29326fb3143bSLen Brown 
2933869ce69eSLen Brown 	case INTEL_FAM6_XEON_PHI_KNL:	/* Knights Landing */
2934005c82d6SLen Brown 	case INTEL_FAM6_XEON_PHI_KNM:
29356fb3143bSLen Brown 		return 1;
29366fb3143bSLen Brown 	default:
29376fb3143bSLen Brown 		return 0;
29386fb3143bSLen Brown 	}
29396fb3143bSLen Brown }
29406fb3143bSLen Brown 
2941fcd17211SLen Brown static void
29421b69317dSColin Ian King dump_cstate_pstate_config_info(unsigned int family, unsigned int model)
2943fcd17211SLen Brown {
2944fcd17211SLen Brown 	if (!do_nhm_platform_info)
2945fcd17211SLen Brown 		return;
2946fcd17211SLen Brown 
2947fcd17211SLen Brown 	dump_nhm_platform_info();
2948fcd17211SLen Brown 
2949fcd17211SLen Brown 	if (has_hsw_turbo_ratio_limit(family, model))
2950fcd17211SLen Brown 		dump_hsw_turbo_ratio_limits();
2951fcd17211SLen Brown 
2952fcd17211SLen Brown 	if (has_ivt_turbo_ratio_limit(family, model))
2953fcd17211SLen Brown 		dump_ivt_turbo_ratio_limits();
2954fcd17211SLen Brown 
295531e07522SLen Brown 	if (has_turbo_ratio_limit(family, model))
295631e07522SLen Brown 		dump_turbo_ratio_limits(family, model);
2957fcd17211SLen Brown 
29580f7887c4SLen Brown 	if (has_atom_turbo_ratio_limit(family, model))
29590f7887c4SLen Brown 		dump_atom_turbo_ratio_limits();
29600f7887c4SLen Brown 
2961fb5d4327SDasaratharaman Chandramouli 	if (has_knl_turbo_ratio_limit(family, model))
2962fb5d4327SDasaratharaman Chandramouli 		dump_knl_turbo_ratio_limits();
2963fb5d4327SDasaratharaman Chandramouli 
29646fb3143bSLen Brown 	if (has_config_tdp(family, model))
29656fb3143bSLen Brown 		dump_config_tdp();
29666fb3143bSLen Brown 
2967fcd17211SLen Brown 	dump_nhm_cst_cfg();
2968fcd17211SLen Brown }
2969fcd17211SLen Brown 
297041618e63SLen Brown static void
297141618e63SLen Brown dump_sysfs_cstate_config(void)
297241618e63SLen Brown {
297341618e63SLen Brown 	char path[64];
297441618e63SLen Brown 	char name_buf[16];
297541618e63SLen Brown 	char desc[64];
297641618e63SLen Brown 	FILE *input;
297741618e63SLen Brown 	int state;
297841618e63SLen Brown 	char *sp;
297941618e63SLen Brown 
298041618e63SLen Brown 	if (!DO_BIC(BIC_sysfs))
298141618e63SLen Brown 		return;
298241618e63SLen Brown 
298341618e63SLen Brown 	for (state = 0; state < 10; ++state) {
298441618e63SLen Brown 
298541618e63SLen Brown 		sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name",
298641618e63SLen Brown 			base_cpu, state);
298741618e63SLen Brown 		input = fopen(path, "r");
298841618e63SLen Brown 		if (input == NULL)
298941618e63SLen Brown 			continue;
299041618e63SLen Brown 		fgets(name_buf, sizeof(name_buf), input);
299141618e63SLen Brown 
299241618e63SLen Brown 		 /* truncate "C1-HSW\n" to "C1", or truncate "C1\n" to "C1" */
299341618e63SLen Brown 		sp = strchr(name_buf, '-');
299441618e63SLen Brown 		if (!sp)
299541618e63SLen Brown 			sp = strchrnul(name_buf, '\n');
299641618e63SLen Brown 		*sp = '\0';
299741618e63SLen Brown 
299841618e63SLen Brown 		fclose(input);
299941618e63SLen Brown 
300041618e63SLen Brown 		sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/desc",
300141618e63SLen Brown 			base_cpu, state);
300241618e63SLen Brown 		input = fopen(path, "r");
300341618e63SLen Brown 		if (input == NULL)
300441618e63SLen Brown 			continue;
300541618e63SLen Brown 		fgets(desc, sizeof(desc), input);
300641618e63SLen Brown 
300741618e63SLen Brown 		fprintf(outf, "cpu%d: %s: %s", base_cpu, name_buf, desc);
300841618e63SLen Brown 		fclose(input);
300941618e63SLen Brown 	}
301041618e63SLen Brown }
30117293fccdSLen Brown static void
30127293fccdSLen Brown dump_sysfs_pstate_config(void)
30137293fccdSLen Brown {
30147293fccdSLen Brown 	char path[64];
30157293fccdSLen Brown 	char driver_buf[64];
30167293fccdSLen Brown 	char governor_buf[64];
30177293fccdSLen Brown 	FILE *input;
30187293fccdSLen Brown 	int turbo;
30197293fccdSLen Brown 
30207293fccdSLen Brown 	sprintf(path, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_driver",
30217293fccdSLen Brown 			base_cpu);
30227293fccdSLen Brown 	input = fopen(path, "r");
30237293fccdSLen Brown 	if (input == NULL) {
30247293fccdSLen Brown 		fprintf(stderr, "NSFOD %s\n", path);
30257293fccdSLen Brown 		return;
30267293fccdSLen Brown 	}
30277293fccdSLen Brown 	fgets(driver_buf, sizeof(driver_buf), input);
30287293fccdSLen Brown 	fclose(input);
30297293fccdSLen Brown 
30307293fccdSLen Brown 	sprintf(path, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor",
30317293fccdSLen Brown 			base_cpu);
30327293fccdSLen Brown 	input = fopen(path, "r");
30337293fccdSLen Brown 	if (input == NULL) {
30347293fccdSLen Brown 		fprintf(stderr, "NSFOD %s\n", path);
30357293fccdSLen Brown 		return;
30367293fccdSLen Brown 	}
30377293fccdSLen Brown 	fgets(governor_buf, sizeof(governor_buf), input);
30387293fccdSLen Brown 	fclose(input);
30397293fccdSLen Brown 
30407293fccdSLen Brown 	fprintf(outf, "cpu%d: cpufreq driver: %s", base_cpu, driver_buf);
30417293fccdSLen Brown 	fprintf(outf, "cpu%d: cpufreq governor: %s", base_cpu, governor_buf);
30427293fccdSLen Brown 
30437293fccdSLen Brown 	sprintf(path, "/sys/devices/system/cpu/cpufreq/boost");
30447293fccdSLen Brown 	input = fopen(path, "r");
30457293fccdSLen Brown 	if (input != NULL) {
30467293fccdSLen Brown 		fscanf(input, "%d", &turbo);
30477293fccdSLen Brown 		fprintf(outf, "cpufreq boost: %d\n", turbo);
30487293fccdSLen Brown 		fclose(input);
30497293fccdSLen Brown 	}
30507293fccdSLen Brown 
30517293fccdSLen Brown 	sprintf(path, "/sys/devices/system/cpu/intel_pstate/no_turbo");
30527293fccdSLen Brown 	input = fopen(path, "r");
30537293fccdSLen Brown 	if (input != NULL) {
30547293fccdSLen Brown 		fscanf(input, "%d", &turbo);
30557293fccdSLen Brown 		fprintf(outf, "cpufreq intel_pstate no_turbo: %d\n", turbo);
30567293fccdSLen Brown 		fclose(input);
30577293fccdSLen Brown 	}
30587293fccdSLen Brown }
305941618e63SLen Brown 
30606574a5d5SLen Brown 
3061889facbeSLen Brown /*
3062889facbeSLen Brown  * print_epb()
3063889facbeSLen Brown  * Decode the ENERGY_PERF_BIAS MSR
3064889facbeSLen Brown  */
3065889facbeSLen Brown int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p)
3066889facbeSLen Brown {
3067889facbeSLen Brown 	unsigned long long msr;
3068889facbeSLen Brown 	char *epb_string;
3069889facbeSLen Brown 	int cpu;
3070889facbeSLen Brown 
3071889facbeSLen Brown 	if (!has_epb)
3072889facbeSLen Brown 		return 0;
3073889facbeSLen Brown 
3074889facbeSLen Brown 	cpu = t->cpu_id;
3075889facbeSLen Brown 
3076889facbeSLen Brown 	/* EPB is per-package */
3077889facbeSLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
3078889facbeSLen Brown 		return 0;
3079889facbeSLen Brown 
3080889facbeSLen Brown 	if (cpu_migrate(cpu)) {
3081b7d8c148SLen Brown 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
3082889facbeSLen Brown 		return -1;
3083889facbeSLen Brown 	}
3084889facbeSLen Brown 
3085889facbeSLen Brown 	if (get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr))
3086889facbeSLen Brown 		return 0;
3087889facbeSLen Brown 
3088e9be7dd6SLen Brown 	switch (msr & 0xF) {
3089889facbeSLen Brown 	case ENERGY_PERF_BIAS_PERFORMANCE:
3090889facbeSLen Brown 		epb_string = "performance";
3091889facbeSLen Brown 		break;
3092889facbeSLen Brown 	case ENERGY_PERF_BIAS_NORMAL:
3093889facbeSLen Brown 		epb_string = "balanced";
3094889facbeSLen Brown 		break;
3095889facbeSLen Brown 	case ENERGY_PERF_BIAS_POWERSAVE:
3096889facbeSLen Brown 		epb_string = "powersave";
3097889facbeSLen Brown 		break;
3098889facbeSLen Brown 	default:
3099889facbeSLen Brown 		epb_string = "custom";
3100889facbeSLen Brown 		break;
3101889facbeSLen Brown 	}
3102b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_IA32_ENERGY_PERF_BIAS: 0x%08llx (%s)\n", cpu, msr, epb_string);
3103889facbeSLen Brown 
3104889facbeSLen Brown 	return 0;
3105889facbeSLen Brown }
31067f5c258eSLen Brown /*
31077f5c258eSLen Brown  * print_hwp()
31087f5c258eSLen Brown  * Decode the MSR_HWP_CAPABILITIES
31097f5c258eSLen Brown  */
31107f5c258eSLen Brown int print_hwp(struct thread_data *t, struct core_data *c, struct pkg_data *p)
31117f5c258eSLen Brown {
31127f5c258eSLen Brown 	unsigned long long msr;
31137f5c258eSLen Brown 	int cpu;
31147f5c258eSLen Brown 
31157f5c258eSLen Brown 	if (!has_hwp)
31167f5c258eSLen Brown 		return 0;
31177f5c258eSLen Brown 
31187f5c258eSLen Brown 	cpu = t->cpu_id;
31197f5c258eSLen Brown 
31207f5c258eSLen Brown 	/* MSR_HWP_CAPABILITIES is per-package */
31217f5c258eSLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
31227f5c258eSLen Brown 		return 0;
31237f5c258eSLen Brown 
31247f5c258eSLen Brown 	if (cpu_migrate(cpu)) {
3125b7d8c148SLen Brown 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
31267f5c258eSLen Brown 		return -1;
31277f5c258eSLen Brown 	}
31287f5c258eSLen Brown 
31297f5c258eSLen Brown 	if (get_msr(cpu, MSR_PM_ENABLE, &msr))
31307f5c258eSLen Brown 		return 0;
31317f5c258eSLen Brown 
3132b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_PM_ENABLE: 0x%08llx (%sHWP)\n",
31337f5c258eSLen Brown 		cpu, msr, (msr & (1 << 0)) ? "" : "No-");
31347f5c258eSLen Brown 
31357f5c258eSLen Brown 	/* MSR_PM_ENABLE[1] == 1 if HWP is enabled and MSRs visible */
31367f5c258eSLen Brown 	if ((msr & (1 << 0)) == 0)
31377f5c258eSLen Brown 		return 0;
31387f5c258eSLen Brown 
31397f5c258eSLen Brown 	if (get_msr(cpu, MSR_HWP_CAPABILITIES, &msr))
31407f5c258eSLen Brown 		return 0;
31417f5c258eSLen Brown 
3142b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_HWP_CAPABILITIES: 0x%08llx "
31436dbd25a2SLen Brown 			"(high %d guar %d eff %d low %d)\n",
31447f5c258eSLen Brown 			cpu, msr,
31457f5c258eSLen Brown 			(unsigned int)HWP_HIGHEST_PERF(msr),
31467f5c258eSLen Brown 			(unsigned int)HWP_GUARANTEED_PERF(msr),
31477f5c258eSLen Brown 			(unsigned int)HWP_MOSTEFFICIENT_PERF(msr),
31487f5c258eSLen Brown 			(unsigned int)HWP_LOWEST_PERF(msr));
31497f5c258eSLen Brown 
31507f5c258eSLen Brown 	if (get_msr(cpu, MSR_HWP_REQUEST, &msr))
31517f5c258eSLen Brown 		return 0;
31527f5c258eSLen Brown 
3153b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_HWP_REQUEST: 0x%08llx "
31546dbd25a2SLen Brown 			"(min %d max %d des %d epp 0x%x window 0x%x pkg 0x%x)\n",
31557f5c258eSLen Brown 			cpu, msr,
31567f5c258eSLen Brown 			(unsigned int)(((msr) >> 0) & 0xff),
31577f5c258eSLen Brown 			(unsigned int)(((msr) >> 8) & 0xff),
31587f5c258eSLen Brown 			(unsigned int)(((msr) >> 16) & 0xff),
31597f5c258eSLen Brown 			(unsigned int)(((msr) >> 24) & 0xff),
31607f5c258eSLen Brown 			(unsigned int)(((msr) >> 32) & 0xff3),
31617f5c258eSLen Brown 			(unsigned int)(((msr) >> 42) & 0x1));
31627f5c258eSLen Brown 
31637f5c258eSLen Brown 	if (has_hwp_pkg) {
31647f5c258eSLen Brown 		if (get_msr(cpu, MSR_HWP_REQUEST_PKG, &msr))
31657f5c258eSLen Brown 			return 0;
31667f5c258eSLen Brown 
3167b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_HWP_REQUEST_PKG: 0x%08llx "
31686dbd25a2SLen Brown 			"(min %d max %d des %d epp 0x%x window 0x%x)\n",
31697f5c258eSLen Brown 			cpu, msr,
31707f5c258eSLen Brown 			(unsigned int)(((msr) >> 0) & 0xff),
31717f5c258eSLen Brown 			(unsigned int)(((msr) >> 8) & 0xff),
31727f5c258eSLen Brown 			(unsigned int)(((msr) >> 16) & 0xff),
31737f5c258eSLen Brown 			(unsigned int)(((msr) >> 24) & 0xff),
31747f5c258eSLen Brown 			(unsigned int)(((msr) >> 32) & 0xff3));
31757f5c258eSLen Brown 	}
31767f5c258eSLen Brown 	if (has_hwp_notify) {
31777f5c258eSLen Brown 		if (get_msr(cpu, MSR_HWP_INTERRUPT, &msr))
31787f5c258eSLen Brown 			return 0;
31797f5c258eSLen Brown 
3180b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_HWP_INTERRUPT: 0x%08llx "
31817f5c258eSLen Brown 			"(%s_Guaranteed_Perf_Change, %s_Excursion_Min)\n",
31827f5c258eSLen Brown 			cpu, msr,
31837f5c258eSLen Brown 			((msr) & 0x1) ? "EN" : "Dis",
31847f5c258eSLen Brown 			((msr) & 0x2) ? "EN" : "Dis");
31857f5c258eSLen Brown 	}
31867f5c258eSLen Brown 	if (get_msr(cpu, MSR_HWP_STATUS, &msr))
31877f5c258eSLen Brown 		return 0;
31887f5c258eSLen Brown 
3189b7d8c148SLen Brown 	fprintf(outf, "cpu%d: MSR_HWP_STATUS: 0x%08llx "
31907f5c258eSLen Brown 			"(%sGuaranteed_Perf_Change, %sExcursion_Min)\n",
31917f5c258eSLen Brown 			cpu, msr,
31927f5c258eSLen Brown 			((msr) & 0x1) ? "" : "No-",
31937f5c258eSLen Brown 			((msr) & 0x2) ? "" : "No-");
3194889facbeSLen Brown 
3195889facbeSLen Brown 	return 0;
3196889facbeSLen Brown }
3197889facbeSLen Brown 
31983a9a941dSLen Brown /*
31993a9a941dSLen Brown  * print_perf_limit()
32003a9a941dSLen Brown  */
32013a9a941dSLen Brown int print_perf_limit(struct thread_data *t, struct core_data *c, struct pkg_data *p)
32023a9a941dSLen Brown {
32033a9a941dSLen Brown 	unsigned long long msr;
32043a9a941dSLen Brown 	int cpu;
32053a9a941dSLen Brown 
32063a9a941dSLen Brown 	cpu = t->cpu_id;
32073a9a941dSLen Brown 
32083a9a941dSLen Brown 	/* per-package */
32093a9a941dSLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
32103a9a941dSLen Brown 		return 0;
32113a9a941dSLen Brown 
32123a9a941dSLen Brown 	if (cpu_migrate(cpu)) {
3213b7d8c148SLen Brown 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
32143a9a941dSLen Brown 		return -1;
32153a9a941dSLen Brown 	}
32163a9a941dSLen Brown 
32173a9a941dSLen Brown 	if (do_core_perf_limit_reasons) {
32183a9a941dSLen Brown 		get_msr(cpu, MSR_CORE_PERF_LIMIT_REASONS, &msr);
3219b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_CORE_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
3220b7d8c148SLen Brown 		fprintf(outf, " (Active: %s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
3221e33cbe85SLen Brown 			(msr & 1 << 15) ? "bit15, " : "",
32223a9a941dSLen Brown 			(msr & 1 << 14) ? "bit14, " : "",
3223e33cbe85SLen Brown 			(msr & 1 << 13) ? "Transitions, " : "",
3224e33cbe85SLen Brown 			(msr & 1 << 12) ? "MultiCoreTurbo, " : "",
3225e33cbe85SLen Brown 			(msr & 1 << 11) ? "PkgPwrL2, " : "",
3226e33cbe85SLen Brown 			(msr & 1 << 10) ? "PkgPwrL1, " : "",
3227e33cbe85SLen Brown 			(msr & 1 << 9) ? "CorePwr, " : "",
3228e33cbe85SLen Brown 			(msr & 1 << 8) ? "Amps, " : "",
3229e33cbe85SLen Brown 			(msr & 1 << 6) ? "VR-Therm, " : "",
3230e33cbe85SLen Brown 			(msr & 1 << 5) ? "Auto-HWP, " : "",
3231e33cbe85SLen Brown 			(msr & 1 << 4) ? "Graphics, " : "",
3232e33cbe85SLen Brown 			(msr & 1 << 2) ? "bit2, " : "",
3233e33cbe85SLen Brown 			(msr & 1 << 1) ? "ThermStatus, " : "",
3234e33cbe85SLen Brown 			(msr & 1 << 0) ? "PROCHOT, " : "");
3235b7d8c148SLen Brown 		fprintf(outf, " (Logged: %s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n",
3236e33cbe85SLen Brown 			(msr & 1 << 31) ? "bit31, " : "",
32373a9a941dSLen Brown 			(msr & 1 << 30) ? "bit30, " : "",
3238e33cbe85SLen Brown 			(msr & 1 << 29) ? "Transitions, " : "",
3239e33cbe85SLen Brown 			(msr & 1 << 28) ? "MultiCoreTurbo, " : "",
3240e33cbe85SLen Brown 			(msr & 1 << 27) ? "PkgPwrL2, " : "",
3241e33cbe85SLen Brown 			(msr & 1 << 26) ? "PkgPwrL1, " : "",
3242e33cbe85SLen Brown 			(msr & 1 << 25) ? "CorePwr, " : "",
3243e33cbe85SLen Brown 			(msr & 1 << 24) ? "Amps, " : "",
3244e33cbe85SLen Brown 			(msr & 1 << 22) ? "VR-Therm, " : "",
3245e33cbe85SLen Brown 			(msr & 1 << 21) ? "Auto-HWP, " : "",
3246e33cbe85SLen Brown 			(msr & 1 << 20) ? "Graphics, " : "",
3247e33cbe85SLen Brown 			(msr & 1 << 18) ? "bit18, " : "",
3248e33cbe85SLen Brown 			(msr & 1 << 17) ? "ThermStatus, " : "",
3249e33cbe85SLen Brown 			(msr & 1 << 16) ? "PROCHOT, " : "");
32503a9a941dSLen Brown 
32513a9a941dSLen Brown 	}
32523a9a941dSLen Brown 	if (do_gfx_perf_limit_reasons) {
32533a9a941dSLen Brown 		get_msr(cpu, MSR_GFX_PERF_LIMIT_REASONS, &msr);
3254b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_GFX_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
3255b7d8c148SLen Brown 		fprintf(outf, " (Active: %s%s%s%s%s%s%s%s)",
32563a9a941dSLen Brown 			(msr & 1 << 0) ? "PROCHOT, " : "",
32573a9a941dSLen Brown 			(msr & 1 << 1) ? "ThermStatus, " : "",
32583a9a941dSLen Brown 			(msr & 1 << 4) ? "Graphics, " : "",
32593a9a941dSLen Brown 			(msr & 1 << 6) ? "VR-Therm, " : "",
32603a9a941dSLen Brown 			(msr & 1 << 8) ? "Amps, " : "",
32613a9a941dSLen Brown 			(msr & 1 << 9) ? "GFXPwr, " : "",
32623a9a941dSLen Brown 			(msr & 1 << 10) ? "PkgPwrL1, " : "",
32633a9a941dSLen Brown 			(msr & 1 << 11) ? "PkgPwrL2, " : "");
3264b7d8c148SLen Brown 		fprintf(outf, " (Logged: %s%s%s%s%s%s%s%s)\n",
32653a9a941dSLen Brown 			(msr & 1 << 16) ? "PROCHOT, " : "",
32663a9a941dSLen Brown 			(msr & 1 << 17) ? "ThermStatus, " : "",
32673a9a941dSLen Brown 			(msr & 1 << 20) ? "Graphics, " : "",
32683a9a941dSLen Brown 			(msr & 1 << 22) ? "VR-Therm, " : "",
32693a9a941dSLen Brown 			(msr & 1 << 24) ? "Amps, " : "",
32703a9a941dSLen Brown 			(msr & 1 << 25) ? "GFXPwr, " : "",
32713a9a941dSLen Brown 			(msr & 1 << 26) ? "PkgPwrL1, " : "",
32723a9a941dSLen Brown 			(msr & 1 << 27) ? "PkgPwrL2, " : "");
32733a9a941dSLen Brown 	}
32743a9a941dSLen Brown 	if (do_ring_perf_limit_reasons) {
32753a9a941dSLen Brown 		get_msr(cpu, MSR_RING_PERF_LIMIT_REASONS, &msr);
3276b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_RING_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
3277b7d8c148SLen Brown 		fprintf(outf, " (Active: %s%s%s%s%s%s)",
32783a9a941dSLen Brown 			(msr & 1 << 0) ? "PROCHOT, " : "",
32793a9a941dSLen Brown 			(msr & 1 << 1) ? "ThermStatus, " : "",
32803a9a941dSLen Brown 			(msr & 1 << 6) ? "VR-Therm, " : "",
32813a9a941dSLen Brown 			(msr & 1 << 8) ? "Amps, " : "",
32823a9a941dSLen Brown 			(msr & 1 << 10) ? "PkgPwrL1, " : "",
32833a9a941dSLen Brown 			(msr & 1 << 11) ? "PkgPwrL2, " : "");
3284b7d8c148SLen Brown 		fprintf(outf, " (Logged: %s%s%s%s%s%s)\n",
32853a9a941dSLen Brown 			(msr & 1 << 16) ? "PROCHOT, " : "",
32863a9a941dSLen Brown 			(msr & 1 << 17) ? "ThermStatus, " : "",
32873a9a941dSLen Brown 			(msr & 1 << 22) ? "VR-Therm, " : "",
32883a9a941dSLen Brown 			(msr & 1 << 24) ? "Amps, " : "",
32893a9a941dSLen Brown 			(msr & 1 << 26) ? "PkgPwrL1, " : "",
32903a9a941dSLen Brown 			(msr & 1 << 27) ? "PkgPwrL2, " : "");
32913a9a941dSLen Brown 	}
32923a9a941dSLen Brown 	return 0;
32933a9a941dSLen Brown }
32943a9a941dSLen Brown 
3295889facbeSLen Brown #define	RAPL_POWER_GRANULARITY	0x7FFF	/* 15 bit power granularity */
3296889facbeSLen Brown #define	RAPL_TIME_GRANULARITY	0x3F /* 6 bit time granularity */
3297889facbeSLen Brown 
32981b69317dSColin Ian King double get_tdp(unsigned int model)
3299144b44b1SLen Brown {
3300144b44b1SLen Brown 	unsigned long long msr;
3301144b44b1SLen Brown 
3302144b44b1SLen Brown 	if (do_rapl & RAPL_PKG_POWER_INFO)
33037ce7d5deSPrarit Bhargava 		if (!get_msr(base_cpu, MSR_PKG_POWER_INFO, &msr))
3304144b44b1SLen Brown 			return ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units;
3305144b44b1SLen Brown 
3306144b44b1SLen Brown 	switch (model) {
3307869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT1:
3308869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT2:
3309144b44b1SLen Brown 		return 30.0;
3310144b44b1SLen Brown 	default:
3311144b44b1SLen Brown 		return 135.0;
3312144b44b1SLen Brown 	}
3313144b44b1SLen Brown }
3314144b44b1SLen Brown 
331540ee8e3bSAndrey Semin /*
331640ee8e3bSAndrey Semin  * rapl_dram_energy_units_probe()
331740ee8e3bSAndrey Semin  * Energy units are either hard-coded, or come from RAPL Energy Unit MSR.
331840ee8e3bSAndrey Semin  */
331940ee8e3bSAndrey Semin static double
332040ee8e3bSAndrey Semin rapl_dram_energy_units_probe(int  model, double rapl_energy_units)
332140ee8e3bSAndrey Semin {
332240ee8e3bSAndrey Semin 	/* only called for genuine_intel, family 6 */
332340ee8e3bSAndrey Semin 
332440ee8e3bSAndrey Semin 	switch (model) {
3325869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSX */
3326869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_X:	/* BDX */
3327869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
3328869ce69eSLen Brown 	case INTEL_FAM6_XEON_PHI_KNL:	/* KNL */
3329005c82d6SLen Brown 	case INTEL_FAM6_XEON_PHI_KNM:
333040ee8e3bSAndrey Semin 		return (rapl_dram_energy_units = 15.3 / 1000000);
333140ee8e3bSAndrey Semin 	default:
333240ee8e3bSAndrey Semin 		return (rapl_energy_units);
333340ee8e3bSAndrey Semin 	}
333440ee8e3bSAndrey Semin }
333540ee8e3bSAndrey Semin 
3336144b44b1SLen Brown 
3337889facbeSLen Brown /*
3338889facbeSLen Brown  * rapl_probe()
3339889facbeSLen Brown  *
3340144b44b1SLen Brown  * sets do_rapl, rapl_power_units, rapl_energy_units, rapl_time_units
3341889facbeSLen Brown  */
3342889facbeSLen Brown void rapl_probe(unsigned int family, unsigned int model)
3343889facbeSLen Brown {
3344889facbeSLen Brown 	unsigned long long msr;
3345144b44b1SLen Brown 	unsigned int time_unit;
3346889facbeSLen Brown 	double tdp;
3347889facbeSLen Brown 
3348889facbeSLen Brown 	if (!genuine_intel)
3349889facbeSLen Brown 		return;
3350889facbeSLen Brown 
3351889facbeSLen Brown 	if (family != 6)
3352889facbeSLen Brown 		return;
3353889facbeSLen Brown 
3354889facbeSLen Brown 	switch (model) {
3355869ce69eSLen Brown 	case INTEL_FAM6_SANDYBRIDGE:
3356869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE:
3357869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
3358869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
3359869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
3360869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
3361869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_GT3E:	/* BDW */
3362144b44b1SLen Brown 		do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_GFX | RAPL_PKG_POWER_INFO;
3363812db3f7SLen Brown 		if (rapl_joules) {
3364812db3f7SLen Brown 			BIC_PRESENT(BIC_Pkg_J);
3365812db3f7SLen Brown 			BIC_PRESENT(BIC_Cor_J);
3366812db3f7SLen Brown 			BIC_PRESENT(BIC_GFX_J);
3367812db3f7SLen Brown 		} else {
3368812db3f7SLen Brown 			BIC_PRESENT(BIC_PkgWatt);
3369812db3f7SLen Brown 			BIC_PRESENT(BIC_CorWatt);
3370812db3f7SLen Brown 			BIC_PRESENT(BIC_GFXWatt);
3371812db3f7SLen Brown 		}
3372889facbeSLen Brown 		break;
3373869ce69eSLen Brown 	case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
3374ac01ac13SLen Brown 	case INTEL_FAM6_ATOM_GEMINI_LAKE:
3375e4085d54SLen Brown 		do_rapl = RAPL_PKG | RAPL_PKG_POWER_INFO;
3376812db3f7SLen Brown 		if (rapl_joules)
3377812db3f7SLen Brown 			BIC_PRESENT(BIC_Pkg_J);
3378812db3f7SLen Brown 		else
3379812db3f7SLen Brown 			BIC_PRESENT(BIC_PkgWatt);
3380e4085d54SLen Brown 		break;
3381869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
3382869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
3383869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
3384869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
338581824921SLen Brown 		do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_GFX | RAPL_PKG_POWER_INFO;
3386812db3f7SLen Brown 		BIC_PRESENT(BIC_PKG__);
3387812db3f7SLen Brown 		BIC_PRESENT(BIC_RAM__);
3388812db3f7SLen Brown 		if (rapl_joules) {
3389812db3f7SLen Brown 			BIC_PRESENT(BIC_Pkg_J);
3390812db3f7SLen Brown 			BIC_PRESENT(BIC_Cor_J);
3391812db3f7SLen Brown 			BIC_PRESENT(BIC_RAM_J);
339281824921SLen Brown 			BIC_PRESENT(BIC_GFX_J);
3393812db3f7SLen Brown 		} else {
3394812db3f7SLen Brown 			BIC_PRESENT(BIC_PkgWatt);
3395812db3f7SLen Brown 			BIC_PRESENT(BIC_CorWatt);
3396812db3f7SLen Brown 			BIC_PRESENT(BIC_RAMWatt);
339781824921SLen Brown 			BIC_PRESENT(BIC_GFXWatt);
3398812db3f7SLen Brown 		}
33990b2bb692SLen Brown 		break;
3400869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSX */
3401869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_X:	/* BDX */
3402869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
3403869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_X:	/* SKX */
3404869ce69eSLen Brown 	case INTEL_FAM6_XEON_PHI_KNL:	/* KNL */
3405005c82d6SLen Brown 	case INTEL_FAM6_XEON_PHI_KNM:
34060b2bb692SLen Brown 		do_rapl = RAPL_PKG | RAPL_DRAM | RAPL_DRAM_POWER_INFO | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO;
3407812db3f7SLen Brown 		BIC_PRESENT(BIC_PKG__);
3408812db3f7SLen Brown 		BIC_PRESENT(BIC_RAM__);
3409812db3f7SLen Brown 		if (rapl_joules) {
3410812db3f7SLen Brown 			BIC_PRESENT(BIC_Pkg_J);
3411812db3f7SLen Brown 			BIC_PRESENT(BIC_RAM_J);
3412812db3f7SLen Brown 		} else {
3413812db3f7SLen Brown 			BIC_PRESENT(BIC_PkgWatt);
3414812db3f7SLen Brown 			BIC_PRESENT(BIC_RAMWatt);
3415812db3f7SLen Brown 		}
3416e6f9bb3cSLen Brown 		break;
3417869ce69eSLen Brown 	case INTEL_FAM6_SANDYBRIDGE_X:
3418869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE_X:
34190b2bb692SLen 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;
3420812db3f7SLen Brown 		BIC_PRESENT(BIC_PKG__);
3421812db3f7SLen Brown 		BIC_PRESENT(BIC_RAM__);
3422812db3f7SLen Brown 		if (rapl_joules) {
3423812db3f7SLen Brown 			BIC_PRESENT(BIC_Pkg_J);
3424812db3f7SLen Brown 			BIC_PRESENT(BIC_Cor_J);
3425812db3f7SLen Brown 			BIC_PRESENT(BIC_RAM_J);
3426812db3f7SLen Brown 		} else {
3427812db3f7SLen Brown 			BIC_PRESENT(BIC_PkgWatt);
3428812db3f7SLen Brown 			BIC_PRESENT(BIC_CorWatt);
3429812db3f7SLen Brown 			BIC_PRESENT(BIC_RAMWatt);
3430812db3f7SLen Brown 		}
3431144b44b1SLen Brown 		break;
3432869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT1:	/* BYT */
3433869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT2:	/* AVN */
3434144b44b1SLen Brown 		do_rapl = RAPL_PKG | RAPL_CORES;
3435812db3f7SLen Brown 		if (rapl_joules) {
3436812db3f7SLen Brown 			BIC_PRESENT(BIC_Pkg_J);
3437812db3f7SLen Brown 			BIC_PRESENT(BIC_Cor_J);
3438812db3f7SLen Brown 		} else {
3439812db3f7SLen Brown 			BIC_PRESENT(BIC_PkgWatt);
3440812db3f7SLen Brown 			BIC_PRESENT(BIC_CorWatt);
3441812db3f7SLen Brown 		}
3442889facbeSLen Brown 		break;
3443869ce69eSLen Brown 	case INTEL_FAM6_ATOM_DENVERTON:	/* DNV */
34440f644909SJacob 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;
3445812db3f7SLen Brown 		BIC_PRESENT(BIC_PKG__);
3446812db3f7SLen Brown 		BIC_PRESENT(BIC_RAM__);
3447812db3f7SLen Brown 		if (rapl_joules) {
3448812db3f7SLen Brown 			BIC_PRESENT(BIC_Pkg_J);
3449812db3f7SLen Brown 			BIC_PRESENT(BIC_Cor_J);
3450812db3f7SLen Brown 			BIC_PRESENT(BIC_RAM_J);
3451812db3f7SLen Brown 		} else {
3452812db3f7SLen Brown 			BIC_PRESENT(BIC_PkgWatt);
3453812db3f7SLen Brown 			BIC_PRESENT(BIC_CorWatt);
3454812db3f7SLen Brown 			BIC_PRESENT(BIC_RAMWatt);
3455812db3f7SLen Brown 		}
34560f644909SJacob Pan 		break;
3457889facbeSLen Brown 	default:
3458889facbeSLen Brown 		return;
3459889facbeSLen Brown 	}
3460889facbeSLen Brown 
3461889facbeSLen Brown 	/* units on package 0, verify later other packages match */
34627ce7d5deSPrarit Bhargava 	if (get_msr(base_cpu, MSR_RAPL_POWER_UNIT, &msr))
3463889facbeSLen Brown 		return;
3464889facbeSLen Brown 
3465889facbeSLen Brown 	rapl_power_units = 1.0 / (1 << (msr & 0xF));
3466869ce69eSLen Brown 	if (model == INTEL_FAM6_ATOM_SILVERMONT1)
3467144b44b1SLen Brown 		rapl_energy_units = 1.0 * (1 << (msr >> 8 & 0x1F)) / 1000000;
3468144b44b1SLen Brown 	else
3469889facbeSLen Brown 		rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F));
3470889facbeSLen Brown 
347140ee8e3bSAndrey Semin 	rapl_dram_energy_units = rapl_dram_energy_units_probe(model, rapl_energy_units);
347240ee8e3bSAndrey Semin 
3473144b44b1SLen Brown 	time_unit = msr >> 16 & 0xF;
3474144b44b1SLen Brown 	if (time_unit == 0)
3475144b44b1SLen Brown 		time_unit = 0xA;
3476889facbeSLen Brown 
3477144b44b1SLen Brown 	rapl_time_units = 1.0 / (1 << (time_unit));
3478144b44b1SLen Brown 
3479144b44b1SLen Brown 	tdp = get_tdp(model);
3480889facbeSLen Brown 
3481889facbeSLen Brown 	rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp;
348296e47158SLen Brown 	if (!quiet)
3483b7d8c148SLen Brown 		fprintf(outf, "RAPL: %.0f sec. Joule Counter Range, at %.0f Watts\n", rapl_joule_counter_range, tdp);
3484889facbeSLen Brown 
3485889facbeSLen Brown 	return;
3486889facbeSLen Brown }
3487889facbeSLen Brown 
34881b69317dSColin Ian King void perf_limit_reasons_probe(unsigned int family, unsigned int model)
34893a9a941dSLen Brown {
34903a9a941dSLen Brown 	if (!genuine_intel)
34913a9a941dSLen Brown 		return;
34923a9a941dSLen Brown 
34933a9a941dSLen Brown 	if (family != 6)
34943a9a941dSLen Brown 		return;
34953a9a941dSLen Brown 
34963a9a941dSLen Brown 	switch (model) {
3497869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
3498869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
3499869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
35003a9a941dSLen Brown 		do_gfx_perf_limit_reasons = 1;
3501869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSX */
35023a9a941dSLen Brown 		do_core_perf_limit_reasons = 1;
35033a9a941dSLen Brown 		do_ring_perf_limit_reasons = 1;
35043a9a941dSLen Brown 	default:
35053a9a941dSLen Brown 		return;
35063a9a941dSLen Brown 	}
35073a9a941dSLen Brown }
35083a9a941dSLen Brown 
3509889facbeSLen Brown int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p)
3510889facbeSLen Brown {
3511889facbeSLen Brown 	unsigned long long msr;
3512f4896fa5SLen Brown 	unsigned int dts, dts2;
3513889facbeSLen Brown 	int cpu;
3514889facbeSLen Brown 
3515889facbeSLen Brown 	if (!(do_dts || do_ptm))
3516889facbeSLen Brown 		return 0;
3517889facbeSLen Brown 
3518889facbeSLen Brown 	cpu = t->cpu_id;
3519889facbeSLen Brown 
3520889facbeSLen Brown 	/* DTS is per-core, no need to print for each thread */
3521889facbeSLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
3522889facbeSLen Brown 		return 0;
3523889facbeSLen Brown 
3524889facbeSLen Brown 	if (cpu_migrate(cpu)) {
3525b7d8c148SLen Brown 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
3526889facbeSLen Brown 		return -1;
3527889facbeSLen Brown 	}
3528889facbeSLen Brown 
3529889facbeSLen Brown 	if (do_ptm && (t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) {
3530889facbeSLen Brown 		if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr))
3531889facbeSLen Brown 			return 0;
3532889facbeSLen Brown 
3533889facbeSLen Brown 		dts = (msr >> 16) & 0x7F;
3534b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_IA32_PACKAGE_THERM_STATUS: 0x%08llx (%d C)\n",
3535889facbeSLen Brown 			cpu, msr, tcc_activation_temp - dts);
3536889facbeSLen Brown 
3537889facbeSLen Brown 		if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &msr))
3538889facbeSLen Brown 			return 0;
3539889facbeSLen Brown 
3540889facbeSLen Brown 		dts = (msr >> 16) & 0x7F;
3541889facbeSLen Brown 		dts2 = (msr >> 8) & 0x7F;
3542b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_IA32_PACKAGE_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
3543889facbeSLen Brown 			cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2);
3544889facbeSLen Brown 	}
3545889facbeSLen Brown 
3546889facbeSLen Brown 
3547f4896fa5SLen Brown 	if (do_dts && debug) {
3548889facbeSLen Brown 		unsigned int resolution;
3549889facbeSLen Brown 
3550889facbeSLen Brown 		if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr))
3551889facbeSLen Brown 			return 0;
3552889facbeSLen Brown 
3553889facbeSLen Brown 		dts = (msr >> 16) & 0x7F;
3554889facbeSLen Brown 		resolution = (msr >> 27) & 0xF;
3555b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_IA32_THERM_STATUS: 0x%08llx (%d C +/- %d)\n",
3556889facbeSLen Brown 			cpu, msr, tcc_activation_temp - dts, resolution);
3557889facbeSLen Brown 
3558889facbeSLen Brown 		if (get_msr(cpu, MSR_IA32_THERM_INTERRUPT, &msr))
3559889facbeSLen Brown 			return 0;
3560889facbeSLen Brown 
3561889facbeSLen Brown 		dts = (msr >> 16) & 0x7F;
3562889facbeSLen Brown 		dts2 = (msr >> 8) & 0x7F;
3563b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_IA32_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
3564889facbeSLen Brown 			cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2);
3565889facbeSLen Brown 	}
3566889facbeSLen Brown 
3567889facbeSLen Brown 	return 0;
3568889facbeSLen Brown }
3569889facbeSLen Brown 
3570889facbeSLen Brown void print_power_limit_msr(int cpu, unsigned long long msr, char *label)
3571889facbeSLen Brown {
3572b7d8c148SLen Brown 	fprintf(outf, "cpu%d: %s: %sabled (%f Watts, %f sec, clamp %sabled)\n",
3573889facbeSLen Brown 		cpu, label,
3574889facbeSLen Brown 		((msr >> 15) & 1) ? "EN" : "DIS",
3575889facbeSLen Brown 		((msr >> 0) & 0x7FFF) * rapl_power_units,
3576889facbeSLen Brown 		(1.0 + (((msr >> 22) & 0x3)/4.0)) * (1 << ((msr >> 17) & 0x1F)) * rapl_time_units,
3577889facbeSLen Brown 		(((msr >> 16) & 1) ? "EN" : "DIS"));
3578889facbeSLen Brown 
3579889facbeSLen Brown 	return;
3580889facbeSLen Brown }
3581889facbeSLen Brown 
3582889facbeSLen Brown int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
3583889facbeSLen Brown {
3584889facbeSLen Brown 	unsigned long long msr;
3585889facbeSLen Brown 	int cpu;
3586889facbeSLen Brown 
3587889facbeSLen Brown 	if (!do_rapl)
3588889facbeSLen Brown 		return 0;
3589889facbeSLen Brown 
3590889facbeSLen Brown 	/* RAPL counters are per package, so print only for 1st thread/package */
3591889facbeSLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
3592889facbeSLen Brown 		return 0;
3593889facbeSLen Brown 
3594889facbeSLen Brown 	cpu = t->cpu_id;
3595889facbeSLen Brown 	if (cpu_migrate(cpu)) {
3596b7d8c148SLen Brown 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
3597889facbeSLen Brown 		return -1;
3598889facbeSLen Brown 	}
3599889facbeSLen Brown 
3600889facbeSLen Brown 	if (get_msr(cpu, MSR_RAPL_POWER_UNIT, &msr))
3601889facbeSLen Brown 		return -1;
3602889facbeSLen Brown 
360396e47158SLen Brown 	fprintf(outf, "cpu%d: MSR_RAPL_POWER_UNIT: 0x%08llx (%f Watts, %f Joules, %f sec.)\n", cpu, msr,
3604144b44b1SLen Brown 		rapl_power_units, rapl_energy_units, rapl_time_units);
360596e47158SLen Brown 
3606144b44b1SLen Brown 	if (do_rapl & RAPL_PKG_POWER_INFO) {
3607144b44b1SLen Brown 
3608889facbeSLen Brown 		if (get_msr(cpu, MSR_PKG_POWER_INFO, &msr))
3609889facbeSLen Brown                 	return -5;
3610889facbeSLen Brown 
3611889facbeSLen Brown 
3612b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_PKG_POWER_INFO: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n",
3613889facbeSLen Brown 			cpu, msr,
3614889facbeSLen Brown 			((msr >>  0) & RAPL_POWER_GRANULARITY) * rapl_power_units,
3615889facbeSLen Brown 			((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units,
3616889facbeSLen Brown 			((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units,
3617889facbeSLen Brown 			((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units);
3618889facbeSLen Brown 
3619144b44b1SLen Brown 	}
3620144b44b1SLen Brown 	if (do_rapl & RAPL_PKG) {
3621144b44b1SLen Brown 
3622889facbeSLen Brown 		if (get_msr(cpu, MSR_PKG_POWER_LIMIT, &msr))
3623889facbeSLen Brown 			return -9;
3624889facbeSLen Brown 
3625b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_PKG_POWER_LIMIT: 0x%08llx (%slocked)\n",
3626889facbeSLen Brown 			cpu, msr, (msr >> 63) & 1 ? "" : "UN");
3627889facbeSLen Brown 
3628889facbeSLen Brown 		print_power_limit_msr(cpu, msr, "PKG Limit #1");
3629b7d8c148SLen Brown 		fprintf(outf, "cpu%d: PKG Limit #2: %sabled (%f Watts, %f* sec, clamp %sabled)\n",
3630889facbeSLen Brown 			cpu,
3631889facbeSLen Brown 			((msr >> 47) & 1) ? "EN" : "DIS",
3632889facbeSLen Brown 			((msr >> 32) & 0x7FFF) * rapl_power_units,
3633889facbeSLen Brown 			(1.0 + (((msr >> 54) & 0x3)/4.0)) * (1 << ((msr >> 49) & 0x1F)) * rapl_time_units,
3634889facbeSLen Brown 			((msr >> 48) & 1) ? "EN" : "DIS");
3635889facbeSLen Brown 	}
3636889facbeSLen Brown 
36370b2bb692SLen Brown 	if (do_rapl & RAPL_DRAM_POWER_INFO) {
3638889facbeSLen Brown 		if (get_msr(cpu, MSR_DRAM_POWER_INFO, &msr))
3639889facbeSLen Brown                 	return -6;
3640889facbeSLen Brown 
3641b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_DRAM_POWER_INFO,: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n",
3642889facbeSLen Brown 			cpu, msr,
3643889facbeSLen Brown 			((msr >>  0) & RAPL_POWER_GRANULARITY) * rapl_power_units,
3644889facbeSLen Brown 			((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units,
3645889facbeSLen Brown 			((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units,
3646889facbeSLen Brown 			((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units);
36470b2bb692SLen Brown 	}
36480b2bb692SLen Brown 	if (do_rapl & RAPL_DRAM) {
3649889facbeSLen Brown 		if (get_msr(cpu, MSR_DRAM_POWER_LIMIT, &msr))
3650889facbeSLen Brown 			return -9;
3651b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_DRAM_POWER_LIMIT: 0x%08llx (%slocked)\n",
3652889facbeSLen Brown 				cpu, msr, (msr >> 31) & 1 ? "" : "UN");
3653889facbeSLen Brown 
3654889facbeSLen Brown 		print_power_limit_msr(cpu, msr, "DRAM Limit");
3655889facbeSLen Brown 	}
3656144b44b1SLen Brown 	if (do_rapl & RAPL_CORE_POLICY) {
3657889facbeSLen Brown 		if (get_msr(cpu, MSR_PP0_POLICY, &msr))
3658889facbeSLen Brown 			return -7;
3659889facbeSLen Brown 
3660b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_PP0_POLICY: %lld\n", cpu, msr & 0xF);
3661144b44b1SLen Brown 	}
36629148494cSJacob Pan 	if (do_rapl & RAPL_CORES_POWER_LIMIT) {
3663889facbeSLen Brown 		if (get_msr(cpu, MSR_PP0_POWER_LIMIT, &msr))
3664889facbeSLen Brown 			return -9;
3665b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_PP0_POWER_LIMIT: 0x%08llx (%slocked)\n",
3666889facbeSLen Brown 				cpu, msr, (msr >> 31) & 1 ? "" : "UN");
3667889facbeSLen Brown 		print_power_limit_msr(cpu, msr, "Cores Limit");
3668889facbeSLen Brown 	}
3669889facbeSLen Brown 	if (do_rapl & RAPL_GFX) {
3670889facbeSLen Brown 		if (get_msr(cpu, MSR_PP1_POLICY, &msr))
3671889facbeSLen Brown 			return -8;
3672889facbeSLen Brown 
3673b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_PP1_POLICY: %lld\n", cpu, msr & 0xF);
3674889facbeSLen Brown 
3675889facbeSLen Brown 		if (get_msr(cpu, MSR_PP1_POWER_LIMIT, &msr))
3676889facbeSLen Brown 			return -9;
3677b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_PP1_POWER_LIMIT: 0x%08llx (%slocked)\n",
3678889facbeSLen Brown 				cpu, msr, (msr >> 31) & 1 ? "" : "UN");
3679889facbeSLen Brown 		print_power_limit_msr(cpu, msr, "GFX Limit");
3680889facbeSLen Brown 	}
3681889facbeSLen Brown 	return 0;
3682889facbeSLen Brown }
3683889facbeSLen Brown 
3684d7899447SLen Brown /*
3685d7899447SLen Brown  * SNB adds support for additional MSRs:
3686d7899447SLen Brown  *
3687d7899447SLen Brown  * MSR_PKG_C7_RESIDENCY            0x000003fa
3688d7899447SLen Brown  * MSR_CORE_C7_RESIDENCY           0x000003fe
3689d7899447SLen Brown  * MSR_PKG_C2_RESIDENCY            0x0000060d
3690d7899447SLen Brown  */
3691103a8feaSLen Brown 
3692d7899447SLen Brown int has_snb_msrs(unsigned int family, unsigned int model)
3693103a8feaSLen Brown {
3694103a8feaSLen Brown 	if (!genuine_intel)
3695103a8feaSLen Brown 		return 0;
3696103a8feaSLen Brown 
3697103a8feaSLen Brown 	switch (model) {
3698869ce69eSLen Brown 	case INTEL_FAM6_SANDYBRIDGE:
3699869ce69eSLen Brown 	case INTEL_FAM6_SANDYBRIDGE_X:
3700869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE:	/* IVB */
3701869ce69eSLen Brown 	case INTEL_FAM6_IVYBRIDGE_X:	/* IVB Xeon */
3702869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
3703869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_X:	/* HSW */
3704869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
3705869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
3706869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
3707869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_GT3E:	/* BDW */
3708869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_X:	/* BDX */
3709869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
3710869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
3711869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
3712869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
3713869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
3714869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_X:	/* SKX */
3715869ce69eSLen Brown 	case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
3716ac01ac13SLen Brown 	case INTEL_FAM6_ATOM_GEMINI_LAKE:
37175bbac26eSXiaolong Wang 	case INTEL_FAM6_ATOM_DENVERTON:	/* DNV */
3718103a8feaSLen Brown 		return 1;
3719103a8feaSLen Brown 	}
3720103a8feaSLen Brown 	return 0;
3721103a8feaSLen Brown }
3722103a8feaSLen Brown 
3723d7899447SLen Brown /*
3724d7899447SLen Brown  * HSW adds support for additional MSRs:
3725d7899447SLen Brown  *
3726d7899447SLen Brown  * MSR_PKG_C8_RESIDENCY		0x00000630
3727d7899447SLen Brown  * MSR_PKG_C9_RESIDENCY		0x00000631
3728d7899447SLen Brown  * MSR_PKG_C10_RESIDENCY	0x00000632
37295a63426eSLen Brown  *
37305a63426eSLen Brown  * MSR_PKGC8_IRTL		0x00000633
37315a63426eSLen Brown  * MSR_PKGC9_IRTL		0x00000634
37325a63426eSLen Brown  * MSR_PKGC10_IRTL		0x00000635
37335a63426eSLen Brown  *
3734d7899447SLen Brown  */
3735d7899447SLen Brown int has_hsw_msrs(unsigned int family, unsigned int model)
3736ca58710fSKristen Carlson Accardi {
3737ca58710fSKristen Carlson Accardi 	if (!genuine_intel)
3738ca58710fSKristen Carlson Accardi 		return 0;
3739ca58710fSKristen Carlson Accardi 
3740ca58710fSKristen Carlson Accardi 	switch (model) {
3741869ce69eSLen Brown 	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
3742869ce69eSLen Brown 	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
3743869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
3744869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
3745869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
3746869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
3747869ce69eSLen Brown 	case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
3748ac01ac13SLen Brown 	case INTEL_FAM6_ATOM_GEMINI_LAKE:
3749ca58710fSKristen Carlson Accardi 		return 1;
3750ca58710fSKristen Carlson Accardi 	}
3751ca58710fSKristen Carlson Accardi 	return 0;
3752ca58710fSKristen Carlson Accardi }
3753ca58710fSKristen Carlson Accardi 
37540b2bb692SLen Brown /*
37550b2bb692SLen Brown  * SKL adds support for additional MSRS:
37560b2bb692SLen Brown  *
37570b2bb692SLen Brown  * MSR_PKG_WEIGHTED_CORE_C0_RES    0x00000658
37580b2bb692SLen Brown  * MSR_PKG_ANY_CORE_C0_RES         0x00000659
37590b2bb692SLen Brown  * MSR_PKG_ANY_GFXE_C0_RES         0x0000065A
37600b2bb692SLen Brown  * MSR_PKG_BOTH_CORE_GFXE_C0_RES   0x0000065B
37610b2bb692SLen Brown  */
37620b2bb692SLen Brown int has_skl_msrs(unsigned int family, unsigned int model)
37630b2bb692SLen Brown {
37640b2bb692SLen Brown 	if (!genuine_intel)
37650b2bb692SLen Brown 		return 0;
37660b2bb692SLen Brown 
37670b2bb692SLen Brown 	switch (model) {
3768869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
3769869ce69eSLen Brown 	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
3770869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
3771869ce69eSLen Brown 	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
37720b2bb692SLen Brown 		return 1;
37730b2bb692SLen Brown 	}
37740b2bb692SLen Brown 	return 0;
37750b2bb692SLen Brown }
37760b2bb692SLen Brown 
3777144b44b1SLen Brown int is_slm(unsigned int family, unsigned int model)
3778144b44b1SLen Brown {
3779144b44b1SLen Brown 	if (!genuine_intel)
3780144b44b1SLen Brown 		return 0;
3781144b44b1SLen Brown 	switch (model) {
3782869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT1:	/* BYT */
3783869ce69eSLen Brown 	case INTEL_FAM6_ATOM_SILVERMONT2:	/* AVN */
3784144b44b1SLen Brown 		return 1;
3785144b44b1SLen Brown 	}
3786144b44b1SLen Brown 	return 0;
3787144b44b1SLen Brown }
3788144b44b1SLen Brown 
3789fb5d4327SDasaratharaman Chandramouli int is_knl(unsigned int family, unsigned int model)
3790fb5d4327SDasaratharaman Chandramouli {
3791fb5d4327SDasaratharaman Chandramouli 	if (!genuine_intel)
3792fb5d4327SDasaratharaman Chandramouli 		return 0;
3793fb5d4327SDasaratharaman Chandramouli 	switch (model) {
3794869ce69eSLen Brown 	case INTEL_FAM6_XEON_PHI_KNL:	/* KNL */
3795005c82d6SLen Brown 	case INTEL_FAM6_XEON_PHI_KNM:
3796fb5d4327SDasaratharaman Chandramouli 		return 1;
3797fb5d4327SDasaratharaman Chandramouli 	}
3798fb5d4327SDasaratharaman Chandramouli 	return 0;
3799fb5d4327SDasaratharaman Chandramouli }
3800fb5d4327SDasaratharaman Chandramouli 
3801b2b34dfeSHubert Chrzaniuk unsigned int get_aperf_mperf_multiplier(unsigned int family, unsigned int model)
3802b2b34dfeSHubert Chrzaniuk {
3803b2b34dfeSHubert Chrzaniuk 	if (is_knl(family, model))
3804b2b34dfeSHubert Chrzaniuk 		return 1024;
3805b2b34dfeSHubert Chrzaniuk 	return 1;
3806b2b34dfeSHubert Chrzaniuk }
3807b2b34dfeSHubert Chrzaniuk 
3808144b44b1SLen Brown #define SLM_BCLK_FREQS 5
3809144b44b1SLen Brown double slm_freq_table[SLM_BCLK_FREQS] = { 83.3, 100.0, 133.3, 116.7, 80.0};
3810144b44b1SLen Brown 
3811144b44b1SLen Brown double slm_bclk(void)
3812144b44b1SLen Brown {
3813144b44b1SLen Brown 	unsigned long long msr = 3;
3814144b44b1SLen Brown 	unsigned int i;
3815144b44b1SLen Brown 	double freq;
3816144b44b1SLen Brown 
38177ce7d5deSPrarit Bhargava 	if (get_msr(base_cpu, MSR_FSB_FREQ, &msr))
3818b7d8c148SLen Brown 		fprintf(outf, "SLM BCLK: unknown\n");
3819144b44b1SLen Brown 
3820144b44b1SLen Brown 	i = msr & 0xf;
3821144b44b1SLen Brown 	if (i >= SLM_BCLK_FREQS) {
3822b7d8c148SLen Brown 		fprintf(outf, "SLM BCLK[%d] invalid\n", i);
38230a91e551SColin Ian King 		i = 3;
3824144b44b1SLen Brown 	}
3825144b44b1SLen Brown 	freq = slm_freq_table[i];
3826144b44b1SLen Brown 
382796e47158SLen Brown 	if (!quiet)
3828b7d8c148SLen Brown 		fprintf(outf, "SLM BCLK: %.1f Mhz\n", freq);
3829144b44b1SLen Brown 
3830144b44b1SLen Brown 	return freq;
3831144b44b1SLen Brown }
3832144b44b1SLen Brown 
3833103a8feaSLen Brown double discover_bclk(unsigned int family, unsigned int model)
3834103a8feaSLen Brown {
3835121b48bbSChrzaniuk, Hubert 	if (has_snb_msrs(family, model) || is_knl(family, model))
3836103a8feaSLen Brown 		return 100.00;
3837144b44b1SLen Brown 	else if (is_slm(family, model))
3838144b44b1SLen Brown 		return slm_bclk();
3839103a8feaSLen Brown 	else
3840103a8feaSLen Brown 		return 133.33;
3841103a8feaSLen Brown }
3842103a8feaSLen Brown 
3843889facbeSLen Brown /*
3844889facbeSLen Brown  * MSR_IA32_TEMPERATURE_TARGET indicates the temperature where
3845889facbeSLen Brown  * the Thermal Control Circuit (TCC) activates.
3846889facbeSLen Brown  * This is usually equal to tjMax.
3847889facbeSLen Brown  *
3848889facbeSLen Brown  * Older processors do not have this MSR, so there we guess,
3849889facbeSLen Brown  * but also allow cmdline over-ride with -T.
3850889facbeSLen Brown  *
3851889facbeSLen Brown  * Several MSR temperature values are in units of degrees-C
3852889facbeSLen Brown  * below this value, including the Digital Thermal Sensor (DTS),
3853889facbeSLen Brown  * Package Thermal Management Sensor (PTM), and thermal event thresholds.
3854889facbeSLen Brown  */
3855889facbeSLen Brown int set_temperature_target(struct thread_data *t, struct core_data *c, struct pkg_data *p)
3856889facbeSLen Brown {
3857889facbeSLen Brown 	unsigned long long msr;
3858889facbeSLen Brown 	unsigned int target_c_local;
3859889facbeSLen Brown 	int cpu;
3860889facbeSLen Brown 
3861889facbeSLen Brown 	/* tcc_activation_temp is used only for dts or ptm */
3862889facbeSLen Brown 	if (!(do_dts || do_ptm))
3863889facbeSLen Brown 		return 0;
3864889facbeSLen Brown 
3865889facbeSLen Brown 	/* this is a per-package concept */
3866889facbeSLen Brown 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
3867889facbeSLen Brown 		return 0;
3868889facbeSLen Brown 
3869889facbeSLen Brown 	cpu = t->cpu_id;
3870889facbeSLen Brown 	if (cpu_migrate(cpu)) {
3871b7d8c148SLen Brown 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
3872889facbeSLen Brown 		return -1;
3873889facbeSLen Brown 	}
3874889facbeSLen Brown 
3875889facbeSLen Brown 	if (tcc_activation_temp_override != 0) {
3876889facbeSLen Brown 		tcc_activation_temp = tcc_activation_temp_override;
3877b7d8c148SLen Brown 		fprintf(outf, "cpu%d: Using cmdline TCC Target (%d C)\n",
3878889facbeSLen Brown 			cpu, tcc_activation_temp);
3879889facbeSLen Brown 		return 0;
3880889facbeSLen Brown 	}
3881889facbeSLen Brown 
3882889facbeSLen Brown 	/* Temperature Target MSR is Nehalem and newer only */
3883d7899447SLen Brown 	if (!do_nhm_platform_info)
3884889facbeSLen Brown 		goto guess;
3885889facbeSLen Brown 
38867ce7d5deSPrarit Bhargava 	if (get_msr(base_cpu, MSR_IA32_TEMPERATURE_TARGET, &msr))
3887889facbeSLen Brown 		goto guess;
3888889facbeSLen Brown 
38893482124aSJean Delvare 	target_c_local = (msr >> 16) & 0xFF;
3890889facbeSLen Brown 
389196e47158SLen Brown 	if (!quiet)
3892b7d8c148SLen Brown 		fprintf(outf, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C)\n",
3893889facbeSLen Brown 			cpu, msr, target_c_local);
3894889facbeSLen Brown 
38953482124aSJean Delvare 	if (!target_c_local)
3896889facbeSLen Brown 		goto guess;
3897889facbeSLen Brown 
3898889facbeSLen Brown 	tcc_activation_temp = target_c_local;
3899889facbeSLen Brown 
3900889facbeSLen Brown 	return 0;
3901889facbeSLen Brown 
3902889facbeSLen Brown guess:
3903889facbeSLen Brown 	tcc_activation_temp = TJMAX_DEFAULT;
3904b7d8c148SLen Brown 	fprintf(outf, "cpu%d: Guessing tjMax %d C, Please use -T to specify\n",
3905889facbeSLen Brown 		cpu, tcc_activation_temp);
3906889facbeSLen Brown 
3907889facbeSLen Brown 	return 0;
3908889facbeSLen Brown }
390969807a63SLen Brown 
3910aa8d8cc7SLen Brown void decode_feature_control_msr(void)
3911aa8d8cc7SLen Brown {
3912aa8d8cc7SLen Brown 	unsigned long long msr;
3913aa8d8cc7SLen Brown 
3914aa8d8cc7SLen Brown 	if (!get_msr(base_cpu, MSR_IA32_FEATURE_CONTROL, &msr))
3915aa8d8cc7SLen Brown 		fprintf(outf, "cpu%d: MSR_IA32_FEATURE_CONTROL: 0x%08llx (%sLocked %s)\n",
3916aa8d8cc7SLen Brown 			base_cpu, msr,
3917aa8d8cc7SLen Brown 			msr & FEATURE_CONTROL_LOCKED ? "" : "UN-",
3918aa8d8cc7SLen Brown 			msr & (1 << 18) ? "SGX" : "");
3919aa8d8cc7SLen Brown }
3920aa8d8cc7SLen Brown 
392169807a63SLen Brown void decode_misc_enable_msr(void)
392269807a63SLen Brown {
392369807a63SLen Brown 	unsigned long long msr;
392469807a63SLen Brown 
392569807a63SLen Brown 	if (!get_msr(base_cpu, MSR_IA32_MISC_ENABLE, &msr))
3926e6512624SLen Brown 		fprintf(outf, "cpu%d: MSR_IA32_MISC_ENABLE: 0x%08llx (%sTCC %sEIST %sMWAIT %sPREFETCH %sTURBO)\n",
392769807a63SLen Brown 			base_cpu, msr,
3928e6512624SLen Brown 			msr & MSR_IA32_MISC_ENABLE_TM1 ? "" : "No-",
3929e6512624SLen Brown 			msr & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP ? "" : "No-",
3930e6512624SLen Brown 			msr & MSR_IA32_MISC_ENABLE_MWAIT ? "No-" : "",
3931e6512624SLen Brown 			msr & MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE ? "No-" : "",
3932e6512624SLen Brown 			msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE ? "No-" : "");
393369807a63SLen Brown }
393469807a63SLen Brown 
393533148d67SLen Brown void decode_misc_feature_control(void)
393633148d67SLen Brown {
393733148d67SLen Brown 	unsigned long long msr;
393833148d67SLen Brown 
393933148d67SLen Brown 	if (!has_misc_feature_control)
394033148d67SLen Brown 		return;
394133148d67SLen Brown 
394233148d67SLen Brown 	if (!get_msr(base_cpu, MSR_MISC_FEATURE_CONTROL, &msr))
394333148d67SLen Brown 		fprintf(outf, "cpu%d: MSR_MISC_FEATURE_CONTROL: 0x%08llx (%sL2-Prefetch %sL2-Prefetch-pair %sL1-Prefetch %sL1-IP-Prefetch)\n",
394433148d67SLen Brown 			base_cpu, msr,
394533148d67SLen Brown 			msr & (0 << 0) ? "No-" : "",
394633148d67SLen Brown 			msr & (1 << 0) ? "No-" : "",
394733148d67SLen Brown 			msr & (2 << 0) ? "No-" : "",
394833148d67SLen Brown 			msr & (3 << 0) ? "No-" : "");
394933148d67SLen Brown }
3950f0057310SLen Brown /*
3951f0057310SLen Brown  * Decode MSR_MISC_PWR_MGMT
3952f0057310SLen Brown  *
3953f0057310SLen Brown  * Decode the bits according to the Nehalem documentation
3954f0057310SLen Brown  * bit[0] seems to continue to have same meaning going forward
3955f0057310SLen Brown  * bit[1] less so...
3956f0057310SLen Brown  */
3957f0057310SLen Brown void decode_misc_pwr_mgmt_msr(void)
3958f0057310SLen Brown {
3959f0057310SLen Brown 	unsigned long long msr;
3960f0057310SLen Brown 
3961f0057310SLen Brown 	if (!do_nhm_platform_info)
3962f0057310SLen Brown 		return;
3963f0057310SLen Brown 
3964cf4cbe53SLen Brown 	if (no_MSR_MISC_PWR_MGMT)
3965cf4cbe53SLen Brown 		return;
3966cf4cbe53SLen Brown 
3967f0057310SLen Brown 	if (!get_msr(base_cpu, MSR_MISC_PWR_MGMT, &msr))
3968ddadb8adSSrinivas Pandruvada 		fprintf(outf, "cpu%d: MSR_MISC_PWR_MGMT: 0x%08llx (%sable-EIST_Coordination %sable-EPB %sable-OOB)\n",
3969f0057310SLen Brown 			base_cpu, msr,
3970f0057310SLen Brown 			msr & (1 << 0) ? "DIS" : "EN",
3971ddadb8adSSrinivas Pandruvada 			msr & (1 << 1) ? "EN" : "DIS",
3972ddadb8adSSrinivas Pandruvada 			msr & (1 << 8) ? "EN" : "DIS");
3973f0057310SLen Brown }
397471616c8eSLen Brown /*
397571616c8eSLen Brown  * Decode MSR_CC6_DEMOTION_POLICY_CONFIG, MSR_MC6_DEMOTION_POLICY_CONFIG
397671616c8eSLen Brown  *
397771616c8eSLen Brown  * This MSRs are present on Silvermont processors,
397871616c8eSLen Brown  * Intel Atom processor E3000 series (Baytrail), and friends.
397971616c8eSLen Brown  */
398071616c8eSLen Brown void decode_c6_demotion_policy_msr(void)
398171616c8eSLen Brown {
398271616c8eSLen Brown 	unsigned long long msr;
398371616c8eSLen Brown 
398471616c8eSLen Brown 	if (!get_msr(base_cpu, MSR_CC6_DEMOTION_POLICY_CONFIG, &msr))
398571616c8eSLen Brown 		fprintf(outf, "cpu%d: MSR_CC6_DEMOTION_POLICY_CONFIG: 0x%08llx (%sable-CC6-Demotion)\n",
398671616c8eSLen Brown 			base_cpu, msr, msr & (1 << 0) ? "EN" : "DIS");
398771616c8eSLen Brown 
398871616c8eSLen Brown 	if (!get_msr(base_cpu, MSR_MC6_DEMOTION_POLICY_CONFIG, &msr))
398971616c8eSLen Brown 		fprintf(outf, "cpu%d: MSR_MC6_DEMOTION_POLICY_CONFIG: 0x%08llx (%sable-MC6-Demotion)\n",
399071616c8eSLen Brown 			base_cpu, msr, msr & (1 << 0) ? "EN" : "DIS");
399171616c8eSLen Brown }
39927f5c258eSLen Brown 
3993fcd17211SLen Brown void process_cpuid()
3994103a8feaSLen Brown {
399561a87ba7SLen Brown 	unsigned int eax, ebx, ecx, edx, max_level, max_extended_level;
3996103a8feaSLen Brown 	unsigned int fms, family, model, stepping;
3997b3a34e93SLen Brown 	unsigned int has_turbo;
3998103a8feaSLen Brown 
3999103a8feaSLen Brown 	eax = ebx = ecx = edx = 0;
4000103a8feaSLen Brown 
40015aea2f7fSLen Brown 	__cpuid(0, max_level, ebx, ecx, edx);
4002103a8feaSLen Brown 
4003103a8feaSLen Brown 	if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)
4004103a8feaSLen Brown 		genuine_intel = 1;
4005103a8feaSLen Brown 
400696e47158SLen Brown 	if (!quiet)
4007b7d8c148SLen Brown 		fprintf(outf, "CPUID(0): %.4s%.4s%.4s ",
4008103a8feaSLen Brown 			(char *)&ebx, (char *)&edx, (char *)&ecx);
4009103a8feaSLen Brown 
40105aea2f7fSLen Brown 	__cpuid(1, fms, ebx, ecx, edx);
4011103a8feaSLen Brown 	family = (fms >> 8) & 0xf;
4012103a8feaSLen Brown 	model = (fms >> 4) & 0xf;
4013103a8feaSLen Brown 	stepping = fms & 0xf;
4014103a8feaSLen Brown 	if (family == 6 || family == 0xf)
4015103a8feaSLen Brown 		model += ((fms >> 16) & 0xf) << 4;
4016103a8feaSLen Brown 
401796e47158SLen Brown 	if (!quiet) {
4018b7d8c148SLen Brown 		fprintf(outf, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n",
4019103a8feaSLen Brown 			max_level, family, model, stepping, family, model, stepping);
4020aa8d8cc7SLen Brown 		fprintf(outf, "CPUID(1): %s %s %s %s %s %s %s %s %s\n",
402169807a63SLen Brown 			ecx & (1 << 0) ? "SSE3" : "-",
402269807a63SLen Brown 			ecx & (1 << 3) ? "MONITOR" : "-",
4023aa8d8cc7SLen Brown 			ecx & (1 << 6) ? "SMX" : "-",
402469807a63SLen Brown 			ecx & (1 << 7) ? "EIST" : "-",
402569807a63SLen Brown 			ecx & (1 << 8) ? "TM2" : "-",
402669807a63SLen Brown 			edx & (1 << 4) ? "TSC" : "-",
402769807a63SLen Brown 			edx & (1 << 5) ? "MSR" : "-",
402869807a63SLen Brown 			edx & (1 << 22) ? "ACPI-TM" : "-",
402969807a63SLen Brown 			edx & (1 << 29) ? "TM" : "-");
403069807a63SLen Brown 	}
4031103a8feaSLen Brown 
4032b2c95d90SJosh Triplett 	if (!(edx & (1 << 5)))
4033b2c95d90SJosh Triplett 		errx(1, "CPUID: no MSR");
4034103a8feaSLen Brown 
4035103a8feaSLen Brown 	/*
4036103a8feaSLen Brown 	 * check max extended function levels of CPUID.
4037103a8feaSLen Brown 	 * This is needed to check for invariant TSC.
4038103a8feaSLen Brown 	 * This check is valid for both Intel and AMD.
4039103a8feaSLen Brown 	 */
4040103a8feaSLen Brown 	ebx = ecx = edx = 0;
40415aea2f7fSLen Brown 	__cpuid(0x80000000, max_extended_level, ebx, ecx, edx);
4042103a8feaSLen Brown 
404361a87ba7SLen Brown 	if (max_extended_level >= 0x80000007) {
4044103a8feaSLen Brown 
4045103a8feaSLen Brown 		/*
4046103a8feaSLen Brown 		 * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8
4047103a8feaSLen Brown 		 * this check is valid for both Intel and AMD
4048103a8feaSLen Brown 		 */
40495aea2f7fSLen Brown 		__cpuid(0x80000007, eax, ebx, ecx, edx);
40508209e054SThomas Renninger 		has_invariant_tsc = edx & (1 << 8);
4051d7899447SLen Brown 	}
4052103a8feaSLen Brown 
4053103a8feaSLen Brown 	/*
4054103a8feaSLen Brown 	 * APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0
4055103a8feaSLen Brown 	 * this check is valid for both Intel and AMD
4056103a8feaSLen Brown 	 */
4057103a8feaSLen Brown 
40585aea2f7fSLen Brown 	__cpuid(0x6, eax, ebx, ecx, edx);
40598209e054SThomas Renninger 	has_aperf = ecx & (1 << 0);
4060812db3f7SLen Brown 	if (has_aperf) {
4061812db3f7SLen Brown 		BIC_PRESENT(BIC_Avg_MHz);
4062812db3f7SLen Brown 		BIC_PRESENT(BIC_Busy);
4063812db3f7SLen Brown 		BIC_PRESENT(BIC_Bzy_MHz);
4064812db3f7SLen Brown 	}
4065889facbeSLen Brown 	do_dts = eax & (1 << 0);
4066812db3f7SLen Brown 	if (do_dts)
4067812db3f7SLen Brown 		BIC_PRESENT(BIC_CoreTmp);
4068b3a34e93SLen Brown 	has_turbo = eax & (1 << 1);
4069889facbeSLen Brown 	do_ptm = eax & (1 << 6);
4070812db3f7SLen Brown 	if (do_ptm)
4071812db3f7SLen Brown 		BIC_PRESENT(BIC_PkgTmp);
40727f5c258eSLen Brown 	has_hwp = eax & (1 << 7);
40737f5c258eSLen Brown 	has_hwp_notify = eax & (1 << 8);
40747f5c258eSLen Brown 	has_hwp_activity_window = eax & (1 << 9);
40757f5c258eSLen Brown 	has_hwp_epp = eax & (1 << 10);
40767f5c258eSLen Brown 	has_hwp_pkg = eax & (1 << 11);
4077889facbeSLen Brown 	has_epb = ecx & (1 << 3);
4078889facbeSLen Brown 
407996e47158SLen Brown 	if (!quiet)
4080b3a34e93SLen Brown 		fprintf(outf, "CPUID(6): %sAPERF, %sTURBO, %sDTS, %sPTM, %sHWP, "
40817f5c258eSLen Brown 			"%sHWPnotify, %sHWPwindow, %sHWPepp, %sHWPpkg, %sEPB\n",
40827f5c258eSLen Brown 			has_aperf ? "" : "No-",
4083b3a34e93SLen Brown 			has_turbo ? "" : "No-",
40847f5c258eSLen Brown 			do_dts ? "" : "No-",
40857f5c258eSLen Brown 			do_ptm ? "" : "No-",
40867f5c258eSLen Brown 			has_hwp ? "" : "No-",
40877f5c258eSLen Brown 			has_hwp_notify ? "" : "No-",
40887f5c258eSLen Brown 			has_hwp_activity_window ? "" : "No-",
40897f5c258eSLen Brown 			has_hwp_epp ? "" : "No-",
40907f5c258eSLen Brown 			has_hwp_pkg ? "" : "No-",
40917f5c258eSLen Brown 			has_epb ? "" : "No-");
4092103a8feaSLen Brown 
409396e47158SLen Brown 	if (!quiet)
409469807a63SLen Brown 		decode_misc_enable_msr();
409569807a63SLen Brown 
409633148d67SLen Brown 
409796e47158SLen Brown 	if (max_level >= 0x7 && !quiet) {
4098aa8d8cc7SLen Brown 		int has_sgx;
4099aa8d8cc7SLen Brown 
4100aa8d8cc7SLen Brown 		ecx = 0;
4101aa8d8cc7SLen Brown 
4102aa8d8cc7SLen Brown 		__cpuid_count(0x7, 0, eax, ebx, ecx, edx);
4103aa8d8cc7SLen Brown 
4104aa8d8cc7SLen Brown 		has_sgx = ebx & (1 << 2);
4105aa8d8cc7SLen Brown 		fprintf(outf, "CPUID(7): %sSGX\n", has_sgx ? "" : "No-");
4106aa8d8cc7SLen Brown 
4107aa8d8cc7SLen Brown 		if (has_sgx)
4108aa8d8cc7SLen Brown 			decode_feature_control_msr();
4109aa8d8cc7SLen Brown 	}
4110aa8d8cc7SLen Brown 
411161a87ba7SLen Brown 	if (max_level >= 0x15) {
41128a5bdf41SLen Brown 		unsigned int eax_crystal;
41138a5bdf41SLen Brown 		unsigned int ebx_tsc;
41148a5bdf41SLen Brown 
41158a5bdf41SLen Brown 		/*
41168a5bdf41SLen Brown 		 * CPUID 15H TSC/Crystal ratio, possibly Crystal Hz
41178a5bdf41SLen Brown 		 */
41188a5bdf41SLen Brown 		eax_crystal = ebx_tsc = crystal_hz = edx = 0;
41195aea2f7fSLen Brown 		__cpuid(0x15, eax_crystal, ebx_tsc, crystal_hz, edx);
41208a5bdf41SLen Brown 
41218a5bdf41SLen Brown 		if (ebx_tsc != 0) {
41228a5bdf41SLen Brown 
412396e47158SLen Brown 			if (!quiet && (ebx != 0))
4124b7d8c148SLen Brown 				fprintf(outf, "CPUID(0x15): eax_crystal: %d ebx_tsc: %d ecx_crystal_hz: %d\n",
41258a5bdf41SLen Brown 					eax_crystal, ebx_tsc, crystal_hz);
41268a5bdf41SLen Brown 
41278a5bdf41SLen Brown 			if (crystal_hz == 0)
41288a5bdf41SLen Brown 				switch(model) {
4129869ce69eSLen Brown 				case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
4130869ce69eSLen Brown 				case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
4131869ce69eSLen Brown 				case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
4132869ce69eSLen Brown 				case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
4133e8efbc80SLen Brown 					crystal_hz = 24000000;	/* 24.0 MHz */
4134e8efbc80SLen Brown 					break;
4135869ce69eSLen Brown 				case INTEL_FAM6_SKYLAKE_X:	/* SKX */
41367268d407SLen Brown 				case INTEL_FAM6_ATOM_DENVERTON:	/* DNV */
4137ec53e594SLen Brown 					crystal_hz = 25000000;	/* 25.0 MHz */
4138ec53e594SLen Brown 					break;
4139869ce69eSLen Brown 				case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
4140ac01ac13SLen Brown 				case INTEL_FAM6_ATOM_GEMINI_LAKE:
4141e8efbc80SLen Brown 					crystal_hz = 19200000;	/* 19.2 MHz */
41428a5bdf41SLen Brown 					break;
41438a5bdf41SLen Brown 				default:
41448a5bdf41SLen Brown 					crystal_hz = 0;
41458a5bdf41SLen Brown 			}
41468a5bdf41SLen Brown 
41478a5bdf41SLen Brown 			if (crystal_hz) {
41488a5bdf41SLen Brown 				tsc_hz =  (unsigned long long) crystal_hz * ebx_tsc / eax_crystal;
414996e47158SLen Brown 				if (!quiet)
4150b7d8c148SLen Brown 					fprintf(outf, "TSC: %lld MHz (%d Hz * %d / %d / 1000000)\n",
41518a5bdf41SLen Brown 						tsc_hz / 1000000, crystal_hz, ebx_tsc,  eax_crystal);
41528a5bdf41SLen Brown 			}
41538a5bdf41SLen Brown 		}
41548a5bdf41SLen Brown 	}
415561a87ba7SLen Brown 	if (max_level >= 0x16) {
415661a87ba7SLen Brown 		unsigned int base_mhz, max_mhz, bus_mhz, edx;
415761a87ba7SLen Brown 
415861a87ba7SLen Brown 		/*
415961a87ba7SLen Brown 		 * CPUID 16H Base MHz, Max MHz, Bus MHz
416061a87ba7SLen Brown 		 */
416161a87ba7SLen Brown 		base_mhz = max_mhz = bus_mhz = edx = 0;
416261a87ba7SLen Brown 
41635aea2f7fSLen Brown 		__cpuid(0x16, base_mhz, max_mhz, bus_mhz, edx);
416496e47158SLen Brown 		if (!quiet)
4165b7d8c148SLen Brown 			fprintf(outf, "CPUID(0x16): base_mhz: %d max_mhz: %d bus_mhz: %d\n",
416661a87ba7SLen Brown 				base_mhz, max_mhz, bus_mhz);
416761a87ba7SLen Brown 	}
41688a5bdf41SLen Brown 
4169b2b34dfeSHubert Chrzaniuk 	if (has_aperf)
4170b2b34dfeSHubert Chrzaniuk 		aperf_mperf_multiplier = get_aperf_mperf_multiplier(family, model);
4171b2b34dfeSHubert Chrzaniuk 
4172812db3f7SLen Brown 	BIC_PRESENT(BIC_IRQ);
4173812db3f7SLen Brown 	BIC_PRESENT(BIC_TSC_MHz);
4174812db3f7SLen Brown 
4175812db3f7SLen Brown 	if (probe_nhm_msrs(family, model)) {
4176812db3f7SLen Brown 		do_nhm_platform_info = 1;
4177812db3f7SLen Brown 		BIC_PRESENT(BIC_CPU_c1);
4178812db3f7SLen Brown 		BIC_PRESENT(BIC_CPU_c3);
4179812db3f7SLen Brown 		BIC_PRESENT(BIC_CPU_c6);
4180812db3f7SLen Brown 		BIC_PRESENT(BIC_SMI);
4181812db3f7SLen Brown 	}
4182d7899447SLen Brown 	do_snb_cstates = has_snb_msrs(family, model);
4183812db3f7SLen Brown 
4184812db3f7SLen Brown 	if (do_snb_cstates)
4185812db3f7SLen Brown 		BIC_PRESENT(BIC_CPU_c7);
4186812db3f7SLen Brown 
41875a63426eSLen Brown 	do_irtl_snb = has_snb_msrs(family, model);
41880f47c08dSLen Brown 	if (do_snb_cstates && (pkg_cstate_limit >= PCL__2))
41890f47c08dSLen Brown 		BIC_PRESENT(BIC_Pkgpc2);
41900f47c08dSLen Brown 	if (pkg_cstate_limit >= PCL__3)
41910f47c08dSLen Brown 		BIC_PRESENT(BIC_Pkgpc3);
41920f47c08dSLen Brown 	if (pkg_cstate_limit >= PCL__6)
41930f47c08dSLen Brown 		BIC_PRESENT(BIC_Pkgpc6);
41940f47c08dSLen Brown 	if (do_snb_cstates && (pkg_cstate_limit >= PCL__7))
41950f47c08dSLen Brown 		BIC_PRESENT(BIC_Pkgpc7);
41960539ba11SLen Brown 	if (has_slv_msrs(family, model)) {
41970f47c08dSLen Brown 		BIC_NOT_PRESENT(BIC_Pkgpc2);
41980f47c08dSLen Brown 		BIC_NOT_PRESENT(BIC_Pkgpc3);
41990f47c08dSLen Brown 		BIC_PRESENT(BIC_Pkgpc6);
42000f47c08dSLen Brown 		BIC_NOT_PRESENT(BIC_Pkgpc7);
42010539ba11SLen Brown 		BIC_PRESENT(BIC_Mod_c6);
42020539ba11SLen Brown 		use_c1_residency_msr = 1;
42030539ba11SLen Brown 	}
42047170a374SLen Brown 	if (is_dnv(family, model)) {
42057170a374SLen Brown 		BIC_PRESENT(BIC_CPU_c1);
42067170a374SLen Brown 		BIC_NOT_PRESENT(BIC_CPU_c3);
42077170a374SLen Brown 		BIC_NOT_PRESENT(BIC_Pkgpc3);
42087170a374SLen Brown 		BIC_NOT_PRESENT(BIC_CPU_c7);
42097170a374SLen Brown 		BIC_NOT_PRESENT(BIC_Pkgpc7);
42107170a374SLen Brown 		use_c1_residency_msr = 1;
42117170a374SLen Brown 	}
421234c76197SLen Brown 	if (is_skx(family, model)) {
421334c76197SLen Brown 		BIC_NOT_PRESENT(BIC_CPU_c3);
421434c76197SLen Brown 		BIC_NOT_PRESENT(BIC_Pkgpc3);
421534c76197SLen Brown 		BIC_NOT_PRESENT(BIC_CPU_c7);
421634c76197SLen Brown 		BIC_NOT_PRESENT(BIC_Pkgpc7);
421734c76197SLen Brown 	}
4218ade0ebacSLen Brown 	if (is_bdx(family, model)) {
4219ade0ebacSLen Brown 		BIC_NOT_PRESENT(BIC_CPU_c7);
4220ade0ebacSLen Brown 		BIC_NOT_PRESENT(BIC_Pkgpc7);
4221ade0ebacSLen Brown 	}
42220f47c08dSLen Brown 	if (has_hsw_msrs(family, model)) {
42230f47c08dSLen Brown 		BIC_PRESENT(BIC_Pkgpc8);
42240f47c08dSLen Brown 		BIC_PRESENT(BIC_Pkgpc9);
42250f47c08dSLen Brown 		BIC_PRESENT(BIC_Pkgpc10);
42260f47c08dSLen Brown 	}
42275a63426eSLen Brown 	do_irtl_hsw = has_hsw_msrs(family, model);
4228*a99d8730SLen Brown 	if (has_skl_msrs(family, model)) {
4229*a99d8730SLen Brown 		BIC_PRESENT(BIC_Totl_c0);
4230*a99d8730SLen Brown 		BIC_PRESENT(BIC_Any_c0);
4231*a99d8730SLen Brown 		BIC_PRESENT(BIC_GFX_c0);
4232*a99d8730SLen Brown 		BIC_PRESENT(BIC_CPUGFX);
4233*a99d8730SLen Brown 	}
4234144b44b1SLen Brown 	do_slm_cstates = is_slm(family, model);
4235fb5d4327SDasaratharaman Chandramouli 	do_knl_cstates  = is_knl(family, model);
4236103a8feaSLen Brown 
423796e47158SLen Brown 	if (!quiet)
4238f0057310SLen Brown 		decode_misc_pwr_mgmt_msr();
4239f0057310SLen Brown 
424096e47158SLen Brown 	if (!quiet && has_slv_msrs(family, model))
424171616c8eSLen Brown 		decode_c6_demotion_policy_msr();
424271616c8eSLen Brown 
4243889facbeSLen Brown 	rapl_probe(family, model);
42443a9a941dSLen Brown 	perf_limit_reasons_probe(family, model);
4245889facbeSLen Brown 
424696e47158SLen Brown 	if (!quiet)
42471b69317dSColin Ian King 		dump_cstate_pstate_config_info(family, model);
4248fcd17211SLen Brown 
424941618e63SLen Brown 	if (!quiet)
425041618e63SLen Brown 		dump_sysfs_cstate_config();
42517293fccdSLen Brown 	if (!quiet)
42527293fccdSLen Brown 		dump_sysfs_pstate_config();
425341618e63SLen Brown 
4254a2b7b749SLen Brown 	if (has_skl_msrs(family, model))
4255a2b7b749SLen Brown 		calculate_tsc_tweak();
4256a2b7b749SLen Brown 
4257812db3f7SLen Brown 	if (!access("/sys/class/drm/card0/power/rc6_residency_ms", R_OK))
4258812db3f7SLen Brown 		BIC_PRESENT(BIC_GFX_rc6);
4259fdf676e5SLen Brown 
4260812db3f7SLen Brown 	if (!access("/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz", R_OK))
4261812db3f7SLen Brown 		BIC_PRESENT(BIC_GFXMHz);
426227d47356SLen Brown 
426396e47158SLen Brown 	if (!quiet)
426433148d67SLen Brown 		decode_misc_feature_control();
426533148d67SLen Brown 
4266889facbeSLen Brown 	return;
4267103a8feaSLen Brown }
4268103a8feaSLen Brown 
4269103a8feaSLen Brown 
4270103a8feaSLen Brown /*
4271103a8feaSLen Brown  * in /dev/cpu/ return success for names that are numbers
4272103a8feaSLen Brown  * ie. filter out ".", "..", "microcode".
4273103a8feaSLen Brown  */
4274103a8feaSLen Brown int dir_filter(const struct dirent *dirp)
4275103a8feaSLen Brown {
4276103a8feaSLen Brown 	if (isdigit(dirp->d_name[0]))
4277103a8feaSLen Brown 		return 1;
4278103a8feaSLen Brown 	else
4279103a8feaSLen Brown 		return 0;
4280103a8feaSLen Brown }
4281103a8feaSLen Brown 
4282103a8feaSLen Brown int open_dev_cpu_msr(int dummy1)
4283103a8feaSLen Brown {
4284103a8feaSLen Brown 	return 0;
4285103a8feaSLen Brown }
4286103a8feaSLen Brown 
4287c98d5d94SLen Brown void topology_probe()
4288c98d5d94SLen Brown {
4289c98d5d94SLen Brown 	int i;
4290c98d5d94SLen Brown 	int max_core_id = 0;
4291c98d5d94SLen Brown 	int max_package_id = 0;
4292c98d5d94SLen Brown 	int max_siblings = 0;
4293c98d5d94SLen Brown 	struct cpu_topology {
4294c98d5d94SLen Brown 		int core_id;
4295c98d5d94SLen Brown 		int physical_package_id;
4296c98d5d94SLen Brown 	} *cpus;
4297c98d5d94SLen Brown 
4298c98d5d94SLen Brown 	/* Initialize num_cpus, max_cpu_num */
4299c98d5d94SLen Brown 	topo.num_cpus = 0;
4300c98d5d94SLen Brown 	topo.max_cpu_num = 0;
4301c98d5d94SLen Brown 	for_all_proc_cpus(count_cpus);
4302c98d5d94SLen Brown 	if (!summary_only && topo.num_cpus > 1)
4303812db3f7SLen Brown 		BIC_PRESENT(BIC_CPU);
4304c98d5d94SLen Brown 
4305d8af6f5fSLen Brown 	if (debug > 1)
4306b7d8c148SLen Brown 		fprintf(outf, "num_cpus %d max_cpu_num %d\n", topo.num_cpus, topo.max_cpu_num);
4307c98d5d94SLen Brown 
4308c98d5d94SLen Brown 	cpus = calloc(1, (topo.max_cpu_num  + 1) * sizeof(struct cpu_topology));
4309b2c95d90SJosh Triplett 	if (cpus == NULL)
4310b2c95d90SJosh Triplett 		err(1, "calloc cpus");
4311c98d5d94SLen Brown 
4312c98d5d94SLen Brown 	/*
4313c98d5d94SLen Brown 	 * Allocate and initialize cpu_present_set
4314c98d5d94SLen Brown 	 */
4315c98d5d94SLen Brown 	cpu_present_set = CPU_ALLOC((topo.max_cpu_num + 1));
4316b2c95d90SJosh Triplett 	if (cpu_present_set == NULL)
4317b2c95d90SJosh Triplett 		err(3, "CPU_ALLOC");
4318c98d5d94SLen Brown 	cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
4319c98d5d94SLen Brown 	CPU_ZERO_S(cpu_present_setsize, cpu_present_set);
4320c98d5d94SLen Brown 	for_all_proc_cpus(mark_cpu_present);
4321c98d5d94SLen Brown 
4322c98d5d94SLen Brown 	/*
43231ef7d21aSLen Brown 	 * Validate that all cpus in cpu_subset are also in cpu_present_set
43241ef7d21aSLen Brown 	 */
43251ef7d21aSLen Brown 	for (i = 0; i < CPU_SUBSET_MAXCPUS; ++i) {
43261ef7d21aSLen Brown 		if (CPU_ISSET_S(i, cpu_subset_size, cpu_subset))
43271ef7d21aSLen Brown 			if (!CPU_ISSET_S(i, cpu_present_setsize, cpu_present_set))
43281ef7d21aSLen Brown 				err(1, "cpu%d not present", i);
43291ef7d21aSLen Brown 	}
43301ef7d21aSLen Brown 
43311ef7d21aSLen Brown 	/*
4332c98d5d94SLen Brown 	 * Allocate and initialize cpu_affinity_set
4333c98d5d94SLen Brown 	 */
4334c98d5d94SLen Brown 	cpu_affinity_set = CPU_ALLOC((topo.max_cpu_num + 1));
4335b2c95d90SJosh Triplett 	if (cpu_affinity_set == NULL)
4336b2c95d90SJosh Triplett 		err(3, "CPU_ALLOC");
4337c98d5d94SLen Brown 	cpu_affinity_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
4338c98d5d94SLen Brown 	CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set);
4339c98d5d94SLen Brown 
4340c98d5d94SLen Brown 
4341c98d5d94SLen Brown 	/*
4342c98d5d94SLen Brown 	 * For online cpus
4343c98d5d94SLen Brown 	 * find max_core_id, max_package_id
4344c98d5d94SLen Brown 	 */
4345c98d5d94SLen Brown 	for (i = 0; i <= topo.max_cpu_num; ++i) {
4346c98d5d94SLen Brown 		int siblings;
4347c98d5d94SLen Brown 
4348c98d5d94SLen Brown 		if (cpu_is_not_present(i)) {
4349d8af6f5fSLen Brown 			if (debug > 1)
4350b7d8c148SLen Brown 				fprintf(outf, "cpu%d NOT PRESENT\n", i);
4351c98d5d94SLen Brown 			continue;
4352c98d5d94SLen Brown 		}
4353c98d5d94SLen Brown 		cpus[i].core_id = get_core_id(i);
4354c98d5d94SLen Brown 		if (cpus[i].core_id > max_core_id)
4355c98d5d94SLen Brown 			max_core_id = cpus[i].core_id;
4356c98d5d94SLen Brown 
4357c98d5d94SLen Brown 		cpus[i].physical_package_id = get_physical_package_id(i);
4358c98d5d94SLen Brown 		if (cpus[i].physical_package_id > max_package_id)
4359c98d5d94SLen Brown 			max_package_id = cpus[i].physical_package_id;
4360c98d5d94SLen Brown 
4361c98d5d94SLen Brown 		siblings = get_num_ht_siblings(i);
4362c98d5d94SLen Brown 		if (siblings > max_siblings)
4363c98d5d94SLen Brown 			max_siblings = siblings;
4364d8af6f5fSLen Brown 		if (debug > 1)
4365b7d8c148SLen Brown 			fprintf(outf, "cpu %d pkg %d core %d\n",
4366c98d5d94SLen Brown 				i, cpus[i].physical_package_id, cpus[i].core_id);
4367c98d5d94SLen Brown 	}
4368c98d5d94SLen Brown 	topo.num_cores_per_pkg = max_core_id + 1;
4369d8af6f5fSLen Brown 	if (debug > 1)
4370b7d8c148SLen Brown 		fprintf(outf, "max_core_id %d, sizing for %d cores per package\n",
4371c98d5d94SLen Brown 			max_core_id, topo.num_cores_per_pkg);
43720f47c08dSLen Brown 	if (!summary_only && topo.num_cores_per_pkg > 1)
4373812db3f7SLen Brown 		BIC_PRESENT(BIC_Core);
4374c98d5d94SLen Brown 
4375c98d5d94SLen Brown 	topo.num_packages = max_package_id + 1;
4376d8af6f5fSLen Brown 	if (debug > 1)
4377b7d8c148SLen Brown 		fprintf(outf, "max_package_id %d, sizing for %d packages\n",
4378c98d5d94SLen Brown 			max_package_id, topo.num_packages);
43797da6e3e2SLen Brown 	if (!summary_only && topo.num_packages > 1)
4380812db3f7SLen Brown 		BIC_PRESENT(BIC_Package);
4381c98d5d94SLen Brown 
4382c98d5d94SLen Brown 	topo.num_threads_per_core = max_siblings;
4383d8af6f5fSLen Brown 	if (debug > 1)
4384b7d8c148SLen Brown 		fprintf(outf, "max_siblings %d\n", max_siblings);
4385c98d5d94SLen Brown 
4386c98d5d94SLen Brown 	free(cpus);
4387c98d5d94SLen Brown }
4388c98d5d94SLen Brown 
4389c98d5d94SLen Brown void
4390c98d5d94SLen Brown allocate_counters(struct thread_data **t, struct core_data **c, struct pkg_data **p)
4391c98d5d94SLen Brown {
4392c98d5d94SLen Brown 	int i;
4393c98d5d94SLen Brown 
4394c98d5d94SLen Brown 	*t = calloc(topo.num_threads_per_core * topo.num_cores_per_pkg *
4395678a3bd1SLen Brown 		topo.num_packages, sizeof(struct thread_data));
4396c98d5d94SLen Brown 	if (*t == NULL)
4397c98d5d94SLen Brown 		goto error;
4398c98d5d94SLen Brown 
4399c98d5d94SLen Brown 	for (i = 0; i < topo.num_threads_per_core *
4400c98d5d94SLen Brown 		topo.num_cores_per_pkg * topo.num_packages; i++)
4401c98d5d94SLen Brown 		(*t)[i].cpu_id = -1;
4402c98d5d94SLen Brown 
4403c98d5d94SLen Brown 	*c = calloc(topo.num_cores_per_pkg * topo.num_packages,
4404678a3bd1SLen Brown 		sizeof(struct core_data));
4405c98d5d94SLen Brown 	if (*c == NULL)
4406c98d5d94SLen Brown 		goto error;
4407c98d5d94SLen Brown 
4408c98d5d94SLen Brown 	for (i = 0; i < topo.num_cores_per_pkg * topo.num_packages; i++)
4409c98d5d94SLen Brown 		(*c)[i].core_id = -1;
4410c98d5d94SLen Brown 
4411678a3bd1SLen Brown 	*p = calloc(topo.num_packages, sizeof(struct pkg_data));
4412c98d5d94SLen Brown 	if (*p == NULL)
4413c98d5d94SLen Brown 		goto error;
4414c98d5d94SLen Brown 
4415c98d5d94SLen Brown 	for (i = 0; i < topo.num_packages; i++)
4416c98d5d94SLen Brown 		(*p)[i].package_id = i;
4417c98d5d94SLen Brown 
4418c98d5d94SLen Brown 	return;
4419c98d5d94SLen Brown error:
4420b2c95d90SJosh Triplett 	err(1, "calloc counters");
4421c98d5d94SLen Brown }
4422c98d5d94SLen Brown /*
4423c98d5d94SLen Brown  * init_counter()
4424c98d5d94SLen Brown  *
4425c98d5d94SLen Brown  * set cpu_id, core_num, pkg_num
4426c98d5d94SLen Brown  * set FIRST_THREAD_IN_CORE and FIRST_CORE_IN_PACKAGE
4427c98d5d94SLen Brown  *
4428c98d5d94SLen Brown  * increment topo.num_cores when 1st core in pkg seen
4429c98d5d94SLen Brown  */
4430c98d5d94SLen Brown void init_counter(struct thread_data *thread_base, struct core_data *core_base,
4431c98d5d94SLen Brown 	struct pkg_data *pkg_base, int thread_num, int core_num,
4432c98d5d94SLen Brown 	int pkg_num, int cpu_id)
4433c98d5d94SLen Brown {
4434c98d5d94SLen Brown 	struct thread_data *t;
4435c98d5d94SLen Brown 	struct core_data *c;
4436c98d5d94SLen Brown 	struct pkg_data *p;
4437c98d5d94SLen Brown 
4438c98d5d94SLen Brown 	t = GET_THREAD(thread_base, thread_num, core_num, pkg_num);
4439c98d5d94SLen Brown 	c = GET_CORE(core_base, core_num, pkg_num);
4440c98d5d94SLen Brown 	p = GET_PKG(pkg_base, pkg_num);
4441c98d5d94SLen Brown 
4442c98d5d94SLen Brown 	t->cpu_id = cpu_id;
4443c98d5d94SLen Brown 	if (thread_num == 0) {
4444c98d5d94SLen Brown 		t->flags |= CPU_IS_FIRST_THREAD_IN_CORE;
4445c98d5d94SLen Brown 		if (cpu_is_first_core_in_package(cpu_id))
4446c98d5d94SLen Brown 			t->flags |= CPU_IS_FIRST_CORE_IN_PACKAGE;
4447c98d5d94SLen Brown 	}
4448c98d5d94SLen Brown 
4449c98d5d94SLen Brown 	c->core_id = core_num;
4450c98d5d94SLen Brown 	p->package_id = pkg_num;
4451c98d5d94SLen Brown }
4452c98d5d94SLen Brown 
4453c98d5d94SLen Brown 
4454c98d5d94SLen Brown int initialize_counters(int cpu_id)
4455c98d5d94SLen Brown {
4456c98d5d94SLen Brown 	int my_thread_id, my_core_id, my_package_id;
4457c98d5d94SLen Brown 
4458c98d5d94SLen Brown 	my_package_id = get_physical_package_id(cpu_id);
4459c98d5d94SLen Brown 	my_core_id = get_core_id(cpu_id);
4460e275b388SDasaratharaman Chandramouli 	my_thread_id = get_cpu_position_in_core(cpu_id);
4461e275b388SDasaratharaman Chandramouli 	if (!my_thread_id)
4462c98d5d94SLen Brown 		topo.num_cores++;
4463c98d5d94SLen Brown 
4464c98d5d94SLen Brown 	init_counter(EVEN_COUNTERS, my_thread_id, my_core_id, my_package_id, cpu_id);
4465c98d5d94SLen Brown 	init_counter(ODD_COUNTERS, my_thread_id, my_core_id, my_package_id, cpu_id);
4466c98d5d94SLen Brown 	return 0;
4467c98d5d94SLen Brown }
4468c98d5d94SLen Brown 
4469c98d5d94SLen Brown void allocate_output_buffer()
4470c98d5d94SLen Brown {
44713b4d5c7fSAndy Shevchenko 	output_buffer = calloc(1, (1 + topo.num_cpus) * 1024);
4472c98d5d94SLen Brown 	outp = output_buffer;
4473b2c95d90SJosh Triplett 	if (outp == NULL)
4474b2c95d90SJosh Triplett 		err(-1, "calloc output buffer");
4475c98d5d94SLen Brown }
447636229897SLen Brown void allocate_fd_percpu(void)
447736229897SLen Brown {
447801a67adfSMika Westerberg 	fd_percpu = calloc(topo.max_cpu_num + 1, sizeof(int));
447936229897SLen Brown 	if (fd_percpu == NULL)
448036229897SLen Brown 		err(-1, "calloc fd_percpu");
448136229897SLen Brown }
4482562a2d37SLen Brown void allocate_irq_buffers(void)
4483562a2d37SLen Brown {
4484562a2d37SLen Brown 	irq_column_2_cpu = calloc(topo.num_cpus, sizeof(int));
4485562a2d37SLen Brown 	if (irq_column_2_cpu == NULL)
4486562a2d37SLen Brown 		err(-1, "calloc %d", topo.num_cpus);
4487c98d5d94SLen Brown 
448801a67adfSMika Westerberg 	irqs_per_cpu = calloc(topo.max_cpu_num + 1, sizeof(int));
4489562a2d37SLen Brown 	if (irqs_per_cpu == NULL)
449001a67adfSMika Westerberg 		err(-1, "calloc %d", topo.max_cpu_num + 1);
4491562a2d37SLen Brown }
4492c98d5d94SLen Brown void setup_all_buffers(void)
4493c98d5d94SLen Brown {
4494c98d5d94SLen Brown 	topology_probe();
4495562a2d37SLen Brown 	allocate_irq_buffers();
449636229897SLen Brown 	allocate_fd_percpu();
4497c98d5d94SLen Brown 	allocate_counters(&thread_even, &core_even, &package_even);
4498c98d5d94SLen Brown 	allocate_counters(&thread_odd, &core_odd, &package_odd);
4499c98d5d94SLen Brown 	allocate_output_buffer();
4500c98d5d94SLen Brown 	for_all_proc_cpus(initialize_counters);
4501c98d5d94SLen Brown }
45023b4d5c7fSAndy Shevchenko 
45037ce7d5deSPrarit Bhargava void set_base_cpu(void)
45047ce7d5deSPrarit Bhargava {
45057ce7d5deSPrarit Bhargava 	base_cpu = sched_getcpu();
45067ce7d5deSPrarit Bhargava 	if (base_cpu < 0)
45077ce7d5deSPrarit Bhargava 		err(-ENODEV, "No valid cpus found");
45087ce7d5deSPrarit Bhargava 
45097ce7d5deSPrarit Bhargava 	if (debug > 1)
4510b7d8c148SLen Brown 		fprintf(outf, "base_cpu = %d\n", base_cpu);
45117ce7d5deSPrarit Bhargava }
45127ce7d5deSPrarit Bhargava 
4513103a8feaSLen Brown void turbostat_init()
4514103a8feaSLen Brown {
45157ce7d5deSPrarit Bhargava 	setup_all_buffers();
45167ce7d5deSPrarit Bhargava 	set_base_cpu();
4517103a8feaSLen Brown 	check_dev_msr();
451898481e79SLen Brown 	check_permissions();
4519fcd17211SLen Brown 	process_cpuid();
4520103a8feaSLen Brown 
4521103a8feaSLen Brown 
452296e47158SLen Brown 	if (!quiet)
45237f5c258eSLen Brown 		for_all_cpus(print_hwp, ODD_COUNTERS);
45247f5c258eSLen Brown 
452596e47158SLen Brown 	if (!quiet)
4526889facbeSLen Brown 		for_all_cpus(print_epb, ODD_COUNTERS);
4527889facbeSLen Brown 
452896e47158SLen Brown 	if (!quiet)
45293a9a941dSLen Brown 		for_all_cpus(print_perf_limit, ODD_COUNTERS);
45303a9a941dSLen Brown 
453196e47158SLen Brown 	if (!quiet)
4532889facbeSLen Brown 		for_all_cpus(print_rapl, ODD_COUNTERS);
4533889facbeSLen Brown 
4534889facbeSLen Brown 	for_all_cpus(set_temperature_target, ODD_COUNTERS);
4535889facbeSLen Brown 
453696e47158SLen Brown 	if (!quiet)
4537889facbeSLen Brown 		for_all_cpus(print_thermal, ODD_COUNTERS);
45385a63426eSLen Brown 
453996e47158SLen Brown 	if (!quiet && do_irtl_snb)
45405a63426eSLen Brown 		print_irtl();
4541103a8feaSLen Brown }
4542103a8feaSLen Brown 
4543103a8feaSLen Brown int fork_it(char **argv)
4544103a8feaSLen Brown {
4545103a8feaSLen Brown 	pid_t child_pid;
4546d91bb17cSLen Brown 	int status;
4547d15cf7c1SLen Brown 
4548218f0e8dSLen Brown 	snapshot_proc_sysfs_files();
4549d91bb17cSLen Brown 	status = for_all_cpus(get_counters, EVEN_COUNTERS);
4550d91bb17cSLen Brown 	if (status)
4551d91bb17cSLen Brown 		exit(status);
4552d15cf7c1SLen Brown 	/* clear affinity side-effect of get_counters() */
4553d15cf7c1SLen Brown 	sched_setaffinity(0, cpu_present_setsize, cpu_present_set);
4554103a8feaSLen Brown 	gettimeofday(&tv_even, (struct timezone *)NULL);
4555103a8feaSLen Brown 
4556103a8feaSLen Brown 	child_pid = fork();
4557103a8feaSLen Brown 	if (!child_pid) {
4558103a8feaSLen Brown 		/* child */
4559103a8feaSLen Brown 		execvp(argv[0], argv);
45600815a3d0SLen Brown 		err(errno, "exec %s", argv[0]);
4561103a8feaSLen Brown 	} else {
4562103a8feaSLen Brown 
4563103a8feaSLen Brown 		/* parent */
4564b2c95d90SJosh Triplett 		if (child_pid == -1)
4565b2c95d90SJosh Triplett 			err(1, "fork");
4566103a8feaSLen Brown 
4567103a8feaSLen Brown 		signal(SIGINT, SIG_IGN);
4568103a8feaSLen Brown 		signal(SIGQUIT, SIG_IGN);
4569b2c95d90SJosh Triplett 		if (waitpid(child_pid, &status, 0) == -1)
4570b2c95d90SJosh Triplett 			err(status, "waitpid");
4571103a8feaSLen Brown 	}
4572c98d5d94SLen Brown 	/*
4573c98d5d94SLen Brown 	 * n.b. fork_it() does not check for errors from for_all_cpus()
4574c98d5d94SLen Brown 	 * because re-starting is problematic when forking
4575c98d5d94SLen Brown 	 */
4576218f0e8dSLen Brown 	snapshot_proc_sysfs_files();
4577c98d5d94SLen Brown 	for_all_cpus(get_counters, ODD_COUNTERS);
4578103a8feaSLen Brown 	gettimeofday(&tv_odd, (struct timezone *)NULL);
4579103a8feaSLen Brown 	timersub(&tv_odd, &tv_even, &tv_delta);
4580ba3dec99SLen Brown 	if (for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS))
4581ba3dec99SLen Brown 		fprintf(outf, "%s: Counter reset detected\n", progname);
4582ba3dec99SLen Brown 	else {
4583c98d5d94SLen Brown 		compute_average(EVEN_COUNTERS);
4584c98d5d94SLen Brown 		format_all_counters(EVEN_COUNTERS);
4585ba3dec99SLen Brown 	}
4586103a8feaSLen Brown 
4587b7d8c148SLen Brown 	fprintf(outf, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);
4588b7d8c148SLen Brown 
4589b7d8c148SLen Brown 	flush_output_stderr();
4590103a8feaSLen Brown 
4591d91bb17cSLen Brown 	return status;
4592103a8feaSLen Brown }
4593103a8feaSLen Brown 
45943b4d5c7fSAndy Shevchenko int get_and_dump_counters(void)
45953b4d5c7fSAndy Shevchenko {
45963b4d5c7fSAndy Shevchenko 	int status;
45973b4d5c7fSAndy Shevchenko 
4598218f0e8dSLen Brown 	snapshot_proc_sysfs_files();
45993b4d5c7fSAndy Shevchenko 	status = for_all_cpus(get_counters, ODD_COUNTERS);
46003b4d5c7fSAndy Shevchenko 	if (status)
46013b4d5c7fSAndy Shevchenko 		return status;
46023b4d5c7fSAndy Shevchenko 
46033b4d5c7fSAndy Shevchenko 	status = for_all_cpus(dump_counters, ODD_COUNTERS);
46043b4d5c7fSAndy Shevchenko 	if (status)
46053b4d5c7fSAndy Shevchenko 		return status;
46063b4d5c7fSAndy Shevchenko 
4607b7d8c148SLen Brown 	flush_output_stdout();
46083b4d5c7fSAndy Shevchenko 
46093b4d5c7fSAndy Shevchenko 	return status;
46103b4d5c7fSAndy Shevchenko }
46113b4d5c7fSAndy Shevchenko 
4612d8af6f5fSLen Brown void print_version() {
46135f9bf02aSLen Brown 	fprintf(outf, "turbostat version 17.04.12"
4614d8af6f5fSLen Brown 		" - Len Brown <lenb@kernel.org>\n");
4615d8af6f5fSLen Brown }
4616d8af6f5fSLen Brown 
4617495c7654SLen Brown int add_counter(unsigned int msr_num, char *path, char *name,
4618495c7654SLen Brown 	unsigned int width, enum counter_scope scope,
461941618e63SLen Brown 	enum counter_type type, enum counter_format format, int flags)
4620388e9c81SLen Brown {
4621388e9c81SLen Brown 	struct msr_counter *msrp;
4622388e9c81SLen Brown 
4623388e9c81SLen Brown 	msrp = calloc(1, sizeof(struct msr_counter));
4624388e9c81SLen Brown 	if (msrp == NULL) {
4625388e9c81SLen Brown 		perror("calloc");
4626388e9c81SLen Brown 		exit(1);
4627388e9c81SLen Brown 	}
4628388e9c81SLen Brown 
4629388e9c81SLen Brown 	msrp->msr_num = msr_num;
4630388e9c81SLen Brown 	strncpy(msrp->name, name, NAME_BYTES);
4631495c7654SLen Brown 	if (path)
4632495c7654SLen Brown 		strncpy(msrp->path, path, PATH_BYTES);
4633388e9c81SLen Brown 	msrp->width = width;
4634388e9c81SLen Brown 	msrp->type = type;
4635388e9c81SLen Brown 	msrp->format = format;
463641618e63SLen Brown 	msrp->flags = flags;
4637388e9c81SLen Brown 
4638388e9c81SLen Brown 	switch (scope) {
4639388e9c81SLen Brown 
4640388e9c81SLen Brown 	case SCOPE_CPU:
4641388e9c81SLen Brown 		msrp->next = sys.tp;
4642388e9c81SLen Brown 		sys.tp = msrp;
4643678a3bd1SLen Brown 		sys.added_thread_counters++;
4644678a3bd1SLen Brown 		if (sys.added_thread_counters > MAX_ADDED_COUNTERS) {
4645678a3bd1SLen Brown 			fprintf(stderr, "exceeded max %d added thread counters\n",
4646678a3bd1SLen Brown 				MAX_ADDED_COUNTERS);
4647678a3bd1SLen Brown 			exit(-1);
4648678a3bd1SLen Brown 		}
4649388e9c81SLen Brown 		break;
4650388e9c81SLen Brown 
4651388e9c81SLen Brown 	case SCOPE_CORE:
4652388e9c81SLen Brown 		msrp->next = sys.cp;
4653388e9c81SLen Brown 		sys.cp = msrp;
4654678a3bd1SLen Brown 		sys.added_core_counters++;
4655678a3bd1SLen Brown 		if (sys.added_core_counters > MAX_ADDED_COUNTERS) {
4656678a3bd1SLen Brown 			fprintf(stderr, "exceeded max %d added core counters\n",
4657678a3bd1SLen Brown 				MAX_ADDED_COUNTERS);
4658678a3bd1SLen Brown 			exit(-1);
4659678a3bd1SLen Brown 		}
4660388e9c81SLen Brown 		break;
4661388e9c81SLen Brown 
4662388e9c81SLen Brown 	case SCOPE_PACKAGE:
4663388e9c81SLen Brown 		msrp->next = sys.pp;
4664388e9c81SLen Brown 		sys.pp = msrp;
4665678a3bd1SLen Brown 		sys.added_package_counters++;
4666678a3bd1SLen Brown 		if (sys.added_package_counters > MAX_ADDED_COUNTERS) {
4667678a3bd1SLen Brown 			fprintf(stderr, "exceeded max %d added package counters\n",
4668678a3bd1SLen Brown 				MAX_ADDED_COUNTERS);
4669678a3bd1SLen Brown 			exit(-1);
4670678a3bd1SLen Brown 		}
4671388e9c81SLen Brown 		break;
4672388e9c81SLen Brown 	}
4673388e9c81SLen Brown 
4674388e9c81SLen Brown 	return 0;
4675388e9c81SLen Brown }
4676388e9c81SLen Brown 
4677388e9c81SLen Brown void parse_add_command(char *add_command)
4678388e9c81SLen Brown {
4679388e9c81SLen Brown 	int msr_num = 0;
4680495c7654SLen Brown 	char *path = NULL;
46810f47c08dSLen Brown 	char name_buffer[NAME_BYTES] = "";
4682388e9c81SLen Brown 	int width = 64;
4683388e9c81SLen Brown 	int fail = 0;
4684388e9c81SLen Brown 	enum counter_scope scope = SCOPE_CPU;
4685388e9c81SLen Brown 	enum counter_type type = COUNTER_CYCLES;
4686388e9c81SLen Brown 	enum counter_format format = FORMAT_DELTA;
4687388e9c81SLen Brown 
4688388e9c81SLen Brown 	while (add_command) {
4689388e9c81SLen Brown 
4690388e9c81SLen Brown 		if (sscanf(add_command, "msr0x%x", &msr_num) == 1)
4691388e9c81SLen Brown 			goto next;
4692388e9c81SLen Brown 
4693388e9c81SLen Brown 		if (sscanf(add_command, "msr%d", &msr_num) == 1)
4694388e9c81SLen Brown 			goto next;
4695388e9c81SLen Brown 
4696495c7654SLen Brown 		if (*add_command == '/') {
4697495c7654SLen Brown 			path = add_command;
4698495c7654SLen Brown 			goto next;
4699495c7654SLen Brown 		}
4700495c7654SLen Brown 
4701388e9c81SLen Brown 		if (sscanf(add_command, "u%d", &width) == 1) {
4702388e9c81SLen Brown 			if ((width == 32) || (width == 64))
4703388e9c81SLen Brown 				goto next;
4704388e9c81SLen Brown 			width = 64;
4705388e9c81SLen Brown 		}
4706388e9c81SLen Brown 		if (!strncmp(add_command, "cpu", strlen("cpu"))) {
4707388e9c81SLen Brown 			scope = SCOPE_CPU;
4708388e9c81SLen Brown 			goto next;
4709388e9c81SLen Brown 		}
4710388e9c81SLen Brown 		if (!strncmp(add_command, "core", strlen("core"))) {
4711388e9c81SLen Brown 			scope = SCOPE_CORE;
4712388e9c81SLen Brown 			goto next;
4713388e9c81SLen Brown 		}
4714388e9c81SLen Brown 		if (!strncmp(add_command, "package", strlen("package"))) {
4715388e9c81SLen Brown 			scope = SCOPE_PACKAGE;
4716388e9c81SLen Brown 			goto next;
4717388e9c81SLen Brown 		}
4718388e9c81SLen Brown 		if (!strncmp(add_command, "cycles", strlen("cycles"))) {
4719388e9c81SLen Brown 			type = COUNTER_CYCLES;
4720388e9c81SLen Brown 			goto next;
4721388e9c81SLen Brown 		}
4722388e9c81SLen Brown 		if (!strncmp(add_command, "seconds", strlen("seconds"))) {
4723388e9c81SLen Brown 			type = COUNTER_SECONDS;
4724388e9c81SLen Brown 			goto next;
4725388e9c81SLen Brown 		}
472641618e63SLen Brown 		if (!strncmp(add_command, "usec", strlen("usec"))) {
472741618e63SLen Brown 			type = COUNTER_USEC;
472841618e63SLen Brown 			goto next;
472941618e63SLen Brown 		}
4730388e9c81SLen Brown 		if (!strncmp(add_command, "raw", strlen("raw"))) {
4731388e9c81SLen Brown 			format = FORMAT_RAW;
4732388e9c81SLen Brown 			goto next;
4733388e9c81SLen Brown 		}
4734388e9c81SLen Brown 		if (!strncmp(add_command, "delta", strlen("delta"))) {
4735388e9c81SLen Brown 			format = FORMAT_DELTA;
4736388e9c81SLen Brown 			goto next;
4737388e9c81SLen Brown 		}
4738388e9c81SLen Brown 		if (!strncmp(add_command, "percent", strlen("percent"))) {
4739388e9c81SLen Brown 			format = FORMAT_PERCENT;
4740388e9c81SLen Brown 			goto next;
4741388e9c81SLen Brown 		}
4742388e9c81SLen Brown 
4743388e9c81SLen Brown 		if (sscanf(add_command, "%18s,%*s", name_buffer) == 1) {	/* 18 < NAME_BYTES */
4744388e9c81SLen Brown 			char *eos;
4745388e9c81SLen Brown 
4746388e9c81SLen Brown 			eos = strchr(name_buffer, ',');
4747388e9c81SLen Brown 			if (eos)
4748388e9c81SLen Brown 				*eos = '\0';
4749388e9c81SLen Brown 			goto next;
4750388e9c81SLen Brown 		}
4751388e9c81SLen Brown 
4752388e9c81SLen Brown next:
4753388e9c81SLen Brown 		add_command = strchr(add_command, ',');
4754495c7654SLen Brown 		if (add_command) {
4755495c7654SLen Brown 			*add_command = '\0';
4756388e9c81SLen Brown 			add_command++;
4757495c7654SLen Brown 		}
4758388e9c81SLen Brown 
4759388e9c81SLen Brown 	}
4760495c7654SLen Brown 	if ((msr_num == 0) && (path == NULL)) {
4761495c7654SLen Brown 		fprintf(stderr, "--add: (msrDDD | msr0xXXX | /path_to_counter ) required\n");
4762388e9c81SLen Brown 		fail++;
4763388e9c81SLen Brown 	}
4764388e9c81SLen Brown 
4765388e9c81SLen Brown 	/* generate default column header */
4766388e9c81SLen Brown 	if (*name_buffer == '\0') {
4767388e9c81SLen Brown 		if (width == 32)
47685f3aea57SLen Brown 			sprintf(name_buffer, "M0x%x%s", msr_num, format == FORMAT_PERCENT ? "%" : "");
4769388e9c81SLen Brown 		else
47705f3aea57SLen Brown 			sprintf(name_buffer, "M0X%x%s", msr_num, format == FORMAT_PERCENT ? "%" : "");
4771388e9c81SLen Brown 	}
4772388e9c81SLen Brown 
477341618e63SLen Brown 	if (add_counter(msr_num, path, name_buffer, width, scope, type, format, 0))
4774388e9c81SLen Brown 		fail++;
4775388e9c81SLen Brown 
4776388e9c81SLen Brown 	if (fail) {
4777388e9c81SLen Brown 		help();
4778388e9c81SLen Brown 		exit(1);
4779388e9c81SLen Brown 	}
4780388e9c81SLen Brown }
478141618e63SLen Brown 
4782dd778a5eSLen Brown int is_deferred_skip(char *name)
4783dd778a5eSLen Brown {
4784dd778a5eSLen Brown 	int i;
4785dd778a5eSLen Brown 
4786dd778a5eSLen Brown 	for (i = 0; i < deferred_skip_index; ++i)
4787dd778a5eSLen Brown 		if (!strcmp(name, deferred_skip_names[i]))
4788dd778a5eSLen Brown 			return 1;
4789dd778a5eSLen Brown 	return 0;
4790dd778a5eSLen Brown }
4791dd778a5eSLen Brown 
479241618e63SLen Brown void probe_sysfs(void)
479341618e63SLen Brown {
479441618e63SLen Brown 	char path[64];
479541618e63SLen Brown 	char name_buf[16];
479641618e63SLen Brown 	FILE *input;
479741618e63SLen Brown 	int state;
479841618e63SLen Brown 	char *sp;
479941618e63SLen Brown 
480041618e63SLen Brown 	if (!DO_BIC(BIC_sysfs))
480141618e63SLen Brown 		return;
480241618e63SLen Brown 
480341618e63SLen Brown 	for (state = 10; state > 0; --state) {
480441618e63SLen Brown 
480541618e63SLen Brown 		sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name",
480641618e63SLen Brown 			base_cpu, state);
480741618e63SLen Brown 		input = fopen(path, "r");
480841618e63SLen Brown 		if (input == NULL)
480941618e63SLen Brown 			continue;
481041618e63SLen Brown 		fgets(name_buf, sizeof(name_buf), input);
481141618e63SLen Brown 
481241618e63SLen Brown 		 /* truncate "C1-HSW\n" to "C1", or truncate "C1\n" to "C1" */
481341618e63SLen Brown 		sp = strchr(name_buf, '-');
481441618e63SLen Brown 		if (!sp)
481541618e63SLen Brown 			sp = strchrnul(name_buf, '\n');
481641618e63SLen Brown 		*sp = '%';
481741618e63SLen Brown 		*(sp + 1) = '\0';
481841618e63SLen Brown 
481941618e63SLen Brown 		fclose(input);
482041618e63SLen Brown 
482141618e63SLen Brown 		sprintf(path, "cpuidle/state%d/time", state);
482241618e63SLen Brown 
4823dd778a5eSLen Brown 		if (is_deferred_skip(name_buf))
4824dd778a5eSLen Brown 			continue;
4825dd778a5eSLen Brown 
482641618e63SLen Brown 		add_counter(0, path, name_buf, 64, SCOPE_CPU, COUNTER_USEC,
482741618e63SLen Brown 				FORMAT_PERCENT, SYSFS_PERCPU);
482841618e63SLen Brown 	}
482941618e63SLen Brown 
483041618e63SLen Brown 	for (state = 10; state > 0; --state) {
483141618e63SLen Brown 
483241618e63SLen Brown 		sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name",
483341618e63SLen Brown 			base_cpu, state);
483441618e63SLen Brown 		input = fopen(path, "r");
483541618e63SLen Brown 		if (input == NULL)
483641618e63SLen Brown 			continue;
483741618e63SLen Brown 		fgets(name_buf, sizeof(name_buf), input);
483841618e63SLen Brown 		 /* truncate "C1-HSW\n" to "C1", or truncate "C1\n" to "C1" */
483941618e63SLen Brown 		sp = strchr(name_buf, '-');
484041618e63SLen Brown 		if (!sp)
484141618e63SLen Brown 			sp = strchrnul(name_buf, '\n');
484241618e63SLen Brown 		*sp = '\0';
484341618e63SLen Brown 		fclose(input);
484441618e63SLen Brown 
484541618e63SLen Brown 		sprintf(path, "cpuidle/state%d/usage", state);
484641618e63SLen Brown 
4847dd778a5eSLen Brown 		if (is_deferred_skip(name_buf))
4848dd778a5eSLen Brown 			continue;
4849dd778a5eSLen Brown 
485041618e63SLen Brown 		add_counter(0, path, name_buf, 64, SCOPE_CPU, COUNTER_ITEMS,
485141618e63SLen Brown 				FORMAT_DELTA, SYSFS_PERCPU);
485241618e63SLen Brown 	}
485341618e63SLen Brown 
485441618e63SLen Brown }
485541618e63SLen Brown 
48561ef7d21aSLen Brown 
48571ef7d21aSLen Brown /*
48581ef7d21aSLen Brown  * parse cpuset with following syntax
48591ef7d21aSLen Brown  * 1,2,4..6,8-10 and set bits in cpu_subset
48601ef7d21aSLen Brown  */
48611ef7d21aSLen Brown void parse_cpu_command(char *optarg)
48621ef7d21aSLen Brown {
48631ef7d21aSLen Brown 	unsigned int start, end;
48641ef7d21aSLen Brown 	char *next;
48651ef7d21aSLen Brown 
48664e4e1e7cSLen Brown 	if (!strcmp(optarg, "core")) {
48674e4e1e7cSLen Brown 		if (cpu_subset)
48684e4e1e7cSLen Brown 			goto error;
48694e4e1e7cSLen Brown 		show_core_only++;
48704e4e1e7cSLen Brown 		return;
48714e4e1e7cSLen Brown 	}
48724e4e1e7cSLen Brown 	if (!strcmp(optarg, "package")) {
48734e4e1e7cSLen Brown 		if (cpu_subset)
48744e4e1e7cSLen Brown 			goto error;
48754e4e1e7cSLen Brown 		show_pkg_only++;
48764e4e1e7cSLen Brown 		return;
48774e4e1e7cSLen Brown 	}
48784e4e1e7cSLen Brown 	if (show_core_only || show_pkg_only)
48794e4e1e7cSLen Brown 		goto error;
48804e4e1e7cSLen Brown 
48811ef7d21aSLen Brown 	cpu_subset = CPU_ALLOC(CPU_SUBSET_MAXCPUS);
48821ef7d21aSLen Brown 	if (cpu_subset == NULL)
48831ef7d21aSLen Brown 		err(3, "CPU_ALLOC");
48841ef7d21aSLen Brown 	cpu_subset_size = CPU_ALLOC_SIZE(CPU_SUBSET_MAXCPUS);
48851ef7d21aSLen Brown 
48861ef7d21aSLen Brown 	CPU_ZERO_S(cpu_subset_size, cpu_subset);
48871ef7d21aSLen Brown 
48881ef7d21aSLen Brown 	next = optarg;
48891ef7d21aSLen Brown 
48901ef7d21aSLen Brown 	while (next && *next) {
48911ef7d21aSLen Brown 
48921ef7d21aSLen Brown 		if (*next == '-')	/* no negative cpu numbers */
48931ef7d21aSLen Brown 			goto error;
48941ef7d21aSLen Brown 
48951ef7d21aSLen Brown 		start = strtoul(next, &next, 10);
48961ef7d21aSLen Brown 
48971ef7d21aSLen Brown 		if (start >= CPU_SUBSET_MAXCPUS)
48981ef7d21aSLen Brown 			goto error;
48991ef7d21aSLen Brown 		CPU_SET_S(start, cpu_subset_size, cpu_subset);
49001ef7d21aSLen Brown 
49011ef7d21aSLen Brown 		if (*next == '\0')
49021ef7d21aSLen Brown 			break;
49031ef7d21aSLen Brown 
49041ef7d21aSLen Brown 		if (*next == ',') {
49051ef7d21aSLen Brown 			next += 1;
49061ef7d21aSLen Brown 			continue;
49071ef7d21aSLen Brown 		}
49081ef7d21aSLen Brown 
49091ef7d21aSLen Brown 		if (*next == '-') {
49101ef7d21aSLen Brown 			next += 1;	/* start range */
49111ef7d21aSLen Brown 		} else if (*next == '.') {
49121ef7d21aSLen Brown 			next += 1;
49131ef7d21aSLen Brown 			if (*next == '.')
49141ef7d21aSLen Brown 				next += 1;	/* start range */
49151ef7d21aSLen Brown 			else
49161ef7d21aSLen Brown 				goto error;
49171ef7d21aSLen Brown 		}
49181ef7d21aSLen Brown 
49191ef7d21aSLen Brown 		end = strtoul(next, &next, 10);
49201ef7d21aSLen Brown 		if (end <= start)
49211ef7d21aSLen Brown 			goto error;
49221ef7d21aSLen Brown 
49231ef7d21aSLen Brown 		while (++start <= end) {
49241ef7d21aSLen Brown 			if (start >= CPU_SUBSET_MAXCPUS)
49251ef7d21aSLen Brown 				goto error;
49261ef7d21aSLen Brown 			CPU_SET_S(start, cpu_subset_size, cpu_subset);
49271ef7d21aSLen Brown 		}
49281ef7d21aSLen Brown 
49291ef7d21aSLen Brown 		if (*next == ',')
49301ef7d21aSLen Brown 			next += 1;
49311ef7d21aSLen Brown 		else if (*next != '\0')
49321ef7d21aSLen Brown 			goto error;
49331ef7d21aSLen Brown 	}
49341ef7d21aSLen Brown 
49351ef7d21aSLen Brown 	return;
49361ef7d21aSLen Brown 
49371ef7d21aSLen Brown error:
49384e4e1e7cSLen Brown 	fprintf(stderr, "\"--cpu %s\" malformed\n", optarg);
49394e4e1e7cSLen Brown 	help();
49401ef7d21aSLen Brown 	exit(-1);
49411ef7d21aSLen Brown }
49421ef7d21aSLen Brown 
4943812db3f7SLen Brown int shown;
4944812db3f7SLen Brown /*
4945812db3f7SLen Brown  * parse_show_hide() - process cmdline to set default counter action
4946812db3f7SLen Brown  */
4947812db3f7SLen Brown void parse_show_hide(char *optarg, enum show_hide_mode new_mode)
4948812db3f7SLen Brown {
4949812db3f7SLen Brown 	/*
4950812db3f7SLen Brown 	 * --show: show only those specified
4951812db3f7SLen Brown 	 *  The 1st invocation will clear and replace the enabled mask
4952812db3f7SLen Brown 	 *  subsequent invocations can add to it.
4953812db3f7SLen Brown 	 */
4954812db3f7SLen Brown 	if (new_mode == SHOW_LIST) {
4955812db3f7SLen Brown 		if (shown == 0)
4956dd778a5eSLen Brown 			bic_enabled = bic_lookup(optarg, new_mode);
4957812db3f7SLen Brown 		else
4958dd778a5eSLen Brown 			bic_enabled |= bic_lookup(optarg, new_mode);
4959812db3f7SLen Brown 		shown = 1;
4960812db3f7SLen Brown 
4961812db3f7SLen Brown 		return;
4962812db3f7SLen Brown 	}
4963812db3f7SLen Brown 
4964812db3f7SLen Brown 	/*
4965812db3f7SLen Brown 	 * --hide: do not show those specified
4966812db3f7SLen Brown 	 *  multiple invocations simply clear more bits in enabled mask
4967812db3f7SLen Brown 	 */
4968dd778a5eSLen Brown 	bic_enabled &= ~bic_lookup(optarg, new_mode);
496941618e63SLen Brown 
4970812db3f7SLen Brown }
4971812db3f7SLen Brown 
4972103a8feaSLen Brown void cmdline(int argc, char **argv)
4973103a8feaSLen Brown {
4974103a8feaSLen Brown 	int opt;
4975d8af6f5fSLen Brown 	int option_index = 0;
4976d8af6f5fSLen Brown 	static struct option long_options[] = {
4977388e9c81SLen Brown 		{"add",		required_argument,	0, 'a'},
49781ef7d21aSLen Brown 		{"cpu",		required_argument,	0, 'c'},
4979d8af6f5fSLen Brown 		{"Dump",	no_argument,		0, 'D'},
498096e47158SLen Brown 		{"debug",	no_argument,		0, 'd'},	/* internal, not documented */
4981d8af6f5fSLen Brown 		{"interval",	required_argument,	0, 'i'},
4982d8af6f5fSLen Brown 		{"help",	no_argument,		0, 'h'},
4983812db3f7SLen Brown 		{"hide",	required_argument,	0, 'H'},	// meh, -h taken by --help
4984d8af6f5fSLen Brown 		{"Joules",	no_argument,		0, 'J'},
4985c8ade361SLen Brown 		{"list",	no_argument,		0, 'l'},
4986b7d8c148SLen Brown 		{"out",		required_argument,	0, 'o'},
498796e47158SLen Brown 		{"quiet",	no_argument,		0, 'q'},
4988812db3f7SLen Brown 		{"show",	required_argument,	0, 's'},
4989d8af6f5fSLen Brown 		{"Summary",	no_argument,		0, 'S'},
4990d8af6f5fSLen Brown 		{"TCC",		required_argument,	0, 'T'},
4991d8af6f5fSLen Brown 		{"version",	no_argument,		0, 'v' },
4992d8af6f5fSLen Brown 		{0,		0,			0,  0 }
4993d8af6f5fSLen Brown 	};
4994103a8feaSLen Brown 
4995103a8feaSLen Brown 	progname = argv[0];
4996103a8feaSLen Brown 
49974e4e1e7cSLen Brown 	while ((opt = getopt_long_only(argc, argv, "+C:c:Ddhi:JM:m:o:qST:v",
4998d8af6f5fSLen Brown 				long_options, &option_index)) != -1) {
4999103a8feaSLen Brown 		switch (opt) {
5000388e9c81SLen Brown 		case 'a':
5001388e9c81SLen Brown 			parse_add_command(optarg);
5002388e9c81SLen Brown 			break;
50031ef7d21aSLen Brown 		case 'c':
50041ef7d21aSLen Brown 			parse_cpu_command(optarg);
50051ef7d21aSLen Brown 			break;
5006d8af6f5fSLen Brown 		case 'D':
5007d8af6f5fSLen Brown 			dump_only++;
50088e180f3cSLen Brown 			break;
5009d8af6f5fSLen Brown 		case 'd':
5010d8af6f5fSLen Brown 			debug++;
50112f32edf1SLen Brown 			break;
5012812db3f7SLen Brown 		case 'H':
5013812db3f7SLen Brown 			parse_show_hide(optarg, HIDE_LIST);
5014812db3f7SLen Brown 			break;
5015d8af6f5fSLen Brown 		case 'h':
5016d8af6f5fSLen Brown 		default:
5017d8af6f5fSLen Brown 			help();
5018d8af6f5fSLen Brown 			exit(1);
5019d8af6f5fSLen Brown 		case 'i':
50202a0609c0SLen Brown 			{
50212a0609c0SLen Brown 				double interval = strtod(optarg, NULL);
50222a0609c0SLen Brown 
50232a0609c0SLen Brown 				if (interval < 0.001) {
5024b7d8c148SLen Brown 					fprintf(outf, "interval %f seconds is too small\n",
50252a0609c0SLen Brown 						interval);
50262a0609c0SLen Brown 					exit(2);
50272a0609c0SLen Brown 				}
50282a0609c0SLen Brown 
50292a0609c0SLen Brown 				interval_ts.tv_sec = interval;
50302a0609c0SLen Brown 				interval_ts.tv_nsec = (interval - interval_ts.tv_sec) * 1000000000;
50312a0609c0SLen Brown 			}
5032889facbeSLen Brown 			break;
50335c56be9aSDirk Brandewie 		case 'J':
50345c56be9aSDirk Brandewie 			rapl_joules++;
50355c56be9aSDirk Brandewie 			break;
5036c8ade361SLen Brown 		case 'l':
5037c8ade361SLen Brown 			list_header_only++;
5038c8ade361SLen Brown 			quiet++;
5039c8ade361SLen Brown 			break;
5040b7d8c148SLen Brown 		case 'o':
5041b7d8c148SLen Brown 			outf = fopen_or_die(optarg, "w");
5042b7d8c148SLen Brown 			break;
504396e47158SLen Brown 		case 'q':
504496e47158SLen Brown 			quiet = 1;
504596e47158SLen Brown 			break;
5046812db3f7SLen Brown 		case 's':
5047812db3f7SLen Brown 			parse_show_hide(optarg, SHOW_LIST);
5048812db3f7SLen Brown 			break;
5049d8af6f5fSLen Brown 		case 'S':
5050d8af6f5fSLen Brown 			summary_only++;
5051d8af6f5fSLen Brown 			break;
5052d8af6f5fSLen Brown 		case 'T':
5053d8af6f5fSLen Brown 			tcc_activation_temp_override = atoi(optarg);
5054d8af6f5fSLen Brown 			break;
5055d8af6f5fSLen Brown 		case 'v':
5056d8af6f5fSLen Brown 			print_version();
5057d8af6f5fSLen Brown 			exit(0);
5058d8af6f5fSLen Brown 			break;
5059103a8feaSLen Brown 		}
5060103a8feaSLen Brown 	}
5061103a8feaSLen Brown }
5062103a8feaSLen Brown 
5063103a8feaSLen Brown int main(int argc, char **argv)
5064103a8feaSLen Brown {
5065b7d8c148SLen Brown 	outf = stderr;
5066b7d8c148SLen Brown 
5067103a8feaSLen Brown 	cmdline(argc, argv);
5068103a8feaSLen Brown 
506996e47158SLen Brown 	if (!quiet)
5070d8af6f5fSLen Brown 		print_version();
5071103a8feaSLen Brown 
507241618e63SLen Brown 	probe_sysfs();
507341618e63SLen Brown 
5074103a8feaSLen Brown 	turbostat_init();
5075103a8feaSLen Brown 
50763b4d5c7fSAndy Shevchenko 	/* dump counters and exit */
50773b4d5c7fSAndy Shevchenko 	if (dump_only)
50783b4d5c7fSAndy Shevchenko 		return get_and_dump_counters();
50793b4d5c7fSAndy Shevchenko 
5080c8ade361SLen Brown 	/* list header and exit */
5081c8ade361SLen Brown 	if (list_header_only) {
5082c8ade361SLen Brown 		print_header(",");
5083c8ade361SLen Brown 		flush_output_stdout();
5084c8ade361SLen Brown 		return 0;
5085c8ade361SLen Brown 	}
5086c8ade361SLen Brown 
5087103a8feaSLen Brown 	/*
5088103a8feaSLen Brown 	 * if any params left, it must be a command to fork
5089103a8feaSLen Brown 	 */
5090103a8feaSLen Brown 	if (argc - optind)
5091103a8feaSLen Brown 		return fork_it(argv + optind);
5092103a8feaSLen Brown 	else
5093103a8feaSLen Brown 		turbostat_loop();
5094103a8feaSLen Brown 
5095103a8feaSLen Brown 	return 0;
5096103a8feaSLen Brown }
5097