CUDA程序优化小记(七)
CUDA全称Computer Unified Device Architecture(计算机同一设备架构),它的引入为计算机计算速度质的提升提供了可能,从此微型计算机也能有与大型机相当计算的能力。可是不恰当地使用CUDA技术,不仅不会让应用程序获得提升,反而会比普通CPU的计算还要慢。最近我通过学习《GPGPU编程技术》这本书,深刻地体会到了这一点,并且用CUDA Runtime应用改写书上的例子程序;来体会CUDA技术给我们计算能力带来的提升。
原创文章,反对未声明的引用。原博客地址:http://blog.youkuaiyun.com/gamesdev/article/details/18800465
上一版的程序的性能有进一步的提高,因为使用的是共享存储器和缩减树算法。可是使用共享存储器就要注意有可能出现的bank冲突(bank conflict)问题。这一版程序我们将要采取措施尽量避免bank冲突的发生。
共享存储器是CUDA中常见的一类存储器,它位于每个多处理器内,属于片上存储器(on-chip memory)。访问速度非常快,和寄存器相仿。
warp源于纺织术,意为“经纱”,和“纬纱(weft)”相对。CUDA中的SIMT控制器以warp为单位来调度线程。在CUDA中,warp是介于块(BLOCK)和线程之间的调度单位,一般以32个线程为一个warp。GPU会对每个warp进行并行的操作,如并行访问共享存储器等。
为了最大限度地提升共享存储器的带宽,共享存储器被分为若干个内存块,称作bank。bank的特点是能够被同时访问。这些能够被同时访问的内存可以提升GPGPU程序的并行度。
由于GPU执行的并行性,在使用共享存储器的时候可能会出现Bank冲突。具体表现在一个warp内的多个线程在同一个时刻访问相同的bank。如n个线程在同一时刻访问相同的bank,那么称之为n路bank冲突(n-way bank conflict)。由于对共享存储器的访问是以半warp为单位的,即16个线程访问bank,另外16个线程执行计算,因此在出现bank冲突的时候,这些线程会被串行化(sequentialize)。这显然不符合我们设计程序的初衷。因此我们必须设计程序的访问方式来避免bank冲突。
在上一版程序中,每次缩减步骤都会有bank被多个线程访问。在计算能力1.x规范中,共享存储器分为16个bank;在计算能力2.x和3.x规范中,这一数字为32。因此,在一个warp为32线程的情况下,会出现线程0和线程16、线程32等同时访问bank0,线程1和线程17以及线程33等同时访问bank1,由此造成bank冲突。
为了解决bank冲突,我们需要重新设计计算思路。如下图:
线程1 |
线程2 |