cuda-Block和Grid设定
生活随笔
收集整理的這篇文章主要介紹了
cuda-Block和Grid设定
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
CUDA的Threading:Block和Grid設(shè)定
硬件基本架構(gòu) 實(shí)際上在 nVidia 的 GPU 里,最基本的處理單元是所謂的 SP(Streaming Processor),而一顆 nVidia 的 GPU 里,會(huì)有非常多的 SP 可以同時(shí)做計(jì)算;而數(shù)個(gè) SP 會(huì)在附加一些其他單元,一起組成一個(gè) SM(Streaming Multiprocessor)。幾個(gè) SM 則會(huì)在組成所謂的 TPC(Texture Processing Clusters)。
在 G80/G92 的架構(gòu)下,總共會(huì)有 128 個(gè) SP,以 8 個(gè) SP 為一組,組成 16 個(gè) SM,再以兩個(gè) SM 為一個(gè) TPC,共分成 8 個(gè) TPC 來(lái)運(yùn)作。而在新一代的 GT200 里,SP 則是增加到 240 個(gè),還是以 8 個(gè) SP 組成一個(gè) SM,但是改成以 3 個(gè) SM 組成一個(gè) TPC,共 10 組 TPC。下面則是提供了兩種不同表示方式的示意圖。(可參考《NVIDIA G92終極狀態(tài)!!》、《NVIDIA D10U繪圖核心》)
對(duì)應(yīng)到 CUDA
而在 CUDA 中,應(yīng)該是沒(méi)有 TPC 的那一層架構(gòu),而是只要根據(jù) GPU 的 SM、SP 的數(shù)量和資源來(lái)調(diào)整就可以了。
如果把 CUDA 的 Grid - Block - Thread 架構(gòu)對(duì)應(yīng)到實(shí)際的硬件上的話,會(huì)類似對(duì)應(yīng)成 GPU - Streaming Multiprocessor - Streaming Processor;一整個(gè) Grid 會(huì)直接丟給 GPU 來(lái)執(zhí)行,而 Block 大致就是對(duì)應(yīng)到 SM,thread 則大致對(duì)應(yīng)到 SP。當(dāng)然,這個(gè)講法并不是很精確,只是一個(gè)簡(jiǎn)單的比喻而已。
SM 中的 Warp 和 Block
CUDA 的 device 實(shí)際在執(zhí)行的時(shí)候,會(huì)以 Block 為單位,把一個(gè)個(gè)的 block 分配給 SM 進(jìn)行運(yùn)算;而 block 中的 thread,又會(huì)以「warp」為單位,把 thread 來(lái)做分組計(jì)算。目前 CUDA 的 warp 大小都是 32,也就是 32 個(gè) thread 會(huì)被群組成一個(gè) warp 來(lái)一起執(zhí)行;同一個(gè) warp 里的 thread,會(huì)以不同的數(shù)據(jù),執(zhí)行同樣的指令。此外,在 Compute Capability 1.2 的硬件中,還加入了 warp vote 的功能,可以快速的進(jìn)行 warp 內(nèi)的簡(jiǎn)單統(tǒng)計(jì)。
基本上 warp 分組的動(dòng)作是由 SM 自動(dòng)進(jìn)行的,會(huì)以連續(xù)的方式來(lái)做分組。比如說(shuō)如果有一個(gè) block 里有 128 個(gè) thread 的話,就會(huì)被分成四組 warp,第 0-31 個(gè) thread 會(huì)是 warp 1、32-63 是 warp 2、64-95 是 warp 3、96-127 是 warp 4。
而如果 block 里面的 thread 數(shù)量不是 32 的倍數(shù),那他會(huì)把剩下的 thread 獨(dú)立成一個(gè) warp;比如說(shuō) thread 數(shù)目是 66 的話,就會(huì)有三個(gè) warp:0-31、32-63、64-65。由于最后一個(gè) warp 里只剩下兩個(gè) thread,所以其實(shí)在計(jì)算時(shí),就相當(dāng)于浪費(fèi)了 30 個(gè) thread 的計(jì)算能力;這點(diǎn)是在設(shè)定 block 中 thread 數(shù)量一定要注意的事!
一個(gè) SM 一次只會(huì)執(zhí)行一個(gè) block 里的一個(gè) warp,但是 SM 不見(jiàn)得會(huì)一次就把這個(gè) warp 的所有指令都執(zhí)行完;當(dāng)遇到正在執(zhí)行的 warp 需要等待的時(shí)候(例如存取 global memory 就會(huì)要等好一段時(shí)間),就切換到別的 warp 來(lái)繼續(xù)做運(yùn)算,藉此避免為了等待而浪費(fèi)時(shí)間。所以理論上效率最好的狀況,就是在 SM 中有夠多的 warp 可以切換,讓在執(zhí)行的時(shí)候,不會(huì)有「所有 warp 都要等待」的情形發(fā)生;因?yàn)楫?dāng)所有的 warp 都要等待時(shí),就會(huì)變成 SM 無(wú)事可做的狀況了~
下圖就是一個(gè) warp 排程的例子。一開(kāi)始是先執(zhí)行 thread block 1 的 warp1,而當(dāng)他執(zhí)行到第六行指令的時(shí)候,因?yàn)樾枰却?#xff0c;所以就會(huì)先切到 thread block 的 warp2 來(lái)執(zhí)行;一直等到存取結(jié)束,且剛好有一個(gè) warp 結(jié)束時(shí),才繼續(xù)執(zhí)行 TB1 warp1 的第七行指令。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
登錄/注冊(cè)后可看大圖 實(shí)際上,warp 也是 CUDA 中,每一個(gè) SM 執(zhí)行的最小單位;如果 GPU 有 16 組 SM 的話,也就代表他真正在執(zhí)行的 thread 數(shù)目會(huì)是 32*16 個(gè)。不過(guò)由于 CUDA 是要透過(guò) warp 的切換來(lái)隱藏 thread 的延遲、等待,來(lái)達(dá)到大量平行化的目的,所以會(huì)用所謂的 active thread 這個(gè)名詞來(lái)代表一個(gè) SM 里同時(shí)可以處理的 thread 數(shù)目。
而在 block 的方面,一個(gè) SM 可以同時(shí)處理多個(gè) thread block,當(dāng)其中有 block 的所有 thread 都處理完后,他就會(huì)再去找其他還沒(méi)處理的 block 來(lái)處理。假設(shè)有 16 個(gè) SM、64 個(gè) block、每個(gè) SM 可以同時(shí)處理三個(gè) block 的話,那一開(kāi)始執(zhí)行時(shí),device 就會(huì)同時(shí)處理 48 個(gè) block;而剩下的 16 個(gè) block 則會(huì)等 SM 有處理完 block 后,再進(jìn)到 SM 中處理,直到所有 block 都處理結(jié)束。
為一個(gè)多處理器指定了一個(gè)或多個(gè)要執(zhí)行的線程塊時(shí),它會(huì)將其分成warp塊,并由SIMT單元進(jìn)行調(diào)度。將塊分割為warp的方法總是相同的,每個(gè)warp都包含連續(xù)的線程,遞增線程索引,第一個(gè)warp中包含全局線程過(guò)索引0-31。每發(fā)出一條指令時(shí),SIMT單元都會(huì)選擇一個(gè)已準(zhǔn)備好執(zhí)行的warp塊,并將指令發(fā)送到該warp塊的活動(dòng)線程。Warp塊每次執(zhí)行一條通用指令,因此在warp塊的全部32個(gè)線程執(zhí)行同一條路徑時(shí),可達(dá)到最高效率。如果一個(gè)warp塊的線程通過(guò)獨(dú)立于數(shù)據(jù)的條件分支而分散,warp塊將連續(xù)執(zhí)行所使用的各分支路徑,而禁用未在此路徑上的線程,完成所有路徑時(shí),線程重新匯聚到同一執(zhí)行路徑下,其執(zhí)行時(shí)間為各時(shí)間總和。分支僅在warp塊內(nèi)出現(xiàn),不同的warp塊總是獨(dú)立執(zhí)行的--無(wú)論它們執(zhí)行的是通用的代碼路徑還是彼此無(wú)關(guān)的代碼路徑。
建議的數(shù)值?
在 Compute Capability 1.0/1.1 中,每個(gè) SM 最多可以同時(shí)管理 768 個(gè) thread(768 active threads)或 8 個(gè) block(8 active blocks);而每一個(gè) warp 的大小,則是 32 個(gè) thread,也就是一個(gè) SM 最多可以有 768 / 32 = 24 個(gè) warp(24 active warps)。到了 Compute Capability 1.2 的話,則是 active warp 則是變?yōu)?32,所以 active thread 也增加到 1024。
在這里,先以 Compute Capability 1.0/1.1 的數(shù)字來(lái)做計(jì)算。根據(jù)上面的數(shù)據(jù),如果一個(gè) block 里有 128 個(gè) thread 的話,那一個(gè) SM 可以容納 6 個(gè) block;如果一個(gè) block 有 256 個(gè) thread 的話,那 SM 就只能容納 3 個(gè) block。不過(guò)如果一個(gè) block 只有 64 個(gè) thread 的話,SM 可以容納的 block 不會(huì)是 12 個(gè),而是他本身的數(shù)量限制的 8 個(gè)。
因此在 Compute Capability 1.0/1.1 的硬件上,決定 block 大小的時(shí)候,最好讓里面的 thread 數(shù)目是 warp 數(shù)量(32)的倍數(shù)(可以的話,是 64 的倍數(shù)會(huì)更好);而在一個(gè) SM 里,最好也要同時(shí)存在復(fù)數(shù)個(gè) block。如果再希望能滿足最多 24 個(gè) warp 的情形下,block 里的 thread 數(shù)目似乎會(huì)是 96(一個(gè) SM 中有 8 個(gè) block)、128(一個(gè) SM 中有 6 個(gè) block)、192(一個(gè) SM 中有 4 個(gè) block)、256(一個(gè) SM 中有 3 個(gè) block) 這些數(shù)字了~
Compute Capability 1.0/1.1 的硬件上,每個(gè)grid最多可以允許65535×65535個(gè)block。每個(gè)block最多可以允許512個(gè)thread,但是第三維上的最大值為64。而官方的建議則是一個(gè) block 里至少要有 64 個(gè) thread,192 或 256 個(gè)也是通常比較合適的數(shù)字(請(qǐng)參考 Programming Guide)。
但是是否這些數(shù)字就是最合適的呢?其實(shí)也不盡然。因?yàn)閷?shí)際上,一個(gè) SM 可以允許的 block 數(shù)量,還要另外考慮到他所用到 SM 的資源:shared memory、registers 等。在 G80 中,每個(gè) SM 有 16KB 的 shared memory 和 8192 個(gè) register。而在同一個(gè) SM 里的 block 和 thread,則要共享這些資源;如果資源不夠多個(gè) block 使用的話,那 CUDA 就會(huì)減少 Block 的量,來(lái)讓資源夠用。在這種情形下,也會(huì)因此讓 SM 的 thread 數(shù)量變少,而不到最多的 768 個(gè)。
比如說(shuō)如果一個(gè) thread 要用到 16 個(gè) register 的話(在 kernel 中宣告的變量),那一個(gè) SM 的 8192 個(gè) register 實(shí)際上只能讓 512 個(gè) thread 來(lái)使用;而如果一個(gè) thread 要用 32 個(gè) register,那一個(gè) SM 就只能有 256 個(gè) thread 了~而 shared memory 由于是 thread block 共享的,因此變成是要看一個(gè) block 要用多少的 shread memory、一個(gè) SM 的 16KB 能分給多少個(gè) block 了。
所以雖然說(shuō)當(dāng)一個(gè) SM 里的 thread 越多時(shí),越能隱藏 latency,但是也會(huì)讓每個(gè) thread 能使用的資源更少。因此,這點(diǎn)也就是在優(yōu)化時(shí)要做取舍的了。
硬件基本架構(gòu) 實(shí)際上在 nVidia 的 GPU 里,最基本的處理單元是所謂的 SP(Streaming Processor),而一顆 nVidia 的 GPU 里,會(huì)有非常多的 SP 可以同時(shí)做計(jì)算;而數(shù)個(gè) SP 會(huì)在附加一些其他單元,一起組成一個(gè) SM(Streaming Multiprocessor)。幾個(gè) SM 則會(huì)在組成所謂的 TPC(Texture Processing Clusters)。
在 G80/G92 的架構(gòu)下,總共會(huì)有 128 個(gè) SP,以 8 個(gè) SP 為一組,組成 16 個(gè) SM,再以兩個(gè) SM 為一個(gè) TPC,共分成 8 個(gè) TPC 來(lái)運(yùn)作。而在新一代的 GT200 里,SP 則是增加到 240 個(gè),還是以 8 個(gè) SP 組成一個(gè) SM,但是改成以 3 個(gè) SM 組成一個(gè) TPC,共 10 組 TPC。下面則是提供了兩種不同表示方式的示意圖。(可參考《NVIDIA G92終極狀態(tài)!!》、《NVIDIA D10U繪圖核心》)
對(duì)應(yīng)到 CUDA
而在 CUDA 中,應(yīng)該是沒(méi)有 TPC 的那一層架構(gòu),而是只要根據(jù) GPU 的 SM、SP 的數(shù)量和資源來(lái)調(diào)整就可以了。
如果把 CUDA 的 Grid - Block - Thread 架構(gòu)對(duì)應(yīng)到實(shí)際的硬件上的話,會(huì)類似對(duì)應(yīng)成 GPU - Streaming Multiprocessor - Streaming Processor;一整個(gè) Grid 會(huì)直接丟給 GPU 來(lái)執(zhí)行,而 Block 大致就是對(duì)應(yīng)到 SM,thread 則大致對(duì)應(yīng)到 SP。當(dāng)然,這個(gè)講法并不是很精確,只是一個(gè)簡(jiǎn)單的比喻而已。
SM 中的 Warp 和 Block
CUDA 的 device 實(shí)際在執(zhí)行的時(shí)候,會(huì)以 Block 為單位,把一個(gè)個(gè)的 block 分配給 SM 進(jìn)行運(yùn)算;而 block 中的 thread,又會(huì)以「warp」為單位,把 thread 來(lái)做分組計(jì)算。目前 CUDA 的 warp 大小都是 32,也就是 32 個(gè) thread 會(huì)被群組成一個(gè) warp 來(lái)一起執(zhí)行;同一個(gè) warp 里的 thread,會(huì)以不同的數(shù)據(jù),執(zhí)行同樣的指令。此外,在 Compute Capability 1.2 的硬件中,還加入了 warp vote 的功能,可以快速的進(jìn)行 warp 內(nèi)的簡(jiǎn)單統(tǒng)計(jì)。
基本上 warp 分組的動(dòng)作是由 SM 自動(dòng)進(jìn)行的,會(huì)以連續(xù)的方式來(lái)做分組。比如說(shuō)如果有一個(gè) block 里有 128 個(gè) thread 的話,就會(huì)被分成四組 warp,第 0-31 個(gè) thread 會(huì)是 warp 1、32-63 是 warp 2、64-95 是 warp 3、96-127 是 warp 4。
而如果 block 里面的 thread 數(shù)量不是 32 的倍數(shù),那他會(huì)把剩下的 thread 獨(dú)立成一個(gè) warp;比如說(shuō) thread 數(shù)目是 66 的話,就會(huì)有三個(gè) warp:0-31、32-63、64-65。由于最后一個(gè) warp 里只剩下兩個(gè) thread,所以其實(shí)在計(jì)算時(shí),就相當(dāng)于浪費(fèi)了 30 個(gè) thread 的計(jì)算能力;這點(diǎn)是在設(shè)定 block 中 thread 數(shù)量一定要注意的事!
一個(gè) SM 一次只會(huì)執(zhí)行一個(gè) block 里的一個(gè) warp,但是 SM 不見(jiàn)得會(huì)一次就把這個(gè) warp 的所有指令都執(zhí)行完;當(dāng)遇到正在執(zhí)行的 warp 需要等待的時(shí)候(例如存取 global memory 就會(huì)要等好一段時(shí)間),就切換到別的 warp 來(lái)繼續(xù)做運(yùn)算,藉此避免為了等待而浪費(fèi)時(shí)間。所以理論上效率最好的狀況,就是在 SM 中有夠多的 warp 可以切換,讓在執(zhí)行的時(shí)候,不會(huì)有「所有 warp 都要等待」的情形發(fā)生;因?yàn)楫?dāng)所有的 warp 都要等待時(shí),就會(huì)變成 SM 無(wú)事可做的狀況了~
下圖就是一個(gè) warp 排程的例子。一開(kāi)始是先執(zhí)行 thread block 1 的 warp1,而當(dāng)他執(zhí)行到第六行指令的時(shí)候,因?yàn)樾枰却?#xff0c;所以就會(huì)先切到 thread block 的 warp2 來(lái)執(zhí)行;一直等到存取結(jié)束,且剛好有一個(gè) warp 結(jié)束時(shí),才繼續(xù)執(zhí)行 TB1 warp1 的第七行指令。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
登錄/注冊(cè)后可看大圖 實(shí)際上,warp 也是 CUDA 中,每一個(gè) SM 執(zhí)行的最小單位;如果 GPU 有 16 組 SM 的話,也就代表他真正在執(zhí)行的 thread 數(shù)目會(huì)是 32*16 個(gè)。不過(guò)由于 CUDA 是要透過(guò) warp 的切換來(lái)隱藏 thread 的延遲、等待,來(lái)達(dá)到大量平行化的目的,所以會(huì)用所謂的 active thread 這個(gè)名詞來(lái)代表一個(gè) SM 里同時(shí)可以處理的 thread 數(shù)目。
而在 block 的方面,一個(gè) SM 可以同時(shí)處理多個(gè) thread block,當(dāng)其中有 block 的所有 thread 都處理完后,他就會(huì)再去找其他還沒(méi)處理的 block 來(lái)處理。假設(shè)有 16 個(gè) SM、64 個(gè) block、每個(gè) SM 可以同時(shí)處理三個(gè) block 的話,那一開(kāi)始執(zhí)行時(shí),device 就會(huì)同時(shí)處理 48 個(gè) block;而剩下的 16 個(gè) block 則會(huì)等 SM 有處理完 block 后,再進(jìn)到 SM 中處理,直到所有 block 都處理結(jié)束。
為一個(gè)多處理器指定了一個(gè)或多個(gè)要執(zhí)行的線程塊時(shí),它會(huì)將其分成warp塊,并由SIMT單元進(jìn)行調(diào)度。將塊分割為warp的方法總是相同的,每個(gè)warp都包含連續(xù)的線程,遞增線程索引,第一個(gè)warp中包含全局線程過(guò)索引0-31。每發(fā)出一條指令時(shí),SIMT單元都會(huì)選擇一個(gè)已準(zhǔn)備好執(zhí)行的warp塊,并將指令發(fā)送到該warp塊的活動(dòng)線程。Warp塊每次執(zhí)行一條通用指令,因此在warp塊的全部32個(gè)線程執(zhí)行同一條路徑時(shí),可達(dá)到最高效率。如果一個(gè)warp塊的線程通過(guò)獨(dú)立于數(shù)據(jù)的條件分支而分散,warp塊將連續(xù)執(zhí)行所使用的各分支路徑,而禁用未在此路徑上的線程,完成所有路徑時(shí),線程重新匯聚到同一執(zhí)行路徑下,其執(zhí)行時(shí)間為各時(shí)間總和。分支僅在warp塊內(nèi)出現(xiàn),不同的warp塊總是獨(dú)立執(zhí)行的--無(wú)論它們執(zhí)行的是通用的代碼路徑還是彼此無(wú)關(guān)的代碼路徑。
建議的數(shù)值?
在 Compute Capability 1.0/1.1 中,每個(gè) SM 最多可以同時(shí)管理 768 個(gè) thread(768 active threads)或 8 個(gè) block(8 active blocks);而每一個(gè) warp 的大小,則是 32 個(gè) thread,也就是一個(gè) SM 最多可以有 768 / 32 = 24 個(gè) warp(24 active warps)。到了 Compute Capability 1.2 的話,則是 active warp 則是變?yōu)?32,所以 active thread 也增加到 1024。
在這里,先以 Compute Capability 1.0/1.1 的數(shù)字來(lái)做計(jì)算。根據(jù)上面的數(shù)據(jù),如果一個(gè) block 里有 128 個(gè) thread 的話,那一個(gè) SM 可以容納 6 個(gè) block;如果一個(gè) block 有 256 個(gè) thread 的話,那 SM 就只能容納 3 個(gè) block。不過(guò)如果一個(gè) block 只有 64 個(gè) thread 的話,SM 可以容納的 block 不會(huì)是 12 個(gè),而是他本身的數(shù)量限制的 8 個(gè)。
因此在 Compute Capability 1.0/1.1 的硬件上,決定 block 大小的時(shí)候,最好讓里面的 thread 數(shù)目是 warp 數(shù)量(32)的倍數(shù)(可以的話,是 64 的倍數(shù)會(huì)更好);而在一個(gè) SM 里,最好也要同時(shí)存在復(fù)數(shù)個(gè) block。如果再希望能滿足最多 24 個(gè) warp 的情形下,block 里的 thread 數(shù)目似乎會(huì)是 96(一個(gè) SM 中有 8 個(gè) block)、128(一個(gè) SM 中有 6 個(gè) block)、192(一個(gè) SM 中有 4 個(gè) block)、256(一個(gè) SM 中有 3 個(gè) block) 這些數(shù)字了~
Compute Capability 1.0/1.1 的硬件上,每個(gè)grid最多可以允許65535×65535個(gè)block。每個(gè)block最多可以允許512個(gè)thread,但是第三維上的最大值為64。而官方的建議則是一個(gè) block 里至少要有 64 個(gè) thread,192 或 256 個(gè)也是通常比較合適的數(shù)字(請(qǐng)參考 Programming Guide)。
但是是否這些數(shù)字就是最合適的呢?其實(shí)也不盡然。因?yàn)閷?shí)際上,一個(gè) SM 可以允許的 block 數(shù)量,還要另外考慮到他所用到 SM 的資源:shared memory、registers 等。在 G80 中,每個(gè) SM 有 16KB 的 shared memory 和 8192 個(gè) register。而在同一個(gè) SM 里的 block 和 thread,則要共享這些資源;如果資源不夠多個(gè) block 使用的話,那 CUDA 就會(huì)減少 Block 的量,來(lái)讓資源夠用。在這種情形下,也會(huì)因此讓 SM 的 thread 數(shù)量變少,而不到最多的 768 個(gè)。
比如說(shuō)如果一個(gè) thread 要用到 16 個(gè) register 的話(在 kernel 中宣告的變量),那一個(gè) SM 的 8192 個(gè) register 實(shí)際上只能讓 512 個(gè) thread 來(lái)使用;而如果一個(gè) thread 要用 32 個(gè) register,那一個(gè) SM 就只能有 256 個(gè) thread 了~而 shared memory 由于是 thread block 共享的,因此變成是要看一個(gè) block 要用多少的 shread memory、一個(gè) SM 的 16KB 能分給多少個(gè) block 了。
所以雖然說(shuō)當(dāng)一個(gè) SM 里的 thread 越多時(shí),越能隱藏 latency,但是也會(huì)讓每個(gè) thread 能使用的資源更少。因此,這點(diǎn)也就是在優(yōu)化時(shí)要做取舍的了。
總結(jié)
以上是生活随笔為你收集整理的cuda-Block和Grid设定的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 最优的cuda线程配置
- 下一篇: 动态引入js只能生效一次_动态插入的sc