簡體   English   中英

在CUDA內核中使用char變量是否會受到懲罰?

[英]Is there a penalty to using char variables in CUDA kernels?

我似乎記得得到提示,我應該盡量避免在CUDA內核中使用char,因為SM喜歡32位整數。 使用它們會有一些速度懲罰嗎? 例如,它做得慢

int a[4];
int b = a[0] + a[1] + a[2] + a[3];
a[1] = a[3];
a2[0] = a[0]

char a[4];
char b = a[0] + a[1] + a[2] + a[3];
a[1] = a[3];
a2[0] = a[0]

在內核代碼?

筆記:

  • 我對使用char值進行算術,執行比較以及讀取和寫入內存的懲罰感興趣。

前面的快速說明:在C / C ++中, char的簽名是實現定義的。 當使用char執行8位整數運算時,因此強烈建議根據計算要求使用signed charunsigned char

可能會在CUDA中使用char類型對性能產生負面影響。 我不建議使用char類型,除非內存大小限制(包括共享內存大小限制)或計算的性質特別需要它。

CUDA是一種遵循基本C ++語言規范的C ++派生語言。 C ++(和C)指定在輸入計算之前,必須將類型窄於int的表達式數據擴展為int 除非底層硬件的整數指令帶有內置轉換,否則這意味着需要額外的轉換指令,這將增加動態指令數量並可能降低性能。

請注意,允許編譯器在“as-if”規則下偏離抽象C ++執行模型:只要結果代碼的行為就像它遵循抽象模型,即它的語義相同,就可以消除這些轉換操作。 我最近的實驗表明,CUDA 6.5編譯器正在積極地應用這種優化,因此能夠徹底消除大多數轉換操作,或者將它們合並到其他指令中。

但是,這並不總是可行的。 一個簡單的設計示例是以下內核,當使用T = charT = int實例化時,它包含一個額外的轉換指令I2I.S32.S8 我通過在可執行文件上運行cuobjdump --dump-sass來轉儲機器代碼來驗證這一點。

template <class T>
__global__ void kernel (T *out, const T *in)
{
    int tid = threadIdx.x;
    if (threadIdx.x < 128) {
        T foo = 5 * in[tid] + 7 * in[tid+1];
        out [tid] = foo * foo;
    }
}

除了增加指令數量之外,由於內存帶寬較低,使用char類型也會對​​性能產生負面影響。 GPU的存儲器子系統的設計使得總可實現的全局存儲器帶寬通常隨着訪問的寬度而增加。 對此的一種可能解釋是跟蹤內存訪問的內部隊列的有限深度,但可能還有其他因素在起作用。

在由於用例的性質(例如圖像處理)而自然出現char類型的情況下,人們會想要研究使用32位復合類型,例如uchar4 在加載和存儲操作期間使用更寬的類型允許改善的存儲器帶寬。 CUDA具有用於處理打包char數據的SIMD內在函數 ,並且使用它們可以有利地減少動態指令計數。 請注意,SIMD內在函數僅在Kepler GPU上由硬件完全支持,在Fermi CPU上完全仿真,並在Maxwell GPU上進行部分仿真。 我已經看到軼事證據表明,與分別處理每個字節相比,即使是模擬版本仍然可以提供性能優勢。 我建議在任何特定用例的上下文中驗證。

CUDA最佳實踐指南的第11.1.3節中也有一個非常簡短的參考問題:

編譯器必須偶爾插入轉換指令,引入額外的執行周期。 這是......的情況

  • charshort上運行的函數,其操作數通常需要轉換為int
  • ...

算術

在一般意義上說,它是否會更快/更慢/不變是不可能的,盡管通常我不會期望有太大差異。 你說chars的算法是32位是正確的,但這是否需要類型轉換將取決於問題。 在問題的例子中,我希望看到編譯器將ab存儲在32位寄存器中,並且在我的實驗中圍繞這個問題(注意,沒有完整的復制情況,很難保證這一點)我沒有看到SASS的差異。 對於在寄存器中完成所有操作的代碼區域,我不希望性能命中。

但是,因為char變量被移動兩次並且從內存中移動,所以會產生影響。 由於char必須在使用前被轉換為32位寄存器,因此會產生額外的指令。 這可能是相當大的影響,也可能不是。

現在,也有一些邊緣情況可能會有所不同。 編譯器可能能夠將多個char打包到寄存器中並使用算術(寄存器保存與算術成本)提取它們。 您甚至可以使用聯合強制執行此行為。 保存是否值得指示將根據具體情況而有所不同。 我想不出任何其他會導致重大投射開銷的人。

記憶

很明顯,如果您可以將變量存儲在1個字節而不是4個字節中,那么您將需要節省4倍的內存和帶寬。 有些事情需要考慮:

  1. 共享內存 當前共享庫大小為4字節或8字節。 除非您使用每個線程至少4/8字節的事務進行讀取,否則無法實現峰值共享內存帶寬。 對於較小的交易,還要考慮銀行沖突。 讀取一個字節大小的1字節將避免這些存儲體沖突,但會增加所需的內存並浪費帶寬。
  2. 全球記憶 當您能夠進行大型交易時,內存系統最有效。 128位事務往往比64位快,這往往比32位快。 因此,打包(和對齊)數據是個好主意,這樣您就可以通過一條指令將多個數據移動到一個線程中。

結論

我不知道有什么重要的理由不使用char如果可能的話,而不是int算術,其中一切都在寄存器中,盡管在讀/寫內存時你會支付轉換成本。 如果你小心的話,將數組存儲為char而不是int應該既節省帶寬又節省空間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM