天天看點

CUDA實踐指南(二十八)

控制流:

分支和分歧:

高優先級:避免同一個warp内的不同執行路徑。

流控制指令(如果,切換,做,為,while)可以通過使同一個warp的線程發散來顯着影響指令吞吐量; 即遵循不同的執行路徑。 如果發生這種情況,不同的執行路徑必須單獨執行; 這會增加為這個warp執行的指令總數。

為了在控制流程取決于線程ID的情況下獲得最佳性能,應該編寫控制條件以盡量減少發散warps的數量。

這是可能的,因為在CUDA C程式設計指南的SIMT體系結構中提到了整個塊上的warp分布是确定性的。 一個簡單的例子是控制條件僅依賴于(threadIdx / WSIZE),其中WSIZE是warp大小。

在這種情況下,由于控制條件與warp完美對齊,是以沒有warp發散。

對于隻包括幾條指令的分支,翹曲散度通常會導緻性能損失的邊際。 例如,編譯器可能使用預測來避免實際的分支。 相反,所有指令都是預定的,但每個線程條件代碼或謂詞控制哪些線程執行指令。 帶有假謂詞的線程不會寫結果,也不會計算位址或讀操作數。

從Volta體系結構開始,獨立線程排程允許warp在資料相關條件塊之外保持分離。 明确的__syncwarp()可以用來保證warp已經為後續指令重新收斂。

分支預測:

低優先級:使編譯器易于使用分支預測來代替循環或控制語句。

有時,編譯器可能會展開循環,或者通過使用分支預測來優化if或switch語句。 在這些情況下,沒有任何扭曲可以分歧。 程式員也可以使用控制循環展開:

當使用分支預測時,跳過執行取決于控制條件的指令。 相反,每個這樣的指令都與根據控制條件設定為真或假的每線程條件代碼或謂詞相關聯。 雖然這些指令中的每一條都被安排執行,但實際上隻執行帶有真謂詞的指令。 帶有假謂詞的指令不寫結果,它們也不評估位址或讀操作數。

隻有當由分支條件控制的指令數小于或等于某個門檻值時,編譯器才會用預測指令替換分支指令:如果編譯器确定該條件可能會産生很多發散warps,則此門檻值為7; 否則是4。

Loop Counters Signed vs. Unsigned:

低中優先級:使用帶符号整數而不是無符号整數作為循環計數器。

在C語言标準中,無符号整數溢出語義被很好地定義,而帶符号整數溢出會導緻未定義的結果。 是以,編譯器可以比使用無符号算術更積極地進行有符号算術優化。 在循環計數器中這一點特别值得注意:因為循環計數器的值始終為正,是以将計數器聲明為未簽名可能是誘人的。 但是,對于稍微好一點的性能,它們應該被聲明為已簽名。

例如,請考慮以下代碼:

這裡,子表達式stride *我可以溢出一個32位整數,是以如果我聲明為unsigned,那麼溢出語義會阻止編譯器使用某些可能已應用的優化,例如強度降低。 如果相反,我被聲明為有符号的,那麼溢出語義未定義,編譯器有更多的餘地來使用這些優化。

繼續閱讀