2026-01-12 13:30:25 +08:00
|
|
|
|
# Systrace/Perfetto全解读
|
2026-01-12 17:14:58 +08:00
|
|
|
|
|
|
|
|
|
|
## 概述
|
|
|
|
|
|
|
|
|
|
|
|
Systrace和Perfetto是Android系统级性能分析工具,可以追踪系统调用、CPU调度、渲染流程等,是性能优化的必备工具。
|
|
|
|
|
|
|
|
|
|
|
|
## Systrace基础
|
|
|
|
|
|
|
|
|
|
|
|
### Systrace简介
|
|
|
|
|
|
|
|
|
|
|
|
Systrace是Android 4.1引入的系统级追踪工具,可以记录系统调用、CPU调度、渲染等信息。
|
|
|
|
|
|
|
|
|
|
|
|
### 安装与使用
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Systrace位于Android SDK的platform-tools/systrace目录
|
|
|
|
|
|
# 或使用Python脚本
|
|
|
|
|
|
python systrace.py [options] [categories]
|
|
|
|
|
|
|
|
|
|
|
|
# 基本用法
|
|
|
|
|
|
python systrace.py -t 10 -o trace.html sched gfx view
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 常用参数
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# -t: 追踪时间(秒)
|
|
|
|
|
|
python systrace.py -t 10 -o trace.html
|
|
|
|
|
|
|
|
|
|
|
|
# -o: 输出文件
|
|
|
|
|
|
python systrace.py -t 10 -o my_trace.html
|
|
|
|
|
|
|
|
|
|
|
|
# -b: 缓冲区大小(KB)
|
|
|
|
|
|
python systrace.py -t 10 -b 32768 -o trace.html
|
|
|
|
|
|
|
|
|
|
|
|
# -a: 指定应用包名
|
|
|
|
|
|
python systrace.py -t 10 -a com.example.app -o trace.html
|
|
|
|
|
|
|
|
|
|
|
|
# -k: 指定要追踪的函数(用逗号分隔)
|
|
|
|
|
|
python systrace.py -t 10 -k load_symbols,unload_symbols -o trace.html
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 追踪类别(Categories)
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# CPU调度
|
|
|
|
|
|
sched
|
|
|
|
|
|
|
|
|
|
|
|
# 图形渲染
|
|
|
|
|
|
gfx
|
|
|
|
|
|
|
|
|
|
|
|
# 视图系统
|
|
|
|
|
|
view
|
|
|
|
|
|
|
|
|
|
|
|
# 输入事件
|
|
|
|
|
|
input
|
|
|
|
|
|
|
|
|
|
|
|
# 磁盘I/O
|
|
|
|
|
|
disk
|
|
|
|
|
|
|
|
|
|
|
|
# 内存
|
|
|
|
|
|
mem
|
|
|
|
|
|
|
|
|
|
|
|
# 活动管理器
|
|
|
|
|
|
am
|
|
|
|
|
|
|
|
|
|
|
|
# 窗口管理器
|
|
|
|
|
|
wm
|
|
|
|
|
|
|
|
|
|
|
|
# 数据库
|
|
|
|
|
|
db
|
|
|
|
|
|
|
|
|
|
|
|
# 网络
|
|
|
|
|
|
network
|
|
|
|
|
|
|
|
|
|
|
|
# 电源管理
|
|
|
|
|
|
power
|
|
|
|
|
|
|
|
|
|
|
|
# 全部类别
|
|
|
|
|
|
-a
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 完整示例
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 追踪应用启动
|
|
|
|
|
|
python systrace.py -t 5 -a com.example.app \
|
|
|
|
|
|
-o startup_trace.html \
|
|
|
|
|
|
sched freq idle am wm gfx view binder_driver hal dalvik camera input res
|
|
|
|
|
|
|
|
|
|
|
|
# 追踪流畅度问题
|
|
|
|
|
|
python systrace.py -t 10 \
|
|
|
|
|
|
-o jank_trace.html \
|
|
|
|
|
|
gfx view sched freq idle
|
|
|
|
|
|
|
|
|
|
|
|
# 追踪内存问题
|
|
|
|
|
|
python systrace.py -t 10 \
|
|
|
|
|
|
-o memory_trace.html \
|
|
|
|
|
|
sched freq idle mem
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Perfetto基础
|
|
|
|
|
|
|
|
|
|
|
|
### Perfetto简介
|
|
|
|
|
|
|
|
|
|
|
|
Perfetto是Google开发的下一代性能分析工具,从Android 9开始集成,功能更强大,支持更长的追踪时间。
|
|
|
|
|
|
|
|
|
|
|
|
### 使用Perfetto
|
|
|
|
|
|
|
|
|
|
|
|
#### 1. 通过Android Studio
|
|
|
|
|
|
|
|
|
|
|
|
1. 打开Android Studio
|
|
|
|
|
|
2. 连接设备
|
|
|
|
|
|
3. 打开Profiler
|
|
|
|
|
|
4. 选择CPU Profiler
|
|
|
|
|
|
5. 点击"Record"开始录制
|
|
|
|
|
|
6. 执行操作
|
|
|
|
|
|
7. 停止录制,查看结果
|
|
|
|
|
|
|
|
|
|
|
|
#### 2. 通过命令行
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 使用perfetto命令行工具
|
|
|
|
|
|
adb shell perfetto -c - --out /data/misc/perfetto-traces/trace
|
|
|
|
|
|
|
|
|
|
|
|
# 或使用配置文件
|
|
|
|
|
|
adb shell perfetto -c /data/local/tmp/config.pb -o /data/local/tmp/trace.pb
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 3. 通过Web UI
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 1. 录制trace
|
|
|
|
|
|
adb shell perfetto -c - --out /data/misc/perfetto-traces/trace
|
|
|
|
|
|
|
|
|
|
|
|
# 2. 拉取trace文件
|
|
|
|
|
|
adb pull /data/misc/perfetto-traces/trace trace.pb
|
|
|
|
|
|
|
|
|
|
|
|
# 3. 在 https://ui.perfetto.dev/ 打开
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Perfetto配置文件
|
|
|
|
|
|
|
|
|
|
|
|
```protobuf
|
|
|
|
|
|
# config.pb (文本格式)
|
|
|
|
|
|
buffers: {
|
|
|
|
|
|
size_kb: 63488
|
|
|
|
|
|
fill_policy: DISCARD
|
|
|
|
|
|
}
|
|
|
|
|
|
buffers: {
|
|
|
|
|
|
size_kb: 2048
|
|
|
|
|
|
fill_policy: DISCARD
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
data_sources: {
|
|
|
|
|
|
config {
|
|
|
|
|
|
name: "android.surfaceflinger.frame"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
data_sources: {
|
|
|
|
|
|
config {
|
|
|
|
|
|
name: "linux.ftrace"
|
|
|
|
|
|
ftrace_config {
|
|
|
|
|
|
ftrace_events: "sched/sched_switch"
|
|
|
|
|
|
ftrace_events: "sched/sched_waking"
|
|
|
|
|
|
ftrace_events: "power/suspend_resume"
|
|
|
|
|
|
ftrace_events: "power/cpu_frequency"
|
|
|
|
|
|
ftrace_events: "power/cpu_idle"
|
|
|
|
|
|
ftrace_events: "gfx/mali_gpu_total"
|
|
|
|
|
|
buffer_size_kb: 2048
|
|
|
|
|
|
drain_period_ms: 250
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
duration_ms: 10000
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Trace文件分析
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 打开Trace文件
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Systrace HTML文件
|
|
|
|
|
|
# 直接在浏览器中打开 trace.html
|
|
|
|
|
|
|
|
|
|
|
|
# Perfetto文件
|
|
|
|
|
|
# 在 https://ui.perfetto.dev/ 打开
|
|
|
|
|
|
# 或使用Android Studio打开
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 关键指标
|
|
|
|
|
|
|
|
|
|
|
|
#### Frame信息
|
|
|
|
|
|
- **绿色**: 正常帧(< 16.67ms)
|
|
|
|
|
|
- **黄色**: 轻微掉帧(16.67-33.33ms)
|
|
|
|
|
|
- **红色**: 严重掉帧(> 33.33ms)
|
|
|
|
|
|
|
|
|
|
|
|
#### CPU信息
|
|
|
|
|
|
- **CPU频率**: 查看CPU是否降频
|
|
|
|
|
|
- **CPU使用率**: 查看CPU负载
|
|
|
|
|
|
- **CPU调度**: 查看线程调度情况
|
|
|
|
|
|
|
|
|
|
|
|
#### 渲染信息
|
|
|
|
|
|
- **VSYNC**: 垂直同步信号
|
|
|
|
|
|
- **Choreographer**: 帧调度
|
|
|
|
|
|
- **RenderThread**: 渲染线程
|
|
|
|
|
|
- **GPU**: GPU渲染时间
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 分析技巧
|
|
|
|
|
|
|
|
|
|
|
|
#### 查找卡顿
|
|
|
|
|
|
1. 找到红色或黄色的Frame
|
|
|
|
|
|
2. 点击Frame查看详细信息
|
|
|
|
|
|
3. 查看该时间段内的CPU活动
|
|
|
|
|
|
4. 查找耗时操作
|
|
|
|
|
|
|
|
|
|
|
|
#### 分析启动时间
|
|
|
|
|
|
1. 找到应用启动的起点
|
|
|
|
|
|
2. 追踪到首帧渲染完成
|
|
|
|
|
|
3. 分析各个阶段的耗时
|
|
|
|
|
|
4. 识别瓶颈
|
|
|
|
|
|
|
|
|
|
|
|
#### 分析内存问题
|
|
|
|
|
|
1. 查看内存分配事件
|
|
|
|
|
|
2. 查找频繁的GC
|
|
|
|
|
|
3. 分析内存增长趋势
|
|
|
|
|
|
|
|
|
|
|
|
## 实战案例
|
|
|
|
|
|
|
|
|
|
|
|
### 案例1:分析应用启动
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 1. 录制启动trace
|
|
|
|
|
|
python systrace.py -t 5 -a com.example.app \
|
|
|
|
|
|
-o startup.html \
|
|
|
|
|
|
sched freq idle am wm gfx view
|
|
|
|
|
|
|
|
|
|
|
|
# 2. 分析步骤
|
|
|
|
|
|
# - 找到Application.onCreate开始时间
|
|
|
|
|
|
# - 找到MainActivity.onCreate开始时间
|
|
|
|
|
|
# - 找到首帧渲染完成时间
|
|
|
|
|
|
# - 计算各阶段耗时
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**关键指标**:
|
|
|
|
|
|
- Application初始化时间
|
|
|
|
|
|
- Activity创建时间
|
|
|
|
|
|
- 布局inflate时间
|
|
|
|
|
|
- 首帧渲染时间
|
|
|
|
|
|
|
|
|
|
|
|
### 案例2:分析流畅度问题
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 1. 录制流畅度trace
|
|
|
|
|
|
python systrace.py -t 10 \
|
|
|
|
|
|
-o jank.html \
|
|
|
|
|
|
gfx view sched freq idle
|
|
|
|
|
|
|
|
|
|
|
|
# 2. 分析步骤
|
|
|
|
|
|
# - 找到掉帧的Frame(红色/黄色)
|
|
|
|
|
|
# - 查看该Frame的耗时
|
|
|
|
|
|
# - 分析主线程活动
|
|
|
|
|
|
# - 查找阻塞操作
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**常见问题**:
|
|
|
|
|
|
- 主线程阻塞
|
|
|
|
|
|
- 布局复杂
|
|
|
|
|
|
- 过度绘制
|
|
|
|
|
|
- 内存抖动
|
|
|
|
|
|
|
|
|
|
|
|
### 案例3:分析CPU使用率
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 1. 录制CPU trace
|
|
|
|
|
|
python systrace.py -t 10 \
|
|
|
|
|
|
-o cpu.html \
|
|
|
|
|
|
sched freq idle
|
|
|
|
|
|
|
|
|
|
|
|
# 2. 分析步骤
|
|
|
|
|
|
# - 查看CPU频率变化
|
|
|
|
|
|
# - 查看CPU使用率
|
|
|
|
|
|
# - 分析线程调度
|
|
|
|
|
|
# - 查找CPU密集型操作
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 高级技巧
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 自定义Trace点
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
// 在代码中添加自定义trace点
|
|
|
|
|
|
import android.os.Trace;
|
|
|
|
|
|
|
|
|
|
|
|
// 开始trace
|
|
|
|
|
|
Trace.beginSection("my_custom_section");
|
|
|
|
|
|
|
|
|
|
|
|
// 执行操作
|
|
|
|
|
|
doSomething();
|
|
|
|
|
|
|
|
|
|
|
|
// 结束trace
|
|
|
|
|
|
Trace.endSection();
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 异步Trace
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
// 异步trace
|
|
|
|
|
|
Trace.beginAsyncSection("async_operation", cookie);
|
|
|
|
|
|
// 执行异步操作
|
|
|
|
|
|
Trace.endAsyncSection("async_operation", cookie);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 计数器
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
// 设置计数器
|
|
|
|
|
|
Trace.setCounter("my_counter", value);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 4. 使用ATrace命令
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 在shell中启用trace
|
|
|
|
|
|
adb shell setprop debug.atrace.tags.enableflags 0x1
|
|
|
|
|
|
|
|
|
|
|
|
# 开始trace
|
|
|
|
|
|
adb shell atrace -t 10 -b 32768 gfx view sched > trace.txt
|
|
|
|
|
|
|
|
|
|
|
|
# 停止trace
|
|
|
|
|
|
adb shell atrace --async_stop
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Perfetto高级功能
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 长时间追踪
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Perfetto支持更长的追踪时间
|
|
|
|
|
|
adb shell perfetto -c - --out /data/misc/perfetto-traces/trace
|
|
|
|
|
|
# 可以追踪数小时
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 多数据源
|
|
|
|
|
|
|
|
|
|
|
|
Perfetto支持同时追踪多个数据源:
|
|
|
|
|
|
- CPU调度
|
|
|
|
|
|
- 内存分配
|
|
|
|
|
|
- 网络活动
|
|
|
|
|
|
- 电源管理
|
|
|
|
|
|
- 自定义事件
|
|
|
|
|
|
|
|
|
|
|
|
### 3. SQL查询
|
|
|
|
|
|
|
|
|
|
|
|
Perfetto支持SQL查询trace数据:
|
|
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
|
-- 查询所有Frame信息
|
|
|
|
|
|
SELECT * FROM slice WHERE name = 'Choreographer#doFrame';
|
|
|
|
|
|
|
|
|
|
|
|
-- 查询掉帧
|
|
|
|
|
|
SELECT * FROM slice
|
|
|
|
|
|
WHERE name = 'Choreographer#doFrame'
|
|
|
|
|
|
AND dur > 16666667;
|
|
|
|
|
|
|
|
|
|
|
|
-- 查询CPU使用率
|
|
|
|
|
|
SELECT ts, cpu, value
|
|
|
|
|
|
FROM counter
|
|
|
|
|
|
WHERE name = 'cpu.freq';
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 性能优化建议
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 基于Trace的优化
|
|
|
|
|
|
|
|
|
|
|
|
1. **识别瓶颈**: 找到耗时最长的操作
|
|
|
|
|
|
2. **分析原因**: 理解为什么耗时
|
|
|
|
|
|
3. **制定方案**: 设计优化策略
|
|
|
|
|
|
4. **验证效果**: 再次录制trace对比
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 常见优化点
|
|
|
|
|
|
|
|
|
|
|
|
- **减少主线程工作**: 将耗时操作移到后台线程
|
|
|
|
|
|
- **优化布局**: 减少布局层级和复杂度
|
|
|
|
|
|
- **减少GC**: 避免内存抖动
|
|
|
|
|
|
- **优化算法**: 使用更高效的算法
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 持续监控
|
|
|
|
|
|
|
|
|
|
|
|
- 建立性能基线
|
|
|
|
|
|
- 定期录制trace
|
|
|
|
|
|
- 设置性能告警
|
|
|
|
|
|
- 跟踪性能趋势
|
|
|
|
|
|
|
|
|
|
|
|
## 工具对比
|
|
|
|
|
|
|
|
|
|
|
|
| 特性 | Systrace | Perfetto |
|
|
|
|
|
|
|------|----------|----------|
|
|
|
|
|
|
| 支持版本 | Android 4.1+ | Android 9+ |
|
|
|
|
|
|
| 追踪时间 | 较短 | 较长 |
|
|
|
|
|
|
| 数据源 | 有限 | 丰富 |
|
|
|
|
|
|
| 分析能力 | 基础 | 强大 |
|
|
|
|
|
|
| SQL查询 | 不支持 | 支持 |
|
|
|
|
|
|
| Web UI | 基础 | 强大 |
|
|
|
|
|
|
|
|
|
|
|
|
## 最佳实践
|
|
|
|
|
|
|
|
|
|
|
|
1. **明确目标**: 在录制前明确要分析的问题
|
|
|
|
|
|
2. **合适时长**: 选择适当的追踪时间
|
|
|
|
|
|
3. **关键类别**: 只追踪相关的类别
|
|
|
|
|
|
4. **多次录制**: 多次录制确保结果一致
|
|
|
|
|
|
5. **对比分析**: 优化前后对比分析
|
|
|
|
|
|
|
|
|
|
|
|
## 相关链接
|
|
|
|
|
|
|
|
|
|
|
|
- [[README]]
|
|
|
|
|
|
- [[06-性能优化体系/流畅度(Choreographer+VSYNC)]]
|
|
|
|
|
|
- [[06-性能优化体系/启动优化方法论]]
|