Le moteur JavaScript V8 9.0 améliore les performances d'appel de WebAssembly depuis JavaScript

Par:
fredericmazue

mer, 31/03/2021 - 16:31

V8, le moteur JavaScript de Google est au coeur de nombreux outils majeurs : Chrome, Node.js, Electron, Deno, notamment. V8 est mis à jour toutes les six semaines. Google vient de publier la version 9.0 bêta, qui viendra en version stable lors de la sortie de Chrome 90.

Google y a apporté une amélioration importante en ce qui concerne la performance des appels à WebAssembly depuis JavaScript.

V8 utilise différentes représentations pour les paramètres des fonctions WebAssembly et JavaScript. Pour cette raison, lorsque JavaScript appelle une fonction WebAssembly exportée, l'appel passe par un wrapper JS-to-Wasm, responsable de l'adaptation des paramètres de JavaScript pour WebAssembly ainsi que de l'adaptation des résultats dans la direction opposée.

Malheureusement, cela a un coût en termes de performances, ce qui signifie que les appels de JavaScript à WebAssembly n'étaient pas aussi rapides que les appels de JavaScript à JavaScript avant cette nouvelle version du moteur. Pour minimiser ce surcoût à l'exécution, l'encapsuleur JS-to-Wasm peut désormais être intégré au site d'appel, ce qui simplifie le code et supprime cette trame supplémentaire.

Supposons que nous avons une fonction WebAssembly pour ajouter deux nombres à virgule flottante double, comme ceci:

double addNumbers(double x, double y) {
  return x + y;
}

et supposons que nous appelons cette fonction à partir de JavaScript pour ajouter des vecteurs (représentés sous forme de tableaux typés):

const addNumbers = instance.exports.addNumbers;

function vectorSum(len, v1, v2) {
  const result = new Float64Array(len);
  for (let i = 0; i < len; i++) {
    result[i] = addNumbers(v1[i], v2[i]);
  }
  return result;
}

const N = 100_000_000;
const v1 = new Float64Array(N);
const v2 = new Float64Array(N);
for (let i = 0; i < N; i++) {
  v1[i] = Math.random();
  v2[i] = Math.random();
}

// Warm up
for (let i = 0; i < 5; i++) {
  vectorSum(N, v1, v2);
}

// Measure.
console.time();
const result = vectorSum(N, v1, v2);
console.timeEnd();

Selon Google le temps d'exécution est réduit de plus de la moitié :

Cette fonctionnalité est pour le moment expérimentale. Elle peut être activée via le commutateur --turbo-inline-js-wasm-calls

Google explique en détail cette fonctionnalité dans un document technique très intéressant, accessible ici.