Systemd 计时器开始随机使用 90% CPU

Systemd 计时器开始随机使用 90% CPU

我的笔记本电脑无法可靠地发送 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

相关内容