在以下矩阵复制内核中合并访问

时间:2018-03-24 20:19:56

标签: cuda gpu

以下内核执行我在本文中遇到的矩阵副本: https://devblogs.nvidia.com/efficient-matrix-transpose-cuda-cc/

__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];
}

我对使用的符号感到困惑。据我所知,数据采用行主格式。 “y”对应于行,“x”对应于列。因此,线性指数计算为data [y] [x] = data [y * width + x];

odata [(y + j)* width + x]如何合并?在行主要中,同一行中的元素位于连续的位置。因此,以时尚方式访问元素,(y,x)(y,x + 1)(y,x + 2)......是连续的。

然而,上面的“j”被添加到似乎没有合并的“y”。 我对这种符号的理解是不正确的还是我在这里遗漏了什么?

1 个答案:

答案 0 :(得分:1)

合并内存事务只需要来自同一warp的线程读取和写入连续的内存块,这可以由单个事务提供。你的代码

int x = blockIdx.x * TILE_DIM + threadIdx.x;
int y = blockIdx.y * TILE_DIM + threadIdx.y;
odata[(y+j)*width + x] = idata[(y+j)*width + x];

生成合并访问,因为j在warp中的每个线程中都是常量。因此访问模式变为:

0. (y * width);             (y * width + 1);             (y * width + 2); .....
1. (y * width + width);     (y * width + width + 1);     (y * width + width + 2); .....
2. (y * width + 2 * width); (y * width + 2 * width + 1); (y * width + 2 * width + 2); .....

在每次warp中,J访问的任何值仍然是带内存的顺序元素,因此读取和写入将合并。