- JDK 23対応GraalVM (最新)
- JDK 24対応GraalVM (早期アクセス)
- JDK 21対応GraalVM
- JDK 17対応GraalVM
- アーカイブ
- 開発ビルド
- Truffle言語実装フレームワーク
- Truffleブランチ計測
- 動的オブジェクトモデル
- 静的オブジェクトモデル
- インタプリタコードのホスト最適化
- Truffleの関数インライン化のアプローチ
- Truffleインタプリタのプロファイリング
- Truffle Interop 2.0
- 言語実装
- Truffleを使用した新しい言語の実装
- Truffle言語とInstrumentsのJavaモジュールへの移行
- Truffleネイティブ関数インターフェース
- Truffleインタプリタの最適化
- オプション
- On-Stack Replacement
- Truffle文字列ガイド
- 特殊化ヒストグラム
- DSL特殊化のテスト
- Polyglot APIベースのTCK
- Truffleのコンパイルキューへのアプローチ
- Truffleライブラリガイド
- Truffle AOT概要
- Truffle AOTコンパイル
- 補助エンジンキャッシング
- Truffle言語セーフポイントチュートリアル
- 単態化
- 分割アルゴリズム
- 単態化のユースケース
- 多態特殊化のランタイムへの報告
特殊化ヒストグラム
このガイドでは、`--engine.SpecializationStatistics`オプションの使い方を説明します。
特殊化ヒストグラムは、Truffle DSLノードが特別な方法で生成される必要があります。そのため、プレーンな特殊化ヒストグラムオプションを使用すると、以下が出力されます。
js --engine.SpecializationStatistics test.js
[engine] Specialization histogram:
No specialization statistics data was collected. Either no node with @Specialization annotations was executed or the interpreter was not compiled with -Atruffle.dsl.GenerateSpecializationStatistics=true e.g as parameter to the javac tool.
エラーのアドバイスに従って、インタプリタを再コンパイルしてください。`mx`ユーザーの場合は、以下のように簡単です。
mx build -c -A-Atruffle.dsl.GenerateSpecializationStatistics=true
再構築後、特殊化統計を使用する準備が整います。その間、IDEがソースを自動的に再コンパイルしないようにしてください。このチュートリアルでは、単純な`test.js`スクリプトを使用します。
function test() {
var array = [42, "", {}, []]
var globalVar = true;
for (element of array) {
globalVar = element;
}
}
test();
次に、特殊化統計を有効にする必要があります。この例では、GraalVMのJavaScriptランチャーを使用します。
js --experimental-options --engine.SpecializationStatistics test.js
スクリプトが実行されると、各クラスのヒストグラムが出力されます。ヒストグラムは各ノードの実行数の合計順に並べられ、最も頻繁に使用されるノードクラスが最後に表示されます。
`test.js`を実行したときに出力されるヒストグラムの一部を以下に示します。(注:出力は既に古くなっている可能性があります。)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Name Instances Executions Executions per instance
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
| JSWriteCurrentFrameSlotNodeGen 8 (17%) 18 (12%) Min= 1 Avg= 2.25 Max= 5 MaxNode= test.js~5-7:76-128
| doBoolean <boolean> 1 (13%) 1 (6%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~4:52-71
| doInt <int> 1 (13%) 1 (6%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~5-7:76-128
| doSafeIntegerInt 0 (0%) 0 (0%) Min= 0 Avg= 0.00 Max= 0 MaxNode= -
| doSafeInteger 0 (0%) 0 (0%) Min= 0 Avg= 0.00 Max= 0 MaxNode= -
| doLong 0 (0%) 0 (0%) Min= 0 Avg= 0.00 Max= 0 MaxNode= -
| doDouble 0 (0%) 0 (0%) Min= 0 Avg= 0.00 Max= 0 MaxNode= -
| doObject 7 (88%) 16 (89%) Min= 1 Avg= 2.29 Max= 5 MaxNode= test.js~5-7:76-128
| <DynamicObjectBasic> 6 (86%) 12 (75%) Min= 1 Avg= 2.00 Max= 5 MaxNode= test.js~5-7:76-128
| <IteratorRecord> 1 (14%) 1 (6%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~1-8:16-130
| <String> 2 (29%) 2 (13%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~5-7:76-128
| <Integer> 1 (14%) 1 (6%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~6:105-123
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------
| [doBoolean] 1 (13%) 1 (6%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~4:52-71
| [doInt, doObject] 1 (13%) 4 (22%) Min= 4 Avg= 4.00 Max= 4 MaxNode= test.js~5-7:76-128
| doInt 1 (100%) 1 (25%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~5-7:76-128
| doObject 1 (100%) 3 (75%) Min= 3 Avg= 3.00 Max= 3 MaxNode= test.js~5-7:76-128
| [doObject] 6 (75%) 13 (72%) Min= 1 Avg= 2.17 Max= 5 MaxNode= test.js~5-7:76-128
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Name Instances Executions Executions per instance
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
| JSReadCurrentFrameSlotNodeGen 8 (17%) 25 (17%) Min= 1 Avg= 3.13 Max= 5 MaxNode= test.js~5-7:76-128
| doBoolean 0 (0%) 0 (0%) Min= 0 Avg= 0.00 Max= 0 MaxNode= -
| doInt <no-args> 1 (13%) 1 (4%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~5:81-87
| doDouble 0 (0%) 0 (0%) Min= 0 Avg= 0.00 Max= 0 MaxNode= -
| doObject <no-args> 8 (100%) 24 (96%) Min= 1 Avg= 3.00 Max= 5 MaxNode= test.js~5-7:76-128
| doSafeInteger 0 (0%) 0 (0%) Min= 0 Avg= 0.00 Max= 0 MaxNode= -
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------
| [doInt, doObject] 1 (13%) 4 (16%) Min= 4 Avg= 4.00 Max= 4 MaxNode= test.js~5:81-87
| doInt 1 (100%) 1 (25%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~5:81-87
| doObject 1 (100%) 3 (75%) Min= 3 Avg= 3.00 Max= 3 MaxNode= test.js~5:81-87
| [doObject] 7 (88%) 21 (84%) Min= 1 Avg= 3.00 Max= 5 MaxNode= test.js~5-7:76-128
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
ヒストグラムは、すべてのノードクラスに対して2つの内部テーブルを出力します。
最初のテーブルは、特殊化と動的型の組み合わせをグループ化します。たとえば、このヒストグラムでは、ノードクラス`JSWriteCurrentFrameSlotNodeGen`は`8`回インスタンス化され、`18`回実行されました。これは、実行全体のインスタンスの`20%`、ノード実行の`11%`に相当します。
このスクリプトでは、`doBoolean`、`doObject`、`doInt`の3つの特殊化がインスタンス化されました。`doBoolean`の特殊化は1回だけインスタンス化および実行され、このノードクラスの全インスタンスの`13%`、全実行の`6%`を占めています。`doObject`の特殊化は、`DynamicObjectBasic`、`IteratorRecord`、`String`の3つの異なる入力値の組み合わせを使用して呼び出されました。特殊化と同様に、ノードごとに使用された回数と実行された回数がわかります。各行には、インスタンスごとの最小、平均、最大実行数が表示されます。最後の列には、実行回数が最大のインスタンスのソースセクションが出力されます。
2番目のテーブルは、ノードクラスで使用された特殊化の各組み合わせをグループ化します。
これらの特殊化統計について、以下のような質問をしたいと思うでしょう。
- 特定の特殊化の組み合わせがめったに使用されない場合は、それを削除/統合できますか?
- 非常に一般的な型の組み合わせを持つ特殊化があり、さらに特殊化することでメリットが得られるでしょうか?
- どの特殊化の組み合わせが一般的で、独自の特殊化に値するでしょうか?これは、コード内の一般的なポリモーフィズムを示している可能性があり、調査する価値があります。
- 一般的な特殊化は何ですか?また、その順序は実行回数と一致していますか?最も一般的に使用される特殊化は、ノードクラスで最初に順序付けする必要があります。これは、インタプリタのパフォーマンスの向上につながる可能性があります。
- 予期しない特殊化がインスタンス化されていますか?はいの場合、出力されたソースセクションを使用してさらに調査してください。
- どの特殊化が頻繁にインスタンス化され、メモリフットプリントの最適化が必要ですか?
- プロファイルに`Uncached`という名前のノードがありましたか?キャッシュされていないノードの使用はまれである必要があります。それらが頻繁に使用された場合、その理由を詳しく調べる価値があります。