補助エンジンキャッシング

以下のドキュメントでは、GraalVMの補助エンジンキャッシュの仕組みについて説明します。

この機能はOracle GraalVMでのみ利用可能です。GraalVM Community Editionでは、これらのオプションは利用できません。

はじめに #

Truffleゲスト言語プログラムのウォームアップには、かなりの時間がかかる場合があります。ウォームアップは、ピークパフォーマンスに達するまでプログラムが実行されるたびに繰り返される作業で構成されます。これには以下が含まれます。

  1. ゲストアプリケーションをTruffle ASTデータ構造にロードして解析します。
  2. インタープリターでのゲストアプリケーションの実行とプロファイリング。
  3. ASTの機械語へのコンパイル。

単一のOSプロセス内では、明示的なエンジンを指定することで、ウォームアップ中に実行された作業を共有できます。これには、コードを共有するコンテキスト間での非最適化を避けるために、言語実装でコンテキスト関連の最適化を無効にする必要があります。補助エンジンキャッシングは、コンテキスト関連の最適化を無効にするメカニズムに基づいて構築され、ASTと最適化された機械語を含むエンジンをディスクに永続化する機能を追加します。これにより、新しいプロセスの最初のアプリケーションコンテキストでのウォームアップ作業を大幅に削減できます。

SVM補助イメージ機能を使用して、必要なデータ構造をディスクに永続化およびロードします。コンパイルを実行する必要があるため、イメージの永続化にはかなりの時間がかかる場合があります。ただし、ロードは可能な限り高速になるように設計されており、通常はほぼ瞬時です。これにより、アプリケーションのウォームアップ時間が大幅に短縮されます。

はじめに #

Oracle GraalVMインストールから開始して、最初に補助エンジンキャッシング機能を備えたイメージを(再)ビルドする必要があります。たとえば、補助エンジンキャッシュ機能を追加することで、JavaScriptイメージを再ビルドできます。

graalvm/bin/native-image --macro:js-launcher -H:+AuxiliaryEngineCache -H:ReservedAuxiliaryImageBytes=1073741824

--macro引数の値はゲスト言語によって異なります。デフォルトでは、最大1GBの補助イメージが可能です。最大サイズは必要に応じて増減できます。予約されたバイト数は、アプリケーションが消費するメモリには実際には影響しません。将来のバージョンでは、--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つしかありません。複数の補助イメージを同時にロードしようとすると失敗します。現在、補助イメージをアンロードすることもできませんが、将来的にこの制限を解除する予定です。

セキュリティに関する考慮事項 #

ディスクに永続化されるすべてのデータは、コードのみを表し、グローバル変数などのアプリケーションコンテキスト固有のデータは表しません。ただし、プロファイリングされたASTとコードには、Truffle ASTで実行された最適化の成果物が含まれている場合があります。たとえば、ランタイム文字列が最適化に使用され、エンジンイメージに永続化される可能性があります。

ネイティブイメージでの開発とデバッグ #

ネイティブイメージで実行する場合に補助エンジンキャッシングのデバッグに役立ついくつかのオプションがあります。

  • -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 --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クラスを参照してください。

お問い合わせ