假设我有以下CUDA内核,启动时有256个块,每个块有256个线程。 nElem
为256*256
,elems
在设备全局内存中分配。该设备支持缓存(Fermi或以上),UVA有效。如您所见,elems
不是volatile
。
__global__ void simpleGPUKernel(int* elems, int nElem) {
unsigned int tid = (blockIdx.x * blockDim.x) + threadIdx.x;
for ( unsigned int i = tid; i < nElem; i += blockDim.x*gridDim.x){
elems[ i ] = i;
}
}
根据我的理解,在每个块的末尾,因为没有数据依赖,同步或防护,L2更新设备内存的时间无法确定,并且主要取决于缓存大小(因为LRU)策略)和其他线程引起的内存访问频率。我对么?
因为没有必要等待实际的内存地址快速更新,所以在elems[ i ] = i;
指令之后,SM warp调度程序在不关心实际设备内存是否更新的情况下运行更多指令块中的warp(在上面的情况下在for
循环中添加和比较)结束块,并为最近释放的资源分配另一个块。在描述的过程中,SM正在享受指令级并行性,并且没有保证设备存储器中的elems[ i ]
被更新。我对此是否正确?
如果在L1中缓存了任何内容,则必须在块的生命周期结束之前在L2中更新它。这是对的吗?
除了从L2更新实际内存的速度之外,如果分配的内存位于主机内存或对等设备全局内存中,上述过程是否有任何区别?
答案 0 :(得分:1)
AFAIK,在子弹1和2上,你是对的。
对于你的子弹3,L1中的数据不必在块之后(通过块,我相信你的意思是线程块)写回L2。原因是,所有写访问总是转到L2,使L1中可能存在的数据无效。
对于你的子弹4.不,我认为没有任何区别。