簡體   English   中英

啟動GPU內核以對3D數據集進行計算的最佳方法是什么?

[英]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<bzbx>MAX_NUMBER_THREADS_PER_BLOCK

對於每種情況,您將需要不同的內核,這有點麻煩,但最終還是可以完成的。

暫無
暫無

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

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