第二章:性能监控工具链——把CPU的“心电图”看懂
做性能调优,说白了就是跟CPU“对话”。你得知道它什么时候累、什么时候偷懒、什么时候在空转。我刚开始接触瑞芯微平台时,最头疼的不是写代码,而是——我根本不知道系统在干嘛。
这一章,我就带你把这套工具链捋一遍。perf、ftrace、trace-cmd,还有RK自己搞的debugfs接口。嗯,这些家伙用好了,你就能像医生看心电图一样,把CPU的脉搏摸得清清楚楚。
2.1 perf:性能分析的瑞士军刀
perf 这工具,我用了快十年了。它基于Linux内核的perf_event子系统,能采集硬件计数器、软件事件、tracepoint……几乎你能想到的指标,它都能拿。
核心能力:
- CPU周期数、指令数、缓存命中/未命中
- 分支预测错误率
- 上下文切换次数
- CPU迁移(migration)统计
我在RK3588上调试一个视频编解码项目时,发现帧率死活上不去。用perf stat一跑,好家伙,L2缓存未命中率高达40%。说白了,数据在内存和缓存之间来回倒腾,CPU大部分时间都在等。
# 采集CPU周期和缓存事件
perf stat -e cycles,instructions,cache-references,cache-misses -a sleep 5
# 采样热点函数
perf record -F 99 -a -g -- sleep 10
perf report -g graph
这里有个小技巧:-F 99 表示每秒采样99次。为什么是99?不是100?因为100Hz容易跟系统定时器产生共振,采样数据会失真。这是我踩过的坑,分享给你。
2.2 ftrace:内核的“显微镜”
perf 看宏观,ftrace 看微观。它能跟踪内核函数的调用过程,精确到纳秒级。你想想看,一个系统调用从用户态陷入内核,中间走了哪些函数?每个函数花了多少时间?ftrace 全给你记下来。
我个人习惯在调试驱动时必开ftrace。尤其是DMA传输、中断处理这类时间敏感的操作,ftrace 能帮你定位到到底是哪个环节在拖后腿。
# 挂载tracefs
mount -t tracefs nodev /sys/kernel/tracing
# 设置跟踪器为function_graph
echo function_graph > /sys/kernel/tracing/current_tracer
# 只跟踪特定函数
echo rk_dma_chan_irq > /sys/kernel/tracing/set_ftrace_filter
# 开始跟踪
echo 1 > /sys/kernel/tracing/tracing_on
# ... 运行你的程序 ...
echo 0 > /sys/kernel/tracing/tracing_on
# 查看结果
cat /sys/kernel/tracing/trace
避坑指南:我曾经在生产环境上直接开function_graph,结果系统负载飙升,业务全挂了。记住,ftrace 的开销不小,尤其是全量跟踪时。建议只过滤你关心的函数,或者用trace-cmd来降低侵入性。
2.3 trace-cmd:ftrace的“友好版”
说实话,直接操作ftrace的sysfs接口有点反人类。trace-cmd 就是它的命令行封装,用起来顺手多了。它支持录制、回放、过滤,还能跟perf联动。
# 录制10秒的系统调用事件
trace-cmd record -e syscalls -e sched_switch -o trace.dat sleep 10
# 查看录制结果
trace-cmd report trace.dat
trace-cmd 最大的好处是——你可以把数据拿到另一台机器上分析。我在客户现场经常这么干:现场录一份trace.dat,回来慢慢看。省得在客户机器上装一堆分析工具。
2.4 RK的debugfs接口:芯片级的“仪表盘”
瑞芯微在debugfs里藏了不少好东西。比如CPU频率的实时状态、DVFS的调频策略、甚至每个cluster的功耗数据。这些信息,perf和ftrace拿不到。
# 查看CPU频率
cat /sys/kernel/debug/clk/clk_core_bus/clk_rate
cat /sys/kernel/debug/clk/clk_cpu_l/clk_rate
# 查看DVFS状态
cat /sys/kernel/debug/regulator/regulator_summary
# 查看CPU负载分布
cat /sys/kernel/debug/sched_features
注意:debugfs 接口在不同内核版本、不同芯片型号上可能不一样。RK3588 和 RK3568 的路径就有差异。我建议你拿到板子后,先 ls /sys/kernel/debug/ 扫一遍,看看有哪些可用节点。
2.5 实战:采集CPU频率与负载
好了,理论说完了。咱们来点实际的。假设你要分析一个视频解码场景下的CPU表现,该怎么做?
我的做法是——三管齐下:
- perf stat 看整体:CPU利用率、缓存命中率、IPC(每周期指令数)
- ftrace 看细节:中断处理时间、调度延迟
- debugfs 看硬件:实际运行频率、电压、温度
# 第一步:perf采集宏观指标
perf stat -e cycles,instructions,cache-misses,branch-misses -p $(pidof gst-launch-1.0) sleep 10
# 第二步:ftrace跟踪调度和中断
echo 0 > /sys/kernel/tracing/tracing_on
echo function > /sys/kernel/tracing/current_tracer
echo rk_vdec_irq_handler > /sys/kernel/debug/tracing/set_ftrace_filter
echo 1 > /sys/kernel/tracing/tracing_on
# 运行视频解码
echo 0 > /sys/kernel/tracing/tracing_on
cat /sys/kernel/tracing/trace > /tmp/ftrace_vdec.log
# 第三步:读取debugfs中的频率和温度
watch -n 1 'cat /sys/kernel/debug/clk/clk_cpu_l/clk_rate; cat /sys/class/thermal/thermal_zone0/temp'
你看,这三步走下来,CPU在干什么、为什么这么干、实际跑在什么状态,全清楚了。我在调一个4K解码卡顿的问题时,就是用这套方法发现——CPU频率被限制在1.2GHz,但解码器需要1.8GHz才能流畅。原因?温控策略太保守了。调整一下thermal的阈值,问题解决。
2.6 关键指标速查表
| 指标 | 工具 | 含义 | 正常范围 |
|---|---|---|---|
| IPC | perf stat | 每周期指令数,衡量CPU效率 | 0.5~2.0(视架构而定) |
| L2缓存命中率 | perf stat | L2缓存访问命中比例 | > 90% |
| 上下文切换 | perf stat / ftrace | 每秒进程切换次数 | < 10000/s |
| CPU频率 | debugfs / cpufreq | 当前运行频率 | 与负载匹配 |
| 中断延迟 | ftrace | 从中断发生到处理的时间 | < 100us |
嗯,这张表你最好打印出来贴在工位上。我当年就是靠它,一步步把RK3399的编解码性能从30fps提到了55fps。
最后说一句:工具只是工具,关键是你得知道看什么、怎么看。perf告诉你“缓存没命中”,ftrace告诉你“哪个函数在等”,debugfs告诉你“频率没上去”。三块拼图凑一起,问题就浮出水面了。
下一章,咱们聊聊CPU调频策略——怎么让大小核真正“各司其职”。