特殊化ヒストグラム

このガイドでは、`--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番目のテーブルは、ノードクラスで使用された特殊化の各組み合わせをグループ化します。

これらの特殊化統計について、以下のような質問をしたいと思うでしょう。

  1. 特定の特殊化の組み合わせがめったに使用されない場合は、それを削除/統合できますか?
  2. 非常に一般的な型の組み合わせを持つ特殊化があり、さらに特殊化することでメリットが得られるでしょうか?
  3. どの特殊化の組み合わせが一般的で、独自の特殊化に値するでしょうか?これは、コード内の一般的なポリモーフィズムを示している可能性があり、調査する価値があります。
  4. 一般的な特殊化は何ですか?また、その順序は実行回数と一致していますか?最も一般的に使用される特殊化は、ノードクラスで最初に順序付けする必要があります。これは、インタプリタのパフォーマンスの向上につながる可能性があります。
  5. 予期しない特殊化がインスタンス化されていますか?はいの場合、出力されたソースセクションを使用してさらに調査してください。
  6. どの特殊化が頻繁にインスタンス化され、メモリフットプリントの最適化が必要ですか?
  7. プロファイルに`Uncached`という名前のノードがありましたか?キャッシュされていないノードの使用はまれである必要があります。それらが頻繁に使用された場合、その理由を詳しく調べる価値があります。

お問い合わせ