為何 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 transpiler (J2CL) 達成。JavaScript 計算引擎會在 Web Worker 中執行,並使用 MessageChannel 與主執行緒通訊。

將使用者從伺服器遷移至 JavaScript 版本的計算引擎 (以及後續從 GWT 遷移至 J2CL) 是一項重大工程,需要仔細驗證。為確保 JavaScript 計算引擎產生的結果與 Java 版本完全相同,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 的試算表非常適合評估 WasmGC,因為這項服務對效能要求很高,而且具備完善的效能和正確性驗證機制。Chrome 設有 V8 團隊,負責建構及最佳化 WasmGC 執行階段,並有 Binaryen 貢獻者負責建構預先 (AOT) 最佳化功能。Chrome 和 Workspace 具備建構及最佳化 WasmGC 工具鍊所需的所有專業知識,而 Google 試算表則是理想的測試平台。

第一個原型

到了 2021 年中,團隊已開發出可用的 Java 至 WasmGC 編譯器。同年年底,他們已推出 Google 試算表的原型版本,可做為 WasmGC 執行並進行計算。他們在過程中遇到許多挑戰,當時沒有可用的剖析和堆積傾印工具,因此我們必須自行建構。現有實作項目依賴許多 JavaScript 程式庫,因此必須為 WasmGC 尋找或編寫替代項目。由於規格、編譯器和新程式庫都處於實驗階段,因此驗證 Wasm 計算引擎的正確性相當耗時。但 Google 試算表的驗證機制再次發揮極大作用。最後,團隊成功讓一切正常運作,並在 2022 年初開始收到成效資料。

其他最佳化

試算表 Wasm 的初始版本顯示,計算效能比 JavaScript 慢了大約兩倍。不過,對於新規格、新編譯器和多個新程式庫來說,這並非壞事。從此時起,Google 試算表團隊開始進行最佳化。在他們發現的最佳化項目中,有幾個類別:

  • 複製 Java 虛擬機器 (JVM) 和 V8 中已有的核心最佳化項目。
  • 使用經過高度最佳化的瀏覽器 API。
  • 移除 JavaScript 專屬的編碼模式。

首先,Google 試算表團隊必須複製其他工具鍊中已有的最佳化項目。最佳範例是最佳化虛擬方法調度,JVM 和 V8 長期以來都已進行最佳化,但 WasmGC 並未進行任何最佳化。實作推測內嵌去虛擬化這兩項非常常見的最佳化措施後,Chrome 的計算時間縮短了約 40%。

其次,在某些情況下,瀏覽器 API 會由經過最佳化的原生實作提供支援,這類實作難以使用 Wasm 競爭。字串和規則運算式就是兩個很好的例子。具體來說,團隊從 re2j (編譯為 WasmGC) 切換至 Chrome 中的 RegExp 瀏覽器 API 後,正規運算式作業的速度提升了近 100 倍,因為後者可將每個正規運算式編譯為自己的機器碼。

最後,他們發現多年的最佳化作業,導致程式碼庫過度配合 JavaScript。舉例來說,他們在 Google 試算表中有一個核心資料結構,模糊了陣列和對應之間的界線。這在 JavaScript 中很有效率,因為 JavaScript 會自動將稀疏陣列建模為對應,但在其他平台上則很慢。因此他們必須以更不限平台的方式重寫程式碼。這也是團隊喜歡 WebAssembly 的另一個原因:多平台應用程式在網路上獲得良好效能變得更加容易。您不必為了 JavaScript 的特性而調整整個應用程式。

最終結果

經過上述所有最佳化作業後,最終的 WasmGC 版試算表計算效能約為 JavaScript 的兩倍,相較於初始 WasmGC 版本,效能提升了四倍。

結論

WasmGC 是一項強大的技術,可望提升開發人員建構網頁應用程式的方式。在接下來幾年,Google 希望 WasmGC 能進一步支援共用記憶體多執行緒,並提升單一執行緒的效能。我們建議所有網頁開發人員在下一個高效能專案中使用 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。