2011-12-18 63 views
0

首先,我想知道什麼是循環優化和改造之間的根本區別,也何時以及如何正確使用循環優化和轉化技術

C中的一個簡單的循環如下:

for (i = 0; i < N; i++) 
{ 
a[i] = b[i]*c[i]; 
} 

但我們可以展開它:

for (i = 0; i < N/2; i++) 
{ 
a[i*2] = b[i*2]*c[i*2]; 
a[i*2 + 1] = b[i*2 + 1]*c[i*2 + 1]; 
} 

,但我們可以進一步展開它..但是我們可以展開它的限制是什麼,以及我們如何找到它。

還有更多的技術,如循環耕種,循環分佈等。 ,如何確定何時使用適當的。

+7

爲什麼不讓你的編譯器爲你做這個?確保優化已啓用,然後出去做點有趣的事情。 – 2011-12-18 14:13:11

+0

編譯器如何決定......出於好奇。 – sum2000 2011-12-18 14:14:16

+0

@pmg它不是我的,它來自Wayner Wolf,它是一本很好的書 – sum2000 2011-12-18 14:25:30

回答

4

我會假設OP已經異形他/她的代碼,並發現這段代碼實際上是很重要的,實際上:-)回答這個問題:

編譯器將盡力使循環根據對代碼和處理器體系結構的瞭解來展開決策。

在使事情變得更快。

  • 正如有人指出的那樣,展開確實減少了循環終止條件比較和跳轉次數。
  • 根據體系結構的不同,硬件也可以支持一種有效的方法來索引近存儲位置(eg,mov eax,[ebx + 4]),而無需添加額外的指令(儘管這可能會擴展到更多的微操作 - 不確定)。
  • 大多數現代處理器使用亂序執行,以找到指令級並行。當接下來的N個指令在多個條件跳轉之後(即,硬件需要能夠放棄可變級別的推測)時,這很難做到。
    • 更有機會提前對內存操作進行重新排序,以便隱藏數據獲取延遲。代碼矢量化(例如,轉換爲SSE ​​/ AVX)也可能發生,其允許在一些情況下並行執行代碼。這也是一種展開形式。

在決定何時停止展開方面:

  • 開卷增加代碼大小。編譯器知道超過指令代碼高速緩存大小(所有現代處理器),跟蹤高速緩存(P4),循環緩存高速緩存(Core2/Nehalem/SandyBridge),微操作高速緩存(SandyBridge)等都會受到懲罰。理想情況下,它使用靜態成本效益啓發式(特定代碼和體系結構的功能)來確定哪種展開級別會導致最佳總體網絡性能。根據編譯器的不同,heurstics可能會有所不同(通常我會發現自己調整它會很好)。
    • 通常,如果循環包含大量代碼,則由於循環成本已經攤銷而不太可能展開,因此有大量ILP可用,並且展開的代碼膨脹成本過高。對於較小的代碼段,循環很可能會被展開,因爲成本可能很低。展開的實際數量將取決於體系結構,編譯器啓發式規則和代碼的具體情況,並且將由編譯器決定的最優(它可能不是:-))。

在的時候你應該做這些優化方面:

  • 當你不覺得編譯器做了正確的事情。編譯器可能不夠複雜(或足夠新的版本),無法充分利用您正在處理的體系結構的知識。

  • 可能,啓發式失敗(畢竟他們只是啓發式)。一般來說,如果您知道這段代碼非常重要,請嘗試展開它,如果它提高了性能,請保留它,否則將其丟棄。此外,只有在大致整個系統完成後才能做到這一點,因爲當代碼工作集爲20k時,可能會有所幫助,但當代碼工作集爲31k時可能沒有好處。

+1

這個答案就目前而言是正確的。但是我不得不指出,如果你真正處理的是一個編譯器沒有做正確的事,而且不夠複雜或者不夠新,那麼你應該更新這個編譯器*。 :-) – 2011-12-19 08:57:41

+1

並不總是一個選項。無論何時出現新的架構特徵,編譯器技術需要很長時間才能發展爲最佳支持。另外,編譯器技術通常永遠都不會到達那裏。作爲一個小例子,如果我有一個約100個uop循環,其中有99.99個應用程序被花費了,我希望它在SB架構(即15x)上展開到我的upop緩存的大小,即使使用PGO也不會發生這種情況。 – Crowley9 2011-12-19 13:57:34

+0

@ Crowley9即使ICC被告知要優化某人?我會認爲他們會在那裏做得更好,但是當然 - 如果你有關於你的應用程序的外部知識,你可以幫助編譯器。你只需要充分理解架構,就可以知道編譯器何時做不正確的事情,這在當今時代並非如此簡單。即有多少程序員知道μop緩存? – Voo 2011-12-19 14:59:53

3

對於你的問題,這可能看起來相當偏離主題,但我不得不強調這一點的重要性。

關鍵是要編寫一個正確的代碼,並根據需求工作,而不用擔心微觀優化問題。
如果後來你發現你的程序缺乏性能,那麼你配置文件!您的應用程序找到問題領域,然後嘗試優化它們。
記得聰明的人之一說It is only 10% of your code which runs 90% of the total run time of your application trick is to identify that code through profiling and then try to optimize it.

+0

在他的書*更有效的C++ *中,這是一個智者,他說* Scott Meyers *。 – 2011-12-19 03:55:32

2

那麼考慮到你在優化的第一次嘗試是已經錯誤在所有病例中50%我真的不會嘗試任何事情更加複雜(老命奇數)。

此外,而不是你的指數相乘,只需添加2〜i和環路高達N再次 - 避免了不必要的變速(影響不大,只要我們留2的冪,但仍然)

總結:你編寫的代碼比編譯器可以做的不正確,速度慢 - 這就是爲什麼你不應該這樣做的最好例子。

+0

那麼**,那麼你是完全錯誤的**,如果可以的話,我會對你的答案低估,這個優化技術來自Wayner Wolf,它比原來的測試花費更少的時間。如果你懷疑剛剛閱讀**循環展開**首先 – sum2000 2011-12-18 14:50:07

+2

@ sum2000你*嘗試*代碼?說這是正確的,因爲有人寫它不是一個很好的論點。無論原始代碼的正確性如何,Voo的觀點都是不錯的。正確優化難以正確進行,而且幾乎永遠不值得。讓編譯器爲你做,這就是優化編譯器的設計目的。根據我的經驗,優秀的編譯器至少90%的時間比優秀的程序員更聰明。 – 2011-12-18 14:51:59

+0

我正在談論嵌入式計算,你想讓我參考這本書,它是頁面..只是爲了確認,我沒有自己寫。 – sum2000 2011-12-18 14:53:35