何时以及为何在 CUDA 中使用atomicInc()?

equ*_*all 2 cuda atomic

我一直在阅读 CUDA 中的原子操作,并且更新模式atomicInc()似乎相当任意。

来自CUDA 编程指南

unsigned int atomicInc(unsigned int* address, unsigned int val);
Run Code Online (Sandbox Code Playgroud)

读取位于全局或共享内存中的地址地址的 32 位字 old,计算 ((old >= val) ? 0 : (old+1)),并将结果存储回内存中的同一地址。这三个操作在一个原子事务中执行。该函数返回旧值。

这是增量和“环绕”操作。 atomicInc(&x, val) 与 非常相似 x = (x+1) % (val+1)

这对于什么样的应用程序有用?这是 CUDA 编程中常见的代码模式吗?如果是这样,是否有专用硬件来执行此操作,这atomicInc()比使用 的等效操作更好atomicCAS()

Rob*_*lla 5

这对于什么样的应用程序有用?

正如评论中所指出的,一种可能的应用是异步访问环形缓冲区。atomicInc具有翻转特性意味着当消费者想要访问超出环形缓冲区“末尾”的元素时,索引(由 返回atomicInc)将翻转到开头,即 0。尽管它不是环形缓冲区示例,这里介绍了使用原子进行缓冲区访问的想法。环形缓冲区atomicInc可能是它的一个简单的扩展。我不会提供有关环形缓冲区的教程。例如,您可能有一个输入索引和一个输出索引,通过两个不同的例程分别维护,这两个例程都将使用atomicInc().

这是 CUDA 编程中常见的代码模式吗?

根据我的经验,它远不如使用 等常见atomicAdd

如果是这样,是否有专用硬件来执行此操作,从而使atomicInc()比使用atomicCAS()的等效操作更好?

是的,有专用的(SASS)指令和硬件。单个变量上的任何原子 RMW 操作都可以使用比较和交换来“模拟” ,但只能使用重试循环。(如在规范的测试循环方法中一样。)通常,与专用指令相比,这种方法的效率和性能较低,而专用指令不需要循环来正确实现。

如果没有这条指令,环形缓冲区的一个选项是让计数器使用 自由运行atomicAdd1并让每个用户在使用它之前进行取模(以索引环形缓冲区)。(这是 CPU 实现通常所做的事情;CPU 通常具有原子添加,但没有自定义包装原子公司。)但这仅适用于 2 的幂次缓冲区大小,因此以类型宽度包装不会引入一个偏移量。因此,只需使用 AND 运算即可高效完成此操作,而不是实际除法或乘法逆运算。

另一个选项是 CAS 重试循环,您可以手动对旧值进行包装,然后尝试对新值进行 CAS。这允许索引非 2 的幂缓冲区,但效率低下。

atomicInc(大约?) 与 一样快atomicAdd,两者均受硬件支持。在 2 的幂情况下使用它会稍微更有效(避免& (size-1)结果atomicAdd),并且避免非 2 的幂情况下的 CAS 重试循环。