Merge branches 'pm-sleep', 'pm-opp' and 'pm-tools'

Merge updates related to system sleep, operating performance points
(OPP) updates, and PM tooling updates for 6.12-rc1:

 - Remove unused stub for saveable_highmem_page() and remove deprecated
   macros from power management documentation (Andy Shevchenko).

 - Use ysfs_emit() and sysfs_emit_at() in "show" functions in the PM
   sysfs interface (Xueqin Luo).

 - Update the maintainers information for the operating-points-v2-ti-cpu DT
   binding (Dhruva Gole).

 - Drop unnecessary of_match_ptr() from ti-opp-supply (Rob Herring).

 - Update directory handling and installation process in the pm-graph
   Makefile and add .gitignore to ignore sleepgraph.py artifacts to
   pm-graph (Amit Vadhavana, Yo-Jung Lin).

 - Make cpupower display residency value in idle-info (Aboorva
   Devarajan).

 - Add missing powercap_set_enabled() stub function to cpupower (John
   B. Wyatt IV).

 - Add SWIG support to cpupower (John B. Wyatt IV).

* pm-sleep:
  PM: hibernate: Remove unused stub for saveable_highmem_page()
  Documentation: PM: Discourage use of deprecated macros
  PM: sleep: Use sysfs_emit() and sysfs_emit_at() in "show" functions
  PM: hibernate: Use sysfs_emit() and sysfs_emit_at() in "show" functions

* pm-opp:
  dt-bindings: opp: operating-points-v2-ti-cpu: Update maintainers
  opp: ti: Drop unnecessary of_match_ptr()

* pm-tools:
  pm:cpupower: Add error warning when SWIG is not installed
  MAINTAINERS: Add Maintainers for SWIG Python bindings
  pm:cpupower: Include test_raw_pylibcpupower.py
  pm:cpupower: Add SWIG bindings files for libcpupower
  pm:cpupower: Add missing powercap_set_enabled() stub function
  pm-graph: Update directory handling and installation process in Makefile
  pm-graph: Make git ignore sleepgraph.py artifacts
  tools/cpupower: display residency value in idle-info
This commit is contained in:
Rafael J. Wysocki 2024-09-11 19:02:23 +02:00
commit 0a06811d66
19 changed files with 551 additions and 99 deletions

View File

@ -19,7 +19,7 @@ description:
the hardware description for the scheme mentioned above.
maintainers:
- Nishanth Menon <nm@ti.com>
- Dhruva Gole <d-gole@ti.com>
allOf:
- $ref: opp-v2-base.yaml#

View File

@ -979,18 +979,17 @@ subsections can be defined as a separate function, it often is convenient to
point two or more members of struct dev_pm_ops to the same routine. There are
a few convenience macros that can be used for this purpose.
The SIMPLE_DEV_PM_OPS macro declares a struct dev_pm_ops object with one
The DEFINE_SIMPLE_DEV_PM_OPS() declares a struct dev_pm_ops object with one
suspend routine pointed to by the .suspend(), .freeze(), and .poweroff()
members and one resume routine pointed to by the .resume(), .thaw(), and
.restore() members. The other function pointers in this struct dev_pm_ops are
unset.
The UNIVERSAL_DEV_PM_OPS macro is similar to SIMPLE_DEV_PM_OPS, but it
additionally sets the .runtime_resume() pointer to the same value as
.resume() (and .thaw(), and .restore()) and the .runtime_suspend() pointer to
the same value as .suspend() (and .freeze() and .poweroff()).
The DEFINE_RUNTIME_DEV_PM_OPS() is similar to DEFINE_SIMPLE_DEV_PM_OPS(), but it
additionally sets the .runtime_resume() pointer to pm_runtime_force_resume()
and the .runtime_suspend() pointer to pm_runtime_force_suspend().
The SET_SYSTEM_SLEEP_PM_OPS can be used inside of a declaration of struct
The SYSTEM_SLEEP_PM_OPS() can be used inside of a declaration of struct
dev_pm_ops to indicate that one suspend routine is to be pointed to by the
.suspend(), .freeze(), and .poweroff() members and one resume routine is to
be pointed to by the .resume(), .thaw(), and .restore() members.

View File

@ -811,8 +811,8 @@ subsystem-level dev_pm_ops structure.
Device drivers that wish to use the same function as a system suspend, freeze,
poweroff and runtime suspend callback, and similarly for system resume, thaw,
restore, and runtime resume, can achieve this with the help of the
UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h (possibly setting its
restore, and runtime resume, can achieve similar behaviour with the help of the
DEFINE_RUNTIME_DEV_PM_OPS() defined in include/linux/pm_runtime.h (possibly setting its
last argument to NULL).
8. "No-Callback" Devices

View File

@ -5824,6 +5824,9 @@ CPU POWER MONITORING SUBSYSTEM
M: Thomas Renninger <trenn@suse.com>
M: Shuah Khan <shuah@kernel.org>
M: Shuah Khan <skhan@linuxfoundation.org>
M: John B. Wyatt IV <jwyatt@redhat.com>
M: John B. Wyatt IV <sageofredondo@gmail.com>
M: John Kacur <jkacur@redhat.com>
L: linux-pm@vger.kernel.org
S: Maintained
F: tools/power/cpupower/

View File

@ -405,7 +405,7 @@ static struct platform_driver ti_opp_supply_driver = {
.probe = ti_opp_supply_probe,
.driver = {
.name = "ti_opp_supply",
.of_match_table = of_match_ptr(ti_opp_supply_of_match),
.of_match_table = ti_opp_supply_of_match,
},
};
module_platform_driver(ti_opp_supply_driver);

View File

@ -1123,11 +1123,11 @@ static const char * const hibernation_modes[] = {
static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
ssize_t count = 0;
int i;
char *start = buf;
if (!hibernation_available())
return sprintf(buf, "[disabled]\n");
return sysfs_emit(buf, "[disabled]\n");
for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
if (!hibernation_modes[i])
@ -1147,12 +1147,16 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
continue;
}
if (i == hibernation_mode)
buf += sprintf(buf, "[%s] ", hibernation_modes[i]);
count += sysfs_emit_at(buf, count, "[%s] ", hibernation_modes[i]);
else
buf += sprintf(buf, "%s ", hibernation_modes[i]);
count += sysfs_emit_at(buf, count, "%s ", hibernation_modes[i]);
}
buf += sprintf(buf, "\n");
return buf-start;
/* Convert the last space to a newline if needed. */
if (count > 0)
buf[count - 1] = '\n';
return count;
}
static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
@ -1210,7 +1214,7 @@ power_attr(disk);
static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "%d:%d\n", MAJOR(swsusp_resume_device),
return sysfs_emit(buf, "%d:%d\n", MAJOR(swsusp_resume_device),
MINOR(swsusp_resume_device));
}
@ -1270,7 +1274,7 @@ power_attr(resume);
static ssize_t resume_offset_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%llu\n", (unsigned long long)swsusp_resume_block);
return sysfs_emit(buf, "%llu\n", (unsigned long long)swsusp_resume_block);
}
static ssize_t resume_offset_store(struct kobject *kobj,
@ -1293,7 +1297,7 @@ power_attr(resume_offset);
static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "%lu\n", image_size);
return sysfs_emit(buf, "%lu\n", image_size);
}
static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr,
@ -1314,7 +1318,7 @@ power_attr(image_size);
static ssize_t reserved_size_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%lu\n", reserved_size);
return sysfs_emit(buf, "%lu\n", reserved_size);
}
static ssize_t reserved_size_store(struct kobject *kobj,

View File

@ -115,7 +115,7 @@ int pm_async_enabled = 1;
static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "%d\n", pm_async_enabled);
return sysfs_emit(buf, "%d\n", pm_async_enabled);
}
static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr,
@ -139,7 +139,7 @@ power_attr(pm_async);
static ssize_t mem_sleep_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
char *s = buf;
ssize_t count = 0;
suspend_state_t i;
for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) {
@ -149,17 +149,17 @@ static ssize_t mem_sleep_show(struct kobject *kobj, struct kobj_attribute *attr,
const char *label = mem_sleep_states[i];
if (mem_sleep_current == i)
s += sprintf(s, "[%s] ", label);
count += sysfs_emit_at(buf, count, "[%s] ", label);
else
s += sprintf(s, "%s ", label);
count += sysfs_emit_at(buf, count, "%s ", label);
}
}
/* Convert the last space to a newline if needed. */
if (s != buf)
*(s-1) = '\n';
if (count > 0)
buf[count - 1] = '\n';
return (s - buf);
return count;
}
static suspend_state_t decode_suspend_state(const char *buf, size_t n)
@ -220,7 +220,7 @@ bool sync_on_suspend_enabled = !IS_ENABLED(CONFIG_SUSPEND_SKIP_SYNC);
static ssize_t sync_on_suspend_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", sync_on_suspend_enabled);
return sysfs_emit(buf, "%d\n", sync_on_suspend_enabled);
}
static ssize_t sync_on_suspend_store(struct kobject *kobj,
@ -257,22 +257,22 @@ static const char * const pm_tests[__TEST_AFTER_LAST] = {
static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
char *s = buf;
ssize_t count = 0;
int level;
for (level = TEST_FIRST; level <= TEST_MAX; level++)
if (pm_tests[level]) {
if (level == pm_test_level)
s += sprintf(s, "[%s] ", pm_tests[level]);
count += sysfs_emit_at(buf, count, "[%s] ", pm_tests[level]);
else
s += sprintf(s, "%s ", pm_tests[level]);
count += sysfs_emit_at(buf, count, "%s ", pm_tests[level]);
}
if (s != buf)
/* convert the last space to a newline */
*(s-1) = '\n';
/* Convert the last space to a newline if needed. */
if (count > 0)
buf[count - 1] = '\n';
return (s - buf);
return count;
}
static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
@ -390,7 +390,7 @@ static const char * const suspend_step_names[] = {
static ssize_t _name##_show(struct kobject *kobj, \
struct kobj_attribute *attr, char *buf) \
{ \
return sprintf(buf, format_str, suspend_stats._name); \
return sysfs_emit(buf, format_str, suspend_stats._name);\
} \
static struct kobj_attribute _name = __ATTR_RO(_name)
@ -404,7 +404,7 @@ suspend_attr(max_hw_sleep, "%llu\n");
static ssize_t _name##_show(struct kobject *kobj, \
struct kobj_attribute *attr, char *buf) \
{ \
return sprintf(buf, "%u\n", \
return sysfs_emit(buf, "%u\n", \
suspend_stats.step_failures[step-1]); \
} \
static struct kobj_attribute _name = __ATTR_RO(_name)
@ -428,7 +428,7 @@ static ssize_t last_failed_dev_show(struct kobject *kobj,
index %= REC_FAILED_NUM;
last_failed_dev = suspend_stats.failed_devs[index];
return sprintf(buf, "%s\n", last_failed_dev);
return sysfs_emit(buf, "%s\n", last_failed_dev);
}
static struct kobj_attribute last_failed_dev = __ATTR_RO(last_failed_dev);
@ -442,7 +442,7 @@ static ssize_t last_failed_errno_show(struct kobject *kobj,
index %= REC_FAILED_NUM;
last_failed_errno = suspend_stats.errno[index];
return sprintf(buf, "%d\n", last_failed_errno);
return sysfs_emit(buf, "%d\n", last_failed_errno);
}
static struct kobj_attribute last_failed_errno = __ATTR_RO(last_failed_errno);
@ -456,7 +456,7 @@ static ssize_t last_failed_step_show(struct kobject *kobj,
index %= REC_FAILED_NUM;
step = suspend_stats.failed_steps[index];
return sprintf(buf, "%s\n", suspend_step_names[step]);
return sysfs_emit(buf, "%s\n", suspend_step_names[step]);
}
static struct kobj_attribute last_failed_step = __ATTR_RO(last_failed_step);
@ -571,7 +571,7 @@ bool pm_print_times_enabled;
static ssize_t pm_print_times_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", pm_print_times_enabled);
return sysfs_emit(buf, "%d\n", pm_print_times_enabled);
}
static ssize_t pm_print_times_store(struct kobject *kobj,
@ -604,7 +604,7 @@ static ssize_t pm_wakeup_irq_show(struct kobject *kobj,
if (!pm_wakeup_irq())
return -ENODATA;
return sprintf(buf, "%u\n", pm_wakeup_irq());
return sysfs_emit(buf, "%u\n", pm_wakeup_irq());
}
power_attr_ro(pm_wakeup_irq);
@ -620,7 +620,7 @@ EXPORT_SYMBOL_GPL(pm_debug_messages_should_print);
static ssize_t pm_debug_messages_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", pm_debug_messages_on);
return sysfs_emit(buf, "%d\n", pm_debug_messages_on);
}
static ssize_t pm_debug_messages_store(struct kobject *kobj,
@ -668,21 +668,23 @@ struct kobject *power_kobj;
static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
char *s = buf;
ssize_t count = 0;
#ifdef CONFIG_SUSPEND
suspend_state_t i;
for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
if (pm_states[i])
s += sprintf(s,"%s ", pm_states[i]);
count += sysfs_emit_at(buf, count, "%s ", pm_states[i]);
#endif
if (hibernation_available())
s += sprintf(s, "disk ");
if (s != buf)
/* convert the last space to a newline */
*(s-1) = '\n';
return (s - buf);
count += sysfs_emit_at(buf, count, "disk ");
/* Convert the last space to a newline if needed. */
if (count > 0)
buf[count - 1] = '\n';
return count;
}
static suspend_state_t decode_state(const char *buf, size_t n)
@ -782,7 +784,7 @@ static ssize_t wakeup_count_show(struct kobject *kobj,
unsigned int val;
return pm_get_wakeup_count(&val, true) ?
sprintf(buf, "%u\n", val) : -EINTR;
sysfs_emit(buf, "%u\n", val) : -EINTR;
}
static ssize_t wakeup_count_store(struct kobject *kobj,
@ -824,17 +826,17 @@ static ssize_t autosleep_show(struct kobject *kobj,
suspend_state_t state = pm_autosleep_state();
if (state == PM_SUSPEND_ON)
return sprintf(buf, "off\n");
return sysfs_emit(buf, "off\n");
#ifdef CONFIG_SUSPEND
if (state < PM_SUSPEND_MAX)
return sprintf(buf, "%s\n", pm_states[state] ?
return sysfs_emit(buf, "%s\n", pm_states[state] ?
pm_states[state] : "error");
#endif
#ifdef CONFIG_HIBERNATION
return sprintf(buf, "disk\n");
return sysfs_emit(buf, "disk\n");
#else
return sprintf(buf, "error");
return sysfs_emit(buf, "error\n");
#endif
}
@ -903,7 +905,7 @@ int pm_trace_enabled;
static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "%d\n", pm_trace_enabled);
return sysfs_emit(buf, "%d\n", pm_trace_enabled);
}
static ssize_t
@ -940,7 +942,7 @@ power_attr_ro(pm_trace_dev_match);
static ssize_t pm_freeze_timeout_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%u\n", freeze_timeout_msecs);
return sysfs_emit(buf, "%u\n", freeze_timeout_msecs);
}
static ssize_t pm_freeze_timeout_store(struct kobject *kobj,

View File

@ -1365,11 +1365,6 @@ static unsigned int count_highmem_pages(void)
}
return n;
}
#else
static inline void *saveable_highmem_page(struct zone *z, unsigned long p)
{
return NULL;
}
#endif /* CONFIG_HIGHMEM */
/**

View File

@ -0,0 +1,8 @@
__pycache__/
raw_pylibcpupower_wrap.c
*.o
*.so
*.py
!test_raw_pylibcpupower.py
# git keeps ignoring this file, use git add -f raw_libcpupower.i
!raw_pylibcpupower.i

View File

@ -0,0 +1,33 @@
# SPDX-License-Identifier: GPL-2.0-only
# Makefile for libcpupower's Python bindings
#
# This Makefile expects you have already run the makefile for cpupower to build
# the .o files in the lib directory for the bindings to be created.
CC := gcc
HAVE_SWIG := $(shell if which swig >/dev/null 2>&1; then echo 1; else echo 0; fi)
HAVE_PYCONFIG := $(shell if which python-config >/dev/null 2>&1; then echo 1; else echo 0; fi)
LIB_DIR := ../../lib
PY_INCLUDE = $(firstword $(shell python-config --includes))
OBJECTS_LIB = $(wildcard $(LIB_DIR)/*.o)
all: _raw_pylibcpupower.so
_raw_pylibcpupower.so: raw_pylibcpupower_wrap.o
$(CC) -shared $(OBJECTS_LIB) raw_pylibcpupower_wrap.o -o _raw_pylibcpupower.so
raw_pylibcpupower_wrap.o: raw_pylibcpupower_wrap.c
$(CC) -fPIC -c raw_pylibcpupower_wrap.c $(PY_INCLUDE)
raw_pylibcpupower_wrap.c: raw_pylibcpupower.i
ifeq ($(HAVE_SWIG),0)
$(error "swig was not found. Make sure you have it installed and in the PATH to generate the bindings.")
else ifeq ($(HAVE_PYCONFIG),0)
$(error "python-config was not found. Make sure you have it installed and in the PATH to generate the bindings.")
endif
swig -python raw_pylibcpupower.i
# Will only clean the bindings folder; will not clean the actual cpupower folder
clean:
rm -f raw_pylibcpupower.py raw_pylibcpupower_wrap.c raw_pylibcpupower_wrap.o _raw_pylibcpupower.so

View File

@ -0,0 +1,59 @@
This folder contains the necessary files to build the Python bindings for
libcpupower (aside from the libcpupower object files).
requirements
------------
* You need the object files in the libcpupower directory compiled by
cpupower's makefile.
* The SWIG program must be installed.
* The Python's development libraries installed.
Please check that your version of SWIG is compatible with the version of Python
installed on your machine by checking the SWIG changelog on their website.
https://swig.org/
Note that while SWIG itself is GPL v3+ licensed; the resulting output,
the bindings code: is permissively licensed + the license of libcpupower's .o
files. For these bindings that means GPL v2.
Please see https://swig.org/legal.html and the discussion [1] for more details.
[1]
https://lore.kernel.org/linux-pm/Zqv9BOjxLAgyNP5B@hatbackup/
build
-----
Install SWIG and the Python development files provided by your distribution.
Build the object files for libcpupower by running make in the cpupower
directory.
Return to the directory this README is in to run:
$ make
testing
-------
Please verify the _raw_pylibcpupower.so and raw_pylibcpupower.py files have
been created.
To run the test script:
$ python test_raw_pylibcpupower.py
credits
-------
Original Bindings Author:
John B. Wyatt IV
jwyatt@redhat.com
sageofredondo@gmail.com
Copyright (C) 2024 Red Hat

View File

@ -0,0 +1,247 @@
/* SPDX-License-Identifier: GPL-2.0-only */
%module raw_pylibcpupower
%{
#include "../../lib/cpupower_intern.h"
#include "../../lib/acpi_cppc.h"
#include "../../lib/cpufreq.h"
#include "../../lib/cpuidle.h"
#include "../../lib/cpupower.h"
#include "../../lib/powercap.h"
%}
/*
* cpupower_intern.h
*/
#define PATH_TO_CPU "/sys/devices/system/cpu/"
#define MAX_LINE_LEN 4096
#define SYSFS_PATH_MAX 255
int is_valid_path(const char *path);
unsigned int cpupower_read_sysfs(const char *path, char *buf, size_t buflen);
unsigned int cpupower_write_sysfs(const char *path, char *buf, size_t buflen);
/*
* acpi_cppc.h
*/
enum acpi_cppc_value {
HIGHEST_PERF,
LOWEST_PERF,
NOMINAL_PERF,
LOWEST_NONLINEAR_PERF,
LOWEST_FREQ,
NOMINAL_FREQ,
REFERENCE_PERF,
WRAPAROUND_TIME,
MAX_CPPC_VALUE_FILES
};
unsigned long acpi_cppc_get_data(unsigned int cpu,
enum acpi_cppc_value which);
/*
* cpufreq.h
*/
struct cpufreq_policy {
unsigned long min;
unsigned long max;
char *governor;
};
struct cpufreq_available_governors {
char *governor;
struct cpufreq_available_governors *next;
struct cpufreq_available_governors *first;
};
struct cpufreq_available_frequencies {
unsigned long frequency;
struct cpufreq_available_frequencies *next;
struct cpufreq_available_frequencies *first;
};
struct cpufreq_affected_cpus {
unsigned int cpu;
struct cpufreq_affected_cpus *next;
struct cpufreq_affected_cpus *first;
};
struct cpufreq_stats {
unsigned long frequency;
unsigned long long time_in_state;
struct cpufreq_stats *next;
struct cpufreq_stats *first;
};
unsigned long cpufreq_get_freq_kernel(unsigned int cpu);
unsigned long cpufreq_get_freq_hardware(unsigned int cpu);
#define cpufreq_get(cpu) cpufreq_get_freq_kernel(cpu);
unsigned long cpufreq_get_transition_latency(unsigned int cpu);
int cpufreq_get_hardware_limits(unsigned int cpu,
unsigned long *min,
unsigned long *max);
char *cpufreq_get_driver(unsigned int cpu);
void cpufreq_put_driver(char *ptr);
struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu);
void cpufreq_put_policy(struct cpufreq_policy *policy);
struct cpufreq_available_governors
*cpufreq_get_available_governors(unsigned int cpu);
void cpufreq_put_available_governors(
struct cpufreq_available_governors *first);
struct cpufreq_available_frequencies
*cpufreq_get_available_frequencies(unsigned int cpu);
void cpufreq_put_available_frequencies(
struct cpufreq_available_frequencies *first);
struct cpufreq_available_frequencies
*cpufreq_get_boost_frequencies(unsigned int cpu);
void cpufreq_put_boost_frequencies(
struct cpufreq_available_frequencies *first);
struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned
int cpu);
void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first);
struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned
int cpu);
void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first);
struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu,
unsigned long long *total_time);
void cpufreq_put_stats(struct cpufreq_stats *stats);
unsigned long cpufreq_get_transitions(unsigned int cpu);
int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy);
int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq);
int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq);
int cpufreq_modify_policy_governor(unsigned int cpu, char *governor);
int cpufreq_set_frequency(unsigned int cpu,
unsigned long target_frequency);
unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
const char **table,
unsigned int index,
unsigned int size);
/*
* cpuidle.h
*/
int cpuidle_is_state_disabled(unsigned int cpu,
unsigned int idlestate);
int cpuidle_state_disable(unsigned int cpu, unsigned int idlestate,
unsigned int disable);
unsigned long cpuidle_state_latency(unsigned int cpu,
unsigned int idlestate);
unsigned long cpuidle_state_usage(unsigned int cpu,
unsigned int idlestate);
unsigned long long cpuidle_state_time(unsigned int cpu,
unsigned int idlestate);
char *cpuidle_state_name(unsigned int cpu,
unsigned int idlestate);
char *cpuidle_state_desc(unsigned int cpu,
unsigned int idlestate);
unsigned int cpuidle_state_count(unsigned int cpu);
char *cpuidle_get_governor(void);
char *cpuidle_get_driver(void);
/*
* cpupower.h
*/
struct cpupower_topology {
/* Amount of CPU cores, packages and threads per core in the system */
unsigned int cores;
unsigned int pkgs;
unsigned int threads; /* per core */
/* Array gets mallocated with cores entries, holding per core info */
struct cpuid_core_info *core_info;
};
struct cpuid_core_info {
int pkg;
int core;
int cpu;
/* flags */
unsigned int is_online:1;
};
int get_cpu_topology(struct cpupower_topology *cpu_top);
void cpu_topology_release(struct cpupower_topology cpu_top);
int cpupower_is_cpu_online(unsigned int cpu);
/*
* powercap.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);

View File

@ -0,0 +1,42 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-only
import raw_pylibcpupower as p
# Simple function call
"""
Get cstate count
"""
cpu_cstates_count = p.cpuidle_state_count(0)
if cpu_cstates_count > -1:
print(f"CPU 0 has {cpu_cstates_count} c-states")
else:
print(f"cstate count error: return code: {cpu_cstates_count}")
"""
Disable cstate (will fail if the above is 0, ex: a virtual machine)
"""
cstate_disabled = p.cpuidle_state_disable(0, 0, 1)
if cpu_cstates_count == 0:
print(f"CPU 0 has {cpu_cstates_count} c-states")
else:
print(f"cstate count error: return code: {cpu_cstates_count}")
match cstate_disabled:
case 0:
print(f"CPU state disabled")
case -1:
print(f"Idlestate not available")
case _:
print(f"Not documented")
# Pointer example
topo = p.cpupower_topology()
total_cpus = p.get_cpu_topology(topo)
if total_cpus > 0:
print(f"Number of total cpus: {total_cpus} and number of cores: {topo.cores}")
else:
print(f"Error: could not get cpu topology")

View File

@ -116,6 +116,7 @@ enum idlestate_value {
IDLESTATE_USAGE,
IDLESTATE_POWER,
IDLESTATE_LATENCY,
IDLESTATE_RESIDENCY,
IDLESTATE_TIME,
IDLESTATE_DISABLE,
MAX_IDLESTATE_VALUE_FILES
@ -125,6 +126,7 @@ static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
[IDLESTATE_USAGE] = "usage",
[IDLESTATE_POWER] = "power",
[IDLESTATE_LATENCY] = "latency",
[IDLESTATE_RESIDENCY] = "residency",
[IDLESTATE_TIME] = "time",
[IDLESTATE_DISABLE] = "disable",
};
@ -254,6 +256,12 @@ unsigned long cpuidle_state_latency(unsigned int cpu,
return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
}
unsigned long cpuidle_state_residency(unsigned int cpu,
unsigned int idlestate)
{
return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_RESIDENCY);
}
unsigned long cpuidle_state_usage(unsigned int cpu,
unsigned int idlestate)
{

View File

@ -8,6 +8,8 @@ int cpuidle_state_disable(unsigned int cpu, unsigned int idlestate,
unsigned int disable);
unsigned long cpuidle_state_latency(unsigned int cpu,
unsigned int idlestate);
unsigned long cpuidle_state_residency(unsigned int cpu,
unsigned int idlestate);
unsigned long cpuidle_state_usage(unsigned int cpu,
unsigned int idlestate);
unsigned long long cpuidle_state_time(unsigned int cpu,

View File

@ -77,6 +77,14 @@ int powercap_get_enabled(int *mode)
return sysfs_get_enabled(path, mode);
}
/*
* TODO: implement function. Returns dummy 0 for now.
*/
int powercap_set_enabled(int mode)
{
return 0;
}
/*
* Hardcoded, because rapl is the only powercap implementation
- * this needs to get more generic if more powercap implementations

View File

@ -64,6 +64,8 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
printf(_("Latency: %lu\n"),
cpuidle_state_latency(cpu, idlestate));
printf(_("Residency: %lu\n"),
cpuidle_state_residency(cpu, idlestate));
printf(_("Usage: %lu\n"),
cpuidle_state_usage(cpu, idlestate));
printf(_("Duration: %llu\n"),
@ -115,6 +117,8 @@ static void proc_cpuidle_cpu_output(unsigned int cpu)
printf(_("promotion[--] demotion[--] "));
printf(_("latency[%03lu] "),
cpuidle_state_latency(cpu, cstate));
printf(_("residency[%05lu] "),
cpuidle_state_residency(cpu, cstate));
printf(_("usage[%08lu] "),
cpuidle_state_usage(cpu, cstate));
printf(_("duration[%020Lu] \n"),

3
tools/power/pm-graph/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# sleepgraph.py artifacts
suspend-[0-9]*-[0-9]*
suspend-[0-9]*-[0-9]*-x[0-9]*

View File

@ -1,51 +1,86 @@
# SPDX-License-Identifier: GPL-2.0
PREFIX ?= /usr
#
# Copyright (c) 2013, Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
# version 2, as published by the Free Software Foundation.
#
# This program is distributed in the hope it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# Authors:
# Todd Brandt <todd.e.brandt@linux.intel.com>
# Prefix to the directories we're installing to
DESTDIR ?=
# Directory definitions. These are default and most probably
# do not need to be changed. Please note that DESTDIR is
# added in front of any of them
BINDIR ?= /usr/bin
MANDIR ?= /usr/share/man
LIBDIR ?= /usr/lib
# Toolchain: what tools do we use, and what options do they need:
INSTALL = /usr/bin/install
INSTALL_DATA = ${INSTALL} -m 644
all:
@echo "Nothing to build"
install : uninstall
install -d $(DESTDIR)$(PREFIX)/lib/pm-graph
install sleepgraph.py $(DESTDIR)$(PREFIX)/lib/pm-graph
install bootgraph.py $(DESTDIR)$(PREFIX)/lib/pm-graph
install -d $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/cgskip.txt $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/freeze-callgraph.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/freeze.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/freeze-dev.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/standby-callgraph.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/standby.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/standby-dev.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/suspend-callgraph.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/suspend.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/suspend-dev.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/suspend-x2-proc.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
$(INSTALL) -d $(DESTDIR)$(LIBDIR)/pm-graph
$(INSTALL) sleepgraph.py $(DESTDIR)$(LIBDIR)/pm-graph
$(INSTALL) bootgraph.py $(DESTDIR)$(LIBDIR)/pm-graph
$(INSTALL) -d $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/cgskip.txt $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/freeze-callgraph.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/freeze.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/freeze-dev.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/standby-callgraph.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/standby.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/standby-dev.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/suspend-callgraph.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/suspend.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/suspend-dev.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/suspend-x2-proc.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
install -d $(DESTDIR)$(PREFIX)/bin
ln -s ../lib/pm-graph/bootgraph.py $(DESTDIR)$(PREFIX)/bin/bootgraph
ln -s ../lib/pm-graph/sleepgraph.py $(DESTDIR)$(PREFIX)/bin/sleepgraph
$(INSTALL) -d $(DESTDIR)$(BINDIR)
ln -s ../lib/pm-graph/bootgraph.py $(DESTDIR)$(BINDIR)/bootgraph
ln -s ../lib/pm-graph/sleepgraph.py $(DESTDIR)$(BINDIR)/sleepgraph
install -d $(DESTDIR)$(PREFIX)/share/man/man8
install bootgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8
install sleepgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8
$(INSTALL) -d $(DESTDIR)$(MANDIR)/man8
$(INSTALL) bootgraph.8 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) sleepgraph.8 $(DESTDIR)$(MANDIR)/man8
uninstall :
rm -f $(DESTDIR)$(PREFIX)/share/man/man8/bootgraph.8
rm -f $(DESTDIR)$(PREFIX)/share/man/man8/sleepgraph.8
rm -f $(DESTDIR)$(MANDIR)/man8/bootgraph.8
rm -f $(DESTDIR)$(MANDIR)/man8/sleepgraph.8
rm -f $(DESTDIR)$(PREFIX)/bin/bootgraph
rm -f $(DESTDIR)$(PREFIX)/bin/sleepgraph
rm -f $(DESTDIR)$(BINDIR)/bootgraph
rm -f $(DESTDIR)$(BINDIR)/sleepgraph
rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/config/*
if [ -d $(DESTDIR)$(PREFIX)/lib/pm-graph/config ] ; then \
rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph/config; \
rm -f $(DESTDIR)$(LIBDIR)/pm-graph/config/*
if [ -d $(DESTDIR)$(LIBDIR)/pm-graph/config ] ; then \
rmdir $(DESTDIR)$(LIBDIR)/pm-graph/config; \
fi;
rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/__pycache__/*
if [ -d $(DESTDIR)$(PREFIX)/lib/pm-graph/__pycache__ ] ; then \
rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph/__pycache__; \
rm -f $(DESTDIR)$(LIBDIR)/pm-graph/__pycache__/*
if [ -d $(DESTDIR)$(LIBDIR)/pm-graph/__pycache__ ] ; then \
rmdir $(DESTDIR)$(LIBDIR)/pm-graph/__pycache__; \
fi;
rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/*
if [ -d $(DESTDIR)$(PREFIX)/lib/pm-graph ] ; then \
rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph; \
rm -f $(DESTDIR)$(LIBDIR)/pm-graph/*
if [ -d $(DESTDIR)$(LIBDIR)/pm-graph ] ; then \
rmdir $(DESTDIR)$(LIBDIR)/pm-graph; \
fi;
help:
@echo 'Building targets:'
@echo ' all - Nothing to build'
@echo ' install - Install the program and create necessary directories'
@echo ' uninstall - Remove installed files and directories'
.PHONY: all install uninstall help