Google 表格为何将其计算工作器从 JavaScript 移植到 WasmGC

Google 表格是 Google 首批在 Chrome 上使用 WasmGC 的产品之一。此举已于 2022 年宣布,Google 表格团队和 Chrome 团队就标准化、工程和工具展开合作,提供有关优化的实时反馈。这种合作伙伴关系开创了 Google 工程团队能够与 Chrome 高效协作的先例,让更多 Google 应用在 WasmGC 上运行。

挑战:JavaScript

Google 表格的计算引擎最初是用 Java 编写的,并于 2006 年推出。在产品开发初期,所有计算都在服务器上进行。但从 2013 年开始,该引擎已开始使用 JavaScript 在浏览器中运行。这一过程最初是通过 Google Web Toolkit (GWT) 完成的,后来通过 Java to Closure JavaScript 转译器 (J2CL) 完成。JavaScript 计算引擎在 Web Worker 中运行,并使用 MessageChannel 与主线程进行通信。

将用户从服务器迁移到 JavaScript 版本的计算引擎(之后从 GWT 迁移到 J2CL)是一项需要仔细验证的重要任务。为确保 JavaScript 计算引擎产生的结果与 Java 版本完全相同,Google 表格团队开发了一种内部验证机制。此机制可以处理大量工作表,并验证多个版本的计算引擎之间的结果是否相同。Google 表格团队会定期使用此工具来验证对 Google 表格所做的更改。但该团队并不只是比较这些计算的结果,而且还比较了客户端上的 JavaScript 与服务器上的 Java 的性能。他们发现 JavaScript 版本的计算引擎速度是 Java 版本的三倍以上。

为什么 JavaScript 比 Java 慢?

对于类型松散的动态语言,JavaScript 可以快速加载。过去 15 年来,我们对即时 (JIT) 编译器(例如 MaglevSparkplugTurbofan)进行了大量投资,提高了 JavaScript 的性能。然而,由于 JavaScript 的宽松类型和动态行为,JIT 编译器很难生成最佳代码。这意味着 JavaScript 在原始吞吐量方面仍然落后于 Java 和 C++ 等语言。TypeScript 为 JavaScript 添加了类型安全,但这种类型信息旨在简化开发,而不是提供编译器生成最佳代码所需的那种保证。在 Google 表格这样的情况下,大型电子表格的计算可能需要几十秒的时间,JavaScript 速度较快,但还不够快。

解决方案:WasmGC

WasmGC 是对现有 WebAssembly 规范的扩展,可添加编译垃圾回收语言(例如 Java)所需的基元。例如,WasmGC 添加了定义类型和分配垃圾回收数据结构的指令。WasmGC 准备处理垃圾回收语言,就像 Wasm 处理 C++(例如 PhotoshopGoogle 地球)一样,即将它们以近乎原生的速度引入网络。在 Google,我们相信,由于垃圾回收语言的流行,WasmGC 可能比 Wasm 更具影响力。

Google Workspace 与 Chrome 合作

WasmGC MVP 规范草案于 2019 年发布。2020 年底,Google Workspace 和 Chrome 合作,使用 Google 表格的计算引擎评估 WasmGC。Workspace 的多平台团队在构建和优化编译器与转译器方面拥有深厚的专业知识。作为 Workspace 的一部分,Google 被确定为评估 WasmGC 的理想候选版本:它对性能敏感,并且具有强大的性能和正确性验证机制。Chrome 拥有可构建和优化 WasmGC 运行时的 V8 团队以及 Binaryen 的贡献者,用于构建预先 (AOT) 优化。Chrome 和 Workspace 都具备构建和优化 WasmGC 工具链所需的所有专业知识,Google 表格是理想的测试平台。

首个原型

到 2021 年年中,该团队已经开发了一个有效的 Java 到 WasmGC 编译器。同年年底,他们开发了以 WasmGC 格式运行并执行计算的 Google 表格原型。在这个过程中,他们遇到了许多挑战。用于分析和获取堆转储的工具不存在,必须构建。现有的实现依赖于许多 JavaScript 库,必须为 WasmGC 找到或编写相应的替换库。由于规范、编译器和新库的实验性质,验证 Wasm 计算引擎的正确性非常耗时。不过,Google 表格的验证机制同样非常有用。最终,团队一切顺利进行,性能数据已于 2022 年初开始提供。

其他优化措施

初始版本的 Sheets Wasm 的计算性能比 JavaScript 大约两倍。不过,这对于新规范、新编译器和几个新库来说并不是一个糟糕的结果。此后,表格团队就开始进行优化了。在他们发现的优化中,有以下几个类别:

  • 复制 Java 虚拟机 (JVM) 和 V8 中已有的核心优化。
  • 使用高度优化的浏览器 API。
  • 移除 JavaScript 特有的编码模式。

首先,表格团队需要复制其他工具链中已有的优化方法。这方面的最佳示例是优化虚拟方法调度,JVM 和 V8 已对其进行了很长时间的优化,但 WasmGC 一无所获。通过实现推测性内嵌去虚拟化(这两项常见的优化措施),可将 Chrome 中的计算时间缩短约 40%。

其次,在某些情况下,浏览器 API 由经过优化的原生实现提供支持,很难使用 Wasm 来竞争。字符串和正则表达式就是两个很好的例子。具体而言,使用正则表达式时,该团队从 re2j(已编译为 WasmGC)切换到 Chrome 中的 RegExp 浏览器 API(可将每个正则表达式编译为自己的机器代码),该团队发现正则表达式操作的速度快了近 100 倍。

最后,他们发现,多年来的优化导致代码库与 JavaScript 过度拟合。例如,他们在 Google 表格中采用了核心数据结构,使数组和映射之间的线条模糊不清。这在 JavaScript 中非常高效,因为 JavaScript 会自动将稀疏数组建模为映射,但在其他平台上速度会很慢。因此,他们必须以与平台无关的方式重新编写代码。该团队同样喜欢 WebAssembly:它让多平台应用能够更轻松地在网络上实现良好性能。您不必将整个应用程序都受 JavaScript 的特性限制。

最终结果

经过上述所有优化后,最终版本的 WasmGC 表格的计算性能大约是 JavaScript 的两倍,表示与初始 WasmGC 版本相比,WasmGC 版本提高了四倍。

总结

WasmGC 是一项强大的技术,有可能推动开发者构建 Web 应用的方式。在未来几年,我们希望 WasmGC 在 Google 实现进步,以支持共享内存多线程,并进一步提升单线程性能。我们建议所有 Web 开发者考虑在下一个高性能项目中使用 WasmGC。加入我们,一起打造更快、更顺畅的网络环境!

致谢

感谢参与 WasmGC 实施工作的人员 Mattha Thomas Thomas 和 Mattie Thomas、J.S.S.S.