我一直试图在简单的矩阵复制示例中理解线程和块索引模式 http://devblogs.nvidia.com/parallelforall/efficient-matrix-transpose-cuda-cc/
为什么我们在计算y时使用TILE_DIM作为步幅,因为我们知道块大小是(TILE_DIM * BLOCK_ROWS)。此外,我们通过强制每个线程执行TILE_DIM / BLOCK_ROWS副本来分摊计算。我尝试将Threads Per Block视为(4,1),将每网格块视为(2,2),方形矩阵宽度为8.我发现创建的偏移值也超过15,高于矩阵线性(1D)维度。如果可能,请帮助使用示例。我想看一些关于矩阵平铺与摊销的链接教程详细解释。
const int TILE_DIM = 32;
const int BLOCK_ROWS = 8;
__global__ void copy(float *odata, const float *idata)
{
int x = blockIdx.x * TILE_DIM + threadIdx.x;
int y = blockIdx.y * TILE_DIM + threadIdx.y;
int width = gridDim.x * TILE_DIM;
for (int j = 0; j < TILE_DIM; j+= BLOCK_ROWS)
odata[(y+j)*width + x] = idata[(y+j)*width + x];
}
...
const int nx = 1024;
const int ny = 1024;
dim3 dimGrid(nx/TILE_DIM, ny/TILE_DIM, 1);
dim3 dimBlock(TILE_DIM, BLOCK_ROWS, 1);
....
copy<<<dimGrid, dimBlock>>>( ... );
答案 0 :(得分:1)
为什么我们在计算
TILE_DIM
时使用y
作为步幅,因为我们知道我们的块大小为TILE_DIM * BLOCK_ROWS
。
根据您的代码,您将1024x1024
矩阵“平铺”到32x32
个磁贴,每个32x32
元素。这是通过按
dim3 dimGrid(nx/TILE_DIM, ny/TILE_DIM, 1);
此外,您正在对每个4
个子8x32
子区域中的每个区块进行分区。这是通过
dim3 dimBlock(TILE_DIM, BLOCK_ROWS, 1);
正如您所注意到的,每个块都应该复制整个图块。通过使用x
和y
的定义,将索引(y+j)*width + x
重写为
y*width + j*width + x =
(blockIdx.y * TILE_DIM)*width + blockIdx.x * TILE_DIM +
(j+threadIdx.y)*width + threadIdx
第一个词(blockIdx.y * TILE_DIM)*width + blockIdx.x * TILE_DIM
标识索引为(blockIdx.y * TILE_DIM, blockIdx.x * TILE_DIM)
的矩阵元素,而索引blockIdx.x
又是由blockIdx.y
和(j+threadIdx.y)*width + threadIdx.x
标识的拼贴的最高元素。第二个元素threadIdx.x,j+threadIdx.y
标识通用切片中索引为threadIdx.x
的元素。现在,请考虑0
介于TILE_DIM-1
和threadIdx.y
之间,而0
介于BLOCK_ROWS
和for
之间。这解释了为什么您需要j+threadIdx.y
循环,以便(0,TILE_DIM-1)
可以跨越整个时间间隔{{1}}。