1. 项目概述:为什么我们需要systrace与perfetto?
在Android应用和系统性能优化的战场上,性能问题往往像幽灵一样难以捉摸。应用启动慢了一拍,列表滑动偶尔掉帧,或者后台服务莫名耗电,这些现象背后是CPU调度、图形渲染、锁竞争、IO阻塞等一系列复杂系统行为的综合结果。作为一名开发者,如果只盯着自己应用的代码,无异于盲人摸象。你需要一双能透视整个Android系统运行状态的“眼睛”,这就是systrace和它的继任者perfetto。
简单来说,systrace和perfetto是Android平台最核心的系统级性能剖析工具。它们不是用来分析某个函数耗时的Profiler,而是记录系统在特定时间段内发生的所有关键事件,并将这些事件以时间线的形式可视化出来。你可以看到每个CPU核心上正在运行哪个线程、线程在等待什么锁、SurfaceFlinger何时进行合成、Binder调用了多久、甚至电量管理模块何时进入了休眠状态。通过这张宏观的“交响乐谱”,你能精准定位出是哪个“乐手”(进程/线程)在哪个“小节”(时间点)出了问题,导致整场“演出”(用户体验)卡顿。
atrace是systrace数据采集的命令行前端,而perfetto则是Google推出的新一代、功能更强大的全平台跟踪解决方案,正在逐步取代传统的systrace。掌握它们,意味着你拿到了从系统层面根治性能顽疾的“手术刀”。无论是应用开发、系统框架开发,还是驱动调试,这都是不可或缺的硬核技能。
2. 工具选型解析:atrace(systrace) 与 perfetto 的定位与抉择
在开始动手之前,我们必须理清atrace(代表systrace)和perfetto的关系与区别,这决定了你后续工作流的选择。很多人会混淆,这里彻底讲明白。
2.1 atrace 与 systrace 的关系
首先明确一个概念:我们常说的“抓取systrace”,这个动作通常是通过atrace命令来完成的。atrace是Android系统中的一个命令行工具,它的作用是启用和配置内核及系统服务的跟踪点(tracepoints),并将跟踪数据写入缓冲区。
而systrace.py是一个Python脚本(位于Android SDK的platform-tools/systrace目录下),它实际上是一个封装好的自动化脚本。它的工作流程是:
- 通过ADB连接设备。
- 在设备上执行
atrace命令,并指定要抓取的类别(如gfx,view,sched)。 - 将
atrace输出的原始数据流抓取到本地。 - 调用
python的trace2html模块,将原始数据转换为可视化的HTML网页。
所以,atrace是底层的数据采集器,systrace是包含采集、转换、可视化的一整套前端工具链。我们说的“使用systrace”,默认指的就是使用systrace.py这个脚本。
2.2 perfetto 的革新与优势
Perfetto是Google在Android 10(API 29)中正式引入,并逐渐成为Android 11+推荐使用的下一代系统跟踪框架。它并非systrace的简单升级,而是一个全新的、更强大的体系。
核心优势对比:
| 特性维度 | atrace (systrace) | perfetto |
|---|---|---|
| 架构 | 基于Linux内核的ftrace,上层通过atrace封装。 | 全新的、高性能的用户态和内核态跟踪守护进程(traced),支持更多数据源。 |
| 数据源 | 主要依赖内核ftrace,扩展性有限。 | 原生支持ftrace,并集成heap profiling(内存堆分析)、native memory dumps、Android Logcat、电源管理事件等,是真正的“一站式”平台。 |
| 配置方式 | 命令行参数,相对简单但功能有限。 | 强大的TraceConfig协议缓冲区(protobuf)配置,可以极其精细地控制跟踪时长、缓冲区大小、数据源开关、触发条件等。 |
| 跟踪时长 | 通常用于短时间(如5-10秒)的跟踪。 | 支持超长时间跟踪(数小时甚至数天),数据会滚动写入磁盘,用于分析间歇性、难以复现的问题。 |
| 可视化 | 生成独立的HTML文件,在Chrome浏览器中打开(chrome://tracing)。 | 使用更现代的Perfetto UI(在线网址ui.perfetto.dev或本地部署),界面更友好,分析功能更强大(如SQL查询跟踪数据)。 |
| 开销 | 相对较低。 | 设计目标就是高性能、低开销,即使长时间开启,对系统影响也极小。 |
> 注意:从Android 12开始,systrace脚本底层实际上已经调用perfetto来捕获ftrace数据了。但为了兼容性和操作习惯,systrace.py这个入口依然保留。
如何选择?
- 新手入门、快速抓取:从
systrace.py开始,语法简单,上手快,能满足大部分UI性能分析(如卡顿、掉帧)的需求。 - 深度分析、复杂场景:必须使用perfetto。例如需要分析内存增长、跟踪native代码、进行长时间功耗记录、或者需要复杂的触发条件时。
- Android 11+ 设备:强烈建议直接学习并使用perfetto,这是未来的方向。
3. 环境准备与基础配置
工欲善其事,必先利其器。无论使用哪种工具,都需要准备好基础环境。
3.1 开发机环境准备
- 安装Python:systrace.py是一个Python 2.7/3.x脚本,确保你的开发机(Windows/Mac/Linux)已安装Python,并已添加到环境变量PATH中。
- 安装Android SDK Platform-Tools:这是必须的,因为它包含了ADB(Android Debug Bridge)和systrace脚本。如果你使用Android Studio,它通常已自动安装。你也可以从 Android开发者官网 单独下载。 将
platform-tools目录的路径添加到系统的PATH环境变量中,以便在终端中直接使用adb和systrace.py命令。 - 安装Chrome浏览器:用于可视化systrace生成的HTML文件(
chrome://tracing)。Perfetto UI也推荐使用Chrome打开。
3.2 设备端配置
跟踪功能需要设备端的支持,并且通常需要开启开发者选项和USB调试。
- 启用开发者选项:在设备的“设置”->“关于手机”中,连续点击“版本号”7次。
- 开启USB调试:进入“设置”->“系统”->“开发者选项”,找到“USB调试”并开启。
- 可选的设备端设置(针对非Root设备):
- 对于systrace:在“开发者选项”中,找到“监控”或“调试”类别,确保“启用跟踪”或类似的选项是开启的。有些厂商设备可能需要额外开启“GPU渲染模式分析”等。
- 对于perfetto:Perfetto服务(
traced)在Android 9+上默认运行。为了允许非Root的ADB连接进行跟踪,你需要开启一个额外的开关:
执行后重启设备。这个设置允许通过ADB使用perfetto。adb shell setprop persist.traced.enable 1
> 重要提示:在生产环境或用户设备上抓取trace,尤其是长时间抓取,可能会涉及隐私和性能问题。务必在测试设备上进行,并告知相关方。
3.3 连接与验证
使用USB线连接设备和开发机,在终端执行:
adb devices如果看到设备序列号后面显示device,则表示连接成功。这是所有后续操作的基础。
4. 使用 atrace 和 systrace.py 进行跟踪
这是最经典、最常用的快速抓取方式,特别适合分析动画、列表滑动、应用启动等场景的卡顿。
4.1 systrace.py 命令行实战
systrace.py命令的基本语法如下:
python systrace.py [options] [categories...]它位于android-sdk/platform-tools/systrace/目录下。为了方便,我们可以进入该目录执行,或将此目录加入PATH。
一个最常用的抓取UI性能trace的命令示例:
cd /path/to/android-sdk/platform-tools/systrace python systrace.py -t 5 -o my_trace.html gfx view sched freq idle am wm让我们拆解这个命令:
-t 5:指定跟踪时间为5秒。你需要在命令执行后,立即在设备上操作你想分析的应用(例如快速滑动列表)。5秒后,trace会自动停止并生成文件。-o my_trace.html:指定输出文件名为my_trace.html。gfx view sched freq idle am wm:这是跟踪类别(categories),决定了采集哪些系统事件。这是命令的核心。gfx:图形相关事件,包括SurfaceFlinger、VSYNC、应用UI线程的绘制等。分析卡顿必选。view:View系统事件,如measure、layout、draw。sched:CPU调度信息。必选,可以看到每个线程在哪个CPU核心上运行、何时被切换出去。freq:CPU频率变化。idle:CPU空闲状态。am:Activity Manager事件,如Activity启动、生命周期。wm:Window Manager事件。
执行流程:
- 在终端输入上述命令并回车。
- 终端会显示
Starting tracing (5 seconds),并开始倒计时。 - 立即切换到你的测试设备,开始执行你想要分析的操作(例如,从桌面点击应用图标启动,或者在一个列表页面疯狂滑动)。
- 倒计时结束,终端显示
Tracing completed. Collecting output...,最后是Output written to: my_trace.html。 - 用Chrome浏览器打开
my_trace.html文件。
4.2 关键类别(Categories)详解
选择正确的类别组合至关重要。抓取过多类别会导致文件巨大、加载缓慢;抓取过少可能会遗漏关键信息。
核心必备类别:
sched:CPU调度。没有它,你无法分析线程是否因为锁或IO而阻塞,也无法看到CPU利用率。这是分析任何性能问题的基石。gfx:图形系统。包含VSYNC信号、SurfaceFlinger合成、应用渲染线程等。分析掉帧、卡顿的利器。view:Android View系统。可以看到performTraversals(即measure/layout/draw)的执行情况。
常用扩展类别:
am/wm:分析应用启动速度、页面跳转时非常有用。input:跟踪触摸、按键等输入事件的处理流程。freq/idle:分析功耗和热问题时,看CPU是否降频或进入深度休眠。binder_driver:查看Binder IPC调用,分析跨进程通信延迟。disk/mmc:分析IO读写性能问题。
查看所有可用类别:
python systrace.py -l这个命令会列出当前连接设备支持的所有跟踪类别。不同设备、不同系统版本支持的类别可能不同。
4.3 atrace 命令直接使用
systrace.py底层调用了atrace。你也可以直接使用adb shell atrace命令,这在一些自动化脚本或需要更精细控制时有用。
基本用法:
adb shell atrace -t 5 -c -o /data/local/tmp/trace_output gfx view sched-c:在跟踪结束后清空(清除)缓冲区。-o:指定设备上的输出文件路径。
抓取完成后,你需要将文件拉取到本地,并使用systrace.py或perfettoUI进行转换和查看。
adb pull /data/local/tmp/trace_output . python systrace.py --from-file=trace_output -o my_trace.html> 实操心得:直接使用atrace命令的一个好处是,你可以编写脚本,在应用执行特定操作时(通过am命令启动Activity等)自动开始和结束跟踪,实现自动化性能测试。
5. 使用 perfetto 进行高级跟踪
Perfetto提供了两种主要的使用方式:通过命令行工具(perfetto)和通过Web UI(ui.perfetto.dev)进行配置和抓取。这里我们重点介绍更强大、更推荐的后一种方式。
5.1 通过 Perfetto Web UI 抓取 Trace
这是最简单直观的方式,无需记忆复杂命令。
- 打开Web UI:在Chrome中访问 https://ui.perfetto.dev 。
- 录制新Trace:点击左侧边栏的**“Record new trace”**。
- 连接设备:在“Recording settings”页面,确保你的设备通过USB连接,并在“Android devices”下拉框中被识别。如果未发现,检查
adb devices和persist.traced.enable属性。 - 配置Trace参数:
- Recording mode:选择“Stop when full”或“Long trace”。前者适用于短时间抓取(类似systrace),后者用于长时间记录(数据会滚动保存到文件)。
- Max duration/Buffer size:设置最大时长和内存缓冲区大小。对于短时间分析,5-10秒,缓冲区256MB通常足够。
- Probes (数据源):这是核心配置区。你可以按需勾选:
atrace:勾选这个,并在下方展开“Android apps & svcs”,选择你需要atrace类别(如gfx,view,sched),这相当于systrace的功能。ftrace:更底层的Linux内核跟踪,可以勾选sched/sched_switch(线程切换)等事件。Java heap graphs:抓取Java堆内存分配信息,用于内存分析。Memory snapshots:捕获native内存快照。Power:电源管理相关事件。Logcat:同时抓取系统日志,便于交叉分析。
- 开始录制:点击右上角的“Start recording”按钮。
- 操作设备:像使用systrace一样,立即在设备上进行你想要分析的操作。
- 停止并下载:操作完成后,回到Web UI点击“Stop”。Perfetto会自动处理数据并下载一个
.perfetto-trace或.pftrace文件。 - 分析:下载完成后,该文件会自动在同一个Web UI中打开,你可以开始进行分析。
5.2 使用 perfetto 命令行工具
对于自动化集成或在无图形界面的环境中,命令行工具是必须的。你需要获取perfetto可执行文件,它通常包含在Android SDK的platform-tools目录下,或者可以从 Perfetto GitHub 源码编译。
步骤:
准备配置文件:Perfetto的强大之处在于其基于protobuf的配置文件(
trace_config.pb或文本格式的trace_config.textproto)。你可以从Web UI导出配置,或手动编写。 一个简单的文本格式配置文件示例 (config.textproto):duration_ms: 5000 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: "irq/irq_handler_entry" } } } data_sources: { config { name: "android.systrace" systrace_config { trace_categories: "gfx" trace_categories: "view" trace_categories: "sched" } } }这个配置抓取5秒的trace,包含ftrace的调度事件和atrace的gfx/view/sched事件。
执行抓取命令:
adb push config.textproto /data/local/tmp/ adb shell perfetto -c /data/local/tmp/config.textproto -o /data/local/tmp/trace.pftrace或者,更简单的一行命令(通过
--txt指定文本配置):adb shell 'echo -e "duration_ms: 5000\nbuffers { size_kb: 32768 }\ndata_sources { config { name: \"android.systrace\" systrace_config { trace_categories: \"gfx view sched\" } } }" | perfetto -c - --txt -o /data/local/tmp/trace.pftrace'拉取Trace文件:
adb pull /data/local/tmp/trace.pftrace .用Perfetto UI打开这个
.pftrace文件进行分析。
> 注意事项:命令行方式需要你对protobuf配置有一定了解。建议先从Web UI配置并导出配置文件,然后基于导出的文件进行修改,这样学习成本最低。
6. Trace文件分析与解读实战
抓取到trace文件(.html或.pftrace)只是第一步,更重要的是从中读出问题。这里以Perfetto UI为主进行讲解,其功能远超旧的Chrome Tracing。
6.1 Perfetto UI 核心界面与操作
打开trace文件后,你会看到如下主要区域:
- 时间线概览区(Overview):顶部,显示整个trace的时间范围,可以缩放和拖拽。
- 轨道区(Tracks):主体部分,每个水平行是一个“轨道”,展示一个实体(如CPU、进程、线程、计数器)随时间的变化。
- CPU轨道:显示每个CPU核心的使用情况,不同颜色代表不同的进程/线程。
- 进程/线程轨道:显示每个线程的状态(运行
Running、可运行Runnable、休眠Sleeping、不可中断休眠Uninterruptible Sleep等)。这是分析卡顿最关键的区域。 - 计数器轨道:如CPU频率、内存用量、帧率(SurfaceFlinger)等。
- 事件轨道:显示特定事件,如VSYNC、Binder事务等。
- 工具栏:提供选择(
S)、移动(M)、时间选择(T)、测量(I)等工具。 - 查询框(Query (SQL)):Perfetto最强大的功能之一,允许你用SQL查询trace数据。例如,查询所有耗时超过5ms的Binder事务。
基本操作技巧:
- 缩放:鼠标滚轮,或使用
W(放大)、S(缩小)键。 - 移动:按住
Shift+鼠标拖拽,或使用A(左移)、D(右移)键。 - 选择与测量:按
I键进入测量模式,在时间线上拖动可以测量两点间的时间差。 - 查看详情:点击任何一段色块或事件,下方会弹出详情面板(
Current Selection),显示该事件的名称、耗时、参数等信息。
6.2 定位卡顿的通用分析流程
假设我们遇到了列表滑动卡顿的问题,分析流程如下:
- 定位卡顿时间点:在轨道区上方的时间线上,找到帧率计数器(FPS)突然下降或出现断层的区域,用
I键框选这个区域,放大查看。 - 观察UI线程状态:找到你的应用进程(如
com.example.myapp),展开它,找到主线程(通常是main或包名同名的线程)。在卡顿时间段内,观察主线程的状态条。- 如果主线程长时间是
Running(绿色):说明CPU正在密集执行你的代码。你需要点击该绿色块,查看详情面板中的“Stack Trace”(如果抓取时启用了应用层符号)。这能告诉你具体是哪个函数/方法耗时最长。 - 如果主线程长时间是
Runnable(蓝色)或Sleeping(灰色):说明它准备好了但没被CPU执行,或者在等待(如锁、IO)。这是典型的线程调度问题。
- 如果主线程长时间是
- 分析CPU调度:立刻去看对应时间点的CPU轨道。
- 如果所有CPU核心都处于繁忙状态(绿色块密集),且运行着其他进程的线程,说明系统整体负载高,你的应用线程抢不到CPU时间片。这可能是因为后台有大量任务。
- 如果CPU有闲置(空白),但你的主线程仍是蓝色(Runnable),这非常反常,可能遇到了优先级反转或CPU频率限制(thermal throttling)。此时可以查看
freq和idle轨道确认。
- 检查锁竞争:如果主线程状态显示为
Uninterruptible Sleep (D),这通常意味着它在等待IO。但如果是在等待锁,在sched和lock事件中会有体现。Perfetto的“Slices”轨道可能会显示MonitorWait等锁事件。 - 检查渲染流水线:展开
SurfaceFlinger进程和你的应用RenderThread。- 查看VSYNC信号(
vsync_*)是否规律。如果VSYNC间隔不稳定,可能是底层显示问题。 - 查看应用
RenderThread的DrawFrame切片。如果两个DrawFrame之间的间隔远大于16.6ms(60Hz),说明渲染一帧的时间过长。 - 查看
SurfaceFlinger的Composition切片。如果合成耗时过长,可能是图层太多或过于复杂。
- 查看VSYNC信号(
6.3 使用SQL查询进行深度挖掘
Perfetto UI内置了一个强大的SQL查询引擎。点击左侧边栏的“Query (SQL)”即可打开。
一些实用的查询示例:
查找耗时最长的Binder调用:
SELECT slice.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 USING (utid) WHERE slice.name LIKE ‘binder%‘ AND dur > 1e6 -- 查找耗时超过1ms的binder事务 ORDER BY dur DESC LIMIT 10;统计所有线程在Runnable状态的总时间:
SELECT thread.name, sum(dur) / 1e6 as total_runnable_ms FROM thread_state JOIN thread USING (utid) WHERE state = ‘R‘ -- ‘R‘ 代表 Runnable GROUP BY thread.name ORDER BY total_runnable_ms DESC;查找因锁等待导致的调度延迟:这需要抓取时启用了
sched和lock相关的事件。查询可能比较复杂,但思路是关联sched_wakeup事件和线程实际开始运行的时间差。
> 实操心得:对于复杂的性能问题,不要只盯着UI线程。一个后台网络线程持有了UI线程需要的锁,或者一个Bitmap解码任务在异步线程占满了CPU,都可能导致UI卡顿。学会在Perfetto中全局地、关联地看问题,是进阶的关键。
7. 常见问题与排查技巧实录
在实际使用中,你肯定会遇到各种问题。这里记录了一些典型场景和解决方法。
7.1 抓取失败或数据为空
- 现象:执行命令后,生成的HTML文件打开是空白或只有零星信息。
- 排查:
- 检查类别:首先用
python systrace.py -l确认你选择的类别在设备上是否支持。有些定制ROM可能移除了某些跟踪点。 - 检查权限:确保设备已开启USB调试,并且电脑已被授权。尝试
adb root(需要工程机或userdebug版本系统)后再抓取,权限最高。 - 检查atrace状态:在设备shell中执行
adb shell atrace --list_categories,看是否能列出类别。执行adb shell atrace -c -t 1 gfx看是否有输出。 - 尝试基础类别:先只用
sched和gfx这两个最核心、支持最广的类别抓取,看是否有数据。 - 对于perfetto:确保
persist.traced.enable已设置为1并重启。
- 检查类别:首先用
7.2 Trace文件巨大,浏览器卡死
- 现象:抓取时间长或类别过多,生成几百MB的HTML文件,Chrome无法加载。
- 解决:
- 控制抓取时长和类别:只抓取问题发生的核心时段(如3-5秒),只选择必要的类别。
- 使用Perfetto UI:Perfetto UI(
ui.perfetto.dev)对大型trace文件的处理能力远强于Chrome Tracing。将.html文件转换为.pftrace格式(Perfetto UI支持导入),或用Perfetto直接抓取。 - 使用命令行过滤:对于perfetto,可以在配置文件中使用
filter字段,或者在抓取后使用perfetto命令行工具进行过滤和裁剪。
7.3 看不到应用层函数调用栈(Stack Trace)
- 现象:在trace中点击线程的Running切片,详情面板中没有“Stack Trace”或显示为
[unknown]。 - 解决:
- 需要带符号的Debug包:要看到Java/Kotlin函数名,必须使用未混淆的Debug版本应用。Release包通常被ProGuard/R8混淆,函数名无意义。
- 对于systrace:在命令中添加
-a <package_name>选项。例如python systrace.py -t 5 -a com.example.myapp -o trace.html gfx view sched。这会将应用进程的跟踪标记关联起来。 - 对于Perfetto:在Web UI配置的“Android apps & svcs”下,勾选你的应用包名。或者在配置文件的
android.systrace数据源中设置target_pid或target_cmdline。 - Native符号:要看到C/C++的函数名,需要将设备的
/system/lib等库的符号表(或你的so文件的调试符号)加载到Perfetto UI中。这通常需要从编译设备的系统镜像中获取。
7.4 如何分析应用启动性能
应用启动是典型的性能分析场景。
- 抓取配置:抓取类别必须包含
am(Activity Manager)和wm(Window Manager)。命令示例:python systrace.py -t 10 -a com.example.myapp -o startup.html am wm gfx view sched. - 抓取时机:在命令开始倒计时后,立即点击应用图标。确保trace覆盖从点击到首页完全加载的完整过程。
- 分析关键路径:
- 在Perfetto UI中,搜索“
launching”或“startActivity”事件,找到你的应用启动的起点。 - 顺着时间线向右看,关注:
am轨道:ActivityThread的performLaunchActivity、handleResumeActivity等事件。- 你的应用进程和主线程:查看
main线程在Activity.onCreate、onStart、onResume期间做了什么。是否有长时间的Running(CPU计算)或Sleeping(等待IO/锁)? gfx轨道:查看第一帧的DrawFrame和SurfaceFlinger合成何时完成。从点击图标到第一帧显示在屏幕上的时间,就是用户感知的启动时间。
- 在Perfetto UI中,搜索“
7.5 自动化集成与进阶技巧
对于需要持续集成(CI)的性能测试,手动抓取是不现实的。
脚本化抓取(使用atrace):
# 开始抓取 adb shell “atrace -c -b 32768 -t 15 gfx view sched wm am -o /data/local/tmp/auto_trace &” # 执行自动化操作,例如启动应用 adb shell am start -W -n com.example.myapp/.MainActivity # 等待抓取结束(简单方法:sleep 比跟踪时间长一点) sleep 16 # 拉取文件并转换 adb pull /data/local/tmp/auto_trace . python systrace.py --from-file=auto_trace -o auto_trace.html脚本化抓取(使用perfetto):编写一个
trace_config.textproto文件,然后使用adb shell perfetto -c ...命令在自动化脚本中调用。这更加强大和稳定。使用Android Studio Profiler:对于应用开发,Android Studio内置的Profiler提供了更友好的systrace集成。你可以在CPU Profiler中直接点击“Record System Trace”按钮,它底层也是调用perfetto/systrace,但提供了与应用代码更好的关联。
掌握systrace和perfetto,就像是获得了Android系统的“时光机”和“显微镜”。它让你能从纷繁复杂的现象背后,直指性能问题的本质——是计算太慢,是等待太久,还是调度不公。最初的学习曲线可能有些陡峭,但一旦你成功用它定位并解决了一个棘手的线上卡顿问题,那种成就感会让你觉得所有投入都是值得的。从今天开始,不要再靠猜来优化性能,让数据说话。