diff --git a/cpupower.changes b/cpupower.changes index f106d39..9dd3f5f 100644 --- a/cpupower.changes +++ b/cpupower.changes @@ -1,3 +1,12 @@ +------------------------------------------------------------------- +Fri Oct 20 15:09:15 UTC 2017 - trenn@suse.de + +fate#321274 +- Provide rapl domain info (cpupower powercap-info cmd) +* Add: cpupower_rapl.patch +- Provide rapl power monitoring +* Add: rapl_monitor.patch + ------------------------------------------------------------------- Fri Oct 6 13:01:48 UTC 2017 - josef.moellers@suse.com diff --git a/cpupower.spec b/cpupower.spec index 80259ce..b5734c9 100644 --- a/cpupower.spec +++ b/cpupower.spec @@ -1,7 +1,7 @@ # # spec file for package cpupower # -# Copyright (c) 2017 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. # Author: Thomas Renninger # # All modifications and additions to the file contributed by third parties @@ -31,6 +31,9 @@ Source: %name-%version.tar.bz2 Source1: turbostat-%tsversion.tar.bz2 Source2: cpupower_export_tarball_from_git.sh +Patch1: cpupower_rapl.patch +Patch2: rapl_monitor.patch + Patch20: turbostat_fix_man_perm.patch Patch22: turbostat_makefile_fix_asm_header.patch # Fixes bsc#1048546: @@ -79,6 +82,8 @@ powersave module. %prep %setup -D -b 1 +%patch1 -p1 +%patch2 -p1 cd ../turbostat-%tsversion %patch20 -p1 %patch22 -p1 @@ -144,6 +149,7 @@ cd ../turbostat-%tsversion %defattr(-,root,root) %_includedir/cpufreq.h %_includedir/cpuidle.h +/usr/include/powercap.h %_libdir/libcpu*.so %changelog diff --git a/cpupower_rapl.patch b/cpupower_rapl.patch new file mode 100644 index 0000000..5b93645 --- /dev/null +++ b/cpupower_rapl.patch @@ -0,0 +1,647 @@ +cpupower: Introduce powercap intel-rapl library helpers and powercap-info command + +Read out powercap zone information via: +cpupower powercap-info +and show the zone hierarchy to the user: + +./cpupower powercap-info +Driver: intel-rapl +Powercap domain hierarchy: + +Zone: package-0 (enabled) +Power consumption can be monitored in micro Watts + + Zone: core (disabled) + Power consumption can be monitored in micro Watts + + Zone: uncore (disabled) + Power consumption can be monitored in micro Watts + + Zone: dram (disabled) + Power consumption can be monitored in micro Watts + +There is a dummy -a option for powercap-info which can/should be used to show +more detailed info later. Like that other args can be added easily later as well. + +Signed-off-by: Thomas Renninger + +Index: cpupower-4.10/Makefile +=================================================================== +--- cpupower-4.10.orig/Makefile 2017-03-31 18:14:02.031075768 +0200 ++++ cpupower-4.10/Makefile 2017-03-31 18:35:37.412218184 +0200 +@@ -135,7 +135,7 @@ UTIL_OBJS = utils/helpers/amd.o utils/h + utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \ + utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ + utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o \ +- utils/cpuidle-set.o ++ utils/cpuidle-set.o utils/powercap-info.o + + UTIL_SRC := $(UTIL_OBJS:.o=.c) + +@@ -145,9 +145,9 @@ UTIL_HEADERS = utils/helpers/helpers.h u + utils/helpers/bitmask.h \ + utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def + +-LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h +-LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c +-LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o ++LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h lib/powercap.h ++LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c lib/powercap.c ++LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o lib/powercap.o + LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS)) + + CFLAGS += -pipe +@@ -278,6 +278,7 @@ install-lib: + $(INSTALL) -d $(DESTDIR)${includedir} + $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h + $(INSTALL_DATA) lib/cpuidle.h $(DESTDIR)${includedir}/cpuidle.h ++ $(INSTALL_DATA) lib/powercap.h $(DESTDIR)${includedir}/powercap.h + + install-tools: + $(INSTALL) -d $(DESTDIR)${bindir} +@@ -292,6 +293,7 @@ install-man: + $(INSTALL_DATA) -D man/cpupower-set.1 $(DESTDIR)${mandir}/man1/cpupower-set.1 + $(INSTALL_DATA) -D man/cpupower-info.1 $(DESTDIR)${mandir}/man1/cpupower-info.1 + $(INSTALL_DATA) -D man/cpupower-monitor.1 $(DESTDIR)${mandir}/man1/cpupower-monitor.1 ++ $(INSTALL_DATA) -D man/cpupower-powercap-info.1 $(DESTDIR)${mandir}/man1/cpupower-powercap-info.1 + + install-gmo: + $(INSTALL) -d $(DESTDIR)${localedir} +@@ -321,6 +323,7 @@ uninstall: + - rm -f $(DESTDIR)${mandir}/man1/cpupower-set.1 + - rm -f $(DESTDIR)${mandir}/man1/cpupower-info.1 + - rm -f $(DESTDIR)${mandir}/man1/cpupower-monitor.1 ++ - rm -f $(DESTDIR)${mandir}/man1/cpupower-powercap-info.1 + - for HLANG in $(LANGUAGES); do \ + rm -f $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \ + done; +Index: cpupower-4.10/bench/Makefile +=================================================================== +--- cpupower-4.10.orig/bench/Makefile 2017-03-31 18:14:02.035075995 +0200 ++++ cpupower-4.10/bench/Makefile 2017-03-31 18:14:16.675904015 +0200 +@@ -8,7 +8,7 @@ endif + ifeq ($(strip $(STATIC)),true) + LIBS = -L../ -L$(OUTPUT) -lm + OBJS = $(OUTPUT)main.o $(OUTPUT)parse.o $(OUTPUT)system.o $(OUTPUT)benchmark.o \ +- $(OUTPUT)../lib/cpufreq.o $(OUTPUT)../lib/sysfs.o ++ $(OUTPUT)../lib/cpufreq.o $(OUTPUT)../lib/cpupower.o + else + LIBS = -L../ -L$(OUTPUT) -lm -lcpupower + OBJS = $(OUTPUT)main.o $(OUTPUT)parse.o $(OUTPUT)system.o $(OUTPUT)benchmark.o +Index: cpupower-4.10/lib/powercap.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ cpupower-4.10/lib/powercap.c 2017-03-31 18:37:15.529756175 +0200 +@@ -0,0 +1,290 @@ ++/* ++ * (C) 2016 Thomas Renninger ++ * ++ * Licensed under the terms of the GNU GPL License version 2. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "powercap.h" ++ ++static unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen) ++{ ++ int fd; ++ ssize_t numread; ++ ++ fd = open(path, O_RDONLY); ++ if (fd == -1) ++ return 0; ++ ++ numread = read(fd, buf, buflen - 1); ++ if (numread < 1) { ++ close(fd); ++ return 0; ++ } ++ ++ buf[numread] = '\0'; ++ close(fd); ++ ++ return (unsigned int) numread; ++} ++ ++static int sysfs_get_enabled(char *path, int *mode) ++{ ++ int fd; ++ char yes_no; ++ ++ *mode = 0; ++ ++ fd = open(path, O_RDONLY); ++ if (fd == -1) ++ return -1; ++ ++ if (read(fd, &yes_no, 1) != 1) { ++ close(fd); ++ return -1; ++ } ++ ++ if (yes_no == '1') { ++ *mode = 1; ++ return 0; ++ } else if (yes_no == '0') { ++ return 0; ++ } ++ return -1; ++} ++ ++int powercap_get_enabled(int *mode) ++{ ++ char path[SYSFS_PATH_MAX] = PATH_TO_POWERCAP "/intel-rapl/enabled"; ++ return sysfs_get_enabled(path, mode); ++} ++ ++/* ++ * Hardcoded, because rapl is the only powercap implementation ++- * this needs to get more generic if more powercap implementations ++ * should show up ++ */ ++int powercap_get_driver(char *driver, int buflen) ++{ ++ char file[SYSFS_PATH_MAX] = PATH_TO_RAPL; ++ struct stat statbuf; ++ ++ if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) { ++ driver = ""; ++ return -1; ++ } else if (buflen > 10) { ++ strcpy(driver, "intel-rapl"); ++ return 0; ++ } else ++ return -1; ++} ++ ++enum powercap_get64 { ++ GET_ENERGY_UJ, ++ GET_MAX_ENERGY_RANGE_UJ, ++ GET_POWER_UW, ++ GET_MAX_POWER_RANGE_UW, ++ MAX_GET_64_FILES ++}; ++ ++static const char *powercap_get64_files[MAX_GET_64_FILES] = { ++ [GET_POWER_UW] = "power_uw", ++ [GET_MAX_POWER_RANGE_UW] = "max_power_range_uw", ++ [GET_ENERGY_UJ] = "energy_uj", ++ [GET_MAX_ENERGY_RANGE_UJ] = "max_energy_range_uj", ++}; ++ ++static int sysfs_powercap_get64_val(struct powercap_zone *zone, ++ enum powercap_get64 which, ++ uint64_t *val) ++{ ++ char file[SYSFS_PATH_MAX] = PATH_TO_POWERCAP "/"; ++ int ret; ++ char buf[MAX_LINE_LEN]; ++ ++ strcat(file, zone->sys_name); ++ strcat(file, "/"); ++ strcat (file, powercap_get64_files[which]); ++ ++ ret = sysfs_read_file(file, buf, MAX_LINE_LEN); ++ if (ret < 0 ) ++ return ret; ++ if (ret == 0) ++ return -1; ++ ++ *val = strtoll(buf, NULL, 10); ++ return 0; ++} ++ ++ ++int powercap_get_max_energy_range_uj (struct powercap_zone *zone, uint64_t *val) ++{ ++ return sysfs_powercap_get64_val(zone, GET_MAX_ENERGY_RANGE_UJ, val); ++} ++ ++int powercap_get_energy_uj (struct powercap_zone *zone, uint64_t *val) ++{ ++ return sysfs_powercap_get64_val(zone, GET_ENERGY_UJ, val); ++} ++ ++int powercap_get_max_power_range_uw (struct powercap_zone *zone, uint64_t *val) ++{ ++ return sysfs_powercap_get64_val(zone, GET_MAX_POWER_RANGE_UW, val); ++} ++ ++int powercap_get_power_uw (struct powercap_zone *zone, uint64_t *val) ++{ ++ return sysfs_powercap_get64_val(zone, GET_POWER_UW, val); ++} ++ ++int powercap_zone_get_enabled (struct powercap_zone *zone, int *mode) ++{ ++ char path[SYSFS_PATH_MAX] = PATH_TO_POWERCAP; ++ ++ if ((strlen(PATH_TO_POWERCAP) + strlen(zone->sys_name)) + ++ strlen("/enabled") + 1 >= SYSFS_PATH_MAX) ++ return -1; ++ ++ strcat(path, "/"); ++ strcat(path, zone->sys_name); ++ strcat(path, "/enabled"); ++ ++ return sysfs_get_enabled(path, mode); ++} ++ ++int powercap_zone_set_enabled (struct powercap_zone *zone, int mode) ++{ ++ /* To be done if needed */ ++ return 0; ++} ++ ++ ++int powercap_read_zone(struct powercap_zone *zone) ++{ ++ struct dirent* dent; ++ DIR* zone_dir; ++ char sysfs_dir[SYSFS_PATH_MAX] = PATH_TO_POWERCAP; ++ struct powercap_zone *child_zone; ++ char file[SYSFS_PATH_MAX] = PATH_TO_POWERCAP; ++ int i, ret = 0; ++ uint64_t val = 0; ++ ++ strcat(sysfs_dir, "/"); ++ strcat(sysfs_dir, zone->sys_name); ++ ++ zone_dir = opendir(sysfs_dir); ++ if (zone_dir == NULL) ++ return -1; ++ ++ strcat(file, "/"); ++ strcat(file, zone->sys_name); ++ strcat(file, "/name"); ++ sysfs_read_file(file, zone->name, MAX_LINE_LEN); ++ if (zone->parent) ++ zone->tree_depth = zone->parent->tree_depth + 1; ++ ret = powercap_get_energy_uj(zone, &val); ++ if (ret == 0) ++ zone->has_energy_uj = 1; ++ ret = powercap_get_power_uw(zone, &val); ++ if (ret == 0) ++ zone->has_power_uw = 1; ++ ++ while((dent = readdir(zone_dir)) != NULL) { ++ struct stat st; ++ ++ if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) ++ continue; ++ ++ if (stat(dent->d_name, &st) != 0 || !S_ISDIR(st.st_mode)) ++ if (fstatat(dirfd(zone_dir), dent->d_name, &st, 0) < 0) ++ continue; ++ ++ if (strncmp(dent->d_name, "intel-rapl:", 11) != 0) ++ continue; ++ ++ child_zone = calloc(1, sizeof(struct powercap_zone)); ++ if (child_zone == NULL) ++ return -1; ++ for (i = 0; i < POWERCAP_MAX_CHILD_ZONES; i++) { ++ if (zone->children[i] == NULL) { ++ zone->children[i] = child_zone; ++ break; ++ } ++ if (i == POWERCAP_MAX_CHILD_ZONES - 1) { ++ free(child_zone); ++ fprintf(stderr, "Reached POWERCAP_MAX_CHILD_ZONES %d\n", ++ POWERCAP_MAX_CHILD_ZONES); ++ return -1; ++ } ++ } ++ strcpy(child_zone->sys_name, zone->sys_name); ++ strcat(child_zone->sys_name, "/"); ++ strcat(child_zone->sys_name, dent->d_name); ++ child_zone->parent = zone; ++ if (zone->tree_depth >= POWERCAP_MAX_TREE_DEPTH) { ++ fprintf(stderr, "Maximum zone hierachy depth[%d] reached\n", ++ POWERCAP_MAX_TREE_DEPTH); ++ ret = -1; ++ break; ++ } ++ powercap_read_zone(child_zone); ++ } ++ closedir(zone_dir); ++ return ret; ++} ++ ++struct powercap_zone *powercap_init_zones() ++{ ++ int enabled; ++ struct powercap_zone *root_zone; ++ int ret; ++ char file[SYSFS_PATH_MAX] = PATH_TO_RAPL "/enabled"; ++ ++ ret = sysfs_get_enabled(file, &enabled); ++ ++ if (ret) ++ return NULL; ++ ++ if (!enabled) ++ return NULL; ++ ++ root_zone = calloc(1, sizeof(struct powercap_zone)); ++ if (!root_zone) ++ return NULL; ++ ++ strcpy(root_zone->sys_name, "intel-rapl/intel-rapl:0"); ++ ++ powercap_read_zone(root_zone); ++ ++ return root_zone; ++} ++ ++/* Call function *f on the passed zone and all its children */ ++ ++int powercap_walk_zones(struct powercap_zone *zone, ++ int (*f)(struct powercap_zone *zone)) ++{ ++ int i, ret; ++ ++ if (!zone) ++ return -1; ++ ++ ret = f(zone); ++ if (ret) ++ return ret; ++ ++ for (i = 0; i < POWERCAP_MAX_CHILD_ZONES; i++) { ++ if (zone->children[i] != NULL) { ++ powercap_walk_zones(zone->children[i], f); ++ } ++ } ++ return 0; ++} +Index: cpupower-4.10/lib/powercap.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ cpupower-4.10/lib/powercap.h 2017-03-31 18:14:16.675904015 +0200 +@@ -0,0 +1,54 @@ ++/* ++ * (C) 2016 Thomas Renninger ++ * ++ * Licensed under the terms of the GNU GPL License version 2. ++ */ ++ ++#ifndef __CPUPOWER_RAPL_H__ ++#define __CPUPOWER_RAPL_H__ ++ ++#define PATH_TO_POWERCAP "/sys/devices/virtual/powercap" ++#define PATH_TO_RAPL "/sys/devices/virtual/powercap/intel-rapl" ++#define PATH_TO_RAPL_CLASS "/sys/devices/virtual/powercap/intel-rapl" ++ ++#define POWERCAP_MAX_CHILD_ZONES 10 ++#define POWERCAP_MAX_TREE_DEPTH 10 ++ ++#define MAX_LINE_LEN 4096 ++#define SYSFS_PATH_MAX 255 ++ ++#include ++ ++struct powercap_zone { ++ char name[MAX_LINE_LEN]; ++ /* ++ * sys_name relative to PATH_TO_POWERCAP, ++ * do not forget the / in between ++ */ ++ char sys_name[SYSFS_PATH_MAX]; ++ int tree_depth; ++ struct powercap_zone *parent; ++ struct powercap_zone *children[POWERCAP_MAX_CHILD_ZONES]; ++ /* More possible caps or attributes to be added? */ ++ uint32_t has_power_uw:1, ++ has_energy_uj:1; ++ ++}; ++ ++int powercap_walk_zones(struct powercap_zone *zone, ++ int (*f)(struct powercap_zone *zone)); ++ ++struct powercap_zone *powercap_init_zones(); ++int powercap_get_enabled(int *mode); ++int powercap_set_enabled(int mode); ++int powercap_get_driver(char *driver, int buflen); ++ ++int powercap_get_max_energy_range_uj (struct powercap_zone *zone, uint64_t *val); ++int powercap_get_energy_uj (struct powercap_zone *zone, uint64_t *val); ++int powercap_get_max_power_range_uw (struct powercap_zone *zone , uint64_t *val); ++int powercap_get_power_uw (struct powercap_zone *zone, uint64_t *val); ++int powercap_zone_get_enabled (struct powercap_zone *zone, int *mode); ++int powercap_zone_set_enabled (struct powercap_zone *zone, int mode); ++ ++ ++#endif /* __CPUPOWER_RAPL_H__ */ +Index: cpupower-4.10/utils/builtin.h +=================================================================== +--- cpupower-4.10.orig/utils/builtin.h 2017-03-31 18:14:02.035075995 +0200 ++++ cpupower-4.10/utils/builtin.h 2017-03-31 18:14:16.675904015 +0200 +@@ -7,6 +7,8 @@ extern int cmd_freq_set(int argc, const + extern int cmd_freq_info(int argc, const char **argv); + extern int cmd_idle_set(int argc, const char **argv); + extern int cmd_idle_info(int argc, const char **argv); ++extern int cmd_cap_info(int argc, const char **argv); ++extern int cmd_cap_set(int argc, const char **argv); + extern int cmd_monitor(int argc, const char **argv); + + #endif +Index: cpupower-4.10/utils/cpupower.c +=================================================================== +--- cpupower-4.10.orig/utils/cpupower.c 2017-03-31 18:14:02.035075995 +0200 ++++ cpupower-4.10/utils/cpupower.c 2017-03-31 18:14:16.675904015 +0200 +@@ -51,6 +51,7 @@ static struct cmd_struct commands[] = { + { "frequency-set", cmd_freq_set, 1 }, + { "idle-info", cmd_idle_info, 0 }, + { "idle-set", cmd_idle_set, 1 }, ++ { "powercap-info", cmd_cap_info, 0 }, + { "set", cmd_set, 1 }, + { "info", cmd_info, 0 }, + { "monitor", cmd_monitor, 0 }, +Index: cpupower-4.10/utils/powercap-info.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ cpupower-4.10/utils/powercap-info.c 2017-03-31 18:14:16.675904015 +0200 +@@ -0,0 +1,113 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "powercap.h" ++#include "helpers/helpers.h" ++ ++int powercap_show_all = 0; ++ ++static struct option info_opts[] = ++{ ++ { "all", no_argument, NULL, 'a'}, ++ { }, ++}; ++ ++static int powercap_print_one_zone(struct powercap_zone *zone) ++{ ++ int mode, i, ret = 0; ++ char pr_prefix[1024] = ""; ++ ++ for (i = 0; i < zone->tree_depth && i < POWERCAP_MAX_TREE_DEPTH; i++) ++ strcat (pr_prefix, "\t"); ++ ++ printf("%sZone: %s", pr_prefix, zone->name); ++ ret = powercap_zone_get_enabled(zone, &mode); ++ if (ret < 0) ++ return ret; ++ printf(" (%s)\n", mode ? "enabled" : "disabled"); ++ ++ if (zone->has_power_uw) ++printf(_("%sEnergy consumption can be monitored in micro Jules\n"), ++ pr_prefix); ++ ++ if (zone->has_energy_uj) ++printf(_("%sPower consumption can be monitored in micro Watts\n"), ++ pr_prefix); ++ ++ printf("\n"); ++ ++ if (ret != 0) ++ return ret; ++ return ret; ++} ++ ++static int powercap_show() ++{ ++ struct powercap_zone *root_zone; ++ char line[MAX_LINE_LEN] = ""; ++ int ret, val; ++ ++ ret = powercap_get_driver(line, MAX_LINE_LEN); ++ if (ret < 0) { ++ printf(_("No powercapping driver loaded\n")); ++ return ret; ++ } ++ ++ printf("Driver: %s\n", line); ++ ret = powercap_get_enabled(&val); ++ if (ret < 0) ++ return ret; ++ if (!val) { ++ printf(_("Powercapping is disabled\n")); ++ return -1; ++ } ++ ++ printf(_("Powercap domain hierarchy:\n\n")); ++ root_zone = powercap_init_zones(); ++ ++ if (root_zone == NULL) { ++ printf(_("No powercap info found\n")); ++ return 1; ++ } ++ ++ powercap_walk_zones(root_zone, powercap_print_one_zone); ++ ++ return 0; ++} ++ ++int cmd_cap_set(int argc, char **argv) ++{ ++ return 0; ++}; ++int cmd_cap_info(int argc, char **argv) ++{ ++ extern char *optarg; ++ extern int optind, opterr, optopt; ++ int ret = 0, cont = 1; ++ do { ++ ret = getopt_long(argc, argv, "a", info_opts, NULL); ++ switch (ret) { ++ case '?': ++ cont = 0; ++ break; ++ case -1: ++ cont = 0; ++ break; ++ case 'a': ++ powercap_show_all = 1; ++ break; ++ default: ++ fprintf(stderr, _("invalid or unknown argument\n")); ++ return EXIT_FAILURE; ++ } ++ } while (cont); ++ ++ powercap_show(); ++ return 0; ++} +Index: cpupower-4.10/utils/helpers/sysfs.c +=================================================================== +--- cpupower-4.10.orig/utils/helpers/sysfs.c 2017-03-31 18:14:02.035075995 +0200 ++++ cpupower-4.10/utils/helpers/sysfs.c 2017-03-31 18:14:16.675904015 +0200 +@@ -18,7 +18,7 @@ + + unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen) + { +- int fd; ++ int fd, i; + ssize_t numread; + + fd = open(path, O_RDONLY); +@@ -31,6 +31,16 @@ unsigned int sysfs_read_file(const char + return 0; + } + ++ /* ++ * Sigh, sysfs workaround, some do return \0 ++ * ++ */ ++ for (i = 0; i < numread; i++) { ++ if (buf[i] == '\n') { ++ numread = i; ++ break; ++ } ++ } + buf[numread] = '\0'; + close(fd); + +Index: cpupower-4.10/man/cpupower-powercap-info.1 +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ cpupower-4.10/man/cpupower-powercap-info.1 2017-03-31 18:14:16.679904240 +0200 +@@ -0,0 +1,25 @@ ++.TH CPUPOWER\-POWERCAP\-INFO "1" "05/08/2016" "" "cpupower Manual" ++.SH NAME ++cpupower\-powercap\-info \- Shows powercapping related kernel and hardware configurations ++.SH SYNOPSIS ++.ft B ++.B cpupower powercap-info ++ ++.SH DESCRIPTION ++\fBcpupower powercap-info \fP shows kernel powercapping subsystem information. ++This needs hardware support and a loaded powercapping driver (at this time only ++intel_rapl driver exits) exporting hardware values userspace via sysfs. ++ ++Some options are platform wide, some affect single cores. By default values ++of core zero are displayed only. cpupower --cpu all cpuinfo will show the ++settings of all cores, see cpupower(1) how to choose specific cores. ++ ++.SH "DOCUMENTATION" ++ ++kernel sources: ++Documentation/power/powercap/powercap.txt ++ ++ ++.SH "SEE ALSO" ++ ++cpupower(1) diff --git a/rapl_monitor.patch b/rapl_monitor.patch new file mode 100644 index 0000000..a398c3e --- /dev/null +++ b/rapl_monitor.patch @@ -0,0 +1,193 @@ +cpupower: rapl monitor - shows the used power consumption in uj for each rapl domain + + +Signed-off-by: Thomas Renninger + +diff --git a/Makefile b/Makefile +index bf968ec..9e746be 100644 +--- a/Makefile ++++ b/Makefile +@@ -136,6 +136,7 @@ UTIL_OBJS = utils/helpers/amd.o utils/helpers/msr.o \ + utils/idle_monitor/hsw_ext_idle.o \ + utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \ + utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \ ++ utils/idle_monitor/rapl_monitor.o \ + utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ + utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o \ + utils/cpuidle-set.o utils/powercap-info.o +diff --git a/utils/idle_monitor/cpupower-monitor.c b/utils/idle_monitor/cpupower-monitor.c +index 05f953f..da1857a 100644 +--- a/utils/idle_monitor/cpupower-monitor.c ++++ b/utils/idle_monitor/cpupower-monitor.c +@@ -454,9 +454,10 @@ int cmd_monitor(int argc, char **argv) + print_results(1, cpu); + } + +- for (num = 0; num < avail_monitors; num++) +- monitors[num]->unregister(); +- ++ for (num = 0; num < avail_monitors; num++) { ++ if (monitors[num]->unregister) ++ monitors[num]->unregister(); ++ } + cpu_topology_release(cpu_top); + return 0; + } +diff --git a/utils/idle_monitor/idle_monitors.def b/utils/idle_monitor/idle_monitors.def +index 0d6ba4d..7c926e9 100644 +--- a/utils/idle_monitor/idle_monitors.def ++++ b/utils/idle_monitor/idle_monitors.def +@@ -4,5 +4,6 @@ DEF(intel_nhm) + DEF(intel_snb) + DEF(intel_hsw_ext) + DEF(mperf) ++DEF(rapl) + #endif + DEF(cpuidle_sysfs) +diff --git a/utils/idle_monitor/rapl_monitor.c b/utils/idle_monitor/rapl_monitor.c +new file mode 100644 +index 0000000..2b02b21 +--- /dev/null ++++ b/utils/idle_monitor/rapl_monitor.c +@@ -0,0 +1,141 @@ ++/* ++ * (C) 2016 Thomas Renninger ++ * ++ * Licensed under the terms of the GNU GPL License version 2. ++ * ++ */ ++ ++#if defined(__i386__) || defined(__x86_64__) ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "idle_monitor/cpupower-monitor.h" ++#include "helpers/helpers.h" ++#include "powercap.h" ++ ++#define MAX_RAPL_ZONES 10 ++ ++int rapl_zone_count = 0; ++cstate_t rapl_zones[MAX_RAPL_ZONES]; ++struct powercap_zone *rapl_zones_pt[MAX_RAPL_ZONES] = { 0 }; ++ ++unsigned long long rapl_zone_previous_count[MAX_RAPL_ZONES]; ++unsigned long long rapl_zone_current_count[MAX_RAPL_ZONES]; ++unsigned long long rapl_max_count; ++ ++static int rapl_get_count_uj(unsigned int id, unsigned long long *count, ++ unsigned int cpu) ++{ ++ if (rapl_zones_pt[id] == NULL) ++ /* error */ ++ return -1; ++ ++ *count = rapl_zone_current_count[id] - rapl_zone_previous_count[id]; ++ ++ return 0; ++} ++ ++static int powercap_count_zones(struct powercap_zone *zone) ++{ ++ if (rapl_zone_count >= MAX_RAPL_ZONES) ++ return -1; ++ ++ if (!zone->has_energy_uj) ++ return 0; ++ ++ strncpy(rapl_zones[rapl_zone_count].name, zone->name, CSTATE_NAME_LEN - 1); ++ strcpy(rapl_zones[rapl_zone_count].desc, ""); ++ rapl_zones[rapl_zone_count].id = rapl_zone_count; ++ rapl_zones[rapl_zone_count].range = RANGE_MACHINE; ++ rapl_zones[rapl_zone_count].get_count = rapl_get_count_uj; ++ rapl_zones_pt[rapl_zone_count] = zone; ++ rapl_zone_count++; ++ ++ return 0; ++} ++ ++static int rapl_start(void) ++{ ++ int i, ret; ++ uint64_t uj_val; ++ ++ for (i = 0; i < rapl_zone_count; i++) { ++ ret = powercap_get_energy_uj(rapl_zones_pt[i], &uj_val); ++ if (ret) ++ return ret; ++ rapl_zone_previous_count[i] = uj_val; ++ } ++ ++ return 0; ++} ++ ++static int rapl_stop(void) ++{ ++ int i; ++ uint64_t uj_val; ++ ++ for (i = 0; i < rapl_zone_count; i++) { ++ int ret; ++ ret = powercap_get_energy_uj(rapl_zones_pt[i], &uj_val); ++ if (ret) ++ return ret; ++ rapl_zone_current_count[i] = uj_val; ++ if (rapl_max_count < uj_val) ++ rapl_max_count = uj_val - rapl_zone_previous_count[i]; ++ } ++ return 0; ++} ++ ++struct cpuidle_monitor *rapl_register(void) ++{ ++ struct powercap_zone *root_zone; ++ char line[MAX_LINE_LEN] = ""; ++ int ret, val; ++ ++ ret = powercap_get_driver(line, MAX_LINE_LEN); ++ if (ret < 0) { ++ dprint("No powercapping driver loaded\n"); ++ return NULL; ++ } ++ ++ dprint("Driver: %s\n", line); ++ ret = powercap_get_enabled(&val); ++ if (ret < 0) ++ return NULL; ++ if (!val) { ++ dprint("Powercapping is disabled\n"); ++ return NULL; ++ } ++ ++ dprint("Powercap domain hierarchy:\n\n"); ++ root_zone = powercap_init_zones(); ++ ++ if (root_zone == NULL) { ++ dprint("No powercap info found\n"); ++ return NULL; ++ } ++ ++ powercap_walk_zones(root_zone, powercap_count_zones); ++ rapl_monitor.hw_states_num = rapl_zone_count; ++ ++ return &rapl_monitor; ++} ++ ++struct cpuidle_monitor rapl_monitor = { ++ .name = "RAPL", ++ .hw_states = rapl_zones, ++ .hw_states_num = 0, ++ .start = rapl_start, ++ .stop = rapl_stop, ++ .do_register = rapl_register, ++ .needs_root = 0, ++ .overflow_s = 60 * 60 * 24 * 100, /* To be implemented */ ++}; ++ ++#endif