SuperAPI AI 工具集

hz-simpleperf-debug

测试与质量

查看项目

更新于 10-15 14:49

技能介绍

用途

hz-simpleperf-debug 用于在 Meta VR 设备上获取硬件级 CPU 性能洞察。它适合以下场景:

  • 判断应用是 CPU 密集型、内存密集型还是 I/O 密集型
  • 找出消耗最多 CPU 周期的热点函数
  • 按线程测量内核态与用户态的 CPU 开销
  • 识别缓存抖动或分支预测问题
  • 用硬件 PMU 计数器数据补充 Perfetto 追踪分析

该技能与 hz-perfetto-debug 互补:Perfetto 展示应用随时间的行为,simpleperf 展示 CPU 在硬件周期上的花费,包括 Perfetto 看不到的缓存未命中、分支预测失败和指令吞吐。

VR 性能背景

Meta VR 设备运行在移动 ARM SoC 上,有严格的热和功耗预算。CPU 密集型应用在以下刷新率下会掉帧:

刷新率 CPU 帧预算 说明
120 Hz 8.3 ms 紧张,simpleperf 对找热点至关重要
90 Hz 11.1 ms 大多数应用的默认目标
72 Hz 13.9 ms 较重应用的降级选项

环境准备

Simpleperf 分析由 metavr CLI 提供支持。可将独立二进制安装到 PATH(参见 metavr-cli 技能),或通过 npx 免安装调用:

metavr --version

下文示例使用裸 metavr 命令;若使用 npm 分发版,请加前缀 npx -y。通过 USB 连接已开启开发者模式的 Meta VR 设备。

快速开始工作流

1. 分类工作负载

优化前先确定瓶颈类型:

# 分类前台应用的工作负载(10 秒采样)
metavr perf simpleperf classify

# 指定应用
metavr perf simpleperf classify --app com.example.myapp

# 自定义时长
metavr perf simpleperf classify --duration 15

返回带证据的分类结果:

分类 指标 优化策略
CPU 密集型 高 IPC、低停顿比 优化算法、减少绘制调用、批处理工作
内存密集型 高停顿比(stalled-cycles-backend / cpu-cycles) 减少缓存未命中、改善数据局部性、缩小工作集
I/O 密集型 高每秒上下文切换 减少阻塞 I/O、使用异步、减少线程争用

2. 录制 CPU 热点

捕获 CPU 周期剖析以找出最昂贵的函数:

# 录制前台应用的 CPU 热点
metavr perf simpleperf record

# 自定义频率和时长
metavr perf simpleperf record --frequency 4000 --duration 10

# 指定应用
metavr perf simpleperf record --app com.example.myapp

录制以指定频率(默认 4000 Hz)采样 CPU 周期,生成显示哪些函数消耗最多 CPU 时间的剖析。

3. 测量内核开销

确定每个线程在内核态与用户态花费的 CPU 时间:

# 测量前台应用的内核开销
metavr perf simpleperf kernel-overhead

# 自定义时长
metavr perf simpleperf kernel-overhead --app com.example.myapp --duration 10

返回每线程的用户态与内核态 CPU 周期细分。某线程内核开销高(>20%)可能意味着:

  • 过多系统调用(文件 I/O、内存分配)
  • 驱动开销(GPU 命令提交、传感器访问)
  • 内核同步原语中的锁争用

分析工作流

第 1 步:先分类

始终从分类开始,避免浪费时间优化错误的方向。

metavr perf simpleperf classify --app com.example.myapp --duration 10

基于结果的决策树:

  • CPU 密集型 → 录制热点(第 2a 步),查看顶部函数
  • 内存密集型 → 用缓存未命中事件录制,检查数据访问模式
  • I/O 密集型 → 检查内核开销,在 Perfetto 中查看线程争用

第 2a 步:CPU 密集型应用——找热点

metavr perf simpleperf record --app com.example.myapp --duration 10

按 CPU 周期消耗查看顶部函数。常见 VR 热点:

函数模式 可能原因 修复
Physics.* / PhysX 复杂物理模拟 减少碰撞体数量、简化网格、增大固定时间步
Render* / Draw* 绘制调用过多 批处理材质、使用 GPU 实例化、减少唯一材质
GC_* / gc_alloc 垃圾回收压力 池化分配、避免每帧分配
memcpy / memmove 大数据拷贝 使用引用、减小缓冲区、避免不必要拷贝
LZ4_* / compress 资源解压 预解压、使用更轻压缩、缓存结果

第 2b 步:内存密集型应用——检查缓存行为

若分类显示内存密集型,问题可能是缓存未命中或内存带宽:

  • 大工作集抖动 L1/L2 缓存
  • 随机访问模式使预取器失效
  • 线程间相邻缓存行的伪共享

使用 Perfetto hz-perfetto-debug 将内存密集区域与具体代码路径关联。

第 3 步:测量内核开销

metavr perf simpleperf kernel-overhead --app com.example.myapp

按线程解读结果:

线程 预期内核占比 高内核占比意味着
主/游戏线程 < 5% 过多文件 I/O、日志或分配
渲染线程 5-15% 正常(GPU 驱动开销)。>20% = 驱动问题
工作线程 < 5% 线程同步开销
音频线程 < 10% 音频 HAL 调用的正常值

第 4 步:与 Perfetto 结合

Simpleperf 告诉你周期去了哪里,Perfetto 告诉你何时、在什么上下文中。配合使用:

  • Simpleperf 分类揭示瓶颈类型
  • Simpleperf 热点录制识别昂贵函数
  • Perfetto 追踪(metavr perf capture)显示这些函数相对帧边界何时运行
  • 使用 metavr perf query 将函数时序与掉帧关联

常见陷阱

  • 不要在热节流时分析。录制前让设备冷却——被节流的时钟会扭曲周期计数。先用 metavr device info 检查热状态。
  • 采样时长很重要。短录制(<5 秒)可能无法捕获代表性行为。分类至少用 10 秒。
  • simpleperf 需要 shell 访问。若 adb shell simpleperf 失败,确保已开启开发者模式并授权 USB 调试。
  • 频率与精度的权衡。更高采样频率(>8000 Hz)可能扰动移动 SoC 上的工作负载。默认 4000 Hz 是良好平衡。
  • 分类是快照。应用可能在游戏过程中是 CPU 密集型,在场景加载时是 I/O 密集型。针对你正在优化的具体场景进行分析。

参考

特定主题的详细指南:

  • 工作负载分类——PMU 计数器解读与瓶颈识别
  • CPU 热点分析——录制和分析 CPU 周期剖析
  • 内核开销——测量和减少内核态 CPU 使用