我一直在阅读 CUDA 中的原子操作,并且更新模式atomicInc()似乎相当任意。
来自CUDA 编程指南:
Run Code Online (Sandbox Code Playgroud)unsigned int atomicInc(unsigned int* address, unsigned int val);读取位于全局或共享内存中的地址地址的 32 位字 old,计算 ((old >= val) ? 0 : (old+1)),并将结果存储回内存中的同一地址。这三个操作在一个原子事务中执行。该函数返回旧值。
这是增量和“环绕”操作。
atomicInc(&x, val)
与 非常相似
x = (x+1) % (val+1)。
这对于什么样的应用程序有用?这是 CUDA 编程中常见的代码模式吗?如果是这样,是否有专用硬件来执行此操作,这atomicInc()比使用 的等效操作更好atomicCAS()?
这对于什么样的应用程序有用?
正如评论中所指出的,一种可能的应用是异步访问环形缓冲区。atomicInc具有翻转特性意味着当消费者想要访问超出环形缓冲区“末尾”的元素时,索引(由 返回atomicInc)将翻转到开头,即 0。尽管它不是环形缓冲区示例,这里介绍了使用原子进行缓冲区访问的想法。环形缓冲区atomicInc可能是它的一个简单的扩展。我不会提供有关环形缓冲区的教程。例如,您可能有一个输入索引和一个输出索引,通过两个不同的例程分别维护,这两个例程都将使用atomicInc().
这是 CUDA 编程中常见的代码模式吗?
根据我的经验,它远不如使用 等常见atomicAdd。
如果是这样,是否有专用硬件来执行此操作,从而使atomicInc()比使用atomicCAS()的等效操作更好?
是的,有专用的(SASS)指令和硬件。单个变量上的任何原子 RMW 操作都可以使用比较和交换来“模拟” ,但只能使用重试循环。(如在规范的测试循环方法中一样。)通常,与专用指令相比,这种方法的效率和性能较低,而专用指令不需要循环来正确实现。
如果没有这条指令,环形缓冲区的一个选项是让计数器使用 自由运行atomicAdd,1并让每个用户在使用它之前进行取模(以索引环形缓冲区)。(这是 CPU 实现通常所做的事情;CPU 通常具有原子添加,但没有自定义包装原子公司。)但这仅适用于 2 的幂次缓冲区大小,因此以类型宽度包装不会引入一个偏移量。因此,只需使用 AND 运算即可高效完成此操作,而不是实际除法或乘法逆运算。
另一个选项是 CAS 重试循环,您可以手动对旧值进行包装,然后尝试对新值进行 CAS。这允许索引非 2 的幂缓冲区,但效率低下。
atomicInc(大约?) 与 一样快atomicAdd,两者均受硬件支持。在 2 的幂情况下使用它会稍微更有效(避免& (size-1)结果atomicAdd),并且避免非 2 的幂情况下的 CAS 重试循环。
| 归档时间: |
|
| 查看次数: |
1363 次 |
| 最近记录: |