17、性能分析工具使用:Systrace/Perfetto使用技巧、Simpleperf CPU采样、Memory Profiler、GPU Inspector、Camera Trace点添加
做Camera性能优化,说白了就是跟时间赛跑。你想想看,从用户按下快门到出图,中间几百毫秒里到底发生了什么?哪个环节拖了后腿?没有趁手的工具,你只能靠猜。
我个人习惯,先把工具链搭好。工欲善其事,必先利其器。今天我就把压箱底的那几个工具用法,掰开了揉碎了讲给你听。
17.1 Systrace / Perfetto:看全局的利器
Systrace 和 Perfetto 其实是一脉相承的东西。Perfetto 是 Systrace 的下一代,功能更强,UI也更现代。我建议你直接上 Perfetto,除非你还在维护 Android 9 以下的旧平台。
用这两个工具,核心就一句话:找到那个「不该那么长」的区间。
举个例子。我在项目中遇到过预览启动慢的问题。打开 Perfetto 一看,从 App 发起请求到 HAL 返回第一帧,中间有个 200ms 的空白。点进去发现,原来是底层在等一个 sensor 的初始化完成。这个等待完全可以在上层准备 UI 的时候并行做掉。
- 抓取时加上
-a 你的包名,只关注自己的进程,不然信息太多看花眼 - 善用「A」键打标记,记录操作时间点,方便对照
- 重点关注
BufferQueue、HAL、CameraService这几个线程
17.2 Simpleperf:CPU 采样的瑞士军刀
Simpleperf 是 Android 官方的 CPU 性能分析工具,比 perf 更友好。它做的是采样——每隔一段时间看看 CPU 正在执行哪个函数,最后统计出热点。
我一般这么用:
# 先找到 camera provider 的 PID
adb shell ps | grep camera
# 采样 10 秒
adb shell simpleperf record -p <PID> -e cpu-clock -f 1000 --duration 10
# 生成报告
adb shell simpleperf report --full-callgraph
输出结果里,你会看到类似这样的东西:
| Overhead | Symbol | Shared Object |
|---|---|---|
| 15.2% | HAL3ProcessRequest | camera.hal.so |
| 8.7% | JpegEncode | libjpeg.so |
| 5.3% | memcpy | libc.so |
看到 memcpy 占 5% 以上,你就要警觉了。我曾经在一个项目里发现 memcpy 占了 12%,最后追查下来是 YUV 转 JPEG 时反复拷贝了三次。改成零拷贝后,拍照速度直接快了 30%。
17.3 Memory Profiler:别让内存成为隐形杀手
Camera 是吃内存大户。一张 12MP 的 raw 图就 20MB 左右,再加上中间 buffer、算法库的临时内存,稍不注意就 OOM 了。
Android Studio 自带的 Memory Profiler 够用。我习惯这么操作:
- 先跑一遍完整的拍照流程,记录内存峰值
- 然后反复进出预览界面,看 GC 次数和内存回收情况
- 重点关注
Native Heap,因为 Camera HAL 层很多内存是 C++ 分配的
嗯,这里要注意。Java 层的内存泄漏相对好查,但 Native 层的泄漏就麻烦了。我建议配合 libmemunreachable 工具一起用,它能帮你找到 native 层谁没释放。
dumpsys meminfo 才定位到。
17.4 GPU Inspector:渲染管线的 X 光机
GPU Inspector 是 Android 12 以后才正式推出的。它能看到 GPU 的每一帧渲染耗时、顶点数、片段着色器负载等。
对于 Camera 来说,GPU 主要干两件事:
- 预览画面的合成(SurfaceFlinger 那边)
- 滤镜、美颜等 GPU 算法的执行
打开 GPU Inspector,如果看到 Frame Duration 超过 16ms(60fps 的阈值),那就说明 GPU 扛不住了。这时候要么降低分辨率,要么优化 shader。
我记得有个项目,美颜算法在 GPU 上跑,一帧要 25ms。后来发现是循环里有个不必要的纹理采样,去掉后降到 8ms。这种问题,没有 GPU Inspector 根本看不出来。
17.5 Camera Trace 点:给你的代码装上「行车记录仪」
前面几个工具都是外挂式的。但有时候,你需要在自己代码里埋点,才能精准知道某个函数花了多久。
Android 提供了 Trace 类,用法很简单:
// Java/Kotlin 层
Trace.beginSection("HAL3:CaptureRequest");
// ... 你的代码 ...
Trace.endSection();
// Native 层
#include <utils/Trace.h>
ATRACE_CALL(); // 自动在函数进出时打点
加了这些 Trace 点之后,再跑 Systrace/Perfetto,你就能看到自己定义的标签了。我习惯在每个关键路径上都加:
App:onCreate→ 应用启动HAL:configureStreams→ 配置流HAL:processCaptureRequest→ 拍照请求Algo:JpegEncode→ JPEG 编码
最后说一句。工具终究是工具,关键还是你得知道「要查什么」。我见过有人拿着 Perfetto 看了半天,说「看不出问题」。其实不是工具不行,是他自己没想清楚——到底是想优化启动速度?还是拍照延迟?还是预览帧率?目标明确了,工具才能发挥威力。
- 先用 Perfetto 看整体流程,找到异常区间
- 用 Simpleperf 定位 CPU 热点函数
- 用 Memory Profiler 检查内存泄漏
- 用 GPU Inspector 确认渲染瓶颈
- 最后加自定义 Trace 点,做精细化验证
公众号:蓝海资料掘金营,微信deep3321