WPR/WPA 實務 ── 從系統整體調查「整台 PC 變慢」的效能調查入門

· 更新日期: · · Windows, 效能, WPR, WPA, ETW, 效能調查, 故障調查, Windows 開發

更新紀錄(僅初版,2026年08月21日 發布)
初次發布
引用本文(DOI(已登錄存檔): 10.5281/zenodo.22176585)

以下 DOI 指向先前登錄的存檔,內容可能與目前正文不同。引用目前正文時,請使用本頁網址。

Go Komura(2026)。〈WPR/WPA 實務 ── 從系統整體調查「整台 PC 變慢」的效能調查入門〉。小村軟體有限公司。 https://comcomponent.com/zh-TW/blog/wpr-wpa-system-performance-analysis/

DOI(已登錄存檔)
10.5281/zenodo.22176585
DOI(上次登錄版本)
10.5281/zenodo.22176586

「裝了應用之後整台 PC 就變慢了。可是看工作管理員,CPU 和記憶體都還有餘裕」「只有一台開機要花 3 分鐘」──這類諮詢最棘手的地方在於,連該調查哪個處理程序都不知道。

就算是應用 A 變慢,原因也可能是防毒軟體的掃描、另一個服務的大量寫入,或是橫跨多個處理程序的鎖鏈。你需要的是把整個 OS 的動作記錄在同一條時間軸上,追出時間消失在哪裡。

為此準備的工具,就是 Windows Performance Recorder(WPR)與 Windows Performance Analyzer(WPA)。WPR 使用 ETW(Event Tracing for Windows)擷取紀錄,WPA 用圖表與表格閱讀那份紀錄。用掉 CPU 的處理程序與堆疊、執行緒在等的對象、磁碟 I/O 的發出者與檔案,都可以順著時刻查出來。

本文要回答的是:「整台 PC 的慢要怎麼記錄下來,又該查 CPU、等待時間、I/O 之中的哪一個」。以中小企業的資訊部門人員與 Windows 應用開發者為對象,依據 2026 年 8 月時點的一手資料,說明從擷取實務到分析的全程。請特別以「CPU 很高時」與「CPU 很低卻還是慢時」的差異為主軸來閱讀。

要調查檔案與登錄存取的 Process Monitor、要追 .NET 應用的 CPU 與 GC 的 PerfView,和本文工具之間的分工,會在第 2 章整理。

1. 先講結論

基本流程是「用 WPR 擷取 → 在 WPA 縮小到出問題的時段 → 區分出是 CPU、等待還是 I/O」。 光看特定處理程序看不出來的問題,只要把所有處理程序與核心放在同一條時間軸上追,就查得出來。12

擷取的地方與閱讀的地方分開

擷取用的 wpr.exe 從 Windows 8.1 起就內建在 OS 裡,不必另外安裝。GUI 版的 WPRUI 與分析用的 WPA 包含在 Windows ADK 裡。因為可以拆成「在客戶環境只用 wpr.exe 擷取,閱讀交給手邊的 WPA」,所以即使是不能加裝軟體的伺服器也擷取得到。12

只要事件能重現,以系統管理員權限執行 wpr -start GeneralProfile -filemode → 重現事件 → wpr -stop C:\temp\trace.etl,就是基本的三個步驟。3 要先準備好儲存資料夾、取得擷取的核准、決定 ETL 的處理方式,再開始執行。 需要守候的情況,以及開機過程中的問題,還有別的擷取方式,請確認第 3 章與第 8 章。

在 WPA 先開哪一張圖

先把範圍縮到事件發生的區間,再用下表選出調查方向。45

該區間的狀態 最先要看的東西 要確認的事
CPU 很高 第 5 章:CPU Usage (Sampled) 哪個處理程序、哪個堆疊、哪個函式用掉了 CPU
CPU 整體很低,但單核、單執行緒滿載 第 5 章:CPU Usage (Sampled) 有沒有被整體使用率掩蓋掉的 CPU 瓶頸
CPU 整體與個別核心都沒滿載卻還是慢 第 6 章:CPU Usage (Precise) 在哪裡等、等了多久、誰解除了等待
懷疑是磁碟或檔案存取 第 7 章:Disk Usage / File I/O 排隊與裝置的處理時間、I/O 的發出者與檔案

Sampled 是以大約每 1 毫秒一次的取樣來看 CPU 時間的組成。6 Precise 則從內容切換的完整紀錄追出等待。以 Waits → ReadyingProcess → ReadyThreadStack 為線索,追出解除等待的那一方,是本文最想傳達的技術。47

依目的選擇閱讀路線

負責擷取的人請從第 2 章與第 3 章開始,要閱讀已擷取 ETL 的人請從第 4 章往下。要用函式名稱讀堆疊就需要符號設定,自家應用還要再加上 PDB 的路徑。8 若要調查 .NET 的 JIT 程式碼,擷取當下的 CLR 事件也不可少,請在擷取前確認第 4 章針對 .NET 的說明。

調查整體的推進方式與 ETL 的處理方式整理在第 9 章。ETL 含有處理程序名稱、檔案路徑等內部資訊,因此只擷取必要的最小量,並先決定好交給外部的條件。

圖中實線表示始終成立的關係,虛線表示附帶條件的關係(成立條件寫在詳細頁面中各關係的說明中)。關係的完整清單(共 16 條,附依據與可信度)以及主要概念的定義,彙整在知識地圖詳細頁面(日文)。資料:JSON-LD / Turtle

2. 工具的定位 ── 擷取的是 WPR,閱讀的是 WPA

Windows Performance Toolkit(WPT)是包含在 Windows ADK(Windows Assessment and Deployment Kit)裡的效能調查工具組,核心是 WPR 與 WPA 這兩個。2 角色分得很清楚。

WPR 負責擷取,WPA 負責分析

  • WPR(Windows Performance Recorder)=擷取。把一群 ETW 提供者綁成叫做「設定檔」的單位,開始與停止記錄,產出 ETL 檔。命令列版的 wpr.exe 從 Windows 8.1 起就內建在 OS 裡,不必另外安裝。GUI 版(WPRUI.exe)包含在 ADK 裡。1
  • WPA(Windows Performance Analyzer)=分析。開啟 ETL 檔,用圖表與表格進行分析。需要安裝 ADK。2

換句話說,如果只是用命令列擷取,就不必在客戶環境裡加裝任何軟體。用 OS 標準的 wpr.exe 擷取,把 ETL 檔帶回來,在手邊的電腦上用 WPA 閱讀──和封包擷取的「用 pktmon 擷取、用 Wireshark 閱讀」是同一種分工。

用 WPR 擷取、用 WPA 閱讀的分工在客戶環境用 OS 標準的 wpr.exe 記錄並產出 ETL 檔,帶回來在手邊以 ADK 安裝了 WPA 的電腦上分析手邊的電腦(已用 ADK 安裝 WPA)客戶環境(不必另外安裝)帶回來用 WPA 做圖表與表格分析ETL 檔wpr -start → 重現事件 → wpr -stop

與 Procmon、PerfView 的分工

和相近工具怎麼分開使用,也先整理一下。

  Process Monitor PerfView WPR + WPA
它回答的問題 哪個處理程序、對哪個路徑、做了什麼、結果如何 .NET 應用的 CPU、GC、配置情況如何 在整個 OS 上,時間消失在哪裡
守備範圍 檔案、登錄、處理程序啟動的操作紀錄 以受控程式碼為中心 CPU、等待、磁碟、檔案 I/O、電源等系統整體
適合的症狀 設定沒被讀到、ACCESS DENIED 自家 .NET 應用單獨變慢或記憶體問題 整台 PC 變慢、CPU 很閒卻還是慢、不知道元兇處理程序
文章 Procmon 實戰指南 PerfView 實務入門 本文

如果說 Procmon 是「做了什麼」的操作紀錄、PerfView 是「.NET 裡面發生了什麼」,那麼 WPA 就是橫跨所有處理程序稽核「時間消失在哪裡」的工具。

想把自家應用的事件一併記錄下來時

ETW 本身的機制,以及怎麼為自家應用加上 ETW 檢測,寫在〈Windows 事件記錄・ETW 入門〉。只要自家應用會發出 ETW 事件,就能把自家應用的關鍵節點一起記進追蹤裡,對照起來會輕鬆許多。

不過WPR 只會記錄所選記錄設定檔啟用的提供者所發出的事件。GeneralProfile 裡不含自家提供者。要一併記錄時,請準備啟用自家提供者的自訂記錄設定檔(.wprp),並像 wpr -start GeneralProfile -start MyApp.wprp!MyAppProfile 這樣,用 ! 指定 .wprp 檔裡的設定檔名稱來搭配使用3。

3. 擷取的實務(WPR)── start、重現、stop

執行前要先決定的事

在正式環境裡,即使只擷取短時間,也不要認為無條件安全。 ETW 雖然輕量,但記錄大量附帶堆疊的事件時,仍會消耗一定的 CPU 與記憶體。請挑對業務影響小的時段,並納入和一般變更作業相同的核准流程。

能重現的情況,就在重現前一刻開始、重現完立刻停止,控制在幾分鐘以內。準備好儲存資料夾,也先決定 ETL 要交給誰、保存期限,以及刪除方式。關於內容的注意事項在第 9 章。

以下是把當場能重現的事件用 File 模式擷取下來的例子。 不知道何時會發生的事件請看 3.1 節的 Memory 模式,開機與登入過程中的問題請往第 8 章。

一般擷取就是「start → 重現 → stop」

在以系統管理員身分開啟的命令提示字元裡執行。-profiles 用來事先確認清單,-status 用來確認擷取中的狀態。結尾的 -cancel 只在中途中止並丟棄時使用,不包含在一般的儲存步驟裡。

:: 可以使用的內建設定檔清單
wpr -profiles

:: 1. 開始擷取(通用設定檔、檔案模式)
wpr -start GeneralProfile -filemode

:: 2. 讓事件重現(擷取中的狀態確認用 wpr -status)

:: 3. 停止並儲存(可以附上問題的說明)。
::    儲存資料夾要事先建好(沒有的話 -stop 會儲存失敗)
mkdir C:\temp 2>nul
wpr -stop C:\temp\slow-pc.etl "重現了啟動應用 X 期間整台 PC 變慢的事件"

:: 中途放棄時不儲存直接丟棄
wpr -cancel

要記錄什麼,由設定檔決定

傳給 -start 的就是設定檔,也就是該次調查所需 ETW 提供者的集合。3 只要記住常用的幾個就夠了。9

設定檔 記錄的內容 使用時機
GeneralProfile CPU 取樣、內容切換、磁碟 I/O 等通用的一整套 先用這個。還不知道哪裡有問題時的第一手
CPU CPU 使用的詳細資料 已經知道 CPU 被燒滿時
DiskIO 磁碟 I/O 活動 懷疑磁碟時
FileIO 檔案 I/O 活動 要追到是存取哪個檔案時

設定檔可以把多個 -start 並排,同時指定好幾個(例如 wpr -start GeneralProfile -start FileIO -filemode)。3

WPR 擷取的流程與模式的選法在手邊能重現的事件用檔案模式短時間確實地擷取,不知道何時會發生的事件用預設的記憶體模式環形緩衝區守候。開機或登入過程中的事件使用開機追蹤。無論哪一種,開始、重現、停止的步驟都相同在手邊能重現不知道何時發生開機、登入過程中事件何時發生用 -filemode 短時間確實擷取用記憶體模式(預設、環形緩衝區)守候(3.1 節)開機追蹤(第 8 章)wpr -start → 重現、發生 → wpr -stop

3.1. Memory 模式與 File 模式 ── 能重現,還是要守候

WPR 的記錄目的地有兩種模式,預設是 Memory 模式(記憶體上的環形緩衝區)。

Memory 模式用在守候事件發生的時候。 因為是從最舊的事件開始覆寫的環形緩衝區,適合讓擷取一直跑著守候不知道何時發生的事件,發生了就停下來的用法。

File 模式用在短時間內能確實重現的時候。 加上 -filemode 就會變成 File 模式,所有內容都記錄到連續的檔案裡。這一邊不會被覆寫掉,代價是上限只有磁碟的可用空間,檔案會無止盡地長大。10

Memory 模式與 File 模式的記錄方式Memory 模式記錄到記憶體上的環形緩衝區,較舊的事件會被覆寫而只留下最近的部分,因此適合守候。File 模式把全部留在檔案裡,但上限只有磁碟可用空間,適合短時間確實重現ETW 事件的流動Memory 模式:環形緩衝區(由舊至新覆寫 → 只留下最近的)File 模式:全部留在檔案裡(上限是磁碟可用空間)適合守候不知道何時發生的事件適合短時間內能確實重現的事件

選用的大致準則如下。

  • 當場能重現 → File 模式。在重現前一刻開始、重現完立刻停止,擷取控制在幾分鐘以內
  • 不知道何時發生 → 用 Memory 模式(預設)守候。一發生就立刻 wpr -stop
  • 即使只是幾分鐘的 GeneralProfile,ETL 也可能達到數百 MB 到 GB 等級。檔案太大時可能無法用 WPA 分析,因此「擷取得愈久愈好」反而會適得其反1011

用 GUI 擷取時

要用 GUI 擷取時,啟動 WPRUI,選好設定檔與 Logging mode,再按 Start/Save 就好。步驟的細節整理在官方的 How-to 裡。11 即使是請客戶端的窗口代為擷取,也能以開始、重現、停止的步驟為中心,把前提條件與中止時的操作分開寫成作業手冊。

4. 讀 WPA 的基本功 ── 圖表、表格的黃金律、縮小時間範圍

把擷取到的 ETL 用 WPA 開啟後,左側的 Graph Explorer 會以 System Activity、Computation、Storage、Memory 等分類排出圖表的縮圖。12 把想看的圖表拖到右側的 Analysis 頁籤,上方會顯示圖、下方會顯示表。

要掌握的是欄位的排列方式、縮小時間範圍、符號設定這三件事。與其每張圖表都重學一次操作,不如從這個共通的閱讀方式開始。

4.1. 欄位的排列決定彙總的切入角度

WPA 的表格上有金色與藍色兩條直線,資料會依金色線左側欄位的順序階層化(分組),而藍色線右側的欄位是彙總值。13

排成「Process → Stack」就是每個處理程序的堆疊彙總,排成「Stack → Process」就是使用同一堆疊的所有處理程序的彙總──拖曳欄位重新排序這件事本身就是分析操作。理解了這一點,WPA 的所有表格就都變成同一種讀法。

表格的黃金律 ── 兩條直線與欄位的角色資料依金色線左側欄位的排列順序階層化,金色線與藍色線之間是顯示欄,藍色線右側是彙總值。拖曳欄位重新排序這件事本身就成為分析操作金色線左側:分組欄(排列順序=階層)金色線兩線之間:顯示欄藍色線藍色線右側:彙總值(Sum、% 等)拖曳欄位=分析操作(Process→Stack 就是各處理程序的堆疊彙總)

4.2. 只鎖定問題發生的時段

在圖上拖曳選取範圍,再按右鍵選「Zoom」,就會切換成只算該區間的彙總。效能調查的原則永遠是只看「事件正在發生的區間」(第 9 章)。

4.3. 載入符號,用函式名稱看堆疊

要用函式名稱讀堆疊,就執行選單的 Trace > Load Symbols。14 因為預設會參照 Microsoft 的公開符號伺服器(msdl.microsoft.com),所以只要有網際網路連線,Windows 本體的堆疊就解析得出來。

要連自家應用的函式名稱都看到,就在 Trace > Configure Symbol Paths 加上自家應用 PDB 所在的資料夾。8 PDB 是什麼、以及為什麼即使是 Release 組建也一定要保留下來,整理在〈PDB(程式資料庫)是什麼〉。

.NET 要把 NGen 映像與 JIT 程式碼分開看

關於 .NET Framework 的 NGen 原生映像,WPR 會在擷取時產生 NGen 用的 PDB(.ngenpdb)放到追蹤旁邊的資料夾,WPA 會自動參照。8 這是 NGen 映像專用的機制,以 JIT 執行的一般 .NET 應用自家程式碼不在範圍內。

JIT 程式碼的位址與函式名稱對應,是由 CLR 發出的 JIT 事件解析出來的,因此要調查 .NET 應用時,請準備啟用 CLR 提供者(Microsoft-Windows-DotNETRuntime 與同名的 Rundown)的記錄設定檔(.wprp),並用和第 2 章自家提供者相同的做法,以 wpr -start GeneralProfile -start MyDotNet.wprp!設定檔名稱 的形式搭配使用,讓 CLR 的事件包含在追蹤裡(手邊的 WPR 可以使用哪些內建設定檔,可用 wpr -profiles 確認)。

在這之上,為了對應到原始碼行,請保留組建產生的 PDB,並加進上述的符號路徑。

為了用函式名稱讀堆疊而做的符號解析執行 Trace Load Symbols 後,Windows 本體從 Microsoft 的公開符號伺服器解析,自家應用從加進符號路徑的組建 PDB 解析。NGen 映像由 WPR 產生的 NGen 用 PDB 解析,JIT 的 .NET 程式碼則以追蹤裡的 CLR JIT 事件與組建 PDB 為解析來源Trace > Load SymbolsWindows 本體:公開符號伺服器(msdl)自家應用:加進 Configure Symbol Paths 的組建 PDB.NET Framework 的 NGen 映像:WPR 產生的 .ngenpdbJIT 的 .NET 程式碼:追蹤裡的 CLR JIT 事件 + 組建 PDB

4.4. 決定要查 CPU、等待,還是 I/O

準備好之後,就看事件區間內的 CPU 是高還是低。高的話往第 5 章的 Sampled。低的話也先確認特定核心、執行緒有沒有滿載,如果也沒有,就用第 6 章的 Precise 追等待。懷疑是磁碟就往第 7 章。

從症狀選擇 WPA 圖表的分支縮放到事件區間,CPU 高就到 CPU Usage Sampled,低卻還是慢就先確認核心是否滿載再到 CPU Usage Precise 的等待分析,懷疑磁碟就到 Disk Usage 與 File IO高低卻還是慢有沒有懷疑是磁碟縮放到事件區間該區間的 CPU 如何?第 5 章:用 CPU Usage (Sampled) 看「誰在哪個函式吃掉 CPU」有沒有單核、單執行緒滿載?第 6 章:用 CPU Usage (Precise) 看「在等什麼」第 7 章:用 Disk Usage / File I/O 找出元兇

5. CPU 很高時 ── 用 CPU Usage (Sampled) 看「誰在哪個函式吃掉 CPU」

本章要找的,是用掉大部分 CPU 時間的呼叫路徑。

如果 CPU 被燒滿,要看的就是 CPU Usage (Sampled)。這是大約每 1 毫秒在所有 CPU 上記錄「現在正在執行的是哪個處理程序的哪個堆疊」的取樣資料,樣本數的比例就直接是 CPU 時間的組成。6

CPU Usage Sampled 的運作方式大約每 1 毫秒在所有 CPU 上記錄正在執行的堆疊,把樣本彙總後的比例就是 CPU 時間的組成。從處理程序往執行緒、堆疊、函式下鑽閱讀。在樣本之間就結束的短活動不會被拍到大約每 1 ms 一次的中斷在所有 CPU 上記錄「現在正在執行的堆疊」彙總樣本(比例=CPU 時間的組成)Process → Thread → Stack → 函式往下鑽在樣本之間就結束的短活動不會被拍到

從處理程序往堆疊、函式一路下鑽

  1. 從 Graph Explorer 的 Computation 把 CPU Usage (Sampled) 放到 Analysis 頁籤,選擇預設集 Utilization by Process, Stack。5
  2. 依 Weight(或 Count)由大到小看處理程序。工作管理員上那個「50%」的真面目,先在處理程序的層級弄清楚。
  3. 展開元兇處理程序的 Stack 欄。堆疊會以樹狀彙總,沿著分岔時數字不會大幅減少的那條路往下走,就會抵達正在吃掉 CPU 的函式。只要符號解析得出來,就能一路直達自家程式碼的哪個函式。
  4. 覺得展開樹狀很麻煩的話,就把圖表顯示切換成 Flame(火焰圖)。因為是以寬度=CPU 時間占比來繪製,所以哪條呼叫路徑占主導地位一目了然。CPU Usage (Sampled) 也備有 Flame by Process, Stack 這個預設集。13

Sampled 量不出單次的精確時間

既然是取樣,在樣本之間就結束的短活動就不會被拍到。6 請記住它是用來看「加總起來 CPU 用在哪裡」的工具,而不是量測單次精確執行時間的工具。

6. CPU 很低卻還是慢 ── CPU Usage (Precise) 與等待分析

6.1. 做等待分析之前,先確認有沒有單核滿載

「整體 CPU 使用率很低」並不代表「CPU 不是瓶頸」。 因為在 16 核的電腦上,釘在單一核心的序列處理(單一 UI 執行緒全力運轉的狀態),整體看起來也只有 6% 左右。

請先用第 5 章的 Sampled,或是 CPU Usage (Precise) 的 Utilization by CPU,確認有沒有特定核心、執行緒滿載。如果也沒有滿載,就可以認定處理不是用不到 CPU,而是在等某件事,接著進入等待分析。從這裡開始用的就是 CPU Usage (Precise)。

6.2. 把「等待的時間」與「醒來後等 CPU 的時間」分開

相對於 Sampled 是取樣,Precise 是內容切換(執行緒切換)的完整紀錄。執行緒進入等待、被某人叫醒(Ready)、再排上 CPU──這一趟來回都以一行一行留下來,可以讀出下列欄位。74

欄位 意義
NewThreadStack 該執行緒在哪個堆疊進入等待(=做了什麼而停下)
Waits (us) 等待的時間
Ready (us) 從被叫醒到排上 CPU 之間被迫等待的時間(CPU 的爭搶)
ReadyingProcess / ReadyingThreadId 叫醒(解除等待)該執行緒的處理程序與執行緒
ReadyThreadStack 叫醒的一方在哪個堆疊叫醒它
一次等待的來回與各欄位的對應執行緒以留在 NewThreadStack 的堆疊進入等待,等上 Waits 的時間。被某人叫醒後,ReadyingProcess 與 ReadyThreadStack 會留下那個對象,再等上 Ready 的時間爭搶 CPU 之後才重新執行進入等待(留在 NewThreadStack)有人叫醒它(ReadyingProcess / ReadyThreadStack)排上 CPU執行中等待(Waits (us))Ready(等待爭搶 CPU)重新執行

6.3. 從延遲的執行緒出發,逐一追出叫醒它的人

閱讀順序如下。4

1. 準備圖表與欄位

套用預設集 Utilization by Process, Thread,並在欄位加上 NewThreadStack 與 ReadyThreadStack。

2. 選出執行延遲操作的執行緒

首先要找出 UI 執行緒或處理目標請求的執行緒等,正在執行延遲操作的執行緒。若只依 Waits 合計由大到小看,訊息幫浦或計時器這類刻意持續等待的正常執行緒會排到前面。

若目標執行緒的 CPU Usage (ms) 很大,就是第 5 章的 CPU 問題;若 Waits 占主導,就是等待問題。

3. 用 NewThreadStack 看「做了什麼而停下」

展開 NewThreadStack。若是 WaitForSingleObject 或 EnterCriticalSection 就是鎖等待,若是在 ReadFile 這類同步 I/O 之中就是 I/O 等待,若是在通訊端接收之中就是在等對方回應。

4. 用 ReadyThreadStack 看「誰解除了等待」

展開 ReadyThreadStack,確認 ReadyingProcess / ReadyingThreadId。若是從核心的 KiTimerExpiration 被叫醒,就是計時器(睡到逾時為止);若是從 I/O 完成處理被叫醒,就佐證了它原本在等 I/O。4

5. 對叫醒它的一方,重複同樣的調查

如果叫醒它的是另一個執行緒或另一個處理程序,這次就用同樣的步驟調查那個執行緒。

例如A 在等 B 釋放鎖、B 在等 C 的 RPC 回應、C 在等磁碟 I/O,就是這樣一條鏈。把這條鏈追到根部,得到的就是延遲的關鍵路徑。7

等待分析要追的關鍵路徑之鏈從延遲的執行緒 A 的 NewThreadStack 看出它做了什麼而停下,再用 ReadyThreadStack 與 ReadyingProcess 找出叫醒它的對象 B,接著以同樣步驟調查 B,一路追到根部的磁碟 I/ONewThreadStack:因鎖等待而停下NewThreadStack:等 RPC 回應NewThreadStack:等同步 I/O完成後叫醒 C回應後叫醒 B釋放鎖後叫醒 A(會出現在 ReadyThreadStack)執行緒 A(延遲的操作)執行緒 B(持有鎖中)處理程序 C磁碟 I/O(根部)

把等待的原因接回設計的檢討

例如在「明明改成多執行緒卻沒變快」的案子裡,這套步驟會把所有工作者都排在同一把鎖上的樣子直接顯示出來。從設計上避開鎖競爭的討論寫在〈多執行緒的實務最佳實踐 .NET 篇〉,而不在同步 I/O 上等待、改以完成通知推動的 Windows 機制,則寫在〈I/O 完成埠(IOCP)與 .NET 執行緒集區〉。在 WPA 查出「它在等誰」,再用這些設計論點去修,是一連貫的流程。

7. 磁碟與檔案 I/O ── 找出「有人在猛掃磁碟」

「整台 PC 變慢」的經典元兇不是 CPU,而是磁碟。用 Storage 分類裡的 Disk Usage 與 File I/O 調查。15

7.1. 用 Disk Usage 分開「裝置的處理」與「排隊」

Disk Usage 是磁碟 I/O 的紀錄。一開始要先區分下面這兩個欄位。6

欄位 代表的時間
Disk Service Time 磁碟裝置實際花在處理該 I/O 上的時間
IO Time 從 I/O 進入 OS 的佇列到完成為止的時間

IO Time 一定會因為排隊的份量而大於等於 Service Time。若 IO Time 遠長於 Service Time,就知道該 I/O 是在佇列裡等待。6

不過請不要只憑時間差就斷定原因。到底是別的處理程序排起了隊伍,還是自己的大量 I/O 排在慢速裝置上,這時都還沒定論。要先用 Service Time 看裝置本身的回應,再用依處理程序、路徑、堆疊的細分來定案。

7.2. 哪個處理程序對哪個檔案發出 I/O

因此要用 Utilization by Process, Path Name, Stack 這個預設集,依 IO Time 或 Size 由大到小,看哪個處理程序、對哪個檔案、從哪個堆疊發出了 I/O。15 現場常見的答案是這兩種。

  • 防毒軟體正在掃過所有檔案。會看成在應用啟動變慢的時段裡,防毒軟體的處理程序發出大量讀取的樣子。處理程序名稱、路徑、數量的證據就這樣直接湊齊,可以作為討論排除設定的材料。
  • 別的處理程序正在大量寫入。備份、索引器、日誌寫太多等等。因為寫入何時會到達磁碟牽涉到快取管理員,所以連「寫下去的那一刻」與「磁碟忙碌的那一刻」會錯開這件事,都在〈快取管理員 ── 你的 WriteFile 究竟何時到達磁碟〉裡說明。

7.3. 用 File I/O 看還沒到磁碟就發生的慢

File I/O 是再上一層,也就是應用發出的檔案操作(Create/Read/Write 等)的紀錄,用 Duration by Process, Thread, Type 等預設集可以依檔名單位、操作單位彙總時間。15

在到達磁碟之前就被檔案系統或篩選驅動程式吃掉時間的情況不會出現在 Disk Usage,所以「Disk Usage 很平靜,File I/O 卻很慢」這種不一致本身就是線索。想從同步 I/O 與非同步 I/O 的機制開始了解的人,請看〈同步 I/O 與非同步 I/O ── OVERLAPPED 真正的意思〉。

File IO 與 Disk Usage 所看的層級差異應用的檔案操作經過檔案系統與篩選驅動程式,從 OS 的 IO 佇列送到磁碟裝置。File IO 記錄上層的操作,Disk Usage 記錄到達磁碟的 IO,而 IO Time 與 Disk Service Time 的差就是排隊的時間應用:ReadFile / WriteFile檔案系統、篩選驅動程式(File I/O 所看的層級)OS 的 I/O 佇列磁碟裝置(Disk Usage 所看的層級)在這裡吃掉時間就不會出現在 Disk UsageIO Time − Disk Service Time = 排隊的時間Disk Service Time = 裝置的處理時間

7.4. 懷疑記憶體不足時,也要確認實體記憶體

「會不會是記憶體不足在換頁」這條思路,在進到 WPA 之前就能用工作管理員與資源監視器做第一輪的初步判斷。

請不要只看認可的記憶體就否定記憶體不足。 即使認可量還有餘裕,仍可能出現實體記憶體吃緊而工作集被削減、硬錯誤持續發生的狀況。請一併確認可用的實體記憶體,以及資源監視器的「硬錯誤/秒」。讀法請參考〈Windows 的「記憶體使用量」代表什麼〉。

8. 開機與登入很慢 ── 開機追蹤的入門

「開機要花 3 分鐘」這一類,還沒來得及親手跑 wpr -start,問題就已經結束了。WPR 有開機追蹤,可以安排成讓 OS 在下次開機時自動開始記錄。3

先安排下次開機的記錄,重新啟動後再儲存

和第 3 章一樣先取得擷取的核准並決定 ETL 的處理方式,再在以系統管理員身分開啟的命令提示字元裡操作。

:: 1. 安排下次開機時自動記錄
wpr -boottrace -addboot GeneralProfile -filemode

:: 2. 重新啟動(重現開機的緩慢)

:: 3. 開機後停止記錄並儲存(安排也會一併解除)
mkdir C:\temp 2>nul
wpr -boottrace -stopboot C:\temp\boot.etl "開機要花 3 分鐘的事件"
開機追蹤的流程用 addboot 安排下次開機時自動記錄後重新啟動,OS 就會在開機時自動開始記錄。登入後用 stopboot 儲存,安排也會一併解除。要放棄時用 cancelboot 解除用 wpr -boottrace -addboot 安排重新啟動(重現開機的緩慢)開機時由 OS 自動開始記錄登入後用 -stopboot 儲存(安排也一併解除)要放棄就用 -cancelboot

擷取到之後,一樣回到「CPU、等待、I/O」的分流

以往由 xbootmgr 負責的開機與關機量測,在現行的 WPR 也可以用 -onoffscenario Boot 之類的選項執行。3

擷取到的追蹤,可以用前面各章相同的工具組來閱讀。在 Processes 圖上依時序看哪個處理程序何時誕生,再縮放到開機卡住的時段,分類出是 CPU、是等待,還是磁碟──啟動應用串在一起等某件事、服務的啟動卡在特定 I/O 之類的形狀就會浮現出來。

開機分析本身就是一門很深的專門領域,本文只走到「用手來不及擷取的事件,用 WPR 也採得到」這個入口。請先從 GeneralProfile 的開機追蹤掌握整體樣貌開始。

9. 實務的套路 ── 分類 → 縮放 → 堆疊,反覆進行

工具都清楚之後,來整理調查整體的套路。先釘住時刻縮小區間,分類之後再追堆疊的順序,在任何症狀下都相同。

從釘住時刻到驗證假設

  1. 釘住現象的時刻。不是「有變慢」,而是要定到「10:23:40~10:24:10 變慢」。應用日誌、事件記錄、操作者的筆記,什麼都行。若自家應用會把關鍵節點寫進 ETW 或事件記錄,追蹤裡的事件就直接成為時刻的錨點。
  2. 只縮放到那個區間。整份追蹤的彙總會被平均抹平,關鍵的異常會被稀釋。WPA 的分析永遠是「異常的區間」對「正常的區間」的比較。
  3. 一開始先分類「是 CPU、是等待,還是 I/O」。看 CPU Usage (Sampled),被燒滿就往第 5 章。沒被燒滿就看 CPU Usage (Precise) 的 Waits(第 6 章)。若 Disk Usage 的 IO Time 膨脹就往第 7 章。一開始先過這個三岔路口,就不會迷路。
  4. 反覆進行假設 → 縮放 → 堆疊。覺得「會不會是防毒軟體?」就縮到那個處理程序,用堆疊取得佐證。猜錯就換下一個假設。在鑽到堆疊取得佐證之前不下結論,是這類調查的紀律。
效能調查的反覆迴圈釘住現象的時刻並縮放到該區間,分類出是 CPU、是等待還是 IO,提出假設縮小範圍,再用堆疊取得佐證。佐證得到就確定原因,猜錯就換下一個假設重複佐證成立猜錯釘住現象的時刻縮放到該區間分類是 CPU、等待,還是 I/O提出假設並縮小範圍用堆疊取得佐證確定原因 → 進入對策

ETL 怎麼處理,要在擷取前就決定

ETL 檔裡廣泛映照出系統的內部:所有處理程序的名稱、開啟過的檔案路徑、載入的模組,以及(依設定檔而定)登錄的機碼名稱等。

GeneralProfile 的標準擷取不含通訊內容之類的資料本體,但若啟用了自訂提供者,該事件的承載(應用記錄的字串等)就會原樣進去。

請先確認啟用的提供者會發出什麼,再把它當成足夠機密的檔案來看待要不要帶出公司。和封包擷取一樣,請把只擷取必要的最小量、與交付對象的共識、保存期限與刪除納入作業程序。

ETL 檔裡映照出什麼,以及要怎麼處理ETL 裡映照出所有處理程序名稱、開啟過的檔案路徑、模組,以及依設定檔而定的登錄機碼名稱,啟用自訂提供者時連其承載也會進去。當成機密看待:只擷取必要的最小量、與對象的共識、保存期限與刪除ETL 檔所有處理程序名稱、檔案路徑、模組(依設定檔而定)登錄機碼名稱自訂提供者的承載(應用記錄的字串)當成機密看待:只擷取必要的最小量、與對象的共識、保存期限與刪除

10. 總結

WPR/WPA 的調查,分成下面三個階段來想就能理清。

  1. 擷取需要的區間。 用 Windows 8.1 起就內建的 wpr.exe 擷取,再用手邊的 WPA 閱讀 ETL。基本是 wpr -start GeneralProfile -filemode → 重現 → wpr -stop trace.etl。能重現就用 File 模式在幾分鐘以內解決,要守候就用 Memory 模式。開機過程中的慢就用 wpr -boottrace。並不是擷取得愈久愈好,而且 ETL 的內部資訊要當成機密看待。
  2. 縮小時段,選出調查方向。 在 WPA 裡,金色線的左邊是分組,藍色線的右邊是彙總值。掌握欄位的排列、區間的縮放、符號設定,再區分出是 CPU、是等待,還是 I/O。自家應用要準備 PDB,.NET 的 JIT 程式碼還要確認擷取當下的 CLR 事件。
  3. 追到堆疊,驗證假設。 CPU 高就用 Sampled 從處理程序往函式下鑽。即使整體 CPU 很低,也要先確認單核、單執行緒有沒有滿載,如果沒有再用 Precise 追等待。對磁碟不要只憑時間差就決定原因,要看到裝置的回應與 I/O 發出者的細分為止。

等待分析要追的,是 NewThreadStack(做了什麼而停下)→ Waits(等了多久)→ ReadyingProcess、ReadyThreadStack(誰叫醒它)。對叫醒它的一方也做同樣的調查,就能把延遲的鎖鏈追到根部。

WPA 一開始也許會讓人被畫面的資訊量壓倒。即使如此,只要掌握「欄位的排列就是彙總的切入角度」「Sampled 看的是用掉 CPU 的地方,Precise 看的是等待的對象」,剩下的就是釘住時刻、縮放、分類、確認堆疊的反覆。下次再接到「CPU 明明還有餘裕卻還是慢」的諮詢時,就照這個順序擷取追蹤並讀下去吧。

相關文章

相關諮詢領域

小村軟體有限公司承接「整台 PC 變慢但找不出原因」「CPU 還有餘裕應用卻很慢」「只有特定環境開機極端地慢」這類系統整體效能問題的調查。從 WPR/WPA 的擷取設計(在哪個環境、用哪個設定檔、擷取多少)到追蹤分析,再到造成問題的應用側、設定側的修正,都以一連貫的方式處理。

參考連結

  1. Microsoft Learn, Introduction to WPR. 關於 WPR 是以 ETW 為基礎的效能記錄工具、命令列版的 WPR.exe 從 Windows 8.1 起就隨 OS 提供而不必另外安裝、它與 GUI 版 WPRUI.exe 的關係,以及記錄設定檔的概念。 ↩ ↩2 ↩3

  2. Microsoft Learn, Windows Performance Analyzer. 關於 WPA 包含在 Windows ADK 裡,是從 WPR、Xperf 等記錄的 ETW 事件產生圖表與資料表格的分析工具,並且可以開啟任意 ETL 檔進行分析。 ↩ ↩2 ↩3 ↩4

  3. Microsoft Learn, WPR Command-Line Options. 關於 wpr -start/-stop/-cancel/-status/-profiles 的語法、-filemode(預設是記憶體模式)、同時指定多個設定檔、用 -boottrace 做開機追蹤(addboot/stopboot/cancelboot),以及用 -onoffscenario 記錄 Boot 等開關轉換。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  4. Microsoft Learn, CPU Analysis. 關於 CPU Usage (Precise) 圖表各欄位(NewThreadStack、ReadyThreadStack、ReadyingProcess、Waits 等)的定義、展開 ReadyThreadStack 並沿 ReadyingProcess/ReadyingThread 追到等待根本原因的步驟,以及怎麼辨別 KiTimerExpiration(計時器等待)或 I/O 完成造成的喚醒。 ↩ ↩2 ↩3 ↩4 ↩5

  5. Microsoft Learn, Troubleshoot processes and threads by using WPR and WPA. 關於高 CPU 使用率時以 Process→Stack 閱讀 CPU Usage (Sampled) 的組態、等待分析(Wait analysis)時使用 CPU Usage (Precise) 的 Readying Process、Readying Thread、Readying Stack 與 Wait 欄位的組態,以及依症狀對應設定檔與圖表的對照表。 ↩ ↩2

  6. Microsoft Learn, Exercise 2 - Evaluate Fast Startup Using Windows Performance Toolkit. 關於 CPU Usage (Sampled) 是大約 1 毫秒間隔的取樣而樣本之間的短活動不會被記錄、往處理程序 → 執行緒 → 堆疊下鑽以找出 CPU 消耗組成的步驟,以及 Disk Usage 的 IO Time(含佇列時間)與 Disk Service Time(磁碟的處理時間)的意義。 ↩ ↩2 ↩3 ↩4 ↩5

  7. Microsoft Learn, Exercise 3 - Understand Critical Path and Wait Analysis. 關於關鍵路徑分析的概念(Running、Ready、Waiting 的分類)、CPU Usage (Precise) 表格中 NewThreadStack、ReadyThreadStack、ReadyingProcess、Waits、Ready 等欄位的意義,以及依序追出叫醒方執行緒以釐清延遲鎖鏈的步驟。 ↩ ↩2 ↩3

  8. Microsoft Learn, Loading Symbols. 關於未設定 _NT_SYMBOL_PATH 時 WPA 會預設參照 Microsoft 公開符號伺服器(msdl.microsoft.com)、加上自家元件 PDB 路徑的做法,以及 WPR 會把 .NET 受控符號用的 PDB 產生到追蹤旁邊的 .ngenpdb 資料夾而 WPA 會自動參照。 ↩ ↩2 ↩3

  9. Microsoft Learn, Built-in Recording Profiles. 關於 WPR 內建記錄設定檔的清單(CPU usage、Disk I/O activity、File I/O activity、Registry I/O activity、Networking I/O activity 等)以及各設定檔記錄的內容。 ↩

  10. Microsoft Learn, Logging Mode. 關於記錄模式有 File(連續檔案)與 Memory(記憶體上的環形緩衝區)兩種且預設是 Memory、Memory 適合不知道何時發生的事件且較舊事件會被覆寫,以及 File 唯一的上限是磁碟可用空間、檔案太大時可能無法用 WPA 分析。 ↩ ↩2

  11. Microsoft Learn, WPR How-to Topics. 關於在 WPRUI 開始與停止記錄的步驟、設定檔與詳細程度與 Logging mode 的選擇,以及長時間記錄會讓檔案變得巨大而可能無法用 WPA 分析、因此應選 Memory 模式的注意事項。 ↩ ↩2

  12. Microsoft Learn, Graph Explorer. 關於 Graph Explorer 視窗會以 System Activity、Computation、Storage、Memory 等分類排出圖表縮圖,以及把圖表拖到 Analysis 頁籤與表格一起顯示。 ↩

  13. Microsoft Learn, Graphs (WPA Features). 關於 WPA 的 Flame(火焰圖)顯示、金色線左側欄位是分組而藍色線右側是彙總值的表格結構,以及 CPU Usage (Sampled) 的 Flame by Process, Stack 預設集。 ↩ ↩2

  14. Microsoft Learn, Load Symbols or Configure Symbol Paths. 關於從 WPA 的 Trace 選單用 Load Symbols 載入符號,以及在 Configure Symbol Paths 對話方塊設定與變更符號路徑的步驟。 ↩

  15. Microsoft Learn, List of WPA Graphs. WPA 可用圖表的清單。關於 Disk Usage 的 IO Time by Process, IO Type、Service Time by Process, Path Name, Stack、Utilization by Process, Path Name, Stack,以及 File I/O 的 Duration by Process, Thread, Type 等預設集。 ↩ ↩2 ↩3

共用相同標籤的最新文章。能以相近的主題延伸理解。

與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。

本文連結到以下服務頁面,歡迎從最接近的入口查看。

常見問題

整理諮詢這個主題時常見的問題。

WPR 和 WPA 要去哪裡拿?不能安裝軟體的客戶環境也能用嗎?
擷取工具 wpr.exe(命令列版)從 Windows 8.1 起就內建在 OS 裡,不必另外安裝就能使用。GUI 版的 WPRUI 與分析工具 WPA(Windows Performance Analyzer)包含在 Windows ADK(Windows Assessment and Deployment Kit)裡,這一邊需要另外安裝。實務上只要拆成「在客戶環境只用 OS 標準的 wpr.exe 擷取 ETL 檔,帶回來用手邊的 WPA 分析」,即使是不能加裝軟體的現場,也能做系統整體的效能調查。
工作管理員顯示 CPU 還有餘裕,為什麼還是慢?用 WPA 能看出什麼?
CPU 使用率很低卻還是慢,代表處理不是用不到 CPU,而是「在等某件事」而停住。鎖的爭搶、等同步 I/O 完成、等另一個處理程序回應,都是典型情況。工作管理員只顯示使用率這個結果,而 WPA 的 CPU Usage (Precise) 從每次內容切換的紀錄,指出執行緒在哪裡開始等(NewThreadStack)、等了多久(Waits)、以及被誰叫醒(ReadyingProcess、ReadyThreadStack)。把讓它等待的對象一個一個追下去,就能把「變慢的元兇」定位到函式層級。
追蹤要擷取多久?檔案會不會變得很巨大?
只要事件能重現,基本原則是在重現前一刻開始、重現完就立刻停止,控制在幾分鐘以內。WPR 的預設是記錄到記憶體上環形緩衝區的 Memory 模式,較舊的事件會被覆寫,適合守候不知道何時會發生的事件。加上 -filemode 的 File 模式會把全部內容留在連續的檔案裡,代價是上限只有磁碟可用空間,檔案太大時可能就無法用 WPA 分析。長時間守候用 Memory 模式,短時間且能確實重現用 File 模式,請這樣分開使用。
PerfView 和 WPA 要怎麼分開使用?
兩者都是處理 ETW 追蹤的工具,但擅長的領域不同。PerfView 對 .NET 執行階段理解得很深,擅長 GC、配置、JIT 這類受控應用特有的調查。WPA 則適合用圖表與表格橫跨地閱讀整個 OS 的 CPU、磁碟、檔案 I/O、電源等,是「不是特定應用而是整台 PC 變慢」「牽涉到多個處理程序」「懷疑問題出在應用之外(防毒軟體、驅動程式、其他處理程序)」時的首選。自家 .NET 應用單獨變慢用 PerfView、整個系統變慢用 WPR/WPA,是大致的判斷標準。
在客戶的正式環境跑 WPR 沒問題嗎?
短時間的擷取在實務上很常見,但並不是無條件安全。ETW 雖然輕量,但要記錄大量附帶堆疊的事件,仍會消耗一定的 CPU 與記憶體。請把「在重現操作前一刻開始、重現完立刻停止」「擷取控制在幾分鐘以內」「挑對業務影響小的時段執行」這些考量,納入和一般變更作業相同的核准流程。另外,ETL 檔含有處理程序名稱、檔案路徑、可執行檔資訊等系統的內部資訊,因此帶出公司時要怎麼處理(最小化、保存期限、刪除)也應該事先決定好。

作者檔案

本文作者的個人檔案頁面。

Go Komura

小村軟體有限公司 代表

以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。

回到部落格一覽