跳到主要内容

Systrace 与 Perfetto

问题

Systrace 和 Perfetto 是什么?如何用它们分析性能问题?

答案

Systrace vs Perfetto

特性SystracePerfetto
状态已停止维护官方推荐
数据源ftraceftrace + 更多
UIChrome HTML 页面ui.perfetto.dev
自定义 TraceTrace.beginSection()同上
分析能力基础SQL 查询、指标计算

抓取 Trace

# Perfetto 命令行
adb shell perfetto \
-c - --txt \
-o /data/misc/perfetto-traces/trace.pb \
<<EOF
buffers: {
size_kb: 63488
fill_policy: RING_BUFFER
}
duration_ms: 10000
data_sources: {
config {
name: "linux.ftrace"
ftrace_config {
ftrace_events: "sched/sched_switch"
ftrace_events: "power/suspend_resume"
atrace_categories: "gfx"
atrace_categories: "view"
atrace_categories: "wm"
atrace_categories: "am"
atrace_apps: "com.example.app"
}
}
}
EOF

# 拉取并在浏览器打开
adb pull /data/misc/perfetto-traces/trace.pb
# 访问 https://ui.perfetto.dev 打开文件

自定义 Trace 点

import androidx.tracing.trace

// 方式 1:Kotlin 扩展函数(推荐)
fun loadData() = trace("loadData") {
val users = repository.getUsers()
processUsers(users)
}

// 方式 2:手动 begin/end
fun loadData() {
Trace.beginSection("loadData")
try {
val users = repository.getUsers()
processUsers(users)
} finally {
Trace.endSection()
}
}

// 异步 Trace
Trace.beginAsyncSection("network_request", requestId)
// ... 异步操作
Trace.endAsyncSection("network_request", requestId)

Perfetto 分析要点

在 Perfetto UI 中重点关注:

  1. Choreographer#doFrame:查看每帧耗时,超过 16ms 的帧标红
  2. 主线程 Slice:查看主线程在做什么
  3. Binder 调用:跨进程调用是否耗时
  4. CPU 调度:主线程是否被抢占
-- Perfetto SQL 查询示例:找出超过 16ms 的帧
SELECT ts, dur, name
FROM slice
WHERE name = 'Choreographer#doFrame'
AND dur > 16000000 -- 16ms in nanoseconds
ORDER BY dur DESC

常见面试问题

Q1: 如何用 Perfetto 定位卡顿原因?

答案

  1. 在 Perfetto 时间轴找到掉帧区域(红色标记)
  2. 放大查看该帧的主线程 Slice
  3. 分析耗时最长的 Section(可能是 layout、measure、或自定义 Trace)
  4. 如果主线程在等待锁,检查持有锁的线程在做什么
  5. 如果 CPU 利用率低但帧慢,可能是被其他进程抢占

Q2: 自定义 Trace 对性能有影响吗?

答案

Trace.beginSection() 在未抓取 trace 时几乎零开销(内部检查一个标志位即返回)。抓取时有微小开销(写入 ftrace buffer),可忽略。Release 包中保留自定义 Trace 是安全的。

相关链接