针对 ThinkPad 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