一、程式優化綜述
1、高效程式的特點
(1)適當的演算法和資料結構。方法和資料的組織形式無疑是最關鍵的,是優化的基礎;
(2)**能夠被編譯器轉化成高效的可執行**。需要深入了解使用的編譯器的優化方法,和常見的優化策略;
(3)運用現代並行程式設計技術。多核以及硬體支援提供更大的加速可能,例如gpu;
2、優化程式的一般步驟
(1)消除不必要的工作,例如消除不必要的函式呼叫(加大棧區負擔),條件測試和記憶體引用;
(2)利用處理器提供的指令級並行能力,同時執行多條指令;指令級並行介於執行緒級併發和單指令多資料並行之間,乙個處理器可實現多指令執行,例如流水線技術;
(3)優化關鍵路徑。就是反覆執行的資料和**;
二、優化編譯器的能力和侷限性
我們可以使用-o1、-o2、-o3來指定編譯器的優化級別,級別越高可能會增加程式的規模。注意一點,優化級別高一般比級別低的效能好,肯定比原始未優化的好!但是,編譯器在優化時會考慮安全問題,如果優化一定會在安全範圍內優化,有乙個條件不滿足就會放棄某模組的優化。
例如:
15//上面的**會被優化為下面嗎?
6
不會,雖然適用一般情況y=y+2x。但是,當x=y時:y=4x 不是3x,所以第一種不是一種好的編碼,沒有很好的體現程式設計思路。編譯器會考慮所有特殊情況,保證安全。還有一種情況,是記憶體別名使用的時候兩個變數值不同,但是指標位址有可能相同。也不會優化.
函式呼叫也會妨礙優化。此時就是用內聯函式優化了,避免頻繁出棧入棧。
三、優化實現方法
發現乙個別人總結的,挺全面的:
1、上面已經看到了儘量減少函式呼叫來降低棧壓力;
2、消除迴圈中的多次條件測試。舉例:
for(int i=0;ii)//上面和下面對比
int s =v.size();
for(int i=0;ii)
含有迴圈的**在翻譯成機器級程式時,會先轉換成goto語句去掉複雜邏輯,然後轉換成組合語言。所以每次都要計算測試條件,像上面這種多次計算測試條件不變的可以提前算好,賦值給區域性變數,區域性變數放在資料區也減輕棧的壓力。如此就不要每次計算了,因為計算大小呼叫庫函式還是需要很大的計算量的。
3、消除不必要的記憶體引用
這裡主要是記憶體和暫存器的訪問效能差別。可以將迴圈中的變數臨時放在累加器暫存器中,計算到最後在寫入記憶體。另乙個方面,對於暫存器溢位要在棧上分配空間,也會拖慢性能,所以對暫存器數量和併發量要協調。
4、現代處理器優化
5、迴圈展開
就是在一次迴圈裡面計算多個元素,例如下例可以將迴圈減半。
//一般做法
for(i=1;ii)
//一次迴圈計算兩個
if(i}
效能是提高了,但是可讀性比較差。用在核心**的瓶頸區比較合適。
6、更低階優化
並行能力提高:將乙個問題拆分,最後多變數合併.。例如:將累乘分為偶數和奇數的分別累乘然後求積,偶數和奇數的計算分開並行。注意棧是執行緒獨享的,多執行緒可解決乙個大問題需要的棧太深的問題!
寫出針對性的分支**演算法:分支**只對有規律的模式可行,所以可以寫出更加「智慧型」的分支**選擇演算法。根據命中率進行乙個排序就能寫出乙個優秀的分支**演算法。結合機器學習會不會效率低?太偏上層了。
四、綜述
優化程式效能的基本策略。
(1)高階設計:選擇合適的資料結構和演算法;
(2)基本編碼原則,就是"三"中提到的;
(3)更低階的優化:迴圈展開、提高指令並行度(6),重寫分支**演算法。後者屬於高階內容。
CSAPP 優化程式效能
1.選擇合適的演算法和資料結構。2.編寫出編譯器能夠有效優化以轉換為高效可執行的源 3.平行計算。當然重點還是第乙個,良好的演算法和資料結構大大減小了程式的時間複雜度。編譯器可以對程式進行不同程式的優化,在終端中,編譯時新增命令列選項 o1,o2等等可以進行不同級別的優化,這樣雖然提高了程式的效能,...
CSAPP 優化程式效能 二
程式示例 為了說明乙個抽象程式是如何被系統地轉換成更有效的 的,我們使用基於如下所示的向量資料結構的執行示例 向量由兩個記憶體塊表示,頭部和資料陣列,頭部宣告結構如下,data t代表基本資料型別 typedef struct vec rec,vec ptr 生成向量,訪問向量元素,確定向量長度的基...
讀CSAPP 2 程式效能優化
合適的資料結構與演算法 編寫出編譯器能夠有效優化以轉換成高效可執行 的原始碼。將運算量特別大的計算,可以分成多部分,這些部分可以在多核多處理器的某種組合上並行處理 本篇主要以第二點進行討論,編譯器在優化的時候只會做最壞打算,做各種假設。為了保證程式的準確性,捨棄效能優化。void twiddle1 ...