MotionMark 是 Apple 开发的一个浏览器图形性能测试套件,用来测试和评估 Safari/WebKit 的图形性能,这里的图形性能并不仅仅包括光栅化和合成,而是涵盖了完整的浏览器渲染流水线,包括 DOM API,样式计算,排版等。
MotionMark 虽然不能涵盖浏览器图形性能的所有方面,但是作为衡量浏览器图形性能的其中一项指标,还是有不错的参考价值。Chromium 目前也会使用 MotionMark 分数作为其中一项指标来衡量自身图形性能优化的成果。
关于浏览器渲染请参考我之前的一些文章,比如渲染流水线中的光栅化。
MotionMark 的一个主要特性是自适应动态调整测试的复杂度,从而更好地适应不同的设备,这些设备的性能可能差异很大,比如 PC 的性能通常几倍甚至十倍于移动设备。MotionMark 的每一项测试都包含一个连续的动画,它收集动画每一帧的复杂度和耗时等数据,然后计算出一个分数(复杂度越高,耗时越少,分数就越高),最后根据所有项目的成绩计算出一个总得分,分数越高代表性能越好。
因为 MotionMark 动态调整复杂度的缘故,导致测试的结果波动较大,所以除了分数外,测试还给出一个波动范围,通常需要测试多次,取波动值较小的为准。
这篇文章主要分析 MotionMark 每一项测试的测试内容,在 Chromium 上,该项测试的主要性能瓶颈在哪里,是在 DOM,是在样式计算和排版,还是在光栅化和合成。如果读者对浏览器的图形性能感兴趣,可以通过这篇文章更好地了解如何通过 MotionMark 的成绩来衡量浏览器的图形性能。
用于分析的 Chromium 版本是 Chrome 77 for Android,我们可以看到从 75 开始,Chrome for Android 已经正式开启了 OOPR,普通图层分块光栅化的主要耗时从原来的光栅化线程(CompositorTileWorker)相当大的一部分转移到了 GPU 线程(CrGpuMain),光栅化的耗时在两个线程上都有一定的比例。测试的设备是 Google Pixel 手机。因为不同的设备有可能有不同的性能瓶颈,所以文章的结论不是普适的,只能作为一个参考。
各项测试分析
Multiply
测试 CSS border radius,transform,opacity 动画的性能。测试过程中不断改变一组 div 元素的样式,包括背景色(带半透明),transform 和可见性,div 设置了 border radius 属性用来绘制圆角。
在 Chromium 上,主要的性能瓶颈是在 Renderer,耗时最多的部分是 DOM API(改变样式),样式计算,重排版,图层树更新(重新绘制),图层光栅化部分耗时也较多,但是相对而言较前者要少。留意上图 CrRendererMain 和 CrGpuMain 线程上调用耗时的比例。
Canvas Arcs
测试 Canvas 路径绘制(弧形路径,包括描边和填充)的性能。
在 Chromium 上,主要的性能瓶颈是在 Renderer,耗时最多的部分是 DOM API(Canvas API),和 Skia 的路径绘制(Canvas 的光栅化)。
Leaves
测试 CSS transform 动画的性能,大量的较小的 img 元素在动画过程被改变 transform。
这个测试在 Chromium 上的结果比较吊诡,并不能真实反映 Chromium 在普通页面上 CSS transorm 动画的性能(通常只有少量元素同时做 transform 动画)。测试使用了大量尺寸较小的 img 元素,触发了 Chromium 的图层合并特性,将大量的小图层合并成一个大图层,它的副作用是导致了反复的图层重复光栅化。从上图可以看到,无论是在 Renderer 上的 DOM API(改变样式)和样式计算的耗时,还是图层光栅化的耗时(分布在光栅化线程和 GPU 线程)都不低,两者都可能成为性能瓶颈。
Canvas Paths
跟 Canvas Arcs 类似,也是测试 Canvas 路径绘制的性能,只是不是弧形而是各种不同的曲线。
Chromium 的性能瓶颈跟 Canvas Arcs 类似,主要的性能瓶颈是在 Renderer,耗时最多的部分是 DOM API(Canvas API),和 Skia 的路径绘制(Canvas 的光栅化)。
Canvas Lines
跟 Canvas Arcs/Paths 类似,测试 Canvas 线段绘制的性能。
Chromium 的性能瓶颈跟 Canvas Arcs/Paths 类似,主要的性能瓶颈是在 Renderer,耗时最多的部分是 DOM API(Canvas API),和 Skia 的线段绘制(Canvas 的光栅化)。
Focus
测试 CSS blur 和 opacity filter 动画的性能。动画过程中不断改变一组 div 元素的 transform 和 blur & opacity filter 的值。
Chromium 的主要性能瓶颈是在 GPU 线程的合成上,也就是 blur & opacity filter 效果的绘制。Renderer 在 DOM API(改变样式)上也有一定的开销,但是相对合成来说还是较低。
Images
测试 Canvas getImageData 和 putImageData 的性能。动画过程中通过 get/putImageData 不断改变一组尺寸较小的 canvas 元素的内容。
Chromium 悲剧地因为 getImageData 被阻塞,GL readPixels 从 GPU 读取纹理数据到 CPU 内存非常耗时。Safari 在这项上应该会有巨大的优势 -_-p
Design
测试大量重复但是使用不同颜色的文本绘制的性能,重复的文本因为 transform 和 color 的差异形成投影的效果。动画过程中不断改变文本元素的 transform 和 color 属性。
Chromium 主要的性能瓶颈反而是在 Renderer 的样式计算上面,文本的光栅化耗时也不少,不过比起 Renderer 的耗时稍微略少,也可能成为瓶颈。
Suits
大量使用不同的非矩形裁剪,不同渐变色,不同 transform 矩阵的 svg 元素的绘制,测试 svg 的绘制性能。
Chromium 在图层光栅化(SVG 的绘制)和 Renderer 的样式计算上耗时都不低,两者都有可能成为性能瓶颈。
结语
跟很多人第一直觉并不完全符合的是,浏览器的图形性能瓶颈,很多时候并不在真正的“图形”上面,也就是说光栅化和合成有时并不是动画的性能瓶颈,有时性能瓶颈反而是在 JavaScript(包括计算和 DOM API 调用),样式计算,和重排版上。当然,MotionMark 是一项压力测试,实际的应用中我们可能很少同时改变那么多元素的属性,但是如果页面碰到性能问题,在检查性能瓶颈时,这也是需要考虑的一个因素。