你想要什么,最终取决于你的输入数据是否是一维或二维阵列,以及是否网格和块是一维或二维。最简单的情况都是1D:
shmem[threadIdx.x] = gmem[blockDim.x * blockIdx.x + threadIdx.x];
这是合并。我使用的经验法则是,最快速变化的坐标(threadIdx)被添加到块偏移量(blockDim * blockIdx)的偏移量上。最终的结果是块中线程之间的索引跨度为1.如果跨度变大,则失去聚结。
简单的规则(在Fermi和后来的GPU上)是,如果warp中的所有线程的地址落入相同的128字节范围内,则会导致一个内存事务(假设缓存启用了负载,这是默认的)。如果它们落入两个对齐的128字节范围内,则导致两个内存交易等。
在GT2xx和更早的GPU上,它变得更加复杂。但是你可以在编程指南中找到这些细节。
其他例子:
不合并:
shmem[threadIdx.x] = gmem[blockDim.x + blockIdx.x * threadIdx.x];
不合并,但不是太糟糕的GT200和更高版本:
stride = 2;
shmem[threadIdx.x] = gmem[blockDim.x * blockIdx.x + stride * threadIdx.x];
不合并都:
stride = 32;
shmem[threadIdx.x] = gmem[blockDim.x * blockIdx.x + stride * threadIdx.x];
Coa lesced,2D网格,1D块:
int elementPitch = blockDim.x * gridDim.x;
shmem[threadIdx.x] = gmem[blockIdx.y * elementPitch +
blockIdx.x * blockDim.x + threadIdx.x];
聚结,二维网格和块:
int x = blockIdx.x * blockDim.x + threadIdx.x;
int y = blockIdx.y * blockDim.y + threadIdx.y;
int elementPitch = blockDim.x * gridDim.x;
shmem[threadIdx.y * blockDim.x + threadIdx.x] = gmem[y * elementPitch + x];
这些都不可以被合并,除了在网格中的第一个块。线程按列主要顺序进行编号。 – talonmies 2012-04-26 05:32:35