:ここ
はいくつかの素晴らしい源です。最も簡単なケースは1D:
shmem[threadIdx.x] = gmem[blockDim.x * blockIdx.x + threadIdx.x];
です。これは合併されています。私が使用する経験則は、ブロックオフセット(blockDim * blockIdx)とのオフセットとして、最も急速に変化する座標(threadIdx)が追加されていることです。最終的には、ブロック内のスレッド間のインデックス化ストライドが1になります。ストライドが大きくなると、結合が失われます。
単純ルール(Fermi以降のGPU)では、ワープ内のすべてのスレッドのアドレスが同じ整列した128バイトの範囲に入ると、1回のメモリトランザクションが発生しますこれはデフォルトです)。 2つの128バイト範囲に整列すると、2つのメモリトランザクションが発生します。
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、2次元グリッド、1Dのブロック:
int elementPitch = blockDim.x * gridDim.x;
shmem[threadIdx.x] = gmem[blockIdx.y * elementPitch +
blockIdx.x * blockDim.x + threadIdx.x];
合体、2Dグリッドとブロック:
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