现代软件工程讲义 2 开发技术 - 效能分析
[移山之道 第九章]
9.4? VSTS 效能分析工具
啊,效能分析,Performance!這是每一個(gè)程序員都?jí)粝氲氖聝?#xff0c;讓自己的程序跑得又快又好,最好是比別的同學(xué)快一個(gè)數(shù)量級(jí),別人的程序是O(N^2),而我的程序是O(n*logN),或者是O(N),這是多爽的一項(xiàng)成就呀!VSTS提供了方便的效能分析工具,讓我們能很快地找到程序的效能瓶頸,從而能有的放矢,改進(jìn)程序。下面我們看一個(gè)具體的例子。
和同學(xué)們的作業(yè)類似,有這樣一道題:
寫一個(gè)程序,分析一個(gè)文本文件中各個(gè)詞出現(xiàn)的頻率,并且把頻率最高的10個(gè)詞打印出來(lái)。
?
果凍很快用C#寫好了程序,命名為WordFreq.exe,然后運(yùn)行了一下,驗(yàn)證了正確性,程序的基本框架如代碼清單9-3所示(全部程序可以在移山社區(qū)網(wǎng)站下載):
代碼清單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大小。在運(yùn)行效能分析之前,阿超讓大家預(yù)計(jì)占用時(shí)間最多的是什么函數(shù),或者哪些語(yǔ)句。大家眾說(shuō)紛紜,有的說(shuō)是處理文件,因?yàn)?/span>I/O很花時(shí)間,有的說(shuō)是排序,有的說(shuō)是處理每個(gè)詞。還有人建議應(yīng)該把排序和處理每一個(gè)詞同時(shí)進(jìn)行,這樣就能加快速度。
我們看看到底會(huì)是什么情況。第一步,要確保編譯的程序是Release版本。然后在VS界面中選中Tools | Performance Tools | Performance Wizard(如圖9-1所示)。
圖9-1? 效能分析,選擇分析方法
我們看到可以選擇兩種分析方法:
(1)??????? 抽樣(Sampling)
(2)??????? 代碼注入(Instrumentation)
通俗地解釋,抽樣就是當(dāng)程序運(yùn)行時(shí),Visual Studio時(shí)不時(shí)看一看這個(gè)程序運(yùn)行在哪一個(gè)函數(shù)內(nèi),并記錄下來(lái),程序結(jié)束后,Visual Studio就會(huì)得出一個(gè)關(guān)于程序運(yùn)行時(shí)間分布的大致的印象。這種方法的優(yōu)點(diǎn)是不需要改動(dòng)程序,運(yùn)行較快,可以很快地找到瓶頸。但是不能得出精確的數(shù)據(jù),代碼中的調(diào)用關(guān)系(CallTree)也不能準(zhǔn)確表示。
另一方面,代碼注入就是將檢測(cè)的代碼加入到每一個(gè)函數(shù)中,這樣程序的一舉一動(dòng)都被記錄在案,程序的各個(gè)效能數(shù)據(jù)都可以被精準(zhǔn)地測(cè)量。這一方法的缺點(diǎn)是程序的運(yùn)行時(shí)間會(huì)大大加長(zhǎng),還會(huì)產(chǎn)生很大的數(shù)據(jù)文件,數(shù)據(jù)分析的時(shí)間也相應(yīng)增加。同時(shí),注入的代碼也影響了程序真實(shí)的運(yùn)行情況(這有點(diǎn)像量子物理學(xué)中的“測(cè)試的光線干擾了測(cè)試物體本身”的現(xiàn)象)。
我們一般的做法是,先用抽樣的方法找到效能瓶頸所在,然后對(duì)特定的模塊用代碼注入的方法進(jìn)行詳細(xì)分析。
對(duì)程序進(jìn)行效能分析,我們先要弄清下面這幾個(gè)名詞,如表9-1所示:
表9-1? 效能分析的名詞解釋
| 名? 詞 | 含? 義 |
| 調(diào)用者Caller | 函數(shù)Foo()中調(diào)用了Bar(),Foo()就是調(diào)用者 |
| 被調(diào)用函數(shù)Callee | 見(jiàn)上,Bar()就是被調(diào)用函數(shù) |
| 調(diào)用關(guān)系樹(shù)Call Tree | 從程序的Main()函數(shù)開(kāi)始,調(diào)用者和被調(diào)用函數(shù)就形成了一個(gè)樹(shù)形關(guān)系——調(diào)用樹(shù) |
| 消逝時(shí)間Elapsed Time | 從用戶的角度來(lái)看程序運(yùn)行所花的時(shí)間。當(dāng)用戶看到一個(gè)程序沒(méi)有反應(yīng),用戶并不知道程序此時(shí)是在運(yùn)行自己的代碼,還是被調(diào)度出去了,或者操作系統(tǒng)此時(shí)正在忙別的事情 |
| 應(yīng)用程序時(shí)間Application Time | 應(yīng)用程序占用CPU的時(shí)間,不包括CPU在核心態(tài)時(shí)花費(fèi)的時(shí)間 |
?
續(xù)表
| 名? 詞 | 含? 義 |
| 本函數(shù)時(shí)間Exclusive Time | 所有在本函數(shù)花費(fèi)的時(shí)間,不包括被調(diào)用者使用的時(shí)間 |
| 所有時(shí)間Inclusive Time | 包含本函數(shù)和所有調(diào)用者使用的時(shí)間 |
理解了上面的各種概念后,我們就不難理解“消逝的本函數(shù)時(shí)間(Elapsed Exclusive Time)”等其他組合名詞所代表的概念了。
我們先進(jìn)行抽樣分析,在效能瀏覽器(Performance Explorer)中開(kāi)始效能分析即可。
圖9-2是WordFreq程序處理一個(gè)30KB的文本文件時(shí)的情況:
圖9-2? 用抽樣的方法分析效能
大家可以看到最花時(shí)間的三個(gè)函數(shù)是:
WordFreq.Freq.FreqOneWord(string)
System.String.EqualsHelper(string,string)
System.Collections.ArrayList.get_Item(int32)
三個(gè)函數(shù)加起來(lái)占用了整個(gè)程序84%的時(shí)間。看來(lái)我們得分析為什么這三個(gè)函數(shù)會(huì)被調(diào)用得這么頻繁,開(kāi)銷這么大了。
我們現(xiàn)在可以進(jìn)行代碼注入的分析,同樣運(yùn)行程序后,我們看看圖9-3的調(diào)用樹(shù)(Call Tree)報(bào)告。
圖9-3? 代碼注入方法產(chǎn)生的效能報(bào)告
?
結(jié)合實(shí)際的代碼(見(jiàn)代碼清單9-4),可以看到在WordFreq. FreqOneWord函數(shù)中,究竟發(fā)生了什么:
代碼清單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);
??????? }
我們可以清楚地看到:
WordFreq.Freq.FreqOneWord(string)被調(diào)用了8 150次,說(shuō)明有8 150個(gè)詞被處理了。但是,System.Collections.ArrayList.Add(object)被調(diào)用了1 112次,說(shuō)明有1 112個(gè)不同的詞被加入到ArrayList中。下面三個(gè)函數(shù)被調(diào)用的次數(shù)相似,它們都花了很多的時(shí)間。
System.Collections.ArrayList.get_Count()
System.Collections.ArrayList.get_Item(int32)
System.String.op_Equality(string,string)
?
果凍:(大叫起來(lái))當(dāng)我寫這一個(gè)語(yǔ)句的時(shí)候
????? for (int i = 0; i < m_wordList.Count; i++)
沒(méi)想到m_wordList.Count,也就是ArrayList.GetCount(),會(huì)花這么多時(shí)間,累計(jì)被調(diào)用了1631884次!
我可以馬上把代碼改成:
??????????? int count = m_wordList.Count;
for (int i = 0; i < count; i++)
這樣會(huì)如何?大家等了一會(huì)兒,代碼分析的結(jié)果出來(lái)了(如圖9-4所示):
圖9-4? 改進(jìn)過(guò)的程序效能分析圖
可以看到System.Collections.ArrayList.get_Count()的調(diào)用次數(shù)和時(shí)間都大幅度地下降了。
我們可以繼續(xù)進(jìn)行“效能測(cè)試,分析,改進(jìn),再效能測(cè)試”的流程,逐漸提高程序的效能和我們的編程水平。
大家也要注意避免沒(méi)有做分析就過(guò)早地進(jìn)行“效能提高”,剛才有人提到我們可能要提高排序的性能,但是從圖9-4來(lái)看,System.Collections. ArrayList.Sort()只占了FreqOneWord()不到1/50的時(shí)間,如果我們不經(jīng)分析就盲目?jī)?yōu)化,也許會(huì)事倍功半。
9.5? 本章討論
果凍:噫吁唏,危乎高哉!我以前一直害怕做效能分析,看來(lái)是否會(huì)用效能分析工具來(lái)提高程序質(zhì)量是一個(gè)優(yōu)秀程序員的標(biāo)志之一。我在今天之前都是盲人騎瞎馬。
小飛:改成盲人摸象更恰當(dāng)。我聽(tīng)說(shuō),如果一個(gè)程序員從來(lái)沒(méi)有用過(guò)效能分析工具,那他就不是一個(gè)程序員,只是一個(gè)編程愛(ài)好者罷了。
我的WC 程序事實(shí)上是最快的。但是在今天的程序評(píng)比之前,我想更進(jìn)一步,就再優(yōu)化了一下,估計(jì)能把速度提高2%。沒(méi)想到出了一個(gè)小錯(cuò)誤,導(dǎo)致報(bào)告的結(jié)果(行數(shù)、詞數(shù)、字?jǐn)?shù))僅僅差了1。由于程序不正確,因此不能參加速度評(píng)比。我才是最需要大喊“噫吁唏”的人。
阿超:這有兩個(gè)教訓(xùn):
(1)先保證正確性,再提高效能。一個(gè)“僅僅差了1”的錯(cuò)誤可能會(huì)導(dǎo)致緩沖區(qū)溢出(Buffer Overflow)的嚴(yán)重漏洞。
(2)如果效能的提高效果在5%以下,用戶不會(huì)注意到程序效能的區(qū)別。所以要考慮那些微小的提高是否值得。
另外,WordFreq算法的時(shí)間復(fù)雜度是多少,能否再優(yōu)化?請(qǐng)寫實(shí)際程序加以驗(yàn)證。
荔荔:怎么才能快捷地得到有適量重復(fù)文字的文件,來(lái)幫助我們進(jìn)行測(cè)試和效能分析?
九條:我是這樣做的,在電腦的根目錄下,運(yùn)行“dir /s > c:\temp\test.txt”命令。
阿超:好主意,大家還有沒(méi)有別的辦法?
?
VS2012:
Visual Studio 2012 提供了更好的效能測(cè)試的功能, 請(qǐng)看這些博客:
http://www.cnblogs.com/smart-code/archive/2012/09/23/2699053.html?
http://www.cnblogs.com/Gun-N-Rose/archive/2012/09/23/2699220.html?
http://www.cnblogs.com/bigbadwolf/archive/2012/09/24/2699438.html??
http://www.cnblogs.com/Gun-N-Rose/archive/2012/09/24/2699804.html?
?
總結(jié)
以上是生活随笔為你收集整理的现代软件工程讲义 2 开发技术 - 效能分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: android icon 圆角半径,iO
- 下一篇: php5.4环境升级,CentOS环境中