Commit 2ff1bc41 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'power-utilities-2026.04.25' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux

Pull power utility updates from Len Brown:
 "x86_energy_perf_policy:
   - Initial SoC Slider support

 turbostat:
   - Display HT siblings in cpu# order
   - Add Module-ID column
   - Print Core-ID and APIC-ID in hex
   - Fix misc bugs"

* tag 'power-utilities-2026.04.25' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux:
  tools/power x86_energy_perf_policy: Version 2026.04.25
  tools/power x86_energy_perf_policy.8: Document SoC Slider Options
  tools/power x86_energy_perf_policy: Enhances SoC Slider related checks
  tools/power turbostat: v2026.04.21
  tools/power turbostat: Process HT siblings in CPU order
  tools/power turbostat: Show module_id column
  tools/power turbostat: Print core_id and apic_id in hex
  tools/power turbostat: Cleanup print helper functions
  tools/power turbostat: Fix --cpu-set 1 regression on HT systems
  tools/power turbostat: Fix --cpu-set 0 regression on HT systems
  tools/power turbostat: Fix unrecognized option '-P'
  tools/power turbostat: Fix AMD RAPL regression on big systems
  tools/power/x86: Add SOC slider and platform profile support
parents 211d5933 6112da1e
Loading
Loading
Loading
Loading
+153 −78
Original line number Diff line number Diff line
@@ -191,6 +191,7 @@ struct msr_counter bic[] = {
	{ 0x0, "Any%C0", NULL, 0, 0, 0, NULL, 0 },
	{ 0x0, "GFX%C0", NULL, 0, 0, 0, NULL, 0 },
	{ 0x0, "CPUGFX%", NULL, 0, 0, 0, NULL, 0 },
	{ 0x0, "Module", NULL, 0, 0, 0, NULL, 0 },
	{ 0x0, "Core", NULL, 0, 0, 0, NULL, 0 },
	{ 0x0, "CPU", NULL, 0, 0, 0, NULL, 0 },
	{ 0x0, "APIC", NULL, 0, 0, 0, NULL, 0 },
@@ -264,6 +265,7 @@ enum bic_names {
	BIC_Any_c0,
	BIC_GFX_c0,
	BIC_CPUGFX,
	BIC_Module,
	BIC_Core,
	BIC_CPU,
	BIC_APIC,
@@ -364,6 +366,7 @@ static void bic_groups_init(void)
	SET_BIC(BIC_Node, &bic_group_topology);
	SET_BIC(BIC_CoreCnt, &bic_group_topology);
	SET_BIC(BIC_PkgCnt, &bic_group_topology);
	SET_BIC(BIC_Module, &bic_group_topology);
	SET_BIC(BIC_Core, &bic_group_topology);
	SET_BIC(BIC_CPU, &bic_group_topology);
	SET_BIC(BIC_Die, &bic_group_topology);
@@ -2383,6 +2386,7 @@ struct platform_counters {
struct cpu_topology {
	int cpu_id;
	int core_id;		/* unique within a package */
	int module_id;
	int package_id;
	int die_id;
	int l3_id;
@@ -2404,6 +2408,8 @@ struct topo_params {
	int allowed_cores;
	int max_cpu_num;
	int max_core_id;	/* within a package */
	int min_module_id;	/* system wide */
	int max_module_id;	/* system wide */
	int max_package_id;
	int max_die_id;
	int max_l3_id;
@@ -2427,11 +2433,17 @@ char *sys_lpi_file_debugfs = "/sys/kernel/debug/pmc_core/slp_s0_residency_usec";

int cpu_is_not_present(int cpu)
{
	if (cpu < 0)
		return 1;

	return !CPU_ISSET_S(cpu, cpu_present_setsize, cpu_present_set);
}

int cpu_is_not_allowed(int cpu)
{
	if (cpu < 0)
		return 1;

	return !CPU_ISSET_S(cpu, cpu_allowed_setsize, cpu_allowed_set);
}

@@ -2443,6 +2455,22 @@ int cpu_is_not_allowed(int cpu)

#define PER_THREAD_PARAMS  struct thread_data *t, struct core_data *c, struct pkg_data *p

int has_allowed_lower_ht_sibling(int cpu)
{
	int i;

	for (i = 0; i <= cpus[cpu].ht_id; ++i) {
		int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i];

		if (sibling_cpu_id == cpu)
			return 0;

		if (!cpu_is_not_allowed(sibling_cpu_id))
			return 1;
	}
	return 0;
}

int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pkg_data *),
		 struct thread_data *thread_base, struct core_data *core_base, struct pkg_data *pkg_base)
{
@@ -2460,7 +2488,7 @@ int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pk
		if (cpu_is_not_allowed(cpu))
			continue;

		if (cpus[cpu].ht_id > 0)	/* skip HT sibling */
		if (has_allowed_lower_ht_sibling(cpu))	/* skip HT sibling */
			continue;

		t = &thread_base[cpu];
@@ -2469,13 +2497,22 @@ int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pk

		retval |= func(t, c, p);

		/* Handle HT sibling now */
		/* Handle other HT siblings now */
		int i;

		for (i = MAX_HT_ID; i > 0; --i) {	/* ht_id 0 is self */
			if (cpus[cpu].ht_sibling_cpu_id[i] <= 0)
		for (i = 0; i <= MAX_HT_ID; ++i) {
			int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i];

			if (sibling_cpu_id < 0)
				break;

			if (sibling_cpu_id == cpu)
				continue;
			t = &thread_base[cpus[cpu].ht_sibling_cpu_id[i]];

			if (cpu_is_not_allowed(sibling_cpu_id))
				continue;

			t = &thread_base[sibling_cpu_id];

			retval |= func(t, c, p);
		}
@@ -2835,31 +2872,38 @@ 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, enum counter_type type, enum counter_format format)
{
	UNUSED(type);
	char *sep = (*printed)++ ? delim : "";

	if (format == FORMAT_RAW && width >= 64)
		return (sprintf(outp, "%s%-8s", ((*printed)++ ? delim : ""), name));
		return sprintf(outp, "%s%-8s", sep, name);
	else
		return (sprintf(outp, "%s%s", ((*printed)++ ? delim : ""), name));
		return sprintf(outp, "%s%s", sep, name);
}

static inline int print_hex_value(int width, int *printed, char *delim, unsigned long long value)
{
	char *sep = (*printed)++ ? delim : "";

	if (width <= 32)
		return (sprintf(outp, "%s%08x", ((*printed)++ ? delim : ""), (unsigned int)value));
		return sprintf(outp, "%s%08llx", sep, value);
	else
		return (sprintf(outp, "%s%016llx", ((*printed)++ ? delim : ""), value));
		return sprintf(outp, "%s%016llx", sep, value);
}

static inline int print_decimal_value(int width, int *printed, char *delim, unsigned long long value)
{
	char *sep = (*printed)++ ? delim : "";

	UNUSED(width);

	return (sprintf(outp, "%s%lld", ((*printed)++ ? delim : ""), value));
	return sprintf(outp, "%s%lld", sep, value);
}

static inline int print_float_value(int *printed, char *delim, double value)
{
	return (sprintf(outp, "%s%0.2f", ((*printed)++ ? delim : ""), value));
	char *sep = (*printed)++ ? delim : "";

	return sprintf(outp, "%s%0.2f", sep, value);
}

void print_header(char *delim)
@@ -2881,6 +2925,8 @@ void print_header(char *delim)
		outp += sprintf(outp, "%sL3", (printed++ ? delim : ""));
	if (DO_BIC(BIC_Node))
		outp += sprintf(outp, "%sNode", (printed++ ? delim : ""));
	if (DO_BIC(BIC_Module))
		outp += sprintf(outp, "%sModule", (printed++ ? delim : ""));
	if (DO_BIC(BIC_Core))
		outp += sprintf(outp, "%sCore", (printed++ ? delim : ""));
	if (DO_BIC(BIC_CPU))
@@ -3176,7 +3222,7 @@ int dump_counters(PER_THREAD_PARAMS)
	}

	if (c && is_cpu_first_thread_in_core(t, c)) {
		outp += sprintf(outp, "core: %d\n", cpus[t->cpu_id].core_id);
		outp += sprintf(outp, "core: 0x%x\n", cpus[t->cpu_id].core_id);
		outp += sprintf(outp, "c3: %016llX\n", c->c3);
		outp += sprintf(outp, "c6: %016llX\n", c->c6);
		outp += sprintf(outp, "c7: %016llX\n", c->c7);
@@ -3350,6 +3396,8 @@ int format_counters(PER_THREAD_PARAMS)
			outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
		if (DO_BIC(BIC_Node))
			outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
		if (DO_BIC(BIC_Module))
			outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
		if (DO_BIC(BIC_Core))
			outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
		if (DO_BIC(BIC_CPU))
@@ -3383,18 +3431,24 @@ int format_counters(PER_THREAD_PARAMS)
			else
				outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
		}
		if (DO_BIC(BIC_Module)) {
			if (c)
				outp += sprintf(outp, "%s0x%x", (printed++ ? delim : ""), cpus[t->cpu_id].module_id);
			else
				outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
		}
		if (DO_BIC(BIC_Core)) {
			if (c)
				outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), cpus[t->cpu_id].core_id);
				outp += sprintf(outp, "%s0x%x", (printed++ ? delim : ""), cpus[t->cpu_id].core_id);
			else
				outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
		}
		if (DO_BIC(BIC_CPU))
			outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->cpu_id);
		if (DO_BIC(BIC_APIC))
			outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->apic_id);
			outp += sprintf(outp, "%s0x%x", (printed++ ? delim : ""), t->apic_id);
		if (DO_BIC(BIC_X2APIC))
			outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->x2apic_id);
			outp += sprintf(outp, "%s0x%x", (printed++ ? delim : ""), t->x2apic_id);
	}

	if (DO_BIC(BIC_Avg_MHz))
@@ -5155,7 +5209,7 @@ static inline int get_rapl_num_domains(void)
	if (!platform->has_per_core_rapl)
		return topo.num_packages;

	return topo.num_cores;
	return GLOBAL_CORE_ID(topo.max_core_id, topo.num_packages) + 1;
}

static inline int get_rapl_domain_id(int cpu)
@@ -6041,6 +6095,11 @@ int get_l3_id(int cpu)
	return parse_int_file("/sys/devices/system/cpu/cpu%d/cache/index3/id", cpu);
}

int get_module_id(int cpu)
{
	return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/cluster_id", cpu);
}

int get_core_id(int cpu)
{
	return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_id", cpu);
@@ -6160,59 +6219,6 @@ static int parse_cpu_str(char *cpu_str, cpu_set_t *cpu_set, int cpu_set_size)
	return 0;
}

int set_thread_siblings(struct cpu_topology *thiscpu)
{
	char path[80], character;
	FILE *filep;
	unsigned long map;
	int so, shift, sib_core;
	int cpu = thiscpu->cpu_id;
	int offset = topo.max_cpu_num + 1;
	size_t size;
	int thread_id = 0;

	thiscpu->put_ids = CPU_ALLOC((topo.max_cpu_num + 1));
	if (thiscpu->ht_id < 0)
		thiscpu->ht_id = thread_id++;
	if (!thiscpu->put_ids)
		return -1;

	size = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
	CPU_ZERO_S(size, thiscpu->put_ids);

	sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings", cpu);
	filep = fopen(path, "r");

	if (!filep) {
		warnx("%s: open failed", path);
		return -1;
	}
	do {
		offset -= BITMASK_SIZE;
		if (fscanf(filep, "%lx%c", &map, &character) != 2)
			err(1, "%s: failed to parse file", path);
		for (shift = 0; shift < BITMASK_SIZE; shift++) {
			if ((map >> shift) & 0x1) {
				so = shift + offset;
				sib_core = get_core_id(so);
				if (sib_core == thiscpu->core_id) {
					CPU_SET_S(so, size, thiscpu->put_ids);
					if ((so != cpu) && (cpus[so].ht_id < 0)) {
						cpus[so].ht_id = thread_id;
						cpus[cpu].ht_sibling_cpu_id[thread_id] = so;
						if (debug)
							fprintf(stderr, "%s: cpu%d.ht_sibling_cpu_id[%d] = %d\n", __func__, cpu, thread_id, so);
						thread_id += 1;
					}
				}
			}
		}
	} while (character == ',');
	fclose(filep);

	return CPU_COUNT_S(size, thiscpu->put_ids);
}

/*
 * run func(thread, core, package) in topology order
 * skip non-present cpus
@@ -6236,7 +6242,7 @@ int for_all_cpus_2(int (func) (struct thread_data *, struct core_data *,
		if (cpu_is_not_allowed(cpu))
			continue;

		if (cpus[cpu].ht_id > 0)	/* skip HT sibling */
		if (has_allowed_lower_ht_sibling(cpu))	/* skip HT sibling */
			continue;

		t = &thread_base[cpu];
@@ -6251,11 +6257,20 @@ int for_all_cpus_2(int (func) (struct thread_data *, struct core_data *,
		/* Handle HT sibling now */
		int i;

		for (i = MAX_HT_ID; i > 0; --i) {	/* ht_id 0 is self */
			if (cpus[cpu].ht_sibling_cpu_id[i] <= 0)
		for (i = 0; i <= MAX_HT_ID; ++i) {
			int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i];

			if (sibling_cpu_id < 0)
				break;

			if (sibling_cpu_id == cpu)
				continue;

			if (cpu_is_not_allowed(sibling_cpu_id))
				continue;
			t = &thread_base[cpus[cpu].ht_sibling_cpu_id[i]];
			t2 = &thread_base2[cpus[cpu].ht_sibling_cpu_id[i]];

			t = &thread_base[sibling_cpu_id];
			t2 = &thread_base2[sibling_cpu_id];

			retval |= func(t, c, p, t2, c2, p2);
		}
@@ -9475,6 +9490,37 @@ int dir_filter(const struct dirent *dirp)
		return 0;
}

int set_thread_siblings(struct cpu_topology *thiscpu)
{
	char path[80];
	int cpu = thiscpu->cpu_id;
	size_t size;
	int ht_id = 0;
	int i;

	thiscpu->put_ids = CPU_ALLOC((topo.max_cpu_num + 1));
	if (thiscpu->ht_id < 0)
		thiscpu->ht_id = 0;	/* first CPU in core */
	if (!thiscpu->put_ids)
		return -1;

	size = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
	CPU_ZERO_S(size, thiscpu->put_ids);

	sprintf(path, "/sys/devices/system/cpu/cpu%d/topology", cpu);

	initialize_cpu_set_from_sysfs(thiscpu->put_ids, path, "thread_siblings_list");

	for (i = 0; i <= topo.max_cpu_num; ++i)
		if (CPU_ISSET_S(i, size, thiscpu->put_ids)) {
			cpus[i].ht_id = ht_id;
			cpus[cpu].ht_sibling_cpu_id[ht_id] = i;
			ht_id += 1;
		}

	return (ht_id - 1);
}

void topology_probe(bool startup)
{
	int i;
@@ -9505,6 +9551,8 @@ void topology_probe(bool startup)
	cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
	CPU_ZERO_S(cpu_present_setsize, cpu_present_set);
	for_all_proc_cpus(mark_cpu_present);
	if (debug)
		print_cpu_set("present set", cpu_present_set);

	/*
	 * Allocate and initialize cpu_possible_set
@@ -9515,6 +9563,8 @@ void topology_probe(bool startup)
	cpu_possible_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
	CPU_ZERO_S(cpu_possible_setsize, cpu_possible_set);
	initialize_cpu_set_from_sysfs(cpu_possible_set, "/sys/devices/system/cpu", "possible");
	if (debug)
		print_cpu_set("possible set", cpu_possible_set);

	/*
	 * Allocate and initialize cpu_effective_set
@@ -9525,6 +9575,8 @@ void topology_probe(bool startup)
	cpu_effective_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
	CPU_ZERO_S(cpu_effective_setsize, cpu_effective_set);
	update_effective_set(startup);
	if (debug)
		print_cpu_set("effective set", cpu_effective_set);

	/*
	 * Allocate and initialize cpu_allowed_set
@@ -9568,6 +9620,8 @@ void topology_probe(bool startup)

		CPU_SET_S(i, cpu_allowed_setsize, cpu_allowed_set);
	}
	if (debug)
		print_cpu_set("allowed set", cpu_allowed_set);

	if (!CPU_COUNT_S(cpu_allowed_setsize, cpu_allowed_set))
		err(-ENODEV, "No valid cpus found");
@@ -9590,6 +9644,7 @@ void topology_probe(bool startup)
	 * For online cpus
	 * find max_core_id, max_package_id, num_cores (per system)
	 */
	topo.min_module_id = 0x7FFFFFFF;
	for (i = 0; i <= topo.max_cpu_num; ++i) {
		int siblings;

@@ -9621,6 +9676,13 @@ void topology_probe(bool startup)
		if (cpus[i].physical_node_id > topo.max_node_num)
			topo.max_node_num = cpus[i].physical_node_id;

		/* get module information */
		cpus[i].module_id = get_module_id(i);
		if (cpus[i].module_id > topo.max_module_id)
			topo.max_module_id = cpus[i].module_id;
		if (cpus[i].module_id < topo.min_module_id)
			topo.min_module_id = cpus[i].module_id;

		/* get core information */
		cpus[i].core_id = get_core_id(i);
		if (cpus[i].core_id > max_core_id)
@@ -9642,6 +9704,11 @@ void topology_probe(bool startup)
	if (!summary_only)
		BIC_PRESENT(BIC_Core);

	if (debug > 1)
		fprintf(outf, "min_module_id %d max_module_id %d\n", topo.min_module_id, topo.max_module_id);
	if (!summary_only && (topo.min_module_id != topo.max_module_id))
		BIC_PRESENT(BIC_Module);

	topo.num_die = topo.max_die_id + 1;
	if (debug > 1)
		fprintf(outf, "max_die_id %d, sizing for %d die\n", topo.max_die_id, topo.num_die);
@@ -9671,12 +9738,18 @@ void topology_probe(bool startup)
		return;

	for (i = 0; i <= topo.max_cpu_num; ++i) {
		int ht_id;

		if (cpu_is_not_present(i))
			continue;
		fprintf(outf,
			"cpu %d pkg %d die %d l3 %d node %d lnode %d core %d thread %d\n",
			"cpu %d pkg %d die %d l3 %d node %d lnode %d module 0x%x core %d ht_id %d",
			i, cpus[i].package_id, cpus[i].die_id, cpus[i].l3_id,
			cpus[i].physical_node_id, cpus[i].logical_node_id, cpus[i].core_id, cpus[i].ht_id);
			cpus[i].physical_node_id, cpus[i].logical_node_id, cpus[i].module_id, cpus[i].core_id, cpus[i].ht_id);
		fprintf(outf, " siblings");
		for (ht_id = 0; ht_id <= MAX_HT_ID; ++ht_id)
			fprintf(outf, " %d", cpus[i].ht_sibling_cpu_id[ht_id]);
		fprintf(outf, "\n");
	}

}
@@ -9817,6 +9890,8 @@ void topology_update(void)
	topo.allowed_cores = 0;
	topo.allowed_packages = 0;
	for_all_cpus(update_topo, ODD_COUNTERS);
	if (debug)
		fprintf(stderr, "allowed_cpus %d allowed_cores %d allowed_packages %d\n", topo.allowed_cpus, topo.allowed_cores, topo.allowed_packages);
}

void setup_all_buffers(bool startup)
@@ -10533,7 +10608,7 @@ int get_and_dump_counters(void)

void print_version()
{
	fprintf(outf, "turbostat version 2026.02.14 - Len Brown <lenb@kernel.org>\n");
	fprintf(outf, "turbostat version 2026.04.21 - Len Brown <lenb@kernel.org>\n");
}

#define COMMAND_LINE_SIZE 2048
@@ -11449,7 +11524,7 @@ void cmdline(int argc, char **argv)
	}
	optind = 0;

	while ((opt = getopt_long_only(argc, argv, "+C:c:Dde:hi:Jn:N:o:qMST:v", long_options, &option_index)) != -1) {
	while ((opt = getopt_long_only(argc, argv, "+C:c:Dde:hi:Jn:N:o:qMPST:v", long_options, &option_index)) != -1) {
		switch (opt) {
		case 'a':
			parse_add_command(optarg);
+26 −0
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@ x86_energy_perf_policy \- Manage Energy vs. Performance Policy
.br
.RB "other: (\-\-force | \-\-hwp-enable | \-\-turbo-enable)  value)"
.br
.RB "soc-slider: --soc-slider-balance # | --soc-slider-offset # | --platform-profile <name>"
.br
.RB "value: # | default | performance | balance-performance | balance-power | power"
.SH DESCRIPTION
\fBx86_energy_perf_policy\fP
@@ -154,6 +156,26 @@ level on this processor, specified in multiples of 100 MHz.
in the sliding window that HWP uses to maintain average frequency.
This parameter is meaningful only when the "desired" field above is non-zero.
Default is 0, allowing the HW to choose.
.SH SOC SLIDER OPTIONS
.PP
Note that the Platform Profile Name must be "SoC Slider", and the
Platform Profile must be "balanced" for the --soc-slider-balance
and --soc-slider-offset options to take effect.
.PP
\fB--soc-slider-balance #\fP write numeric value to the SoC Slider.
Values range from 0 to 6.
Lower values result in higher performance,
and higher values improve energy efficiency.
Actual values are model specific.
.PP
\fB--soc-slider-offset #\fP write the numeric value to the Soc Slider Offset.
The slider offset is the maximum value that software allows the SoC to
autonomously add to the SoC Slider to improve energy efficiency.
The value 0 prohibits the SoC from autonomously changing the slider.
.PP
\fB--platform-profile <name>"\fP set the platform profile to <name>.
Available choices are in platform-profile-0/choices.  The Soc Slider
driver currently supports "low-power", "balanced", and "performance".
.SH OTHER OPTIONS
.PP
\fB-f, --force\fP writes the specified values without bounds checking.
@@ -208,6 +230,10 @@ runs only as root.
EPB: /sys/devices/system/cpu/cpu*/power/energy_perf_bias
EPP: /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference
MSR: /dev/cpu/*/msr
Platform Profile Name: /sys/class/platform-profile/platform-profile-0/name
Platform Profile: /sys/class/platform-profile/platform-profile-0/profile
SOC Slider Balanced: /sys/module/processor_thermal_soc_slider/parameters/slider_balance
SOC Slider Balanced Offset: /sys/module/processor_thermal_soc_slider/parameters/slider_offset
.fi
.SH "SEE ALSO"
.nf
+282 −117

File changed.

Preview size limit exceeded, changes collapsed.