GraalVM Native Image erfüllt RISC-V
Es ist jetzt möglich, GraalVM Native Image auf RISC-V zu verwenden! Ich erkläre hier, wie man Anwendungen für RISC-V kompiliert und die Implementierung durchführt. Standardmäßig verwendet Native Image den Graal-Compiler, um Maschinencode zu erzeugen, es kann jedoch stattdessen den LLVM-Compiler verwenden, indem das LLVM-Backend aktiviert wird ( Dokumentation ). Einer der Hauptgründe für die Verwendung von LLVM besteht darin, dass es eine Vielzahl von Architekturen unterstützt. Das bedeutet, dass wir den Graal-Compiler für sie nicht implementieren müssen, was der schwierigste Schritt beim Hinzufügen von Unterstützung für eine neue Architektur ist. Um dies zu demonstrieren, habe ich das Native Image LLVM-Backend für RISC-V-Maschinen unter Linux mit einem GraalVM-Dev-Build angepasst .
RISC-V
RISC-V ist eine Open-Source-Instruction Set Architecture (ISA), die 2010 entwickelt wurde. Der Hauptunterschied zwischen dieser Architektur und den aktuellen Marktführern besteht darin, dass RISC-V Open Source ist. Ursprünglich war die Verwendung für Forschung und Bildung vorgesehen, doch mittlerweile wächst das Interesse der Industrie.
Es verwendet eine einfache Basis-Ganzzahl-ISA, die eine Überanpassung spezifischer Mikroarchitekturmuster und überoptimierte Funktionen für bestimmte Domänen vermeidet, wodurch die Kosten gesenkt und die Leistung für einfachere Aufgaben verbessert werden. Für komplexere Anwendungen können Erweiterungen zusätzlich zur Basis-ISA hinzugefügt werden, z. B. Unterstützung für Multiplikation, Gleitkommazahlen, Vektoren und mehr. Einige dieser Erweiterungen sind vordefiniert, können aber auch benutzerdefiniert sein.
Mikronauten-Demonstration
Um den Leistungsunterschied zwischen der Ausführung auf der JVM und dem nativen Image zu zeigen, haben wir eine Demonstration basierend auf einer Micronaut-Anwendung, einem kleinen Webserver, auf einem RISC-V-Emulator durchgeführt. Die Demo-Quellen finden Sie hier .
Initialisierung des Micronaut-Servers mithilfe einer mit Native Image kompilierten Anwendung:
__ __ _ _
| \/ (_) ___ _ __ ___ _ __ __ _ _ _| |_
| |\/| | |/ __| '__/ _ \| '_ \ / _` | | | | __|
| | | | | (__| | | (_) | | | | (_| | |_| | |_
|_| |_|_|\___|_| \___/|_| |_|\__,_|\__,_|\__|
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-Binärdateien für RISC-V mit dem LLVM-Backend
Da die meisten aktuellen Methoden zum Ausführen von Linux auf einem RISC-V-Computer langsam sind, wird empfohlen, die Binärdateien für RISC-V übergreifend zu erstellen. Native Image unterstützt dies unter bestimmten Voraussetzungen.
RISC-V-Toolchain mit zlib
Die RISC-V-Toolchain muss Native Image bereitgestellt werden. Es ist hier zu finden . Die Versionen von gccund glibcmüssen dieselben oder älter sein als die, die von der RISC-V-Maschine verwendet werden.
zlibist in der RISC-V-Toolchain enthalten, muss jedoch manuell mit der erstellten Datei kompiliert werden riscv-gcc. Die ausgegebene Bibliothek libz.amuss nach verschoben werden path/to/built/toolchain/sysroot/usr/lib/.
CAPCaches und statische Bibliotheken
Die CAPCaches sind Informationen über C-Intrinsics auf der Zielarchitektur sowie die Werte der CPU-Funktionen und Flags. Sie können hier heruntergeladen werden .
Native Image benötigt statische Java- und Graal-Bibliotheken. Sie können hier heruntergeladen werden .
Vorgehensweise zum Cross-Build einer Binärdatei
Im folgenden Verfahren wird beschrieben, wie Sie eine Binärdatei aus einer einfachen Datei übergreifend erstellen HelloWorld.java.
Der erste Schritt besteht darin, die oben genannten Voraussetzungen zu erfüllen.
Laden Sie dann einen Entwicklungsbuild von GraalVM zusammen mit Native Image herunter.
Führen Sie abschließend die folgenden Befehle aus:
$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=riscv64ermöglicht Ihnen die Angabe der Zielarchitektur.-H:CompilerBackend=llvmGibt an, dass wir das LLVM-Backend verwenden.-H:CAPCacheDir=/path/to/capcacheStellt die vorberechneten CAPCaches für Native Image bereit.-H:CCompilerPath=/path/to/riscv-gccbietetgccvon der RISC-V-Toolchain bis hin zu Native Image.-H:CustomLD=/path/to/riscv-ldbietetldvon der RISC-V-Toolchain bis hin zu Native Image.-H:CLibraryPath=/path/to/static-librariesstellt die statischen Bibliotheken für Native Image bereit.
Berechnen Sie CAPCaches und kompilieren Sie statische Bibliotheken manuell
Um die CAPCaches oder die statischen Bibliotheken manuell abzurufen, besteht eine Lösung darin, Native Image auf RISC-V aus der Quelle zu erstellen. Dies kann mit den folgenden Befehlen erfolgen.
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
Führen Sie den folgenden Befehl aus, um die CAPCaches zu berechnen.
$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
Erstellen Sie nativ eine RISC-V-Binärdatei
Auch wenn die Cross-Build-Binärdateien empfohlen werden, ist es dennoch möglich, sie auf einer RISC-V-Maschine zu erstellen. Das Vorgehen ist dem Cross-Building sehr ähnlich. Die Toolchain wird nicht mehr benötigt, da es sich um die native handelt und die CAPCaches und die statischen Bibliotheken automatisch bereitgestellt werden. Der letzte Unterschied besteht im letzten Befehl:
$JAVA_HOME/bin/native-image HelloWorld -H:CompilerBackend=llvm \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.riscv64=org.graalvm.nativeimage.builder
Um das RISC-V-Ziel zu Native Image hinzuzufügen, mussten wir alle in der Dokumentation beschriebenen Änderungen implementieren . Es gibt jedoch noch einige andere nicht erwähnte Änderungen im Zusammenhang mit RISC-V.
JVMCI-Implementierung
Der Graal-Compiler hängt von der Java Virtual Machine Compiler Interface (JVMCI) ab, was bedeutet, dass diese Java-Unterkomponente implementiert werden muss, um Native Image zu verwenden, da sie vom Graal-Compiler abhängt. Obwohl das LLVM-Backend nicht den gesamten Graal-Compiler nutzt, nutzt es dennoch dessen Frontend und benötigt daher eine Teilmenge von JVMCI. Die Implementierung dieser Teilmenge für RISC-V finden Sie hier .
Abschluss
Das RISC-V LLVM-Backend unterstützt fast alle Funktionen, die auch die anderen LLVM-Backends unterstützen!
Es gibt noch viel zu tun, etwa die Unterstützung für macOS und andere Betriebssysteme hinzuzufügen. Es könnte interessant sein, einige zielspezifische Optimierungen zu untersuchen, da RISC-V einige bestimmte Register bereitstellt, über die nicht alle anderen Architekturen verfügen. Da gibt es zum Beispiel das Thread-Register ( x4).
Wenn man bedenkt, dass es nur etwa sechs Monate gedauert hat, mithilfe des LLVM-Backends RISC-V-Unterstützung zu Native Image hinzuzufügen, ist die Idee, Unterstützung für andere potenzielle Ziele wie WebAssembly hinzuzufügen, verlockend. Tatsächlich wird das Hinzufügen anderer Architekturen sogar noch einfacher, da das LLVM-Backend bald den Native-Image-Datenabschnitt selbst ausgeben wird, sodass das Hinzufügen von Informationen zu Objektdateien übersprungen werden kann.
Wir freuen uns über Ihr Feedback! Sie können es über Slack , GitHub , Twitter oder Mastodon teilen .

![Was ist überhaupt eine verknüpfte Liste? [Teil 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































