V8のLinux perf 統合

V8はLinux perf ツールを組み込みでサポートしています。 --perf-prof コマンドラインオプションで有効になります。
V8は実行中にパフォーマンスデータをファイルに書き込みます。このファイルは、Linux perf ツールを使用して、V8のJITコンパイルされたコード(JS関数名を含む)のパフォーマンスを分析するために使用できます。

要件 #

V8のビルド #

Linux perfとのV8の統合を使用するには、enable_profiling = true gnフラグを指定してビルドする必要があります。

echo 'enable_profiling = true' >> out/x64.release/args.gn
autoninja -C out/x64.release

linux-perf-d8.py を使用したd8のプロファイリング #

d8をビルドした後、linux perfの使用を開始できます。

tools/profiling/linux-perf-d8.py out/x64.release/d8 path/to/test.js;

より完全な例

echo '(function f() {
var s = 0; for (var i = 0; i < 1000000000; i++) { s += i; } return s;
})();'
> test.js;

# Use custom V8 flags and a separate output dir for less clutter:
mkdir perf_results
tools/profiling/linux-perf-d8.py --perf-data-dir=perf_results \
out/x64.release/d8 --expose-gc --allow-natives-syntax test.js;

# Fancy UI (`-flame` is googler-only, use `-web` as a public alternative):
pprof -flame perf_results/XXX_perf.data.jitted;
# Terminal-based tool:
perf report -i perf_results/XXX_perf.data.jitted;

詳細は、linux-perf-d8.py --help を確認してください。 d8バイナリ引数の後にすべてのd8フラグを使用できることに注意してください。

linux-perf-chrome.py を使用したChromeまたはcontent_shellのプロファイリング #

  1. Chromeのプロファイリングには、linux-perf-chrome.py スクリプトを使用できます。適切なC++シンボルを取得するには、必要なchrome gnフラグを追加してください。

  2. ビルドが完了したら、C++とJSコードの両方の完全なシンボルを使用してWebサイトをプロファイリングできます。

    mkdir perf_results;
    tools/profiling/linux-perf-chrome.py out/x64.release/chrome \
    --perf-data-dir=perf_results --timeout=30
  3. Webサイトに移動し、ブラウザを閉じます(または--timeoutが完了するまで待ちます)。

  4. ブラウザを終了すると、linux-perf.pyはファイルを後処理し、各レンダラープロセスの結果ファイルのリストを表示します。

    chrome_renderer_1583105_3.perf.data.jitted      19.79MiB
    chrome_renderer_1583105_2.perf.data.jitted       8.59MiB
    chrome_renderer_1583105_4.perf.data.jitted       0.18MiB
    chrome_renderer_1583105_1.perf.data.jitted       0.16MiB
    

linux-perfの結果の調査 #

最後に、Linux perf ツールを使用して、d8またはchromeレンダラープロセスのプロファイルを調査できます。

perf report -i perf_results/XXX_perf.data.jitted

また、pprofを使用して、より多くの視覚化を生成することもできます。

# Note: `-flame` is google-only, use `-web` as a public alternative:
pprof -flame perf_results/XXX_perf.data.jitted;

低レベルのlinux-perfの使用法 #

d8で直接linux-perfを使用する #

ユースケースによっては、d8で直接linux-perfを使用する必要がある場合があります。
これには2段階のプロセスが必要です。最初にperf recordは、JSシンボルを挿入するためにperf injectで後処理する必要があるperf.dataファイルを作成します。

perf record --call-graph=fp --clockid=mono --freq=max \
--output=perf.data
out/x64.release/d8 \
--perf-prof --no-write-protect-code-memory \
--interpreted-frames-native-stack \
test.js;
perf inject --jit --input=perf.data --output=perf.data.jitted;
perf report --input=perf.data.jitted;

V8 linux-perfフラグ #

--perf-prof は、JITコードでパフォーマンスサンプルを記録するためにV8コマンドラインで使用されます。

--nowrite-protect-code-memory は、コードメモリの書き込み保護を無効にするために必要です。これは、perfがコードページから書き込みビットを削除するイベントを検出すると、コードページに関する情報を破棄するためです。次に、テストJavaScriptファイルからサンプルを記録する例を示します。

--interpreted-frames-native-stack は、解釈された関数に対して異なるエントリポイント(InterpreterEntryTrampolineのコピーされたバージョン)を作成するために使用されます。これにより、アドレスだけでperfで区別できます。 InterpreterEntryTrampolineをコピーする必要があるため、パフォーマンスとメモリのわずかな低下が発生します。

chromeで直接linux-perfを使用する #

  1. Chrome自体をプロファイリングするために、同じV8フラグを使用できます。正しいV8フラグについては上記の手順に従い、chromeビルドに必要なchrome gnフラグを追加します。

  2. ビルドが完了したら、C++とJSコードの両方の完全なシンボルを使用してWebサイトをプロファイリングできます。

    out/x64.release/chrome \
    --user-data-dir=`mktemp -d` \
    --no-sandbox --incognito --enable-benchmarking \
    --js-flags='--perf-prof --no-write-protect-code-memory --interpreted-frames-native-stack'
  3. Chromeを起動した後、タスクマネージャーを使用してレンダラープロセスIDを見つけ、それを使用してプロファイリングを開始します。

    perf record -g -k mono -p $RENDERER_PID -o perf.data
  4. Webサイトに移動し、perf出力の評価方法に関する次のセクションに進みます。

  5. 実行が完了したら、perfツールから収集された静的情報と、V8によって出力されたJITコードのパフォーマンスサンプルを組み合わせます。

    perf inject --jit --input=perf.data --output=perf.data.jitted
  6. 最後に、Linux perf ツールを使用して調査できます

perf のビルド #

古いLinuxカーネルを使用している場合は、JITサポートをローカルでlinux-perfをビルドできます。

以下の手順では、perfsome/director/tip/tools/perf/perfとして呼び出します。