如何确保CUDA中的3D共享数据访问不存在银行冲突

时间:2014-03-04 06:49:41

标签: c cuda

我正在使用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位共享内存库

1 个答案:

答案 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)访问它的线程。红色单元格是您正在使用的填充单元格,任何线程都无法访问它们。

enter image description here