GraalVM Native Image meets RISC-V

原文はこちら。
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に提供する必要がありますが、その方法は以下に記載があります。gccglibcのバージョンは、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

種々のオプションが利用できますが、その一例をご紹介します。

optiondescription
-Dsvm.targetPlatformArch=riscv64ターゲットアーキテクチャの指定
-H:CompilerBackend=llvmLLVMバックエンドの利用を指定
-H:CAPCacheDir=/path/to/capcache事前計算済みのCAPCacheをNative Imageに提供
-H:CCompilerPath=/path/to/riscv-gccRISC-VツールチェーンのgccをNative Imageに提供
-H:CustomLD=/path/to/riscv-ldRISC-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

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中