在CUDA programming guide中声明,从主机或其他设备的角度来看,映射的固定主机内存上的原子操作“不是原子的。”我从这句话得到的是什么如果主机内存区域只能由一个GPU访问,那么在映射的固定主机内存上执行原子操作是很好的(即使是在多个同时内核中也是如此)。
另一方面,在 Nicholas Wilt 的书the CUDA Handbook中,第128页指出:
不要尝试在映射的固定主机内存上使用原子,无论是主机(锁定比较交换)还是设备(
atomicAdd()
)。在CPU方面,PCI Express总线上的外围设备看不到强制执行互锁以进行锁定操作的功能。相反,在GPU方面,原子操作仅适用于本地设备内存位置,因为它们是使用GPU的本地内存控制器实现的。
在映射固定主机内存上从CUDA内核内部执行原子是否安全?我们可以依靠PCI-e总线来保持原子的读取 - 修改 - 写入的原子性吗?
答案 0 :(得分:4)
谨慎适用于使用映射固定内存协调CPU和GPU之间或多个GPU之间执行的人员。当我写这篇文章时,我没想到有人会在单GPU案例中使用这样的机制,因为CUDA提供了许多其他更好的方法来协调CPU和单个GPU之间的执行。
如果CPU和GPU之间存在严格的生产者/消费者关系(即生产者正在更新内存位置而消费者被动地阅读它),那么在某些情况下可以预期这种关系。
如果GPU是生产者,当CPU从L2的L2缓存中发布时,CPU会看到内存位置的更新。但GPU代码可能必须执行内存屏障才能强制执行此操作;即使该代码在x86上工作,它也可能在ARM没有英雄措施的情况下中断,因为ARM不会窥探总线流量。
如果CPU是生产者,GPU将不得不绕过L2缓存,因为它与CPU内存不一致。
如果CPU和GPU正在尝试同时更新相同的内存位置,则没有机制来确保两者之间的原子性。执行CPU原子将确保相对于CPU代码进行原子更新,并且执行GPU原子将确保更新对于正在执行更新的GPU而言是原子的。
所有上述讨论都假设只有一个GPU;如果涉及多个GPU,则所有投注均已关闭。尽管在PCI Express 3.0总线规范中提供了原子,但我认为NVIDIA GPU不支持它们。并且无法保证底层平台的支持。
在我看来,无论开发人员通过在映射的固定内存上执行原子操作来尝试完成什么,都可能有一种方法更快,更有可能工作,或者两者兼而有之。
答案 1 :(得分:1)
是的,这可以从单个GPU原子上运行。因此,如果没有其他CPU或GPU访问内存,它将是原子的。 Atomics在L2缓存和CROP(在各种GPU上)中实现,并且都可以处理系统内存访问。
但是,它会很慢。此内存未缓存在GPU上。当Nick说,“PCI Express总线上的外围设备看不到强制执行互锁操作的设施”,这让我觉得他指的是从两个处理器访问内存时缺乏原子性,这是正确的。