diff options
Diffstat (limited to 'tools/power/x86/turbostat/turbostat.c')
| -rw-r--r-- | tools/power/x86/turbostat/turbostat.c | 425 | 
1 files changed, 298 insertions, 127 deletions
| diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 089220aaa5c9..58a487c225a7 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -31,6 +31,9 @@  )  // 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 @@ -89,6 +92,9 @@  #define PERF_DEV_NAME_BYTES 32  #define PERF_EVT_NAME_BYTES 32 +#define INTEL_ECORE_TYPE	0x20 +#define INTEL_PCORE_TYPE	0x40 +  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 }; @@ -194,6 +200,8 @@ struct msr_counter bic[] = {  	{ 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 },  };  #define MAX_BIC (sizeof(bic) / sizeof(struct msr_counter)) @@ -256,6 +264,8 @@ struct msr_counter bic[] = {  #define	BIC_SAMMHz		(1ULL << 56)  #define	BIC_SAMACTMHz		(1ULL << 57)  #define	BIC_Diec6		(1ULL << 58) +#define	BIC_SysWatt		(1ULL << 59) +#define	BIC_Sys_J		(1ULL << 60)  #define BIC_TOPOLOGY (BIC_Package | BIC_Node | BIC_CoreCnt | BIC_PkgCnt | BIC_Core | BIC_CPU | BIC_Die )  #define BIC_THERMAL_PWR ( BIC_CoreTmp | BIC_PkgTmp | BIC_PkgWatt | BIC_CorWatt | BIC_GFXWatt | BIC_RAMWatt | BIC_PKG__ | BIC_RAM__) @@ -263,7 +273,7 @@ struct msr_counter bic[] = {  #define BIC_IDLE (BIC_sysfs | BIC_CPU_c1 | BIC_CPU_c3 | BIC_CPU_c6 | BIC_CPU_c7 | BIC_GFX_rc6 | BIC_Pkgpc2 | BIC_Pkgpc3 | BIC_Pkgpc6 | BIC_Pkgpc7 | BIC_Pkgpc8 | BIC_Pkgpc9 | BIC_Pkgpc10 | BIC_CPU_LPI | BIC_SYS_LPI | BIC_Mod_c6 | BIC_Totl_c0 | BIC_Any_c0 | BIC_GFX_c0 | BIC_CPUGFX | BIC_SAM_mc6 | BIC_Diec6)  #define BIC_OTHER ( BIC_IRQ | BIC_SMI | BIC_ThreadC | BIC_CoreTmp | BIC_IPC) -#define BIC_DISABLED_BY_DEFAULT	(BIC_USEC | BIC_TOD | BIC_APIC | BIC_X2APIC) +#define BIC_DISABLED_BY_DEFAULT	(BIC_USEC | BIC_TOD | BIC_APIC | BIC_X2APIC | BIC_SysWatt | BIC_Sys_J)  unsigned long long bic_enabled = (0xFFFFFFFFFFFFFFFFULL & ~BIC_DISABLED_BY_DEFAULT);  unsigned long long bic_present = BIC_USEC | BIC_TOD | BIC_sysfs | BIC_APIC | BIC_X2APIC; @@ -370,7 +380,6 @@ enum gfx_sysfs_idx {  };  struct gfx_sysfs_info { -	const char *path;  	FILE *fp;  	unsigned int val;  	unsigned long long val_ull; @@ -502,12 +511,15 @@ enum rapl_msrs {  	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) @@ -708,7 +720,7 @@ static const struct platform_features skl_features = {  	.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_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_GFX | RAPL_PSYS,  	.enable_tsc_tweak = 1,  }; @@ -725,42 +737,44 @@ static const struct platform_features cnl_features = {  	.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_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 = 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 | PC8 | 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, -	.enable_tsc_tweak = 1, +	.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,  }; -static const struct platform_features arl_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 | 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, -	.enable_tsc_tweak = 1, +/* 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 = { @@ -790,7 +804,7 @@ static const struct platform_features icx_features = {  	.has_irtl_msrs = 1,  	.has_cst_prewake_bit = 1,  	.trl_msrs = TRL_BASE | TRL_CORECOUNT, -	.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, +	.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_PSYS,  	.has_fixed_rapl_unit = 1,  }; @@ -806,7 +820,7 @@ static const struct platform_features spr_features = {  	.has_irtl_msrs = 1,  	.has_cst_prewake_bit = 1,  	.trl_msrs = TRL_BASE | TRL_CORECOUNT, -	.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, +	.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_PSYS,  };  static const struct platform_features srf_features = { @@ -822,7 +836,7 @@ static const struct platform_features srf_features = {  	.has_irtl_msrs = 1,  	.has_cst_prewake_bit = 1,  	.trl_msrs = TRL_BASE | TRL_CORECOUNT, -	.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, +	.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_PSYS,  };  static const struct platform_features grr_features = { @@ -838,7 +852,7 @@ static const struct platform_features grr_features = {  	.has_irtl_msrs = 1,  	.has_cst_prewake_bit = 1,  	.trl_msrs = TRL_BASE | TRL_CORECOUNT, -	.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, +	.rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_PSYS,  };  static const struct platform_features slv_features = { @@ -997,18 +1011,19 @@ static const struct platform_data turbostat_pdata[] = {  	{ INTEL_SAPPHIRERAPIDS_X, &spr_features },  	{ INTEL_EMERALDRAPIDS_X, &spr_features },  	{ INTEL_GRANITERAPIDS_X, &spr_features }, +	{ INTEL_GRANITERAPIDS_D, &spr_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_METEORLAKE, &cnl_features }, -	{ INTEL_METEORLAKE_L, &cnl_features }, -	{ INTEL_ARROWLAKE_H, &arl_features }, -	{ INTEL_ARROWLAKE_U, &arl_features }, -	{ INTEL_ARROWLAKE, &arl_features }, -	{ INTEL_LUNARLAKE_M, &arl_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_ATOM_SILVERMONT, &slv_features },  	{ INTEL_ATOM_SILVERMONT_D, &slvd_features },  	{ INTEL_ATOM_AIRMONT, &amt_features }, @@ -1100,6 +1115,7 @@ enum rapl_rci_index {  	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,  }; @@ -1126,6 +1142,7 @@ struct rapl_counter_info_t {  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 { @@ -1247,6 +1264,19 @@ static const struct rapl_counter_arch_info rapl_counter_arch_infos[] = {  	 .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_energy_units, +	 .rci_index = RAPL_RCI_INDEX_ENERGY_PLATFORM, +	 .bic = BIC_SysWatt | BIC_Sys_J, +	 .compat_scale = 1.0, +	 .flags = RAPL_COUNTER_FLAG_PLATFORM_COUNTER | RAPL_COUNTER_FLAG_USE_MSR_SUM, +	  },  };  struct rapl_counter { @@ -1674,6 +1704,7 @@ enum {  	IDX_PP1_ENERGY,  	IDX_PKG_PERF,  	IDX_DRAM_PERF, +	IDX_PSYS_ENERGY,  	IDX_COUNT,  }; @@ -1718,6 +1749,9 @@ off_t idx_to_offset(int idx)  	case IDX_DRAM_PERF:  		offset = MSR_DRAM_PERF_STATUS;  		break; +	case IDX_PSYS_ENERGY: +		offset = MSR_PLATFORM_ENERGY_STATUS; +		break;  	default:  		offset = -1;  	} @@ -1748,6 +1782,9 @@ int offset_to_idx(off_t offset)  	case MSR_DRAM_PERF_STATUS:  		idx = IDX_DRAM_PERF;  		break; +	case MSR_PLATFORM_ENERGY_STATUS: +		idx = IDX_PSYS_ENERGY; +		break;  	default:  		idx = -1;  	} @@ -1769,6 +1806,8 @@ int idx_valid(int idx)  		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;  	} @@ -1840,6 +1879,10 @@ struct system_summary {  	struct pkg_data packages;  } average; +struct platform_counters { +	struct rapl_counter energy_psys;	/* MSR_PLATFORM_ENERGY_STATUS */ +} platform_counters_odd, platform_counters_even; +  struct cpu_topology {  	int physical_package_id;  	int die_id; @@ -1848,6 +1891,7 @@ struct cpu_topology {  	int logical_node_id;	/* 0-based count within the package */  	int physical_core_id;  	int thread_id; +	int type;  	cpu_set_t *put_ids;	/* Processing Unit/Thread IDs */  } *cpus; @@ -2291,7 +2335,7 @@ void print_header(char *delim)  			break;  		case PMT_TYPE_XTAL_TIME: -			outp += sprintf(outp, "%s%s", delim, ppmt->name); +			outp += sprintf(outp, "%s%s", (printed++ ? delim : ""), ppmt->name);  			break;  		} @@ -2365,7 +2409,7 @@ void print_header(char *delim)  			break;  		case PMT_TYPE_XTAL_TIME: -			outp += sprintf(outp, "%s%s", delim, ppmt->name); +			outp += sprintf(outp, "%s%s", (printed++ ? delim : ""), ppmt->name);  			break;  		} @@ -2496,13 +2540,18 @@ void print_header(char *delim)  			break;  		case PMT_TYPE_XTAL_TIME: -			outp += sprintf(outp, "%s%s", delim, ppmt->name); +			outp += sprintf(outp, "%s%s", (printed++ ? delim : ""), ppmt->name);  			break;  		}  		ppmt = ppmt->next;  	} +	if (DO_BIC(BIC_SysWatt)) +		outp += sprintf(outp, "%sSysWatt", (printed++ ? delim : "")); +	if (DO_BIC(BIC_Sys_J)) +		outp += sprintf(outp, "%sSys_J", (printed++ ? delim : "")); +  	outp += sprintf(outp, "\n");  } @@ -2510,6 +2559,7 @@ int dump_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p  {  	int i;  	struct msr_counter *mp; +	struct platform_counters *pplat_cnt = p == package_odd ? &platform_counters_odd : &platform_counters_even;  	outp += sprintf(outp, "t %p, c %p, p %p\n", t, c, p); @@ -2581,6 +2631,7 @@ int dump_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p  		outp += sprintf(outp, "Joules COR: %0llX\n", p->energy_cores.raw_value);  		outp += sprintf(outp, "Joules GFX: %0llX\n", p->energy_gfx.raw_value);  		outp += sprintf(outp, "Joules RAM: %0llX\n", p->energy_dram.raw_value); +		outp += sprintf(outp, "Joules PSYS: %0llX\n", pplat_cnt->energy_psys.raw_value);  		outp += sprintf(outp, "Throttle PKG: %0llX\n", p->rapl_pkg_perf_status.raw_value);  		outp += sprintf(outp, "Throttle RAM: %0llX\n", p->rapl_dram_perf_status.raw_value);  		outp += sprintf(outp, "PTM: %dC\n", p->pkg_temp_c); @@ -2619,6 +2670,9 @@ double rapl_counter_get_value(const struct rapl_counter *c, enum rapl_unit desir   */  int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)  { +	static int count; + +	struct platform_counters *pplat_cnt = NULL;  	double interval_float, tsc;  	char *fmt8;  	int i; @@ -2628,6 +2682,11 @@ int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data  	char *delim = "\t";  	int printed = 0; +	if (t == &average.threads) { +		pplat_cnt = count & 1 ? &platform_counters_odd : &platform_counters_even; +		++count; +	} +  	/* if showing only 1st thread in core and this isn't one, bail out */  	if (show_core_only && !is_cpu_first_thread_in_core(t, c, p))  		return 0; @@ -2788,6 +2847,8 @@ int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data  	}  	for (i = 0, ppmt = sys.pmt_tp; ppmt; i++, ppmt = ppmt->next) { +		const unsigned long value_raw = t->pmt_counter[i]; +		const double value_converted = 100.0 * value_raw / crystal_hz / interval_float;  		switch (ppmt->type) {  		case PMT_TYPE_RAW:  			if (pmt_counter_get_width(ppmt) <= 32) @@ -2799,9 +2860,6 @@ int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data  			break;  		case PMT_TYPE_XTAL_TIME: -			const unsigned long value_raw = t->pmt_counter[i]; -			const double value_converted = 100.0 * value_raw / crystal_hz / interval_float; -  			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), value_converted);  			break;  		} @@ -2869,6 +2927,8 @@ int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data  	}  	for (i = 0, ppmt = sys.pmt_cp; ppmt; i++, ppmt = ppmt->next) { +		const unsigned long value_raw = c->pmt_counter[i]; +		const double value_converted = 100.0 * value_raw / crystal_hz / interval_float;  		switch (ppmt->type) {  		case PMT_TYPE_RAW:  			if (pmt_counter_get_width(ppmt) <= 32) @@ -2880,9 +2940,6 @@ int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data  			break;  		case PMT_TYPE_XTAL_TIME: -			const unsigned long value_raw = c->pmt_counter[i]; -			const double value_converted = 100.0 * value_raw / crystal_hz / interval_float; -  			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), value_converted);  			break;  		} @@ -3068,6 +3125,8 @@ int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data  	}  	for (i = 0, ppmt = sys.pmt_pp; ppmt; i++, ppmt = ppmt->next) { +		const unsigned long value_raw = p->pmt_counter[i]; +		const double value_converted = 100.0 * value_raw / crystal_hz / interval_float;  		switch (ppmt->type) {  		case PMT_TYPE_RAW:  			if (pmt_counter_get_width(ppmt) <= 32) @@ -3079,14 +3138,18 @@ int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data  			break;  		case PMT_TYPE_XTAL_TIME: -			const unsigned long value_raw = p->pmt_counter[i]; -			const double value_converted = 100.0 * value_raw / crystal_hz / interval_float; -  			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), value_converted);  			break;  		}  	} +	if (DO_BIC(BIC_SysWatt) && (t == &average.threads)) +		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), +				rapl_counter_get_value(&pplat_cnt->energy_psys, RAPL_UNIT_WATTS, interval_float)); +	if (DO_BIC(BIC_Sys_J) && (t == &average.threads)) +		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), +				rapl_counter_get_value(&pplat_cnt->energy_psys, RAPL_UNIT_JOULES, interval_float)); +  done:  	if (*(outp - 1) != '\n')  		outp += sprintf(outp, "\n"); @@ -3394,6 +3457,11 @@ int delta_cpu(struct thread_data *t, struct core_data *c,  	return retval;  } +void delta_platform(struct platform_counters *new, struct platform_counters *old) +{ +	old->energy_psys.raw_value = new->energy_psys.raw_value - old->energy_psys.raw_value; +} +  void rapl_counter_clear(struct rapl_counter *c)  {  	c->raw_value = 0; @@ -4123,6 +4191,9 @@ static size_t cstate_counter_info_count_perf(const struct cstate_counter_info_t  void write_rapl_counter(struct rapl_counter *rc, struct rapl_counter_info_t *rci, unsigned int idx)  { +	if (rci->source[idx] == COUNTER_SOURCE_NONE) +		return; +  	rc->raw_value = rci->data[idx];  	rc->unit = rci->unit[idx];  	rc->scale = rci->scale[idx]; @@ -4130,6 +4201,7 @@ void write_rapl_counter(struct rapl_counter *rc, struct rapl_counter_info_t *rci  int get_rapl_counters(int cpu, unsigned int domain, struct core_data *c, struct pkg_data *p)  { +	struct platform_counters *pplat_cnt = p == package_odd ? &platform_counters_odd : &platform_counters_even;  	unsigned long long perf_data[NUM_RAPL_COUNTERS + 1];  	struct rapl_counter_info_t *rci; @@ -4157,6 +4229,7 @@ int get_rapl_counters(int cpu, unsigned int domain, struct core_data *c, struct  	for (unsigned int i = 0, pi = 1; i < NUM_RAPL_COUNTERS; ++i) {  		switch (rci->source[i]) {  		case COUNTER_SOURCE_NONE: +			rci->data[i] = 0;  			break;  		case COUNTER_SOURCE_PERF: @@ -4195,7 +4268,7 @@ int get_rapl_counters(int cpu, unsigned int domain, struct core_data *c, struct  		}  	} -	BUILD_BUG_ON(NUM_RAPL_COUNTERS != 7); +	BUILD_BUG_ON(NUM_RAPL_COUNTERS != 8);  	write_rapl_counter(&p->energy_pkg, rci, RAPL_RCI_INDEX_ENERGY_PKG);  	write_rapl_counter(&p->energy_cores, rci, RAPL_RCI_INDEX_ENERGY_CORES);  	write_rapl_counter(&p->energy_dram, rci, RAPL_RCI_INDEX_DRAM); @@ -4203,6 +4276,7 @@ int get_rapl_counters(int cpu, unsigned int domain, struct core_data *c, struct  	write_rapl_counter(&p->rapl_pkg_perf_status, rci, RAPL_RCI_INDEX_PKG_PERF_STATUS);  	write_rapl_counter(&p->rapl_dram_perf_status, rci, RAPL_RCI_INDEX_DRAM_PERF_STATUS);  	write_rapl_counter(&c->core_energy, rci, RAPL_RCI_INDEX_CORE_ENERGY); +	write_rapl_counter(&pplat_cnt->energy_psys, rci, RAPL_RCI_INDEX_ENERGY_PLATFORM);  	return 0;  } @@ -5385,6 +5459,9 @@ static int parse_cpu_str(char *cpu_str, cpu_set_t *cpu_set, int cpu_set_size)  		if (*next == '-')	/* no negative cpu numbers */  			return 1; +		if (*next == '\0' || *next == '\n') +			break; +  		start = strtoul(next, &next, 10);  		if (start >= CPU_SUBSET_MAXCPUS) @@ -5656,6 +5733,32 @@ int init_thread_id(int cpu)  	return 0;  } +int set_my_cpu_type(void) +{ +	unsigned int eax, ebx, ecx, edx; +	unsigned int max_level; + +	__cpuid(0, max_level, ebx, ecx, edx); + +	if (max_level < CPUID_LEAF_MODEL_ID) +		return 0; + +	__cpuid(CPUID_LEAF_MODEL_ID, eax, ebx, ecx, edx); + +	return (eax >> CPUID_LEAF_MODEL_ID_CORE_TYPE_SHIFT); +} + +int set_cpu_hybrid_type(int cpu) +{ +	if (cpu_migrate(cpu)) +		return -1; + +	int type = set_my_cpu_type(); + +	cpus[cpu].type = type; +	return 0; +} +  /*   * snapshot_proc_interrupts()   * @@ -5728,28 +5831,21 @@ int snapshot_proc_interrupts(void)   */  int snapshot_graphics(int idx)  { -	FILE *fp;  	int retval; +	rewind(gfx_info[idx].fp); +  	switch (idx) {  	case GFX_rc6:  	case SAM_mc6: -		fp = fopen_or_die(gfx_info[idx].path, "r"); -		retval = fscanf(fp, "%lld", &gfx_info[idx].val_ull); +		retval = fscanf(gfx_info[idx].fp, "%lld", &gfx_info[idx].val_ull);  		if (retval != 1)  			err(1, "rc6"); -		fclose(fp);  		return 0;  	case GFX_MHz:  	case GFX_ACTMHz:  	case SAM_MHz:  	case SAM_ACTMHz: -		if (gfx_info[idx].fp == NULL) { -			gfx_info[idx].fp = fopen_or_die(gfx_info[idx].path, "r"); -		} else { -			rewind(gfx_info[idx].fp); -			fflush(gfx_info[idx].fp); -		}  		retval = fscanf(gfx_info[idx].fp, "%d", &gfx_info[idx].val);  		if (retval != 1)  			err(1, "MHz"); @@ -6116,6 +6212,7 @@ restart:  			re_initialize();  			goto restart;  		} +		delta_platform(&platform_counters_odd, &platform_counters_even);  		compute_average(EVEN_COUNTERS);  		format_all_counters(EVEN_COUNTERS);  		flush_output_stdout(); @@ -6139,6 +6236,7 @@ restart:  			re_initialize();  			goto restart;  		} +		delta_platform(&platform_counters_even, &platform_counters_odd);  		compute_average(ODD_COUNTERS);  		format_all_counters(ODD_COUNTERS);  		flush_output_stdout(); @@ -6442,14 +6540,25 @@ static void probe_intel_uncore_frequency(void)  		probe_intel_uncore_frequency_legacy();  } +static void set_graphics_fp(char *path, int idx) +{ +	if (!access(path, R_OK)) +		gfx_info[idx].fp = fopen_or_die(path, "r"); +} + +/* Enlarge this if there are /sys/class/drm/card2 ... */ +#define GFX_MAX_CARDS	2 +  static void probe_graphics(void)  { +	char path[PATH_MAX]; +	int i; +  	/* Xe graphics sysfs knobs */  	if (!access("/sys/class/drm/card0/device/tile0/gt0/gtidle/idle_residency_ms", R_OK)) {  		FILE *fp;  		char buf[8];  		bool gt0_is_gt; -		int idx;  		fp = fopen("/sys/class/drm/card0/device/tile0/gt0/gtidle/name", "r");  		if (!fp) @@ -6468,81 +6577,76 @@ static void probe_graphics(void)  		else  			goto next; -		idx = gt0_is_gt ? GFX_rc6 : SAM_mc6; -		gfx_info[idx].path = "/sys/class/drm/card0/device/tile0/gt0/gtidle/idle_residency_ms"; +		set_graphics_fp("/sys/class/drm/card0/device/tile0/gt0/gtidle/idle_residency_ms", gt0_is_gt ? GFX_rc6 : SAM_mc6); -		idx = gt0_is_gt ? GFX_MHz : SAM_MHz; -		if (!access("/sys/class/drm/card0/device/tile0/gt0/freq0/cur_freq", R_OK)) -			gfx_info[idx].path = "/sys/class/drm/card0/device/tile0/gt0/freq0/cur_freq"; +		set_graphics_fp("/sys/class/drm/card0/device/tile0/gt0/freq0/cur_freq", gt0_is_gt ? GFX_MHz : SAM_MHz); -		idx = gt0_is_gt ? GFX_ACTMHz : SAM_ACTMHz; -		if (!access("/sys/class/drm/card0/device/tile0/gt0/freq0/act_freq", R_OK)) -			gfx_info[idx].path = "/sys/class/drm/card0/device/tile0/gt0/freq0/act_freq"; +		set_graphics_fp("/sys/class/drm/card0/device/tile0/gt0/freq0/act_freq", gt0_is_gt ? GFX_ACTMHz : SAM_ACTMHz); -		idx = gt0_is_gt ? SAM_mc6 : GFX_rc6; -		if (!access("/sys/class/drm/card0/device/tile0/gt1/gtidle/idle_residency_ms", R_OK)) -			gfx_info[idx].path = "/sys/class/drm/card0/device/tile0/gt1/gtidle/idle_residency_ms"; +		set_graphics_fp("/sys/class/drm/card0/device/tile0/gt1/gtidle/idle_residency_ms", gt0_is_gt ? SAM_mc6 : GFX_rc6); -		idx = gt0_is_gt ? SAM_MHz : GFX_MHz; -		if (!access("/sys/class/drm/card0/device/tile0/gt1/freq0/cur_freq", R_OK)) -			gfx_info[idx].path = "/sys/class/drm/card0/device/tile0/gt1/freq0/cur_freq"; +		set_graphics_fp("/sys/class/drm/card0/device/tile0/gt1/freq0/cur_freq", gt0_is_gt ? SAM_MHz : GFX_MHz); -		idx = gt0_is_gt ? SAM_ACTMHz : GFX_ACTMHz; -		if (!access("/sys/class/drm/card0/device/tile0/gt1/freq0/act_freq", R_OK)) -			gfx_info[idx].path = "/sys/class/drm/card0/device/tile0/gt1/freq0/act_freq"; +		set_graphics_fp("/sys/class/drm/card0/device/tile0/gt1/freq0/act_freq", gt0_is_gt ? SAM_ACTMHz : GFX_ACTMHz);  		goto end;  	}  next:  	/* New i915 graphics sysfs knobs */ -	if (!access("/sys/class/drm/card0/gt/gt0/rc6_residency_ms", R_OK)) { -		gfx_info[GFX_rc6].path = "/sys/class/drm/card0/gt/gt0/rc6_residency_ms"; +	for (i = 0; i < GFX_MAX_CARDS; i++) { +		snprintf(path, PATH_MAX, "/sys/class/drm/card%d/gt/gt0/rc6_residency_ms", i); +		if (!access(path, R_OK)) +			break; +	} -		if (!access("/sys/class/drm/card0/gt/gt0/rps_cur_freq_mhz", R_OK)) -			gfx_info[GFX_MHz].path = "/sys/class/drm/card0/gt/gt0/rps_cur_freq_mhz"; +	if (i == GFX_MAX_CARDS) +		goto legacy_i915; -		if (!access("/sys/class/drm/card0/gt/gt0/rps_act_freq_mhz", R_OK)) -			gfx_info[GFX_ACTMHz].path = "/sys/class/drm/card0/gt/gt0/rps_act_freq_mhz"; +	snprintf(path, PATH_MAX, "/sys/class/drm/card%d/gt/gt0/rc6_residency_ms", i); +	set_graphics_fp(path, GFX_rc6); -		if (!access("/sys/class/drm/card0/gt/gt1/rc6_residency_ms", R_OK)) -			gfx_info[SAM_mc6].path = "/sys/class/drm/card0/gt/gt1/rc6_residency_ms"; +	snprintf(path, PATH_MAX, "/sys/class/drm/card%d/gt/gt0/rps_cur_freq_mhz", i); +	set_graphics_fp(path, GFX_MHz); -		if (!access("/sys/class/drm/card0/gt/gt1/rps_cur_freq_mhz", R_OK)) -			gfx_info[SAM_MHz].path = "/sys/class/drm/card0/gt/gt1/rps_cur_freq_mhz"; +	snprintf(path, PATH_MAX, "/sys/class/drm/card%d/gt/gt0/rps_act_freq_mhz", i); +	set_graphics_fp(path, GFX_ACTMHz); -		if (!access("/sys/class/drm/card0/gt/gt1/rps_act_freq_mhz", R_OK)) -			gfx_info[SAM_ACTMHz].path = "/sys/class/drm/card0/gt/gt1/rps_act_freq_mhz"; +	snprintf(path, PATH_MAX, "/sys/class/drm/card%d/gt/gt1/rc6_residency_ms", i); +	set_graphics_fp(path, SAM_mc6); -		goto end; -	} +	snprintf(path, PATH_MAX, "/sys/class/drm/card%d/gt/gt1/rps_cur_freq_mhz", i); +	set_graphics_fp(path, SAM_MHz); + +	snprintf(path, PATH_MAX, "/sys/class/drm/card%d/gt/gt1/rps_act_freq_mhz", i); +	set_graphics_fp(path, SAM_ACTMHz); +	goto end; + +legacy_i915:  	/* Fall back to traditional i915 graphics sysfs knobs */ -	if (!access("/sys/class/drm/card0/power/rc6_residency_ms", R_OK)) -		gfx_info[GFX_rc6].path = "/sys/class/drm/card0/power/rc6_residency_ms"; +	set_graphics_fp("/sys/class/drm/card0/power/rc6_residency_ms", GFX_rc6); -	if (!access("/sys/class/drm/card0/gt_cur_freq_mhz", R_OK)) -		gfx_info[GFX_MHz].path = "/sys/class/drm/card0/gt_cur_freq_mhz"; -	else if (!access("/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz", R_OK)) -		gfx_info[GFX_MHz].path = "/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz"; +	set_graphics_fp("/sys/class/drm/card0/gt_cur_freq_mhz", GFX_MHz); +	if (!gfx_info[GFX_MHz].fp) +		set_graphics_fp("/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz", GFX_MHz); -	if (!access("/sys/class/drm/card0/gt_act_freq_mhz", R_OK)) -		gfx_info[GFX_ACTMHz].path = "/sys/class/drm/card0/gt_act_freq_mhz"; -	else if (!access("/sys/class/graphics/fb0/device/drm/card0/gt_act_freq_mhz", R_OK)) -		gfx_info[GFX_ACTMHz].path = "/sys/class/graphics/fb0/device/drm/card0/gt_act_freq_mhz"; +	set_graphics_fp("/sys/class/drm/card0/gt_act_freq_mhz", GFX_ACTMHz); +	if (!gfx_info[GFX_ACTMHz].fp) +		set_graphics_fp("/sys/class/graphics/fb0/device/drm/card0/gt_act_freq_mhz", GFX_ACTMHz);  end: -	if (gfx_info[GFX_rc6].path) +	if (gfx_info[GFX_rc6].fp)  		BIC_PRESENT(BIC_GFX_rc6); -	if (gfx_info[GFX_MHz].path) +	if (gfx_info[GFX_MHz].fp)  		BIC_PRESENT(BIC_GFXMHz); -	if (gfx_info[GFX_ACTMHz].path) +	if (gfx_info[GFX_ACTMHz].fp)  		BIC_PRESENT(BIC_GFXACTMHz); -	if (gfx_info[SAM_mc6].path) +	if (gfx_info[SAM_mc6].fp)  		BIC_PRESENT(BIC_SAM_mc6); -	if (gfx_info[SAM_MHz].path) +	if (gfx_info[SAM_MHz].fp)  		BIC_PRESENT(BIC_SAMMHz); -	if (gfx_info[SAM_ACTMHz].path) +	if (gfx_info[SAM_ACTMHz].fp)  		BIC_PRESENT(BIC_SAMACTMHz);  } @@ -6911,8 +7015,8 @@ void rapl_probe_intel(void)  	unsigned long long msr;  	unsigned int time_unit;  	double tdp; -	const unsigned long long bic_watt_bits = BIC_PkgWatt | BIC_CorWatt | BIC_RAMWatt | BIC_GFXWatt; -	const unsigned long long bic_joules_bits = BIC_Pkg_J | BIC_Cor_J | BIC_RAM_J | BIC_GFX_J; +	const unsigned long long bic_watt_bits = BIC_SysWatt | BIC_PkgWatt | BIC_CorWatt | BIC_RAMWatt | BIC_GFXWatt; +	const unsigned long long bic_joules_bits = BIC_Sys_J | BIC_Pkg_J | BIC_Cor_J | BIC_RAM_J | BIC_GFX_J;  	if (rapl_joules)  		bic_enabled &= ~bic_watt_bits; @@ -7572,6 +7676,9 @@ void rapl_perf_init(void)  			domain_visited[next_domain] = 1; +			if ((cai->flags & RAPL_COUNTER_FLAG_PLATFORM_COUNTER) && (cpu != base_cpu)) +				continue; +  			struct rapl_counter_info_t *rci = &rapl_counter_info_perdomain[next_domain];  			/* Check if the counter is enabled and accessible */ @@ -8196,7 +8303,7 @@ void topology_probe(bool startup)  	set_max_cpu_num();  	topo.num_cpus = 0;  	for_all_proc_cpus(count_cpus); -	if (!summary_only && topo.num_cpus > 1) +	if (!summary_only)  		BIC_PRESENT(BIC_CPU);  	if (debug > 1) @@ -8284,6 +8391,8 @@ void topology_probe(bool startup)  	for_all_proc_cpus(init_thread_id); +	for_all_proc_cpus(set_cpu_hybrid_type); +  	/*  	 * For online cpus  	 * find max_core_id, max_package_id @@ -8332,7 +8441,7 @@ void topology_probe(bool startup)  	topo.cores_per_node = max_core_id + 1;  	if (debug > 1)  		fprintf(outf, "max_core_id %d, sizing for %d cores per package\n", max_core_id, topo.cores_per_node); -	if (!summary_only && topo.cores_per_node > 1) +	if (!summary_only)  		BIC_PRESENT(BIC_Core);  	topo.num_die = topo.max_die_id + 1; @@ -8548,6 +8657,35 @@ void check_perf_access(void)  		bic_enabled &= ~BIC_IPC;  } +bool perf_has_hybrid_devices(void) +{ +	/* +	 *  0: unknown +	 *  1: has separate perf device for p and e core +	 * -1: doesn't have separate perf device for p and e core +	 */ +	static int cached; + +	if (cached > 0) +		return true; + +	if (cached < 0) +		return false; + +	if (access("/sys/bus/event_source/devices/cpu_core", F_OK)) { +		cached = -1; +		return false; +	} + +	if (access("/sys/bus/event_source/devices/cpu_atom", F_OK)) { +		cached = -1; +		return false; +	} + +	cached = 1; +	return true; +} +  int added_perf_counters_init_(struct perf_counter_info *pinfo)  {  	size_t num_domains = 0; @@ -8604,29 +8742,56 @@ int added_perf_counters_init_(struct perf_counter_info *pinfo)  			if (domain_visited[next_domain])  				continue; -			perf_type = read_perf_type(pinfo->device); +			/* +			 * Intel hybrid platforms expose different perf devices for P and E cores. +			 * Instead of one, "/sys/bus/event_source/devices/cpu" device, there are +			 * "/sys/bus/event_source/devices/{cpu_core,cpu_atom}". +			 * +			 * This makes it more complicated to the user, because most of the counters +			 * are available on both and have to be handled manually, otherwise. +			 * +			 * Code below, allow user to use the old "cpu" name, which is translated accordingly. +			 */ +			const char *perf_device = pinfo->device; + +			if (strcmp(perf_device, "cpu") == 0 && perf_has_hybrid_devices()) { +				switch (cpus[cpu].type) { +				case INTEL_PCORE_TYPE: +					perf_device = "cpu_core"; +					break; + +				case INTEL_ECORE_TYPE: +					perf_device = "cpu_atom"; +					break; + +				default: /* Don't change, we will probably fail and report a problem soon. */ +					break; +				} +			} + +			perf_type = read_perf_type(perf_device);  			if (perf_type == (unsigned int)-1) {  				warnx("%s: perf/%s/%s: failed to read %s", -				      __func__, pinfo->device, pinfo->event, "type"); +				      __func__, perf_device, pinfo->event, "type");  				continue;  			} -			perf_config = read_perf_config(pinfo->device, pinfo->event); +			perf_config = read_perf_config(perf_device, pinfo->event);  			if (perf_config == (unsigned int)-1) {  				warnx("%s: perf/%s/%s: failed to read %s", -				      __func__, pinfo->device, pinfo->event, "config"); +				      __func__, perf_device, pinfo->event, "config");  				continue;  			}  			/* Scale is not required, some counters just don't have it. */ -			perf_scale = read_perf_scale(pinfo->device, pinfo->event); +			perf_scale = read_perf_scale(perf_device, pinfo->event);  			if (perf_scale == 0.0)  				perf_scale = 1.0;  			fd_perf = open_perf_counter(cpu, perf_type, perf_config, -1, 0);  			if (fd_perf == -1) {  				warnx("%s: perf/%s/%s: failed to open counter on cpu%d", -				      __func__, pinfo->device, pinfo->event, cpu); +				      __func__, perf_device, pinfo->event, cpu);  				continue;  			} @@ -8636,7 +8801,7 @@ int added_perf_counters_init_(struct perf_counter_info *pinfo)  			if (debug)  				fprintf(stderr, "Add perf/%s/%s cpu%d: %d\n", -					pinfo->device, pinfo->event, cpu, pinfo->fd_perf_per_domain[next_domain]); +					perf_device, pinfo->event, cpu, pinfo->fd_perf_per_domain[next_domain]);  		}  		pinfo = pinfo->next; @@ -9071,7 +9236,7 @@ int get_and_dump_counters(void)  void print_version()  { -	fprintf(outf, "turbostat version 2024.07.26 - Len Brown <lenb@kernel.org>\n"); +	fprintf(outf, "turbostat version 2024.11.30 - Len Brown <lenb@kernel.org>\n");  }  #define COMMAND_LINE_SIZE 2048 @@ -9781,7 +9946,7 @@ void cmdline(int argc, char **argv)  	 * Parse some options early, because they may make other options invalid,  	 * like adding the MSR counter with --add and at the same time using --no-msr.  	 */ -	while ((opt = getopt_long_only(argc, argv, "MPn:", long_options, &option_index)) != -1) { +	while ((opt = getopt_long_only(argc, argv, "+MPn:", long_options, &option_index)) != -1) {  		switch (opt) {  		case 'M':  			no_msr = 1; @@ -9805,6 +9970,12 @@ void cmdline(int argc, char **argv)  			break;  		case 'D':  			dump_only++; +			/* +			 * Force the no_perf early to prevent using it as a source. +			 * User asks for raw values, but perf returns them relative +			 * to the opening of the file descriptor. +			 */ +			no_perf = 1;  			break;  		case 'e':  			/* --enable specified counter */ | 
