Pourquoi Google Sheets a transféré son worker de calcul de JavaScript vers WasmGC

Google Sheets est l'un des premiers produits Google à utiliser WasmGC sur Chrome. Cette transition a été annoncée en 2022. Les équipes Sheets et Chrome ont collaboré sur la normalisation, l'ingénierie et les outils pour fournir des commentaires en temps réel sur les optimisations. Ce partenariat a servi de précédent pour montrer comment les équipes d'ingénieurs de Google peuvent travailler efficacement avec Chrome pour exécuter davantage d'applications Google sur WasmGC.

Le défi : JavaScript

Le moteur de calcul Google Sheets a été écrit à l'origine en Java et lancé en 2006. Au début du produit, tous les calculs étaient effectués sur le serveur. Toutefois, depuis 2013, le moteur s'exécute dans le navigateur à l'aide de JavaScript. À l'origine, cela était possible grâce à Google Web Toolkit (GWT), puis grâce au transpileur JavaScript Java to Closure (J2CL). Le moteur de calcul JavaScript s'exécute dans un Web Worker et communique avec le thread principal à l'aide d'un MessageChannel.

La migration des utilisateurs du serveur vers la version JavaScript du moteur de calcul (et plus tard de GWT vers J2CL) a été une tâche majeure qui a nécessité une validation minutieuse. Pour s'assurer que le moteur de calcul JavaScript produisait exactement les mêmes résultats que la version Java, l'équipe Sheets a développé un mécanisme de validation interne. Ce mécanisme peut traiter un grand corpus de feuilles et valider que les résultats sont identiques entre plusieurs versions du moteur de calcul. L'équipe Sheets utilise régulièrement cet outil pour valider les modifications apportées à Sheets. Mais l'équipe n'a pas seulement comparé les résultats de ces calculs. Elle a également comparé les performances entre JavaScript sur le client et Java sur le serveur. Ils ont constaté que la version JavaScript du moteur de calcul était plus de trois fois plus lente que la version Java.

Pourquoi JavaScript est-il plus lent que Java ?

JavaScript est un langage dynamique à typage faible, mais il est rapide. Au cours des 15 dernières années, des investissements importants dans les compilateurs juste-à-temps (JIT) (par exemple, Maglev, Sparkplug et Turbofan) ont permis d'améliorer les performances de JavaScript. Toutefois, les types lâches et le comportement dynamique de JavaScript rendent difficile la génération de code optimal par les compilateurs JIT. Cela signifie que JavaScript reste en retrait par rapport à des langages comme Java et C++ en termes de débit brut. TypeScript ajoute la sécurité des types à JavaScript, mais ces informations sur les types sont conçues pour faciliter le développement, et non pour fournir les types de garanties dont les compilateurs ont besoin pour générer un code optimal. Dans des cas comme Google Sheets, où le calcul de grandes feuilles de calcul peut prendre des dizaines de secondes, JavaScript est rapide, mais pas assez.

La solution : WasmGC

WasmGC est une extension de la spécification WebAssembly existante qui ajoute les primitives nécessaires à la compilation des langages avec ramasse-miettes (comme Java). Par exemple, WasmGC ajoute des instructions pour définir des types et allouer des structures de données collectées par le garbage collector. WasmGC est sur le point de faire pour les langages avec ramasse-miettes ce que Wasm a fait pour C++ (par exemple, Photoshop ou Google Earth), c'est-à-dire les amener sur le Web à une vitesse quasi native. Chez Google, nous pensons que WasmGC a le potentiel d'avoir un impact encore plus important que Wasm en raison de la popularité des langages avec ramasse-miettes.

Google Workspace s'associe à Chrome

La spécification provisoire du MVP WasmGC a été publiée en 2019. Fin 2020, Google Workspace et Chrome se sont associés pour évaluer WasmGC à l'aide du moteur de calcul Sheets. L'équipe multiplate-forme de Workspace possède une grande expertise dans la création et l'optimisation de compilateurs et de transpileurs. Sheets, qui fait partie de Workspace, a été identifié comme un candidat idéal pour évaluer WasmGC : il est sensible aux performances et dispose de mécanismes robustes de validation des performances et de l'exactitude. Chrome dispose de l'équipe V8 pour créer et optimiser le runtime WasmGC, ainsi que de contributeurs à Binaryen pour créer des optimisations AOT (Ahead-Of-Time). Entre Chrome et Workspace, vous disposez de toute l'expertise nécessaire pour créer et optimiser une chaîne d'outils WasmGC, Google Sheets étant un banc d'essai idéal.

Le premier prototype

À la mi-2021, les équipes disposaient d'un compilateur Java vers WasmGC fonctionnel. Vers la fin de la même année, ils ont créé une version prototype de Google Sheets fonctionnant en tant que WasmGC et effectuant des calculs. En chemin, ils ont rencontré de nombreux défis. Les outils de profilage et de création de vidages de tas n'existaient pas et ont dû être créés. L'implémentation existante s'appuyait sur de nombreuses bibliothèques JavaScript pour lesquelles des remplacements ont dû être trouvés ou écrits pour WasmGC. La validation de l'exactitude du moteur de calcul Wasm a pris beaucoup de temps en raison du caractère expérimental de la spécification, du compilateur et des nouvelles bibliothèques. Mais les mécanismes de validation de Sheets se sont une fois de plus avérés extrêmement utiles. Les équipes ont finalement réussi à faire fonctionner le tout, et les données de performances ont commencé à arriver début 2022.

Optimisations supplémentaires

La version initiale de Sheets Wasm affichait des performances de calcul environ deux fois plus lentes que JavaScript. Toutefois, ce n'est pas un mauvais résultat pour une nouvelle spécification, un nouveau compilateur et plusieurs nouvelles bibliothèques. À partir de ce moment, l'équipe Sheets a commencé à optimiser le processus. Parmi les optimisations qu'ils ont trouvées, plusieurs catégories sont apparues :

  • Réplication des optimisations de base qui existaient déjà dans la machine virtuelle Java (JVM) et dans V8.
  • Utilisation d'API de navigateur hautement optimisées.
  • Suppression des modèles de codage spécifiques à JavaScript.

Tout d'abord, l'équipe Sheets devait reproduire les optimisations qui existent déjà dans d'autres chaînes d'outils. Le meilleur exemple est l'optimisation de l'envoi de méthodes virtuelles, qui est optimisé depuis longtemps par la JVM et V8, mais rien n'existait pour WasmGC. L'implémentation de l'inlining spéculatif et de la dévirtualisation, deux optimisations très courantes, a permis de réduire le temps de calcul d'environ 40 % dans Chrome.

Deuxièmement, il existe des cas où les API de navigateur sont soutenues par des implémentations natives optimisées qu'il est difficile de concurrencer avec Wasm. Les chaînes et les expressions régulières en sont deux bons exemples. Plus précisément, grâce aux expressions régulières, l'équipe a constaté une accélération des opérations d'expressions régulières de près de 100 fois en passant de re2j (compilé en WasmGC) à l'API de navigateur RegExp dans Chrome, qui peut compiler chaque expression régulière dans son propre code machine.

Enfin, ils ont constaté que des années d'optimisation avaient entraîné un surapprentissage du code de base pour JavaScript. Par exemple, ils disposaient d'une structure de données de base dans Sheets qui brouillait les frontières entre les tableaux et les cartes. Cette méthode est efficace en JavaScript, qui modélise automatiquement les tableaux creux sous forme de cartes, mais elle est lente sur d'autres plates-formes. Ils ont donc dû réécrire le code de manière plus agnostique. C'est un autre avantage que l'équipe apprécie dans WebAssembly : il permet aux applications multiplates-formes d'obtenir de bonnes performances sur le Web. Vous n'avez pas besoin de plier toute votre application aux particularités de JavaScript.

Résultat final

Après toutes ces optimisations, la version finale de Sheets avec WasmGC atteint des performances de calcul environ deux fois plus rapides que JavaScript, ce qui représente une amélioration par quatre par rapport au point de départ de la version initiale de WasmGC.

Conclusion

WasmGC est une technologie puissante qui a le potentiel de faire progresser la façon dont les développeurs créent des applications Web. Au cours des prochaines années, chez Google, nous espérons voir WasmGC évoluer pour prendre en charge le multithreading à mémoire partagée et améliorer encore les performances monothread. Nous encourageons tous les développeurs Web à envisager d'utiliser WasmGC pour leur prochain projet haute performance. Rejoignez-nous et contribuez à rendre le Web plus rapide et plus fluide !

Remerciements

Merci à toutes les personnes qui ont travaillé sur l'implémentation de WasmGC et sur cette étude de cas : 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 et Emanuel Ziegler.