我的笔记本电脑无法可靠地发送 ACPI 放电事件,因此我创建了一个 Systemd 计时器和服务来定期轮询电池电量并决定计算机是否应该休眠。然而,在启动后的一段随机时间内(通常在一个小时左右),Systemd 开始使用大约 90% 的 CPU,并继续这样做,直到systemctl stop
定时器停止。具体来说,进程是(按 CPU 使用率)
~90%:/usr/lib/systemd/systemd --switched-root --system --deserialize 32
~80%:/usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
~20%:/usr/lib/systemd/systemd-logind
当我停止计时器时,这些都回到接近零。相关文件如下。我运行的是 Arch Linux,Systemd 版本 235.8-1。值得注意的是,即使连接到墙上电源,hibernate-if-low-battery
甚至不应该运行时,也会发生此问题。
自动休眠定时器
[Unit]
Description=Check battery level periodically and hibernate when low
[Timer]
OnBootSec=30s
OnUnitActiveSec=30s
[Install]
WantedBy=timers.target
自动休眠服务
[Unit]
Description=Check battery level and hibernate if low
ConditionACPower=false
[Service]
Type=oneshot
ExecStart=/usr/local/bin/hibernate-if-low-battery
电池电量低时休眠
#!/usr/bin/env bash
# Configuration.
BATTERY_PATH=/sys/class/power_supply/BAT0
CRITICAL_BATTERY_PERCENTAGE=5
# Calculate (the floor of) the battery percentage.
current_battery_level=$(< ${BATTERY_PATH}/energy_now)
max_battery_level=$(< ${BATTERY_PATH}/energy_full)
current_battery_percentage=$(((current_battery_level * 100)/max_battery_level))
if ((current_battery_percentage <= critical_battery_percentage)); then
logger 'Hibernating due to low battery.'
systemctl hibernate
fi
答案1
这似乎是由于使用计时器触发使用ConditionACPower
;的服务而导致的 systemd 错误。看https://github.com/systemd/systemd/issues/5969。将交流电源检查移至hibernate-if-low-battery
脚本中应该可以解决问题。具体来说,这有效:
自动休眠服务
[Unit]
Description=Check battery level and hibernate if low
[Service]
Type=oneshot
ExecStart=/usr/local/bin/hibernate-if-low-battery
电池电量低时休眠
#!/usr/bin/env bash
# Configuration.
BATTERY_PATH=/sys/class/power_supply/BAT0
AC_PATH=/sys/class/power_supply/AC
CRITICAL_BATTERY_PERCENTAGE=5
# Get AC power status.
ac_power_active=$(< "${AC_PATH}/online")
# Calculate (the floor of) the battery percentage.
current_battery_level=$(< "${BATTERY_PATH}/energy_now")
max_battery_level=$(< "${BATTERY_PATH}/energy_full")
current_battery_percentage=$(((current_battery_level * 100)/max_battery_level))
battery_level_critical=$((current_battery_percentage <= critical_battery_percentage))
if (( ! ac_power_active && battery_level_critical )); then
logger 'Hibernating due to low battery.'
systemctl hibernate
fi