FILE
powercap.c
File preview with syntax highlighting.
linux-6.19.14/tools/power/cpupower/lib/powercap.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.