第2章 帧率测量指标选择:FPS、Jank Count、FrameTimeline、Dropped Frames、Frame Duration分布

2.1 现象识别 — 不同卡顿表象对应不同测量指标

帧率回归并非单一表现,用户感知的“卡顿”可能来自以下五种典型现象。选择错误的测量指标会导致误判或漏报,因此必须先识别表象,再匹配指标。

用户感知现象 典型描述 最匹配的测量指标
整体画面迟钝、滑动跟手性差 “界面总是慢半拍” FPS(平均帧率)
偶发性画面跳跃、动画不连贯 “突然跳一下,然后又好了” Jank Count(卡顿次数)
特定页面或动画卡死几毫秒 “点下去等了一会才有反应” FrameTimeline(单帧各阶段耗时)
画面撕裂、部分区域刷新延迟 “屏幕好像分成了两块” Dropped Frames(丢帧计数)
性能不稳定,时好时坏 “一会儿流畅一会儿卡” Frame Duration 分布(耗时分布特征)
判断规则:当用户反馈“卡”时,首先归类到上述五种现象之一。若反馈模糊(如“不好用”),优先采集 Jank Count 和 Frame Duration 分布,两者能覆盖 80% 的帧率回归场景。

2.2 数据采集 — 五大指标的标准获取路径

每个指标都有对应的 AOSP 工具链和命令行入口。采集时需固定测试场景、时长(至少 10 秒)、环境温度,避免数据漂移。

指标 采集工具 / 命令 数据粒度
FPS
adb shell dumpsys gfxinfo <package> framestats
每秒平均帧数
Jank Count
adb shell dumpsys gfxinfo <package> --jank
卡顿事件次数
FrameTimeline
adb shell dumpsys gfxinfo <package> framestats --timeline
每帧的 App / Buffer / GPU 耗时
Dropped Frames
adb shell dumpsys gfxinfo <package> --drop
累计丢帧数量
Frame Duration 分布
adb shell dumpsys gfxinfo <package> --histogram
帧耗时区间分布(如 0-16ms, 16-32ms 等)
采集陷阱:仅读取 FPS 可能掩盖“高帧率但高抖动”的问题。例如 FPS=58 但 Jank Count=200 次/分钟,用户体验依然很差。必须组合指标交叉验证。

2.3 原因定位 — 指标组合故障树

单一指标只能描述“是什么”,无法回答“为什么”。使用以下故障树,通过指标组合快速定位根因。

故障树判断规则:
① FPS 正常 & Jank Count 高 → 大概率是单帧异常耗时(查 FrameTimeline)。
② FPS 偏低 & Dropped Frames 高 → 渲染管线瓶颈(查 GPU/Overdraw)。
③ Frame Duration 分布呈双峰 → 存在两种帧耗时模式(检查后台任务或 GC 触发)。
④ FrameTimeline 显示 App 阶段耗时翻倍 → 主线程消息队列堆积(查 Handler/MethodTrace)。
指标组合 典型根因 下一步排查方向
FPS↓ + Jank Count↑ CPU 频率限制 / 调度延迟 检查 cpufreq / sched_stat
FPS↑ + Jank Count↑ 渲染管线频繁丢帧 检查 GPU 频率 / SurfaceFlinger
FrameTimeline App 阶段异常 主线程耗时操作(布局/绘制) 抓取 Systrace 聚焦 UI Thread
Dropped Frames 集中在特定组件 自定义 View 过度绘制 开启 GPU 渲染模式分析
Frame Duration 右尾过长 周期性 GC 或 SO 加载 检查 logcat GC 日志 / 动态链接
帧率测量指标选择决策树 帧率回归现象 FPS Jank Count FrameTimeline Dropped Frames Frame Duration 分布 整体帧率趋势评估 宏观性能快速感知 卡顿频率统计 用户体验量化指标 单帧生命周期分析 各阶段耗时可视化 渲染丢帧计数 管线瓶颈定位手段 帧耗时分布特征 异常帧识别与归类

2.4 修复动作 — 按指标类型定向优化

根据故障树定位到的根因,执行对应的修复策略。以下按指标维度给出典型修复动作。

指标异常特征 典型修复动作
FPS 整体偏低(< 55fps) 检查 CPU 调度策略、降低主线程负载、开启 GPU 渲染加速
Jank Count 单次 > 3 次/秒 异步化耗时操作、预加载资源、减少反射调用
FrameTimeline App 阶段 > 12ms 精简布局层级、使用异步 Inflate、优化自定义 View 的 onDraw
Dropped Frames 累计 > 5% 总帧数 排查 Overdraw、减少 GPU 纹理上传、启用硬件缓冲队列
Frame Duration 分布出现 > 50ms 长尾 排查 GC 频率、检查一帧内是否发生类加载或 IO 操作
修复优先级建议:先解决 FrameTimeline 中 App 阶段的单帧耗时异常(通常影响面最大),再处理 Dropped Frames 类渲染瓶颈。FPS 和 Jank Count 作为验证指标,不要直接作为优化目标。

2.5 复测 — 同一场景下对比指标基线

复测必须使用与“现象识别”阶段完全相同的测试场景、操作路径和环境温度。对比修复前后的五个指标变化,确认回归是否消除。

指标 复测通过标准(示例基线) 检查要点
FPS ≥ 58 fps(与基线偏差 < 2%) 排除温升降频导致的 FPS 波动
Jank Count ≤ 基线值 + 5% 关注峰值 Jank 是否消除
FrameTimeline App 阶段 ≤ 10ms,Buffer 阶段 ≤ 4ms 检查长帧(≥ 20ms)是否消失
Dropped Frames 丢帧率 ≤ 1% 检查连续丢帧是否消除
Frame Duration 分布 90% 帧耗时 ≤ 20ms 检查右尾长度是否缩短
复测陷阱:不要只测一次。连续采集 3 轮(每轮 10 秒),取中位数。如果某一轮指标突然恶化,说明修复不稳定,需要排查偶发干扰(如网络请求、后台同步)。

2.6 预防 — 建立指标基线 + 自动化看护

在版本发布 pipeline 中嵌入指标采集步骤,每次 AOSP 版本更新后自动对比基线,从源头拦截帧率回归。

  • 基线固化:将当前稳定版本的五个指标值记录为 JSON 配置文件,纳入版本管理。
  • 自动化看门狗:在 CI/CD 中执行
    python3 frame_regression.py --baseline baseline.json --current result.json
    自动判定回归。
  • 定期校准:每月使用同一台物理设备、同一场景复测基线,排除系统级漂移。
  • 告警规则:任意指标超过基线阈值(如 FPS 下降 > 3% 或 Jank Count 上升 > 10%)自动触发回归标记。
预防最佳实践:将五个指标合并为一个“帧率健康分”(FPS × 0.3 + (1 - Jank Rate) × 0.25 + ...),单分数下降即告警,降低多指标人工分析成本。