1Dの場合、CUDAのグローバルメモリの合体したアクセス要件全体をほぼ理解しました。
ただし、2次元の場合には少し行き詰まっています(つまり、2Dブロックで構成された2Dグリッドがあります)。
ベクトルがin_vector
あり、カーネルに合体してアクセスしたいとします。そのようです:
__global__ void my_kernel(float* out_matrix, float* in_vector, int size)
{
int i = blockIdx.x * blockDim.x + threadIdx.x;
int j = blockIdx.y * blockDim.y + threadIdx.y;
// ...
float vx = in_vector[i]; // This is good. Here we have coalesced access
float vy = in_vector[j]; // Not sure about this. All threads in my warp access the same global address. (See explanation)
// ...
// Do some calculations... Obtain result
}
この2Dの場合の私の理解では、ブロック内のスレッドは列を中心に「配置」されています。例:(threadIdx.x、threadIdx.y)表記を想定:
- 最初のワープは次のようになります:(0、0)、(1、0)、(2、0)、...、(31、0)、
- 2番目のワープは次のようになります:(0、1)、(1、1)、(2、1)、...、(31、1)、
- 等々...
この場合in_vector[i]
、同じワープ内の連続する各スレッドが連続するアドレスにアクセスするため、呼び出しによって合体したアクセスが得られます。ただしin_vector[j]
、連続する各スレッドがグローバルメモリ内の同じアドレスにアクセスするため、呼び出しは悪い考えのようです(たとえば、ワープ0のすべてのスレッドはin_vector [0]にアクセスし、32の異なるグローバルメモリ要求が発生します)
私はこれを正しく理解しましたか?もしそうなら、どうすればグローバルメモリに合体してアクセスできますin_vector[j]
か?