本篇是 Perfetto 系列文章的第三篇,前两篇介绍了 Perfetto 是什么以及 Perfetto Trace 怎么抓,本篇主要是在网页端打开 Perfetto Trace 之后,面对复杂的 Perfetto 信息该怎么看。
Android 官方将 Systrace 列为 legacy 工具,并推荐在 Android 10 及以上使用 Perfetto。写下本文时,Perfetto 在我的日常工作中已基本取代 Systrace,我接触到的 OPPO、vivo 团队也在迁移,因此用这个系列继续介绍如何观察 Android 系统。
技术核查:2026-10-14。 保留 2024 年界面与案例截图,快捷键和分析语义按官方文档及 v58.3(
11fbaed83636)源码补充。原始案例 Trace 未随文提供,图中的唤醒链和数值不当作新版本实测结果。
本文目录
Paul Graham 说:要么给大部分人提供有点想要的东西,要么给小部分人提供非常想要的东西。Perfetto 属于小部分人非常想要的东西,那就开始写吧,欢迎大家多多交流和沟通,发现错误和描述不准确的地方请及时告知我,我会及时修改,以免误人子弟。
我想借这个系列,和大家一起对照 Perfetto 看 App、Framework、Linux 是怎么配合起来运行的。如果读过不少源码和性能文章,还是记不住流程,不妨把代码放回 Trace 的时间线上看看。
Perfetto 系列目录
- Android Perfetto 系列目录
- Android Perfetto 系列 1:Perfetto 工具简介
- Android Perfetto 系列 2:Perfetto Trace 抓取
- Android Perfetto 系列 3:熟悉 Perfetto View
- Android Perfetto 系列 4:使用命令行在本地打开超大 Trace
- Android Perfetto 系列 5:Android App 基于 Choreographer 的渲染流程
- Android Perfetto 系列 6:为什么是 120Hz?高刷新率的优势与挑战
- Android Perfetto 系列 7:MainThread 和 RenderThread 解读
- Android Perfetto 系列 8:深入理解 Vsync 机制与性能分析
- Android Perfetto 系列 9:CPU 信息解读
- Android Perfetto 系列 10:Binder 调度与锁竞争
- Android Perfetto 系列 11:PerfettoSQL、Trace Processor 与回归检测
- Android Perfetto 系列 12:Trace 数据流与丢失排查
- Android Perfetto 系列 13:Perfetto SDK、Track Event 与 App 现场 Trace
- Android Perfetto 系列 14:heapprofd 与内存 Profiling
- Android Perfetto 系列 15:Boot Trace、长时间现场 Trace 与偶发问题抓取
- Android Perfetto 系列 16:GPU、Power Counters 与硬件瓶颈分析
- Android Perfetto 系列 17:专项场景自动化、问题清单与平台体系
- Android Perfetto 系列 18:响应速度实战,从输入事件到首帧反馈
- 视频(B站) - Android Perfetto 基础和案例分享
- 视频(B站) - Android Perfetto 分享 - 出图类型分享:AOSP、WebView、Flutter + OEM 系统优化分享
如果大家还没看过 Systrace 系列,下面是传送门:
- Systrace 系列目录 : 系统介绍了 Perfetto 的前身 Systrace 的使用,并通过 Systrace 来学习和了解 Android 性能优化和 Android 系统运行的基本规则。
- 个人博客 :个人博客,主要是 Android 相关的内容,也放了一些生活和工作相关的内容。
欢迎大家在 关于我 页面了解微信群入口,讨论你的问题、你最想看到的关于 Perfetto 的部分,以及跟各位群友讨论所有 Android 开发相关的内容
Perfetto View 界面
抓到 Trace 后,可在 Perfetto UI 打开。官方 record_android_trace 脚本默认会拉取文件并打开浏览器;使用 --no-open 时则不会。下图是 2024 年首页,Legacy UI 等入口不能当作当前版本仍有的承诺。

可以点击 Open trace file,或把 Trace 拖进页面。大文件可能受浏览器内存限制,可用本地 Trace Processor 配合 UI。
Perfetto Trace 界面
打开 Perfetto Trace 之后界面如下:

按旧截图,界面大致分为四个区域;新版本可能调整菜单名称和位置:
- 最左边的操作区:这里最主要的是 Current Trace 这一栏下面的那几个会经常用到。
- Show timeline :显示当前 Trace,切到了别的界面之后,再点这个就会回到 Trace View 界面
- Query:写 SQL 查询语句和查看执行结果的地方
- Metrics:预先定义的分析入口,并非所有 Trace 都有完整指标;需要对应数据源和版本支持。
- Info and stats:检查 Trace 元信息、解析统计与数据丢失提示。先确认采集是否覆盖问题时段。
- 上方的信息和操作区域:最主要就是看时间。
- 中间的 Trace 内容区:展示调度、频率、线程埋点等轨道。是否出现 Input、Binder、Memory 或帧信息取决于采集内容。本文沿用旧图的 Task 叫法时,主要指线程的一段状态或执行区间;调度 Running 与函数 slice 不同,后者可能包含等待,不能把色块时长都算成 CPU 时间。
- 最下方的信息区:展示选中事件的详情、范围统计或查询结果。Android Logs 需要采集日志数据,应用打印过日志不等于 Trace 已包含它;Ftrace events 同样受采集配置限制。
Perfetto 界面最初看的时候会觉得很乱,花里胡哨的,但是用习惯了之后,真香~
基本操作
我在当时的环境中,打开约 500 MB Trace 的体验比 Systrace 顺滑。但加载和交互速度还受事件数量、类型、查询、浏览器及主机内存影响,500 MB 不是性能保证或文件大小上限。
常用操作仍是 W/S 缩放、A/D 左右平移、单击选择事件。新版可按 ? 查看当前快捷键,用 Ctrl+Shift+P(macOS 为 Cmd+Shift+P)打开命令面板。快捷键在时间轴获得焦点时使用,不要在 SQL 输入框里触发。下面三张是旧版帮助图,尤其 SQL 页入口和组合键应以当前提示为准,参见官方 UI 指南。



其他快捷键里面用的比较多的:
f 是放大选中
M:按当前选择创建临时区间注释。v58.3 使用同一个临时注释 ID,再按 M 会替换它;从单个事件创建时还会形成范围选择。Esc 清除选择,不应等同于删除注释。参见Notes 实现。

Shift+M:每次创建一个新的区间注释,不会像 M 那样替换上一个,适合同时标注多个区间。“持续”只指这种保留方式,不表示已经把注释写回原始 Trace 文件。

选择注释对应的范围后可查看统计。下图里的
SUM(dur)是 slice 时长汇总,父子 slice 可能重复覆盖时间;thread_dur为 null 也不等于 CPU 时间为 0。
删除持续 Mark
- 点击区间注释的边缘标记,选中注释。
- 旧版在下方 Current Selection 中操作。
- 点击 Remove;v58.3 也提供 Remove selected note 命令(默认 Delete)和 Notes & markers 管理入口。

q :隐藏和显示信息 Tab,由于 Perfetto 非常占屏幕,熟练使用 q 键很重要,看的时候快速打开,看完后快速关闭。
插旗子:Perfetto 还可以通过插旗子的方法来在 Trace 上做标记,Perfetto 支持你把鼠标放到 Trace 最上面,就会出现一个旗子,点击左键即可插一个旗子在上面,方便我们标记某个事件发生,或者某个时间点

- 取消插的旗子:与退出持续选中一样,点击旗子,右下角有个 Remove ,点击就可以把这个旗子干掉了,就不插图了
Perfetto 使用技巧
查看唤醒源
这里的“唤醒源”是线程从等待转为可运行时记录的 waker,不是设备从休眠唤醒的电源原因,也不直接说明锁持有者或完整业务依赖。需要有调度/唤醒事件;缺失记录、IRQ 上下文或 Trace 边界都可能使链路不完整。
在 Android Systrace 响应速度实战 3 :响应速度延伸知识 这篇文章中,有讲 Systrace 如何查看唤醒源。相比 Systrace,Perfetto 中查看唤醒源更直接:
下面分别示范主线程和 RenderThread 的唤醒查看方式,注意每张图里实际选中的线程名称。
点击 Runnable 状态
选中线程状态轨道的 Runnable 区间后,可在 Related thread states 查看关联。第一张图实际选中的是主线程 scrollingexample,waker 是 SurfaceFlinger 的 app 线程,不是 RenderThread。Runnable 也可能来自抢占,不能要求每一段都有一次新的外部唤醒。
- Waker:本次记录到的唤醒线程/状态;它是继续排查的线索。
- Previous state:这个 Task 的前一个状态
- Next state:这个 Task 的后一个状态

点击他上方的 Running 状态,查看连续唤醒信息
选中线程状态里的 Running 区间,可通过详情中的 CPU 链接跳到对应调度切片,再查看它前面的 Runnable 与唤醒事件。不要把紧邻或重叠的另一个线程直接当作 waker。
点击 RenderThread 上方的 Running 状态,通过小箭头跳转到 CPU Info 区域
这张旧图显示所选 RenderThread 区间对应一次主线程唤醒;它不代表 RenderThread 的每次唤醒都来自主线程。
这张旧图中,主线程的唤醒来源是 SurfaceFlinger 的 app 线程。下方 Scheduling latency 量的是从可运行到实际获得 CPU 的间隔,不是发送唤醒调用本身耗费的时间。
查看 Critical Path(Task)
这里的 Critical Path 是 Perfetto 根据线程状态与唤醒关系重建的阻塞路径,用来寻找所选线程等待期间的相关活动。它不是所有依赖任务的并集,也不是自动证明的业务根因;未埋点的异步关系、数据缺失和 IRQ 上下文都会影响解释。
v58.3 的插件实现中,Critical path lite 主要显示状态路径;完整 Critical path 再叠加相关 slice 信息,这些嵌套 slice 不是自动采集的函数调用栈。唤醒图实现也注明 Android 14 之前可能缺少 IRQ 上下文,从而影响准确性。
旧版可选中 Running 状态后在下方点击 Critical path。v58.3 仍有 selected thread state slice 命令,但源码使用该线程和整份 Trace 的时间边界;若只分析一个窗口,应框选线程状态轨道,再用 over area selection 版本。
稍等片刻就会出现我们选择的 MainThread 对应的 Critical path:

这张旧图中,主线程等待结束前关联到了 SurfaceFlinger 的 app 线程。图上的 CPU 编号属于这个实例,不是固定调度规则。
还可以向前检查 app 线程自己的 waker;原文提到的 TimerDispatch 关系没有展示对应截图,需要回到原始 Trace 核实,不能推广成所有帧都经过的固定链路。
这个视图把相关状态和埋点放在一起,便于继续检查等待原因;它本身不能证明优化某个线程就一定缩短端到端耗时。
Pin (固定到最上面)
点击轨道标题旁的 Pin 图标,可把关心的轨道固定到顶部。新版还可用工作区组织轨道,避免全部固定后挤占可视空间。

比如下面是我 Pin 的从 App 到 SF 的流程图,放到一起的话就会清晰很多,看掉帧的话也会更方便。
CPU Info 区域 Task 高亮
在 CPU Info 区域,鼠标放到某一个 Task 上,就会这个 Task 对应的 Thread 的其他 Task 都会高亮。
我们经常用这个方法初步看线程在哪些 CPU 上运行。它显示的是调度结果,不能单凭高亮或颜色判断迁移原因、核容量或完整调度策略。

查看 Buffer 消耗情况
对于提交给 SurfaceFlinger 合成显示的图层,选择 App 的 Actual Timeline 切片可沿 flow 查对应显示帧。同进程多 Layer 时核对 Layer 名与 frame token;一条 flow 不是 BufferQueue 深度,也不证明某个 buffer 被完整复制了一次。FrameTimeline 数据需要 Android 12+ 并已启用采集。

快速查看 App 执行超时
本节的“超时”指帧未按预期预算完成,不是 ANR。多缓冲可以让已有帧继续呈现,但不能据此排除新内容延迟或卡顿。
Expected Timeline 是预算,Actual Timeline 是实际帧处理区间,包含等待与 GPU 工作。结合 Present Type、On time finish、Prediction Type 与 Jank Type 判断,不要把每个长色块都当 CPU 超时。
红色帧可帮助定位问题,但颜色不是完整原因。下图显示 App Deadline Missed、Late Present 与 Valid Prediction;仍需结合主线程、RenderThread 和 GPU 相关数据解释,不能只凭分类断定某个函数有错。参见FrameTimeline 文档。

在 Perfetto 上查看 Log
采集了 android.log 数据后,可以在 Android Logs 中对齐日志时间与线程活动。旧图的悬停竖线只是时间定位,不证明日志对应的调用造成了该处阻塞。

Ftrace events 可以查看已保留的原始事件;缺少条目可能来自未启用、设备不支持或丢失,不能直接理解为事件从未发生。

分析 Thread 的 Running 信息
拖动框选时间窗口,并选中目标线程的状态轨道,可查看各状态的时长分布。只选 slice 轨道得到的是埋点统计,不能代替调度状态。单线程 Running 占比也不等于整机 CPU 利用率。分析 App 启动时,经常会用到这项统计。
做精确统计时应把每条状态区间裁剪到所选窗口,再按有效覆盖时长或窗口时长计算,并写明分母;未知/缺失不能补为 Sleep 或 0。下方旧截图的 Wall duration 合计约 865.44 ms,而 Selected range 为 857.5 ms,不能直接把表内数值当作该窗口的精确占比。

从 UI 操作过渡到 SQL 自动化
本文介绍的是 Perfetto UI 的手工分析路径:看线程、看唤醒源、Pin 关键线程、框选区间、检查 FrameTimeline 和日志。这个阶段适合建立直觉,但不适合批量复盘。
当你已经能在 UI 里稳定找到问题点后,下一步应该把“我刚才看了什么”翻译成 SQL:
- 先确认所选事件的数据表和 SQL ID。
slice存放埋点区间,track、thread_track、process_track描述轨道及归属,不是四种可互换的 Slice 表。 - 调度状态查
thread_state,CPU 上的运行区间查sched/sched_slice;按同一时间窗口裁剪,区分墙钟时间、CPU 时间与未覆盖部分。 - 帧分析优先使用 FrameTimeline 表或标准库模块,核对 frame token、Layer、预测有效性和丢帧状态,不只数红块。
track_id、utid、upid用来关联轨道、线程与进程;它们本身不证明跨进程因果。Binder、Buffer、Camera 或 Audio 链路还需各自的事务、flow、帧 token 等关联证据。
这套从 UI 操作到 SQL 的过渡,第 11 篇有完整展开:Android Perfetto 系列 11:PerfettoSQL、Trace Processor 与回归检测。
总结
上面分享了 Perfetto 基本的界面和操作,以及分享了一些比较常用的 Perfetto 的技巧。Google 目前在积极推广和维护 Perfetto,很多新功能指不定哪天就蹦出来了,到时候觉得有用我也会更新上来。
至此 Perfetto 基础篇就结束了,后续就是通过 Perfetto 这个工具,来了解 Android 系统运行的基本流程,以及使用 Perfetto 以及 Perfetto SQL 来分析遇到的性能、功耗等问题。
关于我 && 博客
下面是个人的介绍和相关的链接,期望与同行的各位多多交流,三人行,则必有我师!
- 博主个人介绍 :里面有个人的微信和微信群链接。
- 本博客内容导航 :个人博客内容的一个导航。
- 个人整理和搜集的优秀博客文章 - Android 性能优化必知必会 :欢迎大家自荐和推荐 (微信私聊即可)
- Android性能优化知识星球 :2026 年已关闭,保留历史介绍。
一个人可以走的更快 , 一群人可以走的更远
