我正在使用CUDA对几个相同大小的三维数据集进行一些操作,每个数据集都由浮点数组成。
以下示例:
out[i+j+k]=in_A[i+j+k]*out[i+j+k]-in_B[i+j+k]*(in_C[i+j+k+1]-in_C[i+j+k]);
其中(numCols,numDepth指的是3D集的y和z维度(例如out,in_A,in_C等)和:
int tx=blockIdx.x*blockDim.x + threadIdx.x; int i=tx*numCols*numDepth;
int ty=blockIdx.y*blockDim.y + threadIdx.y; int j=ty*numDepth
int tz=blockIdx.z*blockDim.z + threadIdx.z; int k=tz;
我已经将我的内核设置为在(11,14,4)块上运行,每个块中有(8,8,8)个线程。以这种方式设置,每个线程对应于来自每个数据集的元素。 为了保持我设置内核的方式,我使用3D共享内存来减少in_C的冗余全局读取:
(8x8x9而不是8x8x8,这样也可以加载边缘in_C[i+j+k+1]
)
__shared__ float s_inC[8][8][9];
还有其他Stack Exchange帖子(ex link)和CUDA文档处理2D共享内存并描述了可以做些什么来确保没有库冲突,例如将列维度填充为1并访问共享数组使用threadIdx.y然后使用threadIdx.x,但我找不到一个描述当使用3D情况时会发生什么。
我认为相同的规则适用于2D情况和3D情况,只需在2D方案中考虑它应用Z次。
通过这种思考,通过以下方式访问s_inC
s_inC[threadIdx.z][threadIdx.y][threadIdx.x]=in_C[i+j+k];
会阻止半warp中的线程同时访问同一个bank,并且共享内存应声明为:
__shared__ float s_inC[8][8+1][9];
(省略同步,边界检查,包含极端情况in_C [i + j + k + 1]等)。
前两个假设是否正确并防止银行冲突?
我正在使用Fermi硬件,因此有32个32位共享内存库
答案 0 :(得分:1)
我认为你对银行冲突预防的结论值得怀疑。
假设8x8x8
个线程阻塞,那么就像
__shared__ int shData[8][8][8];
...
shData[threadIdx.z][threadIdx.y][threadIdx.x] = ...
会给没有银行冲突。
与此相反,使用8x8x8
个线程阻止,然后进行类似
__shared__ int shData[8][9][9];
...
shData[threadIdx.z][threadIdx.y][threadIdx.x] = ...
将提供银行冲突。
这由下图说明,其中黄色单元格表示来自相同扭曲的线程。该图报告了每个32
位bank,将其作为元组(threadIdx.x, threadIdy.y, threadIdz.z)
访问它的线程。红色单元格是您正在使用的填充单元格,任何线程都无法访问它们。