Skip to content

Commit

Permalink
cpupower: Better detect offlined CPUs
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
watologo1 authored and Dominik Brodowski committed Aug 15, 2011
1 parent 88f984e commit 7c74d2b
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 4 deletions.
3 changes: 3 additions & 0 deletions tools/power/cpupower/utils/helpers/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ struct cpupower_topology {
int pkg;
int core;
int cpu;

/* flags */
unsigned int is_online:1;
} *core_info;
};

Expand Down
50 changes: 50 additions & 0 deletions tools/power/cpupower/utils/helpers/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

/*
Expand Down
2 changes: 2 additions & 0 deletions tools/power/cpupower/utils/helpers/sysfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 4 additions & 1 deletion tools/power/cpupower/utils/helpers/topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -78,14 +80,15 @@ 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 &&
cpu_top->core_info[cpu].pkg > cpu_top->pkgs)
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++;

Expand Down
10 changes: 7 additions & 3 deletions tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 7c74d2b

Please sign in to comment.