Merge tag 'turbostat-v2025.12.02' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux

Pull turbostat updates from Len Brown:

 - Add LLC statistics columns:
	LLCkRPS = Last Level Cache Thousands of References Per Second
	LLC%hit = Last Level Cache Hit %

 - Recognize Wildcat Lake and Nova Lake platforms

 - Add MSR check for Android

 - Add APERF check for VMWARE

 - Add RAPL check for AWS

 - Minor fixes to turbostat (and x86_energy_perf_policy)

* tag 'turbostat-v2025.12.02' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux: (21 commits)
  tools/power turbostat: version 2025.12.02
  tools/power turbostat: Print wide names only for RAW 64-bit columns
  tools/power turbostat: Print percentages in 8-columns
  tools/power turbostat: Print "nan" for out of range percentages
  tools/power turbostat: Validate APERF access for VMWARE
  tools/power turbostat: Enhance perf probe
  tools/power turbostat: Validate RAPL MSRs for AWS Nitro Hypervisor
  tools/power x86_energy_perf_policy: Fix potential NULL pointer dereference
  tools/power x86_energy_perf_policy: Fix format string in error message
  tools/power x86_energy_perf_policy: Simplify Android MSR probe
  tools/power x86_energy_perf_policy: Add Android MSR device support
  tools/power turbostat: Add run-time MSR driver probe
  tools/power turbostat: Set per_cpu_msr_sum to NULL after free
  tools/power turbostat: Add LLC stats
  tools/power turbostat: Remove dead code
  tools/power turbostat: Refactor floating point printout code
  tools/power turbostat.8: Update example
  tools/power turbostat: Refactor added-counter value printing code
  tools/power turbostat: Refactor added column header printing
  tools/power turbostat: Add Wildcat Lake and Nova Lake support
  ...
This commit is contained in:
Linus Torvalds
2025-12-06 09:35:00 -08:00
3 changed files with 660 additions and 619 deletions

View File

@@ -101,7 +101,7 @@ The column name "all" can be used to enable all disabled-by-default built-in cou
.PP
\fB--show column\fP show only the specified built-in columns. May be invoked multiple times, or with a comma-separated list of column names.
.PP
\fB--show CATEGORY --hide CATEGORY\fP Show and hide also accept a single CATEGORY of columns: "all", "topology", "idle", "frequency", "power", "cpuidle", "hwidle", "swidle", "other". "idle" (enabled by default), includes "hwidle" and "pct_idle". "cpuidle" (default disabled) includes cpuidle software invocation counters. "swidle" includes "cpuidle" plus "pct_idle". "hwidle" includes only hardware based idle residency counters. Older versions of turbostat used the term "sysfs" for what is now "swidle".
\fB--show CATEGORY --hide CATEGORY\fP Show and hide also accept a comma-separated-list of CATEGORIES of columns: "all", "topology", "idle", "frequency", "power", "cpuidle", "hwidle", "swidle", "cache", "llc", "other". "idle" (enabled by default), includes "hwidle" and "pct_idle". "cpuidle" (default disabled) includes cpuidle software invocation counters. "swidle" includes "cpuidle" plus "pct_idle". "hwidle" includes only hardware based idle residency counters. Older versions of turbostat used the term "sysfs" for what is now "swidle".
.PP
\fB--Dump\fP displays the raw counter values.
.PP
@@ -159,6 +159,10 @@ The system configuration dump (if --quiet is not used) is followed by statistics
.PP
\fBSMI\fP The number of System Management Interrupts serviced CPU during the measurement interval. While this counter is actually per-CPU, SMI are triggered on all processors, so the number should be the same for all CPUs.
.PP
\fBLLCkRPS\fP Last Level Cache Thousands of References Per Second. For CPUs with an L3 LLC, this is the number of references that CPU made to the L3 (and the number of misses that CPU made to it's L2). For CPUs with an L2 LLC, this is the number of references to the L2 (and the number of misses to the CPU's L1). The system summary row shows the sum for all CPUs. In both cases, the value displayed is the actual value divided by 1000 in the interest of usually fitting into 8 columns.
.PP
\fBLLC%hit\fP Last Level Cache Hit Rate %. Hit Rate Percent = 100.0 * (References - Misses)/References. The system summary row shows the weighted average for all CPUs (100.0 * (Sum_References - Sum_Misses)/Sum_References).
.PP
\fBC1, C2, C3...\fP The number times Linux requested the C1, C2, C3 idle state during the measurement interval. The system summary line shows the sum for all CPUs. These are C-state names as exported in /sys/devices/system/cpu/cpu*/cpuidle/state*/name. While their names are generic, their attributes are processor specific. They the system description section of output shows what MWAIT sub-states they are mapped to on each system. These counters are in the "cpuidle" group, which is disabled, by default.
.PP
\fBC1+, C2+, C3+...\fP The idle governor idle state misprediction statistics. Inidcates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a deeper idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/below file. These counters are in the "cpuidle" group, which is disabled, by default.
@@ -410,25 +414,24 @@ CPU pCPU%c1 CPU%c1
.fi
.SH ADD PERF COUNTER EXAMPLE #2 (using virtual cpu device)
Here we run on hybrid, Raptor Lake platform.
We limit turbostat to show output for just cpu0 (pcore) and cpu12 (ecore).
Here we run on hybrid, Meteor Lake platform.
We limit turbostat to show output for just cpu0 (pcore) and cpu4 (ecore).
We add a counter showing number of L3 cache misses, using virtual "cpu" device,
labeling it with the column header, "VCMISS".
We add a counter showing number of L3 cache misses, using virtual "cpu_core" device,
labeling it with the column header, "PCMISS". This will fail on ecore cpu12.
labeling it with the column header, "PCMISS". This will fail on ecore cpu4.
We add a counter showing number of L3 cache misses, using virtual "cpu_atom" device,
labeling it with the column header, "ECMISS". This will fail on pcore cpu0.
We display it only once, after the conclusion of 0.1 second sleep.
.nf
sudo ./turbostat --quiet --cpu 0,12 --show CPU --add perf/cpu/cache-misses,cpu,delta,raw,VCMISS --add perf/cpu_core/cache-misses,cpu,delta,raw,PCMISS --add perf/cpu_atom/cache-misses,cpu,delta,raw,ECMISS sleep .1
sudo ./turbostat --quiet --cpu 0,4 --show CPU --add perf/cpu/cache-misses,cpu,delta,VCMISS --add perf/cpu_core/cache-misses,cpu,delta,PCMISS --add perf/cpu_atom/cache-misses,cpu,delta,ECMISS sleep 5
turbostat: added_perf_counters_init_: perf/cpu_atom/cache-misses: failed to open counter on cpu0
turbostat: added_perf_counters_init_: perf/cpu_core/cache-misses: failed to open counter on cpu12
0.104630 sec
CPU ECMISS PCMISS VCMISS
- 0x0000000000000000 0x0000000000000000 0x0000000000000000
0 0x0000000000000000 0x0000000000007951 0x0000000000007796
12 0x000000000001137a 0x0000000000000000 0x0000000000011392
turbostat: added_perf_counters_init_: perf/cpu_core/cache-misses: failed to open counter on cpu4
5.001207 sec
CPU ECMISS PCMISS VCMISS
- 41586506 46291219 87877749
4 83173012 0 83173040
0 0 92582439 92582458
.fi
.SH ADD PMT COUNTER EXAMPLE

File diff suppressed because it is too large Load Diff

View File

@@ -95,6 +95,8 @@ unsigned int bdx_highest_ratio;
#define PATH_TO_CPU "/sys/devices/system/cpu/"
#define SYSFS_PATH_MAX 255
static int use_android_msr_path;
/*
* maintain compatibility with original implementation, but don't document it:
*/
@@ -370,7 +372,7 @@ void validate_cpu_selected_set(void)
for (cpu = 0; cpu <= max_cpu_num; ++cpu) {
if (CPU_ISSET_S(cpu, cpu_setsize, cpu_selected_set))
if (!CPU_ISSET_S(cpu, cpu_setsize, cpu_present_set))
errx(1, "Requested cpu% is not present", cpu);
errx(1, "Requested cpu%d is not present", cpu);
}
}
@@ -518,7 +520,7 @@ void for_packages(unsigned long long pkg_set, int (func)(int))
void print_version(void)
{
printf("x86_energy_perf_policy 2025.9.19 Len Brown <lenb@kernel.org>\n");
printf("x86_energy_perf_policy 2025.11.22 Len Brown <lenb@kernel.org>\n");
}
void cmdline(int argc, char **argv)
@@ -660,6 +662,11 @@ void err_on_hypervisor(void)
}
flags = strstr(buffer, "flags");
if (!flags) {
fclose(cpuinfo);
free(buffer);
err(1, "Failed to find 'flags' in /proc/cpuinfo");
}
rewind(cpuinfo);
fseek(cpuinfo, flags - buffer, SEEK_SET);
if (!fgets(buffer, 4096, cpuinfo)) {
@@ -684,10 +691,12 @@ int get_msr(int cpu, int offset, unsigned long long *msr)
char pathname[32];
int fd;
sprintf(pathname, "/dev/cpu/%d/msr", cpu);
sprintf(pathname, use_android_msr_path ? "/dev/msr%d" : "/dev/cpu/%d/msr", cpu);
fd = open(pathname, O_RDONLY);
if (fd < 0)
err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname);
err(-1, "%s open failed, try chown or chmod +r %s, or run as root",
pathname, use_android_msr_path ? "/dev/msr*" : "/dev/cpu/*/msr");
retval = pread(fd, msr, sizeof(*msr), offset);
if (retval != sizeof(*msr)) {
@@ -708,10 +717,11 @@ int put_msr(int cpu, int offset, unsigned long long new_msr)
int retval;
int fd;
sprintf(pathname, "/dev/cpu/%d/msr", cpu);
sprintf(pathname, use_android_msr_path ? "/dev/msr%d" : "/dev/cpu/%d/msr", cpu);
fd = open(pathname, O_RDWR);
if (fd < 0)
err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname);
err(-1, "%s open failed, try chown or chmod +r %s, or run as root",
pathname, use_android_msr_path ? "/dev/msr*" : "/dev/cpu/*/msr");
retval = pwrite(fd, &new_msr, sizeof(new_msr), offset);
if (retval != sizeof(new_msr))
@@ -1421,16 +1431,32 @@ void set_base_cpu(void)
err(-ENODEV, "No valid cpus found");
}
static void probe_android_msr_path(void)
{
struct stat sb;
char test_path[32];
sprintf(test_path, "/dev/msr%d", base_cpu);
if (stat(test_path, &sb) == 0)
use_android_msr_path = 1;
}
void probe_dev_msr(void)
{
struct stat sb;
char pathname[32];
sprintf(pathname, "/dev/cpu/%d/msr", base_cpu);
if (stat(pathname, &sb))
if (system("/sbin/modprobe msr > /dev/null 2>&1"))
err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" ");
probe_android_msr_path();
sprintf(pathname, use_android_msr_path ? "/dev/msr%d" : "/dev/cpu/%d/msr", base_cpu);
if (stat(pathname, &sb)) {
if (system("/sbin/modprobe msr > /dev/null 2>&1")) {
if (use_android_msr_path)
err(-5, "no /dev/msr0, Try \"# modprobe msr\" ");
else
err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" ");
}
}
}
static void get_cpuid_or_exit(unsigned int leaf,
@@ -1547,6 +1573,7 @@ void parse_cpuid(void)
int main(int argc, char **argv)
{
set_base_cpu();
probe_dev_msr();
init_data_structures();