Cuda GPU共享内存实例

Cuda GPU共享内存实例,cuda,gpu-shared-memory,bank-conflict,Cuda,Gpu Shared Memory,Bank Conflict,我有这样一个数组: data[16] = {10,1,8,-1,0,-2,3,5,-2,-3,2,7,0,11,0,2} 我想使用G80 GPU上的共享内存计算此阵列的缩减量 在英伟达文献中引用的内核如下: __global__ void reduce1(int *g_idata, int *g_odata) { extern __shared__ int sdata[]; unsigned int tid = threadIdx.x; unsigned int i = blockIdx.x

我有这样一个数组:

data[16] = {10,1,8,-1,0,-2,3,5,-2,-3,2,7,0,11,0,2}
我想使用G80 GPU上的共享内存计算此阵列的缩减量

<>在英伟达文献中引用的内核如下:

__global__ void reduce1(int *g_idata, int *g_odata) {
extern __shared__ int sdata[];

unsigned int tid = threadIdx.x;
unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
sdata[tid] = g_idata[i];
__syncthreads();

// here the reduction :

for (unsigned int s=1; s < blockDim.x; s *= 2) {
int index = 2 * s * tid;
if (index < blockDim.x) {
sdata[index] += sdata[index + s];
}
__syncthreads();
}
\uuuuu全局\uuuuuu无效缩减1(int*g\u idata,int*g\u odata){
外部共享数据数据[];
unsigned int tid=threadIdx.x;
无符号整数i=blockIdx.x*blockDim.x+threadIdx.x;
sdata[tid]=g_idata[i];
__同步线程();
//以下是减少:
for(无符号整数s=1;s
论文作者表示,这种方法存在银行冲突的问题。我试图理解,但不明白为什么?我知道银行冲突的定义和广播访问,但仍然无法理解


G80处理器是第一代CUDA GPU中非常古老的支持CUDA的GPU,其计算能力为1.0。这些设备不再受最新CUDA版本(6.5之后)的支持,因此在线文档不再包含了解这些设备中银行结构的必要信息

因此,我将从CUDA 6.5 C编程指南中摘录cc 1.x设备的必要信息:

G.3.3.共享内存

共享内存有16个存储组,它们被组织成连续的32位字映射 每个组的带宽为每两个时钟周期32位

对扭曲的共享内存请求分为两个内存请求,每个请求一个 半翘曲,是独立发行的。因此,不可能有银行 属于曲线段前半部分的线与属于曲线段的线之间的冲突 同一经线的后半部分

在这些设备中,共享内存有16个存储库结构,这样每个存储库都有一个“宽度”32位或4字节。例如,每个存储组的宽度与
int
float
数量相同。因此,让我们设想可能存储在这种共享内存中的前32个4字节数量及其对应的存储组(使用
f
而不是
sdata
作为数组名称):

共享内存中的前16个
int
数量属于组0到15,共享内存中的下16个
int
数量也属于组0到15(依此类推,如果
int
数组中有更多数据)

现在让我们看一下会触发银行冲突的代码行:

for (unsigned int s=1; s < blockDim.x; s *= 2) {
int index = 2 * s * tid;
if (index < blockDim.x) {
sdata[index] += sdata[index + s];
}
因此,对于此读取操作:

+= sdata[index + s]
我们有:

threadIdx.x: 0 1 2 3 4  5  6  7  8  9 10 11 ...
 index:      0 2 4 6 8 10 12 14 16 18 20 22 ...
 index + s:  1 3 5 7 9 11 13 15 17 19 21 23 ...
 bank:       1 3 5 7 9 11 13 15  1  3  5  7 ...
因此,在前16个线程中,我们有两个线程想要从气缸组1中读取,两个线程想要从气缸组3中读取,两个线程想要从气缸组5中读取,等等。因此,这个读取周期在前16个线程组中遇到了双向气缸组冲突。请注意,在同一行代码上的其他读取和写入操作类似于气缸组冲突冲突:

sdata[index] +=
因为这将在每组16个线程中读取和写入组0、2、4等两次


请阅读本示例的其他人注意:如前所述,本示例仅适用于cc 1.x设备。在cc 2.x和更新的设备上演示银行冲突的方法可能类似,但由于扭曲执行的差异以及这些更新的设备具有32路银行结构而不是16路银行结构。

假设您的
blockDim.x
也是16路,G80上的数据大小为16不会有任何银行冲突。我很确定本文作者没有考虑到您的示例。数据大小至少为32,而
blockDim.x
至少为32,不难演示b是如何实现的ank冲突发生在G80上。我使用的示例与本文中使用的示例相同(我使用的示例与本文中使用的示例相同)。我在第11页中讨论了该方法(你可以从我刚才在问题中添加的图片中看到。请你演示一下银行冲突是如何产生的,共有32个要素?非常感谢@Robert Crovella这是我花了很多时间理解的对问题的非常清楚的解释。非常感谢亲爱的Rober先生@Robert Crovella
threadIdx.x: 0 1 2 3 4  5  6  7  8  9 10 11 ...
 index:      0 2 4 6 8 10 12 14 16 18 20 22 ...
 index + s:  1 3 5 7 9 11 13 15 17 19 21 23 ...
 bank:       1 3 5 7 9 11 13 15  1  3  5  7 ...
sdata[index] +=