8、Perfetto新一代工具:Perfetto架构、与Systrace对比、SQL分析、可视化
说到Android系统调试,Perfetto绝对是个绕不开的话题。我记得几年前大家还在用Systrace抓trace,那时候抓个长一点的场景,动不动就丢帧、卡死,甚至直接OOM。后来Google推出了Perfetto,我第一时间就切过去了。说实话,用完之后就再也没碰过Systrace——不是怀旧,是真的回不去了。
Perfetto的架构:到底长什么样?
Perfetto的架构,说白了就是三个核心组件:数据源(Producers)、服务端(Service)、消费者(Consumers)。你想想看,整个系统就像一条流水线:Producers负责采集各种数据,Service负责把这些数据整理好存起来,Consumers负责把数据拉出来给你看。
我个人习惯把Perfetto的架构画成下面这张图,这样理解起来更直观:
这里有个关键点:Perfetto的Service是运行在系统中的一个守护进程(traced),它负责接收所有Producers发来的数据。我刚开始用的时候,一直以为Perfetto是直接写文件的,后来看了源码才发现,它其实是先写到共享内存缓冲区,再异步落盘。这样做的好处很明显——对性能的影响极小。
Perfetto vs Systrace:到底强在哪?
这个问题我经常被问到。直接说结论:Systrace能做的,Perfetto都能做;Systrace做不了的,Perfetto也能做。
我整理了一个对比表格,你一看就明白了:
| 对比维度 | Systrace | Perfetto |
|---|---|---|
| 数据源 | 仅支持 ftrace + atrace | ftrace、atrace、heapprofd、perf、logcat 等 |
| 内存分析 | 不支持 | 支持 native heap 和 Java heap 采样 |
| SQL 分析 | 不支持 | 内置 trace_processor,支持 SQL 查询 |
| 长时抓取 | 容易 OOM,超过 10 秒就危险 | 支持数十分钟甚至数小时 |
| 可视化 | 基于 Chrome 的旧版 UI | 全新 UI,支持缩放、搜索、标记 |
| 跨平台 | 仅限 Android | Android + Linux + ChromeOS |
| 协议 | 基于文本协议 | 基于 protobuf,更高效 |
SQL分析:这才是Perfetto的杀手锏
Perfetto最让我惊艳的功能,就是它的SQL分析能力。你想想看,以前用Systrace的时候,想查某个进程的某个时间段内发生了多少次Binder调用,只能肉眼盯着看,或者写脚本解析文本。现在呢?一条SQL搞定。
Perfetto内置了一个叫trace_processor的组件,它会把trace数据导入到一个SQLite数据库中。然后你就可以用标准SQL来查询了。我给大家看几个我常用的查询:
查询某个进程的CPU使用率
SELECT
ts / 1e6 AS time_ms,
dur / 1e3 AS dur_us,
cpu,
end_state
FROM sched
WHERE utid = (
SELECT utid FROM thread WHERE name = 'com.example.app'
)
ORDER BY ts
LIMIT 20;
查找所有Binder事务的耗时
SELECT
process.name AS process_name,
thread.name AS thread_name,
slice.name AS binder_name,
dur / 1e6 AS dur_ms
FROM slice
JOIN thread_track ON slice.track_id = thread_track.id
JOIN thread ON thread_track.utid = thread.utid
JOIN process ON thread.upid = process.upid
WHERE slice.name GLOB 'binder*'
AND dur > 1000000 -- 耗时超过1ms的
ORDER BY dur DESC;
--txt 参数,这样生成的trace文件可以直接用文本编辑器打开查看。虽然文件会大一些,但调试的时候方便很多。
可视化:不只是好看
Perfetto的UI界面,说实话,第一次打开的时候我愣了一下——这玩意儿也太精致了吧?但用久了你会发现,它不只是好看,是真的好用。
几个我觉得特别实用的功能:
- 无限缩放:从毫秒级到秒级,随便拖拽缩放,不会卡死。我记得Systrace在缩放的时候经常白屏,Perfetto完全没这个问题。
- 搜索高亮:直接搜函数名、进程名、标签,所有匹配项都会高亮显示。我曾经在分析一个卡顿问题时,直接搜"Choreographer",一秒定位到丢帧位置。
- 标记与注释:可以在时间轴上添加标记,方便团队协作。我经常在分析报告里直接截图带标记的trace,沟通效率高很多。
- 多track联动:CPU、内存、网络、GPU,所有track可以同步滚动。你想想看,当你在CPU track上看到一个高峰,切换到内存track看看是不是同时有GC发生,这种联动分析在Systrace里基本做不到。
--buffer-size 参数,比如 --buffer-size 64mb,够用就好。
实战:一条SQL揪出卡顿元凶
说个我真实遇到的案例。有一次,一个App在启动时总是卡顿,大概卡了2-3秒。用Perfetto抓了trace之后,我直接跑了一条SQL:
SELECT
name,
dur / 1e6 AS dur_ms,
thread.name AS thread_name
FROM slice
JOIN thread_track ON slice.track_id = thread_track.id
JOIN thread ON thread_track.utid = thread.utid
WHERE dur > 5000000 -- 耗时超过5ms的
ORDER BY dur DESC
LIMIT 10;
结果出来,排第一的是一个叫SharedPreferences.load的操作,耗时1.2秒。嗯,问题找到了——主线程直接读了一个很大的SharedPreferences文件。后来改成异步加载,卡顿就消失了。
你看,如果没有SQL分析,我可能得在UI上翻半天才能找到这个点。但一条SQL,10秒钟就定位到了问题。这就是Perfetto的魅力所在。
好了,关于Perfetto的架构、对比、SQL分析和可视化,我就讲这么多。记住一句话:Perfetto不是Systrace的替代品,而是降维打击。如果你还没开始用,今天就可以试试。抓一次trace,跑一条SQL,你会回来感谢我的。
公众号:蓝海资料掘金营,微信deep3321