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

Google 表格是 Google 首批在 Chrome 上使用 WasmGC 的产品之一。我们于 2022 年宣布了这一举措,表格和 Chrome 团队在标准化、工程和工具方面进行了合作,以便就优化提供实时反馈。这项合作为 Google 工程团队如何有效与 Chrome 合作,让更多 Google 应用在 WasmGC 上运行树立了先例。

挑战: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) 编译器(例如 MaglevSparkplugTurbofan)方面进行了大量投资,这提升了 JavaScript 的性能。但是,由于 JavaScript 的类型和动态行为比较宽松,因此 JIT 编译器很难生成最优代码。这意味着,在原始吞吐量方面,JavaScript 仍落后于 Java 和 C++ 等语言。TypeScript 为 JavaScript 添加了类型安全性,但这些类型信息旨在简化开发,而不是提供编译器生成最佳代码所需的保证。对于 Google 表格等大型电子表格可能需要几十秒才能计算完毕的情况,JavaScript 虽然速度很快,但还不够快。

解决方案:WasmGC

WasmGC 是对现有 WebAssembly 规范的扩展,它添加了编译垃圾回收语言(例如 Java)所需的原语。例如,WasmGC 添加了用于定义类型和分配垃圾回收数据结构的指令。WasmGC 将为垃圾回收语言做 Wasm 为 C++ 所做的事(例如,PhotoshopGoogle 地球),即以接近原生速度将这些语言引入 Web 平台。Google 认为,由于垃圾回收语言的普及,WasmGC 的潜在影响力甚至可能超过 Wasm。

Google Workspace 与 Chrome 携手合作

WasmGC MVP 草稿规范于 2019 年发布。2020 年底,Google Workspace 和 Chrome 携手合作,使用 Google 表格计算引擎评估 WasmGC。Workspace 的多平台团队拥有丰富的构建和优化编译器和转译器的专业知识。我们发现 Google 表格(Google Workspace 的一部分)非常适合评估 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 很难与之竞争。字符串和正则表达式就是两个很好的示例。具体而言,在 Chrome 中,当团队从 re2j(编译为 WasmGC)切换到 RegExp 浏览器 API(可将每个正则表达式编译为自己的机器码)时,正则表达式操作的速度提高了近 100 倍。

最后,他们发现多年的优化导致代码库过度适应了 JavaScript。例如,他们在 Google 表格中有一个核心数据结构,模糊了数组和映射之间的界限。在 JavaScript 中,这种方法非常高效,因为 JavaScript 会自动将稀疏数组建模为映射,但在其他平台上速度较慢。因此,他们不得不以更不依赖于平台的方式重写代码。WebAssembly 的另一个优势是:它可以让多平台应用更轻松地在 Web 上实现良好的性能。您不必为了 JavaScript 的特性而调整整个应用。

最终结果

经过所有这些优化后,最终的 WasmGC 版 Google 表格在计算性能方面大约是 JavaScript 的两倍,与最初的 WasmGC 版本相比,性能提升了四倍。

总结

WasmGC 是一项强大的技术,有望改进开发者构建 Web 应用的方式。在未来几年里,我们希望 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。