9.4 VSTS 效能分析工具程序員
啊,效能分析,Performance!這是每個程序員都夢想的事兒,讓本身的程序跑得又快又好,最好是比別的同窗快一個數量級,別人的程序是O(N^2),而個人程序是O(n*logN),或者是O(N),這是多爽的一項成就呀!VSTS提供了方便的效能分析工具,讓咱們能很快地找到程序的效能瓶頸,從而能有的放矢,改進程序。下面咱們看一個具體的例子。瀏覽器
和同窗們的做業相似,有這樣一道題:app
寫一個程序,分析一個文本文件中各個詞出現的頻率,而且把頻率最高的10個詞打印出來。框架
果凍很快用C#寫好了程序,命名爲WordFreq.exe,而後運行了一下,驗證了正確性,程序的基本框架如代碼清單9-3所示(所有程序能夠在移山社區網站下載):ide
代碼清單9-3 WordFreq程序,程序框架函數
DoIt() { ProcessFile() //store all words in a big buffer ProcessBuffer() //calculate and store the frequency of each word OutputResult() //output top 10 } ProcessBuffer() { GetOneWord() //get one word from buffer FreqOneWord() } FreqOneWord(word) { Find the word in the array list, If (found) Update the frequency If (not found) Add the word in the array list with frequency = 1 } OutputResult() { ArrayList.Sort() //sort the array Output Top 10 entry; }
文本文件大約是30KB~300KB大小。在運行效能分析以前,阿超讓你們預計佔用時間最多的是什麼函數,或者哪些語句。你們衆說紛紜,有的說是處理文件,由於I/O很花時間,有的說是排序,有的說是處理每一個詞。還有人建議應該把排序和處理每個詞同時進行,這樣就能加快速度。工具
咱們看看到底會是什麼狀況。第一步,要確保編譯的程序是Release版本。而後在VS界面中選中Tools | Performance Tools | Performance Wizard(如圖9-1所示)。測試
圖9-1 效能分析,選擇分析方法網站
咱們看到能夠選擇兩種分析方法:spa
(1) 抽樣(Sampling)
(2) 代碼注入(Instrumentation)
通俗地解釋,抽樣就是當程序運行時,Visual Studio時不時看一看這個程序運行在哪個函數內,並記錄下來,程序結束後,Visual Studio就會得出一個關於程序運行時間分佈的大體的印象。這種方法的優勢是不須要改動程序,運行較快,能夠很快地找到瓶頸。可是不能得出精確的數據,代碼中的調用關係(CallTree)也不能準確表示。
另外一方面,代碼注入就是將檢測的代碼加入到每個函數中,這樣程序的一舉一動都被記錄在案,程序的各個效能數據均可以被精準地測量。這一方法的缺點是程序的運行時間會大大加長,還會產生很大的數據文件,數據分析的時間也相應增長。同時,注入的代碼也影響了程序真實的運行狀況(這有點像量子物理學中的「測試的光線干擾了測試物體自己」的現象)。
咱們通常的作法是,先用抽樣的方法找到效能瓶頸所在,而後對特定的模塊用代碼注入的方法進行詳細分析。
對程序進行效能分析,咱們先要弄清下面這幾個名詞,如表9-1所示:
表9-1 效能分析的名詞解釋
名 詞 |
含 義 |
調用者Caller |
函數Foo()中調用了Bar(),Foo()就是調用者 |
被調用函數Callee |
見上,Bar()就是被調用函數 |
調用關係樹Call Tree |
從程序的Main()函數開始,調用者和被調用函數就造成了一個樹形關係——調用樹 |
消逝時間Elapsed Time |
從用戶的角度來看程序運行所花的時間。當用戶看到一個程序沒有反應,用戶並不知道程序此時是在運行本身的代碼,仍是被調度出去了,或者操做系統此時正在忙別的事情 |
應用程序時間Application Time |
應用程序佔用CPU的時間,不包括CPU在覈心態時花費的時間 |
續表
名 詞 |
含 義 |
本函數時間Exclusive Time |
全部在本函數花費的時間,不包括被調用者使用的時間 |
全部時間Inclusive Time |
包含本函數和全部調用者使用的時間 |
理解了上面的各類概念後,咱們就不難理解「消逝的本函數時間(Elapsed Exclusive Time)」等其餘組合名詞所表明的概念了。
咱們先進行抽樣分析,在效能瀏覽器(Performance Explorer)中開始效能分析便可。
圖9-2是WordFreq程序處理一個30KB的文本文件時的狀況:
圖9-2 用抽樣的方法分析效能
你們能夠看到最花時間的三個函數是:
WordFreq.Freq.FreqOneWord(string)
System.String.EqualsHelper(string,string)
System.Collections.ArrayList.get_Item(int32)
三個函數加起來佔用了整個程序84%的時間。看來咱們得分析爲何這三個函數會被調用得這麼頻繁,開銷這麼大了。
我們如今能夠進行代碼注入的分析,一樣運行程序後,咱們看看圖9-3的調用樹(Call Tree)報告。
圖9-3 代碼注入方法產生的效能報告
結合實際的代碼(見代碼清單9-4),能夠看到在WordFreq. FreqOneWord函數中,究竟發生了什麼:
代碼清單9-4 FreqOneWord()
private void FreqOneWord(string w) { // see if we have a match, if not, add it to the end, // then assign it initial frequency 1; // if yes, inc the frequency by 1 for (int i = 0; i < m_wordList.Count; i++) { Frequency fi = (Frequency)m_wordList[i]; if (fi.str == w) { fi.n++; return; } } //now we have to append it to the end. Frequency f = new Frequency(); f.str = w; f.n = 1; m_wordList.Add(f); }