mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
cpupower: Better detect offlined CPUs
Before, checking for offlined CPUs was done dirty and it was checked whether topology parsing returned -1 values. But this is a valid case on a Xen (and possibly other) kernels. Do proper online/offline checking, also take CONFIG_HOTPLUG_CPU option into account (no /sys/devices/../cpuX/online file). Signed-off-by: Thomas Renninger <trenn@suse.de> Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
This commit is contained in:
parent
88f984e0e2
commit
7c74d2bc5a
5 changed files with 66 additions and 4 deletions
|
@ -96,6 +96,9 @@ struct cpupower_topology {
|
|||
int pkg;
|
||||
int core;
|
||||
int cpu;
|
||||
|
||||
/* flags */
|
||||
unsigned int is_online:1;
|
||||
} *core_info;
|
||||
};
|
||||
|
||||
|
|
|
@ -56,6 +56,56 @@ static unsigned int sysfs_write_file(const char *path,
|
|||
return (unsigned int) numwrite;
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect whether a CPU is online
|
||||
*
|
||||
* Returns:
|
||||
* 1 -> if CPU is online
|
||||
* 0 -> if CPU is offline
|
||||
* negative errno values in error case
|
||||
*/
|
||||
int sysfs_is_cpu_online(unsigned int cpu)
|
||||
{
|
||||
char path[SYSFS_PATH_MAX];
|
||||
int fd;
|
||||
ssize_t numread;
|
||||
unsigned long long value;
|
||||
char linebuf[MAX_LINE_LEN];
|
||||
char *endp;
|
||||
struct stat statbuf;
|
||||
|
||||
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
|
||||
|
||||
if (stat(path, &statbuf) != 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* kernel without CONFIG_HOTPLUG_CPU
|
||||
* -> cpuX directory exists, but not cpuX/online file
|
||||
*/
|
||||
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
|
||||
if (stat(path, &statbuf) != 0)
|
||||
return 1;
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return -errno;
|
||||
|
||||
numread = read(fd, linebuf, MAX_LINE_LEN - 1);
|
||||
if (numread < 1) {
|
||||
close(fd);
|
||||
return -EIO;
|
||||
}
|
||||
linebuf[numread] = '\0';
|
||||
close(fd);
|
||||
|
||||
value = strtoull(linebuf, &endp, 0);
|
||||
if (value > 1 || value < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
|
||||
|
||||
/*
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
|
||||
|
||||
extern int sysfs_is_cpu_online(unsigned int cpu);
|
||||
|
||||
extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
|
||||
unsigned int idlestate);
|
||||
extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
|
||||
|
|
|
@ -41,6 +41,8 @@ struct cpuid_core_info {
|
|||
unsigned int pkg;
|
||||
unsigned int thread;
|
||||
unsigned int cpu;
|
||||
/* flags */
|
||||
unsigned int is_online:1;
|
||||
};
|
||||
|
||||
static int __compare(const void *t1, const void *t2)
|
||||
|
@ -78,6 +80,8 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
|
|||
return -ENOMEM;
|
||||
cpu_top->pkgs = cpu_top->cores = 0;
|
||||
for (cpu = 0; cpu < cpus; cpu++) {
|
||||
cpu_top->core_info[cpu].cpu = cpu;
|
||||
cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu);
|
||||
cpu_top->core_info[cpu].pkg =
|
||||
sysfs_topology_read_file(cpu, "physical_package_id");
|
||||
if ((int)cpu_top->core_info[cpu].pkg != -1 &&
|
||||
|
@ -85,7 +89,6 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
|
|||
cpu_top->pkgs = cpu_top->core_info[cpu].pkg;
|
||||
cpu_top->core_info[cpu].core =
|
||||
sysfs_topology_read_file(cpu, "core_id");
|
||||
cpu_top->core_info[cpu].cpu = cpu;
|
||||
}
|
||||
cpu_top->pkgs++;
|
||||
|
||||
|
|
|
@ -190,9 +190,13 @@ void print_results(int topology_depth, int cpu)
|
|||
}
|
||||
}
|
||||
}
|
||||
/* cpu offline */
|
||||
if (cpu_top.core_info[cpu].pkg == -1 ||
|
||||
cpu_top.core_info[cpu].core == -1) {
|
||||
/*
|
||||
* The monitor could still provide useful data, for example
|
||||
* AMD HW counters partly sit in PCI config space.
|
||||
* It's up to the monitor plug-in to check .is_online, this one
|
||||
* is just for additional info.
|
||||
*/
|
||||
if (!cpu_top.core_info[cpu].is_online) {
|
||||
printf(_(" *is offline\n"));
|
||||
return;
|
||||
} else
|
||||
|
|
Loading…
Reference in a new issue