GraalVM流行ってますね。

そして、多くの人はGraalをAOTとして使うnative-imageのことだけをGraalVMと言ってたりします。

ご安心を。このエントリではGraalをJITとして使うHotSpotモードとGraalをAOTとして使うnative-imageの両方が遅いという話です。

GraalVMは速い、と言われてますが、残念ながらHotSpotモードでC2より速い結果を手元では出せていません。

公式ブログでは1.7倍から5倍速くなると書いてますけど、手元では再現できてません。

Under the hood of GraalVM JIT optimizations - graalvm - Medium

native-imageは速い、というのはよくありますが、これはネイティブ化によりJVMの起動時間や最適化の時間、最適化されずに動く時間が省略されるので起動が速い、という話です。長く動くプロセスの場合、そういった起動にかかる時間というのは無視できるようになり、実行時に集めた情報を使って最適化するJITのほうが速いです。

用語について

ところでここで用語の確認を。

GraalVMというのは、Javaで書かれたJITコンパイラGraalを中心とした多言語環境です。

普通にGraalをJavaのJITコンパイラとして使うのがGraalVMのHotSpotモードです。ようするにjavaコマンドです。

Graalの最適化機構を一般のスクリプト言語から使えるようにしてJavaScriptやRubyのJITコンパイラにしてしまうのがTruffleです。

そして、Graalを事前にJavaコードに適用してネイティブ化するというのがnative-imageです。

計測

ということで、どのくらい遅いか比べてみます。

コードはこのレイトレ。

https://github.com/kishida/smallpt4j/blob/original/src/main/java/naoki/smallpt/SmallPT.java

commonsのFastMathを使っているので、通常のjava.lang.Mathに置き換えて実行します。また、ループ中のSystem.out.printlnはコメントアウトしました。

それはそうと、以前はこのコードはImageIOを使っているのでGraalVMでネイティブ化できなかったのですが、いまではできるようになってます。

実行するとこんな感じのPNG画像が出力されます。



GraalVM 19.0.2 CE

ここではWindowsで動かしてみました。GraalVMは19.0.2CEです。

まずはHotSpotモード。

C:\Users

aoki\Documents\prj>java -version openjdk version "1.8.0_212" OpenJDK Runtime Environment (build 1.8.0_212-20190603180034.buildslave.jdk8u-src-tar--b03) OpenJDK 64-Bit GraalVM CE 19.0.2 (build 25.212-b03-jvmci-19-b04, mixed mode) C:\Users

aoki\Documents\prj>java SmallPT Samples:40 Type:master Time:PT9.713S

10秒弱。

ネイティブ化してみます。

C:\Users

aoki\Documents\prj>native-image SmallPT [smallpt:21796] classlist: 1,793.30 ms ... [smallpt:21796] write: 786.36 ms [smallpt:21796] [total]: 26,307.39 ms C:\Users

aoki\Documents\prj>smallpt Samples:40 Type:master Time:PT45.234S

45秒。だいぶ遅い！

GraalVM 19.0.2 EE

ついでにEEでも試してみます。

C:\Users

aoki\Documents\prj>java -version java version "1.8.0_212" Java(TM) SE Runtime Environment (build 1.8.0_212-b31) Java HotSpot(TM) 64-Bit GraalVM EE 19.0.2 (build 25.212-b31-jvmci-19-b04, mixed mode) C:\Users

aoki\Documents\prj>java SmallPT Samples:40 Type:master Time:PT10.281S

10秒強。あんま変わらん。

ではネイティブ化。

C:\Users

aoki\Documents\prj>native-image SmallPT [smallpt:43056] classlist: 2,165.31 ms ... [smallpt:43056] image: 788.17 ms Warning: Generating and stripping of debug info not supported on Windows[smallpt:43056] write: 775.12 ms [smallpt:43056] [total]: 29,450.40 ms C:\Users

aoki\Documents\prj>smallpt Samples:40 Type:master Time:PT13.039S

13秒！CEに比べるとめっちゃ速い！

OpenJDK

それではC2版。つまりふつうのOpenJDK

$ java -version openjdk version "1.8.0_212" OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_212-b03) OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.212-b03, mixed mode) $ java SmallPT Samples:40 Type:master Time:PT6.795S

6.8秒。GraalVMに比べるとだいぶ速いです。

OpenJDKの11でも試してみます。

$ java -version openjdk version "11.0.2" 2019-01-15 OpenJDK Runtime Environment 18.9 (build 11.0.2+9) OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode) $ java SmallPT Samples:40 Type:master Time:PT5.8484946S

5.8秒。お、ちょっと速くなってる！

まとめ

ということで、まとめるとこう。

ついでにMacでも計測しています。Windowsが8コアでMacが4コアなので、ちょうど倍くらいの時間がかかってますね。CEのnative-imageがそれほど遅くないのだけど、コア数によるものかWindowsとMacの違いか気になるところ。

GraalVM CE HotSpot GraalVM CE Native GraalVM EE HotSpot GraalVM EE Native OpenJDK 8 OpenJDK 11 Windows(i7-8Cores) 9.713 45.234 10.281 13.039 6.795 5.848 Mac(i7-4Cores) 20.966 47.069 18.797 19.135 16.783 12.594

グラフにするとこう。



ということで、GraalVMのネイティブイメージは起動以外は速くない むしろ遅い、GraalVM EEのネイティブイメージはCEに比べるとかなり速いけどHotSpotモードほどではない、JDKは8から11でも速くなってる、という結果になりました。

LinuxでやればGraalは速いという噂もあります。

7/4追記 19.1.0が出てたので試してみたけど、CEのnative-imageがちょっと速くなった？