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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Thomas Renninger
				Thomas Renninger