Perfetto是Android平台从10版本开始主推的系统级追踪方案,它把内核调度、系统服务与应用自定义事件合并到同一个时间线上,适合排查跨进程卡顿、CPU争抢和Binder调用问题。与原先的Systrace相比,Perfetto在数据源数量、trace体积和查询能力上都有明显提升,手机系统里常驻的traced进程负责管理数据生产者,开发者只需要通过perfetto命令录制即可。

Perfetto的数据来源与缓冲机制
Perfetto的数据源可以粗略分成内核态和用户态两类。内核态主要依赖linux.ftrace,通过读取tracefs中的事件节点获取调度切换、中断、Binder驱动事务等记录。像sched/sched_switch、sched/sched_wakeup、binder/binder_transaction这些ftrace事件不需要修改内核,只要权限足够就能打开。用户态数据源则包括android.log、linux.process_stats、heapprofd等,其中atrace会自动把用户空间TAG映射到对应的ftrace类别或系统服务事件。例如gfx标签会打开SurfaceFlinger和Choreographer相关trace点,view标签会记录View绘制与输入事件。
缓冲机制方面,Perfetto采用生产者和traced服务之间的共享内存缓冲,避免每次事件都陷入系统调用。缓冲区大小可以通过-b参数或配置文件的buffers.size_kb指定。fill_policy有两种常见模式,DISCARD会丢弃最旧数据以容纳新事件,适合长时间固定容量录制;RING_BUFFER则在缓冲区满后停止写入,更适合短时间但必须保留完整事件的场景。这个设计让Perfetto在录制全系统事件时对被分析应用的干扰明显小于早期工具。
与Systrace的直接差异在于数据模型。Systrace主要输出经过汇总的HTML视图,很多原始事件被折叠,Perfetto则保存protobuf编码的完整事件流,并能通过SQL直接查询。像是某个线程在哪几个CPU核上运行、被谁唤醒、在哪个Binder事务上阻塞,这些信息都能从原始表里取出来。
录制系统级Trace的实用方法
最简单的录制方式是执行一条adb shell命令。下面这条命令会录制15秒,缓冲32MB,并同时打开调度、CPU频率、系统服务、图形、Binder驱动和内存等数据源。数据源名称之间用空格分隔,结束后trace文件保存在设备的/data/misc/perfetto-traces目录。
adb shell perfetto -o /data/misc/perfetto-traces/trace.pftrace -t 15s -b 32mb sched freq idle am wm gfx view binder_driver hal dalvik camera input res memory
其中sched和freq负责CPU调度及频率信息,am、wm对应ActivityManager和WindowManager,gfx与view覆盖图形渲染和View层,binder_driver用于追踪跨进程调用。实际排查掉帧问题时,sched、gfx、view、binder_driver通常要一起打开,否则时间线上会缺少关键上下文。
如果希望更精确控制ftrace事件和缓冲区策略,可以写一个文本配置文件。下面配置文件打开调度切换、唤醒和Binder事务事件,同时扫描全部进程信息,录制时长10秒。把配置保存为config.txt后推送到设备,再通过-c参数读取即可。
buffers {
size_kb: 32768
fill_policy: DISCARD
}
data_sources {
config {
name: "linux.ftrace"
ftrace_config {
ftrace_events: "sched/sched_switch"
ftrace_events: "sched/sched_wakeup"
ftrace_events: "binder/binder_transaction"
}
}
}
data_sources {
config {
name: "linux.process_stats"
target_buffer: 1
process_stats_config {
scan_all_processes_on_start: true
}
}
}
duration_ms: 10000
把config.txt推送到/data/local/tmp后执行adb shell perfetto -c /data/local/tmp/config.txt -o /data/misc/perfetto-traces/trace.pftrace。如果使用Windows终端且adb不在PATH中,可以写成C:\Android\platform-tools\adb.exe shell perfetto,这里盘符后的反斜杠必须保留。录制完成后用adb pull /data/misc/perfetto-traces/trace.pftrace .拉到本地。
在Perfetto UI中通过SQL定位耗时线程
拿到trace.pftrace后,在浏览器中打开Perfetto UI并加载文件。时间线视图适合观察整体阶段,但精确到某个线程在哪段时间做了什么,还是要靠SQL查询。Perfetto UI提供查询编辑器,底层数据表按事件类型划分,其中sched表每一行是一次CPU调度切片,thread表存储线程名与所属进程,process表存储进程信息。
下面这条SQL查询所有运行时长超过10ms的调度切片,并按耗时降序排列。dur字段单位是纳秒,除以1000000得到毫秒。通过这条查询能快速看出哪些线程长时间占用CPU。
SELECT thread.name AS thread_name, process.name AS process_name, sched.dur / 1000000 AS dur_ms, sched.ts / 1000000 AS start_ms FROM sched JOIN thread USING (utid) JOIN process USING (upid) WHERE sched.dur > 10000000 ORDER BY sched.dur DESC LIMIT 20;
如果想统计某个应用主线程在整个trace期间实际占用CPU的总时长,可以使用聚合查询。下面的SQL按线程名汇总运行时间,适合对比主线程、渲染线程和后台线程的CPU消耗。
SELECT thread.name AS thread_name, SUM(sched.dur) / 1000000 AS total_ms FROM sched JOIN thread USING (utid) JOIN process USING (upid) WHERE process.name = 'com.ipipp.app' AND thread.name = 'main' GROUP BY thread.name;
除了Running状态,sched表也能反映线程处于Runnable也就是等待CPU的时间。如果某个线程总耗时不长但Runnable时间占比很高,说明CPU竞争激烈;如果线程长时间处于Sleeping但用户操作仍然卡顿,那就不能只看调度切片,需要继续分析Binder调用和锁等待。
锁竞争与Binder阻塞的实战排查
跨进程通信在Android中非常常见,主线程经常会因为等待Binder返回而进入阻塞状态。这类耗时不体现在CPU运行时长上,但在用户看来就是点击无响应或列表滑动掉帧。Perfetto抓取binder_driver数据源后,Binder事务会以slice形式出现在线程轨道上。下面SQL按名字过滤包含binder的切片,列出耗时最长的Binder调用及其所在线程。
SELECT slice.name AS slice_name, slice.dur / 1000000 AS dur_ms, thread.name AS thread_name FROM slice JOIN thread_track ON slice.track_id = thread_track.id JOIN thread USING (utid) WHERE slice.name LIKE '%binder%' ORDER BY slice.dur DESC LIMIT 20;
如果查询结果显示主线程卡在某个Binder事务上,可以进一步根据slice的ts时间点回到时间线视图,查看同一时间段服务端进程在做什么。如果服务端也在等锁或等磁盘IO,就会发现阻塞链条。Binder阻塞的典型表现是主线程长时间处于Sleeping,且相邻的Binder事务切片明显超过预期。
Java层的锁竞争也可以定位。部分Android版本会把monitor contention以slice形式记录在trace中,名字通常包含Lock contention或monitor。用上面类似的SQL过滤slice.name即可。锁竞争高发时,主线程可能并没有执行太多代码,但时间被拆成了大量小片段,每个片段对应一次竞争后的调度延迟。
综合来看,Perfetto系统级追踪的价值在于把CPU调度、图形生产、Binder调用和用户自定义trace放在同一条时间线上,能够回答为什么掉帧、谁在等待谁的问题。分析时不要只盯住主线程自己的Running时间,还要结合Runnable、Sleeping以及Binder事务的持续时间,才能还原真实的阻塞路径。
PerfettoAndroid性能追踪系统级追踪修改时间:2026-09-29 04:52:15