GraalVM Native Image erfüllt RISC-V

Jan 17 2023
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 zum Erstellen von Maschinencode, kann jedoch stattdessen den LLVM-Compiler verwenden, indem das LLVM-Backend aktiviert wird (Dokumentation).

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-gccbietet gccvon der RISC-V-Toolchain bis hin zu Native Image.
  • -H:CustomLD=/path/to/riscv-ldbietet ldvon 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 .