嵌入式平台性能基准测试:用perf、gprof、valgrind给ARM Cortex-A“把脉”
做WebRTC通话质量监控,第一步不是调算法,而是摸清你手头这块ARM Cortex-A处理器的底细。我见过太多团队,上来就优化代码,结果发现瓶颈根本不在CPU——要么是内存带宽卡死,要么是网络IO把整个系统拖垮。
说白了,基准测试就是给你的嵌入式平台拍一张“体检CT”。今天我就带你走一遍,怎么用perf、gprof、valgrind这三把刀,把CPU、内存、网络IO的基线数据老老实实采出来。
2.1 测试环境与准备工作
先交代一下我常用的环境。ARM Cortex-A系列,比如A72、A53、A76,跑Linux 4.14以上内核。工具链用gcc 8.3+,打开-g -O2编译选项。
我个人习惯,在板子上先跑一遍lscpu和cat /proc/cpuinfo,确认CPU频率缩放策略是performance而不是ondemand。为什么?因为ondemand会在低负载时降频,测出来的数据根本不准。
echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor锁频。记得所有核心都设一遍。
另外,关掉看门狗和后台服务。我踩过坑——测试跑到一半,看门狗把系统重启了,数据全丢。
2.2 CPU性能基线:perf实战
perf是Linux内核自带的采样分析器,轻量、精准。对于WebRTC这种实时应用,我主要看三个指标:IPC(每周期指令数)、缓存命中率、分支预测错误率。
先来个最简单的:统计你的WebRTC进程CPU占用。
# 采集30秒,采样频率99Hz
perf stat -e cycles,instructions,cache-references,cache-misses,branch-misses \
-p $(pidof webrtc_agent) sleep 30
输出大概长这样:
| 事件 | 计数 | 比率 |
|---|---|---|
| cycles | 12,345,678,901 | — |
| instructions | 8,765,432,109 | IPC = 0.71 |
| cache-misses | 234,567 | 2.68% |
| branch-misses | 12,345 | 1.41% |
IPC 0.71对于Cortex-A72来说偏低。我记得有一次,一个客户的项目IPC只有0.4,查了半天发现是大量未对齐的内存访问。perf top一抓,热点全在memcpy上。
CONFIG_PERF_EVENTS。有些嵌入式板子的内核是裁剪过的,perf可能跑不起来。提前确认。
如果想看函数级热点,用perf record:
perf record -F 99 -p $(pidof webrtc_agent) -g -- sleep 30
perf report -n --stdio
-g开启调用链,能看到是哪个函数调了哪个函数。我一般先看Overhead最高的几个函数,如果编解码占超过40%,那CPU就是瓶颈。
2.3 内存性能基线:valgrind的cachegrind
valgrind是个重量级选手,但cachegrind工具对分析缓存行为非常有用。它模拟CPU的L1/L2缓存,告诉你每一行代码的缓存缺失情况。
valgrind --tool=cachegrind --I1=32768,8,64 --D1=32768,8,64 \
--LL=262144,16,64 ./webrtc_agent --test-mode
参数说明:I1是L1指令缓存32KB,8路组相联,64字节行。这些参数要根据你的芯片手册填。Cortex-A72的L1是32KB,L2通常是512KB~2MB。
跑完后生成cachegrind.out.xxx,用cg_annotate查看:
cg_annotate cachegrind.out.xxx --auto=yes
重点关注D1mr(L1数据读缺失)和LLmr(LLC读缺失)。如果LLC缺失率超过5%,说明数据局部性差。我在一个H.264编码器里遇到过,LLC缺失率高达12%,后来把宏块数据结构体重新排列,降到3%以下。
2.4 网络IO基线:iperf + 自定义hook
网络IO是WebRTC的生命线。我不用iperf只测带宽,因为那太粗糙。我会同时测延迟抖动和丢包率。
先上iperf测UDP吞吐:
# 服务端
iperf3 -s -p 5001
# 客户端,模拟WebRTC的UDP流
iperf3 -c 192.168.1.100 -p 5001 -u -b 5M -l 1200 -t 60
但更重要的,是看WebRTC内部的数据。我写了个小hook,在pacer_controller和transport_feedback处打点,采集RTT和丢包率。
| 指标 | 良好 | 临界 | 差 |
|---|---|---|---|
| RTT (ms) | < 50 | 50~150 | > 150 |
| 丢包率 (%) | < 0.5 | 0.5~2 | > 2 |
| 抖动 (ms) | < 10 | 10~30 | > 30 |
我曾经在一个Wi-Fi环境下测,丢包率忽高忽低,从0.1%跳到5%。后来发现是Wi-Fi的省电模式在作祟,关掉就稳定了。
2.5 知识体系:一张图看懂基准测试
下面这张SVG图,把整个基准测试的流程和工具串起来了。你照着这个走,不会漏项。
2.6 避坑指南:我踩过的三个坑
做基准测试看着简单,其实全是细节。我把自己踩过的坑列出来,你绕开走。
- 坑一:perf采样频率太高。我曾经设
-F 999,结果perf自己占用了30% CPU,测出来的数据全是perf的开销。建议-F 99或-F 199,够用。 - 坑二:valgrind跑得太慢。valgrind会让程序慢10~20倍。如果你测的是实时音视频流,跑着跑着就卡死了。我的做法:用
--trace-children=no只分析主线程,或者用录制好的pcap文件回放。 - 坑三:网络测试没考虑背景流量。有一次我在板子上跑iperf,结果Wi-Fi芯片同时在扫描热点,吞吐掉了一半。测试前用
tcpdump确认没有其他流量。
2.7 基线数据怎么用
采完数据不是终点。你要把这些基线值写进你的性能监控系统。比如,在WebRTC的StatsCollector里加几个自定义指标:
// 伪代码示例
struct PerformanceBaseline {
float ipc_baseline; // 0.70
float l1_cache_miss_rate; // 0.03
float llc_miss_rate; // 0.015
float rtt_baseline_ms; // 20.0
float packet_loss_baseline; // 0.001
};
每次通话结束后,把实际值和基线对比。如果IPC掉到0.5以下,说明CPU过载;如果丢包率超过基线10倍,说明网络出了问题。这样你就能在用户投诉之前发现问题。
好了,这一章的内容就到这。你手头有Cortex-A的板子的话,现在就可以跑一遍perf stat,看看你的IPC是多少。数据不会骗人。