この記事の対象: ✔️ .NET Core 3.1 SDK 以降のバージョン
このチュートリアルでは、過剰な CPU 使用率シナリオをデバッグする方法について説明します。 ASP.NET Core Web アプリの提供された例のソースコードリポジトリを使用すると、意図的にデッドロックを発生させることができます。 エンドポイントは応答を停止し、スレッドの蓄積が発生します。 さまざまなツールを使用して、いくつかの主要な診断データを使用してこのシナリオを診断する方法について説明します。
このチュートリアルの内容:
- 高い 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
Last Deltaのdotnet.process.cpu.time値に焦点を当てて、CPU がアクティブになっている更新期間内 (現在は既定値の 1 秒に設定) の秒数が示されます。 Web アプリを実行して起動直後には、CPU はまったく使用されず、これらの差分は両方とも 0 です。
api/diagscenario/highcpuをルート パラメーターとして使用して、60000 ルートに移動します。
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 collect は、すべてのオペレーティング システムで機能しますが、セーフポイント バイアスとマネージドのみの呼び出し履歴では、WINDOWS 用の ETW や Linux 用の perf などのカーネル対応プロファイラーよりも一般的な情報に制限されます。 オペレーティング システムと .NET のバージョンによっては、改善されたプロファイリング機能が利用できる場合があります。詳細なガイダンスについては、プラットフォーム固有のタブを参照してください。
dotnet-trace collect-linuxを使用する (.NET 10 以降)
.NET 10 以降では、 dotnet-trace collect-linux は Linux で推奨されるプロファイリングアプローチです。 EventPipe と OS レベルのperf_eventsを組み合わせて、プロセスの再起動を必要とせずに、マネージド呼び出し履歴とネイティブ呼び出し履歴の両方を含む単一の統合トレースを生成します。 これには、ルートアクセス許可と、 CONFIG_USER_EVENTS=yを使用した Linux カーネル 6.4 以降が必要です。 完全な要件については、 collect-linux の前提条件を 参照してください。
サンプル デバッグ ターゲットが .NET 10 以降をターゲットにするように構成されていることを確認し、それを実行して、高 CPU エンドポイント (https://localhost:5001/api/diagscenario/highcpu/60000) をもう一度実行します。 1 分間の要求内で実行されている間は、 dotnet-trace collect-linux を実行してマシン全体のトレースをキャプチャします。
sudo dotnet-trace collect-linux
約 20 ~ 30 秒間実行し、 Ctrl キーを 押しながら C キーまたは Enter キーを押してコレクションを停止します。 その結果、マネージド呼び出し履歴とネイティブ呼び出し履歴の両方を含む .nettrace ファイルが生成されます。
.nettraceでPerfViewを開き、[CPU スタック] ビューを使用して、CPU 時間が最も長い方法を特定します。
トレース内のネイティブ ランタイム シンボルの解決については、「 ネイティブ ランタイム フレームのシンボルを取得する」を参照してください。
perf を使用する
perf ツールを使用して、.NET Core アプリ プロファイルを生成することもできます。
サンプル デバッグ ターゲットの前のインスタンスを終了します。
DOTNET_PerfMapEnabled環境変数を設定して、.NET アプリが map ディレクトリに/tmp ファイルを作成するようにします。 この map ファイルは、名前によって JIT で生成された関数に CPU アドレスをマップするために、 perf によって使用されます。 詳細については、「 パフォーマンス マップと JIT ダンプのエクスポート」を参照してください。
同じターミナル セッションで サンプル デバッグ ターゲット を実行します。
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