我正在尝试学习CUDA,我对计算线程索引有些困惑。假设我正在尝试并行处理此循环:
...
for(int x = 0; x < DIM_x; x++){
for(int y = 0; y < DIM_y; y++){
for(int dx = 0; dx < psize; dx++){
array[y*DIM_x + x + dx] += 1;
}
}
}
在PyCUDA中,我设置:
block = (8, 8, 8)
grid = (96, 96, 16)
我所看到的用于并行化循环的大多数示例都是这样计算线程索引的:
int x = blockIdx.x * blockDim.x + threadIdx.x;
int y = blockIdx.y * blockDim.y + threadIdx.y;
int dx = blockIdx.z * blockDim.z + threadIdx.z;
if (x >= DIM_x || y >= DIM_y || dx >= psize)
return;
atomicAdd(&array[y*DIM_x + x + dx], 1)
DIM_x
= 580,DIM_y
= 550,psize
= 50
但是,如果我打印x,我看到创建了具有相同线程ID的多个线程,并且最终结果是错误的。
相反,如果我使用此(3D块的3D网格):
int blockId = blockIdx.x + blockIdx.y * gridDim.x
+ gridDim.x * gridDim.y * blockIdx.z;
int x = blockId * (blockDim.x * blockDim.y * blockDim.z)
+ (threadIdx.z * (blockDim.x * blockDim.y))
+ (threadIdx.y * blockDim.x) + threadIdx.x;
它解决了x的多个相同线程ID问题,但是我不确定如何并行化y和dx。
如果有人可以帮助我了解我要去哪里,并向我展示并行化循环的正确方法,我将不胜感激。
答案 0 :(得分:1)
但是,如果我打印x,则会看到多个线程具有相同的 创建线程ID,最终结果是错误的。
在多维网格中看到具有相同x线程ID的多个线程是很正常的,因为在宿主代码中观察到具有相同x值的循环的多次迭代也很正常。如果结果错误,则与您显示的任何代码无关,即:
#include <vector>
#include <thrust/device_vector.h>
#include <thrust/copy.h>
#include <assert.h>
void host(int* array, int DIM_x, int DIM_y, int psize)
{
for(int x = 0; x < DIM_x; x++){
for(int y = 0; y < DIM_y; y++){
for(int dx = 0; dx < psize; dx++){
array[y*DIM_x + x + dx] += 1;
}
}
}
}
__global__
void kernel(int* array, int DIM_x, int DIM_y, int psize)
{
int x = blockIdx.x * blockDim.x + threadIdx.x;
int y = blockIdx.y * blockDim.y + threadIdx.y;
int dx = blockIdx.z * blockDim.z + threadIdx.z;
if (x >= DIM_x || y >= DIM_y || dx >= psize)
return;
atomicAdd(&array[y*DIM_x + x + dx], 1);
}
int main()
{
dim3 block(8, 8, 8);
dim3 grid(96, 96, 16);
int DIM_x = 580, DIM_y = 550, psize = 50;
std::vector<int> array_h(DIM_x * DIM_y * psize, 0);
std::vector<int> array_hd(DIM_x * DIM_y * psize, 0);
thrust::device_vector<int> array_d(DIM_x * DIM_y * psize, 0);
kernel<<<grid, block>>>(thrust::raw_pointer_cast(array_d.data()), DIM_x, DIM_y, psize);
host(&array_h[0], DIM_x, DIM_y, psize);
thrust::copy(array_d.begin(), array_d.end(), array_hd.begin());
cudaDeviceSynchronize();
for(int i=0; i<DIM_x * DIM_y * psize; i++) {
assert( array_h[i] == array_hd[i] );
}
return 0;
}
编译并运行时
$ nvcc -arch=sm_52 -std=c++11 -o looploop loop_the_loop.cu
$ cuda-memcheck ./looploop
========= CUDA-MEMCHECK
========= ERROR SUMMARY: 0 errors
没有错误,并针对您问题中的宿主代码通过了所有元素的检查。
如果得到的结果不正确,则可能是在运行内核之前初始化设备内存存在问题。否则,我看不到您显示的代码如何发出不正确的结果。
通常,像您的代码一样,执行大量的原子内存事务并不是在GPU上执行计算的最佳方法。使用非原子事务可能需要依赖其他关于问题结构的先验信息(例如图形分解或问题写模式的精确描述)。
答案 1 :(得分:0)
在具有3D块的3D网格中,线程ID为:
unsigned long blockId = blockIdx.x
+ blockIdx.y * gridDim.x
+ gridDim.x * gridDim.y * blockIdx.z;
unsigned long threadId = blockId * (blockDim.x * blockDim.y * blockDim.z)
+ (threadIdx.z * (blockDim.x * blockDim.y))
+ (threadIdx.y * blockDim.x)
+ threadIdx.x;
不是您计算的x
。 x
只是该3D矩阵的x
索引。
有一个不错的备忘单in this blog