4、CPU性能监控:深入/proc/cpuinfo与/sys/devices/system/cpu,理解CPU调频策略

说到CPU性能监控,很多人第一反应就是跑个top或者htop看看占用率。嗯,这当然没错,但说实话,这只能看到表面。真正要摸透Jetson这颗ARM CPU的脾气,你得学会跟/proc/cpuinfo/sys/devices/system/cpu这两个“内核窗口”打交道。

我个人习惯,拿到一块新的Jetson板子,第一件事不是跑分,而是先看看CPU到底能跑多快、当前在用什么策略跑。你想想看,如果连CPU的“档位”都没搞清楚,后面做性能调优就是瞎忙活。

4.1 从/proc/cpuinfo读懂CPU的“身份证”

/proc/cpuinfo这个文件,说白了就是CPU的户口本。里面记录了每个核心的型号、主频、特性等关键信息。我经常用它来快速确认当前系统是否识别了所有核心。

在Jetson上执行一下:

cat /proc/cpuinfo | grep -E "processor|model name|BogoMIPS|CPU part"

你会看到类似这样的输出:

processor       : 0
model name      : ARMv8 Processor rev 1 (v8l)
BogoMIPS        : 62.50
CPU part        : 0xd03

processor       : 1
model name      : ARMv8 Processor rev 1 (v8l)
BogoMIPS        : 62.50
CPU part        : 0xd03

processor       : 2
model name      : ARMv8 Processor rev 1 (v8l)
BogoMIPS        : 62.50
CPU part        : 0xd04

processor       : 3
model name      : ARMv8 Processor rev 1 (v8l)
BogoMIPS        : 62.50
CPU part        : 0xd04

这里有个细节要注意。CPU part字段的值,0xd03代表Cortex-A53核心(小核),0xd04代表Cortex-A73核心(大核)。我在项目中遇到过,有人发现Jetson Nano的CPU跑不满,查了半天才发现是大小核的调度策略没配好,导致所有任务都压在小核上了。

关键点:Jetson系列普遍采用ARM big.LITTLE架构。大核(高性能)和小核(低功耗)混在一起,/proc/cpuinfo能帮你一眼看出哪个核心是哪个类型。

4.2 /sys/devices/system/cpu:CPU的“控制面板”

如果说/proc/cpuinfo是只读的身份证,那/sys/devices/system/cpu就是你可以动手调节的控制面板。这里每个CPU核心都有一个独立的目录,比如cpu0cpu1……里面藏着调频、调压、热管理的各种接口。

我最常用的几个文件:

  • cpufreq/:调频相关的所有东西都在这里
  • online:控制核心的开关(0表示离线,1表示在线)
  • thermal_throttle/:温度降频的阈值设置

先看看当前CPU能跑哪些频率:

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies

输出可能是:

408000 720000 960000 1200000 1479000

嗯,单位是kHz。也就是说这颗核心最低408MHz,最高1.479GHz。我曾经调试一个实时视频处理项目,发现CPU频率一直在408MHz和720MHz之间跳变,导致画面卡顿。后来一查,是默认的调频策略太保守了。

4.3 CPU调频策略:性能与功耗的博弈

调频策略,英文叫governor。它决定了CPU在什么情况下升频、什么情况下降频。Jetson上常见的策略有这几种:

策略名称 行为特点 适用场景
performance 始终跑在最高频率 对延迟敏感、持续高负载的任务
powersave 始终跑在最低频率 后台低负载、省电优先
ondemand 按需快速升频,空闲时降频 日常使用,兼顾性能与功耗
conservative 缓慢升频,缓慢降频 负载波动不大的场景
schedutil 基于调度器负载反馈调频 Linux内核4.7+推荐,更智能

查看当前策略很简单:

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

Jetson默认通常是ondemandschedutil。我个人建议,如果你在做推理任务或者实时控制,直接切到performance。别犹豫,省那点电不够你折腾的。

小技巧:想一次性设置所有核心的策略?用这个命令:

for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do echo performance > $i; done

注意,Jetson上有些核心可能没有独立的调频目录(比如某些小核被绑定在大核的调频域里),执行前先确认一下。

4.4 实战:手动锁定CPU频率

有时候光改策略还不够。比如你发现某个算法在1.2GHz时跑得最稳,再高就过热降频,再低又性能不够。这时候就需要手动锁定频率。

步骤很简单:

  1. 先把策略改成userspace,这样内核才会听你的手动设置
  2. 然后写入目标频率
echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
echo 1200000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed

验证一下:

cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq

输出应该是1200000。嗯,锁住了。

注意:手动锁定频率后,CPU不会自动降频。如果你跑完高负载任务忘了改回去,板子会一直处于高功耗状态。我曾经有一次调试完忘记恢复,结果Jetson Nano在无负载时也发热严重,白白浪费了几个小时的电。所以养成好习惯:调试完记得改回ondemandschedutil

4.5 监控CPU频率的实时变化

光设置还不够,你得能看到它实时怎么变的。我写了个简单的一行命令,用来盯着频率跳变:

watch -n 1 "cat /sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_cur_freq"

这会每秒刷新一次,显示所有核心的当前频率。如果你看到频率在剧烈抖动,说明负载变化很大,或者调频策略太敏感了。

另外,/proc/cpuinfo里其实也有当前频率信息,但它是采样值,不如sysfs里的实时。我个人更推荐用sysfs接口。

4.6 避坑指南:Jetson特有的调频限制

最后说几个我在Jetson上踩过的坑:

  • 热降频优先级高于调频策略:就算你设了performance,一旦温度超过阈值(比如80°C),内核会强制降频。这时候你查scaling_cur_freq会发现频率上不去,别慌,先看看/sys/class/thermal/thermal_zone*/temp
  • 大小核的调频域可能不同:有些Jetson型号(比如Xavier NX),大核和小核属于不同的调频域,需要分别设置。别只改了cpu0就以为全搞定了。
  • NVPower模式会覆盖你的设置:Jetson有NVIDIA自己的电源管理工具nvpmodel,它会在后台修改调频策略。如果你发现手动设置不生效,先跑一下sudo nvpmodel -q看看当前模式。

好了,关于CPU性能监控和调频策略,核心就是这些。记住一句话:读懂/proc/cpuinfo是入门,玩转/sys/devices/system/cpu才是进阶。下一章我们聊聊GPU的监控,那个更刺激——毕竟Jetson的强项在GPU上。