何时发生在块级别序列化的原子操作? 如果我有以下代码:
__global__ void sum (int *input){
if ( threadIdx.x == 0)
__shared__ int result = 0;
__syncthreads();
atomicAdd(result,input[threadIdx.x+blockDim.x*blockId.x]);
}
此序列化发生在块级别吗? 我一般不理解“块级序列化”是什么意思,因为据我所知,操作始终由线程执行。
答案 0 :(得分:2)
CUDA中有两种原子操作:
全局内存对网格/内核中的所有线程“可见”(即,全局内存只有一个逻辑视图,并且网格中的所有线程共享同一视图),因此,全局原子(根据需要)会创建设备范围的序列化,通常(*)在L2缓存(设备范围的资源)中得到解决。
从逻辑上讲,共享内存是每个线程块的资源(不同的线程块具有共享内存的不同逻辑视图,即它们自己的共享内存的“私有副本”),实际上是每个SM的资源。因为共享内存在逻辑上是每个线程块的资源,所以只有特定线程块中的线程才具有共享内存的相同“视图”或逻辑副本。因此,执行共享内存原子时,可能发生的“序列化”是线程块级别的序列化(与设备范围的序列化相比)。只有同一个线程块中的线程才可以竞争访问特定的共享内存位置,因为从逻辑上讲,共享内存是每个线程块的单独实体。
在单个线程内,所有指令均在逻辑上进行序列化,并且没有原子操作仅在单个线程内操作的概念。原子要么在逻辑上跨属于单个线程块的线程运行,要么跨网格/内核中的所有线程运行。
当然,所有原子操作都涉及线程之间争用特定位置的竞争。重要的区别是它们是否在竞争访问共享内存中的位置还是全局内存中的位置。
从语法上讲,共享内存原子和全局内存原子之间没有区别(在CUDA C ++中,即CUDA PTX或SASS是不同的情况)。确定原子操作将在共享存储器还是全局存储器上进行,取决于传递给提供更新位置的原子的指针的类型(即数值或逻辑关联)。如果该指针“指向”共享内存,则它是共享内存原子。如果该指针“指向”全局内存,则它是全局内存原子。
原子是documented
(*),最近,nvcc
编译器驱动程序获得了识别某些扭曲范围的原子模式并执行atomic aggregation的功能。当编译器选择这种实现时,可能会争辩说,当编译器选择该惯用法时,扭曲内的原子竞争不会在L2缓存中得到解决。