[英]What is the best way to launch a GPU kernel to do calculation on a 3D data set?
我正在使用CUDA對可能較大的3D數據集進行計算。 我認為最好先看到一個簡短的代碼片段:
void launch_kernel(/*arguments . . . */){
int bx = xend-xstart, by = yend-ystart, bz = zend-zstart;
dim3 blocks(/*dimensions*/);
dim3 threads(/*dimensions*/);
kernel<<blocks, threads>>();
}
我有一組3D單元,我需要啟動一個內核來計算每個單元。 問題在於輸入大小可能超過GPU的能力,尤其是線程。 所以這樣的代碼:
void launch_kernel(/*arguments . . . */){
int bx = xend-xstart, by = yend-ystart, bz = zend-zstart;
dim3 blocks(bx,by,1);
dim3 threads(bz);
kernel<<blocks, threads>>();
}
...效果不好。 因為尺寸為1000x1000x1000怎么辦? -我無法在每個塊中啟動1000個線程。 甚至更好,如果尺寸為5x5x1000? -現在我幾乎沒有啟動任何塊,但是需要以硬件的5x5x512 b / c啟動內核,並且每個線程將執行2次計算。 我也不能僅僅將所有維度混合在一起,將一些z放入塊中,而將某些z放入線程b / c中,我需要能夠識別內核中的維度。 目前:
__global__ void kernel(/*arguments*/){
int x = xstart + blockIdx.x;
int y = ystart + blockIdx.y;
int z = zstart + threadIdx.x;
if(x < xend && y < yend && z < zend){
//calculate
}
}
我需要一種可靠,有效的方法來找出這些變量:
塊x尺寸,塊y尺寸,線程x(以及y?和z?),一旦我通過blockIdx和threadIdx進入內核時的x,y,z,並且,如果輸入超出硬件,則a的數量我在內核計算中的for循環中為每個維度選擇“步驟”。
如有疑問,請詢問。 這是一個棘手的問題,這一直困擾着我(特別是因為我啟動的塊/線程數量是性能的主要組成部分)。 對於不同的數據集,此代碼的決策需要自動化,但我不確定如何有效地做到這一點。 先感謝您。
我認為您在很大程度上使這里的事情復雜化。 基本問題似乎是您需要在1000 x 1000 x 1000計算域上運行內核。 因此,您需要1000000000個線程,這完全在所有CUDA兼容硬件的能力之內。 因此,只需使用至少具有執行計算所需線程數的標准2D CUDA執行網格(如果您不知道該怎么做,請在注釋中添加注釋,然后將其添加到答案中),然后在內核調用中使用一點設置功能是這樣的:
__device__ dim3 thread3d(const int dimx, const int dimxy)
{
// The dimensions of the logical computational domain are (dimx,dimy,dimz)
// and dimxy = dimx * dimy
int tidx = threadIdx.x + blockIdx.x * blockDim.x;
int tidy = threadIdx.y + blockIdx.y * blockDim.y;
int tidxy = tidx + gridDim.x * tidy;
dim3 id3d;
id3d.z = tidxy / dimxy;
id3d.y = tidxy / (id3d.z * dimxy);
id3d.x = tidxy - (id3d.z * dimxy - id3d.y * dimx);
return id3d;
}
[免責聲明:在瀏覽器中編寫,請勿編譯,請勿運行,未經測試。 使用風險自負]。
此函數將從CUDA 2D執行網格返回3D域(dimx,dimy,dimz)中的“邏輯”線程坐標。 在內核開始時調用它,如下所示:
__global__ void kernel(arglist, const int dimx, const int dimxy)
{
dim3 tid = thread3d(dimx, dimxy);
// tid.{xyx} now contain unique 3D coordinates on the (dimx,dimy,dimz) domain
.....
}
請注意,建立該網格有很多整數計算開銷,因此您可能要考慮為什么真正需要3D網格。 您會感到驚訝的是,實際上並不需要很多次,並且可以避免很多設置開銷。
我將首先使用cudaGetDeviceProperties()
查找GPU的計算能力,以便您確切知道GPU允許每個塊有多少個線程(如果您的程序需要通用化以便可以在任何支持CUDA的設備上運行)。
然后,使用該數字,我將在測試輸入尺寸的if
語句中進行大量嵌套。 如果所有尺寸都足夠小,則可以(不大可能)有一個(bx,by,bz)線程塊。 如果這不起作用,則找到可以放入一個塊並根據該塊進行分區的最大尺寸(或兩個尺寸)。 如果這不起作用,則必須對最小尺寸進行分區,以使其一部分適合一個塊,例如(MAX_NUMBER_THREADS_PER_BLOCK,1,1)
線程和(bx/MAX_NUMBER)THREADS_PER_BLOCK,by,bz)
假設bx<by<bz
和bx>MAX_NUMBER_THREADS_PER_BLOCK
。
對於每種情況,您將需要不同的內核,這有點麻煩,但最終還是可以完成的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.