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) 编译器(例如 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 的多平台团队拥有丰富的构建和优化编译器和转译器的专业知识。我们发现 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。