GraalVM Native Image rencontre RISC-V
Il est désormais possible d'utiliser GraalVM Native Image sur RISC-V ! Je vais vous expliquer ici comment compiler des applications pour RISC-V et l'implémentation. Par défaut, Native Image utilise le compilateur Graal pour produire du code machine, mais il peut utiliser le compilateur LLVM à la place en activant le backend LLVM ( documentation ). L'une des principales raisons d'utiliser LLVM est qu'il prend en charge un large éventail d'architectures, ce qui signifie que nous n'avons pas besoin d'implémenter le compilateur Graal pour elles, ce qui est l'étape la plus difficile lors de l'ajout de la prise en charge d'une nouvelle architecture. Pour le démontrer, j'ai adapté le backend Native Image LLVM pour les machines RISC-V sous Linux avec une version de développement GraalVM .
RISC-V
RISC-V est une architecture de jeu d'instructions (ISA) open source créée en 2010. La principale différence entre cette architecture et les leaders actuels du marché est le fait que RISC-V est open source. Alors que sa première utilisation prévue était pour la recherche et l'éducation, l'intérêt de l'industrie est maintenant croissant.
Il utilise un simple ISA entier de base, qui évite de trop ajuster des modèles micro-architecturaux spécifiques et des fonctionnalités sur-optimisées conçues pour des domaines particuliers, réduisant ainsi les coûts et améliorant les performances pour des tâches plus simples. Pour des utilisations plus complexes, des extensions peuvent être ajoutées au-dessus de l'ISA de base, telles que la prise en charge de la multiplication, des virgules flottantes, des vecteurs, etc. Certaines de ces extensions sont prédéfinies, mais elles peuvent également être personnalisées.
Démonstration de micronautes
Pour montrer la différence de performances entre l'exécution sur la JVM et l'image native, nous avons effectué une démonstration basée sur une application Micronaut, un petit serveur Web, sur un émulateur RISC-V. Les sources de démonstration peuvent être trouvées ici .
Initialisation du serveur Micronaut à l'aide d'une application compilée avec Native Image :
__ __ _ _
| \/ (_) ___ _ __ ___ _ __ __ _ _ _| |_
| |\/| | |/ __| '__/ _ \| '_ \ / _` | | | | __|
| | | | | (__| | | (_) | | | | (_| | |_| | |_
|_| |_|_|\___|_| \___/|_| |_|\__,_|\__,_|\__|
Micronaut (v3.6.0)
16:52:29.965 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 305ms. Server Running: http://fedora-riscv:8080
Cross-build binaires pour RISC-V avec le backend LLVM
Étant donné que la plupart des méthodes actuelles d'exécution de Linux sur une machine RISC-V sont lentes, il est conseillé de créer de manière croisée les binaires pour RISC-V. Native Image le prend en charge avec quelques prérequis.
Chaîne d'outils RISC-V avec zlib
La chaîne d'outils RISC-V doit être fournie à Native Image. Il peut être trouvé ici . Les versions de gccet glibcdoivent être identiques ou antérieures à celles utilisées par la machine RISC-V.
zlibest inclus dans la chaîne d'outils RISC-V mais doit être compilé manuellement à l'aide du fichier riscv-gcc. La bibliothèque générée libz.adoit être déplacée vers path/to/built/toolchain/sysroot/usr/lib/.
CAPCaches et bibliothèques statiques
Les CAPCaches sont des informations sur les intrinsèques C sur l'architecture cible, ainsi que sur les valeurs des fonctionnalités et des drapeaux du processeur. Ils peuvent être téléchargés ici .
Native Image a besoin des bibliothèques statiques Java et Graal. Ils peuvent être téléchargés ici .
Procédure de construction croisée d'un binaire
La procédure suivante décrit comment construire de manière croisée un binaire à partir d'un simple HelloWorld.javafichier.
La première étape consiste à remplir les conditions préalables mentionnées ci-dessus.
Ensuite, téléchargez une version de développement de GraalVM avec Native Image.
Enfin, exécutez les commandes suivantes :
$JAVA_HOME/bin/javac Helloworld.java
$JAVA_HOME/bin/native-image HelloWorld -H:CompilerBackend=llvm \
-Dsvm.targetPlatformArch=riscv64 -H:CAPCacheDir=/path/to/capcache \
-H:CCompilerPath=/path/to/riscv-gcc -H:CustomLD=/path/to/riscv-ld \
-H:CLibraryPath=/path/to/static-libraries \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.riscv64=org.graalvm.nativeimage.builder
-Dsvm.targetPlatformArch=riscv64permet de spécifier l'architecture cible.-H:CompilerBackend=llvmspécifie que nous utilisons le backend LLVM.-H:CAPCacheDir=/path/to/capcachefournit les CAPCaches précalculés à Native Image.-H:CCompilerPath=/path/to/riscv-gccfournitgccde la chaîne d'outils RISC-V à Native Image.-H:CustomLD=/path/to/riscv-ldfournitldde la chaîne d'outils RISC-V à Native Image.-H:CLibraryPath=/path/to/static-librariesfournit les bibliothèques statiques à Native Image.
Calculer les CAPCaches et compiler manuellement les bibliothèques statiques
Pour obtenir manuellement les CAPCaches ou les bibliothèques statiques, une solution consiste à créer une image native sur RISC-V à partir de la source. Cela peut être fait en utilisant les commandes suivantes.
git clone https://github.com/oracle/graal.git
git clone https://github.com/graalvm/mx.git
export PATH=$PWD/mx:$PATH
cd graal/substratevm
mx fetch-jdk
# Choose one of the jdk version and run the provided export command
export SKIP_LIBRARIES=true
mx build
Pour calculer les CAPCaches, exécutez la commande suivante.
$JAVA_HOME/bin/native-image HelloWorld -H:CompilerBackend=llvm \
-H:+ExitAfterCAPCache -H:CAPCacheDir=/path/to/capcache -H:+NewCAPCache \
-add-exports=jdk.internal.vm.ci/jdk.vm.ci.riscv64=org.graalvm.nativeimage.builder
Construire un binaire RISC-V en mode natif
Même s'il est recommandé de construire des binaires croisés, il est toujours possible de les construire sur une machine RISC-V. La procédure est très similaire à la construction croisée. La chaîne d'outils n'est plus nécessaire, car ce sera la chaîne native, et les CAPCaches et les bibliothèques statiques seront fournies automatiquement. La dernière différence est dans la commande finale :
$JAVA_HOME/bin/native-image HelloWorld -H:CompilerBackend=llvm \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.riscv64=org.graalvm.nativeimage.builder
Pour ajouter la cible RISC-V à Native Image, nous avons dû implémenter toutes les modifications décrites dans la documentation . Il existe cependant d'autres changements non mentionnés liés à RISC-V.
Implémentation JVMCI
Le compilateur Graal dépend de l'interface JVMCI (Java Virtual Machine Compiler Interface), ce qui signifie que ce sous-composant Java doit être implémenté pour utiliser Native Image car il dépend du compilateur Graal. Bien que le backend LLVM n'utilise pas tout le compilateur Graal, il utilise toujours son frontend et a donc besoin d'un sous-ensemble de JVMCI. L'implémentation de ce sous-ensemble pour RISC-V peut être trouvée ici .
Conclusion
Le backend RISC-V LLVM prend en charge presque toutes les fonctionnalités prises en charge par les autres backends LLVM !
Il reste encore du travail à faire, comme ajouter la prise en charge de macOS et d'autres systèmes d'exploitation. Certaines optimisations spécifiques à la cible peuvent être intéressantes à étudier puisque RISC-V fournit certains registres particuliers que toutes les autres architectures n'ont pas. Par exemple, il y a le registre de thread ( x4).
Considérant qu'il n'a fallu qu'environ six mois pour ajouter la prise en charge de RISC-V à Native Image à l'aide du backend LLVM, l'idée d'ajouter la prise en charge d'autres cibles potentielles telles que WebAssembly est attrayante. En fait, l'ajout d'autres architectures deviendra encore plus accessible, car le backend LLVM émettra bientôt la section de données Native Image lui-même, lui permettant d'ignorer l'ajout d'informations sur les fichiers objets.
Vos commentaires sont les bienvenus ! Vous pouvez le partager via Slack , GitHub , Twitter ou Mastodon .
![Qu'est-ce qu'une liste liée, de toute façon? [Partie 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































