GraalVM Insight
GraalVM Insightは、プログラムの実行時の動作をトレースしてインサイトを収集する柔軟な汎用ツールです。
このツールの動的な性質により、ユーザーはパフォーマンスを損なうことなく、すでに実行中のアプリケーションにトレース・ポイントカットを選択的に適用できます。GraalVM Insightにより、プログラムの実行時の動作への詳細なアクセスも提供されるため、ユーザーは、起動サイトまたは割当てサイトで値と型を検査できます。さらにこのツールを使用すると、ユーザーは、計算された値を変更したり、実行を中断したり、アプリケーション・コードを変更せずに動作の変更を迅速に試すことができます。ツールの実装の詳細は、APIの仕様を参照してください。
このページには、20.1バージョン時点のGraalVM Insightに関する情報が記載されています。バージョン20.0および19.3のInsightについて学習するには、ここに進みます。
スタート・ガイド
- 次のコンテンツを含む単純なsource-tracing.jsスクリプトを作成します:
insight.on('source', function(ev) { print(`Loading ${ev.characters.length} characters from ${ev.name}`); });
JAVA_HOME
をGraalVMホーム・ディレクトリに設定した後、--insight
ツールを使用してnode
ランチャを起動し、どのスクリプトがロードおよび評価されるかを確認します:$JAVA_HOME/bin/node --insight=source-tracing.js --js.print -e "print('The result: ' + 6 * 7)" | tail -n 10 Loading 215 characters from internal/modules/esm/transform_source.js Loading 12107 characters from internal/modules/esm/translators.js Loading 1756 characters from internal/modules/esm/create_dynamic_module.js Loading 12930 characters from internal/vm/module.js Loading 2710 characters from internal/modules/run_main.js Loading 308 characters from module.js Loading 10844 characters from internal/source_map/source_map.js Loading 170 characters from [eval]-wrapper Loading 29 characters from [eval] The result: 42
source-tracing.jsスクリプトにより、指定された
insight
オブジェクトを使用して、ソース・リスナーがランタイムにアタッチされました。スクリプトがロードされるたびに、リスナーは通知を受け取り、処理されたスクリプトの長さと名前を出力するアクションを実行できます。
Insight情報は、print文またはヒストグラムに収集できます。次のfunction-hotness-tracing.jsスクリプトは、すべてのメソッド呼出しをカウントし、プログラムの実行が終了した時点で最も頻度が高かったメソッド呼出しをダンプします:
var map = new Map();
function dumpHotness() {
print("==== Hotness Top 10 ====");
var digits = 3;
Array.from(map.entries()).sort((one, two) => two[1] - one[1]).forEach(function (entry) {
var number = entry[1].toString();
if (number.length >= digits) {
digits = number.length;
} else {
number = Array(digits - number.length + 1).join(' ') + number;
}
if (number > 10) print(`${number} calls to ${entry[0]}`);
});
print("========================");
}
insight.on('enter', function(ev) {
var cnt = map.get(ev.name);
if (cnt) {
cnt = cnt + 1;
} else {
cnt = 1;
}
map.set(ev.name, cnt);
}, {
roots: true
});
insight.on('close', dumpHotness);
map
は、Insightスクリプト内で共有されるグローバル変数であり、insight.on('enter')
関数とdumpHotness
関数の間で、コードによるデータの共有を許可します。後者は、ノード・プロセスの実行が終了すると実行されます(insight.on('close', dumpHotness)
を介して登録されます)。node
プロセスの終了時に、関数呼出しの名前と数を含む表が出力されます。
次のように起動します:
$JAVA_HOME/bin/node --insight=function-hotness-tracing.js --js.print -e "print('The result: ' + 6 * 7)"
The result: 42
==== Hotness Top 10 ====
543 calls to isPosixPathSeparator
211 calls to E
211 calls to makeNodeErrorWithCode
205 calls to NativeModule
198 calls to uncurryThis
154 calls to :=>
147 calls to nativeModuleRequire
145 calls to NativeModule.compile
55 calls to internalBinding
53 calls to :anonymous
49 calls to :program
37 calls to getOptionValue
24 calls to copyProps
18 calls to validateString
13 calls to copyPrototype
13 calls to hideStackFrames
13 calls to addReadOnlyProcessAlias
========================
ポリグロット・トレース
前述の例はJavaScriptで記述されていますが、GraalVMのポリグロットの性質上、同じインストゥルメントを取得して、Ruby言語などで記述されたプログラムで使用できます。
- source-trace.jsファイルを作成します:
insight.on('source', function(ev) { if (ev.uri.indexOf('gems') === -1) { let n = ev.uri.substring(ev.uri.lastIndexOf('/') + 1); print('JavaScript instrument observed load of ' + n); } });
- helloworld.rb Rubyファイルを準備します:
puts 'Hello from GraalVM Ruby!'
- JavaScriptインストゥルメントをRubyプログラムに適用します:
$JAVA_HOME/bin/ruby --jvm --polyglot --insight=source-trace.js helloworld.rb JavaScript instrument observed load of helloworld.rb Hello from GraalVM Ruby!
source-tracing.jsスクリプトはJavaScriptで記述されたままであるため、
--polyglot
パラメータを使用してRubyランチャを起動する必要があります。
ユーザーは、GraalVM上で任意の言語をインストゥルメントできますが、InsightスクリプトをGraalVMでサポートされている任意の言語(Truffle言語実装フレームワークを使用して実装)で記述することもできます。
- source-tracing.rb Rubyファイルを作成します:
puts "Ruby: Initializing GraalVM Insight script" insight.on('source', ->(ev) { name = ev[:name] puts "Ruby: observed loading of #{name}" }) puts 'Ruby: Hooks are ready!'
- Node.jsアプリケーションを起動し、Rubyスクリプトを使用してインストゥルメントします:
$JAVA_HOME/bin/node --jvm --polyglot --insight=source-tracing.rb --js.print -e "print('With Ruby: ' + 6 * 7)" | grep Ruby Ruby: Initializing GraalVM Insight script Ruby: Hooks are ready! Ruby: observed loading of internal/per_context/primordials.js Ruby: observed loading of internal/per_context/setup.js Ruby: observed loading of internal/per_context/domexception.js .... Ruby: observed loading of internal/modules/cjs/loader.js Ruby: observed loading of vm.js Ruby: observed loading of fs.js Ruby: observed loading of internal/fs/utils.js Ruby: observed loading of [eval]-wrapper Ruby: observed loading of [eval] With Ruby: 42
値の検査
GraalVM Insightでは、プログラムが実行されている場所をトレースできるだけでなく、プログラムの実行中にローカル変数および関数の引数の値にアクセスすることもできます。たとえば、関数fib
の引数n
の値を示すインストゥルメントを作成できます:
insight.on('enter', function(ctx, frame) {
print('fib for ' + frame.n);
}, {
roots: true,
rootNameFilter: (name) => 'fib' === name
});
このインストゥルメントは、2番目の関数の引数frame
を使用して、インストゥルメントされたすべての関数内のローカル変数の値にアクセスします。前述のスクリプトでは、rootNameFilter
を使用して、そのフックをfib
という名前の関数にのみ適用しています:
function fib(n) {
if (n < 1) return 0;
if (n < 2) return 1;
else return fib(n - 1) + fib(n - 2);
}
print("Two is the result " + fib(3));
インストゥルメントがfib-trace.js
ファイルに格納されており、実際のコードがfib.js
にある場合、次のコマンドを起動すると、プログラムの実行および関数の呼出し間で渡されるパラメータに関する詳細情報が生成されます:
$JAVA_HOME/bin/node --insight=fib-trace.js --js.print fib.js
fib for 3
fib for 2
fib for 1
fib for 0
fib for 1
Two is the result 2
次に読むもの
Insightの詳細
中程度熟練した開発者であれば、独自のいわゆる「フック」を簡単に作成し、それを実際のプログラムに動的に適用できます。これにより、実行速度を損なうことなく、アプリケーションの実行と動作に関する究極のインサイトが提供されます。
GraalVM Insightの学習を続け、深く調べるには、Insightのマニュアルに進みます。これは、必須のHelloWorldの例から始まり、より難しいタスクを示しています。
GraalVM Insightのアプリケーションへの組込み
GraalVM言語(Truffleフレームワークで実装された言語)は、ポリグロット・コンテキストAPIを介してカスタム・アプリケーションに組み込むことができます。GraalVM Insightも、同じAPIを介して制御できます。
GraalVM Insightの機能を安全な方法でアプリケーションに統合する方法については、組込みに関するドキュメントを参照してください。
GraalVM Insightでのトレース
GraalVM Insightでは、トレース機能が既存のコードに動的に追加されます。アプリケーションを通常どおりに記述し、必要に応じてテレメトリを開くトレースを動的に適用します。InsightとJaegerの統合の詳細は、専用ガイドを参照してください。
APIの仕様
実装の詳細については、APIの仕様を参照してください。そこには、insight
オブジェクトのプロパティ、関数などに関する情報が記載されています。