☰
Perfetto Android 10+ 抓 trace 与 SQL 分析实战
2026/10/1 16:07:22 网站建设 项目流程

从 Android 10 开始,设备内部多了一套叫 Perfetto 的性能追踪框架,那个曾经被大家敲了无数遍的systrace.py悄悄退到了幕后,而perfetto这个命令行工具成了抓系统级 trace 的主要入口。如果你还停留在"systrace 抓一切"的思路里,会发现在新设备上要么命令跑不通,要么抓出来的 trace 缺胳膊少腿——不是命令写错了,而是底层的数据采集服务换了实现。这篇内容就是围绕 Perfetto 命令行工具在 Android 10 及更高版本上的实际用法展开的,重点讲清楚它和旧工具的区别、三种工作模式怎么选、数据源和缓冲区怎么配、抓完之后怎么用 SQL 把 trace 里的问题挖出来。

它适合几类人:做 App 卡顿和启动耗时优化的同学、做系统层性能分析的工程师、以及需要给测试团队交付一套可复现抓取脚本的人。不需要你有 framework 源码的阅读经验,但至少得会用 adb,知道什么是线程、什么是调度。文中大部分操作我都在真机上跑过,踩过的坑会单独拎出来说,命令和配置可以直接抄。

1. 为什么 Android 10 之后抓 trace 要换成 Perfetto

1.1 systrace 的退场与 Perfetto 的上位逻辑

systrace 本质上是一个 Python 脚本加上一套 ftrace 的封装,它做的事情是:在设备上打开若干 ftrace 事件和 atrace 分类,把 kernel 和 framework 埋点写进 ftrace 的 ring buffer,最后把原始文本拉回主机,用 HTML 前端解析渲染。这个链路在 Android 9 及之前基本够用,但有两个绕不过去的硬伤。

第一个硬伤是数据源单一。systrace 只能吃 ftrace 这一路的输出,进程内存、CPU 频率电压、系统属性、logcat、native 堆采样这些信息它压根不采集。你排查一个卡顿,往往需要在 systrace、logcat、dumpsys 之间来回切,时间戳还对不齐。第二个硬伤是缓冲和传输机制老旧。ftrace 的 ring buffer 一旦写满就开始覆盖,systrace 又没有可靠的流式传输,长一点的追踪经常出现前后数据接不上的情况。

Perfetto 换了思路:设备端跑一个常驻的追踪服务traced,配合采集代理traced_probes,通过 protobuf 定义的数据源(data source)来统一收数据。ftrace 只是众多数据源里的一个,进程统计、系统统计、日志、堆采样都能挂进来,所有数据走同一套时钟、同一份 trace 文件。命令行工具perfetto就是这套体系对外的客户端,负责下发配置、接收数据、落地文件。理解这一点很关键:Perfetto 不是 systrace 的升级版,而是一个采集框架,systrace 只是它的一个使用场景。

1.2 三种工作模式,别一上来就写配置文件

perfetto命令有三种调用方式,复杂度递增,很多人一上来就去啃 protobuf 配置,结果被劝退。实际按需选就行。

第一种是轻量模式,也叫命令行开关模式。所有参数直接写在命令行上,适合"我现在就要抓 15 秒的调度和图形事件"这类临时需求。它内部会自动帮你拼一份最小配置,你只需要给出 categories。

第二种是配置文件模式,用-c指定一份 protobuf 配置(文本或二进制),把缓冲区大小、数据源、采样周期、文件上限全部写死在文件里。适合团队协作、CI 里跑固定场景、或者需要同时采集多路数据源的复杂场景。

第三种是纯开关模式的遗留兼容写法,用来替代老的systrace参数,比如--categories、--app。现在新写脚本不建议再用了,因为它能表达的配置非常有限。

模式触发方式适合场景主要限制
轻量模式直接跟 categories临时抓取、快速定位数据源固定,细粒度参数调不了
配置文件模式-c file.pbtx+--txt团队脚本、多数据源、长时追踪需要理解 protobuf 字段含义
遗留开关模式--categories等迁移老的 systrace 脚本逐步废弃,能力受限

我的建议是:先用轻量模式抓三五次,摸清楚 categories 的粒度,再过渡到配置文件模式。顺序反过来会浪费很多时间。

2. 环境准备与最小可用链路

2.1 设备端要看的两件事

Android 10 及以上设备上,Perfetto 的服务和二进制是系统内置的,不需要你安装任何东西。但有两点必须先确认,否则后面所有命令都会失败。

第一,确认追踪服务在跑。执行adb shell getprop init.svc.traced,正常返回应该是running。如果返回空或者stopped,说明这台设备上追踪服务被关掉了,可能是定制 ROM 的裁剪,也可能是厂商出于功耗考虑关停。这种情况下getprop persist.traced.enable一般也是 0,普通用户没有权限改这个属性。

第二,确认perfetto二进制存在。执行adb shell which perfetto,正常路径是/system/bin/perfetto。Android 10 之前的设备上这个二进制要么不存在,要么是很早期的残缺版本。所以标题里强调"Android 10 及更高版本"不是随口一说,它是硬性门槛。

顺带解释一下设备端的几个角色。traced是调度中心,负责解析配置、分发任务、汇总数据;traced_probes是干活的,真正去读/sys/kernel/tracing、/proc这些地方;perfetto命令行本身则是一个"消费者",它连上traced,把配置递过去,再把流回来的数据写进文件。你敲完命令之后回车,实际上是命令行进程在等traced通知它"数据采完了"。链路里任何一环断了,现象都是命令挂住然后超时。

2.2 主机端的三个工具

主机这边需要准备的东西很少,但缺一个都会卡住。

adb是必须的,而且建议用较新的版本。原因是 trace 文件是二进制 protobuf,从设备往主机拉的时候必须用adb exec-out而不是adb shell,后者会对输出做换行符转换,二进制文件一旦被转换就直接报废。这个坑我在早期踩过,表现是 trace 文件大小正常但用 UI 打开报解析失败,查了半天才想起来是传输方式的问题。

第二个工具是Perfetto UI,用来可视化。浏览器打开后把 trace 文件拖进去就能看时间轴、线程轨道、CPU 频率曲线,还有一个 Query 面板可以直接跑 SQL。它完全在本地解析文件,trace 数据不会离开你的机器,这点对处理公司内部设备的 trace 比较友好。

第三个工具是trace_processor_shell,命令行版的 trace 解析器。如果你要批量处理 trace、或者想在服务器上跑自动化分析,这个比 UI 更合适。它的用法和 SQLite 命令行很像,支持交互式和非交互式两种模式,后面第五节会细讲。

2.3 三条命令跑通第一个 trace

先来一个最小可用的例子,把整条链路验证通过。第一步抓取:

adb shell perfetto \ -o /data/misc/perfetto-traces/trace.perfetto-trace \ -t 16s \ -b 32768 \ sched freq idle am wm gfx view binder_driver hal dalvik camera input res

逐项拆解一下。-o是输出路径,Android 上 shell 用户可写的目录主要就是/data/misc/perfetto-traces,别往/sdcard写,SELinux 上下文不对,会直接报权限错误。-t 16s是时长,支持s、m、h后缀,不写这个参数命令会一直跑下去,很多新手的第一反应是"命令卡死了",其实就是忘了加时长。-b 32768是每个 CPU 的缓冲区大小,单位 KB,这里给了 32MB。后面的sched freq idle am wm gfx view binder_driver hal dalvik camera input res就是 atrace 的 category 列表,轻量模式下直接跟选项后面,不需要任何前缀。

第二步,把文件拉回主机:

adb exec-out cat /data/misc/perfetto-traces/trace.perfetto-trace > trace.perfetto-trace

第三步,打开 Perfetto UI,把文件拖进去。如果时间轴上能看到各个 CPU 的调度块、SurfaceFlinger 的帧轨道、目标 App 的主线程,说明链路是通的。

提示:/data/misc/perfetto-traces目录里的文件不会自动清理,长时间反复抓取会占掉不少空间,建议养成本地分析完就adb shell rm的习惯。

3. 内置数据源与抓取参数怎么选

3.1 linux.ftrace:最常用也最容易配错的一路

linux.ftrace是使用频率最高的数据源,它负责两件事:订阅内核 ftrace 事件,以及订阅 framework 侧的 atrace 分类。

内核事件用ftrace_events字段指定,常见的有sched/sched_switch(线程切换)、sched/sched_wakeup(唤醒)、sched/sched_waking、power/cpu_frequency(CPU 频率变化)、power/cpu_idle(空闲状态进出)、irq/*(中断)、binder/*(binder 事务)。这些事件是分析 CPU 侧瓶颈的基础,尤其是sched_switch和cpu_frequency两个,几乎每份有价值的 trace 里都该有。

atrace 分类用atrace_categories指定,也就是轻量模式里直接跟在后面的那些名字。常用的几个含义是:gfx抓图形渲染管线,view抓 View 系统的 measure/layout/draw,wm抓窗口管理,am抓 Activity 生命周期,binder_driver抓 binder 驱动层事务,hal抓硬件抽象层调用,dalvik抓虚拟机相关,input抓输入事件分发,res抓资源加载。这些分类不是都开着就好,每开一个都会增加写入量,缓冲区消耗速度会明显变快。

atrace 还有一个容易忽略的参数:atrace_apps。默认情况下,只有系统进程和部分预装应用的 atrace 埋点会被采集,你自己的 App 的Trace.beginSection打点是不出现的。要抓到它,必须把包名加进atrace_apps列表,或者用atrace_apps: "*"抓所有已安装应用。后者在真机上有副作用,应用多了以后数据量会失控,我一般只填目标包名。

ftrace_config { ftrace_events: "sched/sched_switch" ftrace_events: "sched/sched_wakeup" ftrace_events: "power/cpu_frequency" atrace_categories: "gfx" atrace_categories: "view" atrace_categories: "binder_driver" atrace_apps: "com.example.myapp" buffer_size_kb: 16384 drain_period_ms: 250 }

3.2 另外几路值得开的数据源

只抓 ftrace 是过去 systrace 的思路,Perfetto 的价值恰恰在于可以同时挂好几路。下面这几个我在实际分析里几乎每次都会带上一两个。

linux.process_stats采集进程和线程的元数据,包括进程名、线程名、oom_score_adj。别小看它,没有这路数据源,你的 trace 里线程轨道只会显示一堆 PID 数字,根本认不出哪个是渲染线程。而且它开销极小,建议无脑开。

linux.sys_stats采集系统级统计,比如内存使用、CPU 频率统计、进程数。它对排查"内存抖动引发 GC 卡顿"这类问题特别有用。里面的meminfo_period_ms和vmstat_period_ms控制采样周期,默认 1000ms,想看得更细可以调到 250ms,代价是数据量上升。

android.log把 logcat 内容打进 trace,好处是日志和性能事件共用一套时间轴,你在时间轴上点一个卡顿区间,旁边就能看到同一时刻 App 打了什么日志,定位因果关系的效率提升很明显。配置里用log_ids指定要抓的日志缓冲区,一般是main、system、events。

track_event是 Perfetto SDK 的数据源,让应用进程通过 SDK 主动上报自定义事件。如果你的 App 接了 Perfetto SDK,这路数据源能把业务埋点和系统事件对齐,比单纯用Trace.beginSection灵活得多。

android.heapprofd是 native 堆采样,用来排查 native 内存泄漏。它对目标进程有要求,必须是可调试应用,且采样本身有性能开销,不要在生产环境常态化开启。

数据源采什么开销建议
linux.ftrace内核事件 + atrace中到高,取决于事件数按需开分类,别全开
linux.process_stats进程线程元数据低建议常开
linux.sys_stats内存、CPU 统计低到中排查内存问题时开
android.loglogcat中需要对齐日志时开
track_eventSDK 自定义事件低接了 SDK 就开
android.heapprofdnative 堆采样高只在专项排查时开

3.3 缓冲区到底该给多大

这是最常被问的问题,也是 trace 丢数据的主要原因。先讲原理:每个 CPU 有一个独立的 ring buffer,ftrace 往里面写,Perfetto 从里面读走并压缩。如果写入速度持续高于读取速度,ring buffer 写满之后就开始按fill_policy处理——RING_BUFFER是覆盖最老的数据,DISCARD是丢弃最新的数据。

覆盖和丢弃哪个更合适?我的经验是:排查偶发问题用 RING_BUFFER,抓完整启动流程用 DISCARD。偶发卡顿你不知道什么时候发生,保留最近的现场更实用;启动流程有明确的起止点,丢弃末尾数据至少能保证开头是完整的。

至于给多大,可以粗略估算。一台 8 核设备在中高负载下,全量订阅sched_switch加sched_wakeup加cpu_frequency,每秒写入量能到几 MB 级别。默认的 ring buffer 在部分设备上只有 4MB 左右,也就是一两秒就被填满。所以你只要看到 trace 开头正常、后面突然变稀疏,基本可以确定是缓冲区太小。

我的常用配置是:短时抓取(30 秒内)给-b 32768,也就是每 CPU 32MB;长时追踪(几分钟以上)给 64MB,同时把fill_policy设成RING_BUFFER,并且把不必要的事件去掉。还有一种做法是用--size限制整个 trace 文件的上限,比如--size 128mb,到量自动停止,防止长跑把设备存储写满。

注意:缓冲区不是越大越好。它占用的是内核内存,给得过大在低内存设备上可能触发分配失败,命令直接报错退出。64MB 是我在主流设备上验证过的安全上限。

4. 配置文件模式实战

4.1 一份可复用的文本配置逐行拆解

配置文件模式的核心是把所有参数写进一份文本 protobuf,用--txt -c指定。文本格式的好处是可读性高,能直接进 Git 做版本管理。下面这份是我做应用启动分析时用的模板。

buffers { size_kb: 65536 fill_policy: RING_BUFFER } data_sources { config { name: "linux.ftrace" ftrace_config { ftrace_events: "sched/sched_switch" ftrace_events: "sched/sched_wakeup" ftrace_events: "power/cpu_frequency" atrace_categories: "am" atrace_categories: "wm" atrace_categories: "gfx" atrace_categories: "view" atrace_categories: "binder_driver" atrace_apps: "com.example.myapp" } } } data_sources { config { name: "linux.process_stats" process_stats_config { scan_all_processes_on_start: true } } } data_sources { config { name: "android.log" android_log_config { log_ids: "main" log_ids: "system" } } } duration_ms: 20000

分段解释。buffers段定义缓冲区,这里只写了一个 64MB 的 ring buffer。如果想区分不同数据源用不同缓冲区,可以定义多个 buffers,然后在 data_sources 里用target_buffer索引引用,这是进阶玩法,多数据源混合时能避免日志把 ftrace 的空间挤掉。

每个data_sources段是一路数据源。config.name必须是系统已注册的数据源名,写错了不会报错,只是那一路静默不采集,这个坑很隐蔽,建议第一次配完先抓一小段,用 UI 确认每一路都有数据。

duration_ms是总时长,单位毫秒。它和命令行-t是等价的,如果两边都写了,以命令行为准。

下发这份配置有三种方式。最直接的是推送到设备再指定路径:

adb push trace_config.pbtx /data/misc/perfetto-configs/ adb shell perfetto --txt -c /data/misc/perfetto-configs/trace_config.pbtx \ -o /data/misc/perfetto-traces/startup.perfetto-trace

第二种是走标准输入,配置文件不用落地:

cat trace_config.pbtx | adb shell perfetto --txt -c - -o /data/misc/perfetto-traces/startup.perfetto-trace

第三种最省事,把输出直接怼到主机文件,连 pull 都省了:

adb exec-out perfetto --txt -c - -o - < trace_config.pbtx > startup.perfetto-trace

第三种写法我用了很久,但要注意-o -表示输出到标准输出,此时必须用adb exec-out,用adb shell会因为换行转换破坏二进制内容,这个坑重复出现率极高,值得单独记一笔。

4.2 分级抓取:让数据量回归可控

配置写顺手之后最大的诱惑就是"全都开",结果抓出来的文件几百兆,打开卡半天,真正有用的信息淹没在噪声里。解决思路是分级。

第一级是always-on层,包括linux.process_stats和少量 sched 事件,这些开销低、价值高,任何场景都可以带。第二级是场景相关层,比如排查滑动卡顿就加gfx、view、input,排查启动耗时就加am、wm、binder_driver。第三级是专项层,比如 heapprofd、linux.perf,只在明确怀疑某一类问题时才开,而且只开一小段。

atrace_apps 的控制也是分级的一部分。不要写"*",把目标包名明确列出来,这样其他应用的埋点不会来抢缓冲区。如果一次要分析多个应用,可以用多次atrace_apps字段逐个添加,而不是用通配符。

还有一个实战技巧:先用短时长、小 buffer 抓一次"探路 trace",看看数据源的产出速率,再决定正式抓取时的 buffer 大小。比如先抓 5 秒,看 ring buffer 是否被打满(UI 里能看到 buffer 的使用曲线),再按比例放大。比拍脑袋定 64MB 靠谱得多。

4.3 长时追踪与后台模式

抓偶发的卡顿,问题在于你不知道它什么时候出现,总不能盯着屏幕手动按。Perfetto 提供了两种应对方式。

一种是加长时长配合大 ring buffer,比如duration_ms: 300000(5 分钟)配 64MB ring buffer,让旧数据自动被覆盖,最后看到的是最近几分钟的现场。这种方式不需要额外权限,普通 shell 就能用。

另一种是 detached 模式,也就是-s(或--detach)加上一个 key:

adb shell perfetto -s mytrace -o /data/misc/perfetto-traces/long.perfetto-trace \ -t 5m -b 65536 sched freq gfx view

加了-s之后命令行会立刻返回,采集在设备后台继续。这个 key 就是这次会话的标识,后续可以用带同样 key 的命令去做状态查询。这个模式对脚本化特别友好,你可以在自动化测试开始前启动采样,测试结束时再来收文件。

需要提醒的是,长时间追踪必须关注存储空间和功耗。64MB 的 buffer 在持续高负载下可能被写满并被RING_BUFFER策略持续覆盖,最终文件大小取决于实际写回的数据量,但设备侧的内存占用是实打实的。我的习惯是控制在 5 分钟以内,超过这个时长的分析需求,改用分段抓取、事后拼接或按关键事件触发的思路。

5. trace_processor 命令行分析

5.1 trace_processor_shell 的两种用法

拿到 trace 文件之后,UI 适合看趋势和调用链,但如果要回答"主线程在启动过程中最长的 20 个区间是哪些"这种具体问题,SQL 比鼠标点选高效得多。trace_processor_shell就是干这个的。

基础用法是直接跟文件路径进入交互模式:

trace_processor_shell trace.perfetto-trace

进去之后就是一个类似 SQLite 的提示符,可以直接敲 SQL。想退出敲.quit。非交互式用法更适合脚本,两种写法:

trace_processor_shell -q query.sql trace.perfetto-trace
echo "select count(*) from slice" | trace_processor_shell trace.perfetto-trace

非交互模式下,结果默认以表格形式打到标准输出,可以配合-q加输出格式参数转成 CSV,方便后续用脚本处理。批量分析几十份 trace 的时候,这个组合特别顺手。

提醒:trace_processor 的表结构在不同版本之间有过调整,比如帧时间线相关的表在不同版本里字段有增删。跑查询前先执行select name from sqlite_master where type='table'看一眼实际有哪些表,比直接抄网上的 SQL 稳。

5.2 三条能立刻用上的查询

第一条,找出主线程耗时最长的区间。这是最通用的入口,卡顿分析基本都从这里开始。

select s.name, s.ts, s.dur / 1e6 as dur_ms from slice s join thread_track tt on s.track_id = tt.id join thread t on tt.utid = t.utid where t.name = 'main' order by s.dur desc limit 20;

slice表是核心表,代表时间轴上的每一个区间;thread_track把区间关联到线程轨道,thread表再给出线程名。dur的单位是纳秒,除以1e6换算成毫秒看着更直观。跑完这一条,如果发现排在前面的全是某个自定义的打点名,基本就锁定了怀疑对象。

第二条,统计每个线程占用的 CPU 时间。

select t.name, sum(s.dur) / 1e6 as total_ms, count(*) as cnt from sched_slice s join thread t using(utid) group by t.name order by total_ms desc limit 20;

sched_slice表是把内核的调度事件整理成"某个线程在某段时间内占用 CPU"的结构。这条查询能快速看出到底是谁在后台偷跑 CPU,经常能抓到一些意料之外的线程,比如某个第三方 SDK 的轮询线程。count(*)是切换次数,次数多但总时长短,说明线程频繁被唤醒,这本身也是一个耗电问题。

第三条,看线程被阻塞的情况。

select t.name, ts.state, sum(ts.dur) / 1e6 as total_ms from thread_state ts join thread t using(utid) where t.name = 'main' group by t.name, ts.state order by total_ms desc;

thread_state表描述线程的状态区间,state字段的值包括Running、R(可运行但没拿到 CPU)、S(睡眠)、D(不可中断睡眠)等。这条查询的价值在于区分两类问题:如果R状态时间很长,说明线程想跑但 CPU 被别的任务占着,是调度层面的问题;如果是D或者S很长,说明在等 IO 或等锁,要往下查具体等谁。这个区分直接决定你下一步往哪个方向查,比盲猜有效得多。

5.3 SQL 和 UI 配合的正确姿势

SQL 和 UI 不是二选一,配合起来效率最高。我的流程一般是:先跑 SQL 找出可疑的时间点(ts字段就是时间戳),记下来;然后到 UI 里跳到那个时间点,看同一时刻其他轨道上发生了什么——是不是刚好有个 GC、是不是有个大文件读写、是不是 CPU 频率被压到了最低。SQL 负责定位,UI 负责解释,两边来回切几次,问题的轮廓就出来了。

还有一个小技巧:在 UI 的 Query 面板里可以跑一模一样的 SQL,结果可以直接在界面上高亮到时间轴。这比在命令行里查到时间戳再手动找要快。所以我通常先用命令行快速扫几轮,确定方向之后转到 UI 做精查。

6. 常见问题与排查技巧实录

6.1 命令层面的坑

报perfetto: not found。三种可能:设备低于 Android 10;这台设备是定制 ROM 裁剪了 Perfetto;adb 连的其实是模拟器且镜像版本不对。先adb shell getprop ro.build.version.sdk看 API 级别,低于 29 就别折腾了,老老实实用老工具。

命令敲下去没反应也不退出。九成是没写时长,或者写的时长格式不对。检查-t参数,注意单位后缀不能省,-t 10会被当成长度单位不明。另外配置模式下要确认duration_ms存在。

报缓冲区分配失败。给的 buffer 太大,设备内存扛不住。降一半再试,或者把fill_policy改成RING_BUFFER减少内存压力。低端设备上 16MB 可能就已经是上限。

trace 文件拉回主机打不开。优先怀疑传输方式。二进制文件必须用adb exec-out cat或者adb exec-out perfetto -o -,用adb shell会做换行符转换。判断方法很简单:把文件拉到 Linux 上跑file命令,正常的 trace 文件会被识别为 protobuf 相关格式,如果被识别成文本,那基本就是被转换过了。

6.2 数据层面的坑

trace 打开后线程轨道全是数字。缺linux.process_stats数据源。这路数据源负责提供进程线程的名字映射,不开的话只能用 PID 去猜。轻量模式下已经默认包含,配置文件模式下要手动加上。

抓不到自己 App 的埋点。atrace_apps没配。这个字段在轻量模式下对应--app参数。另外确认一下 App 里用的是Trace.beginSection(framework 层)还是 Perfetto SDK 的track_event,前者走 atrace 分类,后者要单独开track_event数据源。

前后数据接不上、中间有空洞。缓冲区被写满并按策略处理过。要么加大 buffer,要么减少事件数量,要么把长追踪拆成多段。可以先看 UI 里缓冲区使用情况的曲线来确认。

文件特别大但有效信息很少。数据源开太多。回到分级抓取的思路,把 always-on 层之外的都关掉,只保留当前问题相关的。

6.3 一份速查表

现象最可能原因处理方式
perfetto: not found设备版本低于 10 或 ROM 裁剪确认 API 级别,换设备
命令挂住不退出未指定时长补-t或duration_ms
报 buffer 分配失败buffer 超设备上限降低-b或 buffer 段大小
文件解析失败传输方式破坏了二进制改用adb exec-out
线程轨道无名字缺 process_stats补上该数据源
无应用埋点atrace_apps未配添加目标包名
数据中间断档ring buffer 溢出加大 buffer 或减少事件
文件过大数据源开太多回归分级抓取

还有一条经验值得单独说:每次抓取都记下设备型号、系统版本和配置内容。同一份卡顿问题,在不同芯片平台上的成因可能完全不同,性能分析的结论强依赖设备上下文。我见过太多只有一份 trace 文件、没有任何设备信息的求助,最后只能靠猜。养成把配置文件和 trace 一起归档的习惯,过几周回头看还能复现当时的分析路径。

另外提一句时间戳对齐的事。Perfetto 默认用 BOOTTIME 时钟域,和内核 ftrace、调度事件是同一套时钟,所以 trace 内部的时间对齐天然没问题。但如果你要把它和外部日志(比如另一台机器上抓的 log)对照,就需要额外做时钟快照,配置里加上clock_snapshot相关的数据源,用两个时钟域的对应关系做换算。这一步在有跨设备联合分析的场景里是必须的,日常单设备分析用不上。

我个人在真机上反复抓取的体会是,Perfetto 命令行最大的价值不在于它能抓多少种数据,而在于它把"抓取"这件事变成了一份可以进版本库的配置。你调好一份针对自己 App 启动流程的配置文件,交给测试同学,他们用同样的命令在同样的设备上抓出来的 trace,和你手里的样本是可以直接对比的。这种可复现性,是过去靠命令行参数临时拼凑的 systrace 时代很难做到的。至于缓冲区给多大、分类开几个,没有标准答案,抓三到五次、看一眼 buffer 曲线,数字自己就出来了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询