CSAPP:優化程序性能

優化程序性能這章作爲CSAPP中最閃光的一章,其重要程度不言而喻。此實驗分爲了兩個部分:第一部分是對一個多項式計算的優化;第二部分是對矩陣代碼的優化。


首先,我們必須瞭解一些優化程序的常識。
編寫高效的程序需要兩個方面下足馬力:第一,我們必須選擇一組最好的的算法和數據結構;第二,我們必須編寫出編譯器能夠有效優化以轉換成高效可執行代碼的源代碼。那麼此時,我們就需要理解優化編譯器的能力和侷限性。它的侷限性表現在兩個方面:

第一,存儲器別名;
 

提示:考慮*xp == *yp的情況。

第二,函數調用。

提示:考慮fun(x)裏面是一個全局變量或靜態變量,並且遞增。
接下來將逐個介紹優化程序的方法。
第一個方法,代碼移動。什麼是代碼移動呢?它就是把在循環中執行多次但結果卻固定不變的代碼移動到循環之外,這是最簡單的優化。
第二個方法,減少過程調用。爲什麼要減少函數調用呢?因爲每次調用一個函數,這個函數都可能會執行冗餘的操作,比如數組邊界檢查,類型檢查等。舉例來說,如果我們需要調用一個函數來獲得數組中的一個元素,我們可以首先獲得數組首地址,然後通過索引訪問每個元素,而非調用一個函數,然後檢查數組是否越界,然後才返回元素值。
第三種方法,消除不必要的存儲器引用。也就是說,在循環體中不使用指針來存放結果,而使用臨時變量。爲什麼呢?目的就是減少讀、寫內存地址的時間。


隨着對優化的深入,研究彙編代碼以及理解現代處理器是如何執行計算則變得很重要。下面繼續瞭解幾種優化技術。
第四種方法,循環展開 。什麼是循環展開?其思想是在一次迭代中對多個數組元素進行訪問和合並操作。那這樣做有什麼原因或者說帶來了什麼好處呢?受限於資源約束,每個週期內只有兩個功能單元可以執行數據相關的操作,然而一個週期內可能有涉及到數據的多個操作。那麼,這些操作就不能在同一週期內完成,必須暫停等待,降低性能。通過循環展開可以在每次迭代中執行更多的數據操作,避免一個週期內產生多於兩個操作,從而降低循環開銷。

理想情況下的整數加法調度

實際資源受限的情況下,整數加法的調度

優化後,三次循環展開的整數加法的調度

 

第五種方法,迭代分割 。什麼是迭代分割呢?我們知道處理器的幾個功能單元是流水線化的,這說明它們在一個操作完成之前可以開始另一個新的操作。但是,我們的代碼沒有這種能力。當執行當前操作時,處理器會處理其它事務(一般不會暫停),直到本操作完成,纔開始下一個操作。這嚴重影響了程序的性能。而通過迭代分割,則可以很好地緩解此問題,以提高性能。迭代分割其實就是把一個操作分割成兩個或更多的部分,並在最後合併結果以提高性能。產生二路並行或n路並行,提高了程序的並行性。

 

理想情況下的整數乘法調度

實際資源受限的情況下,整數乘法的調度

優化後,二次展開、二次並行的整數乘法操作調度

比較直觀的例子

運用上面的方法來優化第一部分多項式代碼,思考!

對於第二部分的矩陣優化,我們用到的核心思想就是利用局部性原理,包括時間局部性和空間局部性,避免大幅度地跨越內存塊。具體的示例在第三章“程序的機器級表示”的嵌套數組以及第六章“存儲器層次結構”的局部性原理中講述。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章