在设备上,多个线程取同一个数据会按串行来执行吗?假如这个数据在常数存储器上或者纹理存储器上呢?也是按串行来执行吗?
这个要看“多个线程”是怎么“多个”了。以及,本文不讨论1.x。
如果是同一个sm(smx)上的同一个warp里的32个线程:
(0)它们读取shared memory的同一个位置,总是广播的,不会串行。
(1)它们读取global memory (通过L1 data cache), 是会广播的,不会串行。
(2)它们读取global memory (不通过L1 data cache, 通过L2), 是会广播的,不会串行。
(3)它们读取constant cache的同一bank里的同一位置 (例如读取__global__的参数), 是总是广播的,不会串行。
(4)它们通过constant cache读取global memory里的同一位置,是总是广播的,不会串行。
(5)它们通过constant cache读取global memory里的不同位置,可能会导致串行,也可能有其他情况(手册没有指出这种导致会如何,所以我用了“可能串行”字样”)。
(6)它们通过texture cache进行纹理/表面读取同一纹理元素,应该是广播的。
(7)在计算能力3.0/3.5上通过read only cache读取同一global memory位置(例如__ldg)/同一texel, 应该是广播的。
所以对于同一个warp里的32个线程,读取同一个元素,在2.x和3.x上,应该都不会串行。
下一帖将继续讨论其他情况。
对于同一个SM上的2个warp里多个线程,访问同一位置:
(0)如果该2 warp都访问shared memory的同一位置,warp间会串行, warp内会广播。
(1)如果该2 warp都访问global memory的同一位置(常规路径), warp间会串行,warp内会广播。
(2)如果1个warp访问shared memory, 另外一个访问global memory(常规路径), warp间会串行,warp内会广播。
(3)如果1个warp访问constant cache(不考虑cache miss), 一个warp访问shared memory, warp间会同时进行,warp内请参考上文的访问constant cache情况。
(4)如果1个warp访问constant cache, 一个warp访问global memory(均不考虑cache miss), warp间会同时进行,访问global memory的warp内部会进行广播,访问constant cache的warp内部请参考2#。
(5)如果1个warp访问constant cache, 一个warp进行纹理读取或者读取global memory(通过texture cache / read only cache通道), (均不考虑cache miss), 那么warp间会并行,warp内请参考2#.
(6)如果2个warp都同时访问global memory (一个通过L1, 一个通过texture cache, 均不考虑cache miss), 那么warp间会同时进行,warp内请参考2#。
下文将继续讨论多个SM上的多种访问情况。
如果来自2个SM的2个warp分别:
(a)访问各自shared memory的各自同一位置
或 通过各自L1 cache访问global memory的同一位置
或 通过各自texture cache / readonly cache访问global memory的同一位置
或 各自通过各自的constant cache读取各自的同一位置
那么他们均会warp间同时进行(因为有多组空间上同时存在的硬件), 以及warp请参考2#。
如果多个SM同时访问了L2 cache的同一位置:
例如 bypass L1的读取
或 3.0/3.5上的直接读取(非__ldg)
或 使用了各种cache但miss后导致对L2 cache的读取。
那么手册没有给出情况,我表示我也不知道。
以上是对楼主1#问题的所有可能情况的给予解答。
感谢您莅临CUDAZone China,
祝您使用CUDA愉快。
EDIT: 于原帖发表半个小时后,横扫千军删除了此文中所有手册没有涉及的资料。
LZ您好,这个问题稍稍有点复杂。
首先,您说的多个线程指的是多少个线程?是一个warp?多个warp?还是一个warp里面的数个线程?考虑到访存是以warp为单位执行的(fermi之前是half-warp),而不同warp之间执行一般是不保证相互顺序的,所以这里只考虑一个warp内部的情况,并且先只考虑所有32个线程访问同一个4B的数据。
其次,您这里讨论的读取数据。那么您要读取的数据是不变的,还是会被改变的。如果是后者,那么不能使用constant memory这种cache福利。
第三,不同硬件架构的情况有所不同,下面讨论一般以fermi架构为默认的典型情况。
-----------------------------------正式开始讨论的分割线-------------------------------------------
在前面的前提下,我么考虑一个warp的线程访问同一个4B的数据,行为是如何的。
总体上说,这取决于访存的类型或者说路径,访存粒度等。
1:如果是global memory,又分为两种情况。第一种情况是默认情况,读取过程是L1-L2-global memory。这种情况下,会一次性读取128B的数据,(即使我们实际上只需要4B,但是访存粒度如此。)然后丢弃其余不用的数据,一个warp的32个线程同时拿到数据。此时浪费掉的数据为128B-4B=124B。第二种情况是bypass L1的情况,读取过程是L2-global memory。此时会一次性读取32B数据,丢弃不用的数据,一个warp的32个线程同时拿到数据,浪费了32-4=28B。
2:如果是shared memory,首先您需要将所需数据读入shared memory,其次shared memory是以block为单位有效的,您在读入数据的时候需要考虑这一点。现在假定一个warp的线程需要读取已在shared memory内部,那么一次广播就可以使整个warp的线程同时拿到所需数据。
3:如果是不需改变的数据,并且被constant cache所缓冲,并且一个warp都是访问同样的4B数据,那么也只需一次访问就可以使全部的32个线程都获得所需数据。值得注意的是,constant cache只能提供32bits per warp per 2 clocks per SM的能力,并且必须是所有一个warp内的线程都访问同样的地址,否则效率会大幅降低。
大致如上,纹理cache我不熟悉,请其他人补充。
祝LZ好运。