Commit ed6a0047 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branches 'pm-devfreq' and 'pm-tools'

Merge devfreq updates and cpupower utility updates for 6.2-rc1:

 - Add a private governor_data for devfreq governors (Kant Fan).

 - Reorganize devfreq code to use device_match_of_node() and
   devm_platform_get_and_ioremap_resource() instead of open coding
   them (ye xingchen, Minghao Chi).

 - Make cpupower choose base_cpu to display default cpupower details
   instead of picking CPU 0 (Saket Kumar Bhaskar).

 - Add Georgian translation to cpupower documentation (Zurab
   Kargareteli).

 - Introduce powercap intel-rapl library, powercap-info command, and
   RAPL monitor into cpupower (Thomas Renninger).

* pm-devfreq:
  PM / devfreq: event: use devm_platform_get_and_ioremap_resource()
  PM / devfreq: event: Use device_match_of_node()
  PM / devfreq: Use device_match_of_node()
  PM/devfreq: governor: Add a private governor_data for governor

* pm-tools:
  cpupower: rapl monitor - shows the used power consumption in uj for each rapl domain
  cpupower: Introduce powercap intel-rapl library and powercap-info command
  cpupower: Add Georgian translation
  tools/cpupower: Choose base_cpu to display default cpupower details
...@@ -233,7 +233,7 @@ struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(struct device *dev, ...@@ -233,7 +233,7 @@ struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(struct device *dev,
mutex_lock(&devfreq_event_list_lock); mutex_lock(&devfreq_event_list_lock);
list_for_each_entry(edev, &devfreq_event_list, node) { list_for_each_entry(edev, &devfreq_event_list, node) {
if (edev->dev.parent && edev->dev.parent->of_node == node) if (edev->dev.parent && device_match_of_node(edev->dev.parent, node))
goto out; goto out;
} }
......
...@@ -776,8 +776,7 @@ static void remove_sysfs_files(struct devfreq *devfreq, ...@@ -776,8 +776,7 @@ static void remove_sysfs_files(struct devfreq *devfreq,
* @dev: the device to add devfreq feature. * @dev: the device to add devfreq feature.
* @profile: device-specific profile to run devfreq. * @profile: device-specific profile to run devfreq.
* @governor_name: name of the policy to choose frequency. * @governor_name: name of the policy to choose frequency.
* @data: private data for the governor. The devfreq framework does not * @data: devfreq driver pass to governors, governor should not change it.
* touch this value.
*/ */
struct devfreq *devfreq_add_device(struct device *dev, struct devfreq *devfreq_add_device(struct device *dev,
struct devfreq_dev_profile *profile, struct devfreq_dev_profile *profile,
...@@ -1011,8 +1010,7 @@ static void devm_devfreq_dev_release(struct device *dev, void *res) ...@@ -1011,8 +1010,7 @@ static void devm_devfreq_dev_release(struct device *dev, void *res)
* @dev: the device to add devfreq feature. * @dev: the device to add devfreq feature.
* @profile: device-specific profile to run devfreq. * @profile: device-specific profile to run devfreq.
* @governor_name: name of the policy to choose frequency. * @governor_name: name of the policy to choose frequency.
* @data: private data for the governor. The devfreq framework does not * @data: devfreq driver pass to governors, governor should not change it.
* touch this value.
* *
* This function manages automatically the memory of devfreq device using device * This function manages automatically the memory of devfreq device using device
* resource management and simplify the free operation for memory of devfreq * resource management and simplify the free operation for memory of devfreq
...@@ -1059,7 +1057,7 @@ struct devfreq *devfreq_get_devfreq_by_node(struct device_node *node) ...@@ -1059,7 +1057,7 @@ struct devfreq *devfreq_get_devfreq_by_node(struct device_node *node)
mutex_lock(&devfreq_list_lock); mutex_lock(&devfreq_list_lock);
list_for_each_entry(devfreq, &devfreq_list, node) { list_for_each_entry(devfreq, &devfreq_list, node) {
if (devfreq->dev.parent if (devfreq->dev.parent
&& devfreq->dev.parent->of_node == node) { && device_match_of_node(devfreq->dev.parent, node)) {
mutex_unlock(&devfreq_list_lock); mutex_unlock(&devfreq_list_lock);
return devfreq; return devfreq;
} }
......
...@@ -214,8 +214,7 @@ static int exynos_nocp_parse_dt(struct platform_device *pdev, ...@@ -214,8 +214,7 @@ static int exynos_nocp_parse_dt(struct platform_device *pdev,
nocp->clk = NULL; nocp->clk = NULL;
/* Maps the memory mapped IO to control nocp register */ /* Maps the memory mapped IO to control nocp register */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base)) if (IS_ERR(base))
return PTR_ERR(base); return PTR_ERR(base);
......
...@@ -21,7 +21,7 @@ struct userspace_data { ...@@ -21,7 +21,7 @@ struct userspace_data {
static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq) static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
{ {
struct userspace_data *data = df->data; struct userspace_data *data = df->governor_data;
if (data->valid) if (data->valid)
*freq = data->user_frequency; *freq = data->user_frequency;
...@@ -40,7 +40,7 @@ static ssize_t set_freq_store(struct device *dev, struct device_attribute *attr, ...@@ -40,7 +40,7 @@ static ssize_t set_freq_store(struct device *dev, struct device_attribute *attr,
int err = 0; int err = 0;
mutex_lock(&devfreq->lock); mutex_lock(&devfreq->lock);
data = devfreq->data; data = devfreq->governor_data;
sscanf(buf, "%lu", &wanted); sscanf(buf, "%lu", &wanted);
data->user_frequency = wanted; data->user_frequency = wanted;
...@@ -60,7 +60,7 @@ static ssize_t set_freq_show(struct device *dev, ...@@ -60,7 +60,7 @@ static ssize_t set_freq_show(struct device *dev,
int err = 0; int err = 0;
mutex_lock(&devfreq->lock); mutex_lock(&devfreq->lock);
data = devfreq->data; data = devfreq->governor_data;
if (data->valid) if (data->valid)
err = sprintf(buf, "%lu\n", data->user_frequency); err = sprintf(buf, "%lu\n", data->user_frequency);
...@@ -91,7 +91,7 @@ static int userspace_init(struct devfreq *devfreq) ...@@ -91,7 +91,7 @@ static int userspace_init(struct devfreq *devfreq)
goto out; goto out;
} }
data->valid = false; data->valid = false;
devfreq->data = data; devfreq->governor_data = data;
err = sysfs_create_group(&devfreq->dev.kobj, &dev_attr_group); err = sysfs_create_group(&devfreq->dev.kobj, &dev_attr_group);
out: out:
...@@ -107,8 +107,8 @@ static void userspace_exit(struct devfreq *devfreq) ...@@ -107,8 +107,8 @@ static void userspace_exit(struct devfreq *devfreq)
if (devfreq->dev.kobj.sd) if (devfreq->dev.kobj.sd)
sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group); sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group);
kfree(devfreq->data); kfree(devfreq->governor_data);
devfreq->data = NULL; devfreq->governor_data = NULL;
} }
static int devfreq_userspace_handler(struct devfreq *devfreq, static int devfreq_userspace_handler(struct devfreq *devfreq,
......
...@@ -152,8 +152,8 @@ struct devfreq_stats { ...@@ -152,8 +152,8 @@ struct devfreq_stats {
* @max_state: count of entry present in the frequency table. * @max_state: count of entry present in the frequency table.
* @previous_freq: previously configured frequency value. * @previous_freq: previously configured frequency value.
* @last_status: devfreq user device info, performance statistics * @last_status: devfreq user device info, performance statistics
* @data: Private data of the governor. The devfreq framework does not * @data: devfreq driver pass to governors, governor should not change it.
* touch this. * @governor_data: private data for governors, devfreq core doesn't touch it.
* @user_min_freq_req: PM QoS minimum frequency request from user (via sysfs) * @user_min_freq_req: PM QoS minimum frequency request from user (via sysfs)
* @user_max_freq_req: PM QoS maximum frequency request from user (via sysfs) * @user_max_freq_req: PM QoS maximum frequency request from user (via sysfs)
* @scaling_min_freq: Limit minimum frequency requested by OPP interface * @scaling_min_freq: Limit minimum frequency requested by OPP interface
...@@ -193,7 +193,8 @@ struct devfreq { ...@@ -193,7 +193,8 @@ struct devfreq {
unsigned long previous_freq; unsigned long previous_freq;
struct devfreq_dev_status last_status; struct devfreq_dev_status last_status;
void *data; /* private data for governors */ void *data;
void *governor_data;
struct dev_pm_qos_request user_min_freq_req; struct dev_pm_qos_request user_min_freq_req;
struct dev_pm_qos_request user_max_freq_req; struct dev_pm_qos_request user_max_freq_req;
......
...@@ -131,9 +131,10 @@ UTIL_OBJS = utils/helpers/amd.o utils/helpers/msr.o \ ...@@ -131,9 +131,10 @@ UTIL_OBJS = utils/helpers/amd.o utils/helpers/msr.o \
utils/idle_monitor/hsw_ext_idle.o \ utils/idle_monitor/hsw_ext_idle.o \
utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.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/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.o utils/cpufreq-info.o utils/cpufreq-set.o \
utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.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) UTIL_SRC := $(UTIL_OBJS:.o=.c)
...@@ -143,9 +144,12 @@ UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \ ...@@ -143,9 +144,12 @@ UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \
utils/helpers/bitmask.h \ utils/helpers/bitmask.h \
utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def
LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h lib/acpi_cppc.h LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h lib/acpi_cppc.h \
LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c lib/acpi_cppc.c lib/powercap.h
LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o lib/acpi_cppc.o LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c lib/acpi_cppc.c \
lib/powercap.c
LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o lib/acpi_cppc.o \
lib/powercap.o
LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS)) LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS))
override CFLAGS += -pipe override CFLAGS += -pipe
...@@ -276,6 +280,7 @@ install-lib: libcpupower ...@@ -276,6 +280,7 @@ install-lib: libcpupower
$(INSTALL) -d $(DESTDIR)${includedir} $(INSTALL) -d $(DESTDIR)${includedir}
$(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h
$(INSTALL_DATA) lib/cpuidle.h $(DESTDIR)${includedir}/cpuidle.h $(INSTALL_DATA) lib/cpuidle.h $(DESTDIR)${includedir}/cpuidle.h
$(INSTALL_DATA) lib/powercap.h $(DESTDIR)${includedir}/powercap.h
install-tools: $(OUTPUT)cpupower install-tools: $(OUTPUT)cpupower
$(INSTALL) -d $(DESTDIR)${bindir} $(INSTALL) -d $(DESTDIR)${bindir}
...@@ -292,6 +297,7 @@ install-man: ...@@ -292,6 +297,7 @@ install-man:
$(INSTALL_DATA) -D man/cpupower-set.1 $(DESTDIR)${mandir}/man1/cpupower-set.1 $(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-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-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: create-gmo install-gmo: create-gmo
$(INSTALL) -d $(DESTDIR)${localedir} $(INSTALL) -d $(DESTDIR)${localedir}
...@@ -321,6 +327,7 @@ uninstall: ...@@ -321,6 +327,7 @@ uninstall:
- rm -f $(DESTDIR)${mandir}/man1/cpupower-set.1 - rm -f $(DESTDIR)${mandir}/man1/cpupower-set.1
- rm -f $(DESTDIR)${mandir}/man1/cpupower-info.1 - rm -f $(DESTDIR)${mandir}/man1/cpupower-info.1
- rm -f $(DESTDIR)${mandir}/man1/cpupower-monitor.1 - rm -f $(DESTDIR)${mandir}/man1/cpupower-monitor.1
- rm -f $(DESTDIR)${mandir}/man1/cpupower-powercap-info.1
- for HLANG in $(LANGUAGES); do \ - for HLANG in $(LANGUAGES); do \
rm -f $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \ rm -f $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \
done; done;
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* (C) 2016 SUSE Software Solutions GmbH
* Thomas Renninger <trenn@suse.de>
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <dirent.h>
#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 hierarchy 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(void)
{
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;
}
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* (C) 2016 SUSE Software Solutions GmbH
* Thomas Renninger <trenn@suse.de>
*/
#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 <stdint.h>
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(void);
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__ */
.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)
This diff is collapsed.
...@@ -8,6 +8,8 @@ extern int cmd_freq_set(int argc, const char **argv); ...@@ -8,6 +8,8 @@ extern int cmd_freq_set(int argc, const char **argv);
extern int cmd_freq_info(int argc, const char **argv); extern int cmd_freq_info(int argc, const char **argv);
extern int cmd_idle_set(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_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); extern int cmd_monitor(int argc, const char **argv);
#endif #endif
...@@ -572,9 +572,9 @@ int cmd_freq_info(int argc, char **argv) ...@@ -572,9 +572,9 @@ int cmd_freq_info(int argc, char **argv)
ret = 0; ret = 0;
/* Default is: show output of CPU 0 only */ /* Default is: show output of base_cpu only */
if (bitmask_isallclear(cpus_chosen)) if (bitmask_isallclear(cpus_chosen))
bitmask_setbit(cpus_chosen, 0); bitmask_setbit(cpus_chosen, base_cpu);
switch (output_param) { switch (output_param) {
case -1: case -1:
......
...@@ -176,9 +176,9 @@ int cmd_idle_info(int argc, char **argv) ...@@ -176,9 +176,9 @@ int cmd_idle_info(int argc, char **argv)
cpuidle_exit(EXIT_FAILURE); cpuidle_exit(EXIT_FAILURE);
} }
/* Default is: show output of CPU 0 only */ /* Default is: show output of base_cpu only */
if (bitmask_isallclear(cpus_chosen)) if (bitmask_isallclear(cpus_chosen))
bitmask_setbit(cpus_chosen, 0); bitmask_setbit(cpus_chosen, base_cpu);
if (output_param == 0) if (output_param == 0)
cpuidle_general_output(); cpuidle_general_output();
......
...@@ -67,9 +67,9 @@ int cmd_info(int argc, char **argv) ...@@ -67,9 +67,9 @@ int cmd_info(int argc, char **argv)
if (!params.params) if (!params.params)
params.params = 0x7; params.params = 0x7;
/* Default is: show output of CPU 0 only */ /* Default is: show output of base_cpu only */
if (bitmask_isallclear(cpus_chosen)) if (bitmask_isallclear(cpus_chosen))
bitmask_setbit(cpus_chosen, 0); bitmask_setbit(cpus_chosen, base_cpu);
/* Add more per cpu options here */ /* Add more per cpu options here */
if (!params.perf_bias) if (!params.perf_bias)
......
...@@ -54,6 +54,7 @@ static struct cmd_struct commands[] = { ...@@ -54,6 +54,7 @@ static struct cmd_struct commands[] = {
{ "frequency-set", cmd_freq_set, 1 }, { "frequency-set", cmd_freq_set, 1 },
{ "idle-info", cmd_idle_info, 0 }, { "idle-info", cmd_idle_info, 0 },
{ "idle-set", cmd_idle_set, 1 }, { "idle-set", cmd_idle_set, 1 },
{ "powercap-info", cmd_cap_info, 0 },
{ "set", cmd_set, 1 }, { "set", cmd_set, 1 },
{ "info", cmd_info, 0 }, { "info", cmd_info, 0 },
{ "monitor", cmd_monitor, 0 }, { "monitor", cmd_monitor, 0 },
......
...@@ -459,9 +459,10 @@ int cmd_monitor(int argc, char **argv) ...@@ -459,9 +459,10 @@ int cmd_monitor(int argc, char **argv)
print_results(1, cpu); print_results(1, cpu);
} }
for (num = 0; num < avail_monitors; num++) for (num = 0; num < avail_monitors; num++) {
monitors[num]->unregister(); if (monitors[num]->unregister)
monitors[num]->unregister();
}
cpu_topology_release(cpu_top); cpu_topology_release(cpu_top);
return 0; return 0;
} }
...@@ -4,5 +4,6 @@ DEF(intel_nhm) ...@@ -4,5 +4,6 @@ DEF(intel_nhm)
DEF(intel_snb) DEF(intel_snb)
DEF(intel_hsw_ext) DEF(intel_hsw_ext)
DEF(mperf) DEF(mperf)
DEF(rapl)
#endif #endif
DEF(cpuidle_sysfs) DEF(cpuidle_sysfs)
// SPDX-License-Identifier: GPL-2.0-only
/*
* (C) 2016 SUSE Software Solutions GmbH
* Thomas Renninger <trenn@suse.de>
*/
#if defined(__i386__) || defined(__x86_64__)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <string.h>
#include <pci/pci.h>
#include "idle_monitor/cpupower-monitor.h"
#include "helpers/helpers.h"
#include "powercap.h"
#define MAX_RAPL_ZONES 10
int rapl_zone_count;
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)
{
uint64_t val;
int uj;
if (rapl_zone_count >= MAX_RAPL_ZONES)
return -1;
if (!zone->has_energy_uj)
return 0;
printf("%s\n", zone->sys_name);
uj = powercap_get_energy_uj(zone, &val);
printf("%d\n", uj);
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,
.flags.needs_root = 0,
.overflow_s = 60 * 60 * 24 * 100, /* To be implemented */
};
#endif
// SPDX-License-Identifier: GPL-2.0-only
/*
* (C) 2016 SUSE Software Solutions GmbH
* Thomas Renninger <trenn@suse.de>
*/
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <getopt.h>
#include "powercap.h"
#include "helpers/helpers.h"
int powercap_show_all;
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(_("%sPower can be monitored in micro Jules\n"),
pr_prefix);
if (zone->has_energy_uj)
printf(_("%sPower can be monitored in micro Watts\n"),
pr_prefix);
printf("\n");
if (ret != 0)
return ret;
return ret;
}
static int powercap_show(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) {
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)
{
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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment