Small Linux daemon for systemd. It watches charger state and switches both GNOME power profiles and CPU frequency policy.
Created in the ArmaniOS era, adapted for GNOME and modern distributions.
On battery:
powerprofilesctl set power-saver- wait
GNOME_SETTLE_SECONDSso GNOME/power-profiles-daemon applies the mode first cpupower -c all frequency-set -g powersavecpupower -c all frequency-set -d 300MHz -u 700MHz- while on battery, adapt the upper cap from 700 MHz upward only after sustained load
On AC:
- restore CPU min/max limits from sysfs
cpupower -c all frequency-set -g performancepowerprofilesctl set performance
- Linux with
/sys/class/power_supply cpupowerpowerprofilesctlfrompower-profiles-daemon- root service permissions, because
cpupowerchanges CPU policy
Do not run multiple power managers at the same time. Disable tools such as TLP, auto-cpufreq, tuned, or distro-specific power daemons if they overwrite powerprofilesctl, governor, or cpufreq limits.
Install runtime dependencies:
sudo dnf install python3 kernel-tools power-profiles-daemon
sudo systemctl enable --now power-profiles-daemon.serviceInstall performy:
sudo ./install.sh
sudo systemctl status performy.serviceInstall runtime dependencies:
sudo pacman -S python cpupower power-profiles-daemon
sudo systemctl enable --now power-profiles-daemon.serviceInstall performy:
sudo ./install.sh
sudo systemctl status performy.serviceInstall runtime dependencies:
sudo apt update
sudo apt install python3 power-profiles-daemon linux-tools-common linux-tools-generic
sudo systemctl enable --now power-profiles-daemon.serviceIf cpupower is still missing, install the cpupower package available for your Ubuntu release:
sudo apt install linux-cpupowerInstall performy:
sudo ./install.sh
sudo systemctl status performy.serviceInstall runtime dependencies:
sudo apt update
sudo apt install python3 power-profiles-daemon linux-cpupower
sudo systemctl enable --now power-profiles-daemon.serviceInstall performy:
sudo ./install.sh
sudo systemctl status performy.serviceImport the provided module from /etc/nixos/configuration.nix:
{
imports = [
/home/csoftware/performy/nixos/performy.nix
];
}Apply it:
sudo nixos-rebuild switch
sudo systemctl restart performy.service
journalctl -u performy.service -fThe NixOS module installs performy-daemon system-wide, enables power-profiles-daemon, creates /etc/performy.conf from performy.conf.example, and starts the root systemd service.
Edit /etc/performy.conf if your CPU does not support the default 650-700 MHz range.
Useful commands:
sudo performy-daemon --once --dry-run
sudo systemctl status performy.service
journalctl -u performy.service -fCopy or edit performy.conf.example. The defaults implement:
- battery: GNOME
power-saver, governorpowersave, idle floor 300 MHz, normal band 650-700 MHz, adaptive boost to average CPU frequency under sustained per-core load - AC: hardware min/max limits, governor
performance, GNOMEperformance
Set ENABLE_GNOME=false or ENABLE_CPUPOWER=false if you need only one side of the switching.
Keep GNOME_SETTLE_SECONDS above zero if your hardware does not lower CPU frequency until GNOME switches to power-saver.
If cpupower -d/-u fails with Trying to set an invalid policy?, keep:
FREQUENCY_LIMIT_BACKEND=sysfs
The daemon will still use cpupower for governor changes, but will write min/max frequency limits directly to policy*/scaling_min_freq and policy*/scaling_max_freq.
Adaptive mode is enabled by default with BATTERY_ADAPTIVE=true.
BATTERY_IDLE_MIN_FREQ=300MHzlets the CPU drop lower while idle. If the CPU reports a higher hardware minimum, performy clamps to that value instead of sending an invalid cpupower policy.BATTERY_MIN_FREQ=650MHzandBATTERY_MAX_FREQ=700MHzdefine the normal battery band.BATTERY_BOOST_MAX_FREQ=averagecaps battery boost at the midpoint between hardware min and max frequency.BATTERY_BOOST_STEP_FREQ=averagejumps to that average cap when boost is needed.BATTERY_BOOST_UP_LOAD=60andBATTERY_BOOST_UP_SAMPLES=1react to sustained per-core load; one hot core is enough to boost.BATTERY_BOOST_DOWN_LOAD=35,BATTERY_BOOST_DOWN_SAMPLES=3, andBATTERY_BOOST_DOWN_HOLD_SECONDS=20make it drop back conservatively.
Set BATTERY_ADAPTIVE=false to get the old static 650-700 MHz battery behavior.