宣布 JetStream 1.1
JetStream 是 WebKit 开发者用于调整 JavaScript 引擎性能的基准测试套件。它包括衡量 JavaScript 引擎启动和最坏情况执行时间的延迟基准测试,以及衡量稳定状态下平均吞吐量的吞吐量基准测试。我们希望 JetStream 能准确反映我们的性能目标——提高分数的改变也应该改善用户体验。今天,我们很高兴宣布推出 JetStream 1.1,它提高了套件延迟组件的准确性。JetStream 1.1 修复了两个现有测试中的错误,并添加了一个新测试,以替代延迟组件中最旧、最小的测试。
一种评估响应性得分的合理方法
JetStream 的延迟组件主要由测量首次执行代码时产生的延迟的测试组成。但它也包含两个测试,splay-latency 和 mandreel-latency,它们的得分反映了浏览器最坏情况性能与平均情况性能的接近程度。splay-latency 上的相对高分表示浏览器的垃圾回收器干扰 Web 应用响应性的可能性较小。mandreel-latency 类似,但由于其更大的代码库和更低的分配率,它主要测试浏览器的即时编译(JIT)器是否干扰响应性。这两个测试都源自 Octane version 2 基准测试套件。
splay-latency 和 mandreel-latency 旨在奖励响应速度快的浏览器。一个响应速度快的浏览器总是能快速执行任务,而不是通常执行得很快但有时会出现性能骤降的情况。但这些测试使用错误的指标来计算响应性得分:它们首先计算数千个样本的均方根(RMS),然后报告一个 RMS 倒数作为得分。结果发现,这个数字并不能充分奖励响应性出色的浏览器,在某些情况下,它甚至给响应性较差的浏览器打出了高分。
例如,考虑如果浏览器 A 总是以 20 毫秒的速度运行一个任务,而浏览器 B 以相同概率随机地以 10 毫秒或 5 毫秒的速度运行同一任务会发生什么。显然,浏览器 B 会显得更具响应性——它总是至少比浏览器 A 快两倍完成任务。但是,使用 RMS 作为延迟指标意味着浏览器 A 获得了更高的分数:因为它的性能始终是 20 毫秒,它的 RMS 将为零,从而导致延迟分数为 1/0,即无穷大。浏览器 B 的 RMS 大约是 3.5,导致分数为 1/3.5,即小于无穷大。撇开浏览器获得无限分数这一荒谬之处——这也是我们想要阻止的——很明显,尽管浏览器 A 总是响应性较差,但它在这些测试中获得了更高的分数。我们希望能够使用这些测试来调整 WebKit 的响应性:我们希望接受能提高分数的更改,并拒绝那些降低分数的更改。但如果分数奖励了不良行为,我们就无法做到这一点。
原因是,当任何一个方向出现异常值时,RMS 都会增加(并且 1/RMS 分数会降低)。好的异常值(浏览器有时完成任务比正常情况快得多)和坏的异常值(浏览器有时花费很长时间)都会以相同的量增加 RMS。我们想要的是一个单边指标,它惩罚坏的异常值而忽略好的异常值——我们乐于接受浏览器有时比平均水平快得多,只要最坏情况仍然很棒。
最简单的解决方案是根据这些测试所进行的数千次执行中最慢的一次执行来计算分数。这样做很诱人,但它会带来一个代价:最坏情况可能是一个嘈杂的数字。我们希望减少测量噪音,因为我们希望能够自信地测量代码不同版本之间的小性能差异。在减少噪音的同时获得最坏情况测量大部分好处的一种简单方法是取所有样本中0.5%最差的样本并报告它们的平均值。
使用最差样本的平均值永远不会因为浏览器有时运行速度比正常快而惩罚它们。它精确地抓住了我们所说的响应性:即浏览器在最坏情况下的运行速度。考虑这会如何影响 splay-latency。高于 99.5 百分位的样本——在一次典型的 splay 运行中大约有 10 个样本——正是 WebKit 垃圾回收器必须进行堆完全扫描的时候。能够将堆扫描分成更小的、不会导致长时间停顿的工作块的浏览器将在此测试中得分更高。splay-latency 和 mandreel-latency 的分数很容易理解:如果一个浏览器得分比另一个高 2 倍,这意味着该浏览器偶尔的性能问题将减轻 2 倍。
splay-latency 和 mandreel-latency 测试的改进由 WebKit 错误 145762 和 146378 跟踪。
介绍 CDjs
JetStream 包含许多来自旧基准测试套件(如 SunSpider 和 V8)的遗留基准测试。其中大多数测试仍然相关,因为它们具有非平凡的工作负载,代表了我们认为开发人员希望在 JavaScript 中高效完成的工作。但我们可以通过逐步用更大、更复杂的测试替换最小、最微不足道的测试来进一步改进基准测试套件。我们在 JetStream 1.1 中朝着这个方向迈出了一小步,用一个名为 CDjs 的新测试取代了 cordic,后者以前是最小的延迟测试,只有 80 行非注释代码,而 CDjs 则复杂得多。
CDjs 是我们用 JavaScript 实现的 CDx 实时基准测试。CDx 是一个碰撞检测基准测试,其中飞机在模拟空域中飞行,通过插值记录帧之间的飞行路径来报告碰撞。CDx 以前曾用 Java 和 C 实现,并 被 用于 比较这些语言的最坏情况性能。CDx 通常运行数百甚至数千次迭代,性能结果根据最坏情况执行计算。这使得 CDx 自然成为 JetStream 延迟组件的候选。CDjs 是 CDx Java 实现(也称为 CDj)的直接移植,但有两处改动:
1. CDjs 使用红黑树而不是哈希表进行各种映射。这使得 CDjs 在实时概念上稍微更忠实,因为哈希表可能会因冲突而出现随机的最坏情况病理。此外,虽然我们曾想在 CDjs 中使用 ES6 中的新 Map API,但由于它需要使用对象的values作为键而不是对象标识,因此未能实现。红黑树实现是 WebKit 现有红黑树 的移植。 2. CDjs 没有像 CDj 那样积极地重用对象。这使得 CDjs 更忠实于 CDx 试图提出的实验性问题:当您用高级语言编写实时工作负载时,运行速度会慢多少?如果高级程序充分利用了高级语言的特性(例如垃圾回收),那么答案就更有意义。
我们通过模拟 1000 架偶尔会发生碰撞的飞机来运行 CDjs 作为基准测试。我们运行该基准测试 200 帧。这使得该基准测试在现代浏览器和典型笔记本电脑上运行大约一秒钟。分数为这 200 帧中 10 个最差执行时间的平均值的倒数。此基准测试的添加不会改变 JetStream 在延迟和吞吐量之间的整体权重,尽管它确实将延迟的定义转向了许多样本的最坏情况,而不是冷启动的成本。
CDjs 加入 JetStream 的进展由 WebKit 错误 146156 跟踪。
结论
我们很高兴推出 JetStream 基准测试套件的这一重要更新。此更新使 JetStream 的延迟指标比以前更加准确。新的套件现已可在 browserbench.org/JetStream/ 上运行。一如既往,如果您在此基准测试中发现任何问题,请在 bugs.webkit.org 提交错误报告。