Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7c74d2bc authored by Thomas Renninger's avatar Thomas Renninger Committed by Dominik Brodowski
Browse files

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: default avatarThomas Renninger <trenn@suse.de>
Signed-off-by: default avatarDominik Brodowski <linux@dominikbrodowski.net>
parent 88f984e0
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -96,6 +96,9 @@ struct cpupower_topology {
		int pkg;
		int core;
		int cpu;

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

+50 −0
Original line number Diff line number Diff line
@@ -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 */

/*
+2 −0
Original line number Diff line number Diff line
@@ -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,
+4 −1
Original line number Diff line number Diff line
@@ -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++;

+7 −3
Original line number Diff line number Diff line
@@ -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