1. 程式人生 > >使用PrefView監測.NET程式效能(二):Perfview的使用

使用PrefView監測.NET程式效能(二):Perfview的使用

上一篇部落格中,我們瞭解了對Windows及應用程式進行效能分析的基礎:Event Trace for Windows (ETW)。現在來看看基於ETW的效能分析工具——Perfview.exe

Perfview簡介

Perfview是一個開源的CPU和記憶體效能分析工具,也包括一些針對.NET的分析功能,例如GC分析,JIT分析,甚至ASP.NET中的請求統計等等。Perfview是一個Windows應用程式,但也能對在Linux系統上採集的資料進行分析(參考)。Perfview免安裝,而且只是一個14M的.exe檔案,非常容易部署到需要進行效能分析的機器上,例如生產環境的伺服器。而且在效能資料收集的過程中不需要重啟應用程式或者伺服器,而且收集的效能資料日誌(.etl檔案)可以被拷貝到其他Windows機器上,再進行分析工作,對業務的影響非常少。

Perfview已遷移到GitHub上,可以在上面下載Perfview.exe,clone庫或者檢視相關資料。

Perfview GitHub:https://github.com/Microsoft/perfview

Perfview視訊教程:https://channel9.msdn.com/Series/PerfView-Tutorial

Vance Morrison關於Perfview的部落格:https://blogs.msdn.microsoft.com/vancem/tag/perfview/

 

 Perfview使用

在簡單介紹Perfview後,我們來使用Perfview進行一個小小的效能分析,來熟悉一下Perfivew的基本操作。

這個實驗使用的程式碼,就是Vance Morrison在視訊教程中用到的Console程式。程式碼可以在Perfivew自帶的幫助檔案中找到。

 using System;
    // using System.Collections.Generic;

    class Program
    {
        public static int aStatic = 0;
        // Spin is a simple compute bound program that lasts for 5 seconds
        // It is a useful test program for CPU profilers.  
static int Main(string[] args) { int numSec = 5; if (args.Length == 1) numSec = int.Parse(args[0]); Console.WriteLine("Spinning for {0} seconds", numSec); RecSpin(numSec); return 0; } // Spin for 'timeSec' seconds. We do only 1 second in this // method, doing the rest in the helper. static void RecSpin(int timeSec) { if (timeSec <= 0) return; --timeSec; SpinForASecond(); RecSpinHelper(timeSec); } // RecSpinHelper is a clone of RecSpin. It is repeated // to simulate mutual recursion (more interesting example) static void RecSpinHelper(int timeSec) { if (timeSec <= 0) return; --timeSec; SpinForASecond(); RecSpin(timeSec); } // SpingForASecond repeatedly calls DateTime.Now until for // 1 second. It also does some work of its own in this // methods so we get some exclusive time to look at. static void SpinForASecond() { DateTime start = DateTime.Now; for (; ; ) { if ((DateTime.Now - start).TotalSeconds > 1) break; // Do some work in this routine as well. for (int i = 0; i < 10; i++) aStatic += i; } } }

 

 以上程式碼很簡單,SpinForASecond()在一秒內不斷呼叫DateTIme.Now,而RecSpin()和RecSpinHelper()則不斷地相互呼叫對方。這裡使用迴圈的目的是,迴圈執行是一種典型的CPU密集型操作,而RecSpin()和RecSpinHelper()則是為了豐富程式的函式呼叫棧。

 

步驟一:收集程式執行資料,生成由ETW資料組成的.etl檔案。

Perfview提供兩種收集資料的方式,Run和Collect。“Run”是直接指定需要啟動的應用程式的名稱,以便啟動該程式。“Collect”則是直接啟動Perfview並開始收集。但不要以為"Run"方式只收集指定程式的資料。事實上無論哪種方式,Perfview都會收集系統範圍內全部資料,並且收集完成後,需要選擇某一個程序以進行分析。

我們以“Run”方式來收集以上程式碼生成的Tutorial.exe程式。

在彈出的對話方塊中,填入需要啟動Tutorial.exe的全檔名,以及填入生成etl檔案的檔名(這裡是PerfViewData.etl),並點選“Run Command”:

Perfview收集和處理資料的時間比較長。在處理過程中,Perfview的右下角會閃動,並且可以檢視執行日誌,瞭解到當前Perfview在執行什麼工作。

 

步驟二:選擇需要分析的程序

在收集完畢後,在左邊選擇“PerfViewData.etl.zip”,並在展開的選擇項中雙擊選擇“CPU Stacks”,此時,會彈出程序選擇對話方塊,選擇需要進行CPU分析的程序。這裡選擇我們執行的Tutorial.exe程序。

 

 

步驟三:檢視執行棧檢視

在雙擊選擇了“Tutorial.exe”的程序後,進入到程式詳細的執行棧的檢視中。這裡記錄著Tutorial.exe的函式呼叫樹,以及函式的執行時間。

在該檢視中,你可以看到Tutorial.exe的函式呼叫情況,包括函式呼叫樹(Call-Tree),某個函式的呼叫者(Calls)和被該函式呼叫的函式(Callees),另外,在檢視右側,是函式的執行時間,其中,“Exc”是指 Exclusive,是指函式自己(不包含該函式裡執行的子函式)的執行時間,而“Inc”是指Inclusive,指該函式及該函式中執行的子函式的總的執行時間。

另外,這個執行時間是怎麼認定的呢? 答案是CPU取樣。Perfview對CPU進行取樣,預設每個CPU取樣是1毫秒(在Prefview的高階設定中可以設定到0.125毫秒~1毫秒),每次取樣中可以得到當前CPU正則執行什麼程式碼。例如DateTime_getNow()有3250取樣,則可以說明在整個程式執行中,DateTime_getNow()佔用了3250毫秒的CPU時間,佔整個執行時間的66.2%。通過比較各個函式的執行時間,我們就可以知道程式中哪個函式佔用比較多的CPU時間。

 以上便是Prefview的基本的使用步驟。Prefview提供了非常多並強大的功能,例如分組(Grouping),摺疊(Folding),時間範圍選擇,這些在後續教程裡再聊。而更強大的是,F1幫助手冊裡,有著非常詳細的使用說明和術語解析,而且介面上幾乎每個功能都有說明的ToolTip和說明的超連結如果對某個功能用法不是很清楚,可以方便地找到說明,真是業界良心。

參考資料

How many samples are enough when using a sample based profiler in a performance Investigation

The TraceEvent Library Programmers Guide