linux-cpupower-6.15-rc1

Fixes lib version-ing, memory leaks in error legs, removes hard-coded
 values, and implements CPU physical core querying.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEPZKym/RZuOCGeA/kCwJExA0NQxwFAmfPGr8ACgkQCwJExA0N
 QxwMHA//YsbRMQtDFWaP71HyF0S2L9W/ZxGz5r/VL73Sz8HQ0yciA4+3GpHMUsrJ
 5Dez9NwDNLmzNFq7aVZN8IGGsBJ7+Q+ok9idzFVmBAt6ufhR4p+l2QqN1G8dQEvM
 ++Cj/eWx3S4t1su8XpEW2cJXEbQV8uvyWWmyViSpuvEAIXVd82M43mP7qO66w8EC
 hie0wOIok2NdW+cuXuwBoMDgN5gPun9gePRPgK0rJK03Rir2deaI4cAjcoJG811c
 cg1IgsO6eieSDbZ+siX/OmpYGvJ7CVOu1dYBqvqLj9Q1ivts8HYyuQrBmScGIG4a
 yAap9m2KzJGuSQKGy/8Drf+pJ2IBMDR3Xwkk+zyS8V91M0bOWiw/cQLQ4j1eJoh0
 RbSHc3vHRB3QJks4V3Tf+80EbNYdwl1Fqwj8YxzYGEfyM4pt8aJbm3EzUVGAOhkp
 nU00Zcx3tLrNxuS1x5NgCZSUJv1y8hxOete3btBU4eduFCmnqXO7XPmn4HzelE/T
 Wl4FSpz1dt+bhDu03I9RriipAR2G+6GiYrYdH7+zkuX8cHeCjn73XKQrfS3MQNjP
 ZnUQFzAgEQs5JqCDuRa3Z22ekP1MoDDUWkyJ5tJPP+HfDIymZimm8UX3An4+FUtp
 xSgHtjA+PMtuc4xQX7MAzrGOXX/Ayle571tGhM7Lqzum+SgqohE=
 =xM94
 -----END PGP SIGNATURE-----

Merge tag 'linux-cpupower-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux

Merge cpupower utility updates for 6.15-rc1 from Shuah Khan:

"Fixes lib version-ing, memory leaks in error legs, removes hard-coded
 values, and implements CPU physical core querying."

* tag 'linux-cpupower-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux:
  cpupower: Make lib versioning scheme more obvious and fix version link
  cpupower: Implement CPU physical core querying
  pm: cpupower: remove hard-coded topology depth values
  pm: cpupower: Fix cmd_monitor() error legs to free cpu_topology
  cpupower: monitor: Exit with error status if execvp() fail
  pm: cpupower: bench: Prevent NULL dereference on malloc failure
This commit is contained in:
Rafael J. Wysocki 2025-03-12 20:15:22 +01:00
commit 80f0f07946
5 changed files with 94 additions and 28 deletions

View File

@ -52,8 +52,11 @@ DESTDIR ?=
# and _should_ modify the PACKAGE_BUGREPORT definition
VERSION:= $(shell ./utils/version-gen.sh)
LIB_MAJ= 0.0.1
LIB_MIN= 1
LIB_FIX= 1
LIB_MIN= 0
LIB_MAJ= 1
LIB_VER= $(LIB_MAJ).$(LIB_MIN).$(LIB_FIX)
PACKAGE = cpupower
PACKAGE_BUGREPORT = linux-pm@vger.kernel.org
@ -200,14 +203,14 @@ $(OUTPUT)lib/%.o: $(LIB_SRC) $(LIB_HEADERS)
$(ECHO) " CC " $@
$(QUIET) $(CC) $(CFLAGS) -fPIC -o $@ -c lib/$*.c
$(OUTPUT)libcpupower.so.$(LIB_MAJ): $(LIB_OBJS)
$(OUTPUT)libcpupower.so.$(LIB_VER): $(LIB_OBJS)
$(ECHO) " LD " $@
$(QUIET) $(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ \
-Wl,-soname,libcpupower.so.$(LIB_MIN) $(LIB_OBJS)
-Wl,-soname,libcpupower.so.$(LIB_MAJ) $(LIB_OBJS)
@ln -sf $(@F) $(OUTPUT)libcpupower.so
@ln -sf $(@F) $(OUTPUT)libcpupower.so.$(LIB_MIN)
@ln -sf $(@F) $(OUTPUT)libcpupower.so.$(LIB_MAJ)
libcpupower: $(OUTPUT)libcpupower.so.$(LIB_MAJ)
libcpupower: $(OUTPUT)libcpupower.so.$(LIB_VER)
# Let all .o files depend on its .c file and all headers
# Might be worth to put this into utils/Makefile at some point of time
@ -217,7 +220,7 @@ $(OUTPUT)%.o: %.c
$(ECHO) " CC " $@
$(QUIET) $(CC) $(CFLAGS) -I./lib -I ./utils -o $@ -c $*.c
$(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_MAJ)
$(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_VER)
$(ECHO) " CC " $@
ifeq ($(strip $(STATIC)),true)
$(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lrt -lpci -L$(OUTPUT) -o $@
@ -262,7 +265,7 @@ update-po: $(OUTPUT)po/$(PACKAGE).pot
done;
endif
compile-bench: $(OUTPUT)libcpupower.so.$(LIB_MAJ)
compile-bench: $(OUTPUT)libcpupower.so.$(LIB_VER)
@V=$(V) confdir=$(confdir) $(MAKE) -C bench O=$(OUTPUT)
# we compile into subdirectories. if the target directory is not the

View File

@ -121,6 +121,10 @@ FILE *prepare_output(const char *dirname)
struct config *prepare_default_config()
{
struct config *config = malloc(sizeof(struct config));
if (!config) {
perror("malloc");
return NULL;
}
dprintf("loading defaults\n");

View File

@ -10,6 +10,7 @@
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "cpupower.h"
#include "cpupower_intern.h"
@ -150,15 +151,25 @@ static int __compare(const void *t1, const void *t2)
return 0;
}
static int __compare_core_cpu_list(const void *t1, const void *t2)
{
struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2;
return strcmp(top1->core_cpu_list, top2->core_cpu_list);
}
/*
* Returns amount of cpus, negative on error, cpu_top must be
* passed to cpu_topology_release to free resources
*
* Array is sorted after ->pkg, ->core, then ->cpu
* Array is sorted after ->cpu_smt_list ->pkg, ->core
*/
int get_cpu_topology(struct cpupower_topology *cpu_top)
{
int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF);
char path[SYSFS_PATH_MAX];
char *last_cpu_list;
cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus);
if (cpu_top->core_info == NULL)
@ -183,6 +194,34 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
cpu_top->core_info[cpu].core = -1;
continue;
}
if (cpu_top->core_info[cpu].core == -1) {
strncpy(cpu_top->core_info[cpu].core_cpu_list, "-1", CPULIST_BUFFER);
continue;
}
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s",
cpu, "core_cpus_list");
if (cpupower_read_sysfs(
path,
cpu_top->core_info[cpu].core_cpu_list,
CPULIST_BUFFER) < 1) {
printf("Warning CPU%u has a 0 size core_cpus_list string", cpu);
}
}
/* Count the number of distinct cpu lists to get the physical core
* count.
*/
qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
__compare_core_cpu_list);
last_cpu_list = cpu_top->core_info[0].core_cpu_list;
cpu_top->cores = 1;
for (cpu = 1; cpu < cpus; cpu++) {
if (strcmp(cpu_top->core_info[cpu].core_cpu_list, last_cpu_list) != 0 &&
cpu_top->core_info[cpu].pkg != -1) {
last_cpu_list = cpu_top->core_info[cpu].core_cpu_list;
cpu_top->cores++;
}
}
qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
@ -203,13 +242,6 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
if (!(cpu_top->core_info[0].pkg == -1))
cpu_top->pkgs++;
/* Intel's cores count is not consecutively numbered, there may
* be a core_id of 3, but none of 2. Assume there always is 0
* Get amount of cores by counting duplicates in a package
for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) {
if (cpu_top->core_info[cpu].core == 0)
cpu_top->cores++;
*/
return cpus;
}

View File

@ -2,6 +2,8 @@
#ifndef __CPUPOWER_CPUPOWER_H__
#define __CPUPOWER_CPUPOWER_H__
#define CPULIST_BUFFER 5
struct cpupower_topology {
/* Amount of CPU cores, packages and threads per core in the system */
unsigned int cores;
@ -16,6 +18,7 @@ struct cpuid_core_info {
int pkg;
int core;
int cpu;
char core_cpu_list[CPULIST_BUFFER];
/* flags */
unsigned int is_online:1;

View File

@ -6,6 +6,7 @@
*/
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
@ -91,7 +92,11 @@ int fill_string_with_spaces(char *s, int n)
return 0;
}
#define MAX_COL_WIDTH 6
#define MAX_COL_WIDTH 6
#define TOPOLOGY_DEPTH_PKG 3
#define TOPOLOGY_DEPTH_CORE 2
#define TOPOLOGY_DEPTH_CPU 1
void print_header(int topology_depth)
{
int unsigned mon;
@ -113,12 +118,19 @@ void print_header(int topology_depth)
}
printf("\n");
if (topology_depth > 2)
switch (topology_depth) {
case TOPOLOGY_DEPTH_PKG:
printf(" PKG|");
if (topology_depth > 1)
break;
case TOPOLOGY_DEPTH_CORE:
printf("CORE|");
if (topology_depth > 0)
break;
case TOPOLOGY_DEPTH_CPU:
printf(" CPU|");
break;
default:
return;
}
for (mon = 0; mon < avail_monitors; mon++) {
if (mon != 0)
@ -152,12 +164,19 @@ void print_results(int topology_depth, int cpu)
cpu_top.core_info[cpu].pkg == -1)
return;
if (topology_depth > 2)
switch (topology_depth) {
case TOPOLOGY_DEPTH_PKG:
printf("%4d|", cpu_top.core_info[cpu].pkg);
if (topology_depth > 1)
break;
case TOPOLOGY_DEPTH_CORE:
printf("%4d|", cpu_top.core_info[cpu].core);
if (topology_depth > 0)
break;
case TOPOLOGY_DEPTH_CPU:
printf("%4d|", cpu_top.core_info[cpu].cpu);
break;
default:
return;
}
for (mon = 0; mon < avail_monitors; mon++) {
if (mon != 0)
@ -294,7 +313,10 @@ int fork_it(char **argv)
if (!child_pid) {
/* child */
execvp(argv[0], argv);
if (execvp(argv[0], argv) == -1) {
printf("Invalid monitor command %s\n", argv[0]);
exit(errno);
}
} else {
/* parent */
if (child_pid == -1) {
@ -423,11 +445,13 @@ int cmd_monitor(int argc, char **argv)
if (avail_monitors == 0) {
printf(_("No HW Cstate monitors found\n"));
cpu_topology_release(cpu_top);
return 1;
}
if (mode == list) {
list_monitors();
cpu_topology_release(cpu_top);
exit(EXIT_SUCCESS);
}
@ -448,15 +472,15 @@ int cmd_monitor(int argc, char **argv)
/* ToDo: Topology parsing needs fixing first to do
this more generically */
if (cpu_top.pkgs > 1)
print_header(3);
print_header(TOPOLOGY_DEPTH_PKG);
else
print_header(1);
print_header(TOPOLOGY_DEPTH_CPU);
for (cpu = 0; cpu < cpu_count; cpu++) {
if (cpu_top.pkgs > 1)
print_results(3, cpu);
print_results(TOPOLOGY_DEPTH_PKG, cpu);
else
print_results(1, cpu);
print_results(TOPOLOGY_DEPTH_CPU, cpu);
}
for (num = 0; num < avail_monitors; num++) {