補助エンジン・キャッシング
次のドキュメントでは、GraalVMの補助エンジン・キャッシュの仕組みについて説明します。
この機能は、Oracle GraalVMでのみ使用できます。GraalVM Community Editionでは、これらのオプションは使用できません。
概要
Truffleゲスト言語プログラムのウォームアップには、かなりの時間がかかることがあります。ウォームアップは、ピーク・パフォーマンスに達するまで、プログラムの実行のたびに繰り返される作業で構成されます。これには次の作業が含まれます:
- Truffle ASTデータ構造へのゲスト・アプリケーションのロードおよび解析。
- インタプリタでのゲスト・アプリケーションの実行およびプロファイリング。
- ASTのマシン・コードへのコンパイル。
単一のOSプロセス内で、明示的なエンジンを指定することで、ウォームアップ中に実行される作業を共有できます。これには、コンテキスト関連の最適化を無効にして、コンテキスト間でコードを共有する脱最適化を回避するための言語実装が必要です。補助エンジン・キャッシングは、コンテキスト関連の最適化を無効にするためのメカニズムをベースに、ASTおよび最適化済マシン・コードを備えたエンジンをディスクに保持できるようにした構成になっています。この方法で、新しいプロセスの最初のアプリケーション・コンテキストでウォームアップ中に実行される作業を大幅に削減できます。
SVM補助イメージ機能を使用して、必要なデータ構造をディスクに保持し、ロードします。イメージの保持には、コンパイルを実行する必要があるため、長い時間がかかる場合があります。ただし、ロードはできるだけ速く、通常はほぼ瞬時に行うように設計されています。これによってアプリケーションのウォームアップ時間が大幅に短縮されます。
スタート・ガイド
Oracle GraalVMをインストールしたら、まず補助エンジン・キャッシング機能を備えたイメージを(再)ビルドする必要があります。たとえば、補助エンジン・キャッシュ機能を追加することで、JavaScriptイメージを再ビルドできます:
graalvm/bin/native-image --macro:js-launcher -H:+AuxiliaryEngineCache -H:ReservedAuxiliaryImageBytes=1073741824
--macro
引数の値は、ゲスト言語によって異なります。デフォルトでは、最大1 GBの補助イメージが可能です。最大サイズは、必要に応じて拡大または縮小できます。予約済バイト数は、アプリケーションによって消費されるメモリーに実際には影響しません。将来のバージョンでは、--macro:js-launcher
マクロを使用すると、補助エンジン・キャッシュがデフォルトで有効になります。
JavaScriptランチャの再ビルド後に、この機能は次のように使用されます:
新しいファイルfib.js
を作成します:
function fib(n) {
if (n == 1 || n == 2) {
return 1;
}
return fib(n - 1) + fib(n - 2);
}
console.log(fib(32))
プロファイリング実行のエンジンをディスクに保持するには、次のコマンドラインを使用します:
graalvm/bin/js --experimental-options --engine.TraceCache=true --engine.CacheStore=fib.image fib.js
` –engine.TraceCache=true`オプションは任意指定であり、現在何が起こっているかを確認できます。
出力内容は次のようになります。
[engine] [cache] No load engine cache configured.
2178309
[engine] [cache] Preparing engine for store (compile policy hot)...
[engine] [cache] Force compile targets mode: hot
[engine] [cache] Prepared engine in 1 ms.
[engine] [cache] Persisting engine for store ...
[engine] [cache] Persisted engine in 20 ms.
[engine] [cache] Detecting changes (update policy always)...
[engine] [cache] New image contains 1 sources and 82 function roots.
[engine] [cache] Always persist policy.
[engine] [cache] Writing image to fib.image...
[engine] [cache] Finished writing 1,871,872 bytes in 4 ms.
次のコマンドを使用してディスクからエンジンをロードできるようになりました:
graalvm/bin/js --experimental-options --engine.TraceCache --engine.CacheLoad=fib.image fib.js
次のように出力されます:
[engine] [cache] Try loading image './fib.image'...
[engine] [cache] Loaded image in 0 ms. 1,871,872 bytes 1 sources 82 roots
[engine] [cache] Engine from image successfully patched with new options.
2178309
[engine] [cache] No store engine cache configured.
アプリケーションをウォームアップする必要がないため、アプリケーションの実行時間が大幅に短縮されます。
使用方法
キャッシュの格納およびロードの操作は、次のオプションを使用して制御できます:
--engine.Cache=<path>
キャッシュされたエンジンをpath
との間でロードおよび格納します。--engine.CacheStore=<path>
キャッシュされたエンジンをpath
に格納します。--engine.CacheLoad=<path>
キャッシュされたエンジンをpath
からロードします。--engine.CachePreinitializeContext=<boolean>
イメージ内の新しいコンテキストを事前に初期化します(デフォルトtrue
)。--engine.TraceCache=<boolean>
デバッグ出力を有効にします。--engine.TraceCompilation=<boolean>
強制コンパイルを出力します。
--engine.CacheCompile=<policy>
オプションを使用してイメージが格納される場合、ルートのコンパイルが強制されることがあります。サポートされているポリシーは次のとおりです:
none
: コンパイルは保持されず、既存のコンパイルは無効になります。compiled
: コンパイルは強制されませんが、終了したコンパイルは保持されます。hot
: すべての開始されたコンパイルが完了して、保持されます(デフォルト)。aot
: すべての開始されたルートおよびAOTコンパイル可能ルートが強制的にコンパイルされ、保持されます。executed
: すべての実行されたルートおよびすべてのAOTコンパイル可能ルートが強制的にコンパイルされます。
デフォルトでは、コンパイル・キュー内のすべての開始されたコンパイルが完了して、保持されます。関数ルートがAOTコンパイル可能かどうかは、言語によって決まります。言語は、RootNode.prepareForAOT()
を実装することにより、AOTをサポートします。
ロードと格納の両方の操作が--engine.UpdatePolicy=<policy>
オプションを使用して設定されている場合は、更新ポリシーを指定できます。使用可能なポリシーは次のとおりです:
always
常に保持します。newsource
以前にロードされたイメージに含まれていない新しいソースがロードされた場合、格納します。newroot
新しいルートがロードされ、それが以前にロードされたイメージに含まれていない場合、格納します。never
保持しません。
既知の制限事項
-
通常、保持できるアプリケーションの種類に制限はありません。言語で共有コンテキスト・ポリシーがサポートされている場合、補助エンジン・キャッシングは機能します。言語でサポートされていない場合、データは保持されません。
-
保持された補助エンジン・イメージは、その作成に使用されたSVMネイティブ・イメージでのみ使用できます。それ以外のネイティブ・イメージでエンジン・イメージを使用すると、失敗します。
-
1つのネイティブ・イメージ分離に対して存在できるアクティブな補助イメージは1つのみです。複数の補助イメージを同時にロードしようとすると、失敗します。現時点では補助イメージのアンロードもできませんが、この制限は将来なくなる予定です。
セキュリティに関する考慮事項
ディスクに保持されたすべてのデータは、コードのみを表し、グローバル変数などのアプリケーション・コンテキスト固有のデータは表しません。ただし、プロファイリングされたASTおよびコードには、Truffle ASTで実行された最適化のアーティファクトが含まれる場合があります。たとえば、ランタイム文字列が最適化に使用され、それによってエンジン・イメージに保持される可能性があります。
NativeImageでの開発およびデバッグ
NativeImageで補助エンジン・キャッシングを実行する際のデバッグに役立ついくつかのオプションがあります:
-XX:+TraceAuxiliaryImageClassHistogram
イメージを保持するときに、それに含まれるすべてのオブジェクトのクラス・ヒストグラムを出力します。-XX:+TraceAuxiliaryImageReferenceTree
イメージを保持するときに、それに含まれるすべてのオブジェクトのクラス参照ツリーを出力します。
HotSpotでの開発およびデバッグ
これは、HotSpotでの補助イメージに関連する言語実装の問題をデバッグする場合に役立ちます。JVMモードのOracle GraalVMでは、この機能に関する問題のデバッグに使用できる追加オプションがあります。HotSpotでの部分ヒープの格納はサポートされていないため、これらのデバッグ機能はHotSpotでは使用できません。
--engine.DebugCacheStore=<boolean>
エンジンをキャッシング用に準備し、ディスクに書き込むかわりに静的フィールドに格納します。--engine.DebugCacheLoad=<boolean>
ディスクから読み取るのではなく静的フィールドに格納されたエンジンを使用するように、エンジンを準備します。--engine.DebugCacheCompile=<boolean>
エンジンを保持する前に、実行されたコール・ターゲットを強制的にコンパイルするために使用するポリシー。これは、--engine.CacheCompile
と同じ値をサポートします。--engine.DebugCacheTrace=<boolean>
エンジン・キャッシュ・デバッグ機能のトレースを有効にします。
たとえば:
js --jvm --experimental-options --engine.TraceCompilation --engine.DebugCacheTrace --engine.DebugCacheStore --engine.DebugCacheCompile=executed fib.js
次のように出力されます:
[engine] opt done fib |ASTSize 32 |Time 231( 147+84 )ms |Tier Last |DirectCallNodes I 6/D 8 |GraalNodes 980/ 1857 |CodeSize 7611 |CodeAddress 0x10e20e650 |Source fib.js:2
2178309
[engine] [cache] Preparing debug engine for storage...
[engine] [cache] Force compile targets mode: executed
[engine] [cache] Force compiling 4 roots for engine caching.
[engine] opt done @72fa3b00 |ASTSize 3 |Time 211( 166+45 )ms |Tier Last |DirectCallNodes I 2/D 1 |GraalNodes 500/ 1435 |CodeSize 4658 |CodeAddress 0x10e26c8d0 |Source n/a
[engine] opt done :program |ASTSize 25 |Time 162( 123+39 )ms |Tier Last |DirectCallNodes I 1/D 1 |GraalNodes 396/ 1344 |CodeSize 4407 |CodeAddress 0x10e27fd50 |Source fib.js:1
[engine] opt done Console.log |ASTSize 3 |Time 26( 11+15 )ms |Tier Last |DirectCallNodes I 0/D 0 |GraalNodes 98/ 766 |CodeSize 2438 |CodeAddress 0x10e285710 |Source <builtin>:1
[engine] [cache] Stored debug engine in memory.
これにより、コンパイルに関連する問題を迅速に反復でき、またJavaデバッガをアタッチできます。Javaデバッガは、--vm.Xdebug --vm.Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
を使用してアタッチできます。
HotSpotではエンジンのディスクへの書込みがサポートされていないため、永続化エンジンのロードをデバッグすることは、より困難です。ただし、ポリグロット埋込みAPIを使用して、ユニット・テストでこのユース・ケースをシミュレートすることは可能です。例として、com.oracle.truffle.enterprise.test.DebugEngineCacheTest
クラスを参照してください。