Screen Test Pro

打造一个永远不会卡死的浏览器基准测试

作者 Screen Test Pro发布于

基准测试会以各种尴尬方式失败:进度卡在 97%,连续运行分数相差 30%,甚至因为笔记本屏幕更好而给它更低的分数。为 2.0 重写测试时,我们把这份故障清单贴在桌前,逐项设计应对方案。以下是开发过程中的一些记录。

把测量倒过来

传统基准的结构是“固定工作负载 + 测量 FPS”,但放进浏览器后几乎没有意义。高性能设备很快就会顶到屏幕刷新率(浏览器不会快于垂直同步绘制,于是所有好设备都只报告“60”或“120”);低性能设备则变成幻灯片,测到的是用户耐心,而不是性能。

所以我们改为固定目标——16.67 毫秒帧预算——把工作负载设为变量。每个场景逐步提高粒子数量,直到帧时间超出预算;随后通过二分搜索找到边界,再要求候选负载连续三个窗口干净通过。最终得到的“最大稳定负载”有直观的物理意义:这台设备最多能推动 840,000 个星云粒子而不开始掉帧。

倒置测量从结构上就能优雅应对弱设备:它不会跑出一个损坏的结果,只会停在同一把负载梯子的较低一级。

使用百分位数,因为卡顿会骗过平均值

每个窗口既要检查平均帧时间,也要检查第 95 百分位数。设置 p95 门槛,是因为平均值会替卡顿洗白:一台设备有 95 帧准时、5 帧耗时 40 毫秒,平均数据可能仍然漂亮,体感却很糟。百分位门槛能把“感觉很差”变成可测数字。单次异常窗口(例如通知或垃圾回收暂停)会重试,而不是直接计为失败;但连续失败两次就会否决该负载。它会原谅意外,不会原谅规律。

近乎多疑的状态机

“不能卡死”的要求催生了项目中最不光鲜、却最关键的一段代码。每个场景都会经过状态机——预检、基线、预热、爬升、夹逼、确认、锚点——而且每个状态都有明确出口:

  • 每个场景最多 30 秒,整次运行最多 150 秒,没有例外;
  • 切到后台会作废当前测量窗口并暂停;隐藏超过 30 秒,测试会以明确原因结束;
  • 窗口大小或像素比变化时,系统会重建场景并重新预热,不会拿垃圾数据计分;
  • WebGL 上下文丢失、GPU 卡住(数秒没有新帧)、场景抛出错误,各自对应独立的退出原因;即使渲染循环停摆,看门狗定时器仍会继续运行;
  • 在以上每一种状态中,Escape 都能退出。只有一切正常时才有效的取消按钮,不能算取消按钮。

测试可以提前结束、带着性能下降标记结束,也可以被取消;唯一不会发生的事情,是永远停在那里。

诚实面对温度

持续 GPU 负载会加热设备,设备升温后会降速;忽略这一点的基准,只会悄悄把机器最好的一分钟和最差的一分钟揉进平均值。因此,每个场景都会两次测量轻量基线——开始一次、结束一次。如果第二次慢 15% 以上,该场景就会被标记为性能下降;标记会保留在结果和分数中(扣分有上限),如果用户提交样本,也会进入数据集,让公开中位数能够排除热降频测试,而不是把它们吸收进去。

公平对待高刷新率

这里有个不明显的陷阱:如果按各自刷新间隔判断,120Hz 笔记本必须在 8.3 毫秒内绘制每一帧才算“跟上刷新”,承担的要求是 60Hz 设备的两倍。我们的预算对所有设备都固定在 16.67 毫秒。高刷屏仍能体现优势(轻负载时显示更多帧),但不同面板的及格线完全相同。显示器是观看方式的选择;基准测试的任务,是测量它背后的电脑。

我们有意没有加入的东西

目前没有 WebGPU——将来若加入,它也会作为独立配置,拥有自己的计分空间,绝不会在同一个数字下面悄悄替换实现。本版本也没有使用 Web Worker 渲染:Worker 终止、上下文转移、跨线程输入等额外故障面,与“永不挂起”的要求相冲突,而两种方案的被测工作负载相同。最后,在匿名数据集达到真正有意义的样本门槛前,结果页不会声称任何百分位排名——拿 40 次测试计算百分位,只是给感觉套上一件数字外衣。

包括计分公式在内的完整规范,已写在方法说明中。如果你发现任何设备不符合上述保证,那就是程序错误,请联系 admin at screentest.pro。