1、編譯技術被分為“與機器無關”和“與機器相關”兩類。“與機器無關”,使用這些技術時可以不考慮將執行代碼的電腦的特性;而“與機器有關”,指這些技術依賴於許多機器的低級細節。
2、最小二乘法擬合
3、最佳化之一:消除迴圈的低效率
將迴圈中需要每次計算,但是計算結果不會改變的語句移出去,稱為代碼移動(code motion)。
4、減少不必要的程序呼叫。如可以確保邊界安全的情況下,就不需要每次都進行邊界安全檢查。
5、消除不必要的儲存空間引用
範例程式碼
void Test1(int *pToInt){*pToInt = 0;for (int i = 0; i < 10; i++){*pToInt += i;}}//上述寫法的機器效率,在資料量大的時候,相對下述寫法//低很多,因為*pToInt涉及到儲存空間的引用。void Test2(int *pToInt2){int iTemp = 0;for (int i = 0; i < 10; i++){iTemp += i;}*pToInt = iTemp;}
引入臨時變數來儲存中間結果。只有在最後的值計算出來時,才將結果存放到數組或全域變數中。而通過最佳化,編譯器用寄存器eax(通常)來儲存中間變數的結果。(通過察看彙編代碼來看得到)
6、現代處理器結構
超標量(superscalar):可以在每個刻度執行多個操作,而且是亂序的(out of order)。亂序,即指令執行的順序不一定要與它們在組譯工具中的順序一致。
整個設計有兩個主要部分:ICU(Instruction Control Unit,指令控制單元)和EU(Execution Unit,執行單元)。前者負責從儲存空間中讀出指令序列,並根據這些指令序列產生一組針對程式資料的基本操作;後者執行這些操作。
退役單元(retirement unit)記錄進行中的處理,並確保它遵守機器級程式的順序語義。
7、大多數單元能夠每個刻度開始一個新的操作。僅有的例外是浮點乘法器和兩個除法器。除法器沒有流水線化。
Latency(執行時間) represents the total number of cycles for a single operation.
Issue time(發射時間) denotes the number of cycles between successive(連續的),
independent(獨立的) operations. (Obtained from Intel literature).
8、降低迴圈開銷
我們可以通過在每次迭代中執行更多的資料操作來減小循開銷的影響,使用的是稱為迴圈展開(loop unrolling)的技術。其思想是在一次迭代中訪問數組元素並做乘法。
9、在一個IA32處理器上,所有的浮點操作都是以擴充的80位精度執行的,而浮點寄存器也是按照這個格式儲存的。只有當寄存器的值寫入儲存空間時,才把它轉換成32位(浮點數)或64位(雙精確度格式)。
10、效能提高
1)為問題選擇適當的資料結構和演算法。
2)編碼中:
(1)前面列出的幾種可能引起低效能的地方都要注意。
11、程式剖析
程式剖析(profiling)包括運行程式的這樣一個版本,其中插入了工具代碼,以確定程式的各個部分需要多少時間。
Unix系統提供了一個剖析程式GPROF。更詳盡的介紹,可以GOOGLE,或參見本書第5章。
12、Amdahl定律
其主要思想是:當我們回快系統一個部分的速度時,對系統整體效能的影響依賴於這個部分有多重要(佔全體的百分比)和速度提高了多少(相比原來,提高了幾倍)。
<Computer Systems:A Programmer's Perspective>