File Index
Files and directories
Sign in
FILE

powercap.c

File preview with syntax highlighting.

linux-6.19.14/tools/power/cpupower/lib/powercap.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 *  (C) 2016 SUSE Software Solutions GmbH
  4 *           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 implementation
 90- * this needs to get more generic if more powercap implementations
 91 * should show up
 92 */
 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	} else
106		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_FILES
115};
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}
~/ Read-only file preview.