CUDA——性能優化之循環展開

循環展開(#pragma unroll)

1)什麼是循環展開?

循環展開顧名思義就是將循環體展開,全部展開或者展開一部分都可以有效提高性能。

循環展開無論是在CPU還是GPU上,都可以有效的提高應用程序運行速度。

以下是一個循環體

float sum=0;
for(int i=0;i<n;++i)
{
	sum+=a[i];
}

循環部分展開

for(int i=0;i<n;i+=2)
{
	sum+=a[i]+a[i+1];
}

2)爲什麼要循環展開

我們知道執行核函數時,通常以warp爲單位去執行指令的。當warp去執行循環時( 線程ID去做for的判斷條件 或者 for裏有線程ID的if條件 ),會產生分支衝突,增加指令數。
所以循環展開可以有效避免分支衝突,提高性能。

3)循環展開在GPU中的應用

編譯器會默認展開帶有循環計數的小循環(比如上述例子中的N是常數的話)。而#pragma unroll 指令則可用於控制任何給定循環的展開。它必須放置在循環前,並只應用於此循環。它後面可以跟一個數字,用於指定循環必須展開多少次。

下列代碼示例中循環將展開5次

#pragma unroll 5
for(int i=0;i<n;++i)

此時,要確保n>=5,不然會影響程序運算結果。

注意(當循環展開之後需要用到寄存器時):

循環展開會使用更多的寄存器,編譯器在編譯的過程中會將確定的量優先存儲在寄存器中,這就導致有些變量會被存儲到局部內存。(循環展開會消耗更多的寄存器,而不展開是不會的)。SM裏的寄存器大小是有限的,SM會根據一個塊需要消耗的寄存器大小和線程的個數去分配該SM上塊的個數,當一個SM連一個塊都分配不了時,就會導致內核啓動不了。

此時的解決辦法就只有 減少線程的數量去換取更多的寄存器
所以循環的展開應該在寄存器適用的範圍去展開,不能過度展開。如何保證不過度展開?就是權衡寄存器大小線程數量之間的關係。

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