Skip to content

Commit f89cb9c

Browse files
John B. Wyatt IVshuahkh
authored andcommitted
cpupower: Implement CPU physical core querying
This patch is also an issue report. get_cpu_topology will always save into cpupower_topology a cores size of 0. The code to handle this looks like it was commented out, and what is commented out is missing a curly bracket. https://elixir.bootlin.com/linux/v6.13.5/source/tools/power/cpupower/lib/cpupower.c#L206-L212 Inspiration was taken from psutil to implement this by querying core_cpu_list. Instead of using a hashmap, I used a sorted array, and counted the number of valid unique strings. The counting of this takes place before the qsort for .pkg as the following code says it is dependent on the order of that sort. The previous code claimed Intel CPUs are not numbered correctly. I was not able to reproduce that issue and removed that comment and the code. This commit was tested with the libcpupower SWIG Python bindings and performed correctly on 4 different setups. The most notable is the Framework Intel laptop; a hybrid system of 4 P cores (8 threads) and 8 E cores (8 threads). The 4 setups: A 4 core virt-manager VM running Fedora 41 4c/4t (specs not listed) was tested as a sanity test for VMs. A Lenovo Ryzen 7 Pro 7840HS 8c/16t. A Supermico Intel(R) Xeon(R) Gold 6330 CPU w/ 56c/112t with 2 CPU sockets. A Framework 12th Gen Intel(R) Core(TM) i5-1240P with hybrid cores. CPU(s): 16 On-line CPU(s) list: 0-15 Vendor ID: AuthenticAMD Model name: AMD Ryzen 7 PRO 7840HS w/ Radeon 780M Graphics CPU family: 25 Model: 116 Thread(s) per core: 2 Core(s) per socket: 8 Socket(s): 1 Stepping: 1 CPU(s): 112 On-line CPU(s) list: 0-111 Vendor ID: GenuineIntel BIOS Vendor ID: Intel(R) Corporation Model name: Intel(R) Xeon(R) Gold 6330 CPU @ 2.00GHz BIOS Model name: Intel(R) Xeon(R) Gold 6330 CPU @ 2.00GHz CPU @ 2.0GHz BIOS CPU family: 179 CPU family: 6 Model: 106 Thread(s) per core: 2 Core(s) per socket: 28 Socket(s): 2 Stepping: 6 CPU(s): 16 On-line CPU(s) list: 0-15 Vendor ID: GenuineIntel Model name: 12th Gen Intel(R) Core(TM) i5-1240P CPU family: 6 Model: 154 Thread(s) per core: 2 Core(s) per socket: 12 Socket(s): 1 Stepping: 3 Link: https://lore.kernel.org/r/[email protected] Signed-off-by: "John B. Wyatt IV" <[email protected]> Signed-off-by: "John B. Wyatt IV" <[email protected]> Signed-off-by: Shuah Khan <[email protected]>
1 parent 0014f65 commit f89cb9c

File tree

2 files changed

+43
-8
lines changed

2 files changed

+43
-8
lines changed

tools/power/cpupower/lib/cpupower.c

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <stdio.h>
1111
#include <errno.h>
1212
#include <stdlib.h>
13+
#include <string.h>
1314

1415
#include "cpupower.h"
1516
#include "cpupower_intern.h"
@@ -150,15 +151,25 @@ static int __compare(const void *t1, const void *t2)
150151
return 0;
151152
}
152153

154+
static int __compare_core_cpu_list(const void *t1, const void *t2)
155+
{
156+
struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
157+
struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2;
158+
159+
return strcmp(top1->core_cpu_list, top2->core_cpu_list);
160+
}
161+
153162
/*
154163
* Returns amount of cpus, negative on error, cpu_top must be
155164
* passed to cpu_topology_release to free resources
156165
*
157-
* Array is sorted after ->pkg, ->core, then ->cpu
166+
* Array is sorted after ->cpu_smt_list ->pkg, ->core
158167
*/
159168
int get_cpu_topology(struct cpupower_topology *cpu_top)
160169
{
161170
int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF);
171+
char path[SYSFS_PATH_MAX];
172+
char *last_cpu_list;
162173

163174
cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus);
164175
if (cpu_top->core_info == NULL)
@@ -183,6 +194,34 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
183194
cpu_top->core_info[cpu].core = -1;
184195
continue;
185196
}
197+
if (cpu_top->core_info[cpu].core == -1) {
198+
strncpy(cpu_top->core_info[cpu].core_cpu_list, "-1", CPULIST_BUFFER);
199+
continue;
200+
}
201+
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s",
202+
cpu, "core_cpus_list");
203+
if (cpupower_read_sysfs(
204+
path,
205+
cpu_top->core_info[cpu].core_cpu_list,
206+
CPULIST_BUFFER) < 1) {
207+
printf("Warning CPU%u has a 0 size core_cpus_list string", cpu);
208+
}
209+
}
210+
211+
/* Count the number of distinct cpu lists to get the physical core
212+
* count.
213+
*/
214+
qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
215+
__compare_core_cpu_list);
216+
217+
last_cpu_list = cpu_top->core_info[0].core_cpu_list;
218+
cpu_top->cores = 1;
219+
for (cpu = 1; cpu < cpus; cpu++) {
220+
if (strcmp(cpu_top->core_info[cpu].core_cpu_list, last_cpu_list) != 0 &&
221+
cpu_top->core_info[cpu].pkg != -1) {
222+
last_cpu_list = cpu_top->core_info[cpu].core_cpu_list;
223+
cpu_top->cores++;
224+
}
186225
}
187226

188227
qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
@@ -203,13 +242,6 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
203242
if (!(cpu_top->core_info[0].pkg == -1))
204243
cpu_top->pkgs++;
205244

206-
/* Intel's cores count is not consecutively numbered, there may
207-
* be a core_id of 3, but none of 2. Assume there always is 0
208-
* Get amount of cores by counting duplicates in a package
209-
for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) {
210-
if (cpu_top->core_info[cpu].core == 0)
211-
cpu_top->cores++;
212-
*/
213245
return cpus;
214246
}
215247

tools/power/cpupower/lib/cpupower.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#ifndef __CPUPOWER_CPUPOWER_H__
33
#define __CPUPOWER_CPUPOWER_H__
44

5+
#define CPULIST_BUFFER 5
6+
57
struct cpupower_topology {
68
/* Amount of CPU cores, packages and threads per core in the system */
79
unsigned int cores;
@@ -16,6 +18,7 @@ struct cpuid_core_info {
1618
int pkg;
1719
int core;
1820
int cpu;
21+
char core_cpu_list[CPULIST_BUFFER];
1922

2023
/* flags */
2124
unsigned int is_online:1;

0 commit comments

Comments
 (0)