在上一篇博客中,咱們瞭解了對Windows及應用程序進行性能分析的基礎:Event Trace for Windows (ETW)。如今來看看基於ETW的性能分析工具——Perfview.exehtml
Perfview是一個開源的CPU和內存性能分析工具,也包括一些針對.NET的分析功能,例如GC分析,JIT分析,甚至ASP.NET中的請求統計等等。Perfview是一個Windows應用程序,但也能對在Linux系統上採集的數據進行分析(參考)。Perfview免安裝,並且只是一個14M的.exe文件,很是容易部署到須要進行性能分析的機器上,例如生產環境的服務器。並且在性能數據收集的過程當中不須要重啓應用程序或者服務器,並且收集的性能數據日誌(.etl文件)能夠被拷貝到其餘Windows機器上,再進行分析工做,對業務的影響很是少。linux
Perfview已遷移到GitHub上,能夠在上面下載Perfview.exe,clone庫或者查看相關資料。git
Perfview GitHub:https://github.com/Microsoft/perfviewgithub
Perfview視頻教程:https://channel9.msdn.com/Series/PerfView-Tutorial服務器
Vance Morrison關於Perfview的博客:https://blogs.msdn.microsoft.com/vancem/tag/perfview/ide
在簡單介紹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()則是爲了豐富程序的函數調用棧。性能
Perfview提供兩種收集數據的方式,Run和Collect。「Run」是直接指定須要啓動的應用程序的名稱,以便啓動該程序。「Collect」則是直接啓動Perfview並開始收集。但不要覺得"Run"方式只收集指定程序的數據。事實上不管哪一種方式,Perfview都會收集系統範圍內所有數據,而且收集完成後,須要選擇某一個進程以進行分析。ui
咱們以「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
使用PerfView監測.NET程序性能(一):Event Trace for Windows