Cuda 用于预取的共享内存配置

Cuda 用于预取的共享内存配置,cuda,nvidia,Cuda,Nvidia,在我的程序中,我使用共享内存来预取数据。一个2D线程块,维度为8×4(32),获得8*4*8*sizeof(float4)字节的共享内存。每个线程在一个循环中复制8个浮点4: 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 + threadI

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

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];
} 
inline\uuu设备\uuuu无效包(常量浮点4*g\u src,浮点4*s\dst,常量无符号整数w,常量无符号整数d){
uint2 indx={blockIdx.x*blockDim.x+threadIdx.x,blockIdx.y*blockDim.y+threadIdx.y};
uint2 sindx={threadIdx.x,threadIdx.y};
int i;
对于(i=0;i
其中,“w”设置为全局内存缓冲区的宽度(以浮点数表示),“d”设置为8(复制的浮点数)

这样的配置和内存的进一步使用是否会导致银行冲突,或者是否会应用广播?如果线程只复制,比如说5个float4s,而不是8个,这种情况也会发生吗

MK

附言。
在预取阶段,将发生相同的主题库冲突。例如,ID为(计算为
threadIdx.x+threadIdx.y*blockDim.x
)0、4、8、。。。28访问同一银行。您可以将其视为属于同一银行的
i
等于0访问
su-dst[0]
su-dst[32]
的线程(0,0)和线程(4,0)

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

只有当线程同时读取相同的地址时,才会应用广播机制

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

编辑: IMHO在预取阶段避免组冲突的最佳方法,特别是在
d
发生变化时,是在各翘曲之间平均分割功。假设您需要将
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] = ...;
}
for(int i=l\u id+w\u id*扭曲大小;i

但这只能帮助避免预取期间的银行冲突。正如我已经说过的,在进一步使用过程中避免冲突取决于您将在预取阶段访问
sdst

的方案,库冲突将发生。例如,ID为(计算为
threadIdx.x+threadIdx.y*blockDim.x
)0、4、8、。。。28访问同一银行。您可以将其视为属于同一银行的
i
等于0访问
su-dst[0]
su-dst[32]
的线程(0,0)和线程(4,0)

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

只有当线程同时读取相同的地址时,才会应用广播机制

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

编辑: IMHO在预取阶段避免组冲突的最佳方法,特别是在
d
发生变化时,是在各翘曲之间平均分割功。假设您需要将
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] = ...;
}
for(int i=l\u id+w\u id*扭曲大小;i

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

是否可以避免银行冲突?展开“for”循环会更好吗?w_id=(threadIdx.x+threadIdx.y*blockDim.x)/32,l_id=(threadIdx.x+threadIdx.y*blockDim.x)%32
n
等于要预取的值的整个计数。根据这一点,寻址全局内存?您必须向由块ID确定的
i
添加一些偏移量,该块ID表示全局内存中属于该块的数据的开头。类似于
g\u src[BLOCK\u ID*n+i]
这样的事情可以在没有银行冲突的情况下完成吗?展开“for”循环会更好吗?w_id=(threadIdx.x+threadIdx.y*blockDim.x)/32,l_id=(threadIdx.x+threadIdx.y*blockDim.x)%32
n
等于要预取的值的整个计数。根据这一点,寻址全局内存?您必须向由块ID确定的
i
添加一些偏移量,该块ID表示全局内存中属于该块的数据的开头。类似于
g\u src[BLOCK\u ID*n+i]