3. 性能分析工具入门

做 OpenGL ES 性能优化,第一步不是改代码,而是建立“可观测性”。如果不知道一帧时间花在哪里、GPU 在等什么、带宽被谁吃掉,任何优化都只是猜测。本节把常用工具按三个层次梳理:GPU 厂商工具看硬件内部、帧调试器看单帧绘制调用、系统级工具看 CPU/GPU/内存的整体协同。三者配合,才能形成完整的性能证据链。

核心思路:先用系统级工具判断“是 CPU 瓶颈还是 GPU 瓶颈”,再用帧调试器定位“哪一次 draw call 异常”,最后用 GPU 厂商工具下钻到“着色器、纹理、带宽、Overdraw”等硬件级指标。

一、三层工具的分工与信号链

三类工具并非互相替代,而是从粗到细、从外到内的关系。系统级工具给出全局时间线,帧调试器给出单帧调用序列,GPU 厂商工具给出硬件计数器的微观解释。下图展示了它们在同一帧上的观测层次与数据流向。

OpenGL ES 性能分析工具的三层观测链 ① 系统级性能分析工具(全局时间线) Systrace / Perfetto Android GPU Inspector Xcode Instruments CPU/GPU 帧时间、线程 ② 帧调试器(单帧调用序列) RenderDoc Snapdragon Profiler Xcode GPU Frame Capture Draw Call / 状态 / 纹理 ③ GPU 厂商工具(硬件计数器) Adreno GPU Profiler 高通 Mali Graphics Debugger Arm PowerVR PVRTune Imagination Shader / 带宽 / Overdraw 硬件计数器

二、GPU 厂商工具:读硬件计数器

不同 GPU 架构的计数器名称不同,但关注维度高度一致:着色器周期、纹理采样、顶点处理、片元输出、带宽、Overdraw、Tile 利用率。以 Adreno 为例,Adreno GPU Profiler 可给出每个渲染阶段的耗时占比;Mali 的 Graphics Debugger 则强调 Tile 与 Shader Core 的负载分布。

使用厂商工具时,建议先看三个“体检指标”:

  • GPU 利用率:长期低于 60% 往往说明 CPU 提交或同步在拖后腿。
  • 带宽占用:纹理读取与帧缓冲写入是否接近峰值,是移动端最常见的瓶颈。
  • Overdraw:同一像素被重复着色的次数,UI 与半透明层是重灾区。
厂商工具通常需要设备支持与驱动配合,部分计数器在 Release 驱动上不可用。建议在开发机上用 Debug/Profile 驱动采集,再回到目标机验证。

三、帧调试器:定位到具体 Draw Call

帧调试器(RenderDoc、Snapdragon Profiler、Xcode GPU Frame Capture)的核心价值是“把一帧拆开”。它能列出每一次 draw call 的着色器、纹理、混合状态、渲染目标,并支持逐像素回放。典型排查路径如下:

  1. 抓取一帧,按 GPU 时间排序 draw call,找出耗时最高的前 5 个。
  2. 检查这些 draw call 的着色器复杂度、纹理格式与采样次数。
  3. 查看渲染目标切换频率,判断是否存在频繁的 FBO 切换与 Tile 回写。
  4. 用像素历史功能确认某个像素被哪些 draw call 重复写入。
// 典型问题:每帧多次切换 FBO 导致 Tile 回写
glBindFramebuffer(GL_FRAMEBUFFER, fboA);   // 离屏渲染
drawScene();
glBindFramebuffer(GL_FRAMEBUFFER, fboB);   // 后处理
drawPostProcess();
glBindFramebuffer(GL_FRAMEBUFFER, 0);      // 回主屏
drawUI();
// 优化方向:合并 Pass、减少 FBO 切换、使用 loadOp=clear 避免无效回读

四、系统级工具:判断 CPU 还是 GPU 瓶颈

Systrace/Perfetto 与 Android GPU Inspector 提供的是“时间线视角”。关键看三件事:主线程是否被阻塞、RenderThread 与 GPU 是否空转、是否存在垂直同步等待。如果主线程长时间处于 doFrame 之外,说明逻辑或 IO 在拖慢帧率;如果 GPU 时间线出现大段空白,说明 CPU 提交不足。

工具层次 代表工具 核心指标 适用场景
系统级 Systrace / Perfetto / AGI 帧时间、线程状态、VSync 判断 CPU/GPU 瓶颈归属
帧调试器 RenderDoc / Snapdragon Profiler Draw Call、状态、纹理、像素历史 定位单帧异常调用
GPU 厂商 Adreno Profiler / Mali GDB / PVRTune Shader 周期、带宽、Overdraw 硬件级下钻与验证

五、指标解读与常见误区

拿到数据不等于找到答案。以下误区在工程中非常常见:

  • 只看平均帧率:平均 60 FPS 可能由大量 16ms 与少量 40ms 帧混合而成,卡顿感来自长尾帧。
  • 把 GPU 利用率高当成坏事:利用率高说明 GPU 被喂饱,真正的问题是“是否在做无用功”。
  • 忽略带宽与功耗:移动端 GPU 往往先撞带宽墙,再撞算力墙。
  • 在 Debug 构建下采集:未优化着色器与断言会严重扭曲数据,必须用 Release/Profile 构建。
采集数据时务必固定场景、固定分辨率、固定画质,并关闭后台应用。否则同一指标在不同轮次之间不可比,优化效果无法量化。

建议建立一份“性能基线表”:记录设备型号、GPU 型号、分辨率、场景、平均帧时间、GPU 时间、带宽、Overdraw。每次优化后重新采集,用数据而非感觉判断收益。工具只是手段,可复现的测量流程才是性能工程的地基。