asm.js 是一个易于优化的 JavaScript 子集。它可以在所有浏览器中运行,无需插件,并且是移植 C/C++ 代码库(例如游戏引擎)的理想目标——事实上,游戏引擎一直是这种方法的最大采用者,例如 Unity 3D 和 虚幻引擎。
显然,使用 asm.js 移植游戏的开发人员希望游戏在所有浏览器中都能良好运行。但是,每个浏览器都有不同的性能特征,因为每个浏览器都拥有不同的 JavaScript 引擎、不同的图形实现等等。在这篇文章中,我们将重点关注 JavaScript 执行速度,并了解 asm.js 执行速度在各个方面所取得的显著进展。现在让我们逐一介绍四大主流浏览器。
Chrome
早在 2013 年,Google 就发布了 Octane 2.0,这是其主要 JavaScript 基准测试套件的新版本,其中包含一个新的 asm.js 基准测试,zlib。基准测试定义了浏览器优化的方向:重要的内容会被纳入基准测试,然后浏览器会竞争以取得最佳分数。因此,将 asm.js 基准测试添加到 Octane 清楚地表明了 Google 相信 asm.js 内容对于优化至关重要。
最近,另一个重大进展是 Google 发布了TurboFan,这是一个用于 Chrome JavaScript 引擎v8 的新的正在开发中的优化编译器。TurboFan 具有“节点海洋”架构(这在 JavaScript 领域是一个新概念,但在其他领域,例如 Java 服务器虚拟机中已非常成功地应用),旨在比 v8 的第一个优化编译器 CrankShaft 达到更高的速度。
虽然 TurboFan 尚未准备好用于所有 JavaScript 内容,但从 Chrome 41 开始,它已启用 asm.js。尽早为 asm.js 提供 TurboFan 的优势表明了 Chrome 团队优化 asm.js 的重要性。这种优势相当显著:例如,TurboFan 将Emscripten 的 zlib 基准测试速度提高了13%,将 fasta 速度提高了24%。
Safari
在过去的一年里,Safari 的 JavaScript 引擎JavaScriptCore 引入了一种名为FTL 的新型 JIT(即时编译器)。FTL 代表“第四层 LLVM”,因为它在之前的三个优化层之上增加了第四层优化,并且它是基于LLVM 的,LLVM 是一种强大的开源编译器框架。这令人兴奋,因为 LLVM 是一种顶级通用编译器,经过多年的优化,Safari 可以利用所有这些努力。正如之前链接的博客文章中所示,FTL 提供的速度提升非常显著。
Apple 今年的另一个有趣发展是引入了一个新的 JavaScript 基准测试,JetStream。JetStream 包含多个 asm.js 基准测试,这表明 Apple 相信 asm.js 内容对于优化至关重要,就像 Google 将 asm.js 基准测试添加到 Octane 一样。
Internet Explorer
Internet Explorer 中的 JavaScript 引擎名为Chakra。去年,Chakra 团队发布博客文章介绍了即将在 Windows 10 中推出的优化套件,并指出 asm.js 工作负载在 Octane 和 JetStream 上取得了显著的性能提升。这再次证明了将 asm.js 工作负载纳入通用基准测试如何推动测量和优化。
然而,最大的消息是 Chakra 团队最近宣布他们正在努力添加特定的 asm.js 优化,这些优化将在 Windows 10 中与之前提到的其他优化一起推出。这些优化尚未出现在预览版中,因此我们无法在这里进行测量和报告。但是,我们可以根据 asm.js 优化在 Firefox 中首次推出产生的影响进行推测。正如这张包含首次推出后测量的基准测试对比幻灯片中所示,asm.js 优化使 Firefox 的速度立即提高到大约是原生性能的 2 倍(之前是原生性能的 5-12 倍)。为什么这些优势会迁移到 Chakra?因为,正如我们之前发布的文章中所解释的那样,asm.js 规范提供了一种可预测的方式来验证 asm.js 代码并根据结果生成高质量的代码。
因此,让我们期待在 Windows 10 中获得良好的 asm.js 性能!
Firefox
正如我们之前提到的,asm.js 优化在 Firefox 中的首次推出通常使 Firefox 的原始吞吐量达到原生性能的 2 倍以内。到 2013 年底,我们可以报告称差距已缩小到大约是原生性能的 1.5 倍——这与不同原生编译器之间的差异非常接近,因此与“原生速度”的比较意义不大。
从高层次上看,这种进步来自两种类型的改进:编译器后端优化和新的 JavaScript 功能。在编译器后端优化领域,有一系列微小的改进(针对特定代码模式或硬件),很难指明任何一项。不过,有两项重大改进非常突出:
- 一种新的寄存器分配算法,基于LLVM 3.0 中的新寄存器分配器:虽然速度提升会有所不同,但一个值得注意的例子是在 Google 的Octane 基准测试 中的 zlib 部分,最初在 x86 上提高了 20%,在改进后又提高了 4%;以及
- 有效地址 优化:在 Firefox Nightly 中最近添加的功能,在堆访问密集型工作负载中提高了 5% – 10% 的速度。
除了后端优化工作之外,还有两个新的 JavaScript 功能已合并到 asm.js 中,这为硬件解锁了新的性能能力。第一个功能,Math.fround,可能看起来很简单,但它使编译器后端能够在 JS 中谨慎使用时生成单精度浮点运算。正如这篇文章中所述,这种切换可以使速度提高 5% – 60%,具体取决于工作负载。第二个功能更大:SIMD.js。这仍然是ES7 的第一阶段提案,因此新的 SIMD 操作以及相关的asm.js 扩展只在Firefox Nightly 中可用。初步结果很有希望。
除了所有这些吞吐量优化之外,Firefox 还进行了一系列加载时间优化:在主线程之外并行编译 asm.js 代码,以及缓存已编译的机器代码。正如这篇文章中所述,这些优化显著改善了启动 Unity 或 Epic 规模的 asm.js 应用程序的体验。上面提到的基准测试中现有的 asm.js 工作负载不会测试 asm.js 性能的这一方面,因此我们组建了一个名为Massive 的新基准测试套件,该套件专门测试这一方面。从Firefox 的 Massive 得分随时间的变化来看,我们可以看到加载时间优化使性能提高了 6 倍以上(有关详细信息,请参阅 Hacks 博客文章,介绍Massive 基准测试)。
结论
最终,最重要的不是底层的实现细节,甚至不是特定基准测试上的特定性能数字。真正重要的是应用程序的运行状况。检查这一点的最佳方法是实际运行真实世界的游戏!Dead Trigger 2 是一个使用 asm.js 的游戏的很好的例子,它是一款 Unity 3D 游戏。
视频显示了该游戏在 Firefox 上运行,但由于它只使用标准 Web API,因此它应该可以在任何浏览器中运行。我们现在试了一下,它在 Firefox、Chrome 和 Safari 上运行得很流畅。我们也期待在 Internet Explorer 的下一个预览版中对其进行测试。
另一个例子是Cloud Raiders
与 Unity 一样,Cloud Raiders 的开发人员能够将他们现有的 C++ 代码库(使用Emscripten)编译为在 Web 上运行,而无需依赖插件。最终的结果可以在四大主流浏览器中都很好地运行。
总之,asm.js 性能在过去一年取得了长足进步。 当然还有提升的空间 - 有时性能并不完美,或者某个特定 API 在某个浏览器中缺失 - 但所有主要浏览器都在努力确保 asm.js 能够快速运行。我们可以通过查看它们优化的基准测试(包含 asm.js)以及它们在 JavaScript 引擎中实施的新改进(通常受 asm.js 推动)来观察这一点。因此,不久前需要插件才能运行的游戏,现在很快就能在 Web 上的现代浏览器中流畅地运行,无需插件。
关于 Alon Zakai
Alon 是 Mozilla 研究团队的成员,主要从事 Emscripten 的开发工作,Emscripten 是一个将 C 和 C++ 编译成 JavaScript 的编译器。Alon 于 2010 年创立了 Emscripten 项目。
关于 Luke Wagner
Luke Wagner 是 Mozilla 的软件工程师,在 Firefox 中开发 JavaScript 和 WebAssembly。
10 条评论