Google 表格是 Google 首批在 Chrome 上使用 WasmGC 的产品之一。这一举措于 2022 年宣布,Google 表格和 Chrome 团队在标准化、工程设计和工具方面开展合作,以提供有关优化的实时反馈。这一合作伙伴关系为 Google 的工程团队如何有效地与 Chrome 合作,以便在 WasmGC 上运行更多 Google 应用树立了先例。
挑战:JavaScript
Google 表格计算引擎最初是用 Java 编写的,于 2006 年推出。在产品推出的早期,所有计算都在服务器上进行。不过,自 2013 年以来,该引擎已开始在浏览器中使用 JavaScript 运行。最初,这是通过 Google Web Toolkit (GWT) 实现的,后来通过 Java 到 Closure JavaScript 转译器 (J2CL) 实现。JavaScript 计算引擎在 Web Worker 中运行,并使用 MessageChannel 与主线程通信。
将用户从服务器迁移到 JavaScript 版本的计算引擎(后来又从 GWT 迁移到 J2CL)是一项重大任务,需要仔细验证。为了确保 JavaScript 计算引擎生成的结果与 Java 版本完全相同,Google 表格团队开发了一种内部验证机制。此机制可以处理大量工作表,并验证多个版本的计算引擎的结果是否相同。Google 表格团队会定期使用此工具来验证对 Google 表格的更改。但该团队不仅比较了这些计算的结果,还比较了客户端上的 JavaScript 和服务器上的 Java 之间的性能。他们发现,JavaScript 版本的计算引擎比 Java 版本慢了三倍以上。
为什么 JavaScript 比 Java 慢?
对于一种松散类型的动态语言,JavaScript 的速度非常快。过去 15 年来,对即时 (JIT) 编译器(例如 Maglev、Sparkplug 和 Turbofan)的大力投资提高了 JavaScript 的性能。不过,JavaScript 的松散类型和动态行为使得 JIT 编译器难以生成最佳代码。这意味着,在原始吞吐量方面,JavaScript 仍然落后于 Java 和 C++ 等语言。TypeScript 为 JavaScript 添加了类型安全功能,但该类型信息旨在简化开发,而不是提供编译器生成最佳代码所需的保证。对于 Google 表格等情况,大型电子表格可能需要数十秒才能完成计算,此时 JavaScript 速度很快,但还不够快。
解决方案:WasmGC
WasmGC 是对现有 WebAssembly 规范的扩展,它添加了编译垃圾回收语言(例如 Java)所需的原语。例如,WasmGC 添加了用于定义类型和分配垃圾收集数据结构的指令。WasmGC 将为垃圾回收语言带来 Wasm 为 C++(例如 Photoshop 或 Google 地球)带来的好处,即以接近原生速度将它们带到 Web 上。在 Google,我们认为 WasmGC 有望比 Wasm 产生更大的影响,因为垃圾回收语言非常受欢迎。
Google Workspace 与 Chrome 携手合作
WasmGC MVP 草稿规范于 2019 年发布。2020 年底,Google Workspace 和 Chrome 合作使用 Google 表格计算引擎评估了 WasmGC。Workspace 的多平台团队在构建和优化编译器和转译器方面拥有丰富的专业知识。作为 Workspace 的一部分,Google 表格被确定为评估 WasmGC 的理想候选对象:它对性能非常敏感,并且具有强大的性能和正确性验证机制。Chrome 有 V8 团队来构建和优化 WasmGC 运行时,还有 Binaryen 的贡献者来构建提前编译 (AOT) 优化。Chrome 和 Workspace 团队拥有构建和优化 WasmGC 工具链所需的所有专业知识,而 Google 表格是理想的测试平台。
第一个原型
到 2021 年年中,团队已开发出可正常运行的 Java 到 WasmGC 编译器。同年年底,他们推出了一个以 WasmGC 运行并进行计算的 Google 表格原型版本。在此过程中,他们遇到了许多挑战。当时没有用于分析和获取堆转储的工具,因此必须自行构建。现有实现依赖于许多 JavaScript 库,必须为这些库找到替代方案或为 WasmGC 编写替代方案。由于规范、编译器和新库都处于实验阶段,因此验证 Wasm 计算引擎的正确性非常耗时。但 Google 表格的验证机制再次发挥了巨大作用。最终,各团队成功解决了所有问题,并于 2022 年初开始接收效果数据。
其他优化
最初版本的 Google 表格 Wasm 的计算性能比 JavaScript 慢了大约两倍。不过,对于新规范、新编译器和多个新库而言,这不算糟糕。从那时起,Google 表格团队就开始进行优化。在他们发现的优化中,出现了以下几个类别:
- 复制 Java 虚拟机 (JVM) 和 V8 中已有的核心优化。
- 使用高度优化的浏览器 API。
- 移除特定于 JavaScript 的编码模式。
首先,Google 表格团队需要复制其他工具链中已有的优化。这方面最好的例子是优化虚拟方法调度,JVM 和 V8 长期以来一直在优化该调度,但 WasmGC 却没有任何相关优化。实施推测性内联和去虚拟化这两项非常常见的优化后,Chrome 中的计算时间缩短了大约 40%。
其次,在某些情况下,浏览器 API 由优化的原生实现提供支持,而使用 Wasm 很难与之竞争。字符串和正则表达式是两个很好的示例。具体而言,通过正则表达式,该团队发现从 re2j(编译为 WasmGC)切换到 Chrome 中的 RegExp 浏览器 API 时,正则表达式操作的速度提高了近 100 倍,该 API 可以将每个正则表达式编译为自己的机器代码。
最后,他们发现,多年的优化导致代码库过度拟合 JavaScript。例如,他们有一个 Google 表格中的核心数据结构,该结构模糊了数组和映射之间的界限。这在 JavaScript 中很高效,因为 JavaScript 会自动将稀疏数组建模为映射,但在其他平台上速度较慢。因此,他们不得不以更具平台无关性的方式重写代码。这是团队喜欢 WebAssembly 的另一个原因:它使多平台应用更容易在 Web 上获得良好的性能。您不必为了迎合 JavaScript 的特殊性而调整整个应用。
最终结果
经过所有这些优化后,最终的 WasmGC 版 Google 表格的计算性能大约是 JavaScript 的两倍,与初始 WasmGC 版本的起点相比,性能提高了四倍。
总结
WasmGC 是一项强大的技术,有望改进开发者构建 Web 应用的方式。未来几年,Google 希望看到 WasmGC 取得进展,支持共享内存多线程,并进一步提升单线程性能。我们鼓励所有 Web 开发者考虑在下一个高性能项目中使用 WasmGC。加入我们,一起让网络变得更快、更流畅!
致谢
感谢以下人员参与了 WasmGC 实现和本案例研究: Diwas Adhikary、 Matthew Albright、 Ksenia Bukina、 Julien Dramaix、 Asim Fazal、 Michael Frederick、 Goktug Gokdogan、 Janice Gu、 Adam Klein、 Manos Koukoutos、 Jakob Kummerow、 Matthias Liedtke、 Thomas Lively、 Roberto Lublinerman、 Vishrut Mehta、 Thomas Nattestad、 Josh Pearlstein、 Joaquim Perotti、 Chris Ruenes、 Steven Saviano、 Derek Schuff、 Tim Sears、 Michael Thomas、 Yuan Tian、 Philipp Weis、 Mason Wu、 Alon Zakai 和 Emanuel Ziegler。