練習 3 - 了解關鍵路徑及等候分析
案例和活動可能會意外延遲。 例如,在 Microsoft Edge 中開啟索引標籤有時可能需要比預期更長的時間。
活動定義為一系列作業,一些循序和一些平行,從開始事件流向結束事件。 追蹤中的任何開始/結束事件組都可以視為活動。 此系列作業的最長路徑稱為關鍵路徑。 減少關鍵路徑上任何作業的持續時間,會直接減少整體活動的持續時間。
建議您識別完成活動的處理常式和執行緒,並從活動完成的時間回溯工作。 首先,分析完成活動的執行緒,以判斷該執行緒花費大部分的時間,以及處於何種狀態: 執行、 就緒或 等候。
重大運行時程表示直接 CPU 使用量可能會造成重大路徑的持續時間。 處於 就緒 狀態所花費的時程表示其他執行緒會藉由防止重要路徑上的執行緒執行,來參與重大路徑的持續時間。 等候點到 I/O、計時器或其他執行緒和進程所花費的時間,位於目前線程正在等候的重要路徑上。
讀取目前線程的每個執行緒可能是重要路徑的另一個連結,也可以進行分析,直到重要路徑的持續時間考慮為止。
所有必要資訊都會記錄在WPA中的CPU 使用量 (精確) 圖形和資料表中。 發送器所記錄的 CPU 使用量事件會與內容切換相關聯。 下表著重于 NewThread ,這是已切換的執行緒,而每個資料列都代表內容切換。 系統會針對下列事件順序收集資料:
NewThread 因為封鎖函式呼叫而切換掉。
NewThread 已準備好由就緒執行緒執行。
NewThread 會在 中切換,因此會切換出舊的執行緒。
NewThread 會再次切換出來。
以下是 CPU 使用量 (精確) 資料表中的有趣資料行。
資料行 | 詳細資料 |
---|---|
% CPU 使用量 | 切換新執行緒後的 CPU 使用量。 此值會以目前可見時段內 CPU 總時間的百分比表示。 |
Count | 資料列所代表的內容參數數目。 這一律為個別資料列的 1。 |
CPU 使用量 (ms) | 內容切換之後新執行緒的 CPU 使用量。 |
NewProcess | 新執行緒的進程。 |
NewThreadId | 新執行緒的執行緒識別碼。 |
NewThreadStack | 當新執行緒切換時,新執行緒的堆疊。 通常表示執行緒遭到封鎖或等候的內容。 |
就緒 () | 執行緒在就緒佇列中花費的時間, (因為先占或 CPU 耗盡而) 。 |
ReadyingThreadId | 就緒執行緒的執行緒識別碼。 |
ReadyingProcess | 擁有就緒執行緒的進程。 |
ReadyThreadStack | 就緒執行緒的堆疊。 |
ReadyTime (s) | 新執行緒整備的時間。 |
SwitchInTime (s) | 切換新執行緒的時間。 |
等候 () | 執行緒在邏輯或實體資源上等候的時間量。 當 ReadyingThreadId向NewThreadId發出訊號時,等候就會結束。 |
步驟 1:擷取並開啟 UI 延遲問題的追蹤
此練習將著重于具有無回應 UI 的虛擬程式。 此程式是具有按鈕和文字方塊的簡單 Windows Form 應用程式。 按一下按鈕時,UI 會變成沒有回應 20 秒,直到文字方塊更新為止。 您將分析此作業的重要路徑。
從這裡下載UIDelay.exe。
啟動 UIDelay.exe。
從 [開始] 功能表開啟WPR。
修改追蹤組態。
選取 [第一層分級 ] 和 [CPU 使用量]。
選取 [一般 ] 作為效能案例。
選取 [詳細資訊 ] 作為詳細資料層級。
按一下 [ 開始]。
在 UIDelay.exe中,按一下 [ 按一下] 按鈕。
- 等到文字方塊顯示 「Done!」
在WPR中,儲存追蹤,並使用WPA加以開啟。
開啟 [追蹤 ] 功能表,然後選取 [ 設定符號路徑]。
- 指定符號快取的路徑。 如需符號的詳細資訊,請參閱 MSDN 上的 [符號支援 ] 頁面。
開啟 [追蹤 ] 功能表,然後選取 [ 載入符號]。
步驟 2:識別延遲的 UI 執行緒
在執行關鍵路徑分析之前,您必須先識別活動啟動和停止事件。
在圖形總管的[系統活動] 節點中尋找UI 延遲圖表。
拖放 [分析] 索引標籤中的 [UI 延遲 ] 圖表。
尋找 UIDelay.exe 程式。
其持續時間應該大約是 20 秒。 這表示 UI 執行緒上的延遲為 20 秒 ,UIDelay.exe。
UI 執行緒識別碼會顯示在 [ 執行緒識別碼 ] 資料行中。 在此範例中,它是 24174。 此值將會在您在電腦上擷取的追蹤中有所不同。 請務必記下執行緒識別碼。
選取整個 UIDelay.exe 時間間隔,以滑鼠右鍵按一下並放大。
您應該一律放大您嘗試分析的區域。 它可減少不相關活動引入的雜訊量。
步驟 3:分析 UI 延遲關鍵路徑
既然您已擁有線程識別碼和時間戳記的分析起點,您可以開始深入活動關鍵路徑,以瞭解導致 UI 執行緒延遲 20 秒的事件序列。
此步驟的 NewThreadId 是您在步驟 2 (執行緒 24174 中所識別的執行緒 ,UIDelay.exe 進程) 。
將 CPU 使用量 (精確) 圖形新增至 分析 索引標籤,並套用 [ 依進程、執行緒預設的使用率 ]。
以滑鼠右鍵按一下資料行標頭,並讓 NewThreadStack、 ReadyThreadStack和 CPU 使用量 (ms) 資料行可見。
移除 [就緒 () [Max] 和 [ 等候 () [Max] 資料行。 您的檢視區現在看起來應該像這樣。
在NewProcess資料行中尋找並展開UIDelay.exe程式,然後按一下資料行標頭,依 [Waits (us) [Sum]排序。
在UIDelay.exe程式中搜尋NewThreadId,並分析其花費在 [執行中]、[就緒] 或 [等候] 狀態的時間。
在下列範例中,您可以找到:
執行緒耗用 10.025 秒的 CPU 時間。
執行緒正在等候 5.159 秒。
執行緒處於就緒狀態, (10 毫秒) 的時間。
注意 您可以使用練習 2 中說明的相同方法分析 10 秒的 CPU 活動,使用 CPU 使用量 (取樣) 圖表,並查看 UIDelay.exe 程式。
若要探索 NewThreadId 正在等候的內容,請展開 NewThreadId 群組以顯示 NewThreadStack。
展開 [Root] 並識別導致等候的函式呼叫。
在此範例中, 當 觸發按鈕按一下函式時,UIDelay.exe執行緒識別碼 24174 正在等候基礎封鎖函式呼叫 5.073 秒:
5.021 秒是因為 ExecuteWMICall 函式底下的作業所造成。
35 毫秒是因為 PingServer 函式下方的作業所造成。
步驟 3.1:查看 ExecuteWMICall 程式碼路徑
如果您在 ExecuteWMICall底下進一步擴充呼叫堆疊,您會發現 UI 執行緒實際上會藉由明確呼叫 Thread.Sleep來睡眠 5 秒。
這種行為應該以所有成本避免,因為它直接影響回應性。 如果程式碼需要等候資訊,它應該以非同步方式在個別執行緒上執行,並使用事件驅動方法。
步驟 3.2:查看 PingServer 程式碼
如果您在 PingServer底下進一步擴充呼叫堆疊,您會發現 UI 執行緒具有 I/O 相依性,因為它透過網路傳送 Ping 命令。
雖然延遲非常小, (35 毫秒) ,但應該避免在 UI 執行緒上。 請記住,平均人員會注意到任何大於 100 毫秒的 UI 延遲。 這項作業可能會增加超過 100 毫秒的總啟用時間,導致使用者對回應性有不良的認知。
這些作業應該以非同步方式在個別執行緒上發生,而不是封鎖 UI。