* [PATCH 2/9] tools/power turbostat: Warn, but don't Err on out-dated perf systems
2026-10-12 18:32 ` [PATCH 1/9] tools/power turbostat: Read complete CPU lists Len Brown
@ 2026-10-12 18:32 ` Len Brown
2026-10-12 18:32 ` [PATCH 3/9] tools/power turbostat: add NULL check after calloc() Len Brown
` (6 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Len Brown @ 2026-10-12 18:32 UTC (permalink / raw)
To: linux-pm; +Cc: Len Brown, David Arcari
From: Len Brown <len.brown@intel.com>
Some systems in the field have perf enabled,
but their kernel perf support lacks the latest L2 stats.
Warn, but don't Err on those systems, and suggest how to avoid the Warn.
Fixes: dd23bfe4c317 ("tools/power turbostat: Add L2 cache statistics")
Reported-by: David Arcari <darcari@redhat.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
tools/power/x86/turbostat/turbostat.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index cec3f2fbba45..0c55698d6843 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -9477,8 +9477,10 @@ void perf_l2_init(void)
free_fd_l2_percpu();
return;
}
- } else
- err(-1, "%s: cpu%d: type %d", __func__, cpu, cpus[cpu].type);
+ } else {
+ warn("%s: cpu%d: type %d: Update kernel perf support or use \"--hide L2MRPS,L2%%hit\" or \"--hide cache\" or \"--no-perf\"", __func__, cpu, cpus[cpu].type);
+ return;
+ }
}
BIC_PRESENT(BIC_L2_MRPS);
BIC_PRESENT(BIC_L2_HIT);
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 3/9] tools/power turbostat: add NULL check after calloc()
2026-10-12 18:32 ` [PATCH 1/9] tools/power turbostat: Read complete CPU lists Len Brown
2026-10-12 18:32 ` [PATCH 2/9] tools/power turbostat: Warn, but don't Err on out-dated perf systems Len Brown
@ 2026-10-12 18:32 ` Len Brown
2026-10-12 18:32 ` [PATCH 4/9] tools/power turbostat: Sanity check GFX%rc6 and SAM%mc6 percentages Len Brown
` (5 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Len Brown @ 2026-10-12 18:32 UTC (permalink / raw)
To: linux-pm; +Cc: longlong yan, Len Brown
From: longlong yan <yanlonglong@kylinos.cn>
Three calloc() calls in turbostat lack NULL return checks, leading to
potential NULL pointer dereferences on allocation failure:
1. rapl_perf_init(): the allocated `domain_visited` is used later via
memset(domain_visited, 0, ...) without checking for NULL.
2. added_perf_counters_init_(): the allocated `domain_visited` is used
later via memset() and domain_visited[next_domain] without checking
for NULL.
3. pmt_add_counter(): the allocated `pcounter` is dereferenced
immediately via strncpy(pcounter->name, ...) without checking for
NULL.
Add NULL checks after each calloc(), using the same error handling
style already present in each function: err(-1, ...) for rapl_perf_init(),
errx(1, ...) for added_perf_counters_init_(), and return 1 for
pmt_add_counter().
Signed-off-by: longlong yan <yanlonglong@kylinos.cn>
Signed-off-by: Len Brown <len.brown@intel.com>
---
tools/power/x86/turbostat/turbostat.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 0c55698d6843..808f079c874c 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -8661,6 +8661,8 @@ void rapl_perf_init(void)
{
const unsigned int num_domains = get_rapl_num_domains();
bool *domain_visited = calloc(num_domains, sizeof(bool));
+ if (!domain_visited)
+ err(-1, "calloc domain_visited");
rapl_counter_info_perdomain = calloc(num_domains, sizeof(*rapl_counter_info_perdomain));
if (rapl_counter_info_perdomain == NULL)
@@ -10007,6 +10009,8 @@ int added_perf_counters_init_(struct perf_counter_info *pinfo)
const size_t max_num_domains = MAX(topo.max_cpu_num + 1, MAX(topo.max_core_id + 1, topo.max_package_id + 1));
domain_visited = calloc(max_num_domains, sizeof(*domain_visited));
+ if (!domain_visited)
+ errx(1, "%s: alloc %s", __func__, "domain_visited");
while (pinfo) {
switch (pinfo->scope) {
@@ -10398,6 +10402,8 @@ int pmt_add_counter(unsigned int guid, unsigned int seq, const char *name, enum
pcounter = pmt_find_counter(*pmt_root, name);
if (!pcounter) {
pcounter = calloc(1, sizeof(*pcounter));
+ if (!pcounter)
+ return 1;
new_counter = true;
}
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 4/9] tools/power turbostat: Sanity check GFX%rc6 and SAM%mc6 percentages
2026-10-12 18:32 ` [PATCH 1/9] tools/power turbostat: Read complete CPU lists Len Brown
2026-10-12 18:32 ` [PATCH 2/9] tools/power turbostat: Warn, but don't Err on out-dated perf systems Len Brown
2026-10-12 18:32 ` [PATCH 3/9] tools/power turbostat: add NULL check after calloc() Len Brown
@ 2026-10-12 18:32 ` Len Brown
2026-10-12 18:32 ` [PATCH 5/9] tools/power turbostat: Fix fd_perf leak on reset Len Brown
` (4 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Len Brown @ 2026-10-12 18:32 UTC (permalink / raw)
To: linux-pm; +Cc: Len Brown
From: Len Brown <len.brown@intel.com>
When measuring over a suspend cycle, GRX%rc6 and SAM%mc6
are observed to print as numbers much greater than 100%.
Those numbers are not useful, and they mess up the columns.
Detect when they are out of range, and print them as NaN.
Signed-off-by: Len Brown <len.brown@intel.com>
---
tools/power/x86/turbostat/turbostat.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 808f079c874c..6a59cdcf8ba3 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -3636,7 +3636,7 @@ int format_counters(PER_THREAD_PARAMS)
if (p->gfx_rc6_ms == -1) { /* detect GFX counter reset */
outp += sprintf(outp, "%s**.**", (printed++ ? delim : ""));
} else {
- outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), p->gfx_rc6_ms / 10.0 / interval_float);
+ outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), pct(p->gfx_rc6_ms / 10.0, interval_float));
}
}
@@ -3653,7 +3653,7 @@ int format_counters(PER_THREAD_PARAMS)
if (p->sam_mc6_ms == -1) { /* detect GFX counter reset */
outp += sprintf(outp, "%s**.**", (printed++ ? delim : ""));
} else {
- outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), p->sam_mc6_ms / 10.0 / interval_float);
+ outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), pct(p->sam_mc6_ms / 10.0, interval_float));
}
}
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 5/9] tools/power turbostat: Fix fd_perf leak on reset
2026-10-12 18:32 ` [PATCH 1/9] tools/power turbostat: Read complete CPU lists Len Brown
` (2 preceding siblings ...)
2026-10-12 18:32 ` [PATCH 4/9] tools/power turbostat: Sanity check GFX%rc6 and SAM%mc6 percentages Len Brown
@ 2026-10-12 18:32 ` Len Brown
2026-10-12 18:32 ` [PATCH 6/9] tools/power turbostat: Fix CWF PMT off-by-one Len Brown
` (3 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Len Brown @ 2026-10-12 18:32 UTC (permalink / raw)
To: linux-pm; +Cc: Len Brown
From: Len Brown <len.brown@intel.com>
When turbostat notices a topology change,
it frees perf file descriptors for each CPU
to prepare to re-initialize.
Fix an off-by-one error in that per-cpu loop that
resulted in a file descriptor leak of the file for
the highest numbered CPU in the system.
Fixes: 67bab430f4e7 ("tools/power turbostat: Group SMI counter with APERF and MPERF")
Assisted-by: GitHub Copilot (claude-sonnet-4.6)
Signed-off-by: Len Brown <len.brown@intel.com>
---
tools/power/x86/turbostat/turbostat.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 6a59cdcf8ba3..8e017b4dbc6c 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -5915,7 +5915,7 @@ void free_fd_msr(void)
if (!msr_counter_info)
return;
- for (int cpu = 0; cpu < topo.max_cpu_num; ++cpu) {
+ for (int cpu = 0; cpu <= topo.max_cpu_num; ++cpu) {
if (msr_counter_info[cpu].fd_perf != -1)
close(msr_counter_info[cpu].fd_perf);
}
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 6/9] tools/power turbostat: Fix CWF PMT off-by-one
2026-10-12 18:32 ` [PATCH 1/9] tools/power turbostat: Read complete CPU lists Len Brown
` (3 preceding siblings ...)
2026-10-12 18:32 ` [PATCH 5/9] tools/power turbostat: Fix fd_perf leak on reset Len Brown
@ 2026-10-12 18:32 ` Len Brown
2026-10-12 18:32 ` [PATCH 7/9] tools/power turbostat: Fix PMT error path fd handling Len Brown
` (2 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Len Brown @ 2026-10-12 18:32 UTC (permalink / raw)
To: linux-pm; +Cc: Len Brown
From: Len Brown <len.brown@intel.com>
Fix off-by-one error causing last CPU on CWF
to never get a pmt counter allocated.
Fixes: 5ce1e9bbb2a1 ("tools/power turbostat: Add CPU%c1e BIC for CWF")
Assisted-by: GitHub Copilot (claude-sonnet-4.6)
Signed-off-by: Len Brown <len.brown@intel.com>
---
tools/power/x86/turbostat/turbostat.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 8e017b4dbc6c..795946bcfd94 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -10453,7 +10453,7 @@ void pmt_init(void)
mod_num = 0; /* Relative module number for current PMT file. */
/* Open the counter for each CPU. */
- for (cpu_num = 0; cpu_num < topo.max_cpu_num;) {
+ for (cpu_num = 0; cpu_num <= topo.max_cpu_num;) {
if (cpu_is_not_allowed(cpu_num))
goto next_loop_iter;
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 7/9] tools/power turbostat: Fix PMT error path fd handling
2026-10-12 18:32 ` [PATCH 1/9] tools/power turbostat: Read complete CPU lists Len Brown
` (4 preceding siblings ...)
2026-10-12 18:32 ` [PATCH 6/9] tools/power turbostat: Fix CWF PMT off-by-one Len Brown
@ 2026-10-12 18:32 ` Len Brown
2026-10-12 18:32 ` [PATCH 8/9] tools/power turbostat: Fix add_counter issue if > 24 counters Len Brown
2026-10-12 18:32 ` [PATCH 9/9] turbostat 2026.09.28 Len Brown
7 siblings, 0 replies; 10+ messages in thread
From: Len Brown @ 2026-10-12 18:32 UTC (permalink / raw)
To: linux-pm; +Cc: Len Brown
From: Len Brown <len.brown@intel.com>
It is possible to leak a file descriptor if a diretory
open succeeds, but the scan fails. Close the fd on error.
Also, on cleanup, check for NULL fd.
Assisted-by: Claude: Claude Sonnet 4.6
Fixes: 4265a86582ea ("tools/power turbostat: Add PMT directory iterator helper")
Signed-off-by: Len Brown <len.brown@intel.com>
---
tools/power/x86/turbostat/turbostat.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 795946bcfd94..bb1e54a23ae8 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -2034,8 +2034,11 @@ const struct dirent *pmt_diriter_begin(struct pmt_diriter_t *iter, const char *p
return NULL;
num_names = scandir(pmt_root_path, &iter->namelist, pmt_telemdir_filter, pmt_telemdir_sort);
- if (num_names == -1)
+ if (num_names == -1) {
+ closedir(iter->dir);
+ iter->dir = NULL;
return NULL;
+ }
}
iter->current_name_idx = 0;
@@ -2063,8 +2066,10 @@ void pmt_diriter_remove(struct pmt_diriter_t *iter)
iter->num_names = 0;
iter->current_name_idx = 0;
- closedir(iter->dir);
- iter->dir = NULL;
+ if (iter->dir) {
+ closedir(iter->dir);
+ iter->dir = NULL;
+ }
}
unsigned int pmt_counter_get_width(const struct pmt_counter *p)
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 8/9] tools/power turbostat: Fix add_counter issue if > 24 counters.
2026-10-12 18:32 ` [PATCH 1/9] tools/power turbostat: Read complete CPU lists Len Brown
` (5 preceding siblings ...)
2026-10-12 18:32 ` [PATCH 7/9] tools/power turbostat: Fix PMT error path fd handling Len Brown
@ 2026-10-12 18:32 ` Len Brown
2026-10-12 18:32 ` [PATCH 9/9] turbostat 2026.09.28 Len Brown
7 siblings, 0 replies; 10+ messages in thread
From: Len Brown @ 2026-10-12 18:32 UTC (permalink / raw)
To: linux-pm; +Cc: Len Brown
From: Len Brown <len.brown@intel.com>
We allocate space for added counters ahead of time,
and we arbitrarily chose 24 added counters of each type.
If a future code flow hits this limit and continues,
and then removes counters, we do a phantom increment
and lose track of the number of added counters.
Increment the count only if there is no error.
Fixes: 388e9c8134be ("tools/power turbostat: Make extensible via the --add parameter")
Assisted-by: Claude: Claude Sonnet 4.6
Signed-off-by: Len Brown <len.brown@intel.com>
---
tools/power/x86/turbostat/turbostat.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index bb1e54a23ae8..9a2aa703d9d6 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -10687,10 +10687,11 @@ int add_counter(unsigned int msr_num, char *path, char *name,
fprintf(stderr, "%s: %s FOUND\n", __func__, name);
break;
}
- if (sys.added_thread_counters++ >= MAX_ADDED_THREAD_COUNTERS) {
+ if (sys.added_thread_counters >= MAX_ADDED_THREAD_COUNTERS) {
warnx("ignoring thread counter %s", name);
return -1;
}
+ sys.added_thread_counters++;
break;
case SCOPE_CORE:
msrp = find_msrp_by_name(sys.cp, name);
@@ -10699,10 +10700,11 @@ int add_counter(unsigned int msr_num, char *path, char *name,
fprintf(stderr, "%s: %s FOUND\n", __func__, name);
break;
}
- if (sys.added_core_counters++ >= MAX_ADDED_CORE_COUNTERS) {
+ if (sys.added_core_counters >= MAX_ADDED_CORE_COUNTERS) {
warnx("ignoring core counter %s", name);
return -1;
}
+ sys.added_core_counters++;
break;
case SCOPE_PACKAGE:
msrp = find_msrp_by_name(sys.pp, name);
@@ -10711,10 +10713,11 @@ int add_counter(unsigned int msr_num, char *path, char *name,
fprintf(stderr, "%s: %s FOUND\n", __func__, name);
break;
}
- if (sys.added_package_counters++ >= MAX_ADDED_PACKAGE_COUNTERS) {
+ if (sys.added_package_counters >= MAX_ADDED_PACKAGE_COUNTERS) {
warnx("ignoring package counter %s", name);
return -1;
}
+ sys.added_package_counters++;
break;
default:
warnx("ignoring counter %s with unknown scope", name);
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 9/9] turbostat 2026.09.28
2026-10-12 18:32 ` [PATCH 1/9] tools/power turbostat: Read complete CPU lists Len Brown
` (6 preceding siblings ...)
2026-10-12 18:32 ` [PATCH 8/9] tools/power turbostat: Fix add_counter issue if > 24 counters Len Brown
@ 2026-10-12 18:32 ` Len Brown
7 siblings, 0 replies; 10+ messages in thread
From: Len Brown @ 2026-10-12 18:32 UTC (permalink / raw)
To: linux-pm; +Cc: Len Brown
From: Len Brown <len.brown@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
tools/power/x86/turbostat/turbostat.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 9a2aa703d9d6..cb3d571f121e 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -10627,7 +10627,7 @@ int get_and_dump_counters(void)
void print_version()
{
- fprintf(outf, "turbostat version 2026.04.21 - Len Brown <lenb@kernel.org>\n");
+ fprintf(outf, "turbostat version 2026.09.28 - Len Brown <lenb@kernel.org>\n");
}
#define COMMAND_LINE_SIZE 2048
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread