如果Cuda共享每个元素的类型大小小于4/8字节的存储器阵列,是否应手动填充到存储区大小?

时间:2018-01-29 12:39:18

标签: cuda

那么,我的意思是,为了避免银行冲突或者NVCC编译器会处理这个问题,应该__shared__ char a[10]填充__shared__ char a[10][4]之类的内容吗?

1 个答案:

答案 0 :(得分:2)

编译器不填充数组。您可以printf每个元素的地址并自行检查。

手动填充也不是必需的,因为访问1字节数组不会产生库冲突。只有访问具有不同字地址的同一个银行才会导致银行冲突。访问具有相同字地址的同一银行是由底层硬件的广播机制处理的,这种情况不是银行冲突。

减少银行冲突是降低执行速度的有效方法,因为如果存在银行冲突,硬件将不得不多次访问同一银行。但是,硬件足够聪明,可以处理不同线程对相同字地址的访问,它只获取一次字并广播所访问的数据,而不是每次为每个线程获取4字节字。

也就是说,在任何情况下,访问__shared__ char a[10]都不符合银行冲突的条件。这是因为位置[0,1,2,3]都属于相同的字地址。它们都在4字节长度的存储器元素内。所以,是的,他们确实访问同一个银行,但由于他们访问相同的字地址,因此硬件足够智能,只需将访问的数据分发到每个线程。请注意,它是处理广播的硬件,而不是编译器。

提及32个线程同时访问共享内存可能会有所帮助。这个32个线程的单元称为 warp ,warp是执行单元。

考虑__shared__ int b[64]

// case 1 - Not a bank conflict.
{
    int warpIdx = threadIdx.x % 32;
    b[warpIdx] = 1;
}

// case 2 - Bank conflict.
{
    int warpIdx = threadIdx.x % 32;
    int accessIdx = warpIdx * 2;
    b[accessIdx] = 1;
}

在案例2中,经线(thread n)中的thread n+160 <= n < 16访问具有不同地址的同一银行,从而导致银行冲突。