Firefox - WebAssembly 75 fois plus rapide !
J’avoue que parfois, les performances de mon navigateur Firefox me laissent sur ma faim lorsque j’utilise certaines applications web. Pourtant j’aime d’amour Firefox depuis toujours, alors je prends mon mal en patience. Et j’ai bien fait puisque les ingénieurs de Mozilla ont réalisé une avancée majeure avec Firefox. Ils ont optimisé le compilateur Ion, permettant ainsi à WebAssembly d’être 75 fois plus rapide. Une coup de boost qui pourrait bien faire des envieux chez la concurrence et ravir les utilisateurs qui comme moi sont toujours en quête de performances.
Pour rappel, WebAssembly est une technologie qui permet d’exécuter du code à haute performance directement dans votre navigateur. Avec WebAssembly, il est possible d’utiliser des applications complexes comme des logiciels de retouche photo, de jouer à des jeux 3D ou d’exécuter des modèles d’apprentissage automatique, tout cela depuis un simple onglet web, sans installation préalable. C’est ça la promesse initiale de WebAssembly mais jusqu’à récemment, compiler et exécuter ce type de code pouvait prendre un temps considérable, surtout pour les grosses applications.
C’est ici qu’intervient le compilateur Ion de Firefox. Sa mission est de transformer le code WebAssembly en instructions machine optimisées pour le processeur, offrant ainsi de meilleures performances d’exécution. Cependant, ce processus pouvait être gourmand en temps et en mémoire, particulièrement avec de grandes applications WebAssembly contenant des fonctions volumineuses.
Pour illustrer l’ampleur de cette optimisation, prenons l’exemple du module ONNX Runtime de Microsoft, une bibliothèque d’apprentissage automatique compilée en WebAssembly. Les ingénieurs de Mozilla ont constaté que la compilation de ce module avec le compilateur Ion prenait environ 5 minutes, consommant plus de 4 Go de RAM : un temps d’attente et une utilisation de ressources vraiment trop élevés pour obtenir une expérience utilisateur fluide.
Après les améliorations apportées, le même module est désormais compilé en moins de 3,9 secondes, avec une consommation de mémoire réduite de plus de 3 Go. Incroyable non ? C’est ce que j’appelle changer radicalement l’expérience utilisateur, à ce niveau.
Alors comment une telle prouesse a-t-elle été possible ? Et bien les développeurs de Mozilla ont identifié plusieurs points clés dans le processus de compilation qui pouvaient être optimisés :
- Gestion efficace des plages de vie des variables : Dans l’allocateur de registres du compilateur Ion, chaque variable virtuelle (ou registre virtuel) a une liste de plages de vie. Initialement, ces plages étaient stockées dans des listes chaînées triées, ce qui entraînait des comportements quadratiques lors de l’allocation de registres, particulièrement pour les fonctions avec des milliers de variables. Les ingénieurs ont remplacé ces listes par des vecteurs, n’ordonnant les plages de vie que lorsque nécessaire. Cette approche a grandement amélioré la performance et la consommation mémoire, rendant l’allocateur de registres jusqu’à 20 fois plus rapide sur ces cas complexes.
- Adoption de l’algorithme Semi-NCA pour le calcul des dominants : Le compilateur Ion utilise un graphe de flux de contrôle pour représenter les programmes. Le calcul des blocs dominants immédiats dans ce graphe était auparavant réalisé avec un algorithme qui ne s’adaptait pas bien aux grands graphes, ce qui ralentissait la compilation. En adoptant l’algorithme Semi-NCA, le temps de calcul des dominants a été considérablement réduit. Par exemple, pour une fonction donnée, ce temps est passé de 7,1 secondes à seulement 0,15 seconde.
- Utilisation de structures de données parcimonieuses (Sparse BitSets) : Le compilateur allouait des ensembles de bits pour chaque bloc de base, ce qui consommait beaucoup de mémoire. En remplaçant ces ensembles de bits denses par des versions éparses, la consommation de mémoire a été réduite de plus de 3 Go, améliorant également l’efficacité du cache et accélérant le processus de compilation.
- Optimisation de la résolution des mouvements : Lors de l’allocation des registres, le compilateur doit insérer des instructions de mouvement pour transférer les valeurs entre registres et emplacements mémoire. Les algorithmes utilisés pour cette étape comportaient des boucles avec un comportement quadratique. En refondant ces algorithmes pour utiliser des boucles linéaires, les développeurs ont considérablement accéléré cette phase, contribuant globalement à la réduction du temps de compilation.
Ces optimisations combinées ont permis d’aboutir à des gains de performance impressionnants. Par exemple, le temps de compilation du module WebAssembly utilisé par Adobe Photoshop en ligne est passé de 4 minutes à seulement 14 secondes. De même, un module de test du benchmark JetStream 2 a vu son temps de compilation réduit de 2,8 secondes à 0,2 seconde.
Ces améliorations ne profitent pas uniquement aux géants du web. Même les applications plus modestes en bénéficient. Pour nous, simple web surfeurs d’argent, cela signifie une navigation plus fluide et des temps de chargement nettement réduits. On va pouvoir enfin profiter d’applications web balèzes sans subir de ralentissements ou de consommations excessives de ressources.
Notez qu’avec cette optimisation, Mozilla a pris une longueur d’avance sur la concurrence. Toutefois, il est probable que ces avancées incitent Chrome et compagnie à investir dans des optimisations équivalentes pour ne pas se laisser distancer.
De plus, les ingénieurs de Mozilla travaillent déjà sur une refonte complète du pipeline de compilation de WebAssembly. L’objectif est de permettre une compilation à la volée des fonctions WebAssembly, au fur et à mesure de leur utilisation, plutôt que de compiler l’ensemble du module dès le départ. Cela permettra à votre navigateur d’optimiser le code en temps réel, améliorant encore la réactivité des applications web complexes et ouvrant la voie à de nouvelles capacités telles que l’inlining spéculatif.
Pour tester ces améliorations par vous-même, il vous suffit de télécharger la dernière version de Firefox et de charger une application utilisant WebAssembly, comme la version en ligne d’Adobe Photoshop ou les démos disponibles sur le site de WebAssembly Studio. Vous constaterez par vous-même la différence en termes de temps de chargement et de réactivité.
Pour les plus curieux, voici quelques liens permettant d’approfondir le sujet :
- Rapport de bug initial : Bugzilla 1916442
- Article détaillé sur le compilateur Baseline : Blog d’Andy Wingo
- Annonce officielle des améliorations : Blog SpiderMonkey
Hâte de tester ça !