http://blog.csdn.net/OpenHero/article/details/3520578 关于CUDA的global内存访问的问题,怎么是访问的冲突,怎样才能更好的访问内存,达到更高的速度。下面先看几张图,这些图都是CUDA编程手册上的图,然后分别对这些图做解释,来理解硬件1.0,1.1 以及现在最新的硬件的访问内存的区别。 我们在这里再深入的讲解一下global内存对齐的问题,每次执行一条明命令的时候,都是会按照32个thread为一个warp,一起来执行,但是在执行的时候,又会按照硬件的条件(这里有两个限制条件,一个是内存访问的时钟和执行core的时钟不一样,第二个是为了细粒度的分支的问题)然后就会把16个thread组成的half-warp来一次访问global内存才能让访问内存的性能高一些,这个可以理解; 就像手册上说的那样,如果16个thread(half-warp)访问内存的时候,如果每一个thread访问32bits就是4个字节,那么就可以合并为一个64bytes的访问,手册上这点写得有点让人咋一看不太明白~4bytes(32bits)*16 = 64bytes,就是这么来的,如果每一个thread访问64bits(8个bytes),那么就可以合并为128bytes的访问;这里啦,由于合并访问的最大限制是128bytes,所以最大也按照128bytes一次访问来合并,如果超过,就得多次访问,或者如果没有按照这样的方式对齐访问,也会多次访问;下面是1.2device之前的访问的几个图,这里要把1.2device以前和以后的分开,是因为这里在对齐访问的方式的时候,有不同的策略;先看1.2device以前的能合并为一次访问的情况: 下图是编程手册上的图: 这里的每一个thread都是访问的对应的地址,是对齐的,所以可以合并为一个存储event; 下面这个图是没有对齐访问,就造成了non-coalesced访问的问题,下面可以看图说话: 左边的那个好理解,中间对应的thread访问的地址交叉了,thread3和thread4交叉访问了,在硬件1.2版本之前的都会造成Non-Coalesced访问; 详细的需要说明的是右边的为什么也造成了Non-Coalesced(非对齐)访问,这个是基础问题,大家理解的内存对齐是怎么样的?按照固定思路,或者教材上强调的都是中间过程的内存访问的对齐,但是内存是从offset 0x00000000位置开始的,就是偏移量0开始的,如果要真的满足内存对齐,严格的说起来就需要从内存的0地址开始算起,再加上我们知道的global内存的对齐方式有几种,4位bytes,8bytes,16bytes,这里说的对齐方式,注意区别关系;再来看看右边的那个图:thread0开始,从address128的位置开始向下便宜的位置是?132-128=4 偏移了4,16个threads整体访问的是16*4=64,是从132开始的,从0算起来,132-0 =132; 132/16 = 8…4,从整体上讲,从0偏移位置开始,偏移了4个位置,这里的就造成了访问的未对齐,这个是从整体角度上讲的,和左边的图比较一下,那个是按照局部对齐来说的,注意理解; 继续看图说话: 左边的图看看,算一下,局部的时候偏移了,从局部和整体来说,都会引起未对齐访问; 右边的图自己算一下,是不是超出了刚才我说的范围;所以造成了内存访问的未对齐情况; 前面我们看的图都是1.2版本前的硬件的情况下的内存访问情况,现在看看1.2版本以后的硬件; 这里解释一下,什么叫1.2版本的硬件,或许有些朋友也不太了解,g80架构的都是1.0或者1.1的硬件架构,现在的gtx200系列的都是1.3的架构,其实1.2的硬件架构,或许是Nvidia的一个内部的,没有推出产品,可能准备提供给低端的产品,但是我想没有推出低端的产品,直接就上1.3device了,市场需求吧~~如果下一步GTX的架构还是按照老路子,不改进的话,或许Intel的Lrb上来以后,对Nvidia的产品,就是一个很大的竞争了; 不说废话了,先看图: 1.2以后的硬件版本,弱化了threads之间交叉访问的时候,没对齐的情况,只要大家都在一次访问的64bytes的一个段里面,或者128bytes的一个段里面面,这样的段访问,那就可以不用多次访问,当然如果你16个threads分别跨过了16个段,那就得产生16个存储event~记住几个段的定义,这里说的段,就是我们常常理解的对齐的方式,全局的内存访问对齐方式,8个bits的是按照32bytes对齐,16bits的是按照64bytes对齐,32bits和64bits都是按照128bytes对齐; 在优化代码的时候,这个地方是一个值得注意的部分; API函数里面有对齐访问的接口,会按照对齐的方式分配global内存给你,不过注意其中的一个offset值的使用,这个是为了解决全局情况下的对齐偏移的问题:)cudaMallocPitch,这个函数,注意使用~