[英]Flattening a 3D array to 1D in cuda
我嘗試在cuda中實現以下代碼,但是在cuda中將3D數組展平為1D時遇到問題
C ++代碼
for(int i=0; i<w; i++)
for(int j=0; j<h; j++)
for(int k=0; k<d; k++)
arr[h*w*i+ w*j+ k] = (h*w*i+ w*j+ k)*2;
這是我到目前為止在Cuda擁有的
int w = h = d;
int N = 64;
__global__ void getIndex(float* A)
{
int i = blockIdx.x;
int j = blockIdx.y;
int k = blockIdx.z;
A[h*w*i+ w*j+ k] = h*w*i+ w*j+ k;
}
int main(int argc, char **argv)
{
float *d_A;
cudaMalloc((void **)&d_A, w * h * d * sizeof(float) );
getIndex <<<N,1>>> (d_A);
}
但是我沒有得到期望的結果,我不知道如何獲得正確的i,j
和k
索引
考慮尺寸的3D問題w
X h
X d
。 (這可能是一個簡單的數組,必須像在您的問題或任何其他易於並行化的3D問題中一樣進行設置。)我將使用您的簡單設置任務進行演示。
使用CUDA內核處理此問題的最簡單方法是為每個數組條目啟動一個線程,即w*h*d
線程。 這個答案討論了為什么每個元素一個線程可能並不總是最好的解決方案。
現在讓我們看一下下面的代碼行
dim3 numThreads(w,h,d);
getIndex <<<1, numThreads>>> (d_A, w, h, d);
在這里,我們正在啟動一個總共有w*h*d
線程的內核。 內核可以實現為
__global__ void getIndex(float* A, int w, int h, int d) // we actually do not need w
{
int i = threadIdx.x;
int j = threadIdx.y;
int k = threadIdx.z;
A[h*d*i+ d*j+ k] = h*d*i+ d*j+ k;
}
但是該內核和內核調用存在一個問題:每個線程塊的線程數是有限的(“特定方向上的線程數”也有界= z方向通常是最大界)。 因為我們只調用一個線程塊,所以我們的問題大小不能超過這些特定限制(例如w*h*d <= 1024
)。
這就是線程塊的用途。 實際上,您可以根據需要啟動具有多個線程的內核。 (這是不正確的,但是線程塊最大數量的限制不太可能用盡。)
以這種方式調用內核:
dim3 numBlocks(w/8,h/8,d/8);
dim3 numThreads(8,8,8);
getIndex <<<numBlocks, numThreads>>> (d_A, w, h, d);
將為w/8 * h/8 * d/8
線程塊啟動內核,而每個塊包含8*8*8
線程。 因此總共將調用w*h*d
線程。 現在我們必須相應地調整內核:
__global__ void getIndex(float* A, int w, int h, int d) // we actually do not need w
{
int bx = blockIdx.x;
int by = blockIdx.y;
int bz = blockIdx.z;
int tx = threadIdx.x;
int ty = threadIdx.y;
int tz = threadIdx.z;
A[h*d*(8*bx + tx)+ d*(8*by + ty)+ (8*bz + tz)] = h*d*(8*bx + tx)+ d*(8*by + ty)+ (8*bz + tz);
}
注意:
blockDim.x
而不是固定大小8
和gridDim.x
編寫更通用的內核,以通過gridDim.x*blockDim.x
計算w
。 其他兩個維度也同樣處理。 w
, h
和d
必須為8的倍數。您還可以泛化內核以允許每個維度。 (然后,您必須將所有三個維度解析到內核,以檢查計算出的位置是否仍在問題范圍之內。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.