4、Perfetto 入门:Perfetto架构、Trace配置、SQL分析、与Systrace的差异
说到Android性能分析,Perfetto现在已经是绕不开的工具了。
我记得几年前,大家还在用Systrace抓取trace,那时候每次抓个长一点的场景,文件动不动就几百兆,打开分析简直是一种煎熬。后来Google推出了Perfetto,我第一时间就切了过去。说实话,用过之后,就再也回不去了。
这一章,我们就来聊聊Perfetto。我会从它的架构讲起,然后带你配置trace、用SQL做分析,最后再对比一下它和Systrace到底差在哪。
Perfetto的架构:它到底是怎么工作的?
Perfetto的架构,说白了就是三个核心组件:数据源(Producers)、服务端(Service)和消费者(Consumers)。
- Producers:负责采集数据。比如CPU调度、内存分配、GPU渲染、磁盘I/O等等。每个数据源都是一个独立的producer,互不干扰。
- Service:运行在设备上的守护进程(traced)。它负责接收producers发来的数据,然后写入共享内存缓冲区。
- Consumers:负责读取数据。可以是命令行工具(perfetto)、Web UI(ui.perfetto.dev),或者你自定义的客户端。
我在项目中遇到过一个问题:某个场景下trace数据总是丢失一部分。后来排查发现,是共享内存缓冲区太小,数据还没来得及被consumer读取就被覆盖了。嗯,这里要注意,缓冲区大小一定要根据你的trace时长和数据量来调整。
核心要点:Perfetto采用生产者-消费者模型,数据通过共享内存传递,避免了频繁的IPC调用,性能开销极低。
Trace配置:怎么写一个高效的配置文件?
Perfetto的trace配置是用protobuf格式写的。你可能会觉得有点麻烦,但用熟了之后,你会发现它比Systrace的命令行参数灵活太多了。
下面是一个我常用的配置模板,专门用来分析UI卡顿和CPU调度问题:
# ui_trace_config.pbtx
buffers: {
size_kb: 65536
fill_policy: DISCARD
}
buffers: {
size_kb: 2048
fill_policy: RING_BUFFER
}
data_sources: {
config {
name: "linux.ftrace"
ftrace_config {
ftrace_events: "sched/sched_switch"
ftrace_events: "power/cpu_frequency"
ftrace_events: "sched/sched_wakeup"
ftrace_events: "sched/sched_wakeup_new"
}
}
}
data_sources: {
config {
name: "android.surfaceflinger.frametimeline"
}
}
data_sources: {
config {
name: "android.gpu.memory"
}
}
duration_ms: 10000
这个配置做了几件事:
- 定义了两个缓冲区:一个64MB用于主数据,一个2MB用于环形缓冲(防止丢失关键事件)。
- 开启了sched调度事件、CPU频率变化、SurfaceFlinger帧时间线、GPU内存等数据源。
- 设置trace时长为10秒。
我的小技巧:我个人习惯把fill_policy设为DISCARD,这样当缓冲区满了之后,新的数据会覆盖旧数据。对于分析最近的性能问题,这个策略非常有效。
SQL分析:为什么说Perfetto的SQL是杀手锏?
这是Perfetto最让我惊艳的地方。它把trace数据全部导入到SQLite数据库中,你可以直接用SQL查询来分析。
举个例子,你想知道某个时间段内,哪个进程占用了最多的CPU时间:
SELECT
process.name,
SUM(dur) AS total_cpu_dur
FROM
sched_slice
JOIN
thread USING(utid)
JOIN
process USING(upid)
WHERE
ts >= 1000000000 AND ts <= 2000000000
GROUP BY
process.name
ORDER BY
total_cpu_dur DESC
LIMIT 10;
你看,一行SQL就把问题搞定了。这在Systrace时代,你得手动在时间轴上拖拽、缩放、肉眼观察,效率完全不在一个量级。
我曾经用这个SQL帮一个同事定位了一个诡异的卡顿问题。他怀疑是某个后台服务在搞鬼,但用Systrace看了半天也没找到。我直接用SQL查了所有线程的唤醒源,发现是一个定时器线程每隔100ms就唤醒一次主线程。嗯,问题一下子就清楚了。
避坑指南:我曾经在分析一个长时间trace时,发现SQL查询特别慢。后来才意识到,一定要在查询条件里加上时间范围(ts)的过滤,否则全表扫描会让你等到怀疑人生。
与Systrace的差异:Perfetto到底强在哪?
很多从Systrace转过来的同学,一开始会不太适应Perfetto。但只要你用上一个月,就再也不想回去了。我整理了一个对比表格,一目了然:
| 对比维度 | Systrace | Perfetto |
|---|---|---|
| 数据格式 | HTML(自带UI) | Protobuf(可被多种工具解析) |
| 数据源扩展 | 固定,难以自定义 | 插件化,可自由添加producer |
| 分析能力 | 仅支持可视化拖拽 | 支持SQL查询 + 可视化 |
| 性能开销 | 较高,长时间trace容易丢帧 | 极低,支持长时间后台采集 |
| 跨平台支持 | 仅Android | Android + Linux + ChromeOS |
| 文件大小 | 大(HTML冗余) | 小(二进制压缩) |
你想想看,Systrace的HTML文件里包含了大量的UI渲染代码,而Perfetto只存原始数据。同样一个10秒的trace,Systrace可能生成50MB,Perfetto只有5MB。这就是差距。
另外,Perfetto的Web UI(ui.perfetto.dev)也做得非常棒。你可以直接在浏览器里打开trace文件,不需要安装任何东西。而且它支持SQL查询面板,边看可视化边写SQL,效率极高。
一句话总结:Systrace是“看”trace的工具,Perfetto是“分析”trace的平台。两者根本不是一个维度的产品。
小结
这一章我们聊了Perfetto的架构、trace配置、SQL分析,以及它和Systrace的差异。说白了,Perfetto就是Google为现代Android性能分析量身打造的全新工具链。它的SQL分析能力,让trace分析从“看图说话”进化到了“数据挖掘”的阶段。
下一章,我会带你深入Perfetto的SQL分析,手把手教你写一些实用的查询语句。到时候你会发现,原来trace分析可以这么爽。