码迷,mamicode.com
首页 > 其他好文 > 详细

Share memory中bank conflict问题

时间:2015-05-21 09:07:59      阅读:222      评论:0      收藏:0      [点我收藏+]

标签:cuda   并行计算   share   bank   

Share memory是片上资源,生命周期是整个block中,它的数据读写十分快,有1个cycle latency。在Share memory中,经常存在bank conflict问题,如果没有bank conflict问题,它的数据读写可以和片上的寄存器(Register)一样快。因此,我们需要尽量减少bank conflicts.
首先,什么是bank?我们以capability 1.x为例,Share memory被等分成同等尺寸大小的存储器模式,即banks,以下图为例:
技术分享

每一个bank的带宽为32-bit,即4 bytes。连续的32-bit字节可以被分到连续的bank中去。我们以G80为例,它具有16个banks,所以每一个bank=4-byte address % 16,此外,bank的数量和半个warp的thread数量一致,所以share memory对一个warp的请求,分成了两个先后请求来做,不同的半个warp之间没有bank conflicts。如果同时有两个请求在同一个bank中,就会出现bank conflicts,如下图:
技术分享技术分享

对于share memory,有数据读写有快慢两种情况:

快:1)半个warp的所有threads在同一时刻读写share memory的不同bank。2)半个warp中的所有threads在同一时刻以广播的形式读写share memory中的同一个bank。

慢:半个warp的所有threads在同一时刻读写share memory的多个bank(不是全部),这时必须串行读写。

以G80为例,其share memory具有16个bank,在下面的图示中,只有S为奇数时,才不会存在bank conflicts。
技术分享
技术分享
当s=4时,
技术分享

同样,在存储结构体数据时,也有可能会出现bank conflicts。

例如如下代码存在三路冲突:

struct vector { float x, y, z; };

__shared__ struct vector vectors[32];

struct vector v = vectors[baseIndex + threadIdx.x];

技术分享
因此,对于share memory,最好的读写方式每个thread读取block中连续的元素。

以如下例程为例:

对于一个二维数组,半个warp的threads读取每一列,这存在了16路bank conflicts。
技术分享

我们有两种方式可以解决:

1) 在每一行的后面加一个元素,例如:
技术分享

2)在处理矩阵之前转置矩阵

我们对上一节global memory中的coalescing的例程,作进一步优化,分配额外的一列:
技术分享

代码如下:

__global__ void transpose_exp(float *odata, float *idata, int width, int height){

__shared__ float block[BLOCK_DIM][BLOCK_DIM+1];

unsigned int xIndex = blockIdx.x * BLOCK_DIM + threadIdx.x;

unsigned int yIndex = blockIdx.y * BLOCK_DIM + threadIdx.y;

if( (xIndex < width)&&(yIndex < height) {

unsigned int index_in = xIndex + yIndex * width;

block[threadIdx.y][threadIdx.x] = idata[index_in];

}

__syncthreads();

xIndex = blockIdx.y * BLOCK_DIM + threadIdx.x;

yIndex = blockIdx.x * BLOCK_DIM + threadIdx.y;

if( (xIndex < height)&&(yIndex < width) ){

unsigned int index_out = yIndex * height + xIndex;

odata[index_out] = block[threadIdx.x][threadIdx.y];

}

}

实验结果为:

 128x128: 0.011ms vs. 0.022ms (2.0X speedup)

 512x512: 0.07ms vs. 0.33ms (4.5X speedup)

 1024x1024: 0.30ms vs. 1.92ms (6.4X speedup)

 1024x2048: 0.79ms vs. 6.6ms (8.4X speedup)

我们再来考虑矩阵相乘时,会不会出现bank conflicts问题,判断技巧在于固定k,考虑同一时刻thread的读些问题

1)当在读一个Ms时,在同一时刻,半个warp的16个threads以广播的形式读取同一个bank

for (int k = 0; k < 16; ++k) //ty is constant over a half-warp
Csub += Ms[ty][k] * Ns[k][tx];//here k is fixed over a half-warp

技术分享

2)当在读一个Ns时,在同一时刻,半个warp的16个threads连续读取不同的bank,stride=1.

for (int k = 0; k < 16; ++k) //tx is constant over a half-warp
Csub += Ms[ty][k] * Ns[k][tx];

技术分享

所以综上所述,矩阵相乘的例子并没有bank conflicts问题。

需要注意的是,我们上述所说的均为capability 1.x的情况,在2.x 3.x中,每个share memory有32个bank,具体还是要看技术手册的。

Share memory中bank conflict问题

标签:cuda   并行计算   share   bank   

原文地址:http://blog.csdn.net/qqlu_did/article/details/45883159

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!