tools/power turbostat: Fix forked child affinity regression

BugLink: https://bugs.launchpad.net/bugs/2111953

[ Upstream commit b32c36975da48afc9089f8b61f7b2dcc40e479d2 ]

In "one-shot" mode, turbostat
1. takes a counter snapshot
2. forks and waits for a child
3. takes the end counter snapshot and prints the result.

But turbostat counter snapshots currently use affinity to travel
around the system so that counter reads are "local", and this
affinity must be cleared between #1 and #2 above.

The offending commit removed that reset that allowed the child
to run on cpu_present_set.

Fix that issue, and improve upon the original by using
cpu_possible_set for the child.  This allows the child
to also run on CPUs that hotplug online during its runtime.

Reported-by: Zhang Rui <rui.zhang@intel.com>
Fixes: 7bb3fe27ad ("tools/power/turbostat: Obey allowed CPUs during startup")
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Manuel Diewald <manuel.diewald@canonical.com>
Signed-off-by: Mehmet Basaran <mehmet.basaran@canonical.com>
This commit is contained in:
Len Brown
2025-01-27 16:42:19 -06:00
committed by Mehmet Basaran
parent 5deeaab435
commit 58b404cb45
+52 -2
View File
@@ -963,8 +963,8 @@ int backwards_count;
char *progname;
#define CPU_SUBSET_MAXCPUS 1024 /* need to use before probe... */
cpu_set_t *cpu_present_set, *cpu_effective_set, *cpu_allowed_set, *cpu_affinity_set, *cpu_subset;
size_t cpu_present_setsize, cpu_effective_setsize, cpu_allowed_setsize, cpu_affinity_setsize, cpu_subset_size;
cpu_set_t *cpu_present_set, *cpu_possible_set, *cpu_effective_set, *cpu_allowed_set, *cpu_affinity_set, *cpu_subset;
size_t cpu_present_setsize, cpu_possible_setsize, cpu_effective_setsize, cpu_allowed_setsize, cpu_affinity_setsize, cpu_subset_size;
#define MAX_ADDED_COUNTERS 8
#define MAX_ADDED_THREAD_COUNTERS 24
#define BITMASK_SIZE 32
@@ -5919,6 +5919,33 @@ int dir_filter(const struct dirent *dirp)
return 0;
}
char *possible_file = "/sys/devices/system/cpu/possible";
char possible_buf[1024];
int initialize_cpu_possible_set(void)
{
FILE *fp;
fp = fopen(possible_file, "r");
if (!fp) {
warn("open %s", possible_file);
return -1;
}
if (fread(possible_buf, sizeof(char), 1024, fp) == 0) {
warn("read %s", possible_file);
goto err;
}
if (parse_cpu_str(possible_buf, cpu_possible_set, cpu_possible_setsize)) {
warnx("%s: cpu str malformat %s\n", possible_file, cpu_effective_str);
goto err;
}
return 0;
err:
fclose(fp);
return -1;
}
void topology_probe(bool startup)
{
int i;
@@ -5950,6 +5977,16 @@ void topology_probe(bool startup)
CPU_ZERO_S(cpu_present_setsize, cpu_present_set);
for_all_proc_cpus(mark_cpu_present);
/*
* Allocate and initialize cpu_possible_set
*/
cpu_possible_set = CPU_ALLOC((topo.max_cpu_num + 1));
if (cpu_possible_set == NULL)
err(3, "CPU_ALLOC");
cpu_possible_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
CPU_ZERO_S(cpu_possible_setsize, cpu_possible_set);
initialize_cpu_possible_set();
/*
* Allocate and initialize cpu_effective_set
*/
@@ -6272,6 +6309,18 @@ void turbostat_init()
(void)get_instr_count_fd(base_cpu);
}
void affinitize_child(void)
{
/* Prefer cpu_possible_set, if available */
if (sched_setaffinity(0, cpu_possible_setsize, cpu_possible_set)) {
warn("sched_setaffinity cpu_possible_set");
/* Otherwise, allow child to run on same cpu set as turbostat */
if (sched_setaffinity(0, cpu_allowed_setsize, cpu_allowed_set))
warn("sched_setaffinity cpu_allowed_set");
}
}
int fork_it(char **argv)
{
pid_t child_pid;
@@ -6287,6 +6336,7 @@ int fork_it(char **argv)
child_pid = fork();
if (!child_pid) {
/* child */
affinitize_child();
execvp(argv[0], argv);
err(errno, "exec %s", argv[0]);
} else {