Commit 2ed6b4c2 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge tag 'linux-cpupower-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux

Pull cpupower utility updates for 6.2-rc1 from Shuah Khan:

"This cpupower update for Linux 6.2-rc1 consists of:

 - enhancement to choose base_cpu to display default cpupower details
   instead of picking cpu 0 and failing show information when it is
   offline. This change ensure user will see power information on
   the cpu the tool runs on.
 - adds Georgian translation to cpupower documentation.
 - introduces powercap intel-rapl library, powercap-info command, and
   rapl monitor. This adds the ability to show the used power consumption
   in for each rapl domain"

* tag 'linux-cpupower-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux:
  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
parents 76dcd734 8c37df3d
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -131,9 +131,10 @@ 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/cpuidle-set.o utils/powercap-info.o

UTIL_SRC := $(UTIL_OBJS:.o=.c)

@@ -143,9 +144,12 @@ UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \
	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/acpi_cppc.h
LIB_SRC = 	lib/cpufreq.c lib/cpupower.c lib/cpuidle.c lib/acpi_cppc.c
LIB_OBJS = 	lib/cpufreq.o lib/cpupower.o lib/cpuidle.o lib/acpi_cppc.o
LIB_HEADERS = 	lib/cpufreq.h lib/cpupower.h lib/cpuidle.h lib/acpi_cppc.h \
	lib/powercap.h
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))

override CFLAGS +=	-pipe
@@ -276,6 +280,7 @@ install-lib: libcpupower
	$(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: $(OUTPUT)cpupower
	$(INSTALL) -d $(DESTDIR)${bindir}
@@ -292,6 +297,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: create-gmo
	$(INSTALL) -d $(DESTDIR)${localedir}
@@ -321,6 +327,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;
+290 −0
Original line number Diff line number Diff line
// 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;
}
+54 −0
Original line number Diff line number Diff line
/* 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__ */
+25 −0
Original line number Diff line number Diff line
.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)
+983 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading