我对CUDA中最方便的全局和共享内存访问布局有些怀疑。
全球记忆
1)以下内存地址(0,0)
,(0,1)
,(1,0)
和(1,1)
如何排列在CPU内存和GPU内存中?换句话说,它们存储的顺序是什么?
2)哪个是行索引,哪个是(m, n)
中的列索引?
3)通过访问列主要顺序或行主要顺序中的元素来实现全局内存合并吗?
共享内存
1)银行冲突是如何产生的?请通过示例/案例告诉我。
2)在总64K
中配置共享内存和L1的命令是什么以及在哪里找到该命令?
答案 0 :(得分:4)
您的问题的很多部分已在上述评论中得到解答。我只想提供一些对您有用的规则,以及一般对下一个用户有关合并内存访问的规则,共享内存库冲突的一些示例以及避免共享内存库冲突的一些规则
合并内存访问
1D数组 - 1D线程网格
gmem[blockDim.x * blockIdx.x + threadIdx.x]
2D数组 - 2D线程网格
int x = blockIdx.x * blockDim.x + threadIdx.x;
int y = blockIdx.y * blockDim.y + threadIdx.y;
int elementPitch = blockDim.x * gridDim.x;
gmem[y][x] or gmem[y * elementPitch + x]
共享内存银行冲突
为了实现高带宽,共享内存分为独立的银行。通过这种方式,共享内存可以服务于线程的同时访问。每个流式多处理器(SM)具有在32
个存储体中组织的共享存储器。每个存储区的带宽为每两个时钟周期32
位,主机字长为4个字节(32
位):连续32
位字地址分配给连续的存储区。
当两个不同的线程访问同一个银行中的不同的字时,会发生银行冲突。银行冲突会对性能产生负面影响,因为它们会强制执行硬件以序列化对共享内存的访问。请注意,如果不同的线程访问同一个单词中的任何字节,则不会发生冲突。另请注意,之间没有银行冲突 属于不同经线的线程。
快速访问
慢访问
32
个线程访问同一个银行中的32
个不同的字词,以便所有访问都被序列化; 示例1
smem[4]: accesses bank #4 (physically, the fifth one – first row)
smem[31]: accesses bank #31 (physically, the last one – first row)
smem[50]: accesses bank #18 (physically, the 19th one – second row)
smem[128]: accesses bank #0 (physically, the first one – fifth row)
smem[178]: accesses bank #18 (physically, the 19th one – sixth row)
如果warp中的第三个线程访问myShMem[50]
和warp访问myShMem[178]
中的八个线程,那么你就会发生双向冲突并且两个事务被序列化。
示例2
考虑以下类型的访问
__shared__ float smem[256];
smem[b + s * threadIdx.x]
要在同一个warp的两个线程t1
和t2
之间发生银行冲突,必须满足以下条件
b + s * t2 = b + s * t1 + 32 * k, with k positive integer
0 <= t2 - t1 < 32
以上意思
32 * k = s * (t2 - t1)
0 <= t2 - t1 < 32
如果s
是奇数,这两个条件不成立,即没有银行冲突。
示例3
从示例2 ,进行以下访问
smem[b + threadIdx.x]
如果smem
属于32
- 位数据类型,不会导致冲突。但也
extern __shared__ char smem[];
foo = smem[baseIndex + threadIdx.x];
和
extern __shared__ short smem[];
foo = smem[baseIndex + threadIdx.x];
导致没有存储体冲突,因为访问了一个字节/线程,因此访问了同一个字的不同的字节。