Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/power/cpupower/lib/powercap.c
26288 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* (C) 2016 SUSE Software Solutions GmbH
4
* Thomas Renninger <[email protected]>
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
18
static 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
39
static 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
}
67
out_close:
68
close(fd);
69
out:
70
return ret;
71
}
72
73
int 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
*/
83
int 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
*/
93
int 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
109
enum 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
117
static 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
124
static 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
146
int 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
151
int 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
156
int 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
161
int 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
166
int 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
181
int powercap_zone_set_enabled(struct powercap_zone *zone, int mode)
182
{
183
/* To be done if needed */
184
return 0;
185
}
186
187
188
int 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
262
struct 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
290
int 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
309