MotionMark
一个新的图形基准测试工具
与 Said Abou-Hallawa 和 Simon Fraser 共同撰写

今天,我们很高兴推出MotionMark,一个针对网页浏览器的新图形基准测试工具。
我们看到网络以惊人的方式发展,成为一个功能丰富的平台,能够运行复杂的网络应用,呈现精美的网页,并提供快速、响应迅速且视觉流畅的用户体验。随着 CSS 动画、SVG 和 HTML5 canvas 等网络标准的开发和广泛采用,网络开发者创建引人入胜且复杂的体验比以往任何时候都更容易。由于这些技术依赖于浏览器图形系统的性能,我们创建了这个基准测试工具来对其进行测试。
我们想谈谈这个基准测试工具是如何工作的,它是如何帮助我们改进 WebKit 性能的,以及未来的发展方向。
现有图形基准测试的局限性
我们需要一种方法来监控和衡量 WebKit 的渲染性能,并寻找一个图形基准测试工具来指导我们的工作。大多数图形基准测试工具通过固定场景动画的帧率来衡量性能,但我们发现它们的方法存在几个缺点。
首先,一些测试工具使用 setTimeout()
来驱动测试并计算帧率,但这可能会以超过每秒 60 帧(fps)的速度触发,导致测试尝试渲染比用户可见更多的帧。由于浏览器和操作系统通常有机制来避免生成用户永远看不到的帧,因此此类测试会遇到这些节流机制。实际上,它们只测试了在帧丢失时避免工作的优化,而不是整个图形堆栈的能力。
其次,我们发现大多数基准测试工具并非旨在适应各种设备。它们未能根据具有不同性能特征的硬件调整其测试,也未能为未来的硬件和软件改进留出余地。
最后,我们发现基准测试工具通常一次测试太多东西。这使得很难解释它们的最终得分。它也阻碍了迭代地改进 WebKit 性能的工作。
MotionMark 的设计
我们希望在 MotionMark 中避免这些问题。因此,我们按照以下原则设计了它:
- 峰值性能。 MotionMark 不会动画固定场景并测量浏览器的帧率,而是运行一系列测试,测量每个测试中的场景在低于我们选择的 60 fps 阈值帧率之前可以变得多复杂。方便的是,它将复杂性报告为测试的得分。通过使用
requestAnimationFrame()
而不是setTimeout()
,MotionMark 避免了以超过 60 fps 的帧率进行绘制。 - 测试简洁性。 MotionMark 测试不动画一个利用所有图形原语的复杂场景,而是绘制多个渲染元素,每个元素都使用相同的少量图形原语。一个元素可以是 SVG 节点、带有 CSS 样式的 HTML 元素,或者一系列 canvas 操作。元素之间的细微变化避免了浏览器进行简单的缓存优化。尽管相当简单,但所选效果旨在反映网络上常用的技术。测试视觉效果丰富,旨在强调图形系统而不是 JavaScript。
- 快速运行。 我们希望基准测试工具方便快捷地运行,同时保持准确性。MotionMark 在相同的时间段内运行每个测试,并从相对较少的动画帧样本中计算得分。
- 设备无关。 我们希望 MotionMark 能够在各种设备上运行。它根据设备的屏幕尺寸调整绘制区域(称为舞台)的大小。
机制
MotionMark 的测试工具包含三个组件:
- 动画循环
- 舞台
- 一个调整测试难度的控制器
动画循环使用 requestAnimationFrame()
来动画场景。帧率的测量是通过使用 performance.now()
计算帧时间戳之间的差异来完成的。
在动画循环的每一帧中,该工具允许测试以指定数量的渲染元素来动画场景。这个数量被称为场景的复杂性。每个元素大致代表相同的工作量,但在大小、形状或颜色上可能略有不同。例如,“Suits”测试渲染带有渐变填充和剪切的 SVG 矩形,但每个矩形的渐变都不同,其剪切是四种形状之一,并且其大小在狭窄范围内变化。
舞台包含动画场景,其大小取决于窗口的尺寸。该工具将尺寸分为三种大小:
- 小:568 x 320,面向手机
- 中:900 x 600,面向平板电脑和笔记本电脑
- 大:1600 x 800,面向桌面电脑
控制器有两个职责。首先,它监控帧率并根据数据通过添加或移除元素来调整场景复杂性。其次,它在测试结束时向基准测试工具报告得分。
MotionMark 对套件中的每个测试都使用这个工具,并取测试得分的几何平均值来报告一次运行的单一得分。
MotionMark 的开发
该基准测试工具的架构模块化使得我们能够在开发过程中进行快速迭代。例如,我们可以迭代控制器如何调整正在运行的测试的复杂性。
我们最初尝试编写控制器时,试图达到精确的阈值或变化点,超过该点系统将无法维持 60 fps。例如,我们尝试让控制器对正确的变化点执行二分查找。在浏览器级别测试图形性能固有的测量噪声要求控制器运行很长时间,这不符合我们对基准测试工具的要求之一。在另一个例子中,我们使用工业控制系统中的技术编写了一个反馈循环,但我们发现当浏览器在压力下表现不同时(例如从 60 fps 直接降到 30 fps),结果不稳定。
因此,我们改变了焦点,不再编写在测试结束时找到变化点的控制器,而是编写一个采样狭窄范围(可能包含变化点)的控制器。通过这种方式,我们能够在相对较短的时间内获得可重复的结果,并且适用于各种浏览器行为。
MotionMark 中使用的控制器分两个阶段动画场景。首先,它通过指数级增加场景的复杂性来找到上限,直到其显著低于 60 fps。其次,它进行一系列迭代,重复从高复杂性开始到低复杂性结束。每次迭代(称为坡道)都会越过变化点,在较高边界处场景动画速度低于 60 fps,在较低边界处动画速度为 60 fps。通过每次坡道,控制器试图使边界收敛,以便测试在最相关的复杂性范围内运行。
通过收集到的样本数据,控制器使用最小二乘法计算分段回归。这种回归对复杂性增加如何影响浏览器做出了两个假设。首先,它假设浏览器在达到变化点之前以 60 fps 的速度动画。其次,它假设当复杂性超过变化点时,帧率要么线性下降,要么跳到较低的速度。测试的得分就是变化点。得分的置信区间是使用一种称为自举法的方法计算的。
MotionMark 的模块化架构使得编写新测试变得快速而容易。我们还可以通过替换舞台来在视觉上复制测试,但使用包括 DOM、SVG 和 canvas 在内的不同技术。
创建一个新测试需要实现渲染元素和舞台。舞台需要覆盖 Stage
类的三个方法:
animate()
更新动画并渲染一帧。这在requestAnimationFrame()
循环内被调用。- 当控制器决定更新动画的复杂性时,会调用
tune()
。舞台被告知要从场景中添加或移除多少元素。 complexity()
简单地返回舞台中正在绘制的渲染元素的数量。
因为一些图形子系统在检测到静态场景时会尝试降低其刷新率,所以测试必须这样编写:场景在每一帧都发生变化。此外,与每个渲染元素相关的工作量必须足够小,以便所有系统都能以 60 fps 的速度至少动画其中一个元素。
MotionMark 的测试范围
MotionMark 的测试套件涵盖了网页开发者可用的各种图形技术:
- Multiply:CSS 边框半径、变换、不透明度
- Arcs and Fills:Canvas 路径填充和圆弧
- Leaves:CSS 变换的
<img>
元素 - Paths:Canvas 直线、二次曲线和贝塞尔曲线路径
- Lines:Canvas 线段
- Focus:CSS 模糊滤镜、不透明度
- Images:Canvas
getImageData()
和putImageData()
- Design:HTML 文本渲染
- Suits:SVG 剪切路径、渐变和变换
我们希望随着基准测试工具的成熟和图形性能的提高,能扩展和更新这个套件,增加更多测试。
WebKit 中的优化
MotionMark 不仅仅让我们能够监控 WebKit 的性能;它成为了一个重要的开发工具。由于每个 MotionMark 测试都专注于少数图形原语,我们可以轻松识别渲染瓶颈,并分析给定代码更改的权衡。此外,我们还可以确保对引擎的更改不会引入新的性能倒退。
例如,我们发现 WebKit 在某些代码路径中花费时间仅仅用于保存和恢复图形上下文的状态。这些操作开销很大,并且它们发生在关键代码路径中,而这些路径中只有少数属性(如变换)正在被更改。我们用显式设置和恢复这些属性的方式替换了这些操作。
在 iOS 上,我们在基准测试中的追踪显示 requestAnimationFrame()
存在一个微妙的时间问题。CADisplayLink
用于将绘图与显示器的刷新率同步。当其计时器触发时,当前帧被绘制,如果绘制完成,则会为下一帧调用 requestAnimationFrame()
处理程序。如果当下一帧的计时器触发时绘制未能及时完成,那么当绘制最终完成时,计时器不会立即重置,这导致了一帧的延迟,并有效地将动画速度减半。
这些只是我们通过分析运行 MotionMark 时收集的追踪数据,从而诊断和修复的问题中的两个例子。因此,我们得以提高 MotionMark 的分数。
结论
我们很高兴推出这个新的基准测试工具,并将其作为改进 WebKit 性能的工具。我们希望更广泛的网络社区能加入我们。要运行它,请访问 http://browserbench.org/MotionMark。我们欢迎您使用 WebKit 的错误管理系统在 Tools/Tests 组件下提交针对该基准测试工具的错误。如有任何意见或问题,请随时通过 Twitter 联系 WebKit 团队 @WebKit 或我们的网络技术布道师 Jonathan Davis @jonathandavis。