第二章:性能监控工具链——把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表现,该怎么做?

我的做法是——三管齐下:

  1. perf stat 看整体:CPU利用率、缓存命中率、IPC(每周期指令数)
  2. ftrace 看细节:中断处理时间、调度延迟
  3. 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调频策略——怎么让大小核真正“各司其职”。