天天看點

調試 .NET Core 中的高 CPU 使用率

本文适用于: ✔️ .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 計數器

在嘗試收集診斷資料之前,需要觀察 CPU 狀況是否過高。 使用以下指令從項目根目錄運作示例應用程式。

dotnet run

若要查找該程序 ID,請使用以下指令:

dotnet-trace ps

注意指令輸出中的程序 ID。 我們的程序 ID 是 22884,你的程序 ID 将不同。 若要檢查目前的 CPU 使用率,請使用 dotnet counters 工具指令:

dotnet-counters monitor --refresh-interval 1 -p 22884

refresh-interval 是計數器輪詢 CPU 值間隔的秒數。 輸出應與以下内容類似:

Press p to pause, r to resume, q to quit.

Status: Running

[System.Runtime]

% Time in GC since last GC (%) 0

Allocation Rate / 1 sec (B) 0

CPU Usage (%) 0

Exception Count / 1 sec 0

GC Heap Size (MB) 4

Gen 0 GC Count / 60 sec 0

Gen 0 Size (B) 0

Gen 1 GC Count / 60 sec 0

Gen 1 Size (B) 0

Gen 2 GC Count / 60 sec 0

Gen 2 Size (B) 0

LOH Size (B) 0

Monitor Lock Contention Count / 1 sec 0

Number of Active Timers 1

Number of Assemblies Loaded 140

ThreadPool Completed Work Item Count / 1 sec 3

ThreadPool Queue Length 0

ThreadPool Thread Count 7

Working Set (MB) 63

在 Web 應用運作的情況下,CPU 根本不會在啟動後就立即被消耗,且會在 0% 進行報告。 使用 60000 作為路由參數導航到 api/diagscenario/highcpu 路由:

https://localhost:5001/api/diagscenario/highcpu/60000

現在,重新運作 dotnet-counters 指令。 若要隻監視 cpu-usage,請在指令中指定 System.Runtime[cpu-usage]。

dotnet-counters monitor --counters System.Runtime[cpu-usage] -p 22884 --refresh-interval 1

你将看到 CPU 使用率已增加,如下所示:

Press p to pause, r to resume, q to quit.

Status: Running

[System.Runtime]

CPU Usage (%) 25

在整個請求期間,CPU 使用率将徘徊在 25% 左右。 根據主機的不同,預期 CPU 使用率會有所不同。

提示

若要可視化更高的 CPU 使用率,可以在多個浏覽器頁籤中同時使用此終結點。

此時,你可以放心地說 CPU 運作的速度比預期的要高。

跟蹤生成

當分析速度較慢的請求時,需要一個診斷工具來提供代碼正在執行的操作的見解。 常見的選擇是探查器,并且有不同的探查器選項可供選擇。

Linux

Windows

perf 工具可用于生成 .NET Core 應用配置檔案。 退出示例調試目标的上一個執行個體。

設定 DOTNET_PerfMapEnabled 環境變量,使 .NET Core 應用在 /tmp 目錄中建立 map 檔案。 perf 使用此 map 檔案按名稱将 CPU 位址映射到 JIT 生成的函數。 有關詳細資訊,請參閱寫入 Perf 映射。

備注

.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

還可以使用以下指令生成 flame-graph:

git clone --depth=1 https://github.com/BrendanGregg/FlameGraph

sudo perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > flamegraph.svg

此指令生成 flamegraph.svg,你可以在浏覽器中檢視 flamegraph.svg 以調查性能問題:

在 Windows 上,可以使用 dotnet-trace 工具作為探查器。 使用之前的示例調試目标,再次使用高 CPU (https://localhost:5001/api/diagscenario/highcpu/60000) 終結點。 當它在 1 分鐘請求内運作時,使用 collect 指令,如下所示:

dotnet-trace collect -p 22884 --providers Microsoft-DotNETCore-SampleProfiler

讓 dotnet-trace 運作大約 20-30 秒,然後按 Enter 退出收集。 結果是位于同一檔案夾中的 nettrace 檔案。 nettrace 檔案是在 Windows 上使用現有分析工具的好方法。

使用 PerfView 打開 nettrace,如下所示。

請參閱

用于列出程序的 dotnet-trace

用于檢查托管記憶體使用情況的 dotnet-counters

用于收集和分析轉儲檔案的 dotnet-dump

dotnet/diagnostics

後續步驟

調試 .NET Core 中的死鎖