第4章:性能测量工具准备——perfetto抓取systrace、sched_wakeup/sched_switch事件、/proc//stat读取

在RTL(Real-Time Linux)环境下,SystemUI的线程调度行为与通用Linux存在显著差异。本章聚焦性能测量工具的准备工作,涵盖perfetto的systrace抓取、sched_wakeup/sched_switch事件的捕获与解析,以及通过/proc//stat读取线程状态与优先级信息。这些工具是诊断线程响应优先级问题的基石。

4.1 perfetto核心事件类型与配置

perfetto是Android系统首选的性能追踪工具。针对RTL下的线程调度分析,需启用以下关键数据源:

  • ftrace events: 捕获内核调度器事件(sched_switch, sched_wakeup, sched_wakeup_new)。
  • process stats: 记录进程的cpu、mem、io等资源使用统计。
  • atrace categories: 收集应用层(SystemUI)的同步、Vsync、Input等标记。
调度事件原理
sched_switch记录线程的“离开CPU”与“进入CPU”时刻,直接反映线程被抢占、休眠或唤醒的时间点。sched_wakeup记录唤醒者与被唤醒者的pid,是追踪线程响应延迟的直接证据。

以下为perfetto抓取的典型配置片段(trace config protobuf格式):

# 关键配置:启用内核调度事件
data_sources {
  config {
    name: "linux.ftrace"
    ftrace_config {
      ftrace_events: "sched/sched_switch"
      ftrace_events: "sched/sched_wakeup"
      ftrace_events: "sched/sched_wakeup_new"
      buffer_size_kb: 4096
    }
  }
}
# 启用进程统计
data_sources {
  config {
    name: "linux.process_stats"
    process_stats_config {
      scan_all_processes: true
      proc_stats_interval_ms: 100
    }
  }
}

4.2 通过adb命令触发trace抓取

生产环境或测试设备上,使用perfetto命令抓取指定时长与大小的trace:

# 将配置文件推送到设备
adb push trace_config.pbtx /data/local/tmp/trace_config.pbtx

# 使用perfetto命令开始抓取(指定输出文件与缓冲区大小)
adb shell perfetto \
  -c /data/local/tmp/trace_config.pbtx \
  -o /data/local/tmp/systemui_trace.perfetto-trace \
  --txt \
  --duration 15s \
  --buffer-size 64mb

# 拉取trace到本地
adb pull /data/local/tmp/systemui_trace.perfetto-trace .
RTL环境适配:
若设备未预装perfetto,可通过adb push手动推送perfetto二进制(取自对应平台)。同时,确保内核配置项CONFIG_FTRACE、CONFIG_SCHED_TRACING已启用。

4.3 /proc/<pid>/stat的字段提取与优先级解析

/proc//stat文件提供了线程最底层的调度统计,包括:进程状态、优先级、nice值、策略、上下文切换次数、CPU时间片等。在RTL环境下,通过轮询此文件可低开销监视SystemUI主线程的状态迁移。

字段索引 含义 RTL调优关注点
2 进程状态(S/R/D/T/t) 频繁“D”状态可能表示I/O阻塞
17 nice值 RTL下nice>0可能被抢占
18 调度策略(0=normal, 1=FIFO, 2=RR) 确认是否使用SCHED_FIFO
39 CPU时间片(sum_exec_runtime) 线程累积执行时间
40 线程优先级(prio) 动态优先级,实时任务通常0-99

读取方法(shell脚本示例):

# 获取SystemUI主线程PID
SYSUI_PID=$(adb shell pidof com.android.systemui | awk '{print $NF}')
# 循环读取stat(每秒10次,低开销)
while true; do
  adb shell "cat /proc/$SYSUI_PID/stat" | \
    awk '{print "pid:", $1, "state:", $3, "prio:", $18, "policy:", $41}'
  sleep 0.1
done
常见错误:
在RTL上直接cat /proc/<pid>/stat可能返回空值或<unknown>,原因通常是进程快速退出或stat文件权限不足。解决方案:使用sched_setattr或sysfs查询实时优先级更稳定。

4.4 三工具集成分析流程

将perfetto的sched事件与/proc/stat的轮询数据结合,可构建完整的线程响应延迟链路。下图展示了数据流与核心分析步骤:

perfetto + /proc/stat 集成分析流程 perfetto trace config 启用sched_switch/wakeup adb shell perfetto ... 抓取15s trace二进制 /proc/<pid>/stat 轮询 线程状态、优先级、nice Trace Processor 解析sched_wakeup/sched_switch 输出唤醒延迟表 perfetto-ui / traceconv 可视化时间轴 标记关键事件 脚本解析stat数据 提取prio、policy、state 与trace时间戳对齐 汇聚分析 & 延迟归因 对比sched_event时间戳与stat状态变迁,判断线程是否因优先级反转让出CPU 识别出哪些线程在RTL下成为SystemUI的调度瓶颈 输出:线程响应延迟报告 + 优先级调整建议

4.5 调试与稳定性检查

  • 验证事件完整性:在perfetto trace中搜索sched_switch条目,若无数据则检查ftrace权限(需root或adb shell setenforce 0)。
  • 时间对齐:perfetto的时间戳基于CLOCK_MONOTONIC,/proc/stat轮询需自行记录高精度时间戳(如使用clock_gettime),否则无法精确对齐。
  • 性能开销:不要在生产环境高频(<1ms)轮询/proc/stat,建议间隔≥50ms。perfetto的缓冲区大小设为64MB可避免高频丢失早期数据。
部署检查清单:
1. 确认设备有无perfetto二进制(adb shell which perfetto)。
2. 确认ftrace目录挂载(adb shell ls /sys/kernel/debug/tracing/)。
3. 对SystemUI的PID做cap_sys_nice权限检查,否则无法读取实时优先级字段。
4. 预跑一次短trace(5s),快速验证sched_wakeup/sched_switch事件存在。

4.6 常见错误与解决

现象 原因 解决
trace中无sched事件 ftrace未开启或权限不足 adb shell setenforce 0;确认内核配置
/proc/stat返回<unknown> stat字段格式变更(RTL定制内核) 使用procps-ng或直接解析字段索引
perfetto命令找不到 设备未集成perfetto用户空间工具 从Android平台单独推送perfetto可执行文件
trace文件过大导致拉取失败 缓冲区设置过大或持续时间过长 --buffer-size 32mb --duration 10s

通过上述工具的准备与正确配置,可获得观察RTL下SystemUI线程调度行为所需的原始数据,为后续的优先级分析和调优打下基础。