// SPDX-License-Identifier: GPL-2.0-only
/*
* turbostat -- show CPU frequency and C-state residency
* on modern Intel and AMD processors.
*
* Copyright (c) 2025 Intel Corporation.
* Len Brown <len.brown@intel.com>
*/
#define _GNU_SOURCE
#include MSRHEADER
// copied from arch/x86/include/asm/cpu_device_id.h
#define VFM_MODEL_BIT 0
#define VFM_FAMILY_BIT 8
#define VFM_VENDOR_BIT 16
#define VFM_RSVD_BIT 24
#define VFM_MODEL_MASK GENMASK(VFM_FAMILY_BIT - 1, VFM_MODEL_BIT)
#define VFM_FAMILY_MASK GENMASK(VFM_VENDOR_BIT - 1, VFM_FAMILY_BIT)
#define VFM_VENDOR_MASK GENMASK(VFM_RSVD_BIT - 1, VFM_VENDOR_BIT)
#define VFM_MODEL(vfm) (((vfm) & VFM_MODEL_MASK) >> VFM_MODEL_BIT)
#define VFM_FAMILY(vfm) (((vfm) & VFM_FAMILY_MASK) >> VFM_FAMILY_BIT)
#define VFM_VENDOR(vfm) (((vfm) & VFM_VENDOR_MASK) >> VFM_VENDOR_BIT)
#define VFM_MAKE(_vendor, _family, _model) ( \
((_model) << VFM_MODEL_BIT) | \
((_family) << VFM_FAMILY_BIT) | \
((_vendor) << VFM_VENDOR_BIT) \
)
// end copied section
#define CPUID_LEAF_MODEL_ID 0x1A
#define CPUID_LEAF_MODEL_ID_CORE_TYPE_SHIFT 24
#define X86_VENDOR_INTEL 0
#include INTEL_FAMILY_HEADER
#include BUILD_BUG_HEADER
#include <stdarg.h>
#include <stdio.h>
#include <err.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/resource.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <stdlib.h>
#include <getopt.h>
#include <dirent.h>
#include <string.h>
#include <ctype.h>
#include <sched.h>
#include <time.h>
#include <cpuid.h>
#include <sys/capability.h>
#include <errno.h>
#include <math.h>
#include <linux/perf_event.h>
#include <asm /unistd.h>
#include <stdbool.h>
#include <assert.h>
#include <linux/kernel.h>
#include <limits.h>
#define UNUSED(x) (void )(x)
/*
* This list matches the column headers, except
* 1. built-in only, the sysfs counters are not here -- we learn of those at run-time
* 2. Core and CPU are moved to the end, we can't have strings that contain them
* matching on them for --show and --hide.
*/
/*
* buffer size used by sscanf() for added column names
* Usually truncated to 7 characters, but also handles 18 columns for raw 64-bit counters
*/
#define NAME_BYTES 20
#define PATH_BYTES 128
#define PERF_NAME_BYTES 128
#define MAX_NOFILE 0x8000
#define COUNTER_KIND_PERF_PREFIX "perf/"
#define COUNTER_KIND_PERF_PREFIX_LEN strlen(COUNTER_KIND_PERF_PREFIX)
#define PERF_DEV_NAME_BYTES 32
#define PERF_EVT_NAME_BYTES 32
#define INTEL_ECORE_TYPE 0x20
#define INTEL_PCORE_TYPE 0x40
#define ROUND_UP_TO_PAGE_SIZE(n) (((n) + 0x1000UL-1UL) & ~(0x1000UL-1UL))
enum counter_scope { SCOPE_CPU, SCOPE_CORE, SCOPE_PACKAGE };
enum counter_type { COUNTER_ITEMS, COUNTER_CYCLES, COUNTER_SECONDS, COUNTER_USEC, COUNTER_K2M };
enum counter_format { FORMAT_RAW, FORMAT_DELTA, FORMAT_PERCENT, FORMAT_AVERAGE };
enum counter_source { COUNTER_SOURCE_NONE, COUNTER_SOURCE_PERF, COUNTER_SOURCE_MSR };
struct perf_counter_info {
struct perf_counter_info *next;
/* How to open the counter / What counter it is. */
char device[PERF_DEV_NAME_BYTES];
char event[PERF_EVT_NAME_BYTES];
/* How to show/format the counter. */
char name[PERF_NAME_BYTES];
unsigned int width;
enum counter_scope scope;
enum counter_type type;
enum counter_format format;
double scale;
/* For reading the counter. */
int *fd_perf_per_domain;
size_t num_domains;
};
struct sysfs_path {
char path[PATH_BYTES];
int id;
struct sysfs_path *next;
};
struct msr_counter {
unsigned int msr_num;
char name[NAME_BYTES];
struct sysfs_path *sp;
unsigned int width;
enum counter_type type;
enum counter_format format;
struct msr_counter *next;
unsigned int flags;
#define FLAGS_HIDE (1 << 0)
#define FLAGS_SHOW (1 << 1)
#define SYSFS_PERCPU (1 << 1)
};
struct msr_counter bic[] = {
{ 0x0, "usec" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Time_Of_Day_Seconds" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Package" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Node" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Avg_MHz" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Busy%" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Bzy_MHz" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "TSC_MHz" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "IRQ" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "SMI" , NULL, 32, 0, FORMAT_DELTA, NULL, 0 },
{ 0x0, "cpuidle" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "CPU%c1" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "CPU%c3" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "CPU%c6" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "CPU%c7" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "ThreadC" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "CoreTmp" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "CoreCnt" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "PkgTmp" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "GFX%rc6" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "GFXMHz" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Pkg%pc2" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Pkg%pc3" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Pkg%pc6" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Pkg%pc7" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Pkg%pc8" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Pkg%pc9" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Pk%pc10" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "CPU%LPI" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "SYS%LPI" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "PkgWatt" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "CorWatt" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "GFXWatt" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "PkgCnt" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "RAMWatt" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "PKG_%" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "RAM_%" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Pkg_J" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Cor_J" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "GFX_J" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "RAM_J" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Mod%c6" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Totl%C0" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Any%C0" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "GFX%C0" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "CPUGFX%" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Core" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "CPU" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "APIC" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "X2APIC" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Die" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "L3" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "GFXAMHz" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "IPC" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "CoreThr" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "UncMHz" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "SAM%mc6" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "SAMMHz" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "SAMAMHz" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Die%c6" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "SysWatt" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "Sys_J" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "NMI" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "CPU%c1e" , NULL, 0, 0, 0, NULL, 0 },
{ 0x0, "pct_idle" , NULL, 0, 0, 0, NULL, 0 },
};
/* n.b. bic_names must match the order in bic[], above */
enum bic_names {
BIC_USEC,
BIC_TOD,
BIC_Package,
BIC_Node,
BIC_Avg_MHz,
BIC_Busy,
BIC_Bzy_MHz,
BIC_TSC_MHz,
BIC_IRQ,
BIC_SMI,
BIC_cpuidle,
BIC_CPU_c1,
BIC_CPU_c3,
BIC_CPU_c6,
BIC_CPU_c7,
BIC_ThreadC,
BIC_CoreTmp,
BIC_CoreCnt,
BIC_PkgTmp,
BIC_GFX_rc6,
BIC_GFXMHz,
BIC_Pkgpc2,
BIC_Pkgpc3,
BIC_Pkgpc6,
BIC_Pkgpc7,
BIC_Pkgpc8,
BIC_Pkgpc9,
BIC_Pkgpc10,
BIC_CPU_LPI,
BIC_SYS_LPI,
BIC_PkgWatt,
BIC_CorWatt,
BIC_GFXWatt,
BIC_PkgCnt,
BIC_RAMWatt,
BIC_PKG__,
BIC_RAM__,
BIC_Pkg_J,
BIC_Cor_J,
BIC_GFX_J,
BIC_RAM_J,
BIC_Mod_c6,
BIC_Totl_c0,
BIC_Any_c0,
BIC_GFX_c0,
BIC_CPUGFX,
BIC_Core,
BIC_CPU,
BIC_APIC,
BIC_X2APIC,
BIC_Die,
BIC_L3,
BIC_GFXACTMHz,
BIC_IPC,
BIC_CORE_THROT_CNT,
BIC_UNCORE_MHZ,
BIC_SAM_mc6,
BIC_SAMMHz,
BIC_SAMACTMHz,
BIC_Diec6,
BIC_SysWatt,
BIC_Sys_J,
BIC_NMI,
BIC_CPU_c1e,
BIC_pct_idle,
MAX_BIC
};
void print_bic_set(char *s, cpu_set_t *set)
{
int i;
assert(MAX_BIC < CPU_SETSIZE);
printf("%s:" , s);
for (i = 0; i <= MAX_BIC; ++i) {
if (CPU_ISSET(i, set)) {
assert(i < MAX_BIC);
printf(" %s" , bic[i].name);
}
}
putchar('\n' );
}
static cpu_set_t bic_group_topology;
static cpu_set_t bic_group_thermal_pwr;
static cpu_set_t bic_group_frequency;
static cpu_set_t bic_group_hw_idle;
static cpu_set_t bic_group_sw_idle;
static cpu_set_t bic_group_idle;
static cpu_set_t bic_group_other;
static cpu_set_t bic_group_disabled_by_default;
static cpu_set_t bic_enabled;
static cpu_set_t bic_present;
/* modify */
#define BIC_INIT(set) CPU_ZERO(set)
#define SET_BIC(COUNTER_NUMBER, set) CPU_SET(COUNTER_NUMBER, set)
#define CLR_BIC(COUNTER_NUMBER, set) CPU_CLR(COUNTER_NUMBER, set)
#define BIC_PRESENT(COUNTER_NUMBER) SET_BIC(COUNTER_NUMBER, &bic_present)
#define BIC_NOT_PRESENT(COUNTER_NUMBER) CPU_CLR(COUNTER_NUMBER, &bic_present)
/* test */
#define BIC_IS_ENABLED(COUNTER_NUMBER) CPU_ISSET(COUNTER_NUMBER, &bic_enabled)
#define DO_BIC_READ(COUNTER_NUMBER) CPU_ISSET(COUNTER_NUMBER, &bic_present)
#define DO_BIC(COUNTER_NUMBER) (CPU_ISSET(COUNTER_NUMBER, &bic_enabled) && CPU_ISSET(COUNTER_NUMBER, &bic_present))
static void bic_set_all(cpu_set_t *set)
{
int i;
assert(MAX_BIC < CPU_SETSIZE);
for (i = 0; i < MAX_BIC; ++i)
SET_BIC(i, set);
}
/*
* bic_clear_bits()
* clear all the bits from "clr" in "dst"
*/
static void bic_clear_bits(cpu_set_t *dst, cpu_set_t *clr)
{
int i;
assert(MAX_BIC < CPU_SETSIZE);
for (i = 0; i < MAX_BIC; ++i)
if (CPU_ISSET(i, clr))
CLR_BIC(i, dst);
}
static void bic_groups_init(void )
{
BIC_INIT(&bic_group_topology);
SET_BIC(BIC_Package, &bic_group_topology);
SET_BIC(BIC_Node, &bic_group_topology);
SET_BIC(BIC_CoreCnt, &bic_group_topology);
SET_BIC(BIC_PkgCnt, &bic_group_topology);
SET_BIC(BIC_Core, &bic_group_topology);
SET_BIC(BIC_CPU, &bic_group_topology);
SET_BIC(BIC_Die, &bic_group_topology);
SET_BIC(BIC_L3, &bic_group_topology);
BIC_INIT(&bic_group_thermal_pwr);
SET_BIC(BIC_CoreTmp, &bic_group_thermal_pwr);
SET_BIC(BIC_PkgTmp, &bic_group_thermal_pwr);
SET_BIC(BIC_PkgWatt, &bic_group_thermal_pwr);
SET_BIC(BIC_CorWatt, &bic_group_thermal_pwr);
SET_BIC(BIC_GFXWatt, &bic_group_thermal_pwr);
SET_BIC(BIC_RAMWatt, &bic_group_thermal_pwr);
SET_BIC(BIC_PKG__, &bic_group_thermal_pwr);
SET_BIC(BIC_RAM__, &bic_group_thermal_pwr);
SET_BIC(BIC_SysWatt, &bic_group_thermal_pwr);
BIC_INIT(&bic_group_frequency);
SET_BIC(BIC_Avg_MHz, &bic_group_frequency);
SET_BIC(BIC_Busy, &bic_group_frequency);
SET_BIC(BIC_Bzy_MHz, &bic_group_frequency);
SET_BIC(BIC_TSC_MHz, &bic_group_frequency);
SET_BIC(BIC_GFXMHz, &bic_group_frequency);
SET_BIC(BIC_GFXACTMHz, &bic_group_frequency);
SET_BIC(BIC_SAMMHz, &bic_group_frequency);
SET_BIC(BIC_SAMACTMHz, &bic_group_frequency);
SET_BIC(BIC_UNCORE_MHZ, &bic_group_frequency);
BIC_INIT(&bic_group_hw_idle);
SET_BIC(BIC_Busy, &bic_group_hw_idle);
SET_BIC(BIC_CPU_c1, &bic_group_hw_idle);
SET_BIC(BIC_CPU_c3, &bic_group_hw_idle);
SET_BIC(BIC_CPU_c6, &bic_group_hw_idle);
SET_BIC(BIC_CPU_c7, &bic_group_hw_idle);
SET_BIC(BIC_GFX_rc6, &bic_group_hw_idle);
SET_BIC(BIC_Pkgpc2, &bic_group_hw_idle);
SET_BIC(BIC_Pkgpc3, &bic_group_hw_idle);
SET_BIC(BIC_Pkgpc6, &bic_group_hw_idle);
SET_BIC(BIC_Pkgpc7, &bic_group_hw_idle);
SET_BIC(BIC_Pkgpc8, &bic_group_hw_idle);
SET_BIC(BIC_Pkgpc9, &bic_group_hw_idle);
SET_BIC(BIC_Pkgpc10, &bic_group_hw_idle);
SET_BIC(BIC_CPU_LPI, &bic_group_hw_idle);
SET_BIC(BIC_SYS_LPI, &bic_group_hw_idle);
SET_BIC(BIC_Mod_c6, &bic_group_hw_idle);
SET_BIC(BIC_Totl_c0, &bic_group_hw_idle);
SET_BIC(BIC_Any_c0, &bic_group_hw_idle);
SET_BIC(BIC_GFX_c0, &bic_group_hw_idle);
SET_BIC(BIC_CPUGFX, &bic_group_hw_idle);
SET_BIC(BIC_SAM_mc6, &bic_group_hw_idle);
SET_BIC(BIC_Diec6, &bic_group_hw_idle);
BIC_INIT(&bic_group_sw_idle);
SET_BIC(BIC_Busy, &bic_group_sw_idle);
SET_BIC(BIC_cpuidle, &bic_group_sw_idle);
SET_BIC(BIC_pct_idle, &bic_group_sw_idle);
BIC_INIT(&bic_group_idle);
CPU_OR(&bic_group_idle, &bic_group_idle, &bic_group_hw_idle);
SET_BIC(BIC_pct_idle, &bic_group_idle);
BIC_INIT(&bic_group_other);
SET_BIC(BIC_IRQ, &bic_group_other);
SET_BIC(BIC_NMI, &bic_group_other);
SET_BIC(BIC_SMI, &bic_group_other);
SET_BIC(BIC_ThreadC, &bic_group_other);
SET_BIC(BIC_CoreTmp, &bic_group_other);
SET_BIC(BIC_IPC, &bic_group_other);
BIC_INIT(&bic_group_disabled_by_default);
SET_BIC(BIC_USEC, &bic_group_disabled_by_default);
SET_BIC(BIC_TOD, &bic_group_disabled_by_default);
SET_BIC(BIC_cpuidle, &bic_group_disabled_by_default);
SET_BIC(BIC_APIC, &bic_group_disabled_by_default);
SET_BIC(BIC_X2APIC, &bic_group_disabled_by_default);
BIC_INIT(&bic_enabled);
bic_set_all(&bic_enabled);
bic_clear_bits(&bic_enabled, &bic_group_disabled_by_default);
BIC_INIT(&bic_present);
SET_BIC(BIC_USEC, &bic_present);
SET_BIC(BIC_TOD, &bic_present);
SET_BIC(BIC_cpuidle, &bic_present);
SET_BIC(BIC_APIC, &bic_present);
SET_BIC(BIC_X2APIC, &bic_present);
SET_BIC(BIC_pct_idle, &bic_present);
}
/*
* MSR_PKG_CST_CONFIG_CONTROL decoding for pkg_cstate_limit:
* If you change the values, note they are used both in comparisons
* (>= PCL__7) and to index pkg_cstate_limit_strings[].
*/
#define PCLUKN 0 /* Unknown */
#define PCLRSV 1 /* Reserved */
#define PCL__0 2 /* PC0 */
#define PCL__1 3 /* PC1 */
#define PCL__2 4 /* PC2 */
#define PCL__3 5 /* PC3 */
#define PCL__4 6 /* PC4 */
#define PCL__6 7 /* PC6 */
#define PCL_6N 8 /* PC6 No Retention */
#define PCL_6R 9 /* PC6 Retention */
#define PCL__7 10 /* PC7 */
#define PCL_7S 11 /* PC7 Shrink */
#define PCL__8 12 /* PC8 */
#define PCL__9 13 /* PC9 */
#define PCL_10 14 /* PC10 */
#define PCLUNL 15 /* Unlimited */
struct amperf_group_fd;
char *proc_stat = "/proc/stat" ;
FILE *outf;
int *fd_percpu;
int *fd_instr_count_percpu;
struct timeval interval_tv = { 5, 0 };
struct timespec interval_ts = { 5, 0 };
unsigned int num_iterations;
unsigned int header_iterations;
unsigned int debug;
unsigned int quiet;
unsigned int shown;
unsigned int sums_need_wide_columns;
unsigned int rapl_joules;
unsigned int summary_only;
unsigned int list_header_only;
unsigned int dump_only;
unsigned int force_load;
unsigned int has_aperf;
unsigned int has_aperf_access;
unsigned int has_epb;
unsigned int has_turbo;
unsigned int is_hybrid;
unsigned int units = 1000000; /* MHz etc */
unsigned int genuine_intel;
unsigned int authentic_amd;
unsigned int hygon_genuine;
unsigned int max_level, max_extended_level;
unsigned int has_invariant_tsc;
unsigned int aperf_mperf_multiplier = 1;
double bclk;
double base_hz;
unsigned int has_base_hz;
double tsc_tweak = 1.0;
unsigned int show_pkg_only;
unsigned int show_core_only;
char *output_buffer, *outp;
unsigned int do_dts;
unsigned int do_ptm;
unsigned int do_ipc;
unsigned long long cpuidle_cur_cpu_lpi_us;
unsigned long long cpuidle_cur_sys_lpi_us;
unsigned int tj_max;
unsigned int tj_max_override;
double rapl_power_units, rapl_time_units;
double rapl_dram_energy_units, rapl_energy_units, rapl_psys_energy_units;
double rapl_joule_counter_range;
unsigned int crystal_hz;
unsigned long long tsc_hz;
int base_cpu;
unsigned int has_hwp; /* IA32_PM_ENABLE, IA32_HWP_CAPABILITIES */
/* IA32_HWP_REQUEST, IA32_HWP_STATUS */
unsigned int has_hwp_notify; /* IA32_HWP_INTERRUPT */
unsigned int has_hwp_activity_window; /* IA32_HWP_REQUEST[bits 41:32] */
unsigned int has_hwp_epp; /* IA32_HWP_REQUEST[bits 31:24] */
unsigned int has_hwp_pkg; /* IA32_HWP_REQUEST_PKG */
unsigned int first_counter_read = 1;
static struct timeval procsysfs_tv_begin;
int ignore_stdin;
bool no_msr;
bool no_perf;
enum gfx_sysfs_idx {
GFX_rc6,
GFX_MHz,
GFX_ACTMHz,
SAM_mc6,
SAM_MHz,
SAM_ACTMHz,
GFX_MAX
};
struct gfx_sysfs_info {
FILE *fp;
unsigned int val;
unsigned long long val_ull;
};
static struct gfx_sysfs_info gfx_info[GFX_MAX];
int get_msr(int cpu, off_t offset, unsigned long long *msr);
int add_counter(unsigned int msr_num, char *path, char *name,
unsigned int width, enum counter_scope scope,
enum counter_type type, enum counter_format format, int flags, int package_num);
/* Model specific support Start */
/* List of features that may diverge among different platforms */
struct platform_features {
bool has_msr_misc_feature_control; /* MSR_MISC_FEATURE_CONTROL */
bool has_msr_misc_pwr_mgmt; /* MSR_MISC_PWR_MGMT */
bool has_nhm_msrs; /* MSR_PLATFORM_INFO, MSR_IA32_TEMPERATURE_TARGET, MSR_SMI_COUNT, MSR_PKG_CST_CONFIG_CONTROL, MSR_IA32_POWER_CTL, TRL MSRs */
bool has_config_tdp; /* MSR_CONFIG_TDP_NOMINAL/LEVEL_1/LEVEL_2/CONTROL, MSR_TURBO_ACTIVATION_RATIO */
int bclk_freq; /* CPU base clock */
int crystal_freq; /* Crystal clock to use when not available from CPUID.15 */
int supported_cstates; /* Core cstates and Package cstates supported */
int cst_limit; /* MSR_PKG_CST_CONFIG_CONTROL */
bool has_cst_auto_convension; /* AUTOMATIC_CSTATE_CONVERSION bit in MSR_PKG_CST_CONFIG_CONTROL */
bool has_irtl_msrs; /* MSR_PKGC3/PKGC6/PKGC7/PKGC8/PKGC9/PKGC10_IRTL */
bool has_msr_core_c1_res; /* MSR_CORE_C1_RES */
bool has_msr_module_c6_res_ms; /* MSR_MODULE_C6_RES_MS */
bool has_msr_c6_demotion_policy_config; /* MSR_CC6_DEMOTION_POLICY_CONFIG/MSR_MC6_DEMOTION_POLICY_CONFIG */
bool has_msr_atom_pkg_c6_residency; /* MSR_ATOM_PKG_C6_RESIDENCY */
bool has_msr_knl_core_c6_residency; /* MSR_KNL_CORE_C6_RESIDENCY */
bool has_ext_cst_msrs; /* MSR_PKG_WEIGHTED_CORE_C0_RES/MSR_PKG_ANY_CORE_C0_RES/MSR_PKG_ANY_GFXE_C0_RES/MSR_PKG_BOTH_CORE_GFXE_C0_RES */
bool has_cst_prewake_bit; /* Cstate prewake bit in MSR_IA32_POWER_CTL */
int trl_msrs; /* MSR_TURBO_RATIO_LIMIT/LIMIT1/LIMIT2/SECONDARY, Atom TRL MSRs */
int plr_msrs; /* MSR_CORE/GFX/RING_PERF_LIMIT_REASONS */
int rapl_msrs; /* RAPL PKG/DRAM/CORE/GFX MSRs, AMD RAPL MSRs */
bool has_per_core_rapl; /* Indicates cores energy collection is per-core, not per-package. AMD specific for now */
bool has_rapl_divisor; /* Divisor for Energy unit raw value from MSR_RAPL_POWER_UNIT */
bool has_fixed_rapl_unit; /* Fixed Energy Unit used for DRAM RAPL Domain */
bool has_fixed_rapl_psys_unit; /* Fixed Energy Unit used for PSYS RAPL Domain */
int rapl_quirk_tdp; /* Hardcoded TDP value when cannot be retrieved from hardware */
int tcc_offset_bits; /* TCC Offset bits in MSR_IA32_TEMPERATURE_TARGET */
bool enable_tsc_tweak; /* Use CPU Base freq instead of TSC freq for aperf/mperf counter */
bool need_perf_multiplier; /* mperf/aperf multiplier */
};
struct platform_data {
unsigned int vfm;
const struct platform_features *features;
};
/* For BCLK */
enum bclk_freq {
BCLK_100MHZ = 1,
BCLK_133MHZ,
BCLK_SLV,
};
#define SLM_BCLK_FREQS 5
double slm_freq_table[SLM_BCLK_FREQS] = { 83.3, 100.0, 133.3, 116.7, 80.0 };
double slm_bclk(void )
{
unsigned long long msr = 3;
unsigned int i;
double freq;
if (get_msr(base_cpu, MSR_FSB_FREQ, &msr))
fprintf(outf, "SLM BCLK: unknown\n" );
i = msr & 0xf;
if (i >= SLM_BCLK_FREQS) {
fprintf(outf, "SLM BCLK[%d] invalid\n" , i);
i = 3;
}
freq = slm_freq_table[i];
if (!quiet)
fprintf(outf, "SLM BCLK: %.1f Mhz\n" , freq);
return freq;
}
/* For Package cstate limit */
enum package_cstate_limit {
CST_LIMIT_NHM = 1,
CST_LIMIT_SNB,
CST_LIMIT_HSW,
CST_LIMIT_SKX,
CST_LIMIT_ICX,
CST_LIMIT_SLV,
CST_LIMIT_AMT,
CST_LIMIT_KNL,
CST_LIMIT_GMT,
};
/* For Turbo Ratio Limit MSRs */
enum turbo_ratio_limit_msrs {
TRL_BASE = BIT(0),
TRL_LIMIT1 = BIT(1),
TRL_LIMIT2 = BIT(2),
TRL_ATOM = BIT(3),
TRL_KNL = BIT(4),
TRL_CORECOUNT = BIT(5),
};
/* For Perf Limit Reason MSRs */
enum perf_limit_reason_msrs {
PLR_CORE = BIT(0),
PLR_GFX = BIT(1),
PLR_RING = BIT(2),
};
/* For RAPL MSRs */
enum rapl_msrs {
RAPL_PKG_POWER_LIMIT = BIT(0), /* 0x610 MSR_PKG_POWER_LIMIT */
RAPL_PKG_ENERGY_STATUS = BIT(1), /* 0x611 MSR_PKG_ENERGY_STATUS */
RAPL_PKG_PERF_STATUS = BIT(2), /* 0x613 MSR_PKG_PERF_STATUS */
RAPL_PKG_POWER_INFO = BIT(3), /* 0x614 MSR_PKG_POWER_INFO */
RAPL_DRAM_POWER_LIMIT = BIT(4), /* 0x618 MSR_DRAM_POWER_LIMIT */
RAPL_DRAM_ENERGY_STATUS = BIT(5), /* 0x619 MSR_DRAM_ENERGY_STATUS */
RAPL_DRAM_PERF_STATUS = BIT(6), /* 0x61b MSR_DRAM_PERF_STATUS */
RAPL_DRAM_POWER_INFO = BIT(7), /* 0x61c MSR_DRAM_POWER_INFO */
RAPL_CORE_POWER_LIMIT = BIT(8), /* 0x638 MSR_PP0_POWER_LIMIT */
RAPL_CORE_ENERGY_STATUS = BIT(9), /* 0x639 MSR_PP0_ENERGY_STATUS */
RAPL_CORE_POLICY = BIT(10), /* 0x63a MSR_PP0_POLICY */
RAPL_GFX_POWER_LIMIT = BIT(11), /* 0x640 MSR_PP1_POWER_LIMIT */
RAPL_GFX_ENERGY_STATUS = BIT(12), /* 0x641 MSR_PP1_ENERGY_STATUS */
RAPL_GFX_POLICY = BIT(13), /* 0x642 MSR_PP1_POLICY */
RAPL_AMD_PWR_UNIT = BIT(14), /* 0xc0010299 MSR_AMD_RAPL_POWER_UNIT */
RAPL_AMD_CORE_ENERGY_STAT = BIT(15), /* 0xc001029a MSR_AMD_CORE_ENERGY_STATUS */
RAPL_AMD_PKG_ENERGY_STAT = BIT(16), /* 0xc001029b MSR_AMD_PKG_ENERGY_STATUS */
RAPL_PLATFORM_ENERGY_LIMIT = BIT(17), /* 0x64c MSR_PLATFORM_ENERGY_LIMIT */
RAPL_PLATFORM_ENERGY_STATUS = BIT(18), /* 0x64d MSR_PLATFORM_ENERGY_STATUS */
};
#define RAPL_PKG (RAPL_PKG_ENERGY_STATUS | RAPL_PKG_POWER_LIMIT)
#define RAPL_DRAM (RAPL_DRAM_ENERGY_STATUS | RAPL_DRAM_POWER_LIMIT)
#define RAPL_CORE (RAPL_CORE_ENERGY_STATUS | RAPL_CORE_POWER_LIMIT)
#define RAPL_GFX (RAPL_GFX_POWER_LIMIT | RAPL_GFX_ENERGY_STATUS)
#define RAPL_PSYS (RAPL_PLATFORM_ENERGY_STATUS | RAPL_PLATFORM_ENERGY_LIMIT)
#define RAPL_PKG_ALL (RAPL_PKG | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO)
#define RAPL_DRAM_ALL (RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_DRAM_POWER_INFO)
#define RAPL_CORE_ALL (RAPL_CORE | RAPL_CORE_POLICY)
#define RAPL_GFX_ALL (RAPL_GFX | RAPL_GFX_POLICY)
#define RAPL_AMD_F17H (RAPL_AMD_PWR_UNIT | RAPL_AMD_CORE_ENERGY_STAT | RAPL_AMD_PKG_ENERGY_STAT)
/* For Cstates */
enum cstates {
CC1 = BIT(0),
CC3 = BIT(1),
CC6 = BIT(2),
CC7 = BIT(3),
PC2 = BIT(4),
PC3 = BIT(5),
PC6 = BIT(6),
PC7 = BIT(7),
PC8 = BIT(8),
PC9 = BIT(9),
PC10 = BIT(10),
};
static const struct platform_features nhm_features = {
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.bclk_freq = BCLK_133MHZ,
.supported_cstates = CC1 | CC3 | CC6 | PC3 | PC6,
.cst_limit = CST_LIMIT_NHM,
.trl_msrs = TRL_BASE,
};
static const struct platform_features nhx_features = {
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.bclk_freq = BCLK_133MHZ,
.supported_cstates = CC1 | CC3 | CC6 | PC3 | PC6,
.cst_limit = CST_LIMIT_NHM,
};
static const struct platform_features snb_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7,
.cst_limit = CST_LIMIT_SNB,
.has_irtl_msrs = 1,
.trl_msrs = TRL_BASE,
.rapl_msrs = RAPL_PKG | RAPL_CORE_ALL | RAPL_GFX | RAPL_PKG_POWER_INFO,
};
static const struct platform_features snx_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7,
.cst_limit = CST_LIMIT_SNB,
.has_irtl_msrs = 1,
.trl_msrs = TRL_BASE,
.rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM_ALL,
};
static const struct platform_features ivb_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7,
.cst_limit = CST_LIMIT_SNB,
.has_irtl_msrs = 1,
.trl_msrs = TRL_BASE,
.rapl_msrs = RAPL_PKG | RAPL_CORE_ALL | RAPL_GFX | RAPL_PKG_POWER_INFO,
};
static const struct platform_features ivx_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7,
.cst_limit = CST_LIMIT_SNB,
.has_irtl_msrs = 1,
.trl_msrs = TRL_BASE | TRL_LIMIT1,
.rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM_ALL,
};
static const struct platform_features hsw_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7,
.cst_limit = CST_LIMIT_HSW,
.has_irtl_msrs = 1,
.trl_msrs = TRL_BASE,
.plr_msrs = PLR_CORE | PLR_GFX | PLR_RING,
.rapl_msrs = RAPL_PKG | RAPL_CORE_ALL | RAPL_GFX | RAPL_PKG_POWER_INFO,
};
static const struct platform_features hsx_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7,
.cst_limit = CST_LIMIT_HSW,
.has_irtl_msrs = 1,
.trl_msrs = TRL_BASE | TRL_LIMIT1 | TRL_LIMIT2,
.plr_msrs = PLR_CORE | PLR_RING,
.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL,
.has_fixed_rapl_unit = 1,
};
static const struct platform_features hswl_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7 | PC8 | PC9 | PC10,
.cst_limit = CST_LIMIT_HSW,
.has_irtl_msrs = 1,
.trl_msrs = TRL_BASE,
.plr_msrs = PLR_CORE | PLR_GFX | PLR_RING,
.rapl_msrs = RAPL_PKG | RAPL_CORE_ALL | RAPL_GFX | RAPL_PKG_POWER_INFO,
};
static const struct platform_features hswg_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7,
.cst_limit = CST_LIMIT_HSW,
.has_irtl_msrs = 1,
.trl_msrs = TRL_BASE,
.plr_msrs = PLR_CORE | PLR_GFX | PLR_RING,
.rapl_msrs = RAPL_PKG | RAPL_CORE_ALL | RAPL_GFX | RAPL_PKG_POWER_INFO,
};
static const struct platform_features bdw_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7 | PC8 | PC9 | PC10,
.cst_limit = CST_LIMIT_HSW,
.has_irtl_msrs = 1,
.trl_msrs = TRL_BASE,
.rapl_msrs = RAPL_PKG | RAPL_CORE_ALL | RAPL_GFX | RAPL_PKG_POWER_INFO,
};
static const struct platform_features bdwg_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7,
.cst_limit = CST_LIMIT_HSW,
.has_irtl_msrs = 1,
.trl_msrs = TRL_BASE,
.rapl_msrs = RAPL_PKG | RAPL_CORE_ALL | RAPL_GFX | RAPL_PKG_POWER_INFO,
};
static const struct platform_features bdx_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC3 | CC6 | PC2 | PC3 | PC6,
.cst_limit = CST_LIMIT_HSW,
.has_irtl_msrs = 1,
.has_cst_auto_convension = 1,
.trl_msrs = TRL_BASE,
.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL,
.has_fixed_rapl_unit = 1,
};
static const struct platform_features skl_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.crystal_freq = 24000000,
.supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7 | PC8 | PC9 | PC10,
.cst_limit = CST_LIMIT_HSW,
.has_irtl_msrs = 1,
.has_ext_cst_msrs = 1,
.trl_msrs = TRL_BASE,
.tcc_offset_bits = 6,
.rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_GFX | RAPL_PSYS,
.enable_tsc_tweak = 1,
};
static const struct platform_features cnl_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7 | PC8 | PC9 | PC10,
.cst_limit = CST_LIMIT_HSW,
.has_irtl_msrs = 1,
.has_msr_core_c1_res = 1,
.has_ext_cst_msrs = 1,
.trl_msrs = TRL_BASE,
.tcc_offset_bits = 6,
.rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_GFX | RAPL_PSYS,
.enable_tsc_tweak = 1,
};
/* Copied from cnl_features, with PC7/PC9 removed */
static const struct platform_features adl_features = {
.has_msr_misc_feature_control = cnl_features.has_msr_misc_feature_control,
.has_msr_misc_pwr_mgmt = cnl_features.has_msr_misc_pwr_mgmt,
.has_nhm_msrs = cnl_features.has_nhm_msrs,
.has_config_tdp = cnl_features.has_config_tdp,
.bclk_freq = cnl_features.bclk_freq,
.supported_cstates = CC1 | CC6 | CC7 | PC2 | PC3 | PC6 | PC8 | PC10,
.cst_limit = cnl_features.cst_limit,
.has_irtl_msrs = cnl_features.has_irtl_msrs,
.has_msr_core_c1_res = cnl_features.has_msr_core_c1_res,
.has_ext_cst_msrs = cnl_features.has_ext_cst_msrs,
.trl_msrs = cnl_features.trl_msrs,
.tcc_offset_bits = cnl_features.tcc_offset_bits,
.rapl_msrs = cnl_features.rapl_msrs,
.enable_tsc_tweak = cnl_features.enable_tsc_tweak,
};
/* Copied from adl_features, with PC3/PC8 removed */
static const struct platform_features lnl_features = {
.has_msr_misc_feature_control = adl_features.has_msr_misc_feature_control,
.has_msr_misc_pwr_mgmt = adl_features.has_msr_misc_pwr_mgmt,
.has_nhm_msrs = adl_features.has_nhm_msrs,
.has_config_tdp = adl_features.has_config_tdp,
.bclk_freq = adl_features.bclk_freq,
.supported_cstates = CC1 | CC6 | CC7 | PC2 | PC6 | PC10,
.cst_limit = adl_features.cst_limit,
.has_irtl_msrs = adl_features.has_irtl_msrs,
.has_msr_core_c1_res = adl_features.has_msr_core_c1_res,
.has_ext_cst_msrs = adl_features.has_ext_cst_msrs,
.trl_msrs = adl_features.trl_msrs,
.tcc_offset_bits = adl_features.tcc_offset_bits,
.rapl_msrs = adl_features.rapl_msrs,
.enable_tsc_tweak = adl_features.enable_tsc_tweak,
};
static const struct platform_features skx_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC6 | PC2 | PC6,
.cst_limit = CST_LIMIT_SKX,
.has_irtl_msrs = 1,
.has_cst_auto_convension = 1,
.trl_msrs = TRL_BASE | TRL_CORECOUNT,
.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL,
.has_fixed_rapl_unit = 1,
};
static const struct platform_features icx_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC6 | PC2 | PC6,
.cst_limit = CST_LIMIT_ICX,
.has_msr_core_c1_res = 1,
.has_irtl_msrs = 1,
.has_cst_prewake_bit = 1,
.trl_msrs = TRL_BASE | TRL_CORECOUNT,
.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_PSYS,
.has_fixed_rapl_unit = 1,
};
static const struct platform_features spr_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC6 | PC2 | PC6,
.cst_limit = CST_LIMIT_SKX,
.has_msr_core_c1_res = 1,
.has_irtl_msrs = 1,
.has_cst_prewake_bit = 1,
.has_fixed_rapl_psys_unit = 1,
.trl_msrs = TRL_BASE | TRL_CORECOUNT,
.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_PSYS,
};
static const struct platform_features dmr_features = {
.has_msr_misc_feature_control = spr_features.has_msr_misc_feature_control,
.has_msr_misc_pwr_mgmt = spr_features.has_msr_misc_pwr_mgmt,
.has_nhm_msrs = spr_features.has_nhm_msrs,
.bclk_freq = spr_features.bclk_freq,
.supported_cstates = spr_features.supported_cstates,
.cst_limit = spr_features.cst_limit,
.has_msr_core_c1_res = spr_features.has_msr_core_c1_res,
.has_cst_prewake_bit = spr_features.has_cst_prewake_bit,
.has_fixed_rapl_psys_unit = spr_features.has_fixed_rapl_psys_unit,
.trl_msrs = spr_features.trl_msrs,
.has_msr_module_c6_res_ms = 1, /* DMR has Dual-Core-Module and MC6 MSR */
.rapl_msrs = 0, /* DMR does not have RAPL MSRs */
.plr_msrs = 0, /* DMR does not have PLR MSRs */
.has_irtl_msrs = 0, /* DMR does not have IRTL MSRs */
.has_config_tdp = 0, /* DMR does not have CTDP MSRs */
};
static const struct platform_features srf_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC6 | PC2 | PC6,
.cst_limit = CST_LIMIT_SKX,
.has_msr_core_c1_res = 1,
.has_msr_module_c6_res_ms = 1,
.has_irtl_msrs = 1,
.has_cst_prewake_bit = 1,
.trl_msrs = TRL_BASE | TRL_CORECOUNT,
.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_PSYS,
};
static const struct platform_features grr_features = {
.has_msr_misc_feature_control = 1,
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC6,
.cst_limit = CST_LIMIT_SKX,
.has_msr_core_c1_res = 1,
.has_msr_module_c6_res_ms = 1,
.has_irtl_msrs = 1,
.has_cst_prewake_bit = 1,
.trl_msrs = TRL_BASE | TRL_CORECOUNT,
.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_PSYS,
};
static const struct platform_features slv_features = {
.has_nhm_msrs = 1,
.bclk_freq = BCLK_SLV,
.supported_cstates = CC1 | CC6 | PC6,
.cst_limit = CST_LIMIT_SLV,
.has_msr_core_c1_res = 1,
.has_msr_module_c6_res_ms = 1,
.has_msr_c6_demotion_policy_config = 1,
.has_msr_atom_pkg_c6_residency = 1,
.trl_msrs = TRL_ATOM,
.rapl_msrs = RAPL_PKG | RAPL_CORE,
.has_rapl_divisor = 1,
.rapl_quirk_tdp = 30,
};
static const struct platform_features slvd_features = {
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.bclk_freq = BCLK_SLV,
.supported_cstates = CC1 | CC6 | PC3 | PC6,
.cst_limit = CST_LIMIT_SLV,
.has_msr_atom_pkg_c6_residency = 1,
.trl_msrs = TRL_BASE,
.rapl_msrs = RAPL_PKG | RAPL_CORE,
.rapl_quirk_tdp = 30,
};
static const struct platform_features amt_features = {
.has_nhm_msrs = 1,
.bclk_freq = BCLK_133MHZ,
.supported_cstates = CC1 | CC3 | CC6 | PC3 | PC6,
.cst_limit = CST_LIMIT_AMT,
.trl_msrs = TRL_BASE,
};
static const struct platform_features gmt_features = {
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.bclk_freq = BCLK_100MHZ,
.crystal_freq = 19200000,
.supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7 | PC8 | PC9 | PC10,
.cst_limit = CST_LIMIT_GMT,
.has_irtl_msrs = 1,
.trl_msrs = TRL_BASE | TRL_CORECOUNT,
.rapl_msrs = RAPL_PKG | RAPL_PKG_POWER_INFO,
};
static const struct platform_features gmtd_features = {
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.bclk_freq = BCLK_100MHZ,
.crystal_freq = 25000000,
.supported_cstates = CC1 | CC6 | PC2 | PC6,
.cst_limit = CST_LIMIT_GMT,
.has_irtl_msrs = 1,
.has_msr_core_c1_res = 1,
.trl_msrs = TRL_BASE | TRL_CORECOUNT,
.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_CORE_ENERGY_STATUS,
};
static const struct platform_features gmtp_features = {
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.bclk_freq = BCLK_100MHZ,
.crystal_freq = 19200000,
.supported_cstates = CC1 | CC3 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7 | PC8 | PC9 | PC10,
.cst_limit = CST_LIMIT_GMT,
.has_irtl_msrs = 1,
.trl_msrs = TRL_BASE,
.rapl_msrs = RAPL_PKG | RAPL_PKG_POWER_INFO,
};
static const struct platform_features tmt_features = {
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC6 | CC7 | PC2 | PC3 | PC6 | PC7 | PC8 | PC9 | PC10,
.cst_limit = CST_LIMIT_GMT,
.has_irtl_msrs = 1,
.trl_msrs = TRL_BASE,
.rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_GFX,
.enable_tsc_tweak = 1,
};
static const struct platform_features tmtd_features = {
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC6,
.cst_limit = CST_LIMIT_GMT,
.has_irtl_msrs = 1,
.trl_msrs = TRL_BASE | TRL_CORECOUNT,
.rapl_msrs = RAPL_PKG_ALL,
};
static const struct platform_features knl_features = {
.has_msr_misc_pwr_mgmt = 1,
.has_nhm_msrs = 1,
.has_config_tdp = 1,
.bclk_freq = BCLK_100MHZ,
.supported_cstates = CC1 | CC6 | PC3 | PC6,
.cst_limit = CST_LIMIT_KNL,
.has_msr_knl_core_c6_residency = 1,
.trl_msrs = TRL_KNL,
.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL,
.has_fixed_rapl_unit = 1,
.need_perf_multiplier = 1,
};
static const struct platform_features default_features = {
};
static const struct platform_features amd_features_with_rapl = {
.rapl_msrs = RAPL_AMD_F17H,
.has_per_core_rapl = 1,
.rapl_quirk_tdp = 280, /* This is the max stock TDP of HEDT/Server Fam17h+ chips */
};
static const struct platform_data turbostat_pdata[] = {
{ INTEL_NEHALEM, &nhm_features },
{ INTEL_NEHALEM_G, &nhm_features },
{ INTEL_NEHALEM_EP, &nhm_features },
{ INTEL_NEHALEM_EX, &nhx_features },
{ INTEL_WESTMERE, &nhm_features },
{ INTEL_WESTMERE_EP, &nhm_features },
{ INTEL_WESTMERE_EX, &nhx_features },
{ INTEL_SANDYBRIDGE, &snb_features },
{ INTEL_SANDYBRIDGE_X, &snx_features },
{ INTEL_IVYBRIDGE, &ivb_features },
{ INTEL_IVYBRIDGE_X, &ivx_features },
{ INTEL_HASWELL, &hsw_features },
{ INTEL_HASWELL_X, &hsx_features },
{ INTEL_HASWELL_L, &hswl_features },
{ INTEL_HASWELL_G, &hswg_features },
{ INTEL_BROADWELL, &bdw_features },
{ INTEL_BROADWELL_G, &bdwg_features },
{ INTEL_BROADWELL_X, &bdx_features },
{ INTEL_BROADWELL_D, &bdx_features },
{ INTEL_SKYLAKE_L, &skl_features },
{ INTEL_SKYLAKE, &skl_features },
{ INTEL_SKYLAKE_X, &skx_features },
{ INTEL_KABYLAKE_L, &skl_features },
{ INTEL_KABYLAKE, &skl_features },
{ INTEL_COMETLAKE, &skl_features },
{ INTEL_COMETLAKE_L, &skl_features },
{ INTEL_CANNONLAKE_L, &cnl_features },
{ INTEL_ICELAKE_X, &icx_features },
{ INTEL_ICELAKE_D, &icx_features },
{ INTEL_ICELAKE_L, &cnl_features },
{ INTEL_ICELAKE_NNPI, &cnl_features },
{ INTEL_ROCKETLAKE, &cnl_features },
{ INTEL_TIGERLAKE_L, &cnl_features },
{ INTEL_TIGERLAKE, &cnl_features },
{ INTEL_SAPPHIRERAPIDS_X, &spr_features },
{ INTEL_EMERALDRAPIDS_X, &spr_features },
{ INTEL_GRANITERAPIDS_X, &spr_features },
{ INTEL_GRANITERAPIDS_D, &spr_features },
{ INTEL_PANTHERCOVE_X, &dmr_features },
{ INTEL_LAKEFIELD, &cnl_features },
{ INTEL_ALDERLAKE, &adl_features },
{ INTEL_ALDERLAKE_L, &adl_features },
{ INTEL_RAPTORLAKE, &adl_features },
{ INTEL_RAPTORLAKE_P, &adl_features },
{ INTEL_RAPTORLAKE_S, &adl_features },
{ INTEL_BARTLETTLAKE, &adl_features },
{ INTEL_METEORLAKE, &adl_features },
{ INTEL_METEORLAKE_L, &adl_features },
{ INTEL_ARROWLAKE_H, &adl_features },
{ INTEL_ARROWLAKE_U, &adl_features },
{ INTEL_ARROWLAKE, &adl_features },
{ INTEL_LUNARLAKE_M, &lnl_features },
{ INTEL_PANTHERLAKE_L, &lnl_features },
{ INTEL_ATOM_SILVERMONT, &slv_features },
{ INTEL_ATOM_SILVERMONT_D, &slvd_features },
{ INTEL_ATOM_AIRMONT, &amt_features },
{ INTEL_ATOM_GOLDMONT, &gmt_features },
{ INTEL_ATOM_GOLDMONT_D, &gmtd_features },
{ INTEL_ATOM_GOLDMONT_PLUS, &gmtp_features },
{ INTEL_ATOM_TREMONT_D, &tmtd_features },
{ INTEL_ATOM_TREMONT, &tmt_features },
{ INTEL_ATOM_TREMONT_L, &tmt_features },
{ INTEL_ATOM_GRACEMONT, &adl_features },
{ INTEL_ATOM_CRESTMONT_X, &srf_features },
{ INTEL_ATOM_CRESTMONT, &grr_features },
{ INTEL_ATOM_DARKMONT_X, &srf_features },
{ INTEL_XEON_PHI_KNL, &knl_features },
{ INTEL_XEON_PHI_KNM, &knl_features },
/*
* Missing support for
* INTEL_ICELAKE
* INTEL_ATOM_SILVERMONT_MID
* INTEL_ATOM_SILVERMONT_MID2
* INTEL_ATOM_AIRMONT_NP
*/
{ 0, NULL },
};
static const struct platform_features *platform;
void probe_platform_features(unsigned int family, unsigned int model)
{
int i;
if (authentic_amd || hygon_genuine) {
/* fallback to default features on unsupported models */
force_load++;
if (max_extended_level >= 0x80000007) {
unsigned int eax, ebx, ecx, edx;
__cpuid(0x80000007, eax, ebx, ecx, edx);
/* RAPL (Fam 17h+) */
if ((edx & (1 << 14)) && family >= 0x17)
platform = &amd_features_with_rapl;
}
goto end;
}
if (!genuine_intel)
goto end;
for (i = 0; turbostat_pdata[i].features; i++) {
if (VFM_FAMILY(turbostat_pdata[i].vfm) == family && VFM_MODEL(turbostat_pdata[i].vfm) == model) {
platform = turbostat_pdata[i].features;
return ;
}
}
end:
if (force_load && !platform) {
fprintf(outf, "Forced to run on unsupported platform!\n" );
platform = &default_features;
}
if (platform)
return ;
fprintf(stderr, "Unsupported platform detected.\n\tSee RUN THE LATEST VERSION on turbostat(8)\n" );
exit (1);
}
/* Model specific support End */
#define TJMAX_DEFAULT 100
/* MSRs that are not yet in the kernel-provided header. */
#define MSR_RAPL_PWR_UNIT 0xc0010299
#define MSR_CORE_ENERGY_STAT 0xc001029a
#define MSR_PKG_ENERGY_STAT 0xc001029b
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int backwards_count;
char *progname;
#define CPU_SUBSET_MAXCPUS 8192 /* need to use before probe... */
cpu_set_t *cpu_present_set, *cpu_possible_set, *cpu_effective_set, *cpu_allowed_set, *cpu_affinity_set, *cpu_subset;
size_t cpu_present_setsize, cpu_possible_setsize, cpu_effective_setsize, cpu_allowed_setsize, cpu_affinity_setsize,
cpu_subset_size;
#define MAX_ADDED_THREAD_COUNTERS 24
#define MAX_ADDED_CORE_COUNTERS 8
#define MAX_ADDED_PACKAGE_COUNTERS 16
#define PMT_MAX_ADDED_THREAD_COUNTERS 24
#define PMT_MAX_ADDED_CORE_COUNTERS 8
#define PMT_MAX_ADDED_PACKAGE_COUNTERS 16
#define BITMASK_SIZE 32
#define ZERO_ARRAY(arr) (memset(arr, 0, sizeof (arr)) + __must_be_array(arr))
/* Indexes used to map data read from perf and MSRs into global variables */
enum rapl_rci_index {
RAPL_RCI_INDEX_ENERGY_PKG = 0,
RAPL_RCI_INDEX_ENERGY_CORES = 1,
RAPL_RCI_INDEX_DRAM = 2,
RAPL_RCI_INDEX_GFX = 3,
RAPL_RCI_INDEX_PKG_PERF_STATUS = 4,
RAPL_RCI_INDEX_DRAM_PERF_STATUS = 5,
RAPL_RCI_INDEX_CORE_ENERGY = 6,
RAPL_RCI_INDEX_ENERGY_PLATFORM = 7,
NUM_RAPL_COUNTERS,
};
enum rapl_unit {
RAPL_UNIT_INVALID,
RAPL_UNIT_JOULES,
RAPL_UNIT_WATTS,
};
struct rapl_counter_info_t {
unsigned long long data[NUM_RAPL_COUNTERS];
enum counter_source source[NUM_RAPL_COUNTERS];
unsigned long long flags[NUM_RAPL_COUNTERS];
double scale[NUM_RAPL_COUNTERS];
enum rapl_unit unit[NUM_RAPL_COUNTERS];
unsigned long long msr[NUM_RAPL_COUNTERS];
unsigned long long msr_mask[NUM_RAPL_COUNTERS];
int msr_shift[NUM_RAPL_COUNTERS];
int fd_perf;
};
/* struct rapl_counter_info_t for each RAPL domain */
struct rapl_counter_info_t *rapl_counter_info_perdomain;
unsigned int rapl_counter_info_perdomain_size;
#define RAPL_COUNTER_FLAG_PLATFORM_COUNTER (1u << 0)
#define RAPL_COUNTER_FLAG_USE_MSR_SUM (1u << 1)
struct rapl_counter_arch_info {
int feature_mask; /* Mask for testing if the counter is supported on host */
const char *perf_subsys;
const char *perf_name;
unsigned long long msr;
unsigned long long msr_mask;
int msr_shift; /* Positive mean shift right, negative mean shift left */
double *platform_rapl_msr_scale; /* Scale applied to values read by MSR (platform dependent, filled at runtime) */
unsigned int rci_index; /* Maps data from perf counters to global variables */
unsigned int bic_number;
double compat_scale; /* Some counters require constant scaling to be in the same range as other, similar ones */
unsigned long long flags;
};
static const struct rapl_counter_arch_info rapl_counter_arch_infos[] = {
{
.feature_mask = RAPL_PKG,
.perf_subsys = "power" ,
.perf_name = "energy-pkg" ,
.msr = MSR_PKG_ENERGY_STATUS,
.msr_mask = 0xFFFFFFFFFFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_energy_units,
.rci_index = RAPL_RCI_INDEX_ENERGY_PKG,
.bic_number = BIC_PkgWatt,
.compat_scale = 1.0,
.flags = RAPL_COUNTER_FLAG_USE_MSR_SUM,
},
{
.feature_mask = RAPL_PKG,
.perf_subsys = "power" ,
.perf_name = "energy-pkg" ,
.msr = MSR_PKG_ENERGY_STATUS,
.msr_mask = 0xFFFFFFFFFFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_energy_units,
.rci_index = RAPL_RCI_INDEX_ENERGY_PKG,
.bic_number = BIC_Pkg_J,
.compat_scale = 1.0,
.flags = RAPL_COUNTER_FLAG_USE_MSR_SUM,
},
{
.feature_mask = RAPL_AMD_F17H,
.perf_subsys = "power" ,
.perf_name = "energy-pkg" ,
.msr = MSR_PKG_ENERGY_STAT,
.msr_mask = 0xFFFFFFFFFFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_energy_units,
.rci_index = RAPL_RCI_INDEX_ENERGY_PKG,
.bic_number = BIC_PkgWatt,
.compat_scale = 1.0,
.flags = RAPL_COUNTER_FLAG_USE_MSR_SUM,
},
{
.feature_mask = RAPL_AMD_F17H,
.perf_subsys = "power" ,
.perf_name = "energy-pkg" ,
.msr = MSR_PKG_ENERGY_STAT,
.msr_mask = 0xFFFFFFFFFFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_energy_units,
.rci_index = RAPL_RCI_INDEX_ENERGY_PKG,
.bic_number = BIC_Pkg_J,
.compat_scale = 1.0,
.flags = RAPL_COUNTER_FLAG_USE_MSR_SUM,
},
{
.feature_mask = RAPL_CORE_ENERGY_STATUS,
.perf_subsys = "power" ,
.perf_name = "energy-cores" ,
.msr = MSR_PP0_ENERGY_STATUS,
.msr_mask = 0xFFFFFFFFFFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_energy_units,
.rci_index = RAPL_RCI_INDEX_ENERGY_CORES,
.bic_number = BIC_CorWatt,
.compat_scale = 1.0,
.flags = RAPL_COUNTER_FLAG_USE_MSR_SUM,
},
{
.feature_mask = RAPL_CORE_ENERGY_STATUS,
.perf_subsys = "power" ,
.perf_name = "energy-cores" ,
.msr = MSR_PP0_ENERGY_STATUS,
.msr_mask = 0xFFFFFFFFFFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_energy_units,
.rci_index = RAPL_RCI_INDEX_ENERGY_CORES,
.bic_number = BIC_Cor_J,
.compat_scale = 1.0,
.flags = RAPL_COUNTER_FLAG_USE_MSR_SUM,
},
{
.feature_mask = RAPL_DRAM,
.perf_subsys = "power" ,
.perf_name = "energy-ram" ,
.msr = MSR_DRAM_ENERGY_STATUS,
.msr_mask = 0xFFFFFFFFFFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_dram_energy_units,
.rci_index = RAPL_RCI_INDEX_DRAM,
.bic_number = BIC_RAMWatt,
.compat_scale = 1.0,
.flags = RAPL_COUNTER_FLAG_USE_MSR_SUM,
},
{
.feature_mask = RAPL_DRAM,
.perf_subsys = "power" ,
.perf_name = "energy-ram" ,
.msr = MSR_DRAM_ENERGY_STATUS,
.msr_mask = 0xFFFFFFFFFFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_dram_energy_units,
.rci_index = RAPL_RCI_INDEX_DRAM,
.bic_number = BIC_RAM_J,
.compat_scale = 1.0,
.flags = RAPL_COUNTER_FLAG_USE_MSR_SUM,
},
{
.feature_mask = RAPL_GFX,
.perf_subsys = "power" ,
.perf_name = "energy-gpu" ,
.msr = MSR_PP1_ENERGY_STATUS,
.msr_mask = 0xFFFFFFFFFFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_energy_units,
.rci_index = RAPL_RCI_INDEX_GFX,
.bic_number = BIC_GFXWatt,
.compat_scale = 1.0,
.flags = RAPL_COUNTER_FLAG_USE_MSR_SUM,
},
{
.feature_mask = RAPL_GFX,
.perf_subsys = "power" ,
.perf_name = "energy-gpu" ,
.msr = MSR_PP1_ENERGY_STATUS,
.msr_mask = 0xFFFFFFFFFFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_energy_units,
.rci_index = RAPL_RCI_INDEX_GFX,
.bic_number = BIC_GFX_J,
.compat_scale = 1.0,
.flags = RAPL_COUNTER_FLAG_USE_MSR_SUM,
},
{
.feature_mask = RAPL_PKG_PERF_STATUS,
.perf_subsys = NULL,
.perf_name = NULL,
.msr = MSR_PKG_PERF_STATUS,
.msr_mask = 0xFFFFFFFFFFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_time_units,
.rci_index = RAPL_RCI_INDEX_PKG_PERF_STATUS,
.bic_number = BIC_PKG__,
.compat_scale = 100.0,
.flags = RAPL_COUNTER_FLAG_USE_MSR_SUM,
},
{
.feature_mask = RAPL_DRAM_PERF_STATUS,
.perf_subsys = NULL,
.perf_name = NULL,
.msr = MSR_DRAM_PERF_STATUS,
.msr_mask = 0xFFFFFFFFFFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_time_units,
.rci_index = RAPL_RCI_INDEX_DRAM_PERF_STATUS,
.bic_number = BIC_RAM__,
.compat_scale = 100.0,
.flags = RAPL_COUNTER_FLAG_USE_MSR_SUM,
},
{
.feature_mask = RAPL_AMD_F17H,
.perf_subsys = NULL,
.perf_name = NULL,
.msr = MSR_CORE_ENERGY_STAT,
.msr_mask = 0xFFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_energy_units,
.rci_index = RAPL_RCI_INDEX_CORE_ENERGY,
.bic_number = BIC_CorWatt,
.compat_scale = 1.0,
.flags = 0,
},
{
.feature_mask = RAPL_AMD_F17H,
.perf_subsys = NULL,
.perf_name = NULL,
.msr = MSR_CORE_ENERGY_STAT,
.msr_mask = 0xFFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_energy_units,
.rci_index = RAPL_RCI_INDEX_CORE_ENERGY,
.bic_number = BIC_Cor_J,
.compat_scale = 1.0,
.flags = 0,
},
{
.feature_mask = RAPL_PSYS,
.perf_subsys = "power" ,
.perf_name = "energy-psys" ,
.msr = MSR_PLATFORM_ENERGY_STATUS,
.msr_mask = 0x00000000FFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_psys_energy_units,
.rci_index = RAPL_RCI_INDEX_ENERGY_PLATFORM,
.bic_number = BIC_SysWatt,
.compat_scale = 1.0,
.flags = RAPL_COUNTER_FLAG_PLATFORM_COUNTER | RAPL_COUNTER_FLAG_USE_MSR_SUM,
},
{
.feature_mask = RAPL_PSYS,
.perf_subsys = "power" ,
.perf_name = "energy-psys" ,
.msr = MSR_PLATFORM_ENERGY_STATUS,
.msr_mask = 0x00000000FFFFFFFF,
.msr_shift = 0,
.platform_rapl_msr_scale = &rapl_psys_energy_units,
.rci_index = RAPL_RCI_INDEX_ENERGY_PLATFORM,
.bic_number = BIC_Sys_J,
.compat_scale = 1.0,
.flags = RAPL_COUNTER_FLAG_PLATFORM_COUNTER | RAPL_COUNTER_FLAG_USE_MSR_SUM,
},
};
struct rapl_counter {
unsigned long long raw_value;
enum rapl_unit unit;
double scale;
};
/* Indexes used to map data read from perf and MSRs into global variables */
enum ccstate_rci_index {
CCSTATE_RCI_INDEX_C1_RESIDENCY = 0,
CCSTATE_RCI_INDEX_C3_RESIDENCY = 1,
CCSTATE_RCI_INDEX_C6_RESIDENCY = 2,
CCSTATE_RCI_INDEX_C7_RESIDENCY = 3,
PCSTATE_RCI_INDEX_C2_RESIDENCY = 4,
PCSTATE_RCI_INDEX_C3_RESIDENCY = 5,
PCSTATE_RCI_INDEX_C6_RESIDENCY = 6,
PCSTATE_RCI_INDEX_C7_RESIDENCY = 7,
PCSTATE_RCI_INDEX_C8_RESIDENCY = 8,
PCSTATE_RCI_INDEX_C9_RESIDENCY = 9,
PCSTATE_RCI_INDEX_C10_RESIDENCY = 10,
NUM_CSTATE_COUNTERS,
};
struct cstate_counter_info_t {
unsigned long long data[NUM_CSTATE_COUNTERS];
enum counter_source source[NUM_CSTATE_COUNTERS];
unsigned long long msr[NUM_CSTATE_COUNTERS];
int fd_perf_core;
int fd_perf_pkg;
};
struct cstate_counter_info_t *ccstate_counter_info;
unsigned int ccstate_counter_info_size;
#define CSTATE_COUNTER_FLAG_COLLECT_PER_CORE (1u << 0)
#define CSTATE_COUNTER_FLAG_COLLECT_PER_THREAD ((1u << 1) | CSTATE_COUNTER_FLAG_COLLECT_PER_CORE)
#define CSTATE_COUNTER_FLAG_SOFT_C1_DEPENDENCY (1u << 2)
struct cstate_counter_arch_info {
int feature_mask; /* Mask for testing if the counter is supported on host */
const char *perf_subsys;
const char *perf_name;
unsigned long long msr;
unsigned int rci_index; /* Maps data from perf counters to global variables */
unsigned int bic_number;
unsigned long long flags;
int pkg_cstate_limit;
};
static struct cstate_counter_arch_info ccstate_counter_arch_infos[] = {
{
.feature_mask = CC1,
.perf_subsys = "cstate_core" ,
.perf_name = "c1-residency" ,
.msr = MSR_CORE_C1_RES,
.rci_index = CCSTATE_RCI_INDEX_C1_RESIDENCY,
.bic_number = BIC_CPU_c1,
.flags = CSTATE_COUNTER_FLAG_COLLECT_PER_THREAD,
.pkg_cstate_limit = 0,
},
{
.feature_mask = CC3,
.perf_subsys = "cstate_core" ,
.perf_name = "c3-residency" ,
.msr = MSR_CORE_C3_RESIDENCY,
.rci_index = CCSTATE_RCI_INDEX_C3_RESIDENCY,
.bic_number = BIC_CPU_c3,
.flags = CSTATE_COUNTER_FLAG_COLLECT_PER_CORE | CSTATE_COUNTER_FLAG_SOFT_C1_DEPENDENCY,
.pkg_cstate_limit = 0,
},
{
.feature_mask = CC6,
.perf_subsys = "cstate_core" ,
.perf_name = "c6-residency" ,
.msr = MSR_CORE_C6_RESIDENCY,
.rci_index = CCSTATE_RCI_INDEX_C6_RESIDENCY,
.bic_number = BIC_CPU_c6,
.flags = CSTATE_COUNTER_FLAG_COLLECT_PER_CORE | CSTATE_COUNTER_FLAG_SOFT_C1_DEPENDENCY,
.pkg_cstate_limit = 0,
},
{
.feature_mask = CC7,
.perf_subsys = "cstate_core" ,
.perf_name = "c7-residency" ,
.msr = MSR_CORE_C7_RESIDENCY,
.rci_index = CCSTATE_RCI_INDEX_C7_RESIDENCY,
.bic_number = BIC_CPU_c7,
.flags = CSTATE_COUNTER_FLAG_COLLECT_PER_CORE | CSTATE_COUNTER_FLAG_SOFT_C1_DEPENDENCY,
.pkg_cstate_limit = 0,
},
{
.feature_mask = PC2,
.perf_subsys = "cstate_pkg" ,
.perf_name = "c2-residency" ,
.msr = MSR_PKG_C2_RESIDENCY,
.rci_index = PCSTATE_RCI_INDEX_C2_RESIDENCY,
.bic_number = BIC_Pkgpc2,
.flags = 0,
.pkg_cstate_limit = PCL__2,
},
{
.feature_mask = PC3,
.perf_subsys = "cstate_pkg" ,
.perf_name = "c3-residency" ,
.msr = MSR_PKG_C3_RESIDENCY,
.rci_index = PCSTATE_RCI_INDEX_C3_RESIDENCY,
.bic_number = BIC_Pkgpc3,
.flags = 0,
.pkg_cstate_limit = PCL__3,
},
{
.feature_mask = PC6,
.perf_subsys = "cstate_pkg" ,
.perf_name = "c6-residency" ,
.msr = MSR_PKG_C6_RESIDENCY,
.rci_index = PCSTATE_RCI_INDEX_C6_RESIDENCY,
.bic_number = BIC_Pkgpc6,
.flags = 0,
.pkg_cstate_limit = PCL__6,
},
{
.feature_mask = PC7,
.perf_subsys = "cstate_pkg" ,
.perf_name = "c7-residency" ,
.msr = MSR_PKG_C7_RESIDENCY,
.rci_index = PCSTATE_RCI_INDEX_C7_RESIDENCY,
.bic_number = BIC_Pkgpc7,
.flags = 0,
.pkg_cstate_limit = PCL__7,
},
{
.feature_mask = PC8,
.perf_subsys = "cstate_pkg" ,
.perf_name = "c8-residency" ,
.msr = MSR_PKG_C8_RESIDENCY,
.rci_index = PCSTATE_RCI_INDEX_C8_RESIDENCY,
.bic_number = BIC_Pkgpc8,
.flags = 0,
.pkg_cstate_limit = PCL__8,
},
{
.feature_mask = PC9,
.perf_subsys = "cstate_pkg" ,
.perf_name = "c9-residency" ,
.msr = MSR_PKG_C9_RESIDENCY,
.rci_index = PCSTATE_RCI_INDEX_C9_RESIDENCY,
.bic_number = BIC_Pkgpc9,
.flags = 0,
.pkg_cstate_limit = PCL__9,
},
{
.feature_mask = PC10,
.perf_subsys = "cstate_pkg" ,
.perf_name = "c10-residency" ,
.msr = MSR_PKG_C10_RESIDENCY,
.rci_index = PCSTATE_RCI_INDEX_C10_RESIDENCY,
.bic_number = BIC_Pkgpc10,
.flags = 0,
.pkg_cstate_limit = PCL_10,
},
};
/* Indexes used to map data read from perf and MSRs into global variables */
enum msr_rci_index {
MSR_RCI_INDEX_APERF = 0,
MSR_RCI_INDEX_MPERF = 1,
MSR_RCI_INDEX_SMI = 2,
NUM_MSR_COUNTERS,
};
struct msr_counter_info_t {
unsigned long long data[NUM_MSR_COUNTERS];
enum counter_source source[NUM_MSR_COUNTERS];
unsigned long long msr[NUM_MSR_COUNTERS];
unsigned long long msr_mask[NUM_MSR_COUNTERS];
int fd_perf;
};
struct msr_counter_info_t *msr_counter_info;
unsigned int msr_counter_info_size;
struct msr_counter_arch_info {
const char *perf_subsys;
const char *perf_name;
unsigned long long msr;
unsigned long long msr_mask;
unsigned int rci_index; /* Maps data from perf counters to global variables */
bool needed;
bool present;
};
enum msr_arch_info_index {
MSR_ARCH_INFO_APERF_INDEX = 0,
MSR_ARCH_INFO_MPERF_INDEX = 1,
MSR_ARCH_INFO_SMI_INDEX = 2,
};
static struct msr_counter_arch_info msr_counter_arch_infos[] = {
[MSR_ARCH_INFO_APERF_INDEX] = {
.perf_subsys = "msr" ,
.perf_name = "aperf" ,
.msr = MSR_IA32_APERF,
.msr_mask = 0xFFFFFFFFFFFFFFFF,
.rci_index = MSR_RCI_INDEX_APERF,
},
[MSR_ARCH_INFO_MPERF_INDEX] = {
.perf_subsys = "msr" ,
.perf_name = "mperf" ,
.msr = MSR_IA32_MPERF,
.msr_mask = 0xFFFFFFFFFFFFFFFF,
.rci_index = MSR_RCI_INDEX_MPERF,
},
[MSR_ARCH_INFO_SMI_INDEX] = {
.perf_subsys = "msr" ,
.perf_name = "smi" ,
.msr = MSR_SMI_COUNT,
.msr_mask = 0xFFFFFFFF,
.rci_index = MSR_RCI_INDEX_SMI,
},
};
/* Can be redefined when compiling, useful for testing. */
#ifndef SYSFS_TELEM_PATH
#define SYSFS_TELEM_PATH "/sys/class/intel_pmt"
#endif
#define PMT_COUNTER_MTL_DC6_OFFSET 120
#define PMT_COUNTER_MTL_DC6_LSB 0
#define PMT_COUNTER_MTL_DC6_MSB 63
#define PMT_MTL_DC6_GUID 0x1a067102
#define PMT_MTL_DC6_SEQ 0
#define PMT_COUNTER_CWF_MC1E_OFFSET_BASE 20936
#define PMT_COUNTER_CWF_MC1E_OFFSET_INCREMENT 24
#define PMT_COUNTER_CWF_MC1E_NUM_MODULES_PER_FILE 12
#define PMT_COUNTER_CWF_CPUS_PER_MODULE 4
#define PMT_COUNTER_CWF_MC1E_LSB 0
#define PMT_COUNTER_CWF_MC1E_MSB 63
#define PMT_CWF_MC1E_GUID 0x14421519
unsigned long long tcore_clock_freq_hz = 800000000;
#define PMT_COUNTER_NAME_SIZE_BYTES 16
#define PMT_COUNTER_TYPE_NAME_SIZE_BYTES 32
struct pmt_mmio {
struct pmt_mmio *next;
unsigned int guid;
unsigned int size;
/* Base pointer to the mmaped memory. */
void *mmio_base;
/*
* Offset to be applied to the mmio_base
* to get the beginning of the PMT counters for given GUID.
*/
unsigned long pmt_offset;
} *pmt_mmios;
enum pmt_datatype {
PMT_TYPE_RAW,
PMT_TYPE_XTAL_TIME,
PMT_TYPE_TCORE_CLOCK,
};
struct pmt_domain_info {
/*
* Pointer to the MMIO obtained by applying a counter offset
* to the mmio_base of the mmaped region for the given GUID.
*
* This is where to read the raw value of the counter from.
*/
unsigned long *pcounter;
};
struct pmt_counter {
struct pmt_counter *next;
/* PMT metadata */
char name[PMT_COUNTER_NAME_SIZE_BYTES];
enum pmt_datatype type;
enum counter_scope scope;
unsigned int lsb;
unsigned int msb;
/* BIC-like metadata */
enum counter_format format;
unsigned int num_domains;
struct pmt_domain_info *domains;
};
/*
* PMT telemetry directory iterator.
* Used to iterate telemetry files in sysfs in correct order.
*/
struct pmt_diriter_t {
DIR *dir;
struct dirent **namelist;
unsigned int num_names;
unsigned int current_name_idx;
};
int pmt_telemdir_filter(const struct dirent *e)
{
unsigned int dummy;
return sscanf(e->d_name, "telem%u" , &dummy);
}
int pmt_telemdir_sort(const struct dirent **a, const struct dirent **b)
{
unsigned int aidx = 0, bidx = 0;
sscanf((*a)->d_name, "telem%u" , &aidx);
sscanf((*b)->d_name, "telem%u" , &bidx);
return (aidx > bidx) ? 1 : (aidx < bidx) ? -1 : 0;
}
const struct dirent *pmt_diriter_next(struct pmt_diriter_t *iter)
{
const struct dirent *ret = NULL;
if (!iter->dir)
return NULL;
if (iter->current_name_idx >= iter->num_names)
return NULL;
ret = iter->namelist[iter->current_name_idx];
++iter->current_name_idx;
return ret;
}
const struct dirent *pmt_diriter_begin(struct pmt_diriter_t *iter, const char *pmt_root_path)
{
int num_names = iter->num_names;
if (!iter->dir) {
iter->dir = opendir(pmt_root_path);
if (iter->dir == NULL)
return NULL;
num_names = scandir(pmt_root_path, &iter->namelist, pmt_telemdir_filter, pmt_telemdir_sort);
if (num_names == -1)
return NULL;
}
iter->current_name_idx = 0;
iter->num_names = num_names;
return pmt_diriter_next(iter);
}
void pmt_diriter_init(struct pmt_diriter_t *iter)
{
memset(iter, 0, sizeof (*iter));
}
void pmt_diriter_remove(struct pmt_diriter_t *iter)
{
if (iter->namelist) {
for (unsigned int i = 0; i < iter->num_names; i++) {
free(iter->namelist[i]);
iter->namelist[i] = NULL;
}
}
free(iter->namelist);
iter->namelist = NULL;
iter->num_names = 0;
iter->current_name_idx = 0;
closedir(iter->dir);
iter->dir = NULL;
}
unsigned int pmt_counter_get_width(const struct pmt_counter *p)
{
return (p->msb - p->lsb) + 1;
}
void pmt_counter_resize_(struct pmt_counter *pcounter, unsigned int new_size)
{
struct pmt_domain_info *new_mem;
new_mem = (struct pmt_domain_info *)reallocarray(pcounter->domains, new_size, sizeof (*pcounter->domains));
if (!new_mem) {
fprintf(stderr, "%s: failed to allocate memory for PMT counters\n" , __func__);
exit (1);
}
/* Zero initialize just allocated memory. */
const size_t num_new_domains = new_size - pcounter->num_domains;
memset(&new_mem[pcounter->num_domains], 0, num_new_domains * sizeof (*pcounter->domains));
pcounter->num_domains = new_size;
pcounter->domains = new_mem;
}
void pmt_counter_resize(struct pmt_counter *pcounter, unsigned int new_size)
{
/*
* Allocate more memory ahead of time.
*
* Always allocate space for at least 8 elements
* and double the size when growing.
*/
if (new_size < 8)
new_size = 8;
new_size = MAX(new_size, pcounter->num_domains * 2);
pmt_counter_resize_(pcounter, new_size);
}
struct thread_data {
struct timeval tv_begin;
struct timeval tv_end;
struct timeval tv_delta;
unsigned long long tsc;
unsigned long long aperf;
unsigned long long mperf;
unsigned long long c1;
unsigned long long instr_count;
unsigned long long irq_count;
unsigned long long nmi_count;
unsigned int smi_count;
unsigned int cpu_id;
unsigned int apic_id;
unsigned int x2apic_id;
unsigned int flags;
bool is_atom;
unsigned long long counter[MAX_ADDED_THREAD_COUNTERS];
unsigned long long perf_counter[MAX_ADDED_THREAD_COUNTERS];
unsigned long long pmt_counter[PMT_MAX_ADDED_THREAD_COUNTERS];
} *thread_even, *thread_odd;
struct core_data {
int base_cpu;
unsigned long long c3;
unsigned long long c6;
unsigned long long c7;
unsigned long long mc6_us; /* duplicate as per-core for now, even though per module */
unsigned int core_temp_c;
struct rapl_counter core_energy; /* MSR_CORE_ENERGY_STAT */
unsigned int core_id;
unsigned long long core_throt_cnt;
unsigned long long counter[MAX_ADDED_CORE_COUNTERS];
unsigned long long perf_counter[MAX_ADDED_CORE_COUNTERS];
unsigned long long pmt_counter[PMT_MAX_ADDED_CORE_COUNTERS];
} *core_even, *core_odd;
struct pkg_data {
int base_cpu;
unsigned long long pc2;
unsigned long long pc3;
unsigned long long pc6;
unsigned long long pc7;
unsigned long long pc8;
unsigned long long pc9;
unsigned long long pc10;
long long cpu_lpi;
long long sys_lpi;
unsigned long long pkg_wtd_core_c0;
unsigned long long pkg_any_core_c0;
unsigned long long pkg_any_gfxe_c0;
unsigned long long pkg_both_core_gfxe_c0;
long long gfx_rc6_ms;
unsigned int gfx_mhz;
unsigned int gfx_act_mhz;
long long sam_mc6_ms;
unsigned int sam_mhz;
unsigned int sam_act_mhz;
unsigned int package_id;
struct rapl_counter energy_pkg; /* MSR_PKG_ENERGY_STATUS */
struct rapl_counter energy_dram; /* MSR_DRAM_ENERGY_STATUS */
struct rapl_counter energy_cores; /* MSR_PP0_ENERGY_STATUS */
struct rapl_counter energy_gfx; /* MSR_PP1_ENERGY_STATUS */
struct rapl_counter rapl_pkg_perf_status; /* MSR_PKG_PERF_STATUS */
struct rapl_counter rapl_dram_perf_status; /* MSR_DRAM_PERF_STATUS */
unsigned int pkg_temp_c;
unsigned int uncore_mhz;
unsigned long long die_c6;
unsigned long long counter[MAX_ADDED_PACKAGE_COUNTERS];
unsigned long long perf_counter[MAX_ADDED_PACKAGE_COUNTERS];
unsigned long long pmt_counter[PMT_MAX_ADDED_PACKAGE_COUNTERS];
} *package_even, *package_odd;
#define ODD_COUNTERS thread_odd, core_odd, package_odd
#define EVEN_COUNTERS thread_even, core_even, package_even
#define GET_THREAD(thread_base, thread_no, core_no, node_no, pkg_no) \
((thread_base) + \
((pkg_no) * \
topo.nodes_per_pkg * topo.cores_per_node * topo.threads_per_core) + \
((node_no) * topo.cores_per_node * topo.threads_per_core) + \
((core_no) * topo.threads_per_core) + \
(thread_no))
#define GET_CORE(core_base, core_no, node_no, pkg_no) \
((core_base) + \
((pkg_no) * topo.nodes_per_pkg * topo.cores_per_node) + \
((node_no) * topo.cores_per_node) + \
(core_no))
/*
* The accumulated sum of MSR is defined as a monotonic
* increasing MSR, it will be accumulated periodically,
* despite its register's bit width.
*/
enum {
IDX_PKG_ENERGY,
IDX_DRAM_ENERGY,
IDX_PP0_ENERGY,
IDX_PP1_ENERGY,
IDX_PKG_PERF,
IDX_DRAM_PERF,
IDX_PSYS_ENERGY,
IDX_COUNT,
};
int get_msr_sum(int cpu, off_t offset, unsigned long long *msr);
struct msr_sum_array {
/* get_msr_sum() = sum + (get_msr() - last) */
struct {
/*The accumulated MSR value is updated by the timer */
unsigned long long sum;
/*The MSR footprint recorded in last timer */
unsigned long long last;
} entries[IDX_COUNT];
};
/* The percpu MSR sum array.*/
struct msr_sum_array *per_cpu_msr_sum;
off_t idx_to_offset(int idx)
{
off_t offset;
switch (idx) {
case IDX_PKG_ENERGY:
if (platform->rapl_msrs & RAPL_AMD_F17H)
offset = MSR_PKG_ENERGY_STAT;
else
offset = MSR_PKG_ENERGY_STATUS;
break ;
case IDX_DRAM_ENERGY:
offset = MSR_DRAM_ENERGY_STATUS;
break ;
case IDX_PP0_ENERGY:
offset = MSR_PP0_ENERGY_STATUS;
break ;
case IDX_PP1_ENERGY:
offset = MSR_PP1_ENERGY_STATUS;
break ;
case IDX_PKG_PERF:
offset = MSR_PKG_PERF_STATUS;
break ;
case IDX_DRAM_PERF:
offset = MSR_DRAM_PERF_STATUS;
break ;
case IDX_PSYS_ENERGY:
offset = MSR_PLATFORM_ENERGY_STATUS;
break ;
default :
offset = -1;
}
return offset;
}
int offset_to_idx(off_t offset)
{
int idx;
switch (offset) {
case MSR_PKG_ENERGY_STATUS:
case MSR_PKG_ENERGY_STAT:
idx = IDX_PKG_ENERGY;
break ;
case MSR_DRAM_ENERGY_STATUS:
idx = IDX_DRAM_ENERGY;
break ;
case MSR_PP0_ENERGY_STATUS:
idx = IDX_PP0_ENERGY;
break ;
case MSR_PP1_ENERGY_STATUS:
idx = IDX_PP1_ENERGY;
break ;
case MSR_PKG_PERF_STATUS:
idx = IDX_PKG_PERF;
break ;
case MSR_DRAM_PERF_STATUS:
idx = IDX_DRAM_PERF;
break ;
case MSR_PLATFORM_ENERGY_STATUS:
idx = IDX_PSYS_ENERGY;
break ;
default :
idx = -1;
}
return idx;
}
int idx_valid(int idx)
{
switch (idx) {
case IDX_PKG_ENERGY:
return platform->rapl_msrs & (RAPL_PKG | RAPL_AMD_F17H);
case IDX_DRAM_ENERGY:
return platform->rapl_msrs & RAPL_DRAM;
case IDX_PP0_ENERGY:
return platform->rapl_msrs & RAPL_CORE_ENERGY_STATUS;
case IDX_PP1_ENERGY:
return platform->rapl_msrs & RAPL_GFX;
case IDX_PKG_PERF:
return platform->rapl_msrs & RAPL_PKG_PERF_STATUS;
case IDX_DRAM_PERF:
return platform->rapl_msrs & RAPL_DRAM_PERF_STATUS;
case IDX_PSYS_ENERGY:
return platform->rapl_msrs & RAPL_PSYS;
default :
return 0;
}
}
struct sys_counters {
/* MSR added counters */
unsigned int added_thread_counters;
unsigned int added_core_counters;
unsigned int added_package_counters;
struct msr_counter *tp;
struct msr_counter *cp;
struct msr_counter *pp;
/* perf added counters */
unsigned int added_thread_perf_counters;
unsigned int added_core_perf_counters;
unsigned int added_package_perf_counters;
struct perf_counter_info *perf_tp;
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5 C=94 H=99 G=96
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland