Dlaczego Arkusze Google przeniosły narzędzie obliczeniowe do obliczeń z JavaScriptu do WasmGC

Arkusze Google to jedna z pierwszych usług Google, która korzysta z WasmGC w Chrome. W 2022 r. ogłosiliśmy tę zmianę. Zespoły Arkuszy i Chrome współpracowały ze sobą w zakresie standaryzacji, inżynierii i narzędzi, aby zapewnić informacje zwrotne na temat optymalizacji w czasie rzeczywistym. To partnerstwo wyznaczyło standardy współpracy zespołów inżynierów Google z Chrome, aby więcej aplikacji Google mogło działać na WasmGC.

Wyzwanie: JavaScript

Silnik obliczeniowy Arkuszy Google został pierwotnie napisany w Javie i wprowadzony w 2006 r. Na początku istnienia usługi wszystkie obliczenia były wykonywane na serwerze. Od 2013 r. silnik działa jednak w przeglądarce za pomocą JavaScriptu. Początkowo było to realizowane za pomocą Google Web Toolkit (GWT), a później za pomocą transpilatora Java to Closure JavaScript (J2CL). Silnik obliczeniowy JavaScript działa w elementach roboczych sieci Web i komunikuje się z głównym wątkiem za pomocą MessageChannel.

Migracja użytkowników z serwera na wersję JavaScriptową mechanizmu obliczeniowego (a później z GWT na J2CL) była dużym przedsięwzięciem, które wymagało dokładnej weryfikacji. Aby mieć pewność, że silnik obliczeniowy JavaScriptu daje dokładnie takie same wyniki jak wersja w Javie, zespół Arkuszy opracował wewnętrzny mechanizm weryfikacji. Ten mechanizm może przetwarzać duży zbiór arkuszy i sprawdzać, czy wyniki są identyczne w przypadku różnych wersji mechanizmu obliczeniowego. Zespół Arkuszy Google regularnie używa tego narzędzia do sprawdzania zmian w Arkuszach Google. Zespół nie tylko porównał wyniki tych obliczeń, ale też porównał wydajność JavaScript na kliencie i Javy na serwerze. Okazało się, że wersja silnika obliczeniowego w JavaScript była ponad 3 razy wolniejsza niż wersja w Javie.

Dlaczego JavaScript jest wolniejszy niż Java?

JavaScript jest szybki jak na język dynamiczny o luźnym typowaniu. W ciągu ostatnich 15 lat znaczne inwestycje w kompilatory just-in-time (JIT) (np. Maglev, SparkplugTurbofan) zwiększyły wydajność JavaScriptu. Jednak ze względu na luźne typy i dynamiczne zachowanie JavaScriptu kompilatory JIT mają trudności z generowaniem optymalnego kodu. Oznacza to, że JavaScript nadal pozostaje w tyle za językami takimi jak Java czy C++, jeśli chodzi o czysty przepływ danych. TypeScript zwiększa bezpieczeństwo typów w JavaScript, ale te informacje o typach mają ułatwić rozwój, a nie zapewnić tego rodzaju gwarancji, których potrzebują kompilatory do generowania optymalnego kodu. W przypadku Arkuszy Google, gdzie obliczenia dużych arkuszy mogą zająć kilkadziesiąt sekund, JavaScript jest szybki, ale nie wystarczająco szybki.

Rozwiązanie: WasmGC

WasmGC to rozszerzenie istniejącej specyfikacji WebAssembly, które dodaje elementy potrzebne do kompilowania języków z zbieraniem elementów odśmieci (takich jak Java). Na przykład WasmGC dodaje instrukcje definiowania typów i przydzielania struktur danych z zbieraniem elementów do usunięcia. WasmGC ma za zadanie wprowadzić do sieci języki z obsługą zwolnień pamięci (np. Photoshop czy Google Earth), aby działały one w sieci z blisko natywnej prędkości. W Google uważamy, że WasmGC może mieć jeszcze większy wpływ niż WasmGC ze względu na popularność języków z zbieraniem śmieci.

Google Workspace współpracuje z Chrome

W 2019 r. opublikowano projekt specyfikacji MVP WasmGC. Pod koniec 2020 r. zespoły Google Workspace i Chrome połączyły siły, aby ocenić WasmGC za pomocą mechanizmu obliczeniowego Arkuszy. Zespół Workspace zajmujący się platformami ma duże doświadczenie w tworzeniu i optymalizowaniu kompilatorów oraz transpilacji. Arkusze Google, które są częścią Workspace, zostały uznane za idealny kandydata do oceny WasmGC: aplikacja ta jest wrażliwa na wydajność i ma solidne mechanizmy weryfikacji wydajności i poprawności. W Chrome jest zespół V8, który tworzy i optymalizuje środowisko wykonawcze WasmGC, a także współpracownicy Binaryen, którzy tworzą optymalizacje AOT (z wyprzedzeniem). Chrome i Workspace zapewniają wszystkie informacje potrzebne do tworzenia i optymalizowania łańcucha narzędzi WasmGC, a Arkusze Google są idealnym miejscem do testowania.

Pierwszy prototyp

W połowie 2021 r. zespoły miały działający kompilator Java na WasmGC. Pod koniec tego samego roku prototyp Arkuszy Google działał jako WasmGC i wykonywał obliczenia. Po drodze napotkali wiele wyzwań. Narzędzia do profilowania i tworzenia dumpów stosu nie istniały i trzeba je było stworzyć. Dotychczasowa implementacja wykorzystywała wiele bibliotek JavaScript, które trzeba było znaleźć lub napisać na potrzeby WasmGC. Weryfikacja poprawności silnika obliczeniowego Wasm wymagała sporo czasu ze względu na eksperymentalny charakter specyfikacji, kompilatora i nowych bibliotek. Jednak mechanizmy sprawdzania arkuszy były ponownie bardzo pomocne. Ostatecznie wszystko zaczęło działać, a na początku 2022 r. zaczęły napływać dane o skuteczności.

Dodatkowe optymalizacje

Początkowa wersja Wasm w Arkuszach wykazała, że obliczenia są wykonywane około 2 razy wolniej niż w JavaScript. Nie jest to jednak zły wynik dla nowej specyfikacji, nowego kompilatora i kilku nowych bibliotek. Od tego momentu zespół Arkuszy zaczął optymalizować. Wśród znalezionych optymalizacji wyróżniliśmy kilka kategorii:

  • powielanie optymalizacji jądra, które istniały już w maszynie wirtualnej Java (JVM) i w V8;
  • Korzystanie z optymalizowanych interfejsów API przeglądarki.
  • Usuwanie wzorów kodowania specyficznych dla JavaScriptu.

Po pierwsze zespół arkuszy kalkulacyjnych musiał odtworzyć optymalizacje, które istnieją już w innych łańcuchach narzędzi. Najlepszym przykładem jest optymalizacja wysyłania wywołań metod wirtualnych, które od dawna są optymalizowane przez JVM i V8, ale nie było nic dla WasmGC. Wdrożenie speculatywnego wstawiania kodu i dewirtualizacji – 2 bardzo popularnych optymalizacji – skróciło czas obliczeń w Chrome o około 40%.

Po drugie, są przypadki, w których interfejsy API przeglądarki są obsługiwane przez zoptymalizowane natywne implementacje, które trudno jest zastąpić za pomocą Wasm. Przykładami takich danych są ciągi znaków i wyrażenia regularne. W szczególności w przypadku wyrażeń regularnych zespół zauważył prawie 100-krotne przyspieszenie operacji wyrażeń regularnych po przejściu z re2j (skompilowanego do WasmGC) na RegExp API przeglądarki w Chrome, który może kompilować każde wyrażenie regularne do własnego kodu maszynowego.

W końcu okazało się, że lata optymalizacji spowodowały, że kod źródłowy jest zbytnio dostosowany do JavaScriptu. Na przykład mieli podstawową strukturę danych w Arkuszach, która zacierała różnice między tablicami a mapami. Jest to wydajne w JavaScriptzie, który automatycznie modeluje rzadkie tablice jako mapy, ale powolne na innych platformach. Z tego powodu musieli przepisać kod w taki sposób, aby był bardziej uniwersalny. To kolejna zaleta WebAssembly: ułatwia ono aplikacjom wieloplatformowym osiąganie dobrej wydajności w internecie. Nie musisz dostosowywać całej aplikacji do specyfiki JavaScript.

Ostateczny wynik

Po zastosowaniu wszystkich tych optymalizacji ostateczna wersja WasmGC w Arkuszach osiąga wydajność obliczeń dwa razy większą niż JavaScript, co oznacza czterokrotny wzrost w stosunku do początkowej wersji WasmGC.

Podsumowanie

WasmGC to zaawansowana technologia, która może usprawnić tworzenie aplikacji internetowych przez programistów. W nadchodzących latach chcielibyśmy, aby WasmGC ewoluował, aby obsługiwać wielowątkowość z wspólnym użyciem pamięci i dalej poprawiać wydajność pojedynczego wątku. Zachęcamy wszystkich web developerów do rozważenia zastosowania WasmGC w przyszłych projektach o wysokiej wydajności. Dołącz do nas i pomóż nam sprawić, aby internet był szybszy i płynniejszy.

Podziękowania

Dziękujemy tym, którzy pracowali nad wdrożeniem WasmGC i tym przypadkiem: 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 i Emanuel Ziegler.