飞书机器人 × AI Agent(二):给车载 3D HMI 做「性能体检」——AI 分析 CPU / GPU / 内存 / 帧率的实战方法论
在飞书里发一句"3D 场景帧率有点抖,帮我做次性能体检",二十分钟后话题里收到一张卡片:帧率曲线与 jank 分布、CPU 线程画像、GPU 占用、内存 PSS 曲线,外加一段归因——“主线程 doFrame 间隔异常,疑与绑核配置相关,trace 关键区间已圈出,建议复核”。这不是畅想,是上一篇那套平台正在跑的另一条日常线:上一篇文章讲了冒烟测试的"对不对",这一篇讲性能分析的"快不快、稳不稳"。
前篇:飞书机器人 × AI Agent:一套车载 HMI 自动化测试平台的架构设计与落地
前言:3D HMI 的性能分析,到底难在哪
车载 3D HMI 的性能问题,有几个很"拧巴"的特点:
- 四个指标互为因果,单看哪个都会误判。CPU 慢会拖帧率;GPU 满了会让渲染线程堵在等 GPU 空闲,回头又把 CPU 挂起来;内存吃紧会引来 GC 尖刺和换页,帧间隔瞬间飙出几个数量级。只看一张均值表,十有八九归因错误。
- 被测对象是 3D 引擎应用,线程模型复杂。一个 Unity 系应用跑起来,至少有主线程(游戏逻辑 + 渲染命令提交)、渲染线程(驱动提交)、Job 工作线程池;系统侧还有 SurfaceFlinger 合成器、视频解码线程在抢同一块 8 核 SoC。不知道哪个线程"该"吃多少 CPU,数据就只是数字。
- 工具链是割裂的。调度和帧要看 Perfetto/systrace,线程 CPU 要看
top -H,内存要看dumpsys meminfo,图形栈还有厂商工具——四套工具四种口径四种导出格式,人工拼一张表要来回倒腾。 - 环境坑密度极高。大小核调度、绑核配置、双屏双系统(中控 Android + 仪表 QNX)、十几小时长稳运行、甚至采集工具自己把 CPU 跑到 40% 抢占被测对象——每一个坑都能让数据失真。
传统做法的两个极端,和冒烟测试时代一模一样:
| 方案 | 优点 | 死穴 |
|---|---|---|
| 人工 adb 现场敲命令 | 灵活、能兜底 | 一轮多场景摸底 2~3 天,人被钉在设备前;数据散落各目录,事后难对齐 |
| 固定脚本一把梭 | 快、无人值守 | 指标口径写死,场景一换就废;出了异常分不清是采集问题还是真问题 |
我们的思路延续上一篇:把"口径"和"流程"沉淀成技能文档,把"采集"固化成脚本,把"读数"交给 AI Agent,把"结论"留给人。
一、先定口径:四维指标体系
动手之前先回答"测什么、怎么判"。我们把车载 3D 应用的性能体检收敛成四个维度,每个维度都有明确的采集手段和判定口径:
| 维度 | 采集手段 | 口径 | 3D 应用特有看点 |
|---|---|---|---|
| CPU | 循环top -H快照 + Perfetto sched 轨道 | 8 核整机按 /800%;分线程、分核看 | UnityMain / 渲染线程 / 解码线程谁在吃核;关键线程跑在大核还是小核 |
| GPU | 内部常驻采集工具(REST API)+ Perfetto 图形轨道 | 使用率均值 / 峰值 | 3D 场景渲染负载是否把 vsync 周期吃满,判定 GPU bound |
| 内存 | dumpsys meminfo(PSS)+topRES | 均值 / 峰值 MB、整机占比 | 纹理与 Mesh 资产、IL2CPP 堆、长稳运行的泄漏斜率 |
| 帧率 | Perfetto(doFrame + SurfaceFlinger/vsync 事件) | fps、帧间隔 P95/P99、jank 帧占比 | 主线程瓶颈 vs 合成器瓶颈 vs GPU 瓶颈的分辨 |
几个口径上的经验教训:
- 帧率不看均值,看分布。平均 58fps 的曲线里可能藏着一堆 300ms 的长帧——车机上这就是肉眼可见的卡顿。我们以"超过 2 个 vsync 周期的帧"计 jank,报 P95/P99 帧间隔。
- CPU 必须落到线程级。整机 CPU 65% 没有任何行动价值;"UnityMain 单线程 95%、其他全闲"才指向问题。
- 内存要区分 PSS 和 RES,并与整机容量对齐。我们的一台 16G 整机上,被测 3D 应用典型 RES 约 1.4G(8.9%)——脱离整机容量的"应用吃了 1.4G"没有评审意义。
二、采集层:把"敲命令"固化成脚本
2.1 三个采集脚本 + 一个绑核脚本
所有现场采集都固化成 bat 脚本,Agent 按场景组合调用:
capture_top.bat 循环 top -H 快照,每轮打印时间戳 capture_perfetto.bat 抓 Perfetto trace:root 重试 → 采集 → 落盘校验 → pull capture_mem.bat dumpsys meminfo 快照,与 top 同一时间戳节奏 cpu_bind_cores.bat 按核容量把关键线程绑到指定核top 采样脚本的核心逻辑(脱敏简化):
:loop for /f