AGI揭秘:精准定位性能瓶颈的终极武器
它补的是哪块空白前面几篇用的工具各有盲区:Unity Profiler CPU 侧耗时分布,GPU 只给一个粗略总数 Frame Debugger 画了什么、合批如何 —— 但完全没有耗时 Perfdog 帧率/温度/功耗曲线 —— 不告诉你为什么 AGI GPU 内部:每个 Pass 花多久、卡在哪个阶段、带宽多少 ✅前面说降分辨率帧率不变可能是顶点瓶颈,当时只能靠推断。AGI 是直接把数字摆出来的那一步。它是 Google 出的免费工具(早期叫 GAPID),针对 Android。一、两种模式,解决不同问题System Profile(系统追踪) 基于 Perfetto,抓一段时间(几秒)的全系统数据 → CPU 各核调度、GPU 占用率与频率、内存带宽 → vsync、帧提交节奏、卡顿点 → 回答:瓶颈在哪一侧?有没有降频?卡顿发生在什么时刻? Frame Profile(单帧分析) 抓一帧,逐 Render Pass / Draw Call 展开 → 每个 Pass 的 GPU 耗时 → GPU 硬件计数器(片元数、顶点数、纹理采样量、带宽) → 回答:这一帧的时间具体花在哪?实践顺序通常是:先 System Profile 定性,再 Frame Profile 定位。二、前置条件(最容易卡住的地方)这一步失败率很高,先说清。应用必须是 debuggableUnity: Build Settings → ☑ Development Build 或者在 AndroidManifest 里: application android:debuggabletrue⚠️ Development Build 自带额外开销 → 用它看「比例关系」和「哪个 Pass 贵」✅ → 不要用它的绝对数值下结论 ❌ 想测真实耗时,需要单独出一个 debuggable 的 Release 配置图形 API 建议用 VulkanPlayer Settings → Other Settings → Graphics APIs 把 Vulkan 拖到第一位AGI 的 Frame Profile 对 Vulkan 支持最完整。OpenGL ES 的支持情况随 AGI 版本和设备驱动而不同,我没法给你一个可靠的兼容列表——建议直接在目标机型上试一次。设备支持有限System Profile: 支持面较广(Perfetto 是 Android 系统能力) Frame Profile: 要求 GPU 驱动暴露性能计数器 → 只有部分机型支持 → Google Pixel 系列、部分 Adreno / Mali 设备这是 AGI 最大的实用障碍。官方维护一份支持设备列表,用之前先去查,别指望手上任意一台测试机都能用。某些厂商的定制 ROM 会把计数器接口关掉。连接步骤① 开发者模式 USB 调试 ② adb devices 确认能连上 ③ 启动 AGI → 选择设备 → 选择应用包名 ④ 选 System Profile 或 Frame Profile ⑤ Capture连不上的常见原因: · adb 版本太老 · 应用不是 debuggable · 手机弹了授权框没点(拔插线重试) · 厂商 ROM 限制了性能计数器访问 · 后台有别的 adb 客户端占着(adb kill-server 重试)三、System Profile 怎么读抓到的是一张时间轴,上下叠了很多条轨道:时间 ────────────────────────────────────────────────► VSync │ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ │ 16.6ms 一格 CPU 0 (小核) │▓▓░░▓▓░░░░▓▓▓░░░░░░░░░░░░░░░░░░░░░░░│ CPU 4 (大核) │▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓│ ← 主线程满载 CPU 7 (超大核)│▓▓▓▓░░░░▓▓▓▓░░░░▓▓▓▓░░░░░░░░░░░░░░░░│ GPU 占用率 │▓▓▓▓▓▓▓░░░░▓▓▓▓▓▓░░░░▓▓▓▓▓░░░░░░░░░░│ 约 60% GPU 频率 │━━━━━━━━━━━━╲____________________────│ ← 降频了 UnityMain │████████████████████████████████████│ RenderThread │ ███ ███ ███ ███ ███ │要盯的四件事① GPU 占用率持续 95% GPU bound,去做 Frame Profile 50% ~ 80% GPU 有余力 → 瓶颈在 CPU 或提交节奏 剧烈波动 负载不均,某些帧特别重② GPU 频率曲线这是 System Profile 独有的价值——看降频。频率 │ │━━━━━━━━╲ │ ╲________________ │ ← 稳定在低频 └──────────────────────────► 时间 2min 频率掉下来,帧率跟着掉 → 这不是渲染效率问题,是功耗/温度问题 → 优化方向是「降低整体功耗」,不是「优化某个 Pass」带宽、Overdraw、过多的 RT 切换都是发热大户。前面讲的 tile 相关优化,收益主要体现在这条曲线上。③ CPU 各核分布只有一个核满载,其他闲着 → 主线程瓶颈,考虑 Jobs / 多线程渲染 频繁在大小核之间迁移 → 线程亲和性问题,或者系统调度在省电④ 主线程和渲染线程的关系UnityMain │████████████████│ 满 RenderThd │ ██ ██ ██ │ 有空隙 → CPU 提交端是瓶颈 UnityMain │██ ██ ██ ██ │ 有空隙 RenderThd │████████████████│ 满 → 渲染线程或 GPU 是瓶颈四、Frame Profile 怎么读抓一帧,左边是 Render Pass 树,每项带 GPU 耗时:Frame 18.4 ms ├─ RenderPass: ShadowMap 3.8 ms 21% │ ├─ Cascade 0 1.1 ms │ ├─ Cascade 1 0.9 ms │ ├─ Cascade 2 0.8 ms │ └─ Cascade 3 1.0 ms ├─ RenderPass: Opaque 7.2 ms 39% │ ├─ Draw (terrain) 2.1 ms │ ├─ Draw (characters) ×8 2.8 ms │ └─ Draw (props) ×120 2.3 ms ├─ RenderPass: Transparent 4.1 ms 22% ← 偏高 │ └─ Draw (particles) ×40 3.7 ms ← 这里 ├─ RenderPass: PostProcess 2.6 ms 14% │ ├─ Bloom downsample ×4 0.9 ms │ ├─ Bloom upsample ×4 0.8 ms │ └─ UberPost 0.9 ms └─ RenderPass: UI 0.7 ms 4%这张表就是前面所有工具给不了的东西。Frame Debugger 能告诉你有 40 个粒子 Draw Call,只有 AGI 告诉你它们吃了 3.7ms,占了整帧的 20%。第一眼先看占比看到 Transparent 22% 还只画了 40 个粒子 → 典型的 Overdraw 问题 → 对上了前面讲的「半透明不能深度剔除」 看到 ShadowMap 21% → 阴影确实是双倍成本的实证 → 砍 Max Distance / 减级联,这里会直接下来 看到 PostProcess 14% 全是 Blit → 全屏带宽开销,低端档应该关掉五、用计数器细分瓶颈这是 AGI 最核心的能力,也是我前面说要进一步确认的那一步。选中一个 Pass 或 Draw Call,右侧给出 GPU 硬件计数器。具体名称和可用项因 GPU 厂商(Adreno / Mali)而异,但大致分这几类:几何类 Vertices / Primitives 处理了多少顶点和图元 Vertex Shader Cycles 顶点着色花的周期 Culled Primitives 被剔掉多少 片元类 Fragments Shaded 实际着色的片元数 Fragment Shader Cycles 片元着色周期 Early-Z Killed 被提前剔除的片元 纹理类 Texture Fetches / Cycles 采样次数和开销 Texture Cache Miss 缓存未命中 带宽类 Read / Write Bytes 主内存读写量 Tile Read / Write tile 的 resolve 量怎么用它们判断判断 OverdrawFragments Shaded ÷ 屏幕像素数 实际 Overdraw 倍数 1080p 207 万像素 Fragments Shaded 250 万 → 1.2x,很好 Fragments Shaded 800 万 → 3.9x,偏高 Fragments Shaded 2000 万 → 9.7x,严重这个数字比 Scene 视图的 Overdraw 热力图精确得多——它是真机上的实测值,不是编辑器估算。区分片元 bound 和顶点 boundFragment Shader Cycles Vertex Shader Cycles → 片元瓶颈 → 简化 Shader / 降分辨率 / 减 Overdraw Vertex Shader Cycles Fragment Shader Cycles → 顶点瓶颈 ← 这正是「降分辨率没用」的那种情况 → 做 LOD / 减面 / 合并网格 / 减少阴影 Pass判断带宽瓶颈Read Write Bytes 很大,但 Shader Cycles 不高 → 带宽 bound,GPU 在等内存 → 压纹理 / 开 Mipmap / 减 RT 切换 / 减分辨率 典型的带宽大户: · 未压缩纹理 · 没开 Mipmap(缓存命中率极低) · 一串全屏 Blit · 大尺寸 RenderTarget判断 Shader 太复杂Shader Cycles ÷ Fragments Shaded 每片元的平均开销 这个值高 → Shader 本身重 → 查是否有逐像素光照、多层采样、复杂数学 → 对照 Frame Debugger 看 Keywords 是否过多判断纹理缓存问题Texture Cache Miss 比例高 → 大概率是没开 Mipmap → 或者贴图尺寸远超实际需要的采样密度 这直接验证了前面说的「不开 Mipmap 省内存是错误优化」六、串起来的完整诊断流程把前面几篇的工具连成一条线:① Perfdog / System Profile 跑 20 分钟,看帧率和 GPU 频率曲线 ↓ 频率掉了?→ 功耗问题,重点查带宽和 Overdraw 频率稳定?→ 继续 ↓ ② Unity Profiler 降分辨率测试 定性:CPU bound 还是 GPU bound ↓ CPU bound → 走 CPU 优化路线(脚本/物理/UI/GC) GPU bound → 继续 ↓ ③ Frame Debugger 看结构:画了什么、合批如何、有无多余 Pass ↓ ④ AGI Frame Profile 看耗时:哪个 Pass 占比最高 ↓ ⑤ AGI 计数器 细分:片元 / 顶点 / 带宽 / Shader 哪一项 ↓ ⑥ 针对性优化 → 回到 ① 验证⚠️ 每一步都要闭环验证 改完回到 AGI 重抓一次,确认那个 Pass 的耗时真的下来了 不要改完就认为有效七、常见现象对照现象AGI 里的特征处理方向降分辨率无效Vertex Cycles 高,Fragment 低LOD、减面、减阴影 Pass发热降频GPU 频率曲线下行,带宽计数器高压纹理、减 Overdraw、减 RT 切换特效一开就卡Transparent Pass 占比高,Fragments 远超像素数减粒子数量/尺寸,序列帧替代叠加阴影很贵ShadowMap Pass 占比 20%砍 Max Distance、减级联、关小物件投影后处理很贵PostProcess 下一串 Blit,Write Bytes 高合并 Pass,低端档关闭某个材质特别慢单个 Draw 的 Shader Cycles/片元 异常高简化 Shader,查 Keywords画面没问题但就是慢Texture Cache Miss 高开 Mipmap,检查贴图尺寸GPU 占用不满但帧率低System Profile 显示 CPU 单核满载CPU 侧优化,考虑 Jobs八、局限与替代AGI 的问题: · Frame Profile 设备支持有限,很多机型用不了 ← 最大障碍 · 需要 debuggable 包,数据有额外开销 · 连接不稳定,断连重试是常态 · 只支持 Android · 学习曲线比 Unity 自带工具陡所以实际项目通常不会只用一个:需求工具Adreno 深度分析Snapdragon Profiler(高通官方,计数器更全)Mali 深度分析Arm Mobile Studio / StreamlineiOS GPU 分析Xcode GPU Frame Capture长期帧率/温度/功耗Perfdog快速看结构Unity Frame DebuggerCPU 侧Unity Profiler实用建议: 主力测试机选一台 AGI 支持的(Pixel 系列最稳) 专门用来做 GPU 深度分析 其他机型用 Perfdog 做覆盖测试,看表现是否一致要点1. AGI 填的是「GPU 内部耗时」这块空白 Frame Debugger 看结构,AGI 看耗时,两者配合用 2. System Profile 定性(含 GPU 频率曲线,这是看降频的关键) Frame Profile 定位(逐 Pass 耗时 硬件计数器) 3. 前置条件容易卡住:debuggable 包 Vulkan 设备在支持列表里 Frame Profile 的设备限制是最大的实用障碍 4. 用 Development Build 看比例关系,不要信绝对数值 5. 计数器的核心用法: Fragments Shaded ÷ 屏幕像素 真实 Overdraw Fragment vs Vertex Cycles 片元 bound 还是顶点 bound Read/Write Bytes 高但周期低 带宽 bound Cycles ÷ Fragments Shader 单位开销 Cache Miss 高 Mipmap 没开 6. 顶点 bound 是「降分辨率测不出来」的那种情况 AGI 的计数器是确认它的唯一可靠手段 7. GPU 频率下行说明是功耗问题, 优化方向是降带宽,而不是优化某个具体 Pass 8. 改完必须回到 AGI 重抓验证,确认目标 Pass 的耗时真的下来了