Truffleインタプリタのプロファイリング

Truffleを使用して記述されたインタープリタをプロファイリングするためのツールは豊富にあります。JVMモードで実行する場合は、VisualVM、Java Flight Recorder、Oracle Developer Studioなどの標準のJVMツールを使用できます。ネイティブイメージで実行する場合は、Valgrindツールスイートのcallgrindや、straceなどの他のシステムツールを使用できます。GraalVMで実行される言語として、他のGraalVMツールも使用できます。プロファイリングの広義の定義では、コンパイラの出力を検査するためにIdeal Graph Visualizer (IGV)やC1 Visualizerを使用することもできます。

このガイドは、各ツールの使用方法ではなく、基本的な使用法を理解していることを前提として、ツールから最も有用な情報を抽出するための提案に重点を置いています。

CPUサンプラーを使用したプロファイリング #

アプリケーションレベルをプロファイリングする最も簡単な方法は、例えば、どのゲスト言語関数で最も時間が費やされているかを調べるために、/toolsスイートの一部であり、GraalVMの一部であるCPUサンプラーを使用することです。言語ランチャーに--cpusamplerを渡すだけです。

language-launcher --cpusampler --cpusampler.Delay=MILLISECONDS -e 'p :hello'

ウォームアップ後にのみプロファイリングを開始するために、--cpusampler.Delay=MILLISECONDSでサンプリング遅延を使用することをお勧めします。そうすることで、どの関数がコンパイルされて、どの関数がコンパイルされていないにもかかわらず、実行にかなりの時間がかかるかを簡単に特定できます。

language-launcher --help:toolsで、その他の--cpusamplerオプションを確認してください。

CPUサンプラーからコンパイルデータを取得する #

CPUサンプラーは、コンパイルされたコードに費やされた時間に関する情報を表示しません。これは、少なくとも部分的には、「コンパイルされたコード」では十分に説明できなくなったマルチティアコンパイルの導入によって動機付けられました。--cpusampler.ShowTiersオプションを使用すると、ユーザーはコンパイルデータを見るかどうかを制御できるだけでなく、レポートで考慮する必要があるコンパイルティアを正確に指定できます。たとえば、--cpusampler.ShowTiers=trueを追加すると、以下に示すように、実行中に発生したすべてのコンパイルティアが表示されます。

-----------------------------------------------------------------------------------------------------------------------------------------------------------
Sampling Histogram. Recorded 553 samples with period 10ms.
  Self Time: Time spent on the top of the stack.
  Total Time: Time spent somewhere on the stack.
  T0: Percent of time spent in interpreter.
  T1: Percent of time spent in code compiled by tier 1 compiler.
  T2: Percent of time spent in code compiled by tier 2 compiler.
-----------------------------------------------------------------------------------------------------------------------------------------------------------
Thread[main,5,main]
 Name              ||             Total Time    |   T0   |   T1   |   T2   ||              Self Time    |   T0   |   T1   |   T2   || Location
-----------------------------------------------------------------------------------------------------------------------------------------------------------
 accept            ||             4860ms  87.9% |  31.1% |  18.3% |  50.6% ||             4860ms  87.9% |  31.1% |  18.3% |  50.6% || ../primes.js~13-22:191-419
 :program          ||             5530ms 100.0% | 100.0% |   0.0% |   0.0% ||              360ms   6.5% | 100.0% |   0.0% |   0.0% || ../primes.js~1-46:0-982
 next              ||             5150ms  93.1% |  41.7% |  39.4% |  18.8% ||              190ms   3.4% | 100.0% |   0.0% |   0.0% || ../primes.js~31-37:537-737
 DivisibleByFilter ||              190ms   3.4% |  89.5% |  10.5% |   0.0% ||              100ms   1.8% |  80.0% |  20.0% |   0.0% || ../primes.js~7-23:66-421
 AcceptFilter      ||               30ms   0.5% | 100.0% |   0.0% |   0.0% ||               20ms   0.4% | 100.0% |   0.0% |   0.0% || ../primes.js~1-5:0-63
 Primes            ||               40ms   0.7% | 100.0% |   0.0% |   0.0% ||                0ms   0.0% |   0.0% |   0.0% |   0.0% || ../primes.js~25-38:424-739
-----------------------------------------------------------------------------------------------------------------------------------------------------------

あるいは、以下に示すように、--cpusampler.ShowTiers=0,2は、インタプリタ時間とティア2でコンパイルされたコードに費やされた時間のみを表示します。

-----------------------------------------------------------------------------------------------------------------------------------------
Sampling Histogram. Recorded 620 samples with period 10ms.
  Self Time: Time spent on the top of the stack.
  Total Time: Time spent somewhere on the stack.
  T0: Percent of time spent in interpreter.
  T2: Percent of time spent in code compiled by tier 2 compiler.
-----------------------------------------------------------------------------------------------------------------------------------------
Thread[main,5,main]
 Name              ||             Total Time    |   T0   |   T2   ||              Self Time    |   T0   |   T2   || Location
-----------------------------------------------------------------------------------------------------------------------------------------
 accept            ||             5510ms  88.9% |  30.9% |  52.3% ||             5510ms  88.9% |  30.9% |  52.3% || ../primes.js~13-22:191-419
 :program          ||             6200ms 100.0% | 100.0% |   0.0% ||              320ms   5.2% | 100.0% |   0.0% || ../primes.js~1-46:0-982
 next              ||             5870ms  94.7% |  37.3% |  20.6% ||              190ms   3.1% |  89.5% |  10.5% || ../primes.js~31-37:537-737
 DivisibleByFilter ||              330ms   5.3% | 100.0% |   0.0% ||              170ms   2.7% | 100.0% |   0.0% || ../primes.js~7-23:66-421
 AcceptFilter      ||               20ms   0.3% | 100.0% |   0.0% ||               10ms   0.2% | 100.0% |   0.0% || ../primes.js~1-5:0-63
 Primes            ||               20ms   0.3% | 100.0% |   0.0% ||                0ms   0.0% |   0.0% |   0.0% || ../primes.js~25-38:424-739
-----------------------------------------------------------------------------------------------------------------------------------------

CPUサンプラーからフレームグラフを作成する #

CPUSamplerからのヒストグラム出力は非常に大きくなる可能性があり、分析が困難になります。さらに、フラット形式では、出力に情報がエンコードされていないため、コールグラフを分析することはできません。フレームグラフは、コールグラフ全体を表示します。その構造により、アプリケーションの時間がどこに費やされているかをかなり簡単に確認できます。

フレームグラフの作成は多段階のプロセスです。まず、JSONフォーマッタでアプリケーションをプロファイリングする必要があります。

language-launcher --cpusampler --cpusampler.SampleInternal --cpusampler.Output=json -e 'p :hello' > simple-app.json

標準ライブラリ関数などの内部ソースをプロファイリングする場合は、--cpusampler.SampleInternal=trueオプションを使用します。

JSONフォーマッタは、ヒストグラム形式では利用できないコールグラフ情報をエンコードします。ただし、この出力からフレームグラフを作成するには、コールスタックサンプルを単一行に折りたたむ形式に変換する必要があります。これは、Benoit DalozeのFlameGraphのフォークにあるstackcollapse-graalvm.rbを使用して行うことができます。

まだ行っていない場合は、このFlameGraphのフォークを親ディレクトリにクローンする必要があります。これで、スクリプトを実行して出力を変換し、SVGデータを生成するスクリプトにパイプできます。

../FlameGraph/stackcollapse-graalvm.rb simple-app.json | ../FlameGraph/flamegraph.pl > simple-app.svg

この時点で、ChromiumベースのWebブラウザでSVGファイルを開く必要があります。システムでは、SVGファイルのデフォルトのアプリケーションとして別の画像操作アプリケーションが構成されている場合があります。このようなアプリケーションにファイルを読み込むとグラフがレンダリングされる場合がありますが、フレームグラフのインタラクティブなコンポーネントは処理されない可能性があります。Firefoxも同様に機能する可能性がありますが、Chromiumベースのブラウザは現在、フレームグラフファイルに対するより優れたサポートとパフォーマンスを備えているようです。

Oracle Developer Studioを使用したプロファイリング #

Oracle Developer Studioには、GraalVMで使用できるパフォーマンスアナライザが含まれています。Developer StudioはOTNからダウンロードでき、執筆時点での現在のバージョン(12.6)は、本番環境での使用および商用アプリケーションの開発に対して永久的な無償ライセンスを提供しています。

Developer Studio Performance Analyzerの使用は簡単です。Developer StudioのバイナリへのパスをPATHに含め、通常のコマンドラインの前にcollectを付加します。例:

collect js mybenchmark.js

完了すると、コマンド実行のプロファイリングデータを含む「実験」(.er)ディレクトリが作成されます。デフォルトではtest.1.erです。プロファイリング結果を表示するには、analyzerツールを使用します。

analyzer test.1.er

analyzer GUIを使用すると、キャプチャされたプロファイリング情報を、アプリケーションのタイムライン、フラット関数リスト、コールツリー、フレームグラフなど、いくつかの異なる方法で表示できます。また、テキスト形式でプロファイリング情報を出力してさらに分析するために使用できるコマンドラインツールer_printもあります。

詳細については、パフォーマンスアナライザドキュメントを参照してください。

お問い合わせ