この記事の対象: ✔️ .NET Core 3.1 SDK 以降のバージョン
このチュートリアルでは、過剰な CPU 使用率シナリオをデバッグする方法について説明します。 Core Web アプリのソース コード リポジトリ ASP.NET 例を使用すると、意図的にデッドロックが発生する可能性があります。 エンドポイントは応答を停止し、スレッドの蓄積が発生します。 さまざまなツールを使用して、いくつかの主要な診断データを使用してこのシナリオを診断する方法について説明します。
このチュートリアルの内容:
- CPU 使用率の高い調査
- dotnet-counters を使用して CPU 使用率を決定する
- トレース生成に dotnet-trace を使用する
- PerfView でのプロファイル パフォーマンス
- 過剰な CPU 使用率を診断して解決する
[前提条件]
このチュートリアルでは、次の内容を使用します。
- .NET Core 3.1 SDK 以降のバージョン。
- シナリオをトリガーするサンプル デバッグ ターゲット。
- dotnet-trace を使用してプロセスを一覧表示し、プロファイルを生成します。
- dotnet-counters を使用して CPU 使用率を監視します。
CPU カウンター
このチュートリアルを試す前に、最新バージョンの dotnet-counters をインストールしてください。
dotnet tool install --global dotnet-counters
アプリで .NET 9 より古いバージョンの .NET を実行している場合、dotnet-counters の出力 UI は若干異なって表示されます。詳細については 、dotnet-counters を参照してください。
診断データの収集を試みる前に、CPU の状態が高い状態を観察する必要があります。 プロジェクト のルート ディレクトリから次のコマンドを使用して 、サンプル アプリケーション を実行します。
dotnet run
現在の CPU 使用率を確認するには、 dotnet-counters ツール コマンドを使用します。
dotnet-counters monitor -n DiagnosticScenarios --showDeltas
出力は次のようになります。
Press p to pause, r to resume, q to quit.
Status: Running
Name Current Value Last Delta
[System.Runtime]
dotnet.assembly.count ({assembly}) 111 0
dotnet.gc.collections ({collection})
gc.heap.generation
------------------
gen0 8 0
gen1 1 0
gen2 0 0
dotnet.gc.heap.total_allocated (By) 4,042,656 24,512
dotnet.gc.last_collection.heap.fragmentation.size (By)
gc.heap.generation
------------------
gen0 801,728 0
gen1 6,048 0
gen2 0 0
loh 0 0
poh 0 0
dotnet.gc.last_collection.heap.size (By)
gc.heap.generation
------------------
gen0 811,512 0
gen1 562,024 0
gen2 1,095,056 0
loh 98,384 0
poh 24,528 0
dotnet.gc.last_collection.memory.committed_size (By) 5,623,808 0
dotnet.gc.pause.time (s) 0.019 0
dotnet.jit.compilation.time (s) 0.582 0
dotnet.jit.compiled_il.size (By) 138,895 0
dotnet.jit.compiled_methods ({method}) 1,470 0
dotnet.monitor.lock_contentions ({contention}) 4 0
dotnet.process.cpu.count ({cpu}) 22 0
dotnet.process.cpu.time (s)
cpu.mode
--------
system 0.109 0
user 0.453 0
dotnet.process.memory.working_set (By) 65,515,520 0
dotnet.thread_pool.queue.length ({work_item}) 0 0
dotnet.thread_pool.thread.count ({thread}) 0 0
dotnet.thread_pool.work_item.count ({work_item}) 6 0
dotnet.timer.count ({timer}) 0 0
dotnet.process.cpu.timeのLast Delta値に焦点を当てて、CPU がアクティブになっている更新期間内 (現在は既定値の 1 秒に設定) の秒数が示されます。 Web アプリを実行すると、起動直後に CPU がまったく消費されず、これらの差分が両方とも 0。
60000をルート パラメーターとして使用して、api/diagscenario/highcpu ルートに移動します。
https://localhost:5001/api/diagscenario/highcpu/60000
次に、 dotnet-counters コマンドを 再実行します。
dotnet-counters monitor -n DiagnosticScenarios --showDeltas
次に示すように、CPU 使用率の増加が表示されます (ホスト コンピューターによっては、さまざまな CPU 使用率が予想されます)。
Press p to pause, r to resume, q to quit.
Status: Running
Name Current Value Last Delta
[System.Runtime]
dotnet.assembly.count ({assembly}) 111 0
dotnet.gc.collections ({collection})
gc.heap.generation
------------------
gen0 8 0
gen1 1 0
gen2 0 0
dotnet.gc.heap.total_allocated (By) 4,042,656 24,512
dotnet.gc.last_collection.heap.fragmentation.size (By)
gc.heap.generation
------------------
gen0 801,728 0
gen1 6,048 0
gen2 0 0
loh 0 0
poh 0 0
dotnet.gc.last_collection.heap.size (By)
gc.heap.generation
------------------
gen0 811,512 0
gen1 562,024 0
gen2 1,095,056 0
loh 98,384 0
poh 24,528 0
dotnet.gc.last_collection.memory.committed_size (By) 5,623,808 0
dotnet.gc.pause.time (s) 0.019 0
dotnet.jit.compilation.time (s) 0.582 0
dotnet.jit.compiled_il.size (By) 138,895 0
dotnet.jit.compiled_methods ({method}) 1,470 0
dotnet.monitor.lock_contentions ({contention}) 4 0
dotnet.process.cpu.count ({cpu}) 22 0
dotnet.process.cpu.time (s)
cpu.mode
--------
system 0.344 0.013
user 14.203 0.963
dotnet.process.memory.working_set (By) 65,515,520 0
dotnet.thread_pool.queue.length ({work_item}) 0 0
dotnet.thread_pool.thread.count ({thread}) 0 0
dotnet.thread_pool.work_item.count ({work_item}) 6 0
dotnet.timer.count ({timer}) 0 0
要求の期間中、CPU 使用率は増加した値の周りにホバーします。
ヒント
さらに高い CPU 使用率を視覚化するには、複数のブラウザー タブで同時にこのエンドポイントを実行できます。
この時点で、CPU が予想以上に高く実行されていることを安全に言うことができます。 問題の影響を特定することは、原因を見つける上で重要です。 診断ツールに加えて、高い CPU 消費量の影響を使用して、問題の原因を見つけます。
Profiler を使用して高 CPU を分析する
CPU 使用率が高いアプリを分析する場合は、コードの動作に関する分析情報を提供できる診断ツールが必要です。 通常の選択はプロファイラーであり、選択できるプロファイラー のオプションは異なります。
dotnet-trace は、すべてのオペレーティング システムで使用できますが、セーフポイント バイアスとマネージドのみの呼び出し履歴の制限により、Linux 用の "perf" や Windows 用 ETW などのカーネル対応プロファイラーと比較して、より一般的な情報が得られます。 パフォーマンス調査にマネージド コードのみが含まれる場合は、通常、 dotnet-trace で十分です。
perf ツールを使用して、.NET Core アプリ プロファイルを生成できます。 このツールを示しますが、dotnet-trace も使用できます。
サンプル デバッグ ターゲットの前のインスタンスを終了します。
DOTNET_PerfMapEnabled環境変数を設定して、.NET アプリが /tmp ディレクトリにmap ファイルを作成するようにします。 この map ファイルは、名前によって JIT で生成された関数に CPU アドレスをマップするために、 perf によって使用されます。 詳細については、「 パフォーマンス マップと JIT ダンプのエクスポート」を参照してください。
注
.NET 6 では、.NET ランタイム動作を構成する環境変数の DOTNET_ ではなく、プレフィックス COMPlus_ が標準化されています。 ただし、COMPlus_ プレフィックスは引き続き機能します。 以前のバージョンの .NET ランタイムを使用している場合でも、環境変数には COMPlus_ プレフィックスを使用する必要があります。
同じターミナル セッションで サンプル デバッグ ターゲット を実行します。
export DOTNET_PerfMapEnabled=1
dotnet run
高 CPU API エンドポイント (https://localhost:5001/api/diagscenario/highcpu/60000) をもう一度実行します。 1 分間の要求内で実行されている間は、プロセス ID で perf コマンドを実行します。
sudo perf record -p 2266 -g
perf コマンドは、パフォーマンス収集プロセスを開始します。 約 20 ~ 30 秒間実行し、 Ctrl キーを押しながら C キーを押してコレクション プロセスを終了します。 同じ perf コマンドを使用して、トレースの出力を確認できます。
sudo perf report -f
次のコマンドを使用して 、炎グラフ を生成することもできます。
git clone --depth=1 https://github.com/BrendanGregg/FlameGraph
sudo perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > flamegraph.svg
このコマンドを実行すると、パフォーマンスの問題を調査するためにブラウザーで表示できる flamegraph.svg が生成されます。
Visual Studio を使用した高 CPU データの分析
すべての *.nettrace ファイルは、Visual Studio で分析できます。 Visual Studio で Linux の *.nettrace ファイルを分析するには、他の必要なドキュメントに加えて 、*.nettrace ファイルを Windows コンピューターに転送し、Visual Studio で *.nettrace ファイルを開きます。 詳細については、「 CPU 使用率データの分析」を参照してください。
こちらも参照ください
- dotnet-trace を 使用してプロセスを一覧表示する
- マネージド メモリの使用状況を確認するための dotnet-counters
- dotnet-dump を使用してダンプ ファイルを収集および分析する
- dotnet/diagnostics
次のステップ
.NET