日常分析性能问题时,想要抓取trace文件,无非atrace、systrace、perfetto这三种方式,那么他们对于分析来说有什么区别呢?本文对此进行梳理。
一、三者本质关系
┌─────────────────────────────────────────────────────┐
│ 数据来源层 │
│ ftrace (Linux kernel) + Android atrace events │
└──────────────┬──────────────────────────────────────┘
│
┌──────────┼──────────┐
▼ ▼ ▼
atrace systrace perfetto
(采集工具) (采集+展示) (采集+展示)
它们共享同一底层数据源,区别在于采集方式、格式和分析能力。
二、详细对比
2.1 atrace
定位:纯命令行数据采集工具(Android底层)
输出:原始 ftrace 文本格式
工作原理:
# atrace 本质是写入 /sys/kernel/debug/tracing/
atrace --list_categories # 查看可用分类
atrace -t 10 -b 32768 gfx view wm am -o trace.atrace
输出格式示例(原始文本):
# tracer: nop
#
# entries-in-buffer/entries-written: 84780/84780 #P:8
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
RenderThread-1234 [003] ...1 1234.567890: tracing_mark_write: B|1234|DrawFrame
RenderThread-1234 [003] ...1 1234.578901: tracing_mark_write: E|1234|
适合场景:
脚本自动化采集
需要原始数据做二次处理
嵌入到 CI/CD 流程
2.2 systrace
plain
定位:Python脚本,采集atrace数据并转换为HTML可视化
输出:HTML文件(内嵌 Trace Viewer,基于 Chromium)
生命周期:Android 10+ 已标记为 deprecated
工作原理:
systrace.py → 调用 atrace → 收集 ftrace 数据
→ 转换为 JSON → 生成 HTML(Catapult Trace Viewer)
使用方式:
# 旧方式
python systrace.py -t 10 -b 32768 gfx view wm am -o trace.html
# 或通过 Android Studio
# CPU Profiler → System Trace
输出特点:
trace.html
├── 内嵌 trace-viewer.js(Chromium项目)
├── 数据格式:JSON(Chrome Trace Format)
└── 直接用浏览器打开查看
时间线视图结构:
┌─────────────────────────────────────────┐
│ Process: com.example.app (pid 1234) │
│ ├── Thread: main │
│ │ ├── [Choreographer#doFrame ] │
│ │ │ ├── [traversal ] │
│ │ │ └── [draw ] │
│ ├── Thread: RenderThread │
│ └── ... │
│ Kernel Threads │
│ ├── CPU 0 Frequency │
│ └── ... │
└─────────────────────────────────────────┘
适合场景:
分析帧率/卡顿(帧边界清晰可见)
UI 渲染流水线分析
快速分享(单个 HTML 文件)
旧项目维护(不建议新项目使用)
2.3 Perfetto
定位:新一代全平台追踪框架
输出:.perfetto-trace(protobuf二进制)
官方推荐:Android 9+ 使用,Android 10+ 完整支持
架构:
┌─────────────────────────────────────────────────┐
│ Perfetto 架构 │
│ │
│ 数据源(Data Sources) │
│ ├── ftrace (kernel events) │
│ ├── /proc/stat, /proc/meminfo │
│ ├── Heapprofd (heap profiling) │
│ ├── Android GPU counter │
│ ├── Chrome browser events │
│ └── 自定义 SDK (Java/C++/Rust) │
│ ↓ │
│ traced (后台服务,ring buffer管理) │
│ ↓ │
│ 输出:.perfetto-trace (protobuf) │
└─────────────────────────────────────────────────┘
采集方式:
方式1:命令行
adb shell perfetto \
-c - --txt \
-o /data/misc/perfetto-traces/trace \
<<EOF
buffers: {
size_kb: 63488
fill_policy: RING_BUFFER
}
data_sources: {
config {
name: "linux.ftrace"
ftrace_config {
ftrace_events: "sched/sched_switch"
atrace_categories: "gfx"
atrace_categories: "view"
atrace_categories: "am"
}
}
}
data_sources: {
config {
name: "android.heapprofd" # 额外能力:堆内存
heapprofd_config {
sampling_interval_bytes: 4096
process_cmdline: "com.example.app"
}
}
}
duration_ms: 10000
EOF
方式2:使用 record_android_trace 脚本(推荐)
curl -O https://raw.githubusercontent.com/google/perfetto/master/tools/record_android_trace
python3 record_android_trace -o trace.perfetto-trace -t 10s -b 64mb \
gfx view am wm
代码插桩(SDK):
kotlin
// Kotlin/Java
import android.os.Trace
// 简单方式(atrace兼容)
Trace.beginSection("MyOperation")
doSomething()
Trace.endSection()
// Perfetto SDK(更强大)
// build.gradle
implementation 'dev.perfetto:sdk:0.0.1'
cpp
// C++ 使用 Perfetto SDK
#include <perfetto.h>
PERFETTO_DEFINE_CATEGORIES(
perfetto::Category("myapp").SetDescription("My app events"));
TRACE_EVENT("myapp", "MyFunction");
// 支持携带参数
TRACE_EVENT("myapp", "ProcessRequest",
"request_id", request_id,
"size", data.size());
适合场景:
内存分析(native heap profiling)
长时间采集(ring buffer,可采集分钟级)
跨进程/跨平台分析(Android + Chrome)
SQL 查询分析(内置 TraceProcessor + SQLite)
自动化分析(Python API)
新项目首选
三、具体功能差异举例
3.1 帧分析(Frame Timeline)
atrace 转换后:
┌────────────────────────────────────────┐
│ RenderThread │
│ [DrawFrame][DrawFrame][DrawFrame] │
│ │
│ 只能看到函数名和耗时, │
│ 无法判断是否掉帧、Jank 类型 │
└────────────────────────────────────────┘
Perfetto 原生(Android 12+):
┌────────────────────────────────────────┐
│ Expected Timeline [16ms][16ms][16ms] │
│ Actual Timeline [14ms][32ms!][15ms] │
│ ↑ │
│ 自动标红 Jank │
│ 点击显示原因: │
│ "GPU completion │
│ deadline missed" │
└────────────────────────────────────────┘
3.2 Slice 携带的参数信息
// atrace 方式(无法携带参数)
ATRACE_BEGIN("processRequest");
// ... 处理逻辑
ATRACE_END();
// Perfetto SDK 方式(可携带丰富参数)
TRACE_EVENT("myapp", "processRequest",
"request_id", req.id, // 整数参数
"url", req.url, // 字符串参数
"size_bytes", req.body.size(), // 大小
"is_cached", cached); // 布尔值
cpp
atrace 转换后在 UI 点击 slice:
┌─────────────────┐
│ Name: processRequest │
│ Start: 1234.56ms │
│ Duration: 23.4ms │
│ (无其他信息) │
└─────────────────┘
Perfetto 原生在 UI 点击 slice:
┌─────────────────────────┐
│ Name: processRequest │
│ Start: 1234.56ms │
│ Duration: 23.4ms │
│ ─── Arguments ─── │
│ request_id: 42 │
│ url: /api/user/profile │
│ size_bytes: 1024 │
│ is_cached: false │
└─────────────────────────┘
3.3 CPU Wakeup 分析
atrace 转换后:
线程 A 等待中... → 突然被唤醒
(无法知道谁唤醒了它)
Perfetto 原生:
线程 A 等待中... → [wakeup by 线程B] → 运行
↑
点击可跳转到线程B
的对应位置,显示
完整唤醒调用栈
3.4 SQL 查询能力对比
sql
-- atrace 转换后可以查的(基础):
SELECT name, dur FROM slice
WHERE dur > 16000000
ORDER BY dur DESC;
-- 有数据但有限:
-- slice 表:有
-- sched 表:部分有
-- counter 表:基础有
-- Perfetto 原生可以查的(丰富):
-- 查询导致Jank的帧
SELECT
f.ts, f.dur,
f.jank_type,
f.on_time_finish
FROM frame_slice f
WHERE f.jank_type != 'none';
-- 查询内存分配热点(需heapprofd数据)
SELECT
h.name as function,
SUM(h.size) as total_bytes,
COUNT(*) as alloc_count
FROM heap_profile_allocation h
GROUP BY h.name
ORDER BY total_bytes DESC
LIMIT 20;
-- 查询线程唤醒链
SELECT
t1.name as waiter,
t2.name as waker,
w.ts,
w.dur as wait_time
FROM thread_state w
JOIN thread t1 ON w.utid = t1.utid
JOIN thread t2 ON w.waker_utid = t2.utid
WHERE w.state = 'S' -- sleeping
AND w.dur > 10000000; -- 等待超过10ms
四、一个直观的信息量对比
假设分析一个卡顿问题:
用 atrace 转换后分析:
─────────────────────
✅ 能看到:哪个函数耗时长(23ms > 16ms)
✅ 能看到:发生在哪个线程
✅ 能看到:同期 CPU 频率
❌ 不知道:为什么慢(内存分配?锁等待?)
❌ 不知道:是否有频繁的小内存分配
❌ 不知道:具体是哪行代码
❌ 不知道:GPU 侧是否也有延迟
用 Perfetto 原生分析:
─────────────────────
✅ 能看到:函数耗时 + 内部调用栈
✅ 能看到:这23ms里有18ms在等锁(sched状态)
✅ 能看到:持锁的是哪个线程在做什么
✅ 能看到:同期发生了 2MB 的 native 内存分配
✅ 能看到:具体分配来自哪个调用路径(火焰图)
✅ 能看到:GPU 完成时间比预期晚了 5ms
✅ 能看到:帧被系统标记为 AppDeadlineMissed Jank
五、总结
核心结论:三者数据来源相同,perfetto 是进化版,在数据丰富度、分析能力、工具链上全面超越前两者。新项目直接用 perfetto,老项目的 systrace trace 可通过 traceconv 转换复用。
