Graal JITコンパイラ操作マニュアル
パフォーマンスの測定
パフォーマンスの測定時に最初に確認することは、Java仮想マシン(JVM)がGraal JITコンパイラを使用していることです。
GraalVMは、デフォルトでGraal JITコンパイラを最上位層のコンパイラとして使用するように構成されています。
Graal JITコンパイラをJava HotSpot仮想マシンで使用できるようにするには、-XX:+UseGraalJIT
オプションを使用します。(-XX:+UseGraalJIT
オプションは、この試験段階の統合をロック解除する-XX:+UnlockExperimentalVMOptions
オプションと一緒に使用する必要があります。)
次の例では、Graal JITコンパイラを有効にしてJavaアプリケーションcom.example.myapp
を実行します:
java -XX:+UnlockExperimentalVMOptions -XX:+UseGraalJIT com.example.myapp
Graal JITコンパイラを使用していることを確認するには、コマンドラインに-Djdk.graal.ShowConfiguration=info
オプションを追加します。これにより、コンパイラが初期化されるとき、次のような出力行が生成されます:
Using "Graal Enterprise compiler with Truffle extensions" loaded from a PGO optimized Native Image shared library
ノート: Graalコンパイラは、最上位層のJITコンパイルが初めてリクエストされたときにのみ初期化されるため、アプリケーションの存続期間が短い場合、この出力が表示されないことがあります。
JVMベースのアプリケーションの最適化は、それ自体が1つの知識体系です。JVMの他の部分(I/O、ガベージ・コレクション、スレッドなど)か、アプリケーションやサードパーティのライブラリ・コードの不適切な記述に問題がある場合があるため、コンパイルがパフォーマンスの低下の要因ではない可能性があります。このため、JDK Mission Controlツールチェーンを使用してアプリケーションの動作を診断することをお薦めします。
コマンドラインに-XX:-UseJVMCICompiler
を追加することで、JVMのネイティブの最上位層のコンパイラとパフォーマンスを比較することもできます。
Graal JITコンパイラの使用時にパフォーマンスが大幅に低下する場合は、GitHubで問題をオープンしてください。Javaフライト・レコーダのログや問題を再現する手順を添付すると、調査が容易になり、修正される可能性が高くなります。アプリケーションで最もホットである(ことがプロファイラによって識別された)部分を示すJMHベンチマークを提出できると、さらに役立ちます。これにより、欠けている最適化の機会の迅速な特定や、パフォーマンス・ボトルネックを回避または削減するようにコードを再構築する方法に関する提案が可能になります。
Graal JITコンパイラのトラブルシューティング
セキュリティの脆弱性を発見した場合は、GitHub Issuesや公開メーリング・リストではなく、脆弱性の報告ガイドで概説されているプロセスに従って報告してください。
コンパイル例外
コンパイラをJavaで記述する利点の1つは、コンパイル中のJava例外が致命的なJVMエラーではないことです。かわりに、各コンパイルには、graal.CompilationFailureAction
プロパティに基づいてアクションを実行する例外ハンドラがあります。
デフォルト値はSilent
です。Diagnose
を指定すると、失敗したコンパイルは追加の診断で再試行されます。この場合、JVMが終了する直前に、再試行されたコンパイル中に取得されたすべての診断出力がZIPファイルに書き込まれ、その場所が次のようにコンソールに出力されます:
Graal diagnostic output saved in /Users/demo/graal-dumps/1499768882600/graal_diagnostics_64565.zip
その後、ZIPファイルをGitHubで問題に添付できます。
Silent
およびDiagnose
に加えて、graal.CompilationFailureAction
の次の値を使用できます:
Print
: コンソールにメッセージおよびスタック・トレースを出力しますが、再コンパイルは実行しません。ExitVM
:Diagnose
と同じですが、再コンパイル後にJVMプロセスは終了します。
コード生成エラー
コンパイラで発生する可能性のあるその他のタイプのエラーは、不正なマシン・コードの生成です。このエラーによってJVMクラッシュが発生し、JVMプロセスの現在の作業ディレクトリにhs_err_pidで始まるファイルが生成される場合があります。ほとんどの場合、次の例に示すように、ファイル内にはクラッシュの時点のスタックを示すセクションがあり、そこに、スタック内の各フレームのコードのタイプが含まれています:
Stack: [0x00007000020b1000,0x00007000021b1000], sp=0x00007000021af7a0, free space=1017k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
J 761 JVMCI jdk.graal.compiler.core.gen.NodeLIRBuilder.matchComplexExpressions(Ljava/util/List;)V (299 bytes) @ 0x0000000108a2fc01 [0x0000000108a2fac0+0x141] (null)
j jdk.graal.compiler.core.gen.NodeLIRBuilder.doBlock(Ljdk.graal.compiler/nodes/cfg/Block;Ljdk.graal.compiler/nodes/StructuredGraph;Ljdk.graal.compiler/core/common/cfg/BlockMap;)V+211
j jdk.graal.compiler.core.LIRGenerationPhase.emitBlock(Ljdk.graal.compiler/nodes/spi/NodeLIRBuilderTool;Ljdk.graal.compiler/lir/gen/LIRGenerationResult;Ljdk.graal.compiler/nodes/cfg/Block;Ljdk.graal.compiler/nodes/StructuredGraph;Ljdk.graal.compiler/core/common/cfg/BlockMap;)V+65
この例は、最上位のフレームがJVMCIコンパイラ(これはGraal JITコンパイラです)によってコンパイルされた(J
)ことを示しています。次に対して生成されたマシン・コードのオフセット0x141
でクラッシュが発生しました:
jdk.graal.compiler.core.gen.NodeLIRBuilder.matchComplexExpressions(Ljava/util/List;)V
スタック内の次の2つのフレームは解釈されました(j
)。クラッシュの場所も、多くの場合、次のようなものでファイルの上部付近に示されます:
# Problematic frame:
# J 761 JVMCI jdk.graal.compiler.core.gen.NodeLIRBuilder.matchComplexExpressions(Ljava/util/List;)V (299 bytes) @ 0x0000000108a2fc01 [0x0000000108a2fac0+0x141] (null)
この例では、NodeLIRBuilder.matchComplexExpressions
に対してGraal JITコンパイラによって生成されたコードにエラーがある可能性があります。
このようなクラッシュについてGitHubで問題を提出する場合、まず、問題のあるメソッドのコンパイルに対して追加の診断を有効にして、クラッシュの再現を試みる必要があります。この例では、次のオプションをコマンドラインに追加します:
-Djdk.graal.MethodFilter=NodeLIRBuilder.matchComplexExpressions, -Djdk.graal.Dump=:2
これらのオプションの詳細は、コンパイラ・デバッグのドキュメントを参照してください。簡単に言うと、これらのオプションは、NodeLIRBuilder
という単純名を持つクラス内のmatchComplexExpressions
という名前のメソッドのコンパイル時に、Graal JITコンパイラの状態のスナップショットを冗長レベル2で取得するようにコンパイラに指定します。MethodFilter
オプションの完全な形式については、MethodFilterHelp.txtで説明されています。
多くの場合、クラッシュの場所はクラッシュ・ログで示された問題のあるメソッド自体には存在せず、インライン化されたメソッドから発生しています。
このような場合、単に問題のあるメソッドをフィルタ処理しても、クラッシュの原因となった誤ったコンパイルを捕捉できないことがあります。
誤ったコンパイルを捕捉する可能性を高めるには、MethodFilter
値を拡大します。そのためには、クラッシュの直前に何がコンパイルされたかを確認できるように、クラッシュの再現を試行するときに-Djdk.graal.PrintCompilation=true
オプションを追加します。
次に、コンソールからの出力例を示します:
HotSpotCompilation-1218 Ljdk.graal.compiler/core/amd64/AMD64NodeLIRBuilder; peephole (Ljdk.graal.compiler/nodes/ValueNode;)Z | 87ms 428B 447B 1834kB
HotSpotCompilation-1212 Ljdk.graal.compiler/lir/LIRInstructionClass; forEachState (Ljdk.graal.compiler/lir/LIRInstruction;Ljdk.graal.compiler/lir/InstructionValueProcedure;)V | 359ms 92B 309B 6609kB
HotSpotCompilation-1221 Ljdk.graal.compiler/hotspot/amd64/AMD64HotSpotLIRGenerator; getResult ()Ljdk.graal.compiler/hotspot/HotSpotLIRGenerationResult; | 54ms 18B 142B 1025kB
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x000000010a6cafb1, pid=89745, tid=0x0000000000004b03
#
# JRE version: OpenJDK Runtime Environment (8.0_121-b13) (build 1.8.0_121-graalvm-olabs-b13)
# Java VM: OpenJDK 64-Bit GraalVM (25.71-b01-internal-jvmci-0.30 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# J 1221 JVMCI jdk.graal.compiler.hotspot.amd64.AMD64HotSpotLIRGenerator.getResult()Ljdk.graal.compiler/hotspot/HotSpotLIRGenerationResult; (18 bytes) @ 0x000000010a6cafb1 [0x000000010a6caf60+0x51] (null)
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
ここでは、クラッシュは最初のクラッシュとは異なるメソッドで発生しています。そのため、フィルタ引数を-Djdk.graal.MethodFilter=NodeLIRBuilder.matchComplexExpressions,AMD64HotSpotLIRGenerator.getResult
に拡大して、再度実行します。
この方法でJVMがクラッシュした場合、Graalコンパイラの診断出力をアーカイブするシャットダウン・コードが実行されないか、それが書き込まれたディレクトリが削除されます。これは、クラッシュ後に手動で行う必要があります。
デフォルトでは、ディレクトリは$PWD/graal-dumps/<timestamp>です(たとえば、./graal-dumps/1499938817387)。ただし、-Djdk.graal.DumpPath=<path>
オプションを使用してディレクトリを指定できます。
このディレクトリがコンパイラによって最初に使用されると、次のようなメッセージがコンソールに出力されます:
Dumping debug output in /Users/demo/graal-dumps/1499768882600
このディレクトリには、クラッシュしたメソッドに関する次のような内容が含まれます:
ls -l /Users/demo/graal-dumps/1499768882600
-rw-r--r-- 1 demo staff 144384 Jul 13 11:46 HotSpotCompilation-1162[AMD64HotSpotLIRGenerator.getResult()].bgv
-rw-r--r-- 1 demo staff 96925 Jul 13 11:46 HotSpotCompilation-1162[AMD64HotSpotLIRGenerator.getResult()].cfg
-rw-r--r-- 1 demo staff 12600725 Jul 13 11:46 HotSpotCompilation-791[NodeLIRBuilder.matchComplexExpressions(List)].bgv
-rw-r--r-- 1 demo staff 1727409 Jul 13 11:46 HotSpotCompilation-791[NodeLIRBuilder.matchComplexExpressions(List)].cfg
GitHubで、このディレクトリのZIPファイルを問題に添付してください。