WebAssembly: quoi et comment


Cet article est basé sur ma présentation à la conférence ITSubbotnik, tenue le 2 novembre 2019 à Moscou.


En général, je suis programmeur backend, mais j'étais intéressé par cette technologie, elle me permet d'utiliser mes connaissances backend en front.


Le problème


Commençons par le problème qui est résolu par cette technologie (relativement nouvelle). Ce problème consiste à exécuter rapidement du code dans un navigateur . Rapide - cela signifie «plus rapide que JavaScript», idéalement aussi rapide que le permet notre processeur actuel.
De plus, historiquement, d'importantes exigences supplémentaires sont progressivement apparues autour de ce problème:


  • Configuration zéro - ce devrait être une solution "prête à l'emploi", rien qu'un navigateur.
  • Sûr - la nouvelle technologie ne doit pas créer de nouvelles menaces, nous avons déjà quelque chose à voir avec la sécurité.
  • Multiplateforme - les navigateurs fonctionnent sur tous les principaux processeurs, y compris les plates-formes mobiles.
  • Pratique pour les développeurs - c'est-à-dire pour nous.

L'histoire avant Wasm


Nous avons vu de nombreuses options pour exécuter du code dans un navigateur. On peut dire qu'il y a des gagnants et des perdants dans ce domaine.



Gagnants: Il s'agit définitivement de JavaScript; le moteur V8 qui a rendu JS si rapide; ainsi que HTML5.


Losers: ActiveX - si vous vous souvenez, cette technologie vous a permis de faire n'importe quoi avec la machine en général, c'est-à-dire la sécurité était très mauvaise; Flash - nous assistons maintenant à l'ère du déclin de Flash, bien qu'ActionScript fonctionne à l'intérieur, essentiellement le même JavaScript; Silverlight - il doit être apparu trop tard pour occuper une niche sérieuse.
En conséquence, tous les plugins ont été perdus, notamment en raison de problèmes de sécurité.


Il y a eu d'autres tentatives pour résoudre le problème, déjà dans le navigateur:


  • NaCl - Native Client proposé par Google; code natif directement dans le navigateur, ce qui convient bien sûr pour les plates-formes multiples; Mozilla n'a pas soutenu cette initiative, par conséquent, la mise en œuvre était uniquement dans Chrome.
  • PNaCl - Portable Native Client - un sous-ensemble de LLVM IR a été utilisé comme code portable; également n'était pas pris en charge dans Mozilla, encore une fois seulement Chrome. En conséquence, Google a refusé de prendre en charge PNaCl en mai 2017.

asm.js


asm.js est une autre initiative intéressante, déjà de la Fondation Mozilla, qui nous rapproche du sujet de WebAssembly. Il est apparu en 2010 et en 2013, il est devenu accessible au public.


asm.js est un sous-ensemble de JavaScript, vous pouvez compiler du code à partir de C et C ++ à l'aide du compilateur Emscripten.


Comme il s'agit également de JavaScript, ce code sera exécuté dans n'importe quel navigateur. De plus, les principaux navigateurs modernes sont depuis longtemps capables de reconnaître rapidement asm.js et de le compiler efficacement dans le code natif du processeur. Comparé au code natif obtenu directement à partir de C / C ++, le code obtenu à partir de asm.js est plus lent de 1,5 à 2 fois (50 à 67%).



À gauche se trouve le code de la fonction la plus simple en C / C ++, à droite, il montre ce qu'il transforme après compilation en asm.js. Tout d'abord, nous voyons ici la ligne 'use asm' , c'est un marqueur, qui indique clairement que le code pour asm.js va ensuite. Et dans ce code, nous voyons des constructions de la forme |0 , il s'agit d'une opération OR au niveau du bit avec une valeur nulle. Selon la spécification, le résultat de cette opération est un entier signé 32 bits. Mais ce type n'est même pas en JavaScript. Cependant, ce type résulte de cette opération, c'est-à-dire il s'agit essentiellement d'une conversion vers un type donné.


En général, asm.js est l'utilisation de notre connaissance de la façon dont le moteur de navigation compile JS afin d'optimiser ce travail.


Qu'est-ce que WebAssembly?



WebAssembly (ou Wasm ) est un format binaire exécuté dans un navigateur, une machine virtuelle et le résultat d'une compilation à partir d'un langage de haut niveau.


Wasm n'est pas un langage de programmation, tout comme le bytecode Java n'est pas un langage de programmation, mais un résultat de compilation et un bloc de code en cours d'exécution.


Quelqu'un de très intelligent a dit que le nom d'assemblage Web (c'est-à-dire «assembleur pour le Web») est complètement incorrect, car il ne s'agit pas d'un assembleur (pas d'un langage de programmation) et cela n'a rien à voir avec le Web (car ce n'est qu'une machine virtuelle).


Les créateurs de WebAssembly ont été guidés par les objectifs et limitations suivants - voir la vidéo Evolving Wasm en un mauvais nom: Andreas Rossberg .



En fait, ils se résument à trois choses: multiplateforme, compacte, vitesse. Mais il y avait une autre exigence importante, c'était la «vendabilité» - les développeurs des principaux navigateurs auraient dû prendre et prendre l'initiative. En conséquence, il a été possible de "vendre", des représentants de Google, Mozilla, Microsoft et Apple ont participé à l'élaboration de la spécification.


Voyons ce qu'est Wasm comme une machine virtuelle.



C'est un tel "processeur fictif", mais sans registres, tout se fait via la pile. Seulement quatre types de données: deux entiers, deux flottants. Ensemble d'opérations relativement simple - voir la spécification et le tableau interactif .



Modèle de mémoire plate: un seul bloc est alloué pour la mémoire, dont la taille est un multiple de 64 Ko. Voici le code, les données, les constantes, les variables globales, la pile qui grandit, le tas qui grandit. Vous pouvez augmenter automatiquement le segment de mémoire si nécessaire, tandis que le bloc de mémoire se développe par un multiple de 64 Ko.


Les pointeurs ne sont pas utilisés (cela est fait pour des raisons de sécurité), un index est utilisé à la place. L'index est de 32 bits, il traite donc jusqu'à 4 Go de mémoire.


Toute la mémoire WebAssembly est entièrement accessible à partir de JavaScript, à la fois pour la lecture et l'écriture.



Jetons un coup d'œil au modèle d'exécution WebAssembly. Wasm est toujours chargé et appelé UNIQUEMENT à partir de JavaScript. De plus, JS et Wasm fonctionnent dans le même bac à sable et sont exécutés par le même moteur.


Notez que vous pouvez également appeler JS depuis Wasm. Il peut s'agir d'un appel de fonction avec passage d'arguments et retour d'une valeur, ou il peut simplement être en train d'exécuter une chaîne arbitraire en tant que code JS.


Essayer WebAssembly


Afin de commencer avec WebAssembly, je recommande d'utiliser le site Web WasmFiddle ou WebAssembly Studio - c'est un moyen simple et visuel de comprendre par vous-même ce qu'est vraiment Wasm.



Ici, le code source en C / C ++ est en haut à gauche (dans ce cas, la fonction récursive pour calculer le nombre de Fibonacci), en haut à droite est le code JS pour charger le Wasm, instancier le module Wasm et appeler la fonction fib() depuis celui-ci. Lorsque nous appuyons sur le bouton Build, nous obtenons un bloc de code Wasm (fichier .wasm), que nous pouvons toujours développer en une représentation textuelle (fichier .wat).


Cette représentation textuelle avec un ensemble de crochets est essentiellement un arbre de syntaxe abstraite (AST). Eh bien, en fait avec un crochet, il ressemble au langage Lisp. En théorie, nous pouvons éditer le code sous forme de représentation textuelle, puis le réduire à nouveau dans un format binaire - cela rappelle la programmation en langage assembleur. Mais généralement, nous obtenons du Wasm binaire à la suite de la compilation à partir d'un langage de haut niveau.


2017: Prêt pour la production


En novembre 2017, WebAssembly a été déclaré «prêt à l'emploi en production». La spécification pour toutes les parties principales de Wasm a été préparée, l'implémentation de Wasm a été publiée dans tous les principaux navigateurs. Ainsi, pour WebAssembly, MVP a été publié - Minimum Viable Product, version 1.0, dont nous traitons maintenant.


Prise en charge du navigateur


Fin 2017, les versions de tous les principaux navigateurs prenant en charge WebAssembly ont été publiées:



L'exception est IE11, il n'est pas pris en charge et il est probable qu'il disparaîtra. Il a été supposé que pour les navigateurs plus anciens, il y aura un polyfill - la possibilité de convertir Wasm en asm.js; il y a de tels prototypes, mais à ce que je sache, ces projets sont abandonnés, apparemment, la communauté n'est pas à la hauteur.


Désormais, parmi tous les navigateurs installés, ~ 88% prennent en charge Wasm .



Prise en charge linguistique


Pour que votre langue préférée compile dans Wasm, vous avez besoin du compilateur pour fournir cet objectif de compilation. Maintenant, plusieurs langues prennent en charge Wasm, et il y en a de plus en plus chaque mois. Voir appcypher / awesome-wasm-langs .


  • C / C ++ - via Emscripten , très bon support.
  • Rust - Le support de Wasm est apparu il y a longtemps, l'écosystème autour de Wasm est construit en grande partie sur la base de Rust.
  • Java - via TeaVM, JWebAssembly, Bytecoder - à un niveau expérimental.
  • Kotlin - il y a un support dans Kotlin / Native via le backend LLVM - expérimental.
  • Allez
  • C # - via Blazor (mono) et à l'avenir sur Uno Platform .
  • TypeScript - via AssemblyScript .

Il n'y a pas si longtemps, il y avait des nouvelles que LLVM supporte maintenant Wasm comme cible de compilation. Cela permet aux développeurs de langages de programmation d'obtenir plus de langages de compilation dans Wasm.


Cas d'utilisation


C'est probablement l'une des principales questions - "Comment puis-je utiliser Wasm?"


WebAssembly utilise déjà activement:


  • Jeux, moteurs de jeux, moteurs physiques, VR / AR - par exemple, Godot , Doom 3
  • Émulateurs, machines virtuelles - par exemple, DOSBox
  • Éditeurs graphiques / 3D - Figma , AutoCAD
  • Clients Web pour les plateformes de trading financier - J'ai vu des présentations sur deux de ces clients
  • Codecs et filtres audio / vidéo - par exemple ffmpeg
  • Bases de données - par exemple sqlite

Autres scénarios possibles:


  • Applications Web progressives (PWA)
  • Reconnaissance par un réseau neuronal formé

Performances


La performance de Wasm était l'un de ses principaux facteurs de vente, mais que se passe-t-il vraiment?


Par rapport à JavaScript, il s'avère qu'en moyenne, Wasm est plus rapide, mais dans chaque cas particulier, vous devez faire une comparaison JS / Wasm, car il peut s'avérer être beaucoup mieux et plusieurs fois pire. Il peut également dépendre fortement du navigateur utilisé.


En fait, les performances de pointe de JS et Wasm sont les mêmes, car les deux finissent par se transformer en code processeur natif. Mais JS est beaucoup plus facile à perdre en performances, et Wasm propose une approche plus "uniforme".


En règle générale, Wasm fonctionne bien en calcul volumétrique. Là où il y a beaucoup d'opérations de mémoire, Wasm perd. Eh bien, le principal problème dans les applications réelles est l'interopérabilité lente de JS <-> Wasm. Voir par exemple un benchmark .



En juillet 2019, l'article scientifique «Pas si vite: analyse des performances de WebAssembly vs. Code natif . " Les auteurs ont mis en œuvre la possibilité d'exécuter des utilitaires de console Linux sous WebAssembly pour exécuter des tests de performance et ont utilisé des tests de performance SPEC pour évaluer les performances de Wasm par rapport aux mêmes tests sur asm.js et le code natif.


Les résultats sont les suivants:


  • Wasm 30% plus rapide que JavaScript (moyenne pour ces tests)
  • Wasm est 50% plus lent que le code natif (en moyenne dans ces tests)

Les auteurs de l'article ont également analysé les raisons pour lesquelles Wasm «ralentit»:


  • environ deux fois plus d'opérations de chargement / sauvegarde de données par rapport au code natif;
  • plus de branches - causées par la nécessité de contrôles supplémentaires lors de l'accès à la mémoire;
  • plus de ratés après le cache L1.

En général, en fait, les performances ne sont pas si mauvaises. De plus, cette analyse permettra aux développeurs de navigateurs de rendre Wasm encore plus rapide.


À l'avenir, Wem accélérera non seulement en raison d'une meilleure optimisation des navigateurs, mais également en raison de nouvelles fonctionnalités, telles que: les opérations de blocage sur la mémoire, la prise en charge des instructions SIMD, la prise en charge des threads.


Que se passera-t-il ensuite?


Comment se développe WebAssembly?


Premièrement, l'équipe de spécification de Wasm poursuit son travail. Les spécifications sont à différents stades (phases), il existe une certaine «feuille de route» pour ce travail.


En particulier, dans un proche avenir, nous nous attendons à voir de telles fonctionnalités plus loin:


  • Conversions float-to-int sans recouvrement - désormais la conversion d'une valeur flottante en un entier dans certaines conditions peut provoquer une exception; Pour un programmeur, c'est assez inattendu, donc toutes ces conversions doivent être encapsulées, ce qui réduit les performances à ce sujet. Cette fonctionnalité résout le problème.
  • Multi-valeur - la possibilité de renvoyer plus d'une valeur à partir d'une fonction, la possibilité de créer de nouvelles instructions qui renvoient plus d'une valeur - par exemple, le résultat de la division et le reste de la division, ou le résultat de l'addition et du bit de retenue.
  • Les types de référence sont une introduction du type anyref, qui signifie «lien vers quelque chose sur le tas JS», la première étape pour accélérer l'interaction avec JS.

Deuxièmement, les développeurs de navigateurs mettent en œuvre ces spécifications, c'est-à-dire progressivement de nouvelles fonctionnalités sont ajoutées à Wasm, d'abord cachées «sous le drapeau» dans les paramètres, puis activées par défaut.


Par exemple, voici une liste des fonctionnalités de Chrome liées à WebAssembly .
Pour Firefox, une liste similaire peut être trouvée ici .


WebAssembly en dehors du navigateur


Comme mentionné ci-dessus, Wasm n'est essentiellement pas connecté au Web, c'est juste une machine virtuelle. Cela signifie qu'il peut également être utilisé en dehors du Web.


Il existe maintenant plusieurs scénarios d'utilisation de Wasm en dehors du navigateur:


  • Node.js - Node.js est basé sur le moteur V8 qui prend en charge Wasm.
  • Une application console distincte, le code d'application est exécuté dans Wasm VM - exemples d'un tel runtime: wasmtime , wasmer.
  • Wasm VM est utilisé comme bibliothèque à partir d'autres langues - par exemple, wasmer vous permet de vous appeler à partir d'une douzaine de langues différentes.

Pour Wasm travaillant en dehors du navigateur, les restrictions sandbox ne sont plus nécessaires, au contraire, l'accès aux fonctions système est nécessaire - le système de fichiers et les fichiers, les E / S de la console, etc. Cela a conduit à la création de l'interface système WebAssembly (WASI), une spécification d'API multiplateforme similaire à POSIX. Voir WebAssembly / WASI et wasi.dev .



L'étape suivante consistait à créer un gestionnaire de packages - Wasm Package Manager (WAPM) - wapm.io. Ici, vous pouvez prendre le fichier .wasm terminé et l'utiliser dans votre application. Habituellement, nous parlons des versions Wasm de certaines bibliothèques bien connues. Certains packages sont étiquetés avec la balise WASI, ce qui signifie qu'ils ne peuvent être utilisés que dans des scénarios en dehors du navigateur.


Conclusion


Ainsi, WebAssembly est tout à fait possible à utiliser, il est «prêt pour la production» depuis maintenant deux ans.
L'utilisation de Wasm peut bien donner une accélération par rapport à un code JavaScript similaire, mais vous devriez toujours vérifier si vous obtenez un boost de vitesse.
Le support Wasm des langages de programmation est en constante évolution.


Eh bien et surtout, WebAssembly a quelque peu «changé le paysage» du Web - nous a fourni de nouveaux scénarios d'utilisation que nous pouvons implémenter dans nos applications.


Les références



Super listes:



Vidéo:


Source: https://habr.com/ru/post/fr475778/


All Articles