VT2020-GraalVM-Fiche

From air
Jump to navigation Jump to search

Rappels sur l'architecture de la plateforme Java

L'architecture de GraalVM se basant sur celle d'un Java Development Toolkit, un rappel sur le fonctionnement de la plateforme Java peut s'avérer utile.

Tout d'abord, le Java a la particularité d'être un langage à la fois compilé et interprété. Les tâches de compilation et d'interprétation sont distinctes et réalisées par des composants différents. Comme on peut le voir sur le schéma ci-dessous, le code Java est d'abord compilé en bytecode par un Java Compiler pour ensuite être interprété et exécuté par une Java Virtual Machine.

Composition d'un JDK

Il faut donc distinguer dans cette architecture :

  • La Java Virtual Machine (JVM), qui interprète et exécute le code.
  • Le Java Runtime Environment (JRE), qui est un environnement d'exécution contenant des librairies et la JVM.
  • Le Java Development Toolkit (JDK), qui est composé de librairies en Java, du JRE et du Java Compiler.

GraalVM

Abstract

"GraalVM is a high-performance multilingual runtime. It is designed to accelerate the execution of applications written in Java and other JVM languages while also providing runtimes for JavaScript, Ruby, Python, and a number of other popular languages. GraalVM’s polyglot capabilities make it possible to mix multiple programming languages in a single application while eliminating any foreign language call costs."

Documentation officielle de GraalVM

Origines

Constats

Malgré son apparente popularité, le langage Java est sur le déclin. A l'origine, ce langage conçue par Sun Microsystems et dit "JVM" (comme Kotlin ou Scala) avait été conçu avec l'idée de pouvoir être exécuté sur n'importe quelle plateforme ayant une JVM, affranchissant ainsi le développeur des spécifités d'exécution de la plateforme (d'où le slogan "Write Once Run Anywere"). Cependant, à cause la surcouche logicielle induite par la JVM, le langage Java a essuyé des critiques sur sa performance et sur sa verbosité.

S'ajoute à cela un regain de popularité des langages natifs dans les années 2010, notamment grâce à Apple et son développement mobile iOS en Objective-C qui contraste avec Java ou Kotlin (étant tous deux des langages JVM) en terme de performance.

Pour répondre à ces problématiques, l'entreprise Oracle se doit d'adapter constamment Java afin de rester compétitive, et sa JVM avec.

Ce qui existait déjà

Evidemment, Java fonctionnait bien avant l'arrivée de GraalVM, ce qui signifie qu'il existait donc déjà des machines virtuelles. La plus utilisée d'entre elles est HotSpot, écrites en C++. Elle a été créé par Sun et appartient aujourd'hui à Oracle depuis le rachat de Sun. Notez que toutes les JVM (ou autres composants de la plateforme Java), ne sont pas forcément propriété d'Oracle : par exemple, OpenJ9 est une JVM dont la propriété revient à IBM et à la fondation Eclipse. Ces composants doivent ceci dit respecter des spécifications dictées par Sun (https://docs.oracle.com/javase/specs/).

La première version de Hotspot n'était qu'un interpréteur, puis elle a été améliorée avec un ajout de la compilation à la volée (Just-In-Time). Ensuite elle a été capable de détecter les portions de code les plus fréquemment utilisés et de les optimiser.

Ceci dit, GraalVM trouve ses racines dans le projet Maxine (dévelopé par Sun Microsystems Laboratories en 2005), dont l'objectif était d'écrire une JVM en langage Java pour s'affranchir des problèmes de développement liés au C++, plus particulièrement la gestion de la mémoire. Le projet s'est avéré trop ambitieux à l'époque mais a servi de point de départ pour GraalVM presque 15 ans plus tard.

Solution

Les objectifs ayant mené à la création de GraalVM sont multiples :

  • Avoir un environnement qui accélère l'exécution des applications écrites en Java ou d'autres langages JVM afin de rivaliser avec les langages natifs
  • Fournir un environnement d'exécution qui supporte plusieurs langages de programmation, supprimant ainsi l'isolation entre eux et établissant une véritable inter-opérabilité.

La solution développée est GraalVM, une machine virtuelle haute performance (d'après les dires d'Oracle) qui prend en fait la forme d'un JDK dont la partie VM a été grandement améliorée.

Fonctionnalités

Les principaux atouts de GraalVM sont:

  • Graal Compiler, un nouveau compilateur JIT (Just-In-Time) pour Java
  • GraalVM Native Image, permettant la compilation AOT (Ahead-Of-Time) pour les applications Java
  • Truffle Language Implementation framework et GraalVM SDK, fournissant des runtimes pour d'autres langages de programmation
  • LLVM Runtime et JavaScript Runtime

On a en plus la possibilité d'installer des langages et même de définir le nôtre. Actuellement, tous les langages suivants sont compatibles avec Graal (moyennant installations supplémentaires) : Listes des langages compatibles avec GraalVM

Architecture

Architecture de la JVM GraalVM

GraalVM réutilise l'architecture d'OpenJDK (qui est sans grande surprise un JDK), mais avec quelques particularités au niveau de la JVM :

  • Il réutilise la VM Hotspot, mais de laquelle on a retiré le JIT Compiler.
  • Il bénéficie d'un nouveau compilateur JIT, Graal Compiler, écrit en Java et en dehors de Hotspot. Il a pour mission de transformer du bytecode en code machine (ne pas confondre avec le Java Compiler, plus haut niveau).
  • Pour permettre à la JVM Hotspot d'utiliser un compilateur écrit en Java, une couche intermédiaire est nécessaire : la JVM Compiler Interface.
  • Tout ce qui doit arriver au compilateur JIT doit être du bytecode. C'est pourquoi les langages non-JVM ne peuvent pas être directement pris en entrée de Graal Compiler. La couche Truffle framework répond à cette problématique. Truffle est un framework open-source qui sert à définir nos propres langages de programmation à travers un AST (Abstract Syntax Tree) et à construire des interpréteurs pour ce dernier. Il est réutilisé dans GraalVM pour définir des implémentations Truffle de Python, Ruby ou encore Javascript.
  • La couche Truffle suffisait pour les langages interprétés puisque Truffle construit des interpréteurs. Mais pour les langages LLVM (Low Level Virtual Machine) comme le C, le C++ ou le Fortran, une surcouche est nécessaire. Sulong est une LLVM qui permet de produire du bitcode en s'appuyant sur les fonctionnalités de Truffle.

Utilisation

Installation

GraalVM est très simple à installer.

java -version
  • Dézippez l'archive à l'endroit de votre choix.
tar -xzf <graalvm-archive>.tar.gz
  • Configurez votre variable d'environnement PATH:
export PATH=<graalvm>/bin:$PATH

Si vous souhaitez remplacer votre JDK par GraalVM pour toutes vos applications utilisant Java, vous pouvez changer la variable d'environnement JAVA_HOME.

export JAVA_HOME=<graalvm>

Si vous ne souhaitez pas modifier votre JAVA_HOME, vous pouvez définir une variable d'environnement GRAAL_HOME qui vous sera utile pour ne pas avoir à réécrire le chemin complet de Graal. Notez également que vous pouvez rendre les commandes au-dessus permanentes en les ajoutant à votre fichier .bashrc ou .zshrc.

Exécution

Le dossier /bin est similaire à un JDK standard, mais contient des launchers additionnels (en plus de javac pour le Java):

  • js, un launcher JavaScript
  • node, un launcher Node.js
  • lli, un launcher LLVM

En d'autres termes, GraalVM ne comprend que le Java, Node.js (grâce au Javascript Runtime) et les langages LLVM (grâce au LLVM Runtime). Cependant, d'autres launchers peuvent être installés avec la commande :

gu install <nom_du_langage>

Par ligne de commande

En règle générale, les commandes d'exécution sont de la forme :

<nom_du_laucher> <nom_du_programme>

Par exemple :

node app.js

Les programmes LLVM doivent êtres compilés avant avec l'outil LLVM Toolchain car le launcher lli ne comprend que du bitcode :

gu install llvm-toolchain
export LLVM_TOOLCHAIN=$(lli --print-toolchain-path)
$LLVM_TOOLCHAIN/clang hello.c -o hello
lli hello

Dans un IDE

Dans l'IDE, il suffit de remplacer le path du JRE ou du JDK par le path de GraalVM. Sous eclipse par exemple, cela peut se faire en allant dans Window/Preferences/Java/Installed JREs.

Spécification du JDK dans l'IDE

Limites

Même si les promesses de GraalVM, à savoir l'amélioration des performances à l'exécution des langages JVM et le polyglottisme, sont respectées, l'outil d'Oracle rencontre quand même quelques limites :

  • On peut regretter que les langages les plus bas niveaux comme le C soient paradoxalement ceux qui traversent le plus de couches logicielles dans l'architecture de GraalVM. Leur interêt en termes de performance est donc extrêmement diminué puisqu'ils nécessitent de nombreuses opérations pour être transformé en bytecode, bytecode qui est logé à la même enseigne que le bytecode issu de code Java au yeux du compilateur.
  • En règle générale, les performances hors langages JVM sont tout de même loins d'être extraordinaires. L'inter-opérabilité entre langages est fonctionnelles mais coûteuse en ressources.
  • Les langages compris par GraalVM étant en fait des implémentations Truffle de langages et pas les langages en eux-mêmes, il manque les librairies utiles à chaque langage. Il est donc impossible par exemple, d'utiliser matplolib dans un programme Python. Les programmes en sont plus ou moins réduit à de l'algorithmie selon les capacités natives du langage.

Demonstration

Sources

Veille Technologique 2020