Skip to content

Frame Time 实时采集与流畅度报告 v4

指标八要素

要素内容
定义相邻两个被 exact debugid 接受的 presented-frame 时间戳之差
metricIDios.frame.time;Session 汇总指标沿用 ios.frame.* Registry
scopeforeground-device;不表示目标 PID 独占的渲染帧
unitmilliseconds
来源字段CoreProfile RAW v2 kd_buf.timestamp、Mach numer/denom、exact debugid 0x31800318
质量语义首帧 warmup;可解码有限值 candidate;后台 not-foreground;头/时基/debugid 失配则 missing 或 unsupported-schema,绝不以 1000/FPS 伪造
当前校准状态iOS 16/17/18 CoreProfile 来源 E4 candidate;本版增加选中指标后的实时投影,等待新构建的真机 UI 验收
版本历史decoder core-profile-v2-presented-frame.candidate.v2;实时投影 frame-time-realtime.candidate.v1;报告 frame-report.candidate.v2

实时公式和窗口

text
timestampNs[i] = floor(machTicks[i] × numer / denom)
frameTimeMs[i] = (timestampNs[i] - timestampNs[i-1]) / 1,000,000
instantFPS[i] = 1,000 / frameTimeMs[i]
  • 底层通信服务com.apple.instruments.server.services.coreprofilesessiontap
  • 底层实现归属:基于 pymobiledevice3.services.dvt.instruments.core_profile_session_tap.CoreProfileSessionTap 打开 RAW v2 协议流(配置 bm=0/1,按选择启用 sampling-trigger)。Perfowl 自研 RealtimeFrameDecoder 解码 64 字节 kd_buf 结构。
  • CoreProfile 仅在用户选中 Frame Time 时启动,与其他指标共用唯一 DTX owner。
  • decoder 持有当前 Session 的 RAW v2 追加缓冲,每次只发布新增 accepted timestamp;重复解码结果不重复发布。
  • 首个 accepted timestamp 只建立前值,不生成 0 ms。逆序、相等、越 generation 的 timestamp 不参与差分。
  • 目标 App 进入后台时实时值立即失效(not-foreground);回到前台后必须等待新的 accepted presented-frame 事实。
  • 计算层保留 Double,UI 可格式化一位小数,Session/CSV 不回写 UI 取整值。

汇总报告与流畅度详细算法(frame-report.candidate.v2)

所有汇总指标均直接由 Session 内接受的完整 FrameTime 序列计算得出:

1. 动态平滑基线与三档 Jank 判定

  • 动态平滑基线 ($B_n$):前 3 帧平均耗时 $$B_n = \frac{FT_{n-1} + FT_{n-2} + FT_{n-3}}{3} \quad (\text{当样本数 } \ge 3)$$
  • 动态门槛 ($D_n$):$D_n = 2 \times B_n$
  • 三档 Jank 判定规则
    • SmallJank:$FT_n > D_n \quad \text{且} \quad FT_n > 41.66\text{ ms}$
    • Jank:$FT_n > D_n \quad \text{且} \quad FT_n > 83.33\text{ ms}$
    • BigJank:$FT_n > D_n \quad \text{且} \quad FT_n > 125.00\text{ ms}$
  • 10 分钟频次折算: $$\text{Jank/10min} = \frac{\text{Count}}{\text{Duration (seconds)}} \times 600$$

2. 卡顿率(Stutter %)

所有被判定为 Jank 的帧中,其超出基线的卡顿耗时之和占测试总时长的比例: $$\text{Stutter%} = \frac{\sum_{i \in \text{Jank Frames}} \max(0, FT_i - B_i)}{\text{Session Total Duration (ms)}} \times 100%$$

3. 平均 FPS 与 1% Low FPS

  • Average FPS:采用加权真实均值(即 1000 除以平均帧耗时),而非简单帧率算术平均: $$\text{Avg FPS} = \frac{1000}{\text{mean}(FT)}$$
  • 1% Low FPS:将所有帧耗时降序排列,取耗时最长的最差 $1%$ 帧($\lceil 0.01 \times N \rceil$ 个),计算其平均帧耗时的倒数: $$\text{1% Low FPS} = \frac{1000}{\text{mean}(\text{Slowest 1% } FT)}$$

4. 掉帧率(Drop Rate)与稳态区间

  • Dropped Frames / Hour:统计相邻帧瞬时 FPS 跌幅大于 8 的总次数($\text{DropCount} = \sum [FPS_i - FPS_{i+1} > 8]$),折算每小时频次: $$\text{Drop / Hour} = \frac{\text{DropCount}}{\text{Duration (seconds)}} \times 3600$$
  • FT >= 100ms 占比:帧耗时超过 100ms 的帧数占总帧数的百分比。
  • MedRange% (80%~120% 稳态占比):落在 $[0.8 \times \text{Median(FPS)}, 1.2 \times \text{Median(FPS)}]$ 区间内的帧数占比。
  • TinyJank 与 Smooth:因竞品未公开可信严谨算法,Perfowl 保持 Unsupported 并输出 null,绝不自行编造。

版本历史

  • v4(2026-09-06):增加按选择启用 CoreProfile、追加解码、实时 Frame Time 和前后台失效规则;来源:P4 工作台指标支持收口方案
  • v3(2026-09-05):RAW v2 重放与 iOS 16/17/18 来源校准,已被本页取代。

Perfowl · Performance Observer