Comment nous avons multiplié par 20 la vitesse de l'application web grâce à WebAssembly

Comment nous avons multiplié par 20 la vitesse de l'application web grâce à WebAssembly

Cet article aborde le cas de l'accélération d'une application web en remplaçant les calculs JavaScript par WebAssembly.

Qu'est-ce que WebAssembly ?

En résumé, c'est un format binaire d'instructions pour une machine virtuelle à pile. Souvent, le terme Wasm (nom abrégé) est qualifié de langage de programmation, mais ce n'est pas le cas. Ce format d'instructions s'exécute dans le navigateur aux côtés de JavaScript.

Il est important de noter que WebAssembly peut être généré en compilant du code source dans des langages tels que C/C++, Rust, Go. Ici, la typage statique et le modèle de mémoire dit plat sont appliqués. Le code, comme mentionné ci-dessus, est stocké dans un format binaire compact, permettant ainsi une exécution presque aussi rapide que si l'application était lancée via la ligne de commande. Ces capacités ont contribué à la popularité croissante de WebAssembly.

Rappelons-le : pour tous les lecteurs de « Habr » — une réduction de 10 000 roubles lors de l'inscription à tout cours Skillbox avec le code promo « Habr ».

Skillbox recommande : Cours pratique « Développeur mobile PRO ».

Actuellement, Wasm est utilisé dans de nombreuses applications, des jeux comme Doom 3 aux applications portées sur le web comme Autocad et Figma. Wasm est également utilisé dans des domaines tels que le calcul sans serveur.

Cet article fournit un exemple d'utilisation de Wasm pour accélérer un service web analytique. Pour la clarté, nous avons utilisé une application fonctionnelle écrite en C, qui sera compilée en WebAssembly. Le résultat sera utilisé pour remplacer les sections peu performantes de JS.

Transformation de l'application

Dans l'exemple, nous utiliserons le service web fastq.bio, destiné aux généticiens. Cet outil permet d'évaluer la qualité du séquençage (décodage) de l'ADN.

Voici un exemple de l'application en cours d'utilisation :

Comment nous avons multiplié par 20 la vitesse de l'application web grâce à WebAssembly

Les détails du processus ne valent pas la peine d'être fournis, car ils sont assez complexes pour les non-spécialistes. En résumé, les chercheurs, grâce à l'infographie ci-dessus, peuvent comprendre si le processus de séquençage de l'ADN s'est bien déroulé et quels problèmes ont pu survenir.

Ce service a des alternatives, des programmes de bureau. Cependant, fastq.bio permet d'accélérer le travail en visualisant les données. Dans la plupart des autres cas, il est nécessaire de savoir travailler avec la ligne de commande, mais tous les généticiens n'ont pas l'expérience requise.

Tout fonctionne simplement. En entrée, des données sont présentées sous la forme d'un fichier texte. Ce fichier est généré par des outils spécialisés pour le séquençage. Il contient une liste de séquences d'ADN et une évaluation de la qualité de chaque nucléotide. Le format du fichier est .fastq, d'où le nom du service.

Implémentation en JavaScript

La première étape pour l'utilisateur travaillant avec fastq.bio est de sélectionner le fichier approprié. En utilisant l'objet File, l'application lit un échantillon aléatoire de données à partir du fichier et traite ce lot. La tâche de JavaScript ici consiste à effectuer des opérations simples sur les chaînes et à calculer des indicateurs. L'un d'eux est le nombre de nucléotides A, C, G et T dans différents fragments d'ADN.

Après le calcul des indicateurs nécessaires, ils sont visualisés à l'aide de Plotly.js, et le service commence à travailler avec un nouvel échantillon de données. La division en fragments est faite pour améliorer la qualité de l'expérience utilisateur. Si l'on travaille avec toutes les données à la fois, le processus se bloquera un moment, car les fichiers de résultats du séquençage occupent des centaines de gigaoctets d'espace de stockage. Le service traite des segments de données d'une taille comprise entre 0.5 et 1 Mo, les traitant étape par étape pour construire des données graphiques.

Voici comment ça fonctionne :

Comment nous avons multiplié par 20 la vitesse de l'application web grâce à WebAssembly

Dans le rectangle rouge se trouve l'algorithme de transformation de chaînes pour obtenir la visualisation. C'est la partie la plus exigeante en calculs du service. Il vaut la peine d'essayer de la remplacer par Wasm.

Testons WebAssembly

Pour évaluer la possibilité d'utiliser Wasm, l'équipe du projet a cherché des solutions prêtes à l'emploi pour créer une métrique QC (QC - contrôle qualité) basée sur des fichiers fastq. La recherche portait sur des outils écrits en C, C++ ou Rust, afin de pouvoir porter le code sur WebAssembly. De plus, l'outil ne devait pas être "brut", un service déjà validé par des chercheurs était requis.

En conséquence, le choix s'est porté sur seqtk. L'application est assez populaire, elle est open-source et le langage source est C.

Avant de la transformer en Wasm, il convient d'examiner le principe de compilation de seqtk pour le bureau. Selon le Makefile, voici ce qu'il faut :

# Compile to binary
$ gcc seqtk.c 
   -o seqtk 
   -O2 
   -lm 
   -lz

En principe, on peut compiler seqtk à l'aide d'Emscripten. Si vous ne l'avez pas, vous pouvez utiliser la méthode Docker.

$ docker pull robertaboukhalil/emsdk:1.38.26
$ docker run -dt --name wasm-seqtk robertaboukhalil/emsdk:1.38.26

Si vous le souhaitez, vous pouvez également le compiler vous-même, mais cela prend du temps.

À l'intérieur du conteneur, on peut facilement utiliser emcc comme alternative à gcc :

# Compile to WebAssembly
$ emcc seqtk.c 
    -o seqtk.js 
    -O2 
    -lm 
    -s USE_ZLIB=1 
    -s FORCE_FILESYSTEM=1

Peu de changements :

Au lieu de générer un fichier binaire, Emscripten utilise .wasm et .js pour produire des fichiers, qui sont utilisés pour exécuter le module WebAssembly.

Pour prendre en charge la bibliothèque zlib, le drapeau USE_ZLIB est utilisé. Cette bibliothèque est largement répandue et a été portée sur WebAssembly, et Emscripten l'inclut dans le projet.

Le système de fichiers virtuel Emscripten est activé. Cela est un système de fichiers de type POSIX, qui fonctionne en mémoire vive à l'intérieur du navigateur. Lorsque la page est actualisée, la mémoire est nettoyée.

Pour comprendre l'utilité d'un système de fichiers virtuel, il vaut la peine de comparer le lancement de seqtk à partir de la ligne de commande avec le lancement d'un module WebAssembly compilé.

# On the command line
$ ./seqtk fqchk data.fastq
 
# In the browser console
> Module.callMain(["fqchk", "data.fastq"])

Accéder au système de fichiers virtuel permet de ne pas réécrire seqtk pour qu'il fonctionne avec une entrée en ligne au lieu d'une entrée de fichier. Dans ce cas, le fragment de données est mappé en tant que fichier data.fastq dans le FS virtuel avec l'appel main() seqtk.

Voici la nouvelle architecture :

Comment nous avons multiplié par 20 la vitesse de l'application web grâce à WebAssembly

L'illustration montre que contrairement aux calculs dans le thread principal du navigateur, WebWorkerssont utilisés. Cette méthode permet d'effectuer des calculs dans un thread d'arrière-plan sans nuire à la réactivité du navigateur. De plus, le contrôleur WebWorker lance le Worker, gérant son interaction avec le thread principal.

La commande seqtk est exécutée via le Worker sur le fichier monté. Une fois que le Worker a terminé son exécution, il renvoie le résultat sous forme de Promise. Lorsque le message est reçu par le thread principal, le résultat est utilisé pour mettre à jour les graphiques. Et cela se fait sur plusieurs itérations.

Qu'en est-il des performances de WebAssembly ?

Pour évaluer le changement de performance, l'équipe du projet a mesuré le nombre d'opérations de lecture par seconde. Le temps de construction des graphiques interactifs n'est pas pris en compte, car JavaScript est utilisé dans les deux implémentations.

Avec une solution 'clé en main', le gain de performance était de neuf fois.

Comment nous avons multiplié par 20 la vitesse de l'application web grâce à WebAssembly

C'est un excellent résultat, mais il s'avère qu'il est possible de l'optimiser davantage. En effet, un grand nombre de résultats de l'analyse QC ne sont pas utilisés par seqtk, donc ils peuvent être supprimés. Si cela est fait, le résultat par rapport à JavaScript s'améliore de 13 fois.

Comment nous avons multiplié par 20 la vitesse de l'application web grâce à WebAssembly

Cela a été atteint simplement en commentant les commandes printf().

Mais ce n'est pas tout. En effet, à ce stade, fastq.bio reçoit les résultats de l'analyse en appelant différentes fonctions C. Chacune d'elles calcule son propre ensemble de caractéristiques, de sorte que chaque fragment de fichier est lu deux fois.

Pour contourner ce problème, il a été décidé de combiner deux fonctions en une seule. En conséquence, les performances ont été multipliées par 20.

Comment nous avons multiplié par 20 la vitesse de l'application web grâce à WebAssembly

Il convient de noter qu'un tel résultat remarquable ne peut pas toujours être atteint. Dans certains cas, les performances chutent, donc il est important d'évaluer chaque situation spécifique.

En conclusion, on peut dire que Wasm permet effectivement d'améliorer les performances de l'application, mais il faut l'utiliser judicieusement.

Skillbox recommande :

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster