我一直在与cuda进行一场生活游戏。我想找到每个元素的数组索引,以便我可以计算该元素的邻居,以便我可以将新值写入该数组。我发现的关于这一切的所有东西都在使用指向行的指针而我无法弄清楚它是如何准确转换为索引的。为了更好地了解我的意思,我必须遵循代码(一些片段):
#define THREADSPERBLOCK 1024
lifeState *d_gameStateInitial;
size_t d_gameStateInitial_pitch;
int sizeX = 100;
int sizeY = 100;
int numBlocks = ((sizeX * sizeY) % THREADSPERBLOCK) + 1;
int numThreadsPerBlock;
if(numBlocks == 1)
{
numThreadsPerBlock = sizeX * sizeY;
}
else
{
numThreadsPerBlock = THREADSPERBLOCK;
}
cudaMallocPitch((void **)&d_gameStateInitial, &d_gameStateInitial_pitch, sizeX * sizeof(lifeState), sizeY);
doTheGame<<<numBlocks, numThreadsPerBlock>>>(d_gameStateInitial, d_gameStateInitial_pitch, d_gameStateNew, d_gameStateNew_pitch, sizeX, sizeY);
“lifestate *”只是一个包含死/活枚举的结构。两个阵列,初始阵列和新阵列都是完全相同的malloc。在doTheGame内核中,我现在想知道如何计算索引,我正在考虑这样的事情,但我认为这是错误的:
__global__ void doTheGame(lifeState *initialArray, size_t initialArrayPitch,
lifeState *newArray, size_t newArrayPitch,
int sizeX, int sizeY)
{
int initialArrayThreadIndex = (blockIdx.x * initialArrayPitch) + threadIdx.x;
int newArrayThreadIndex = (blockIdx.x * initialArrayPitch) + threadIdx.x;
}
到目前为止我找到的所有内容基本上与cudaMallocPitch示例完全相同:
T* pElement = (T*)((char*)BaseAddress + Row * pitch) + Column;
但我不知道这是如何转换为块,线程以及x和y的确切。
提前致谢。
答案 0 :(得分:3)
假设我有一个double data[]
数组,如下所示:
A B C D x x x x
E F G H x x x x
然后data[0] = A
,data[1] = B
等
这可能是分配一个间距分配为64字节的2x4数组的结果(因此每行中有4个额外的x
个条目)。我们假设上面数组中的每个元素都是double
数量。
现在假设我有一个内核,我正在启动一个2x4线程的数组,每个有效元素一个(x
元素无效 - 它们是满足音高要求的额外分配,这是任意的为此示例选择为64字节)。
在这个内核中,我可以创建一个x和y索引,如下所示:
int idx = threadIdx.x +blockDim.x * blockIdx.x;
int idy = threadIdx.y +blockDim.y * blockIdx.y;
然后,每个线程可以按如下方式访问其各自的元素。
由于pitch
返回的cudaMallocPitch
数量以字节为单位,我们需要先使用char
指针算法计算行偏移量:
double *rowptr = (double *)((char *)data + idy*pitch);
然后我们可以像这样访问该行上的元素:
rowptr[idx] = 0.0;
如果我想让线程访问与其线程索引相对应的元素以外的元素,则计算类似。
例如,要在上面的G
数组中将元素data
(即元素(1,2))设置为零,我可以这样做:
double *rowptr = (double *)((char *)data + 1*pitch);
rowptr[2] = 0.0;