C++應用程序性能優化(一)——應用程序性能優化簡介
一、程序性能優化簡介
1、程序性能優化簡介
在計算機發展的早期階段,硬件資源相對而言是非常昂貴的,CPU運行時間與內存容量給程序開發人員設置了極大限制。因此,早期的程序對運行性能和內存空間占用的要求是非常嚴格的,很多開發人員為了減少1%的CPU運行時間,為減少幾十個甚至幾個字節而不懈努力。隨著計算機技術的快速發展,硬件資源變得相對便宜。但如果認為軟件開發時,程序的性能優化不再重要,硬件將解決性能問題也是片面的。計算機硬件的發展解決了部分軟件的性能問題,但隨著硬件計算能力的提高,用戶對軟件功能的要求也越來越高,軟件功能也變得越來越復雜,給用戶的界面和操作體驗也越來越智能和友好。但復雜的用戶需求帶來軟件性能上的要求是硬件不能完全解決的。眾多實際項目經驗證明,如果在開發軟件時不重視性能優化,最終實現了軟件的功能要求,但軟件的運行效率低下,最終也不能給用戶帶來很好的效益。但另一方面,計算機硬件越來越便宜,而優秀的軟件開發工程師則越來越昂貴,在軟件開發過程中無限制的性能優化同樣會導致軟件開發過程中人力成本的大幅增加。因此,軟件開發過程中的性能優化必須在便宜的計算機硬件和昂貴的優秀工程師之間找到一個平衡點。
2、程序性能優化的流程
應用程序性能優化的流程如下:
(1)性能測量,對於規模較大、較為復雜的軟件系統,測量性能數據是進行性能優化的基礎。只有獲取真實的數據才能分析數據找出系統的性能瓶頸。
(2)分析數據,找到系統的性能瓶頸。性能瓶頸必須建立在客觀真實的性能數據基礎上,不能是主觀臆測的。
(3)分析原因,修改程序,是程序性能優化的核心。程序的性能包括啟動速度、運行速度、運行時占用內存等。影響程序性能的因素主要分為兩類:
(1)軟件編程設計因素:算法和數據結構的選擇,編程語言的使用。
(2)軟件系統結構因素:動態庫、靜態庫的組織,外部數據的存儲以及網絡環境等。
軟件編程設計因素是對軟件性能影響較大的因素,只有對算法、數據結構、編程語言有深入的了解才能分析出原因,並且找到解決性能問題的方法。
二、程序性能的定義
1、性能指標定義
應用程序的性能指標通常是多維的,比如響應時間、並發量等。對於桌面應用程序,其服務對象通常為終端用戶。因此,桌面應用程序最重要的性能指標是響應時間,即針對某一個具體的操作,用戶從發出命令到應用程序完成任務並響應用戶的時間,響應時間越短越好。
除了響應時間,內存使用也是桌面應用程序的重要指標之一。內存使用包括進程工作集(任務管理器看到的內存使用)和虛擬內存使用兩個指標,越小越好。如果一個應用程序占用內存過高,會影響其它正在運行的應用程序的響應時間。
(1)小於0.1秒的響應時間,用戶感覺是即時的。
(2)小於1秒的響應時間,用戶感覺是可接受的。
(3)大於1秒的操作應該有一個簡單標示(如鼠標變成沙漏)。
(4)大於10秒的操作應該有明顯的提示(如進度條)。
2、性能基準
桌面應用程序的性能指標包括響應時間和內存使用,但響應時間和內存使用指標通常針對單個操作。現代軟件系統通常包括多項功能,例如一個文字處理軟件能夠提供的功能不下數百種,每種功能作用在不同類型和大小的文檔上會表現出不同的性能,性能基準就是用於定義程序的總體性能的。
性能基準(Performance Benchmark)是用來衡量應用程序整體性能的一套體系,通過為應用程序輸入預先設計好的工作負載,運行一批基準用例,運行結果可以反映應用程序在通常情況下的性能。因此,性能基準=基準負載+基準用例。
(1)基準負載
對於桌面應用程序,運行性能基準時需要的基準負載通常表現為一系列基準文件。基準文件應該是具有典型大小和典型內容的文件,而基準文件選取的優劣直接影響性能基準的準確性。
對於通用文字處理軟件,主要功能是創建、打開文檔,修改並保存文檔,支持的文檔類型包括.doc,.dot,.odt,.ott,.txt,.lwp等,支持文字、圖片、文本框、表格、圖形等。設計基準文件時,從文檔類型考慮,在兼顧到主要的文檔類型又要排除類似的文檔類型;從文檔內容考慮,需要覆蓋用戶最常用的內容對象類型和文檔大小,具體基準文件列表如下:
對於同一種文檔類型,每一種文檔類型包含兩個基準文件,分別有不同的文檔內容。
(2)基準用例
基準用例是性能基準測試時需要執行的一系列用例。基準用例的選擇有一定原則,既要盡可能全面地覆蓋應用程序的主要功能,又不能像功能測試用例那樣復雜,因此,基準用例應該是用戶日常操作經常遇到的情形。
不同的基準用例在性能基準中的地位並不相同,每一個基準用例都需要一個權值來表明它對整體性能基準的貢獻度。權值的定義依據具體情況各有不同,一個比較實用的定義公式如下:
權值=用例頻率X用例重要性
用例頻率是用戶一定時間內執行該用例的平均次數。理想的用例頻率應該通過用戶行為數據反饋獲得。例如通用文字處理軟件的用戶一天內可能會執行“打開文檔”用例5次,執行“保存文檔”的用例15次。
用例重要性是一個修正系數,反映用例沒有完成前對用戶工作的影響程度。文字處理軟件打開一個文檔時有“異步打開”的功能,即程序會首先讀入文檔的部分內容並顯示給用戶,然後在後臺繼續讀入文檔的後續內容。對於“異步打開”功能可以定義兩個用例,“第一頁顯示”(從用戶選擇打開文檔到文檔的第一頁顯示出來的過程)和“全部讀入完畢”(從用戶選擇打開文檔到文檔的所有頁的內容已經加載完畢的過程)。“第一頁顯示”用例的重要性為1,表示不執行完本用例,用戶不能繼續工作;“全部讀入完畢”用例的重要性為0.5,表示本用例不會顯著影響用戶的工作,文檔在後臺加載,用戶前臺已經可以編輯,除非用戶需要編輯的內容還沒有加載出來。
文字處理程序的部分基準用例如下:
相同的操作步驟操作不同類型或不同內容的基準文件會形成不同的基準用例。
3、性能基準的運行
準備好基準文件和基準用例後就可以運行性能基準並得出基準結果。
為了保證性能基準運行的準確性,性能基準的測試環境必須滿足一定要求。例如保證固定的基準測試平臺(軟件和硬件平臺不變),盡可能排除其它應用程序對目標應用層程序的影響。基準測試平臺也可以有同時運行在多種硬件平臺上的考量:運行在4G內存和8G內存時應用程序的性能表現的差別;運行在三年前硬件配置和當前主流硬件配置的性能表現的差別。
運行基準測試的過程是在固定的基準測試環境中針對基準文件順序執行一系列基準用例並記錄下每個用例結果的過程,執行過程分為手動執行和自動執行,結果記錄也可以分為手動記錄和自動記錄。
通常手工執行和記錄是基礎,最能反映最終用戶的體驗。
自動運行和記錄是目標,可以大幅提升工作效率,並排除人工不穩定的結果。但自動運行的腳本必須保證多次自動運行結果的穩定,保證自動運行結果和手動運行結果的可比較。
性能基準運行的過程需要註意:
(1)每一個用例需要運行多次求平均值,如需要去除最大值、最小值,然後取平均值。
(2)多個用例執行的先後順序必須固定,否則很難得到穩定的性能基準結果。
4、性能基準結果
性能基準運行結果的原始數據是一系列的絕對數值,可以根據不同的需要生成不同的報告,如:
整體性能水平分值:每個用例絕對值結合每個用例的權值,可以給整體性能水平打分。
性能變化趨勢圖:歷史上不同版本的整體性能分值曲線可以體現出性能變化趨勢。
關鍵性能指標圖表:給用戶演示的重點用例的結果圖表。
產品性能對比圖:和其它產品的性能對比圖,包括絕對值的對比和加權後分值的對比。
文字處理程序的部分基準用例運行結果數據如下:
性能基準可以反映應用程序的總體性能,定義良好的性能基準用途如下:
(1)應用程序性能的絕對指標。任何想要了解產品性能的人,無論是管理層還是客戶,都可以通過產品性能報告了解產品的性能。
(2)通過比較不同版本的基準結果,提前發現性能下降的問題和驗證性能提升的設計結果。軟件開發過程中通常都會進行每日構建,性能基準也可以在每日構建的基礎上每日運行,及時發現性能問題,而不是在產品即將發布時進行性能優化。
(3)比較不同廠商的類似軟件的性能。橫向的比較需要性能基準,可以找出自己軟件產品的性能薄弱環節,集中力量進行優化。
三、程序性能分析方法
1、性能分析方法簡介
擁有定義良好的性能基準後,可以輕易發現應用程序存在的性能問題。發現性能問題後需要對性能問題進行分析,程序的性能分析過程包括:性能問題分類、查找性能瓶頸、進行性能優化。
2、性能問題分類
一個操作執行太慢,需要首先分類是IO操作密集引起的問題還是CPU相關的計算密集型問題。正確的分類將直接影響進一步的問題分析。
區別IO相關還是CPU相關問題的簡單方法是隔離IO影響後,看性能是否得到改善,例如同時在機械硬盤和SSD硬盤上測試,如果性能顯著提高,則是IO相關的問題。
對於文字處理軟件,冷啟動需要10.5秒,熱啟動需要2.1秒,因此冷啟動的主要問題在IO。無論是冷啟動還是熱啟動,應用程序都是完全退出後再重新啟動,執行的代碼流程完全一樣,唯一區別在於IO:冷啟動後操作系統會緩存很多動態庫的代碼頁在內存。
3、查找性能瓶頸
對性能問題分類後,可以使用性能分析工具在代碼層次查找性能瓶頸,性能分析工具有監測工具和註入工具兩類。
監測工具如下:
perfmon,Windows工具,可以監測所有的性能指標。
FileMon,Windows工具,監測IO操作。
ProcessExplorer,Windows工具,監測進程相關的所有操作。
sysstat,Linux工具,監測所有的性能指標。
iostat,Linux工具,監測IO操作。
vmstat,Linux工具,監測內存變化。
註入工具如下:
IBM rational quantify,Windows工具,針對C++應用程序代碼註入,可以計算函數調用次數、時間等。
Valgrind,Linux工具,針對C++應用程序代碼註入,可以計算函數調用次數、事件、內存分配、內存泄漏檢測等。
IBM rational purify,Windows工具,針對C++應用程序代碼註入,可以進行內存分析。
WinDbg,Windows工具,調試工具。
GDB,Linux工具,調試工具。
Dependency walker,Windows工具,分析動態鏈接庫之間的動態、靜態依賴關系。
ldd,Linux工具,分析共享對象間的依賴關系。
4、查找性能優化機會
代碼層次的性能優化設計的改動通常局限在有限的函數調用內,相對比較容易完成。進一步的性能提升的機會需要在設計層次進行查找。設計層面的性能分析需要性能優化者對軟件的整體架構有比較深入的了解,需要具體問題具體分析。
四、程序性能優化方法
性能問題分析完成後,需要進行性能優化。根據性能分析結果的不同,優化方法也各有不同。
1、針對IO瓶頸的性能優化
每次IO操作大概在10ms量級,100次就需要1秒左右,因此盡量避免不必要的IO操作。具體做法如下:
(1)預先順序讀文件避免隨機訪問。
(2)合並多個小文件為單個大文件。
(3)優化動態庫文件的加載。
(4)交錯IO時間和CPU時間。
2、針對計算密集的性優化
計算密集的性能問題主要有內存分配性能、字符串操作、共享變量的互斥鎖保護等,具體優化方法如下:
(1)去除冗余代碼。
(2)字符串操作優化。
(3)減少內存分配、釋放操作,例如使用內存池。
(4)減少不必要的互斥鎖操作。
(5)根據性能需求選擇數據結構。
(6)延遲工作,按需執行。
(7)減少跨進程的調用。
(8)使用高性能的函數庫。
3、C++語言特性相關的性能優化
C++語言特性相關的性能優化包括內聯函數、引用、編譯優化選項等。
4、用戶體驗的性能優化
有些設計不能真正提升性能,但讓用戶體驗到了性能提升。如:
(1)流式播放設計,用戶不需要等到視頻文件下載完成再播放,可以邊下載邊播放。
(2)線程化設計,對於需要較長時間完成的操作,可以設計為非阻塞式的,用戶可以在等待時間完成其它操作任務。
5、設計層面的性能優化
設計層面的性能優化需要根據軟件整體架構具體問題具體分析。
C++應用程序性能優化(一)——應用程序性能優化簡介