htop 中 CPU 频率读取错误的迷之问题
从某一天开始,我也不知道更新了什么, htop 的 CPU 频率突然就变得奇怪了。具体现象是空载时CPU频率基本全部保持在2600Mhz(正好是不开睿频的最高频率)。正常的情况下,空载的时候由于 intel_pstate 的作用,CPU本身的频率应该维持在 800Mhz 左右。一开始我还以为真的是 CPU 频率有问题,怀疑到 CPU 调度器上,但是完成换了几个内核之后状况相同,就排除是调度器的问题了。应该是 htop 读取频率的时候出了问题,而不是 CPU 本身。
除了htop还有什么可以读取CPU频率并与之作对比呢?接着我就去试了试KDE的系统监视器。在KDE的监视器里添加CPU频率的监视条目,可以发现用这个工具读取的频率应该差不多是对的——空载时多数CPU频率处于800Mhz. 然而到现在,一个极为怪诞的现象发生了:
- 先开htop,后开系统监视器,htop频率不正确
- 先开系统监视器,再开htop,htop频率正确
- 在上一步的基础上,关闭系统监视器,htop频率不正确
到这里我真的蒙圈,完全不知道是怎么回事了。到这里只能想想这些软件读取的原理了。遂去看了下 htop 的 issue. 发现读取CPU频率主要是靠两个地方,一个是/proc/cpuinfo
,另一个是/sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
. 在我的机器上,前者的频率并不正确,而后者的频率是正确的(可以看下这个 issue),看来只能去看下htop的源码了。
总之在代码里搜来搜去的,这个 commit引起了我的注意。这条commit的大概意思是,先从前者读取CPU频率,若读取速度太慢(判断标准是读取CPU0频率的时间大于500us),则会在后面30次读取中使用后者获取CPU频率。那我们就要测试一下读取的速度了。
1 |
|
我也通过 debug 测试了一下,我读取CPU0频率的时间高达16000us, htop 自然会去读后者的频率导致频率显示不正确了。
同时还有另一个发现,也可以解释上面的第二条现象,当用有一个进程在读取/sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
时,再去读这个地方:
1 |
|
快多了!这就可以解释上面第二条异常现象的成因了,当有另一个进程在读取的时候,htop测得的延迟小于500us,就获得了正确的频率。
那么到现在解决的方法就昭然若揭了:
- 改内核,让延迟降下来
- 加入异步,让htop读取成功后再刷新
- 让htop开一个子进程去读取频率来降低延迟
- 改变阈值让htop不去读取
/proc/cpuinfo
很遗憾方法1我是没法做到的,这个延迟似乎涉及psate
的实现,是我完全不懂的领域;方法2和方法3估计我写出来提交 PR 也不一定被通过,就不费那个事了;咱就选用最简单的方法,改一下延迟,把500us改成19000us,凑合用得了。这样的后果是 htop 的操作会卡卡的,但是影响也不是很大。