Skip to contentSkip to conversation

cpupower improvements on AMD systems

PATCH In review Mario Limonciello 2 participants 9 messages Dec 18, 2024 – Dec 20, 2024 CPU power monitoring

lore
Share & tools
lore
#0 lore raw

cover cpupower improvements on AMD systems

From: Mario Limonciello <[email protected]>

cpupower shows a number of errors on AMD systems configured in 'active' mode where the hardware transitions states for the user.

Clean up those errors and add some extra information for the amd-pstate preferred core feature.

Mario Limonciello (7):
cpupower: Remove spurious return statement
cpupower: Add support for parsing 'enabled' or 'disabled' strings from
table
cpupower: Add support for amd-pstate preferred core rankings
cpupower: Don't try to read frequency from hardware when kernel uses
aperfmperf
cpupower: Add support for showing energy performance preference
cpupower: Don't fetch maximum latency when EPP is enabled
cpupower: Adjust whitespace for amd-pstate specific prints

 tools/power/cpupower/lib/cpufreq.c        | 18 ++++++++++++
 tools/power/cpupower/lib/cpufreq.h        |  8 +++++
 tools/power/cpupower/utils/cpufreq-info.c | 36 +++++++++++++++++++++--
 tools/power/cpupower/utils/helpers/amd.c  | 18 +++++++++---
 4 files changed, 73 insertions(+), 7 deletions(-)
Signature · 1 line
2.43.0
#1 lore raw

PATCH 1/7 cpupower: Remove spurious return statement

From: Mario Limonciello <[email protected]>

print_duration() has a return; statement at the end of the function that is not necessary as it's a void function.

---
 tools/power/cpupower/utils/cpufreq-info.c | 1 -
 1 file changed, 1 deletion(-)
tools/power/cpupower/utils/cpufreq-info.c +0 -1
index c96b77365c637..5f092f3c729e7 100644
@@ -120,7 +120,6 @@ static void print_duration(unsigned long duration)
 		} else
 			printf("%lu ns", duration);
 	}
-	return;
 }
 
 static int get_boost_mode_x86(unsigned int cpu)
Signature · 1 line
2.43.0
#2 lore raw

PATCH 2/7 cpupower: Add support for parsing 'enabled' or 'disabled' strings from table

In reply to Mario Limonciello

From: Mario Limonciello <[email protected]>

When cpufreq_get_sysfs_value_from_table() is passed a table with kernel strings that report 'enabled' or 'disabled' it always returns 0 because these can't cleanly convert to integers.

Explicitly look for enabled or disabled strings from the kernel to handle this.

---
 tools/power/cpupower/lib/cpufreq.c | 4 ++++
 1 file changed, 4 insertions(+)
tools/power/cpupower/lib/cpufreq.c +4 -0
index 1516d23c17c98..f27ee6d4b000c 100644
@@ -102,6 +102,10 @@ unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
 	if (len == 0)
 		return 0;
 
+	if (!strcmp(linebuf, "enabled\n"))
+		return 1;
+	if (!strcmp(linebuf, "disabled\n"))
+		return 0;
 	value = strtoul(linebuf, &endp, 0);
 
 	if (endp == linebuf || errno == ERANGE)
Signature · 1 line
2.43.0
#3 lore raw

PATCH 3/7 cpupower: Add support for amd-pstate preferred core rankings

In reply to Mario Limonciello

From: Mario Limonciello <[email protected]>

The rankings are useful information to determine if the scheduler is placing tasks appropriately for the hardware.

---
 tools/power/cpupower/utils/helpers/amd.c | 8 ++++++++
 1 file changed, 8 insertions(+)
tools/power/cpupower/utils/helpers/amd.c +8 -0
index 0a56e22240fc8..090fdd6d15510 100644
@@ -177,6 +177,8 @@ enum amd_pstate_value {
 	AMD_PSTATE_HIGHEST_PERF,
 	AMD_PSTATE_MAX_FREQ,
 	AMD_PSTATE_LOWEST_NONLINEAR_FREQ,
+	AMD_PSTATE_HW_PREFCORE,
+	AMD_PSTATE_PREFCORE_RANKING,
 	MAX_AMD_PSTATE_VALUE_READ_FILES,
 };
 
@@ -184,6 +186,8 @@ static const char *amd_pstate_value_files[MAX_AMD_PSTATE_VALUE_READ_FILES] = {
 	[AMD_PSTATE_HIGHEST_PERF] = "amd_pstate_highest_perf",
 	[AMD_PSTATE_MAX_FREQ] = "amd_pstate_max_freq",
 	[AMD_PSTATE_LOWEST_NONLINEAR_FREQ] = "amd_pstate_lowest_nonlinear_freq",
+	[AMD_PSTATE_HW_PREFCORE] = "amd_pstate_hw_prefcore",
+	[AMD_PSTATE_PREFCORE_RANKING] = "amd_pstate_prefcore_ranking",
 };
 
 static unsigned long amd_pstate_get_data(unsigned int cpu,
@@ -240,6 +244,10 @@ void amd_pstate_show_perf_and_freq(unsigned int cpu, int no_rounding)
 	       acpi_cppc_get_data(cpu, LOWEST_PERF));
 	print_speed(acpi_cppc_get_data(cpu, LOWEST_FREQ) * 1000, no_rounding);
 	printf(".\n");
+
+	printf(_("    Preferred Core Support: %lu. Preferred Core Ranking: %lu.\n"),
+	       amd_pstate_get_data(cpu, AMD_PSTATE_HW_PREFCORE),
+	       amd_pstate_get_data(cpu, AMD_PSTATE_PREFCORE_RANKING));
 }
 
 /* AMD P-State Helper Functions ************************************/
Signature · 1 line
2.43.0
#4 lore raw

PATCH 4/7 cpupower: Don't try to read frequency from hardware when kernel uses aperfmperf

In reply to Mario Limonciello

From: Mario Limonciello <[email protected]>

When the amd-pstate is in use frequency is set by the hardware and measured by the kernel through using the aperf and mperf registers.

There is no direct call to the hardware to indicate current frequency.

Detect that this feature is in use and skip the check.

---
 tools/power/cpupower/utils/cpufreq-info.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
tools/power/cpupower/utils/cpufreq-info.c +6 -1
index 5f092f3c729e7..3df28e45be421 100644
@@ -254,7 +254,12 @@ static int get_freq_kernel(unsigned int cpu, unsigned int human)
 
 static int get_freq_hardware(unsigned int cpu, unsigned int human)
 {
-	unsigned long freq = cpufreq_get_freq_hardware(cpu);
+	unsigned long freq;
+
+	if (cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)
+		return -EINVAL;
+
+	freq = cpufreq_get_freq_hardware(cpu);
 	printf(_("  current CPU frequency: "));
 	if (!freq) {
 		printf("Unable to call hardware\n");
Signature · 1 line
2.43.0
#5 lore raw

PATCH 5/7 cpupower: Add support for showing energy performance preference

In reply to Mario Limonciello

From: Mario Limonciello <[email protected]>

The EPP value is useful for characterization of performance. Show it in cpupower frequency-info output.

---
 tools/power/cpupower/lib/cpufreq.c        | 14 +++++++++++++
 tools/power/cpupower/lib/cpufreq.h        |  8 ++++++++
 tools/power/cpupower/utils/cpufreq-info.c | 25 ++++++++++++++++++++++-
 3 files changed, 46 insertions(+), 1 deletion(-)
tools/power/cpupower/lib/cpufreq.c +14 -0
index f27ee6d4b000c..8dda3db2dff0e 100644
@@ -127,12 +127,14 @@ static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
 enum cpufreq_string {
 	SCALING_DRIVER,
 	SCALING_GOVERNOR,
+	ENERGY_PERFORMANCE_PREFERENCE,
 	MAX_CPUFREQ_STRING_FILES
 };
 
 static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = {
 	[SCALING_DRIVER] = "scaling_driver",
 	[SCALING_GOVERNOR] = "scaling_governor",
+	[ENERGY_PERFORMANCE_PREFERENCE] = "energy_performance_preference",
 };
 
 
@@ -207,6 +209,18 @@ unsigned long cpufreq_get_transition_latency(unsigned int cpu)
 	return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY);
 }
 
+char *cpufreq_get_energy_performance_preference(unsigned int cpu)
+{
+	return sysfs_cpufreq_get_one_string(cpu, ENERGY_PERFORMANCE_PREFERENCE);
+}
+
+void cpufreq_put_energy_performance_preference(char *ptr)
+{
+	if (!ptr)
+		return;
+	free(ptr);
+}
+
 int cpufreq_get_hardware_limits(unsigned int cpu,
 				unsigned long *min,
 				unsigned long *max)
tools/power/cpupower/lib/cpufreq.h +8 -0
index 2f3c840358063..bfc617311ebd6 100644
@@ -68,6 +68,14 @@ unsigned long cpufreq_get_freq_hardware(unsigned int cpu);
 unsigned long cpufreq_get_transition_latency(unsigned int cpu);
 
 
+/* determine energy performance preference
+ *
+ * returns NULL on failure, else the string that represents the energy performance
+ * preference requested.
+ */
+char *cpufreq_get_energy_performance_preference(unsigned int cpu);
+void cpufreq_put_energy_performance_preference(char *ptr);
+
 /* determine hardware CPU frequency limits
  *
  * These may be limited further by thermal, energy or other
tools/power/cpupower/utils/cpufreq-info.c +24 -1
index 3df28e45be421..eb9cc0f106342 100644
@@ -422,6 +422,23 @@ static int get_freq_stats(unsigned int cpu, unsigned int human)
 	return 0;
 }
 
+/* --epp / -z */
+
+static int get_epp(unsigned int cpu, bool interactive)
+{
+	char *epp;
+
+	epp = cpufreq_get_energy_performance_preference(cpu);
+	if (!epp)
+		return -EINVAL;
+	if (interactive)
+		printf(_("  energy performance preference: %s\n"), epp);
+
+	cpufreq_put_energy_performance_preference(epp);
+
+	return 0;
+}
+
 /* --latency / -y */
 
 static int get_latency(unsigned int cpu, unsigned int human)
@@ -461,6 +478,7 @@ static void debug_output_one(unsigned int cpu)
 	get_related_cpus(cpu);
 	get_affected_cpus(cpu);
 	get_latency(cpu, 1);
+	get_epp(cpu, true);
 	get_hardware_limits(cpu, 1);
 
 	freqs = cpufreq_get_available_frequencies(cpu);
@@ -501,6 +519,7 @@ static struct option info_opts[] = {
 	{"human",	 no_argument,		 NULL,	 'm'},
 	{"no-rounding", no_argument,	 NULL,	 'n'},
 	{"performance", no_argument,	 NULL,	 'c'},
+	{"epp",		 no_argument,		 NULL,	 'z'},
 	{ },
 };
 
@@ -514,7 +533,7 @@ int cmd_freq_info(int argc, char **argv)
 	int output_param = 0;
 
 	do {
-		ret = getopt_long(argc, argv, "oefwldpgrasmybnc", info_opts,
+		ret = getopt_long(argc, argv, "oefwldpgrasmybncz", info_opts,
 				  NULL);
 		switch (ret) {
 		case '?':
@@ -538,6 +557,7 @@ int cmd_freq_info(int argc, char **argv)
 		case 's':
 		case 'y':
 		case 'c':
+		case 'z':
 			if (output_param) {
 				output_param = -1;
 				cont = 0;
@@ -647,6 +667,9 @@ int cmd_freq_info(int argc, char **argv)
 		case 'c':
 			ret = get_perf_cap(cpu);
 			break;
+		case 'z':
+			ret = get_epp(cpu, true);
+			break;
 		}
 		if (ret)
 			return ret;
Signature · 1 line
2.43.0
#6 lore raw

PATCH 6/7 cpupower: Don't fetch maximum latency when EPP is enabled

In reply to Mario Limonciello

From: Mario Limonciello <[email protected]>

When EPP has been enabled the hardware will autonomously change frequencies on it's own and thus there is no latency with changing from the kernel.

Avoid doing the maximum latency check when EPP is found. This will apply to both amd-pstate and intel-pstate drivers.

---
 tools/power/cpupower/utils/cpufreq-info.c | 3 +++
 1 file changed, 3 insertions(+)
tools/power/cpupower/utils/cpufreq-info.c +3 -0
index eb9cc0f106342..fc750e127404c 100644
@@ -445,6 +445,9 @@ static int get_latency(unsigned int cpu, unsigned int human)
 {
 	unsigned long latency = cpufreq_get_transition_latency(cpu);
 
+	if (!get_epp(cpu, false))
+		return -EINVAL;
+
 	printf(_("  maximum transition latency: "));
 	if (!latency || latency == UINT_MAX) {
 		printf(_(" Cannot determine or is not supported.\n"));
Signature · 1 line
2.43.0
#7 lore raw

PATCH 7/7 cpupower: Adjust whitespace for amd-pstate specific prints

In reply to Mario Limonciello

From: Mario Limonciello <[email protected]>

The amd-pstate section is grouped under boost, which isn't appropriate.

Adjust the indentation so that it is it's own section.

---
 tools/power/cpupower/utils/helpers/amd.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
tools/power/cpupower/utils/helpers/amd.c +6 -4
index 090fdd6d15510..795562e879dee 100644
@@ -219,7 +219,9 @@ void amd_pstate_boost_init(unsigned int cpu, int *support, int *active)
 
 void amd_pstate_show_perf_and_freq(unsigned int cpu, int no_rounding)
 {
-	printf(_("    AMD PSTATE Highest Performance: %lu. Maximum Frequency: "),
+
+	printf(_("  amd-pstate limits:\n"));
+	printf(_("    Highest Performance: %lu. Maximum Frequency: "),
 	       amd_pstate_get_data(cpu, AMD_PSTATE_HIGHEST_PERF));
 	/*
 	 * If boost isn't active, the cpuinfo_max doesn't indicate real max
@@ -228,19 +230,19 @@ void amd_pstate_show_perf_and_freq(unsigned int cpu, int no_rounding)
 	print_speed(amd_pstate_get_data(cpu, AMD_PSTATE_MAX_FREQ), no_rounding);
 	printf(".\n");
 
-	printf(_("    AMD PSTATE Nominal Performance: %lu. Nominal Frequency: "),
+	printf(_("    Nominal Performance: %lu. Nominal Frequency: "),
 	       acpi_cppc_get_data(cpu, NOMINAL_PERF));
 	print_speed(acpi_cppc_get_data(cpu, NOMINAL_FREQ) * 1000,
 		    no_rounding);
 	printf(".\n");
 
-	printf(_("    AMD PSTATE Lowest Non-linear Performance: %lu. Lowest Non-linear Frequency: "),
+	printf(_("    Lowest Non-linear Performance: %lu. Lowest Non-linear Frequency: "),
 	       acpi_cppc_get_data(cpu, LOWEST_NONLINEAR_PERF));
 	print_speed(amd_pstate_get_data(cpu, AMD_PSTATE_LOWEST_NONLINEAR_FREQ),
 		    no_rounding);
 	printf(".\n");
 
-	printf(_("    AMD PSTATE Lowest Performance: %lu. Lowest Frequency: "),
+	printf(_("    Lowest Performance: %lu. Lowest Frequency: "),
 	       acpi_cppc_get_data(cpu, LOWEST_PERF));
 	print_speed(acpi_cppc_get_data(cpu, LOWEST_FREQ) * 1000, no_rounding);
 	printf(".\n");
Signature · 1 line
2.43.0
maintainer
#8 lore raw
In reply to Mario Limonciello
Quoted 20 lines · Mario Limonciello

From: Mario Limonciello <[email protected]>

cpupower shows a number of errors on AMD systems configured in 'active' mode where the hardware transitions states for the user.

Clean up those errors and add some extra information for the amd-pstate preferred core feature.

Mario Limonciello (7):
cpupower: Remove spurious return statement
cpupower: Add support for parsing 'enabled' or 'disabled' strings from
table
cpupower: Add support for amd-pstate preferred core rankings
cpupower: Don't try to read frequency from hardware when kernel uses
aperfmperf
cpupower: Add support for showing energy performance preference
cpupower: Don't fetch maximum latency when EPP is enabled
cpupower: Adjust whitespace for amd-pstate specific prints

Quoted 6 lines
  tools/power/cpupower/lib/cpufreq.c        | 18 ++++++++++++
  tools/power/cpupower/lib/cpufreq.h        |  8 +++++
  tools/power/cpupower/utils/cpufreq-info.c | 36 +++++++++++++++++++++--
  tools/power/cpupower/utils/helpers/amd.c  | 18 +++++++++---
  4 files changed, 73 insertions(+), 7 deletions(-)

Thank you. The patch series is now in

https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux.git/log/?h=cpupower

I will include this in pull request to Rafael in early January.

thanks,
-- Shuah