原文はこちら。
The original article was written by Sacha Coppey (GraalVM in Oracle Labs).
https://medium.com/graalvm/graalvm-native-image-meets-risc-v-899be38eddd9
RISC-V上でGraalVM Native Imageが使えるようになりました。このエントリでは、RISC-V用のアプリケーションをコンパイルする方法と、その実装について説明します。Native Imageは、デフォルトではGraalコンパイラを使用してマシンコードを生成しますが、LLVMバックエンドを有効にすると、Graalコンパイラの代わりにLLVMコンパイラを使用できます。
LLVM Backend for Native Image
https://graalvm.org/22.2/reference-manual/native-image/LLVMBackend/
LLVMを使用する主な理由の1つは、幅広いアーキテクチャをサポートしている点です。つまり、新しいアーキテクチャのサポートを追加する際に最も困難なステップである、新アーキテクチャ用のGraalコンパイラの実装が必要ないのです。これを実証するために、GraalVM開発ビルドを使用して、Linux上のRISC-Vマシン用にNative Image LLVMバックエンドを適合させました。
graalvm/graalvm-ce-dev-builds
https://github.com/graalvm/graalvm-ce-dev-builds/releases
RISC-V
RISC-Vは、2010年に作成されたオープンソースのInstruction Set Architecture (ISA、命令セットアーキテクチャ)です。現在市場をリードしているアーキテクチャとの主な違いは、RISC-Vがオープンソースであることです。当初の用途は研究・教育用でしたが、現在では産業界からの関心も高まっています。
シンプルな基本整数ISA(命令セットアーキテクチャ)を採用しているため、特定のマイクロアーキテクチャパターンや、特定のドメイン向けに設計された過剰な最適化機能を避けることができ、より単純なタスクのコスト削減と性能向上を実現しています。より複雑な用途には、乗算、浮動小数点、ベクトルなどのサポートなど、基本ISA上に拡張機能を追加できます。これらの拡張機能は、あらかじめ定義されているものもありますが、カスタムで対応もできます。
Micronaut Demonstration
JVMとNative Imageで実行した場合の性能差を示すために、RISC-Vエミュレータ上で小型WebサーバであるMicronautアプリケーションをベースにしたデモを実施しました。デモアプリのソースは以下にあります。
graalvm-demos/micronaut-nativeimage
https://github.com/graalvm/graalvm-demos/tree/master/micronaut-nativeimage
Native Imageでコンパイルしたアプリケーションを用いたMicronautサーバーの初期化
__ __ _ _
| \/ (_) ___ _ __ ___ _ __ __ _ _ _| |_
| |\/| | |/ __| '__/ _ \| '_ \ / _` | | | | __|
| | | | | (__| | | (_) | | | | (_| | |_| | |_
|_| |_|_|\___|_| \___/|_| |_|\__,_|\__,_|\__|
Micronaut (v3.6.0)
16:52:29.965 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 305ms. Server Running: http://fedora-riscv:8080
Native ImageでコンパイルしたMicronautアプリケーションでは、起動時間が〜300msでしたが、Javaを使用した場合の起動時間は約9300msです。Native Imageを使用して、約31倍のスピードアップを実現しました。
Cross-build Binaries for RISC-V with the LLVM Backend
ほとんどの場合、RISC-Vマシン上でのLinuxの実行が遅いことを考慮し、RISC-V用のバイナリのクロスビルドをお勧めします。Native Imageは、いくつかの前提条件付きでこれをサポートしています。
RISC-V Toolchain with zlib
RISC-VツールチェーンをNative Imageに提供する必要がありますが、その方法は以下に記載があります。gcc
とglibc
のバージョンは、RISC-Vマシンで使用されているものと同じか古いものである必要があります。
GNU toolchain for RISC-V, including GCC
https://github.com/riscv-collab/riscv-gnu-toolchain
zlib
はRISC-Vのツールチェーンに含まれていますが、生成されたriscv-gcc
を使い手動でコンパイルする必要があります。出力されたライブラリlibz.a
は、path/to/built/toolchain/sysroot/usr/lib/
に移動する必要があります。
CAPCaches and Static Libraries
CAPCachesは、ターゲット・アーキテクチャのC intrinsicsに関する情報、およびCPUの機能、フラグの値で、こちらからダウンロードできます。
Native ImageではJavaとGraalの静的ライブラリが必要です。これらはこちらからダウンロードできます。
Procedure to Cross-Build a Binary
以下は、単純なHelloWorld.javaファイルからバイナリをクロスビルドする手順です。
まず、上記の前提条件を満たしている必要があります。続いて、GraalVMの開発ビルドをNative Imageと一緒にダウンロードします。
graalvm/graalvm-ce-dev-builds
https://github.com/graalvm/graalvm-ce-dev-builds/releases
最後に、以下のコマンドを実行します。
$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
Options Explanation
種々のオプションが利用できますが、その一例をご紹介します。
option | description |
---|---|
-Dsvm.targetPlatformArch=riscv64 | ターゲットアーキテクチャの指定 |
-H:CompilerBackend=llvm | LLVMバックエンドの利用を指定 |
-H:CAPCacheDir=/path/to/capcache | 事前計算済みのCAPCacheをNative Imageに提供 |
-H:CCompilerPath=/path/to/riscv-gcc | RISC-Vツールチェーンのgcc をNative Imageに提供 |
-H:CustomLD=/path/to/riscv-ld | RISC-Vツールチェーンのld をNative Imageに提供 |
-H:CLibraryPath=/path/to/static-libraries | 静的ライブラリをNative Imageに提供 |
LLVMバックエンドやその他のオプションに関する詳細情報は、以下のドキュメントをご覧ください。
LLVM Backend for Native Image
https://graalvm.org/22.2/reference-manual/native-image/LLVMBackend/
Compute CAPCaches and Compile Static Libraries Manually
CAPCacheや静的ライブラリを手動で得るのであれば、RISC-V上のNative Imageをソースからビルドするのが1つの方法です。これは、以下のコマンドで可能です。
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
上記コマンドにより、静的ライブラリは graal/sdk/latest_graalvm_home/lib
と graal/sdk/latest_graalvm_home/lib/svm/clibraries/linux-riscv64/
に配置されます。
CAPCacheの計算では以下のコマンドを実行します。
$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
CAPCacheは /path/to/capcache
に格納されます。
Build a RISC-V Binary Natively
バイナリのクロスビルドを推奨しているとはいえ、RISC-Vマシンでビルドも可能です。手順はクロスビルドと非常に似ています。ネイティブビルドの場合、別途用意すべきツールチェインはありません。というのも、利用するツールチェーンはネイティブなものであり、CAPCachesとスタティックライブラリが自動的に提供されるためです。違いは、最後のコマンドにあります。
$JAVA_HOME/bin/native-image HelloWorld -H:CompilerBackend=llvm \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.riscv64=org.graalvm.nativeimage.builder
Implementation
Native ImageにRISC-Vターゲットを追加するために、以下のドキュメントに記載されているすべての変更を実装する必要がありました。ただし、RISC-Vに関連する未記載の変更もいくつかあります。
LLVM Backend for Native Image
https://graalvm.org/22.2/reference-manual/native-image/LLVMBackend/
JVMCI Implementation
GraalコンパイラはJava Virtual Machine Compiler Interface(JVMCI)に依存しています。つまり、Native ImageはGraalコンパイラに依存しているため、このJavaサブコンポーネントをNative Imageを使って実装する必要があります。LLVMバックエンドはGraalコンパイラ全体を使用しませんが、そのフロントエンドを使用するため、JVMCIのサブセットを必要とします。このサブセットのRISC-V向け実装は、以下から確認できます。
8290154: [JVMCI] partially implement JVMCI for RISC-V #9587
https://github.com/openjdk/jdk/pull/9587
Conclusion
RISC-VのLLVMバックエンドは、他のLLVMバックエンドがサポートしている機能をほぼ全てサポートしています。
まだ、macOSや他のOSのサポートを追加するなどの作業が残っています。RISC-Vは他のアーキテクチャにはない特殊なレジスタを提供しているので、ターゲット固有の最適化も調査すると面白いかもしれません。例えば、スレッドレジスタ(x4
)です。
LLVMバックエンドを使用してNative ImageにRISC-Vサポートを追加するのに約半年しかかからなかったことを考えると、WebAssemblyのような他のターゲットへのサポートを追加するアイデアは魅力的です。実際、LLVMバックエンドはまもなくNative Imageのデータセクションを自ら生成し、オブジェクトファイルに関する情報の追加を省略できるようになるため、他のアーキテクチャの追加はさらに容易になるでしょう。
みなさまからのフィードバックをお待ちしております。Slack、GitHub、Twitter、Mastodonからどうぞ。
Slack invitation
https://www.graalvm.org/slack-invitation
GitHub Issues
https://github.com/oracle/graal
Twitter
https://twitter.com/graalvm
Mastodon
https://mastodon.online/@graalvm