PerfCollect を使用して .NET アプリケーションをトレースする

この記事の対象: ✔️ .NET Core 2.1 SDK 以降のバージョン

Linux でパフォーマンスの問題が発生した場合は、perfcollect でトレースを収集することにより、パフォーマンスの問題が発生したときにコンピューターで何が起きていたかに関する詳細な情報を収集できます。

perfcollect は Bash スクリプトであり、Linux Trace Toolkit: next generation (LTTng) を利用して、ランタイムまたは任意の EventSource から書き込まれたイベントを収集すると共に、perf を利用してターゲット プロセスの CPU サンプルを収集します。

コンピューターを準備する

perfcollect を使用してパフォーマンス トレースが収集されるようコンピューターを準備するには、以下の手順のようにします。

Note

コンテナー内からキャプチャする場合は、コンテナーに適切な機能が必要です。 最低限必要な機能は、PERFMONSYS_PTRACE です。 最小セットでキャプチャが失敗した場合は、コンテナーに SYS_ADMIN 機能を追加してください。 PerfCollect を使用してコンテナー内のアプリケーションをトレースする方法の詳細については、「コンテナーでの診断の収集」を参照してください。

  1. perfcollect をダウンロードします。

    curl -OL https://aka.ms/perfcollect
    
  2. スクリプトを実行できるようにします。

    chmod +x perfcollect
    
  3. トレースの前提条件をインストールします。これらは実際のトレース ライブラリです。

    sudo ./perfcollect install
    

    これにより、次の前提条件がコンピューターにインストールされます。

    1. perf: Linux Performance Events サブシステムと、コンパニオン ユーザーモード コレクションおよびビューアー アプリケーション。 perf は Linux カーネル ソースの一部ですが、通常は既定ではインストールされません。

    2. LTTng: 実行時に CoreCLR によって生成されるイベント データをキャプチャするために使用されます。 その後、このデータを使用して、GC、JIT、スレッド プールなどのさまざまなランタイム コンポーネントの動作が分析されます。

最新のバージョンの .NET Core および Linux perf ツールでは、フレームワーク コードのためのメソッド名の自動解決がサポートされています。

ネイティブ ランタイム DLL (libcoreclr.so など) のメソッド名の解決の場合は、perfcollect によってデータの変換時にそれらのシンボルが解決されますが、それが行われるのはこれらのバイナリのシンボルが存在する場合だけです。 詳細については、ネイティブ ランタイムのシンボルの取得に関するセクションを参照してください。

トレースを収集する

  1. 2 つのシェルを使用できるようにします。1 つはトレースの制御用で ( [Trace] と呼びます)、もう 1 つはアプリケーションの実行用です ( [App] と呼びます)。

  2. [Trace] 収集を開始します。

    sudo ./perfcollect collect sampleTrace
    

    予想される出力:

    Collection started.  Press CTRL+C to stop.
    
  3. [App] 次の環境変数を使用して、アプリケーションのシェルを設定します。これにより、CoreCLR のトレース構成が有効になります。

    export DOTNET_PerfMapEnabled=1
    export DOTNET_EnableEventLog=1
    

    注意

    .NET 7 でアプリを実行するとき、前述の環境変数に加え、DOTNET_EnableWriteXorExecute=0 も設定する必要があります。 次に例を示します。

    export DOTNET_EnableWriteXorExecute=0
    

    注意

    .NET 6 では、.NET の実行時の動作を構成する環境変数のプレフィックスが、COMPlus_ ではなく DOTNET_ に標準化されています。 ただし、プレフィックス COMPlus_ は引き続き機能します。 以前のバージョンの .NET ランタイムを使用している場合は、環境変数に COMPlus_ プレフィックスをまだ使用する必要があります。

  4. [App] アプリを実行します。パフォーマンスの問題をキャプチャするために必要な限り実行させておきます。 正確な長さは、調査する必要があるパフォーマンスの問題が発生した時間帯を十分に把握できる限り、必要なだけ短くできます。

    dotnet run
    
  5. [Trace] 収集を停止します。Ctrl + C キーを押します。

    ^C
    ...STOPPED.
    
    Starting post-processing. This may take some time.
    
    Generating native image symbol files
    ...SKIPPED
    Saving native symbols
    ...FINISHED
    Exporting perf.data file
    ...FINISHED
    Compressing trace files
    ...FINISHED
    Cleaning up artifacts
    ...FINISHED
    
    Trace saved to sampleTrace.trace.zip
    

    圧縮されたトレース ファイルが、現在の作業ディレクトリに格納されます。

トレースを表示する

収集されたトレースを表示するには、いくつかのオプションがあります。 トレースは、Windows で PerfView を使用すると最も適切に表示されますが、PerfCollect 自体または TraceCompass を使用して Linux で直接表示することもできます。

PerfCollect を使用してトレース ファイルを表示する

Perfcollect 自体を使用して、収集したトレースを表示できます。 これを行うには、次のコマンドを使用します。

./perfcollect view sampleTrace.trace.zip

このようにすると、既定では、perf を使用しているアプリケーションの CPU トレースが表示されます。

LTTng によって収集されたイベントを見るには、フラグ -viewer lttng を渡して個々のイベントを表示します。

./perfcollect view sampleTrace.trace.zip -viewer lttng

このようにすると、babeltrace ビューアーを使用してイベントのペイロードが出力されます。

# [01:02:18.189217659] (+0.020132603) ubuntu-xenial DotNETRuntime:ExceptionThrown_V1: { cpu_id = 0 }, { ExceptionType = "System.Exception", ExceptionMessage = "An exception happened", ExceptionEIP = 139875671834775, ExceptionHRESULT = 2148734208, ExceptionFlags = 16, ClrInstanceID = 0 }
# [01:02:18.189250227] (+0.020165171) ubuntu-xenial DotNETRuntime:ExceptionCatchStart: { cpu_id = 0 }, { EntryEIP = 139873639728404, MethodID = 139873626968120, MethodName = "void [helloworld] helloworld.Program::Main(string[])", ClrInstanceID = 0 }

PerfView を使用してトレース ファイルを開く

CPU サンプルとイベント両方の集約ビューを表示するには、Windows コンピューターで PerfView を使用します。

  1. trace.zip ファイルを Linux から Windows コンピューターにコピーします。

  2. https://aka.ms/perfview から PerfView をダウンロードします。

  3. PerfView.exe を実行する

    PerfView.exe <path to trace.zip file>
    

PerfView により、トレース ファイルに含まれるデータに基づいてサポートされるビューの一覧が表示されます。

  • CPU の調査の場合は、 [CPU stacks](CPU スタック) を選択します。

  • GC の詳細な情報の場合は、 [GCStats](GC 統計) を選択します。

  • プロセス、モジュール、メソッドごとの JIT の情報の場合は、 [JITStats](JIT 統計) を選択します。

  • 必要な情報のビューがない場合は、生のイベント ビューでイベントを検索してみることができます。 [Events](イベント) を選択します。

PerfView でのビューの解釈方法の詳細については、ビュー自体のヘルプ リンクを参照するか、PerfView のメイン ウィンドウで [ヘルプ] > [ユーザー ガイド] の順に選択してください。

注意

System.Diagnostics.Tracing.EventSource API を使用して書き込まれたイベント (フレームワークからのイベントを含む) は、プロバイダー名の下に表示されません。 代わりに、Microsoft-Windows-DotNETRuntime プロバイダーの下に EventSourceEvent イベントとして書き込まれ、そのペイロードは JSON でシリアル化されます。

Note

メソッドの名前とコールスタックに [unknown] /memfd:doublemapper フレームがある場合、perfcollect で追跡するアプリを実行する前に DOTNET_EnableWriteXorExecute=0 を設定します。

TraceCompass を使用してトレース ファイルを開く

Eclipse TraceCompass は、トレースを表示するために使用できるもう 1 つのオプションです。 TraceCompass は Linux マシンでも動作するので、トレースを Windows コンピューターに移動する必要はありません。 TraceCompass を使用してトレース ファイルを開くには、ファイルを解凍する必要があります。

unzip myTrace.trace.zip

perfcollect によって収集された LTTng トレースは、lttngTrace 内のサブディレクトリに CTF ファイル形式で保存されます。 具体的には、CTF ファイルは lttngTrace/auto-20201025-101230\ust\uid\1000\64-bit\ のようなディレクトリに格納されます。

File -> Open Trace を選択して metadata ファイルを選択することにより、TraceCompass で CTF トレースファイルを開くことができます。

詳細については、TraceCompass のドキュメントを参照してください。

ネイティブ ランタイムのシンボルを取得する

ほとんどの場合、関心があるのは独自のコードであり、それは perfcollect によって既定で解決されます。 場合によっては、NET DLL の内部で起こっていること (最後のセクションの内容) を確認すると役に立つことがありますが、ネイティブ ランタイム dll (通常は libcoreclr.so) で何が起こっているかは興味深いものです。 perfcollect によってデータの変換時にこれらに対するシンボルが解決されますが、これらのネイティブ DLL のシンボルが存在する場合 (および、それらが対象のライブラリの隣にある場合) に限られます。

これを行う dotnet-symbol という名前のグローバル コマンドがあります。 dotnet-symbol を使用してネイティブ ランタイム シンボルを取得するには:

  1. dotnet-symbol をインストールします。

    dotnet tool install -g dotnet-symbol
    
  2. シンボルをダウンロードします。 インストールされている .NET Core ランタイムのバージョンが 2.1.0 の場合は、次のコマンドを実行します。

    mkdir mySymbols
    dotnet symbol --symbols --output mySymbols  /usr/share/dotnet/shared/Microsoft.NETCore.App/2.1.0/lib*.so
    
  3. シンボルを正しい場所にコピーします。

    sudo cp mySymbols/* /usr/share/dotnet/shared/Microsoft.NETCore.App/2.1.0
    

    適切なディレクトリへの書き込みアクセス権がないためにこの操作を実行できない場合は、perf buildid-cache を使用してシンボルを追加できます。

その後、perfcollect を実行するときに、ネイティブ dll のシンボル名を取得する必要があります。

Docker コンテナー内で収集する

コンテナー環境で perfcollect を使用する方法の詳細については、「コンテナーでの診断の収集」を参照してください。

収集オプションについての詳細情報

診断のニーズに合わせて、perfcollect を使用して次のオプションのフラグを指定できます。

特定の期間について収集する

特定の期間についてトレースを収集する場合は、-collectsec オプションに続けて、トレースを収集する合計秒数を数値で指定できます。

threadtime のトレースを収集する

-threadtime と共に perfcollect を指定すると、スレッドごとの CPU 使用率データを収集できます。 これにより、各スレッドが CPU 時間を費やしていた場所を分析できます。

マネージド メモリとガベージ コレクターのパフォーマンスのトレースを収集する

次のオプションを使用すると、ランタイムから特に GC イベントを収集できます。

  • perfcollect collect -gccollectonly

GC 収集イベントの最小セットのみを収集します。 これは、ターゲット アプリのパフォーマンスへの影響が最も少ない、最も詳細度の低い GC イベント収集プロファイルです。 このコマンドは PerfView の PerfView.exe /GCCollectOnly collect コマンドと似ています。

  • perfcollect collect -gconly

JIT、ローダー、例外イベントを使用して、より詳細な GC 収集イベントを収集します。 これにより、より詳細なイベント (割り当て情報や GC 結合情報など) が要求され、-gccollectonly オプションよりもターゲット アプリのパフォーマンスに大きく影響します。 このコマンドは PerfView の PerfView.exe /GCOnly collect コマンドと似ています。

  • perfcollect collect -gcwithheap

最も詳細な GC コレクション イベントを収集します。これにより、ヒープの存続と移動も追跡されます。 これにより、GC の動作を詳細に分析できますが、各 GC に 2 倍以上の時間がかかるおそれがあるため、パフォーマンス コストが高くなります。 運用環境でトレースするときにこのトレース オプションを使用した場合のパフォーマンスへの影響を理解しておくことをお勧めします。