装 Linux 的 Thinkpad X1C 在发高烧
前话
本着对小黑和 Linux 的喜欢,在去年年中买了 Thinkpad X1C 并装上了 Gentoo,然后,就很少再见它……因为我还有一本老 Thinkpad T440s + Gentoo 和一台性能强劲的 ITX + Gentoo,各种“派”小电脑。
今年因疫情原因,终于打开我的小宝贝,发现不该有的异常高温居然出现在小本本身上,待机 65 - 70 度,回顾了我 2010 年的 Thinkpad R400,调教完可是日常使用 30 度不到,14 年我一直抱怨烫手的 Thinkpad T440s 是 45 度,而今,这 Thinkpad X1C 就让人有点情绪了,高温伴随的可不只只是性能的下降,还有续航的短暂。我打开了我的 Thinkpad T440s,服役六年,大屁股(6 芯)电池现在使用 Gnome 3 和 默认系统配置(CPU 的 Governor 是 Conservative,没有使用 tlp 或 laptop mode tools 等)还剩 6 到 7 小时,而 X1C 使用 KDE 5 和默认系统配置居然有 1.5 小时那么长……和官方宣称的 10 多小时也差太多了吧。
发热问题
Linux 下大部分都是使用 lm-sensors 来检测温度的,详细的模块需要内核支持,不同笔记本的内核配置不同,针对自己的在 XXX Wiki 上找就行,而我去年就将匹配我电脑的内核 /usr/src/linux/.config
弄好,所以直接输入 sensors
来看看各个模块的温度。
解决问题
面对笔记本产生的热浪,一波接一波,我只能一步一步尝试能否解决,解决方向不外乎 ACPI。
从 BIOS 入手(失败)
基本所有的笔电都会可以设置 CPU 和 ACPI 的,看了下,默认的 ACPI 没得多余可以设置,肯定是用 AC 时候就性能,用 Battery 就节能。CPU 唯一能做的就是关闭多线程和虚拟化。结果关闭之后温度下降 2 度左右,这不知道是误差还是其他,算了,开启回来吧……
Cpupower 工具调节(失败)
依照我之前使用 AMD Ryzen 的经验,CPU 的发热在于他的 Turbo Boost,我使用 Cpupower 限制最高频率的时候,居然会把 Ryzen 的 Turbo Boost 搞没(意思就是你最高重设为多大都没有了)……但温度真的憨憨下降 10 多度……
我这里试下,发现怎么限制频率都没用,Governor 也没用,仿佛这个工具就是个玩具一样……
这里得说下 Ryzen 的 CPU Governor 是使用 Linux Kernel 的,但是到了 Intel Sandy Bridge 后的架构都是使用 intel_pstate 来搞事情,他自身也只有 Performance 和 Powersave 两种 Governor 而已,外部工具还对他没啥用。
使用 Intel 的私货调节(失败)
在 /sys/devices/system/cpu/intel_pstate
可以看到 intel_pstate 的信息,而 Governor 不管是 AC 还是 Battery,都是 Powersave:
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
所以用其方式来关闭 Turbo Boost:
echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo
发现确实温度确实低了,而且 CPU 没法跑到 3 GHz 以上了,性能砍一刀,温度总是能够看了吧。打开了我们熟悉的 B 站看弹幕视频,哇,温度一下子就 80 多度……
回归最开始的内核控制 CPU 频率(不妥)
上面那般折腾,我在想能不能使用之前内核调节那种,不就一切迎刃而解了吗。
直接在 grub 的内核配置 intel_pstate=disable
就可以禁用 intel_pstate,使用内核的管理了,果然 Conservative 的 Governor 回来了。
可是可是可是,新问题来了!禁用 intel_pstate 后,CPU 的频率可调节范围变了,从 400MHz - 3.9GHz 变成 800MHz - 1.6GHz 了,想砸键盘了没……
寻找外挂工具(失败)
外挂工具最出名的,当有 Laptop Mode Tools 的一个位置,而不知道是不是跟 intel_pstate 有冲突,CPU 和 GPU 控制不了,风扇差点搞坏,各种设备设置很多,确实可以省电,但是我这里的电老虎和大太阳并非它们……
寻找外挂工具二(勉强)
在 Gentoo Wiki 上有看到推荐的 Thermald,是 Intel 那帮人专门搞冷却 CPU 的。安装是特别简单,但是配置就头大了。基本网络上和官网都没有详细的参数说明,唯一给出的是帮助手册:
man thermal-conf.xml
但是可以发现里面参数说明缺失严重。
配置可以通过 dptfxtract
来自动检测生成,在 github 上拉下来就可以用了。
开启 Thermald 后,基本温度都是在机器自己风扇启动的阀值内,Thinkpad X1C 2019 是 63 度。没开启的续航是 1.5 小时不到,开启后则是 4 个多小时。
不过开启后,为了冷却,CPU 的频率经常是 1GHz 以下,越是占资源,频率越低,所以我打开个 Emacs + Java Lsp 卡得都写不了代码,频率经常是在 400MHz - 800MHz 之间跳。看电影有解码就很流畅,轻量办公的续航还是不错的。
但回归下,Battery 模式为了节能没毛病,AC 模式肯定不能有那么卡顿的体验,Thermald 的官网说开启和关闭是这么来的:
[root]: systemctl start thermald # turn on
[root]: systemctl stop thermald # turn off
但实际上,假如你开启了,关闭后怎么样也回不了性能状态了……
Thermald 其实还支持动态修改配置,通过 --enable-dbus
来开启对 dbus 消息的支持,那么这里是不是我们就可以不关闭,而直接动态设定一个温度墙来保证性能和节能呢?
很遗憾,不管在 thermal-conf.xml 还是 dbus 来通知 thermald 温度墙多少,他都不会变的,我的 Thinkpad X1C 永远就是 63 度……
在多种尝试后,我发现现在的 Thermald 是通过 PPCC 的电源表来控制的,假如 thermal-conf.xml 文件有 PPCC 配置,就会实现冷却功能,若无,就会回归原始状态,不知道是不是 bug,从 1.9.1 到 2.1 版本皆如此。
对于最后 Thermal 虽然有些不完美,但是我们可以去完善它。我的期望,简单如述:AC 下性能模式,Battery 下节能模式。
我们先创建一个目录,用来跑电源管理脚本的:
mkdir ~/.myacpi
然后呢,我们将之前自动生成的 /etc/thermald/thermal-conf.xml.auto
拷贝两份到该目录下:
cp /etc/thermald/thermal-conf.xml.auto ~/.myacpi/thermal-conf.xml.ac
cp /etc/thermald/thermal-conf.xml.auto ~/.myacpi/thermal-conf.xml.battery
紧接着,我们 battery 保留 PPCC 配置,ac 去掉:
<!--<PPCC>
<PowerLimitIndex>0</PowerLimitIndex>
<PowerLimitMinimum>5000</PowerLimitMinimum>
<PowerLimitMaximum>5000</PowerLimitMaximum>
<TimeWindowMinimum>28000</TimeWindowMinimum>
<TimeWindowMaximum>32000</TimeWindowMaximum>
<StepSize>500</StepSize>
</PPCC>-->
再者就是编写两个 Shell 脚本,ac 和 battery,而在这之前,需要我们的用户有 thermald
和 dbus-send
的 sudo
nopasswd 权限,当然这是因为这里我使用的是 KDE 的电源管理,针对用户的。
#! /usr/bin/env bash
## file: ac
sudo thermald --dbus-enable --config-file ~/.myacpi/thermal-conf.xml.ac && sudo dbus-send --system --dest=org.freedesktop.thermald /org/freedesktop/thermald org.freedesktop.thermald.Terminate && echo "[`date +'%F %T'`] ac thermald" >> ~/.myacpi/log
#! /usr/bin/env bash
## file: battery
sudo thermald --dbus-enable --config-file ~/.myacpi/thermal-conf.xml.battery && sudo dbus-send --system --dest=org.freedesktop.thermald /org/freedesktop/thermald org.freedesktop.thermald.Terminate && echo "[`date +'%F %T'`] battery thermald" >> ~/.myacpi/log
最后,就是在 KDE 的电源管理的 AC 和 Battery 选项卡里面加入各自的运行脚本。
寻找外挂工具三(失败)
顺藤摸瓜,就 Thermald 摸到另一个 Intel 的官方工具 intel-undervolt。想着给电脑减减压,也许是他压力太大了!但更改电压着实是个冒险的做法,在尝试过程中,笔电各种崩溃,睡眠各种唤不醒……
调节出合适的电压,每一种电脑都是不太一样的,所以要小心尝试,别步伐迈得过大,我的 Thinkpad X1C Carbon 2019 这里可以达到 -120mV,这是个比较大胆的值,所以还是提醒下,要千万小心,修改 /etc/intel-undervolt.conf
配置:
undervolt 0 'CPU' -120
undervolt 1 'GPU' -120
undervolt 2 'CPU Cache' -120
undervolt 3 'System Agent' -120
undervolt 4 'Analog I/O' 0
这里的 I/O 我是没有更改,因为之前 USB 和 Type-C 因为各种电压不足没法连接外设。
intel-undervolt read # 查看当前值
intel-undervolt apply # 更改为配置值
在观查功耗时,我能看到大概是下降了 2W 到 3W,那么我 51W 电池(实际可用感觉应该是 45W),大概也只能多出 30 分钟,但换来的可能是损坏硬件和系统不稳定。
尝试从功耗解决(还算 OK)
既然主要是关注续航,那么在 AC 下就让它继续发热,Battery 下就通过限制功耗来解决,这时性能低下,也就让它低下吧。这里刚好可以利用之前的 intel-undervolt 来检测功耗:
intel-undervolt measure
内核配置 powercap 后,是可以直接可以动态修改 /sys/class/powercap/intel-rapl/
目录里面的配置来实现功耗限制。在该目录下面可能有类似 intel-rapl:0 或 intel-rapl:1 的目录,我们只能更改类型为 package0,不能是 psys 的,具体在这对应目录下的 name 可以分辨类型。功耗墙的设定是在 constraint_0_power_limit_uw 和 constraint_1_power_limit_uw 文件中,一个是 long term 一个是 short term。
为了方便,我随便写了一个简单脚本放到 /sbin
下,并且给 sudo
无密权限
#! /usr/bin/env bash
### file: my-acpi-mode
orginal_value=51000000
min_value=3500000
mid_value=5000000
value="$1"
if [ "$value" == "min" ]; then
value=$min_value
fi
if [ "$value" == "max" ] || [ -z "$value" ]; then
value=$orginal_value
fi
if [ "$value" == "mid" ]; then
value=$mid_value
fi
if (( value >= min_value && value <= orginal_value )); then
echo $value > /sys/class/powercap/intel-rapl/intel-rapl\:0/constraint_0_power_limit_uw
echo $value > /sys/class/powercap/intel-rapl/intel-rapl\:0/constraint_1_power_limit_uw
else
echo "Error Value"
fi
最后,将之前 KDE 触发的 ac 和 battery 脚本改成:
#! /usr/bin/env bash
## file: ac
sudo my-acpi-mode max && echo "[`date +'%F %T'`] ac mode" >> ~/.myacpi/log
#! /usr/bin/env bash
## file: battery
sudo my-acpi-mode mid && echo "[`date +'%F %T'`] battery mode" >> ~/.myacpi/log
在外出的时候,可能还会运行:
sudo my-acpi-mode min
来保证更长的续航。
后话
在使用 powertop 检测耗电的时候,发现发热和耗电的原因其实是 Intel kaby GPU在 Kernel 是 5.5 以下 RC6 是不起作用,而现在的 5.5 以上 GPU 是经常会 hang 的 bug,这种情况持续了 7 到 8 个月了,所以只能期待 5.6+ 以上的内核能够不 hang 让 GPU 的 RC6 生效。
但本子总要使用起来,Intel 的 GPU 是在 CPU 结构的 Package 里的,所以降压和降低功耗,是现在能够缓解下续航短的压力的,且等到 GPU RC6 解决了,减少功耗的脚本依然能够适用,将续航变得更长。