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分析可以这么爽。