2012-04-09 153 views
5

給予代碼:循環展開和優化

for (int i = 0; i < n; ++i) 
{ 
    A(i) ; 
    B(i) ; 
    C(i) ; 
} 

而優化的版本:

for (int i = 0; i < (n - 2); i+=3) 
{ 
    A(i) 
    A(i+1) 
    A(i+2) 
    B(i) 
    B(i+1) 
    B(i+2) 
    C(i) 
    C(i+1) 
    C(i+2) 
} 

東西是我不明白:這是更好?使用其他版本看不到任何更快的工作。我在這裏錯過了什麼嗎?

所有我看到的是,每一個指令根據之前的指令,這意味着 我需要等待前一指令將在以開始一前一後完成...

感謝

+1

哪種語言? – Bytemain 2012-04-09 22:00:44

+0

維基百科有一篇很好的文章,介紹循環展開後的想法,以瞭解它的價值:http://en.wikipedia.org/wiki/Loop_unwinding – 2012-04-09 22:02:00

+0

一般而言,這些並不等同。應該是A(i);雙); C(I); A(I + 1); B(I + 1);等等。 – gnasher729 2014-06-10 21:43:15

回答

9

在語言的高級視圖中,您不會看到優化。速度增強來自編譯器對你所擁有的內容的處理。

在第一種情況下,它是這樣的:

LOCATION_FLAG; 
DO_SOMETHING; 
TEST FOR LOOP COMPLETION;//Jumps to LOCATION_FLAG if false 

在第二個它是這樣的:

LOCATION_FLAG; 
DO_SOMETHING; 
DO_SOMETHING; 
DO_SOMETHING; 
TEST FOR LOOP COMPLETION;//Jumps to LOCATION_FLAG if false 

您可以在後一種情況看,測試和跳躍的開銷僅爲每3個指令1個。首先是1個指令1;所以它經常發生很多。因此,如果你有不變式可以依賴(使用你的例子中的一個mod 3的數組),那麼展開循環會更高效,因爲底層組件的編寫更直接。

3

那麼,這個代碼是「更好」還是「更糟糕」完全取決於ABC的實現,您期望的值爲n,您正在使用哪種編譯器以及正在運行哪個硬件。

通常,循環展開的好處是可以減少循環的開銷(即增加i並將其與n進行比較)。在這種情況下,可以減少3倍。

4

循環展開用於減少分支指令的跳轉次數,這可能會使循環更快,但會增加二進制文件的大小。取決於實施和平臺,要麼可能會更快。

2

只要函數A(),B()和C()不修改相同的數據集,第二個版本就提供了更多的並行化選項。

在第一個版本中,三個函數可以同時運行,假設沒有相互依賴關係。在第二個版本中,假設你有足夠的執行單元來做這樣一次又一次,所有三個函數可以同時運行所有三個數據集,沒有相互依賴關係。

0

一般來說,嘗試「發明」優化並不是一個好主意,除非您有確鑿證據表明您會獲得增加,因爲很多時候您最終可能會引入降級。通常,獲得這種證據的最佳方式是使用一個好的分析器。我會用一個分析器來測試這個代碼的兩個版本,以查看其差異。

而且,多次循環展開心不是很可移植,如前面提到的,它極大地取決於平臺,編譯器等

您可以使用編譯器選項還播放。一個有趣的gcc的選項是 「-floop-優化」,你有 「-O,-O2,-O3和-Os」

編輯另外自動獲取,看看 「-funroll-循環」 編譯選項。

+0

另外,看看這個相當簡潔但令人驚歎的循環展開示例:[Duff's device](http://en.wikipedia.org/wiki/Duff%27s_device) – Brady 2012-04-10 07:33:53