brintos

brintos / linux-shallow public Read only

0
0
Text · 6.3 KiB · 94a0c69 Raw
308 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  (C) 2016 SUSE Software Solutions GmbH4 *           Thomas Renninger <trenn@suse.de>5 */6 7#include <sys/types.h>8#include <sys/stat.h>9#include <unistd.h>10#include <stdlib.h>11#include <string.h>12#include <fcntl.h>13#include <stdio.h>14#include <dirent.h>15 16#include "powercap.h"17 18static unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)19{20	int fd;21	ssize_t numread;22 23	fd = open(path, O_RDONLY);24	if (fd == -1)25		return 0;26 27	numread = read(fd, buf, buflen - 1);28	if (numread < 1) {29		close(fd);30		return 0;31	}32 33	buf[numread] = '\0';34	close(fd);35 36	return (unsigned int) numread;37}38 39static int sysfs_get_enabled(char *path, int *mode)40{41	int fd;42	char yes_no;43	int ret = 0;44 45	*mode = 0;46 47	fd = open(path, O_RDONLY);48	if (fd == -1) {49		ret = -1;50		goto out;51	}52 53	if (read(fd, &yes_no, 1) != 1) {54		ret = -1;55		goto out_close;56	}57 58	if (yes_no == '1') {59		*mode = 1;60		goto out_close;61	} else if (yes_no == '0') {62		goto out_close;63	} else {64		ret = -1;65		goto out_close;66	}67out_close:68	close(fd);69out:70	return ret;71}72 73int powercap_get_enabled(int *mode)74{75	char path[SYSFS_PATH_MAX] = PATH_TO_POWERCAP "/intel-rapl/enabled";76 77	return sysfs_get_enabled(path, mode);78}79 80/*81 * TODO: implement function. Returns dummy 0 for now.82 */83int powercap_set_enabled(int mode)84{85	return 0;86}87 88/*89 * Hardcoded, because rapl is the only powercap implementation90- * this needs to get more generic if more powercap implementations91 * should show up92 */93int powercap_get_driver(char *driver, int buflen)94{95	char file[SYSFS_PATH_MAX] = PATH_TO_RAPL;96 97	struct stat statbuf;98 99	if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {100		driver = "";101		return -1;102	} else if (buflen > 10) {103		strcpy(driver, "intel-rapl");104		return 0;105	} else106		return -1;107}108 109enum powercap_get64 {110	GET_ENERGY_UJ,111	GET_MAX_ENERGY_RANGE_UJ,112	GET_POWER_UW,113	GET_MAX_POWER_RANGE_UW,114	MAX_GET_64_FILES115};116 117static const char *powercap_get64_files[MAX_GET_64_FILES] = {118	[GET_POWER_UW] = "power_uw",119	[GET_MAX_POWER_RANGE_UW] = "max_power_range_uw",120	[GET_ENERGY_UJ] = "energy_uj",121	[GET_MAX_ENERGY_RANGE_UJ] = "max_energy_range_uj",122};123 124static int sysfs_powercap_get64_val(struct powercap_zone *zone,125				      enum powercap_get64 which,126				      uint64_t *val)127{128	char file[SYSFS_PATH_MAX] = PATH_TO_POWERCAP "/";129	int ret;130	char buf[MAX_LINE_LEN];131 132	strcat(file, zone->sys_name);133	strcat(file, "/");134	strcat(file, powercap_get64_files[which]);135 136	ret = sysfs_read_file(file, buf, MAX_LINE_LEN);137	if (ret < 0)138		return ret;139	if (ret == 0)140		return -1;141 142	*val = strtoll(buf, NULL, 10);143	return 0;144}145 146int powercap_get_max_energy_range_uj(struct powercap_zone *zone, uint64_t *val)147{148	return sysfs_powercap_get64_val(zone, GET_MAX_ENERGY_RANGE_UJ, val);149}150 151int powercap_get_energy_uj(struct powercap_zone *zone, uint64_t *val)152{153	return sysfs_powercap_get64_val(zone, GET_ENERGY_UJ, val);154}155 156int powercap_get_max_power_range_uw(struct powercap_zone *zone, uint64_t *val)157{158	return sysfs_powercap_get64_val(zone, GET_MAX_POWER_RANGE_UW, val);159}160 161int powercap_get_power_uw(struct powercap_zone *zone, uint64_t *val)162{163	return sysfs_powercap_get64_val(zone, GET_POWER_UW, val);164}165 166int powercap_zone_get_enabled(struct powercap_zone *zone, int *mode)167{168	char path[SYSFS_PATH_MAX] = PATH_TO_POWERCAP;169 170	if ((strlen(PATH_TO_POWERCAP) + strlen(zone->sys_name)) +171	    strlen("/enabled") + 1 >= SYSFS_PATH_MAX)172		return -1;173 174	strcat(path, "/");175	strcat(path, zone->sys_name);176	strcat(path, "/enabled");177 178	return sysfs_get_enabled(path, mode);179}180 181int powercap_zone_set_enabled(struct powercap_zone *zone, int mode)182{183	/* To be done if needed */184	return 0;185}186 187 188int powercap_read_zone(struct powercap_zone *zone)189{190	struct dirent *dent;191	DIR *zone_dir;192	char sysfs_dir[SYSFS_PATH_MAX] = PATH_TO_POWERCAP;193	struct powercap_zone *child_zone;194	char file[SYSFS_PATH_MAX] = PATH_TO_POWERCAP;195	int i, ret = 0;196	uint64_t val = 0;197 198	strcat(sysfs_dir, "/");199	strcat(sysfs_dir, zone->sys_name);200 201	zone_dir = opendir(sysfs_dir);202	if (zone_dir == NULL)203		return -1;204 205	strcat(file, "/");206	strcat(file, zone->sys_name);207	strcat(file, "/name");208	sysfs_read_file(file, zone->name, MAX_LINE_LEN);209	if (zone->parent)210		zone->tree_depth = zone->parent->tree_depth + 1;211	ret = powercap_get_energy_uj(zone, &val);212	if (ret == 0)213		zone->has_energy_uj = 1;214	ret = powercap_get_power_uw(zone, &val);215	if (ret == 0)216		zone->has_power_uw = 1;217 218	while ((dent = readdir(zone_dir)) != NULL) {219		struct stat st;220 221		if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)222			continue;223 224		if (stat(dent->d_name, &st) != 0 || !S_ISDIR(st.st_mode))225			if (fstatat(dirfd(zone_dir), dent->d_name, &st, 0) < 0)226				continue;227 228		if (strncmp(dent->d_name, "intel-rapl:", 11) != 0)229			continue;230 231		child_zone = calloc(1, sizeof(struct powercap_zone));232		if (child_zone == NULL)233			return -1;234		for (i = 0; i < POWERCAP_MAX_CHILD_ZONES; i++) {235			if (zone->children[i] == NULL) {236				zone->children[i] = child_zone;237				break;238			}239			if (i == POWERCAP_MAX_CHILD_ZONES - 1) {240				free(child_zone);241				fprintf(stderr, "Reached POWERCAP_MAX_CHILD_ZONES %d\n",242				       POWERCAP_MAX_CHILD_ZONES);243				return -1;244			}245		}246		strcpy(child_zone->sys_name, zone->sys_name);247		strcat(child_zone->sys_name, "/");248		strcat(child_zone->sys_name, dent->d_name);249		child_zone->parent = zone;250		if (zone->tree_depth >= POWERCAP_MAX_TREE_DEPTH) {251			fprintf(stderr, "Maximum zone hierarchy depth[%d] reached\n",252				POWERCAP_MAX_TREE_DEPTH);253			ret = -1;254			break;255		}256		powercap_read_zone(child_zone);257	}258	closedir(zone_dir);259	return ret;260}261 262struct powercap_zone *powercap_init_zones(void)263{264	int enabled;265	struct powercap_zone *root_zone;266	int ret;267	char file[SYSFS_PATH_MAX] = PATH_TO_RAPL "/enabled";268 269	ret = sysfs_get_enabled(file, &enabled);270 271	if (ret)272		return NULL;273 274	if (!enabled)275		return NULL;276 277	root_zone = calloc(1, sizeof(struct powercap_zone));278	if (!root_zone)279		return NULL;280 281	strcpy(root_zone->sys_name, "intel-rapl/intel-rapl:0");282 283	powercap_read_zone(root_zone);284 285	return root_zone;286}287 288/* Call function *f on the passed zone and all its children */289 290int powercap_walk_zones(struct powercap_zone *zone,291			int (*f)(struct powercap_zone *zone))292{293	int i, ret;294 295	if (!zone)296		return -1;297 298	ret = f(zone);299	if (ret)300		return ret;301 302	for (i = 0; i < POWERCAP_MAX_CHILD_ZONES; i++) {303		if (zone->children[i] != NULL)304			powercap_walk_zones(zone->children[i], f);305	}306	return 0;307}308