针对Thinkpad的Linux电源管理配置

X1C 2019 (gen7) Linux 配置

刚从 MacBook 13-inch 2016 换成 ThinkPad X1C 2019. 刷入 ArchLinux, 记录下针对 X1C 的CPU性能, 电源管理, 风扇调速配置.

电源管理

参考: ArchLinux wiki: Power Management,
ThinkWiki: How to reduce power consumption
ArchLinux wiki: tpacpi-bat, ThinkWiki: Tpacpi-bat

配置TLP

使用TLP (Linux 高级电源管理功能)以获得一些高级电源管理功能. 比如一些省电配置, 以及充放电管理. 首先安装:

yay -S tlp tlp-rdw
sudo systemctl enable tlp

如果想要开启tlp-rdw (针对无线电设备的省电模式) 需要开启NetworkManager-dispatcher, 然后mask掉systemd-rfkill.service和systemd-rfkill.socket
参考: NetworkManager_dispatcher, TLP-无线电设备向导

yay -S tlp-rdw
sudo systemctl enable NetworkManager-dispatcher
sudo systemctl mask systemd-rfkill.service
sudo systemctl mask systemd-rfkill.socket

tlp的配置文件在 /etc/tlp.conf, 可以参考默认配置文件. 以下是我的配置:

##下面的设置可以让设备在接入有线时关闭wifi
DEVICES_TO_DISABLE_ON_LAN_CONNECT="wifi wwan"
DEVICES_TO_DISABLE_ON_WIFI_CONNECT="wwan"
DEVICES_TO_DISABLE_ON_WWAN_CONNECT="wifi"
DEVICES_TO_ENABLE_ON_LAN_DISCONNECT="wifi wwan"
##自动设置CPU调速; 接入电源时设置为performance,
##使用电池时为powersave
CPU_SCALING_GOVERNOR_ON_AC=performance
CPU_SCALING_GOVERNOR_ON_BAT=powersave
##设置充放电阈值
START_CHARGE_THRESH_BAT0=80
STOP_CHARGE_THRESH_BAT0=90

如果对CPU调速器有疑惑可以看下面的文章: What are the implications of setting the CPU governor to “performance”?

注: performance 对应的EPP/EPB为 performance
powersave 对应的EPP/EPB为 balance

关于充电阈值设置, 参考: TLP-电池充电阈值.

当然也可以手动设置充电阈值:
sudo tlp fullcharge 此命令可以临时设置本次充满电
sudo tlp setcharge 80 90 BAT0 设置充到90%停止充电, 电量降至80%开始充电

另一种电源管理: tpacpi-bat

另一种选择: 也可以安装针对ThinkPad的 tpacpi-bat (注意 tp_smapi 在X1C gen7上不起作用)

临时手动设置充电阈值:

tpacpi-bat -v -s startThreshold 0 40 # 40%开始充
tpacpi-bat -v -s stopThreshold 0 80  # 80%停止充

使用 systemd 设置充电阈值, 编辑 /etc/conf.d/tpacpi

# battery is 1 for main, 2 for secondary, or 0 for either/both
BATTERY="0"
# Start charging threshold (0 for default, 1-99 for percent)
START_THRESHOLD="40"
# Stop charging threshold (0 for default, 1-99 for percent)
STOP_THRESHOLD="80"

sudo systemctl enable tpacpi-bat.service 开启服务

手动设置 CPU 调速

参考: ArchLinux wiki: CPU frequency scaling, CPU优化建议使用cpupower设置CPU Performance模式

除了使用TLP自动控制CPU调速外, 我们还可以使用 cpupower 手动控制.

# 调整cpufreq的governor
sudo cpupower frequency-set -g performance # performance模式
sudo cpupower frequency-set -g powersave # powersave模式

风扇调速

根据 ArchLinux wiki: Fan speed control, Linux 常常使用 NBFC 控制风扇
由于我是ThinkPad, 使用更简洁的 thinkfan 来控制风扇.

参考: ArchLinux wiki: thinkfan, ThinkFan项目主页

thinkfan

开始配置前最好先查看manpage: man thinkfan, man thinkfan.conf

需要修改配置文件/etc/thinkfan.conf, 示例配置在 GitHub: thinkfan/examples/ 和系统的 /usr/share/doc/thinkfan/examples/thinkfan.yaml 注意新版使用的是 yaml 语法, 不要使用旧版配置.

根据 man thinkfan.conf , ThinkFan 可以从 hwmon, thinkpad_acpi, NVML, atasmart 驱动程序获取温度信息. 我的 X1C 主要使用 hwmon 和 thinkpad_acpi.

温度传感器的路径

查看哪些hwmon可以使用:

find /sys/ -name 'temp*_input*'

查到的路径有4种, 类似于:

/sys/devices/platform/thinkpad_hwmon/hwmon/hwmon4/temp6_input
/sys/devices/platform/coretemp.0/hwmon/hwmon6/temp2_input
/sys/devices/pci0000:00/0000:00:1d.0/0000:03:00.0/hwmon/hwmon1/temp1_input
/sys/devices/virtual/thermal/thermal_zone0/hwmon0/temp1_input

查看各hwmon目录下的name文件得知:
/sys/devices/platform/thinkpad_hwmon/hwmon/hwmon4/ 是 thinkpad_acpi 附带的hwmon,
/sys/devices/platform/coretemp.0/hwmon/hwmon6/ 是coretemp (CPU核心温度*)
/sys/devices/pci0000:00/0000:00:1d.0/0000:03:00.0/hwmon/hwmon1/ 是nvme硬盘
/sys/devices/virtual/thermal/thermal_zone0/hwmon0/ acpitz (好像temp1是CPU插槽, temp4是电池*, 不过我没有temp4)
/sys/devices/virtual/thermal/thermal_zone6/hwmon7/iwlwifi (无线网卡*)

风扇调速接口

风扇速度控制就使用 thinkpad_acpi 接口了:

cat /proc/acpi/ibm/fan
status:     enabled
speed:      0
level:      auto
commands:   level <level> (<level> is 0-7, auto, disengaged, full-speed)
commands:   enable, disable
commands:   watchdog <timeout> (<timeout> is 0 (off), 1-120 (seconds))

最终的配置文件

最终配置如下:

sensors:
  - hwmon: /sys/class/hwmon
    name: iwlwifi_1 # 根据name文件的值搜索
    indices: [1]
    optional: true # 网卡温度在启动一段时间后才能读取, 设成可选

  - hwmon: /sys/class/hwmon
    name: acpitz
    indices: [1]

  - hwmon: /sys/class/hwmon
    name: nvme
    indices: [1]

  - hwmon: /sys/class/hwmon
    name: pch_cannonlake # 南桥
    indices: [1]

  - hwmon: /sys/devices/platform/coretemp.0/hwmon
    indices: [1, 2, 3, 4, 5, 6, 7] # CPU sensors, 其实只有6个核. 多出一个估计是平均温度?

fans:
  - tpacpi: /proc/acpi/ibm/fan

levels:
  - [0, 0, 35]
  - [1, 30, 40]
  - [2, 35, 45]
  - [3, 40, 50]
  - [4, 45, 55]
  - [5, 50, 60]
  - [6, 55, 65]
  - [7, 60, 70]
  - ["level disengaged", 65, 255]

不知为什么, 我安装的 ThinkFan optional: true不生效. 每次启动, 服务都会挂掉. 所以使用 Github issues 中的方法, 添加systemd附加配置

vim /etc/systemd/system/thinkfan.service.d/10-restart-on-failure.conf
[Unit]
StartLimitIntervalSec=60
StartLimitBurst=3

[Service]
Restart=on-failure
RestartSec=10

休眠/锁屏相关

合盖休眠

参考: Power_management#ACPI_events, Power_management#Delayed_lid_switch_action

这个好像是要修改 /etc/systemd/logind.conf 的. 不过我好像什么都没做就已经可以合盖休眠了哈哈.

低电量自动休眠

参考: 低电量自动休眠

编辑 /etc/udev/rules.d/99-lowbat.rules

# Suspend the system when battery level is low
SUBSYSTEM=="power_supply", ATTR{status}=="Discharging", ATTR{ca    pacity_level}=="Low", RUN+="/usr/local/bin/lowbat.sh"

编辑 /usr/local/bin/lowbat.sh

#!/usr/bin/env bash
# 倒计时结束后休眠, 中途插电就能取消
# udev 没有 PATH 环境变量, 所以要export
export PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:$PATH
# 设定参数
DUNST_ID=10086 # 给dunst使用的消息id号
TIME_OUT=30    # 倒计时
#Detect the name of the display in use
display=":$(ls /tmp/.X11-unix/* | sed 's#/tmp/.X11-unix/X##' | head -n 1)"
#Detect the user using such display
user=$(who | grep '('$display')' | awk '{print $1}' | head -n 1)
#Detect the id of the user
uid=$(id -u $user)
function notify-send() {
  sudo -u $user DISPLAY=$display DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus dunstify "$@"
}

function countdown() {
  for ((i = $TIME_OUT; i >= 0; i--)); do
    if test $((i % 2)) -eq 0; then
      notify-send --replace=$DUNST_ID --icon=error -h "string:fgcolor:#ff4444" "Battery level is low!" "System will hibernate in ${i} seconds."
    else
      notify-send --replace=$DUNST_ID --icon=error "Battery level is low!" "System will hibernate in ${i} seconds."
    fi
    # " Charging" / " Discharging"
    status=$(acpi -b | awk -F'[,:%]' '{print $2}')
    if [[ "$status" == " Charging" ]]; then
      notify-send --close=$DUNST_ID
      return
    fi
    sleep 1
  done
  systemctl hybrid-sleep
}

countdown

定时背光, 锁屏, 亮度调节

记录一下用到的工具和最后每阶段的时间.

用到的工具 电源下timeout 电池下timeout
变暗 clight 18分钟 3分钟
息屏 clight 20 5
锁屏 xidlehook 20 20
休眠 xidlehook 30

顺便记录一下: grep -q 1 /sys/class/power_supply/AC/online 可以判断是否正在使用电池

使用i3lock的锁屏脚本

因为需要被udev触发, 锁屏脚本还是放在 /usr/local/bin 下比较好

sudo vim /usr/local/bin/screenlock.sh

#!/usr/bin/env bash
is_running=$(ps aux | grep i3lock | grep -v grep)
[ -n "$is_running" ] && exit;

rectangles=" "
SCALE=$(($(xrdb -query |grep Xft.dpi|grep -o '[0-9]\+')/96))
SR=$(xrandr --query | grep ' connected' | grep -o '[0-9][0-9]*x[0-9][0-9]*[^ ]*')
for RES in $SR; do
  SRA=(${RES//[x+]/ })
  CX=$((${SRA[2]} + 25*$SCALE))
  CY=$((${SRA[1]} - 30*$SCALE))
  rectangles+="rectangle $CX,$CY $((CX+300*$SCALE)),$((CY-80*$SCALE)) "
done

TMPBG=/tmp/screen.png

if [[ $SCALE == 2 ]]; then
  maim $TMPBG && convert $TMPBG -scale 2.5% -scale 4000% -draw "fill black fill-opacity 0.4 $rectangles" $TMPBG
else # $SCALE is 1
  maim $TMPBG && convert $TMPBG -scale 5% -scale 2000% -draw "fill black fill-opacity 0.4 $rectangles" $TMPBG
fi

i3lock \
  -i $TMPBG \
  --timepos="x+110:h-70" \
  --datepos="x+135:h-45" \
  --clock --datestr "Type password to unlock..." \
  --insidecolor=00000000 --ringcolor=ffffffff --line-uses-inside \
  --keyhlcolor=d23c3dff --bshlcolor=d23c3dff --separatorcolor=00000000 \
  --insidevercolor=fecf4dff --insidewrongcolor=d23c3dff \
  --ringvercolor=ffffffff --ringwrongcolor=ffffffff --indpos="x+280:h-70" \
  --radius=20 --ring-width=3 --veriftext="" --wrongtext="" --noinputtext=""\
  --verifcolor="ffffffff" --wrongcolor="ffffffff" --timecolor="ffffffff" --datecolor="ffffffff"

rm $TMPBG

发表评论

邮箱地址不会被公开。 必填项已用*标注