用于预取的共享内存配置

时间:2013-02-27 10:11:40

标签: cuda nvidia

在我的程序中,我使用共享内存来预取数据。 2D线程块,维度8乘4(32),共享内存的8 * 4 * 8 * sizeof(float4)字节。每个线程在循环中复制8个float4:

inline __device__ void pack(const float4 *g_src, float4 *s_dst, const unsigned int w, const unsigned int d) {
    uint2 indx = { blockIdx.x * blockDim.x + threadIdx.x, blockIdx.y * blockDim.y + threadIdx.y };
    uint2 sindx = { threadIdx.x, threadIdx.y };
    int i;

    for (i = 0; i < d; ++i) s_dst[(sindx.y * blockDim.x + sindx.x) * d + i] = g_src[(w * indx.y + indx.x) * d + i];
} 

其中'w'设置为全局内存缓冲区的宽度(float4s的数量),'d'设置为8(复制的float4的数量)。

是否可以应用此类配置以及内存的进一步使用,导致银行冲突或广播?当线程只复制时,例如5个浮点4,而不是8?

,这也是一个例子

MK

P.S。 相同主题here

1 个答案:

答案 0 :(得分:1)

在预取阶段,将发生银行冲突。例如。第一个warp中的线程ID(计算为threadIdx.x + threadIdx.y * blockDim.x)0,4,8,... 28访问同一个bank。您可以将其视为线程(0,0)和i的线程(4,0)等于0访问属于同一银行的s_dst[0]s_dst[32]

如果在进一步使用期间发生银行冲突取决于您将访问s_dst的方案。

仅当线程同时读取相同的地址时才应用广播机制。

发生了多少次银行冲突取决于d的值。如果d mod 32 == 1没有任何冲突。

修改 恕我直言,在预取阶段避免银行冲突的最佳方法,特别是如果d正在改变,则是在warp之间平等分配工作。假设您需要将n值预取到共享内存,w_id是warp的ID,l_id是warp中的线程ID(从0到31)。预取应该如下所示:

for(int i = l_id + w_id*WARP_SIZE; i < n; i += WARP_SIZE*COUNT_OF_WARPS_IN_BLOCK)
{
    s_dst[i] = ...;
}

但这有助于避免预取期间的银行冲突。正如我已经说过,在进一步使用过程中避免冲突取决于您将访问s_dst的方案。