linux-pm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* PATCH[0/8] turbostat updates through 2025.10.24
@ 2025-10-24 15:38 Len Brown
  2025-10-24 15:38 ` [PATCH 1/8] tools/power turbostat: Regression fix Uncore MHz printed in hex Len Brown
  0 siblings, 1 reply; 9+ messages in thread
From: Len Brown @ 2025-10-24 15:38 UTC (permalink / raw)
  To: rafael, linux-pm

Rafael, can you pick up 1/8? It is regression fix.

[PATCH 1/8] tools/power turbostat: Regression fix Uncore MHz printed

2/8 is ready for upstream, though technically a feature...

[PATCH 2/8] tools/power turbostat: Add Wildcat Lake and Nova Lake

3-7 are random cleanups.

[PATCH 3/8] tools/power turbostat: Refactor added column header
[PATCH 4/8] tools/power turbostat: Refactor added-counter value
[PATCH 5/8] tools/power turbostat.8: Update example
[PATCH 6/8] tools/power turbostat: Refactor floating point printout
[PATCH 7/8] tools/power turbostat: Remove dead code

8/8 is a new feature to show LLC statistics.
It "works for me", and I'd be delighted to
receive feedback on it!

[PATCH 8/8] tools/power turbostat: Add LLC stats

These patches can be pulled altogether here:
git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git turbostat

thanks!
-Len Brown
Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/8] tools/power turbostat: Regression fix Uncore MHz printed in hex
  2025-10-24 15:38 PATCH[0/8] turbostat updates through 2025.10.24 Len Brown
@ 2025-10-24 15:38 ` Len Brown
  2025-10-24 15:38   ` [PATCH 2/8] tools/power turbostat: Add Wildcat Lake and Nova Lake support Len Brown
                     ` (6 more replies)
  0 siblings, 7 replies; 9+ messages in thread
From: Len Brown @ 2025-10-24 15:38 UTC (permalink / raw)
  To: rafael, linux-pm; +Cc: Len Brown, Andrej Tkalcec

From: Len Brown <len.brown@intel.com>

A patch to allow specifying FORMAT_AVERAGE to added counters...
broke the internally added counter for Cluster Uncore MHz -- printing it in HEX.

Fixes: dcd1c379b0f1 ("tools/power turbostat: add format "average" for external attributes")
Reported-by: Andrej Tkalcec <andrej.tkalcec@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
 tools/power/x86/turbostat/turbostat.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index f2512d78bcbd..1b5ca2f4e92f 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -3285,13 +3285,13 @@ int format_counters(PER_THREAD_PARAMS)
 
 	/* Added counters */
 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
-		if (mp->format == FORMAT_RAW || mp->format == FORMAT_AVERAGE) {
+		if (mp->format == FORMAT_RAW) {
 			if (mp->width == 32)
 				outp +=
 				    sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int)t->counter[i]);
 			else
 				outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), t->counter[i]);
-		} else if (mp->format == FORMAT_DELTA) {
+		} else if (mp->format == FORMAT_DELTA || mp->format == FORMAT_AVERAGE) {
 			if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns)
 				outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), t->counter[i]);
 			else
@@ -3382,13 +3382,13 @@ int format_counters(PER_THREAD_PARAMS)
 		outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), c->core_throt_cnt);
 
 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
-		if (mp->format == FORMAT_RAW || mp->format == FORMAT_AVERAGE) {
+		if (mp->format == FORMAT_RAW) {
 			if (mp->width == 32)
 				outp +=
 				    sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int)c->counter[i]);
 			else
 				outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), c->counter[i]);
-		} else if (mp->format == FORMAT_DELTA) {
+		} else if (mp->format == FORMAT_DELTA || mp->format == FORMAT_AVERAGE) {
 			if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns)
 				outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), c->counter[i]);
 			else
@@ -3581,7 +3581,7 @@ int format_counters(PER_THREAD_PARAMS)
 		outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->uncore_mhz);
 
 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
-		if (mp->format == FORMAT_RAW || mp->format == FORMAT_AVERAGE) {
+		if (mp->format == FORMAT_RAW) {
 			if (mp->width == 32)
 				outp +=
 				    sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int)p->counter[i]);
@@ -3758,7 +3758,7 @@ int delta_package(struct pkg_data *new, struct pkg_data *old)
 	    new->rapl_dram_perf_status.raw_value - old->rapl_dram_perf_status.raw_value;
 
 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
-		if (mp->format == FORMAT_RAW || mp->format == FORMAT_AVERAGE)
+		if (mp->format == FORMAT_RAW)
 			old->counter[i] = new->counter[i];
 		else if (mp->format == FORMAT_AVERAGE)
 			old->counter[i] = new->counter[i];
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/8] tools/power turbostat: Add Wildcat Lake and Nova Lake support
  2025-10-24 15:38 ` [PATCH 1/8] tools/power turbostat: Regression fix Uncore MHz printed in hex Len Brown
@ 2025-10-24 15:38   ` Len Brown
  2025-10-24 15:38   ` [PATCH 3/8] tools/power turbostat: Refactor added column header printing Len Brown
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Len Brown @ 2025-10-24 15:38 UTC (permalink / raw)
  To: rafael, linux-pm; +Cc: Len Brown

From: Len Brown <len.brown@intel.com>

Treat Wildcat Lake and Nova Lake (and Panther Lake)
the same as Lunar Lake, for now.

Signed-off-by: Len Brown <len.brown@intel.com>
---
 tools/power/x86/turbostat/turbostat.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 1b5ca2f4e92f..7c24c2f9a075 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -1210,6 +1210,9 @@ static const struct platform_data turbostat_pdata[] = {
 	{ INTEL_ARROWLAKE, &adl_features },
 	{ INTEL_LUNARLAKE_M, &lnl_features },
 	{ INTEL_PANTHERLAKE_L, &lnl_features },
+	{ INTEL_NOVALAKE, &lnl_features },
+	{ INTEL_NOVALAKE_L, &lnl_features },
+	{ INTEL_WILDCATLAKE_L, &lnl_features },
 	{ INTEL_ATOM_SILVERMONT, &slv_features },
 	{ INTEL_ATOM_SILVERMONT_D, &slvd_features },
 	{ INTEL_ATOM_AIRMONT, &amt_features },
@@ -10126,7 +10129,7 @@ int get_and_dump_counters(void)
 
 void print_version()
 {
-	fprintf(outf, "turbostat version 2025.09.09 - Len Brown <lenb@kernel.org>\n");
+	fprintf(outf, "turbostat version 2025.10.18 - Len Brown <lenb@kernel.org>\n");
 }
 
 #define COMMAND_LINE_SIZE 2048
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/8] tools/power turbostat: Refactor added column header printing
  2025-10-24 15:38 ` [PATCH 1/8] tools/power turbostat: Regression fix Uncore MHz printed in hex Len Brown
  2025-10-24 15:38   ` [PATCH 2/8] tools/power turbostat: Add Wildcat Lake and Nova Lake support Len Brown
@ 2025-10-24 15:38   ` Len Brown
  2025-10-24 15:38   ` [PATCH 4/8] tools/power turbostat: Refactor added-counter value printing code Len Brown
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Len Brown @ 2025-10-24 15:38 UTC (permalink / raw)
  To: rafael, linux-pm; +Cc: Len Brown

From: Len Brown <len.brown@intel.com>

Over time, we built up many copies of nearly identical code...

Signed-off-by: Len Brown <len.brown@intel.com>
---
 tools/power/x86/turbostat/turbostat.c | 137 +++++++-------------------
 1 file changed, 36 insertions(+), 101 deletions(-)

diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 7c24c2f9a075..5d753df8706d 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -2705,6 +2705,24 @@ void bic_lookup(cpu_set_t *ret_set, char *name_list, enum show_hide_mode mode)
 	}
 }
 
+/*
+ * print_name()
+ * Print column header name for 64-bit counter in 16 columns (at least 8-char plus a tab)
+ * Otherwise, allow the name + tab to fit within 8-coumn tab-stop.
+ * In both cases, left justififed, just like other turbostat columns,
+ * to allow the column values to consume the tab.
+ *
+ * Yes, 32-bit counters can overflow 8-columns, but then they are usually 64-bit counters.
+ * 64-bit counters can overflow 16-columns, but rarely do.
+ */
+static inline int print_name(int width, int *printed, char *delim, char *name)
+{
+	if (width == 64)
+		return (sprintf(outp, "%s%-8s", (*printed++ ? delim : ""), name));
+	else
+		return (sprintf(outp, "%s%s", (*printed++ ? delim : ""), name));
+}
+
 void print_header(char *delim)
 {
 	struct msr_counter *mp;
@@ -2760,50 +2778,22 @@ void print_header(char *delim)
 	if (DO_BIC(BIC_SMI))
 		outp += sprintf(outp, "%sSMI", (printed++ ? delim : ""));
 
-	for (mp = sys.tp; mp; mp = mp->next) {
+	for (mp = sys.tp; mp; mp = mp->next)
+		outp += print_name(mp->width, &printed, delim, mp->name);
 
-		if (mp->format == FORMAT_RAW || mp->format == FORMAT_AVERAGE) {
-			if (mp->width == 64)
-				outp += sprintf(outp, "%s%18.18s", (printed++ ? delim : ""), mp->name);
-			else
-				outp += sprintf(outp, "%s%10.10s", (printed++ ? delim : ""), mp->name);
-		} else {
-			if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns)
-				outp += sprintf(outp, "%s%8s", (printed++ ? delim : ""), mp->name);
-			else
-				outp += sprintf(outp, "%s%s", (printed++ ? delim : ""), mp->name);
-		}
-	}
-
-	for (pp = sys.perf_tp; pp; pp = pp->next) {
-
-		if (pp->format == FORMAT_RAW) {
-			if (pp->width == 64)
-				outp += sprintf(outp, "%s%18.18s", (printed++ ? delim : ""), pp->name);
-			else
-				outp += sprintf(outp, "%s%10.10s", (printed++ ? delim : ""), pp->name);
-		} else {
-			if ((pp->type == COUNTER_ITEMS) && sums_need_wide_columns)
-				outp += sprintf(outp, "%s%8s", (printed++ ? delim : ""), pp->name);
-			else
-				outp += sprintf(outp, "%s%s", (printed++ ? delim : ""), pp->name);
-		}
-	}
+	for (pp = sys.perf_tp; pp; pp = pp->next)
+		outp += print_name(pp->width, &printed, delim, pp->name);
 
 	ppmt = sys.pmt_tp;
 	while (ppmt) {
 		switch (ppmt->type) {
 		case PMT_TYPE_RAW:
-			if (pmt_counter_get_width(ppmt) <= 32)
-				outp += sprintf(outp, "%s%10.10s", (printed++ ? delim : ""), ppmt->name);
-			else
-				outp += sprintf(outp, "%s%18.18s", (printed++ ? delim : ""), ppmt->name);
-
+			outp += print_name(pmt_counter_get_width(ppmt), &printed, delim, ppmt->name);
 			break;
 
 		case PMT_TYPE_XTAL_TIME:
 		case PMT_TYPE_TCORE_CLOCK:
-			outp += sprintf(outp, "%s%s", (printed++ ? delim : ""), ppmt->name);
+			outp += print_name(32, &printed, delim, ppmt->name);
 			break;
 		}
 
@@ -2836,49 +2826,23 @@ void print_header(char *delim)
 			outp += sprintf(outp, "%sCor_J", (printed++ ? delim : ""));
 	}
 
-	for (mp = sys.cp; mp; mp = mp->next) {
-		if (mp->format == FORMAT_RAW || mp->format == FORMAT_AVERAGE) {
-			if (mp->width == 64)
-				outp += sprintf(outp, "%s%18.18s", delim, mp->name);
-			else
-				outp += sprintf(outp, "%s%10.10s", delim, mp->name);
-		} else {
-			if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns)
-				outp += sprintf(outp, "%s%8s", delim, mp->name);
-			else
-				outp += sprintf(outp, "%s%s", delim, mp->name);
-		}
-	}
-
-	for (pp = sys.perf_cp; pp; pp = pp->next) {
+	for (mp = sys.cp; mp; mp = mp->next)
+		outp += print_name(mp->width, &printed, delim, mp->name);
 
-		if (pp->format == FORMAT_RAW) {
-			if (pp->width == 64)
-				outp += sprintf(outp, "%s%18.18s", (printed++ ? delim : ""), pp->name);
-			else
-				outp += sprintf(outp, "%s%10.10s", (printed++ ? delim : ""), pp->name);
-		} else {
-			if ((pp->type == COUNTER_ITEMS) && sums_need_wide_columns)
-				outp += sprintf(outp, "%s%8s", (printed++ ? delim : ""), pp->name);
-			else
-				outp += sprintf(outp, "%s%s", (printed++ ? delim : ""), pp->name);
-		}
-	}
+	for (pp = sys.perf_cp; pp; pp = pp->next)
+		outp += print_name(pp->width, &printed, delim, pp->name);
 
 	ppmt = sys.pmt_cp;
 	while (ppmt) {
 		switch (ppmt->type) {
 		case PMT_TYPE_RAW:
-			if (pmt_counter_get_width(ppmt) <= 32)
-				outp += sprintf(outp, "%s%10.10s", (printed++ ? delim : ""), ppmt->name);
-			else
-				outp += sprintf(outp, "%s%18.18s", (printed++ ? delim : ""), ppmt->name);
+			outp += print_name(pmt_counter_get_width(ppmt), &printed, delim, ppmt->name);
 
 			break;
 
 		case PMT_TYPE_XTAL_TIME:
 		case PMT_TYPE_TCORE_CLOCK:
-			outp += sprintf(outp, "%s%s", (printed++ ? delim : ""), ppmt->name);
+			outp += print_name(32, &printed, delim, ppmt->name);
 			break;
 		}
 
@@ -2966,51 +2930,22 @@ void print_header(char *delim)
 	if (DO_BIC(BIC_UNCORE_MHZ))
 		outp += sprintf(outp, "%sUncMHz", (printed++ ? delim : ""));
 
-	for (mp = sys.pp; mp; mp = mp->next) {
-		if (mp->format == FORMAT_RAW || mp->format == FORMAT_AVERAGE) {
-			if (mp->width == 64)
-				outp += sprintf(outp, "%s%18.18s", delim, mp->name);
-			else if (mp->width == 32)
-				outp += sprintf(outp, "%s%10.10s", delim, mp->name);
-			else
-				outp += sprintf(outp, "%s%7.7s", delim, mp->name);
-		} else {
-			if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns)
-				outp += sprintf(outp, "%s%8s", delim, mp->name);
-			else
-				outp += sprintf(outp, "%s%7.7s", delim, mp->name);
-		}
-	}
-
-	for (pp = sys.perf_pp; pp; pp = pp->next) {
+	for (mp = sys.pp; mp; mp = mp->next)
+		outp += print_name(mp->width, &printed, delim, mp->name);
 
-		if (pp->format == FORMAT_RAW) {
-			if (pp->width == 64)
-				outp += sprintf(outp, "%s%18.18s", (printed++ ? delim : ""), pp->name);
-			else
-				outp += sprintf(outp, "%s%10.10s", (printed++ ? delim : ""), pp->name);
-		} else {
-			if ((pp->type == COUNTER_ITEMS) && sums_need_wide_columns)
-				outp += sprintf(outp, "%s%8s", (printed++ ? delim : ""), pp->name);
-			else
-				outp += sprintf(outp, "%s%s", (printed++ ? delim : ""), pp->name);
-		}
-	}
+	for (pp = sys.perf_pp; pp; pp = pp->next)
+		outp += print_name(pp->width, &printed, delim, pp->name);
 
 	ppmt = sys.pmt_pp;
 	while (ppmt) {
 		switch (ppmt->type) {
 		case PMT_TYPE_RAW:
-			if (pmt_counter_get_width(ppmt) <= 32)
-				outp += sprintf(outp, "%s%10.10s", (printed++ ? delim : ""), ppmt->name);
-			else
-				outp += sprintf(outp, "%s%18.18s", (printed++ ? delim : ""), ppmt->name);
-
+			outp += print_name(pmt_counter_get_width(ppmt), &printed, delim, ppmt->name);
 			break;
 
 		case PMT_TYPE_XTAL_TIME:
 		case PMT_TYPE_TCORE_CLOCK:
-			outp += sprintf(outp, "%s%s", (printed++ ? delim : ""), ppmt->name);
+			outp += print_name(32, &printed, delim, ppmt->name);
 			break;
 		}
 
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/8] tools/power turbostat: Refactor added-counter value printing code
  2025-10-24 15:38 ` [PATCH 1/8] tools/power turbostat: Regression fix Uncore MHz printed in hex Len Brown
  2025-10-24 15:38   ` [PATCH 2/8] tools/power turbostat: Add Wildcat Lake and Nova Lake support Len Brown
  2025-10-24 15:38   ` [PATCH 3/8] tools/power turbostat: Refactor added column header printing Len Brown
@ 2025-10-24 15:38   ` Len Brown
  2025-10-24 15:38   ` [PATCH 5/8] tools/power turbostat.8: Update example Len Brown
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Len Brown @ 2025-10-24 15:38 UTC (permalink / raw)
  To: rafael, linux-pm; +Cc: Len Brown

From: Len Brown <len.brown@intel.com>

We build up many copies of very similar code...

Signed-off-by: Len Brown <len.brown@intel.com>
---
 tools/power/x86/turbostat/turbostat.c | 153 ++++++++++----------------
 1 file changed, 57 insertions(+), 96 deletions(-)

diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 5d753df8706d..f9b99940b247 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -2717,10 +2717,24 @@ void bic_lookup(cpu_set_t *ret_set, char *name_list, enum show_hide_mode mode)
  */
 static inline int print_name(int width, int *printed, char *delim, char *name)
 {
-	if (width == 64)
+	if (width <= 32)
+		return (sprintf(outp, "%s%s", (*printed++ ? delim : ""), name));
+	else
 		return (sprintf(outp, "%s%-8s", (*printed++ ? delim : ""), name));
+}
+static inline int print_hex_value(int width, int *printed, char *delim, unsigned long long value)
+{
+	if (width <= 32)
+		return (sprintf(outp, "%s%08x", (*printed++ ? delim : ""), (unsigned int)value));
 	else
-		return (sprintf(outp, "%s%s", (*printed++ ? delim : ""), name));
+		return (sprintf(outp, "%s%016llx", (*printed++ ? delim : ""), value));
+}
+static inline int print_decimal_value(int width, int *printed, char *delim, unsigned long long value)
+{
+	if (width <= 32)
+		return (sprintf(outp, "%s%d", (*printed++ ? delim : ""), (unsigned int)value));
+	else
+		return (sprintf(outp, "%s%-8lld", (*printed++ ? delim : ""), value));
 }
 
 void print_header(char *delim)
@@ -3221,20 +3235,13 @@ int format_counters(PER_THREAD_PARAMS)
 	if (DO_BIC(BIC_SMI))
 		outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->smi_count);
 
-	/* Added counters */
+	/* Added Thread Counters */
 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
-		if (mp->format == FORMAT_RAW) {
-			if (mp->width == 32)
-				outp +=
-				    sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int)t->counter[i]);
-			else
-				outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), t->counter[i]);
-		} else if (mp->format == FORMAT_DELTA || mp->format == FORMAT_AVERAGE) {
-			if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns)
-				outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), t->counter[i]);
-			else
-				outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), t->counter[i]);
-		} else if (mp->format == FORMAT_PERCENT) {
+		if (mp->format == FORMAT_RAW)
+			outp += print_hex_value(mp->width, &printed, delim, t->counter[i]);
+		else if (mp->format == FORMAT_DELTA || mp->format == FORMAT_AVERAGE)
+			outp += print_decimal_value(mp->width, &printed, delim, t->counter[i]);
+		else if (mp->format == FORMAT_PERCENT) {
 			if (mp->type == COUNTER_USEC)
 				outp +=
 				    sprintf(outp, "%s%.2f", (printed++ ? delim : ""),
@@ -3244,21 +3251,13 @@ int format_counters(PER_THREAD_PARAMS)
 		}
 	}
 
-	/* Added perf counters */
+	/* Added perf Thread Counters */
 	for (i = 0, pp = sys.perf_tp; pp; ++i, pp = pp->next) {
-		if (pp->format == FORMAT_RAW) {
-			if (pp->width == 32)
-				outp +=
-				    sprintf(outp, "%s0x%08x", (printed++ ? delim : ""),
-					    (unsigned int)t->perf_counter[i]);
-			else
-				outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), t->perf_counter[i]);
-		} else if (pp->format == FORMAT_DELTA) {
-			if ((pp->type == COUNTER_ITEMS) && sums_need_wide_columns)
-				outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), t->perf_counter[i]);
-			else
-				outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), t->perf_counter[i]);
-		} else if (pp->format == FORMAT_PERCENT) {
+		if (pp->format == FORMAT_RAW)
+			outp += print_hex_value(pp->width, &printed, delim, t->perf_counter[i]);
+		else if (pp->format == FORMAT_DELTA)
+			outp += print_decimal_value(pp->width, &printed, delim, t->perf_counter[i]);
+		else if (pp->format == FORMAT_PERCENT) {
 			if (pp->type == COUNTER_USEC)
 				outp +=
 				    sprintf(outp, "%s%.2f", (printed++ ? delim : ""),
@@ -3269,17 +3268,13 @@ int format_counters(PER_THREAD_PARAMS)
 		}
 	}
 
+	/* Added PMT Thread Counters */
 	for (i = 0, ppmt = sys.pmt_tp; ppmt; i++, ppmt = ppmt->next) {
 		const unsigned long value_raw = t->pmt_counter[i];
 		double value_converted;
 		switch (ppmt->type) {
 		case PMT_TYPE_RAW:
-			if (pmt_counter_get_width(ppmt) <= 32)
-				outp += sprintf(outp, "%s0x%08x", (printed++ ? delim : ""),
-						(unsigned int)t->pmt_counter[i]);
-			else
-				outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), t->pmt_counter[i]);
-
+			outp += print_hex_value(pmt_counter_get_width(ppmt), &printed, delim, t->pmt_counter[i]);
 			break;
 
 		case PMT_TYPE_XTAL_TIME:
@@ -3319,52 +3314,35 @@ int format_counters(PER_THREAD_PARAMS)
 	if (DO_BIC(BIC_CORE_THROT_CNT))
 		outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), c->core_throt_cnt);
 
+	/* Added Core Counters */
 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
-		if (mp->format == FORMAT_RAW) {
-			if (mp->width == 32)
-				outp +=
-				    sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int)c->counter[i]);
-			else
-				outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), c->counter[i]);
-		} else if (mp->format == FORMAT_DELTA || mp->format == FORMAT_AVERAGE) {
-			if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns)
-				outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), c->counter[i]);
-			else
-				outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), c->counter[i]);
-		} else if (mp->format == FORMAT_PERCENT) {
+		if (mp->format == FORMAT_RAW)
+			outp += print_hex_value(mp->width, &printed, delim, c->counter[i]);
+		else if (mp->format == FORMAT_DELTA || mp->format == FORMAT_AVERAGE)
+			outp += print_decimal_value(mp->width, &printed, delim, c->counter[i]);
+		else if (mp->format == FORMAT_PERCENT) {
 			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->counter[i] / tsc);
 		}
 	}
 
+	/* Added perf Core counters */
 	for (i = 0, pp = sys.perf_cp; pp; i++, pp = pp->next) {
-		if (pp->format == FORMAT_RAW) {
-			if (pp->width == 32)
-				outp +=
-				    sprintf(outp, "%s0x%08x", (printed++ ? delim : ""),
-					    (unsigned int)c->perf_counter[i]);
-			else
-				outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), c->perf_counter[i]);
-		} else if (pp->format == FORMAT_DELTA) {
-			if ((pp->type == COUNTER_ITEMS) && sums_need_wide_columns)
-				outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), c->perf_counter[i]);
-			else
-				outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), c->perf_counter[i]);
-		} else if (pp->format == FORMAT_PERCENT) {
+		if (pp->format == FORMAT_RAW)
+			outp += print_hex_value(pp->width, &printed, delim, c->perf_counter[i]);
+		else if (pp->format == FORMAT_DELTA)
+			outp += print_decimal_value(pp->width, &printed, delim, c->perf_counter[i]);
+		else if (pp->format == FORMAT_PERCENT) {
 			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->perf_counter[i] / tsc);
 		}
 	}
 
+	/* Added PMT Core counters */
 	for (i = 0, ppmt = sys.pmt_cp; ppmt; i++, ppmt = ppmt->next) {
 		const unsigned long value_raw = c->pmt_counter[i];
 		double value_converted;
 		switch (ppmt->type) {
 		case PMT_TYPE_RAW:
-			if (pmt_counter_get_width(ppmt) <= 32)
-				outp += sprintf(outp, "%s0x%08x", (printed++ ? delim : ""),
-						(unsigned int)c->pmt_counter[i]);
-			else
-				outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), c->pmt_counter[i]);
-
+			outp += print_hex_value(pmt_counter_get_width(ppmt), &printed, delim, c->pmt_counter[i]);
 			break;
 
 		case PMT_TYPE_XTAL_TIME:
@@ -3518,37 +3496,24 @@ int format_counters(PER_THREAD_PARAMS)
 	if (DO_BIC(BIC_UNCORE_MHZ))
 		outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->uncore_mhz);
 
+	/* Added Package Counters */
 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
-		if (mp->format == FORMAT_RAW) {
-			if (mp->width == 32)
-				outp +=
-				    sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int)p->counter[i]);
-			else
-				outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), p->counter[i]);
-		} else if (mp->format == FORMAT_DELTA) {
-			if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns)
-				outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), p->counter[i]);
-			else
-				outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), p->counter[i]);
-		} else if (mp->format == FORMAT_PERCENT) {
+		if (mp->format == FORMAT_RAW)
+			outp += print_hex_value(mp->width, &printed, delim, p->counter[i]);
+		else if (mp->format == FORMAT_DELTA)
+			outp += print_decimal_value(mp->width, &printed, delim, p->counter[i]);
+		else if (mp->format == FORMAT_PERCENT) {
 			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->counter[i] / tsc);
 		} else if (mp->type == COUNTER_K2M)
 			outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), (unsigned int)p->counter[i] / 1000);
 	}
 
+	/* Added perf Package Counters */
 	for (i = 0, pp = sys.perf_pp; pp; i++, pp = pp->next) {
-		if (pp->format == FORMAT_RAW) {
-			if (pp->width == 32)
-				outp +=
-				    sprintf(outp, "%s0x%08x", (printed++ ? delim : ""),
-					    (unsigned int)p->perf_counter[i]);
-			else
-				outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), p->perf_counter[i]);
-		} else if (pp->format == FORMAT_DELTA) {
-			if ((pp->type == COUNTER_ITEMS) && sums_need_wide_columns)
-				outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), p->perf_counter[i]);
-			else
-				outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), p->perf_counter[i]);
+		if (pp->format == FORMAT_RAW)
+			outp += print_hex_value(pp->width, &printed, delim, p->perf_counter[i]);
+		else if (pp->format == FORMAT_DELTA) {
+			outp += print_decimal_value(pp->width, &printed, delim, p->perf_counter[i]);
 		} else if (pp->format == FORMAT_PERCENT) {
 			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->perf_counter[i] / tsc);
 		} else if (pp->type == COUNTER_K2M) {
@@ -3557,17 +3522,13 @@ int format_counters(PER_THREAD_PARAMS)
 		}
 	}
 
+	/* Added PMT Package Counters */
 	for (i = 0, ppmt = sys.pmt_pp; ppmt; i++, ppmt = ppmt->next) {
 		const unsigned long value_raw = p->pmt_counter[i];
 		double value_converted;
 		switch (ppmt->type) {
 		case PMT_TYPE_RAW:
-			if (pmt_counter_get_width(ppmt) <= 32)
-				outp += sprintf(outp, "%s0x%08x", (printed++ ? delim : ""),
-						(unsigned int)p->pmt_counter[i]);
-			else
-				outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), p->pmt_counter[i]);
-
+			outp += print_hex_value(pmt_counter_get_width(ppmt), &printed, delim, p->pmt_counter[i]);
 			break;
 
 		case PMT_TYPE_XTAL_TIME:
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5/8] tools/power turbostat.8: Update example
  2025-10-24 15:38 ` [PATCH 1/8] tools/power turbostat: Regression fix Uncore MHz printed in hex Len Brown
                     ` (2 preceding siblings ...)
  2025-10-24 15:38   ` [PATCH 4/8] tools/power turbostat: Refactor added-counter value printing code Len Brown
@ 2025-10-24 15:38   ` Len Brown
  2025-10-24 15:38   ` [PATCH 6/8] tools/power turbostat: Refactor floating point printout code Len Brown
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Len Brown @ 2025-10-24 15:38 UTC (permalink / raw)
  To: rafael, linux-pm; +Cc: Len Brown

From: Len Brown <len.brown@intel.com>

Update the added-counters example to print counters in decimal
rather than hex -- now that it is working...

Signed-off-by: Len Brown <len.brown@intel.com>
---
 tools/power/x86/turbostat/turbostat.8 | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
index 3340def58d01..ad3fc201552f 100644
--- a/tools/power/x86/turbostat/turbostat.8
+++ b/tools/power/x86/turbostat/turbostat.8
@@ -410,25 +410,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
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 6/8] tools/power turbostat: Refactor floating point printout code
  2025-10-24 15:38 ` [PATCH 1/8] tools/power turbostat: Regression fix Uncore MHz printed in hex Len Brown
                     ` (3 preceding siblings ...)
  2025-10-24 15:38   ` [PATCH 5/8] tools/power turbostat.8: Update example Len Brown
@ 2025-10-24 15:38   ` Len Brown
  2025-10-24 15:38   ` [PATCH 7/8] tools/power turbostat: Remove dead code Len Brown
  2025-10-24 15:38   ` [PATCH 8/8] tools/power turbostat: Add LLC stats Len Brown
  6 siblings, 0 replies; 9+ messages in thread
From: Len Brown @ 2025-10-24 15:38 UTC (permalink / raw)
  To: rafael, linux-pm; +Cc: Len Brown

From: Len Brown <len.brown@intel.com>

Too many copies of (usually) the same printf code...

Also, unify code for added-counter FORMAT_AVERAGE,
which was correct where it was tested, but neglected elsewhere.

Signed-off-by: Len Brown <len.brown@intel.com>
---
 tools/power/x86/turbostat/turbostat.c | 60 +++++++++++++--------------
 1 file changed, 28 insertions(+), 32 deletions(-)

diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index f9b99940b247..47cb72343038 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -2736,6 +2736,10 @@ static inline int print_decimal_value(int width, int *printed, char *delim, unsi
 	else
 		return (sprintf(outp, "%s%-8lld", (*printed++ ? delim : ""), value));
 }
+static inline int print_float_value(int *printed, char *delim, double value)
+{
+	return (sprintf(outp, "%s%0.2f", (*printed++ ? delim : ""), value));
+}
 
 void print_header(char *delim)
 {
@@ -3243,11 +3247,9 @@ int format_counters(PER_THREAD_PARAMS)
 			outp += print_decimal_value(mp->width, &printed, delim, t->counter[i]);
 		else if (mp->format == FORMAT_PERCENT) {
 			if (mp->type == COUNTER_USEC)
-				outp +=
-				    sprintf(outp, "%s%.2f", (printed++ ? delim : ""),
-					    t->counter[i] / interval_float / 10000);
+				outp += print_float_value(&printed, delim, t->counter[i] / interval_float / 10000);
 			else
-				outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * t->counter[i] / tsc);
+				outp += print_float_value(&printed, delim, 100.0 * t->counter[i] / tsc);
 		}
 	}
 
@@ -3255,16 +3257,13 @@ int format_counters(PER_THREAD_PARAMS)
 	for (i = 0, pp = sys.perf_tp; pp; ++i, pp = pp->next) {
 		if (pp->format == FORMAT_RAW)
 			outp += print_hex_value(pp->width, &printed, delim, t->perf_counter[i]);
-		else if (pp->format == FORMAT_DELTA)
+		else if (pp->format == FORMAT_DELTA || mp->format == FORMAT_AVERAGE)
 			outp += print_decimal_value(pp->width, &printed, delim, t->perf_counter[i]);
 		else if (pp->format == FORMAT_PERCENT) {
 			if (pp->type == COUNTER_USEC)
-				outp +=
-				    sprintf(outp, "%s%.2f", (printed++ ? delim : ""),
-					    t->perf_counter[i] / interval_float / 10000);
+				outp += print_float_value(&printed, delim, t->perf_counter[i] / interval_float / 10000);
 			else
-				outp +=
-				    sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * t->perf_counter[i] / tsc);
+				outp += print_float_value(&printed, delim, 100.0 * t->perf_counter[i] / tsc);
 		}
 	}
 
@@ -3320,20 +3319,18 @@ int format_counters(PER_THREAD_PARAMS)
 			outp += print_hex_value(mp->width, &printed, delim, c->counter[i]);
 		else if (mp->format == FORMAT_DELTA || mp->format == FORMAT_AVERAGE)
 			outp += print_decimal_value(mp->width, &printed, delim, c->counter[i]);
-		else if (mp->format == FORMAT_PERCENT) {
-			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->counter[i] / tsc);
-		}
+		else if (mp->format == FORMAT_PERCENT)
+			outp += print_float_value(&printed, delim, 100.0 * c->counter[i] / tsc);
 	}
 
 	/* Added perf Core counters */
 	for (i = 0, pp = sys.perf_cp; pp; i++, pp = pp->next) {
 		if (pp->format == FORMAT_RAW)
 			outp += print_hex_value(pp->width, &printed, delim, c->perf_counter[i]);
-		else if (pp->format == FORMAT_DELTA)
+		else if (pp->format == FORMAT_DELTA || mp->format == FORMAT_AVERAGE)
 			outp += print_decimal_value(pp->width, &printed, delim, c->perf_counter[i]);
-		else if (pp->format == FORMAT_PERCENT) {
-			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->perf_counter[i] / tsc);
-		}
+		else if (pp->format == FORMAT_PERCENT)
+			outp += print_float_value(&printed, delim, 100.0 * c->perf_counter[i] / tsc);
 	}
 
 	/* Added PMT Core counters */
@@ -3347,12 +3344,12 @@ int format_counters(PER_THREAD_PARAMS)
 
 		case PMT_TYPE_XTAL_TIME:
 			value_converted = 100.0 * value_raw / crystal_hz / interval_float;
-			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), value_converted);
+			outp += print_float_value(&printed, delim, value_converted);
 			break;
 
 		case PMT_TYPE_TCORE_CLOCK:
 			value_converted = 100.0 * value_raw / tcore_clock_freq_hz / interval_float;
-			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), value_converted);
+			outp += print_float_value(&printed, delim, value_converted);
 		}
 	}
 
@@ -3500,26 +3497,25 @@ int format_counters(PER_THREAD_PARAMS)
 	for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
 		if (mp->format == FORMAT_RAW)
 			outp += print_hex_value(mp->width, &printed, delim, p->counter[i]);
-		else if (mp->format == FORMAT_DELTA)
-			outp += print_decimal_value(mp->width, &printed, delim, p->counter[i]);
-		else if (mp->format == FORMAT_PERCENT) {
-			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->counter[i] / tsc);
-		} else if (mp->type == COUNTER_K2M)
+		else if (mp->type == COUNTER_K2M)
 			outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), (unsigned int)p->counter[i] / 1000);
+		else if (mp->format == FORMAT_DELTA || mp->format == FORMAT_AVERAGE)
+			outp += print_decimal_value(mp->width, &printed, delim, p->counter[i]);
+		else if (mp->format == FORMAT_PERCENT)
+			outp += print_float_value(&printed, delim, 100.0 * p->counter[i] / tsc);
 	}
 
 	/* Added perf Package Counters */
 	for (i = 0, pp = sys.perf_pp; pp; i++, pp = pp->next) {
 		if (pp->format == FORMAT_RAW)
 			outp += print_hex_value(pp->width, &printed, delim, p->perf_counter[i]);
-		else if (pp->format == FORMAT_DELTA) {
-			outp += print_decimal_value(pp->width, &printed, delim, p->perf_counter[i]);
-		} else if (pp->format == FORMAT_PERCENT) {
-			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->perf_counter[i] / tsc);
-		} else if (pp->type == COUNTER_K2M) {
+		else if (pp->type == COUNTER_K2M)
 			outp +=
 			    sprintf(outp, "%s%d", (printed++ ? delim : ""), (unsigned int)p->perf_counter[i] / 1000);
-		}
+		else if (pp->format == FORMAT_DELTA || mp->format == FORMAT_AVERAGE)
+			outp += print_decimal_value(pp->width, &printed, delim, p->perf_counter[i]);
+		else if (pp->format == FORMAT_PERCENT)
+			outp += print_float_value(&printed, delim, 100.0 * p->perf_counter[i] / tsc);
 	}
 
 	/* Added PMT Package Counters */
@@ -3533,12 +3529,12 @@ int format_counters(PER_THREAD_PARAMS)
 
 		case PMT_TYPE_XTAL_TIME:
 			value_converted = 100.0 * value_raw / crystal_hz / interval_float;
-			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), value_converted);
+			outp += print_float_value(&printed, delim, value_converted);
 			break;
 
 		case PMT_TYPE_TCORE_CLOCK:
 			value_converted = 100.0 * value_raw / tcore_clock_freq_hz / interval_float;
-			outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), value_converted);
+			outp += print_float_value(&printed, delim, value_converted);
 		}
 	}
 
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 7/8] tools/power turbostat: Remove dead code
  2025-10-24 15:38 ` [PATCH 1/8] tools/power turbostat: Regression fix Uncore MHz printed in hex Len Brown
                     ` (4 preceding siblings ...)
  2025-10-24 15:38   ` [PATCH 6/8] tools/power turbostat: Refactor floating point printout code Len Brown
@ 2025-10-24 15:38   ` Len Brown
  2025-10-24 15:38   ` [PATCH 8/8] tools/power turbostat: Add LLC stats Len Brown
  6 siblings, 0 replies; 9+ messages in thread
From: Len Brown @ 2025-10-24 15:38 UTC (permalink / raw)
  To: rafael, linux-pm; +Cc: Len Brown

From: Len Brown <len.brown@intel.com>

amperf_group_fd is never used.

Signed-off-by: Len Brown <len.brown@intel.com>
---
 tools/power/x86/turbostat/turbostat.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 47cb72343038..f63525a1877c 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -466,8 +466,6 @@ static void bic_groups_init(void)
 #define PCL_10 14		/* PC10 */
 #define PCLUNL 15		/* Unlimited */
 
-struct amperf_group_fd;
-
 char *proc_stat = "/proc/stat";
 FILE *outf;
 int *fd_percpu;
@@ -4418,11 +4416,6 @@ int get_core_throt_cnt(int cpu, unsigned long long *cnt)
 	return 0;
 }
 
-struct amperf_group_fd {
-	int aperf;		/* Also the group descriptor */
-	int mperf;
-};
-
 static int read_perf_counter_info(const char *const path, const char *const parse_format, void *value_ptr)
 {
 	int fdmt;
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 8/8] tools/power turbostat: Add LLC stats
  2025-10-24 15:38 ` [PATCH 1/8] tools/power turbostat: Regression fix Uncore MHz printed in hex Len Brown
                     ` (5 preceding siblings ...)
  2025-10-24 15:38   ` [PATCH 7/8] tools/power turbostat: Remove dead code Len Brown
@ 2025-10-24 15:38   ` Len Brown
  6 siblings, 0 replies; 9+ messages in thread
From: Len Brown @ 2025-10-24 15:38 UTC (permalink / raw)
  To: rafael, linux-pm; +Cc: Len Brown

From: Len Brown <len.brown@intel.com>

LLCkRPS = Last Level Cache Thousands of References Per Second
LLC%hit = Last Level Cache Hit %

These columns are enabled by-default.
They can be controlled with the --show/--hide options
by individual column names above,
or together using the "llc" or "cache" groups.

Signed-off-by: Len Brown <len.brown@intel.com>
---
 tools/power/x86/turbostat/turbostat.8 |   6 +-
 tools/power/x86/turbostat/turbostat.c | 176 ++++++++++++++++++++++----
 2 files changed, 154 insertions(+), 28 deletions(-)

diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
index ad3fc201552f..1551fcdbfd8a 100644
--- a/tools/power/x86/turbostat/turbostat.8
+++ b/tools/power/x86/turbostat/turbostat.8
@@ -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.
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index f63525a1877c..b85fa6bda96b 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -209,6 +209,8 @@ struct msr_counter bic[] = {
 	{ 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 },
+	{ 0x0, "LLCkRPS", NULL, 0, 0, 0, NULL, 0 },
+	{ 0x0, "LLC%hit", NULL, 0, 0, 0, NULL, 0 },
 };
 
 /* n.b. bic_names must match the order in bic[], above */
@@ -278,6 +280,8 @@ enum bic_names {
 	BIC_NMI,
 	BIC_CPU_c1e,
 	BIC_pct_idle,
+	BIC_LLC_RPS,
+	BIC_LLC_HIT,
 	MAX_BIC
 };
 
@@ -305,6 +309,7 @@ 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_cache;
 static cpu_set_t bic_group_other;
 static cpu_set_t bic_group_disabled_by_default;
 static cpu_set_t bic_enabled;
@@ -413,9 +418,14 @@ static void bic_groups_init(void)
 	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_cache);
+	SET_BIC(BIC_LLC_RPS, &bic_group_cache);
+	SET_BIC(BIC_LLC_HIT, &bic_group_cache);
+
 	BIC_INIT(&bic_group_other);
 	SET_BIC(BIC_IRQ, &bic_group_other);
 	SET_BIC(BIC_NMI, &bic_group_other);
@@ -470,6 +480,7 @@ char *proc_stat = "/proc/stat";
 FILE *outf;
 int *fd_percpu;
 int *fd_instr_count_percpu;
+int *fd_llc_percpu;
 struct timeval interval_tv = { 5, 0 };
 struct timespec interval_ts = { 5, 0 };
 
@@ -1992,6 +2003,10 @@ void pmt_counter_resize(struct pmt_counter *pcounter, unsigned int new_size)
 	pmt_counter_resize_(pcounter, new_size);
 }
 
+struct llc_stats {
+	unsigned long long references;
+	unsigned long long misses;
+};
 struct thread_data {
 	struct timeval tv_begin;
 	struct timeval tv_end;
@@ -2004,6 +2019,7 @@ struct thread_data {
 	unsigned long long irq_count;
 	unsigned long long nmi_count;
 	unsigned int smi_count;
+	struct llc_stats llc;
 	unsigned int cpu_id;
 	unsigned int apic_id;
 	unsigned int x2apic_id;
@@ -2363,23 +2379,19 @@ int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pk
 	return retval;
 }
 
-int is_cpu_first_thread_in_core(PER_THREAD_PARAMS)
+int is_cpu_first_thread_in_core(struct thread_data *t, struct core_data *c)
 {
-	UNUSED(p);
-
 	return ((int)t->cpu_id == c->base_cpu || c->base_cpu < 0);
 }
 
-int is_cpu_first_core_in_package(PER_THREAD_PARAMS)
+int is_cpu_first_core_in_package(struct thread_data *t, struct pkg_data *p)
 {
-	UNUSED(c);
-
 	return ((int)t->cpu_id == p->base_cpu || p->base_cpu < 0);
 }
 
-int is_cpu_first_thread_in_package(PER_THREAD_PARAMS)
+int is_cpu_first_thread_in_package(struct thread_data *t, struct core_data *c, struct pkg_data *p)
 {
-	return is_cpu_first_thread_in_core(t, c, p) && is_cpu_first_core_in_package(t, c, p);
+	return is_cpu_first_thread_in_core(t, c) && is_cpu_first_core_in_package(t, p);
 }
 
 int cpu_migrate(int cpu)
@@ -2657,6 +2669,12 @@ void bic_lookup(cpu_set_t *ret_set, char *name_list, enum show_hide_mode mode)
 			} else if (!strcmp(name_list, "idle")) {
 				CPU_OR(ret_set, ret_set, &bic_group_idle);
 				break;
+			} else if (!strcmp(name_list, "cache")) {
+				CPU_OR(ret_set, ret_set, &bic_group_cache);
+				break;
+			} else if (!strcmp(name_list, "llc")) {
+				CPU_OR(ret_set, ret_set, &bic_group_cache);
+				break;
 			} else if (!strcmp(name_list, "swidle")) {
 				CPU_OR(ret_set, ret_set, &bic_group_sw_idle);
 				break;
@@ -2794,6 +2812,12 @@ void print_header(char *delim)
 	if (DO_BIC(BIC_SMI))
 		outp += sprintf(outp, "%sSMI", (printed++ ? delim : ""));
 
+	if (DO_BIC(BIC_LLC_RPS))
+		outp += sprintf(outp, "%sLLCkRPS", (printed++ ? delim : ""));
+
+	if (DO_BIC(BIC_LLC_HIT))
+		outp += sprintf(outp, "%sLLC%%hit", (printed++ ? delim : ""));
+
 	for (mp = sys.tp; mp; mp = mp->next)
 		outp += print_name(mp->width, &printed, delim, mp->name);
 
@@ -2864,7 +2888,6 @@ void print_header(char *delim)
 
 		ppmt = ppmt->next;
 	}
-
 	if (DO_BIC(BIC_PkgTmp))
 		outp += sprintf(outp, "%sPkgTmp", (printed++ ? delim : ""));
 
@@ -3001,6 +3024,10 @@ int dump_counters(PER_THREAD_PARAMS)
 		if (DO_BIC(BIC_SMI))
 			outp += sprintf(outp, "SMI: %d\n", t->smi_count);
 
+		outp += sprintf(outp, "LLC refs: %lld", t->llc.references);
+		outp += sprintf(outp, "LLC miss: %lld", t->llc.misses);
+		outp += sprintf(outp, "LLC Hit%%: %.2f", 100.0 * (t->llc.references - t->llc.misses) / t->llc.references);
+
 		for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
 			outp +=
 			    sprintf(outp, "tADDED [%d] %8s msr0x%x: %08llX %s\n", i, mp->name, mp->msr_num,
@@ -3008,7 +3035,7 @@ int dump_counters(PER_THREAD_PARAMS)
 		}
 	}
 
-	if (c && is_cpu_first_thread_in_core(t, c, p)) {
+	if (c && is_cpu_first_thread_in_core(t, c)) {
 		outp += sprintf(outp, "core: %d\n", c->core_id);
 		outp += sprintf(outp, "c3: %016llX\n", c->c3);
 		outp += sprintf(outp, "c6: %016llX\n", c->c6);
@@ -3030,7 +3057,7 @@ int dump_counters(PER_THREAD_PARAMS)
 		outp += sprintf(outp, "mc6_us: %016llX\n", c->mc6_us);
 	}
 
-	if (p && is_cpu_first_core_in_package(t, c, p)) {
+	if (p && is_cpu_first_core_in_package(t, p)) {
 		outp += sprintf(outp, "package: %d\n", p->package_id);
 
 		outp += sprintf(outp, "Weighted cores: %016llX\n", p->pkg_wtd_core_c0);
@@ -3088,6 +3115,23 @@ double rapl_counter_get_value(const struct rapl_counter *c, enum rapl_unit desir
 	return scaled;
 }
 
+void get_perf_llc_stats(int cpu, struct llc_stats *llc)
+{
+	struct read_format {
+		unsigned long long num_read;
+		struct llc_stats llc;
+	} r;
+	const ssize_t expected_read_size = sizeof(r);
+	ssize_t actual_read_size;
+
+	actual_read_size = read(fd_llc_percpu[cpu], &r, expected_read_size);
+
+	llc->references = r.llc.references;
+	llc->misses = r.llc.misses;
+	if (actual_read_size != expected_read_size)
+		warn("%s: failed to read perf_data (req %zu act %zu)", __func__, expected_read_size, actual_read_size);
+}
+
 /*
  * column formatting convention & formats
  */
@@ -3097,7 +3141,8 @@ int format_counters(PER_THREAD_PARAMS)
 
 	struct platform_counters *pplat_cnt = NULL;
 	double interval_float, tsc;
-	char *fmt8;
+	char *fmt8 = "%s%.2f";
+
 	int i;
 	struct msr_counter *mp;
 	struct perf_counter_info *pp;
@@ -3111,11 +3156,11 @@ int format_counters(PER_THREAD_PARAMS)
 	}
 
 	/* 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))
+	if (show_core_only && !is_cpu_first_thread_in_core(t, c))
 		return 0;
 
 	/* if showing only 1st thread in pkg and this isn't one, bail out */
-	if (show_pkg_only && !is_cpu_first_core_in_package(t, c, p))
+	if (show_pkg_only && !is_cpu_first_core_in_package(t, p))
 		return 0;
 
 	/*if not summary line and --cpu is used */
@@ -3237,6 +3282,16 @@ int format_counters(PER_THREAD_PARAMS)
 	if (DO_BIC(BIC_SMI))
 		outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->smi_count);
 
+	/* LLC Stats */
+	if (DO_BIC(BIC_LLC_RPS) || DO_BIC(BIC_LLC_HIT)) {
+		if (DO_BIC(BIC_LLC_RPS))
+			outp += sprintf(outp, "%s%.0f", (printed++ ? delim : ""), t->llc.references / interval_float / 1000);
+
+		if (DO_BIC(BIC_LLC_HIT))
+			outp += sprintf(outp, fmt8, (printed++ ? delim : ""), 100.0 * (t->llc.references - t->llc.misses) / t->llc.references);
+	}
+
+
 	/* Added Thread Counters */
 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
 		if (mp->format == FORMAT_RAW)
@@ -3290,7 +3345,7 @@ int format_counters(PER_THREAD_PARAMS)
 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * t->c1 / tsc);
 
 	/* print per-core data only for 1st thread in core */
-	if (!is_cpu_first_thread_in_core(t, c, p))
+	if (!is_cpu_first_thread_in_core(t, c))
 		goto done;
 
 	if (DO_BIC(BIC_CPU_c3))
@@ -3351,8 +3406,6 @@ int format_counters(PER_THREAD_PARAMS)
 		}
 	}
 
-	fmt8 = "%s%.2f";
-
 	if (DO_BIC(BIC_CorWatt) && platform->has_per_core_rapl)
 		outp +=
 		    sprintf(outp, fmt8, (printed++ ? delim : ""),
@@ -3362,7 +3415,7 @@ int format_counters(PER_THREAD_PARAMS)
 				rapl_counter_get_value(&c->core_energy, RAPL_UNIT_JOULES, interval_float));
 
 	/* print per-package data only for 1st core in package */
-	if (!is_cpu_first_core_in_package(t, c, p))
+	if (!is_cpu_first_core_in_package(t, p))
 		goto done;
 
 	/* PkgTmp */
@@ -3808,6 +3861,12 @@ int delta_thread(struct thread_data *new, struct thread_data *old, struct core_d
 	if (DO_BIC(BIC_SMI))
 		old->smi_count = new->smi_count - old->smi_count;
 
+	if (DO_BIC(BIC_LLC_RPS))
+		old->llc.references = new->llc.references - old->llc.references;
+
+	if (DO_BIC(BIC_LLC_HIT))
+		old->llc.misses = new->llc.misses - old->llc.misses;
+
 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
 		if (mp->format == FORMAT_RAW || mp->format == FORMAT_AVERAGE)
 			old->counter[i] = new->counter[i];
@@ -3838,14 +3897,14 @@ int delta_cpu(struct thread_data *t, struct core_data *c,
 	int retval = 0;
 
 	/* calculate core delta only for 1st thread in core */
-	if (is_cpu_first_thread_in_core(t, c, p))
+	if (is_cpu_first_thread_in_core(t, c))
 		delta_core(c, c2);
 
 	/* always calculate thread delta */
 	retval = delta_thread(t, t2, c2);	/* c2 is core delta */
 
 	/* calculate package delta only for 1st core in package */
-	if (is_cpu_first_core_in_package(t, c, p))
+	if (is_cpu_first_core_in_package(t, p))
 		retval |= delta_package(p, p2);
 
 	return retval;
@@ -3886,6 +3945,9 @@ void clear_counters(PER_THREAD_PARAMS)
 	t->nmi_count = 0;
 	t->smi_count = 0;
 
+	t->llc.references = 0;
+	t->llc.misses = 0;
+
 	c->c3 = 0;
 	c->c6 = 0;
 	c->c7 = 0;
@@ -3894,6 +3956,9 @@ void clear_counters(PER_THREAD_PARAMS)
 	rapl_counter_clear(&c->core_energy);
 	c->core_throt_cnt = 0;
 
+	t->llc.references = 0;
+	t->llc.misses = 0;
+
 	p->pkg_wtd_core_c0 = 0;
 	p->pkg_any_core_c0 = 0;
 	p->pkg_any_gfxe_c0 = 0;
@@ -3991,6 +4056,9 @@ int sum_counters(PER_THREAD_PARAMS)
 	average.threads.nmi_count += t->nmi_count;
 	average.threads.smi_count += t->smi_count;
 
+	average.threads.llc.references += t->llc.references;
+	average.threads.llc.misses += t->llc.misses;
+
 	for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
 		if (mp->format == FORMAT_RAW)
 			continue;
@@ -4008,7 +4076,7 @@ int sum_counters(PER_THREAD_PARAMS)
 	}
 
 	/* sum per-core values only for 1st thread in core */
-	if (!is_cpu_first_thread_in_core(t, c, p))
+	if (!is_cpu_first_thread_in_core(t, c))
 		return 0;
 
 	average.cores.c3 += c->c3;
@@ -4038,7 +4106,7 @@ int sum_counters(PER_THREAD_PARAMS)
 	}
 
 	/* sum per-pkg values only for 1st core in pkg */
-	if (!is_cpu_first_core_in_package(t, c, p))
+	if (!is_cpu_first_core_in_package(t, p))
 		return 0;
 
 	if (DO_BIC(BIC_Totl_c0))
@@ -5009,6 +5077,9 @@ int get_counters(PER_THREAD_PARAMS)
 
 	get_smi_aperf_mperf(cpu, t);
 
+	if (DO_BIC(BIC_LLC_RPS) || DO_BIC(BIC_LLC_HIT))
+		get_perf_llc_stats(cpu, &t->llc);
+
 	if (DO_BIC(BIC_IPC))
 		if (read(get_instr_count_fd(cpu), &t->instr_count, sizeof(long long)) != sizeof(long long))
 			return -4;
@@ -5032,7 +5103,7 @@ int get_counters(PER_THREAD_PARAMS)
 		t->pmt_counter[i] = pmt_read_counter(pp, t->cpu_id);
 
 	/* collect core counters only for 1st thread in core */
-	if (!is_cpu_first_thread_in_core(t, c, p))
+	if (!is_cpu_first_thread_in_core(t, c))
 		goto done;
 
 	if (platform->has_per_core_rapl) {
@@ -5076,7 +5147,7 @@ int get_counters(PER_THREAD_PARAMS)
 		c->pmt_counter[i] = pmt_read_counter(pp, c->core_id);
 
 	/* collect package counters only for 1st core in package */
-	if (!is_cpu_first_core_in_package(t, c, p))
+	if (!is_cpu_first_core_in_package(t, p))
 		goto done;
 
 	if (DO_BIC(BIC_Totl_c0)) {
@@ -5631,6 +5702,20 @@ void free_fd_instr_count_percpu(void)
 	fd_instr_count_percpu = NULL;
 }
 
+void free_fd_llc_percpu(void)
+{
+	if (!fd_llc_percpu)
+		return;
+
+	for (int i = 0; i < topo.max_cpu_num + 1; ++i) {
+		if (fd_llc_percpu[i] != 0)
+			close(fd_llc_percpu[i]);
+	}
+
+	free(fd_llc_percpu);
+	fd_llc_percpu = NULL;
+}
+
 void free_fd_cstate(void)
 {
 	if (!ccstate_counter_info)
@@ -5755,6 +5840,7 @@ void free_all_buffers(void)
 
 	free_fd_percpu();
 	free_fd_instr_count_percpu();
+	free_fd_llc_percpu();
 	free_fd_msr();
 	free_fd_rapl_percpu();
 	free_fd_cstate();
@@ -6101,6 +6187,7 @@ void linux_perf_init(void);
 void msr_perf_init(void);
 void rapl_perf_init(void);
 void cstate_perf_init(void);
+void perf_llc_init(void);
 void added_perf_counters_init(void);
 void pmt_init(void);
 
@@ -6112,6 +6199,7 @@ void re_initialize(void)
 	msr_perf_init();
 	rapl_perf_init();
 	cstate_perf_init();
+	perf_llc_init();
 	added_perf_counters_init();
 	pmt_init();
 	fprintf(outf, "turbostat: re-initialized with num_cpus %d, allowed_cpus %d\n", topo.num_cpus,
@@ -7976,7 +8064,7 @@ int print_thermal(PER_THREAD_PARAMS)
 	cpu = t->cpu_id;
 
 	/* DTS is per-core, no need to print for each thread */
-	if (!is_cpu_first_thread_in_core(t, c, p))
+	if (!is_cpu_first_thread_in_core(t, c))
 		return 0;
 
 	if (cpu_migrate(cpu)) {
@@ -7984,7 +8072,7 @@ int print_thermal(PER_THREAD_PARAMS)
 		return -1;
 	}
 
-	if (do_ptm && is_cpu_first_core_in_package(t, c, p)) {
+	if (do_ptm && is_cpu_first_core_in_package(t, p)) {
 		if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr))
 			return 0;
 
@@ -8263,6 +8351,11 @@ void linux_perf_init(void)
 		if (fd_instr_count_percpu == NULL)
 			err(-1, "calloc fd_instr_count_percpu");
 	}
+	if (BIC_IS_ENABLED(BIC_LLC_RPS) && has_aperf) {
+		fd_llc_percpu = calloc(topo.max_cpu_num + 1, sizeof(int));
+		if (fd_llc_percpu == NULL)
+			err(-1, "calloc fd_llc_percpu");
+	}
 }
 
 void rapl_perf_init(void)
@@ -8933,6 +9026,33 @@ void probe_pm_features(void)
 		decode_misc_feature_control();
 }
 
+void perf_llc_init(void)
+{
+	int cpu;
+	int retval;
+
+	for (cpu = 0; cpu < topo.max_cpu_num; ++cpu) {
+
+		if (cpu_is_not_allowed(cpu))
+			continue;
+
+		fd_llc_percpu[cpu] = open_perf_counter(cpu, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES, -1, PERF_FORMAT_GROUP);
+		if (fd_llc_percpu[cpu] == -1) {
+			warnx("%s: perf REFS: failed to open counter on cpu%d", __func__, cpu);
+			free_fd_llc_percpu();
+			return;
+		}
+		retval = open_perf_counter(cpu, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES, fd_llc_percpu[cpu], PERF_FORMAT_GROUP);
+		if (retval == -1) {
+			warnx("%s: perf MISS: failed to open counter on cpu%d", __func__, cpu);
+			free_fd_llc_percpu();
+			return;
+		}
+	}
+	BIC_PRESENT(BIC_LLC_RPS);
+	BIC_PRESENT(BIC_LLC_HIT);
+}
+
 /*
  * in /dev/cpu/ return success for names that are numbers
  * ie. filter out ".", "..", "microcode".
@@ -9239,6 +9359,7 @@ void init_counter(struct thread_data *thread_base, struct core_data *core_base,
 
 	t->cpu_id = cpu_id;
 	if (!cpu_is_not_allowed(cpu_id)) {
+
 		if (c->base_cpu < 0)
 			c->base_cpu = t->cpu_id;
 		if (pkg_base[pkg_id].base_cpu < 0)
@@ -9909,6 +10030,7 @@ void turbostat_init()
 	linux_perf_init();
 	rapl_perf_init();
 	cstate_perf_init();
+	perf_llc_init();
 	added_perf_counters_init();
 	pmt_init();
 
@@ -10014,7 +10136,7 @@ int get_and_dump_counters(void)
 
 void print_version()
 {
-	fprintf(outf, "turbostat version 2025.10.18 - Len Brown <lenb@kernel.org>\n");
+	fprintf(outf, "turbostat version 2025.10.24 - Len Brown <lenb@kernel.org>\n");
 }
 
 #define COMMAND_LINE_SIZE 2048
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-10-24 15:46 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-24 15:38 PATCH[0/8] turbostat updates through 2025.10.24 Len Brown
2025-10-24 15:38 ` [PATCH 1/8] tools/power turbostat: Regression fix Uncore MHz printed in hex Len Brown
2025-10-24 15:38   ` [PATCH 2/8] tools/power turbostat: Add Wildcat Lake and Nova Lake support Len Brown
2025-10-24 15:38   ` [PATCH 3/8] tools/power turbostat: Refactor added column header printing Len Brown
2025-10-24 15:38   ` [PATCH 4/8] tools/power turbostat: Refactor added-counter value printing code Len Brown
2025-10-24 15:38   ` [PATCH 5/8] tools/power turbostat.8: Update example Len Brown
2025-10-24 15:38   ` [PATCH 6/8] tools/power turbostat: Refactor floating point printout code Len Brown
2025-10-24 15:38   ` [PATCH 7/8] tools/power turbostat: Remove dead code Len Brown
2025-10-24 15:38   ` [PATCH 8/8] tools/power turbostat: Add LLC stats Len Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).