1
0
Fork 0

tuned-ppd: Detect battery change events

power-profiles-daemon has the ability to detect battery change events
using upower and to apply different tuned settings based upon whether
plugged into power or not.

In PPD this is used specifically to set the energy performance preference
differently in the 'balanced' profile, but there is no reason that this
concept can't actually apply to all profiles.

Add support for detecting battery change events and apply a profile
specified in ppd.conf for battery in the different PPD states.
This commit is contained in:
Mario Limonciello 2024-04-01 23:26:01 -05:00
parent 1fb7c803b6
commit 6ef5b58ea8
4 changed files with 62 additions and 1 deletions

View file

@ -0,0 +1,10 @@
#
# tuned configuration
#
[main]
summary=Balanced profile biased towards power savings changes for battery
include=balanced
[cpu]
energy_performance_preference=balance_power

View file

@ -7,13 +7,19 @@ PPD_PERFORMANCE = "performance"
MAIN_SECTION = "main" MAIN_SECTION = "main"
PROFILES_SECTION = "profiles" PROFILES_SECTION = "profiles"
BATTERY_SECTION = "battery"
DEFAULT_PROFILE_OPTION = "default" DEFAULT_PROFILE_OPTION = "default"
BATTERY_DETECTION_OPTION = "battery_detection"
class PPDConfig: class PPDConfig:
def __init__(self, config_file): def __init__(self, config_file):
self.load_from_file(config_file) self.load_from_file(config_file)
@property
def battery_detection(self):
return self._battery_detection
@property @property
def default_profile(self): def default_profile(self):
return self._default_profile return self._default_profile
@ -26,6 +32,10 @@ class PPDConfig:
def tuned_to_ppd(self): def tuned_to_ppd(self):
return self._tuned_to_ppd return self._tuned_to_ppd
@property
def ppd_to_tuned_battery(self):
return self._ppd_to_tuned_battery
def load_from_file(self, config_file): def load_from_file(self, config_file):
cfg = ConfigParser() cfg = ConfigParser()
@ -59,3 +69,17 @@ class PPDConfig:
self._default_profile = cfg[MAIN_SECTION][DEFAULT_PROFILE_OPTION] self._default_profile = cfg[MAIN_SECTION][DEFAULT_PROFILE_OPTION]
if self._default_profile not in self._ppd_to_tuned: if self._default_profile not in self._ppd_to_tuned:
raise TunedException("Unknown default profile '%s'" % self._default_profile) raise TunedException("Unknown default profile '%s'" % self._default_profile)
if BATTERY_DETECTION_OPTION not in cfg[MAIN_SECTION]:
raise TunedException("Missing battery detection option in the configuration file '%s'" % config_file)
self._ppd_to_tuned_battery = self._ppd_to_tuned
self._battery_detection = cfg.getboolean(MAIN_SECTION, BATTERY_DETECTION_OPTION)
if self._battery_detection:
if BATTERY_SECTION not in cfg:
raise TunedException("Missing battery section in the configuration file '%s'" % config_file)
for k, _v in dict(cfg[PROFILES_SECTION]).items():
if k in cfg[BATTERY_SECTION].keys():
self._tuned_to_ppd = self._tuned_to_ppd | {cfg[BATTERY_SECTION][k]:k}
for k, v in dict(cfg[BATTERY_SECTION]).items():
if k in cfg[PROFILES_SECTION].keys():
self._ppd_to_tuned_battery = self._ppd_to_tuned_battery | {k:v}

View file

@ -13,6 +13,9 @@ DRIVER = "tuned"
NO_TURBO_PATH = "/sys/devices/system/cpu/intel_pstate/no_turbo" NO_TURBO_PATH = "/sys/devices/system/cpu/intel_pstate/no_turbo"
LAP_MODE_PATH = "/sys/bus/platform/devices/thinkpad_acpi/dytc_lapmode" LAP_MODE_PATH = "/sys/bus/platform/devices/thinkpad_acpi/dytc_lapmode"
UPOWER_DBUS_NAME = "org.freedesktop.UPower"
UPOWER_DBUS_PATH = "/org/freedesktop/UPower"
UPOWER_DBUS_INTERFACE = "org.freedesktop.UPower"
class PerformanceDegraded(StrEnum): class PerformanceDegraded(StrEnum):
NONE = "" NONE = ""
@ -101,8 +104,25 @@ class Controller(exports.interfaces.ExportableInterface):
self._performance_degraded = PerformanceDegraded.NONE self._performance_degraded = PerformanceDegraded.NONE
self._cmd = commands() self._cmd = commands()
self._terminate = threading.Event() self._terminate = threading.Event()
self._on_battery = False
self.load_config() self.load_config()
def upower_changed(self, interface, changed, invalidated):
properties = dbus.Interface(self.proxy, dbus.PROPERTIES_IFACE)
self._on_battery = bool(properties.Get(UPOWER_DBUS_INTERFACE, "OnBattery"))
tuned_profile = self._config.ppd_to_tuned_battery[self._base_profile] if self._on_battery else self._config.ppd_to_tuned[self._base_profile]
log.info("Switching to profile '%s' due to battery %s" % (tuned_profile, self._on_battery))
self._tuned_interface.switch_profile(tuned_profile)
def setup_battery_signaling(self):
try:
bus = dbus.SystemBus()
self.proxy = bus.get_object(UPOWER_DBUS_NAME, UPOWER_DBUS_PATH)
self.proxy.connect_to_signal("PropertiesChanged", self.upower_changed)
self.upower_changed(None, None, None)
except dbus.exceptions.DBusException as error:
log.debug(error)
def _check_performance_degraded(self): def _check_performance_degraded(self):
performance_degraded = PerformanceDegraded.NONE performance_degraded = PerformanceDegraded.NONE
if os.path.exists(NO_TURBO_PATH): if os.path.exists(NO_TURBO_PATH):
@ -137,11 +157,13 @@ class Controller(exports.interfaces.ExportableInterface):
self._config = PPDConfig(PPD_CONFIG_FILE) self._config = PPDConfig(PPD_CONFIG_FILE)
self._base_profile = self._config.default_profile self._base_profile = self._config.default_profile
self.switch_profile(self._config.default_profile) self.switch_profile(self._config.default_profile)
if self._config.battery_detection:
self.setup_battery_signaling()
def switch_profile(self, profile): def switch_profile(self, profile):
if self.active_profile() == profile: if self.active_profile() == profile:
return return
tuned_profile = self._config.ppd_to_tuned[profile] tuned_profile = self._config.ppd_to_tuned_battery[profile] if self._on_battery else self._config.ppd_to_tuned[profile]
log.info("Switching to profile '%s'" % tuned_profile) log.info("Switching to profile '%s'" % tuned_profile)
self._tuned_interface.switch_profile(tuned_profile) self._tuned_interface.switch_profile(tuned_profile)
exports.property_changed("ActiveProfile", profile) exports.property_changed("ActiveProfile", profile)

View file

@ -1,9 +1,14 @@
[main] [main]
# The default PPD profile # The default PPD profile
default=balanced default=balanced
battery_detection=true
[profiles] [profiles]
# PPD = TuneD # PPD = TuneD
power-saver=powersave power-saver=powersave
balanced=balanced balanced=balanced
performance=throughput-performance performance=throughput-performance
[battery]
# PPD = TuneD
balanced=balanced-battery