CUDA 内核中映射固定主机内存上的原子操作:做还是不做?

Posted

技术标签:

【中文标题】CUDA 内核中映射固定主机内存上的原子操作:做还是不做?【英文标题】:Atomic operations in CUDA kernels on mapped pinned host memory: to do or not to do? 【发布时间】:2014-06-05 06:24:38 【问题描述】:

在CUDA programming guide 中指出,映射固定主机内存上的原子操作“从主机或其他设备的角度来看不是原子操作。” 我从这句话中得到的是如果主机内存区域仅由一个 GPU 访问,则可以在映射的固定主机内存上执行原子操作(即使在多个同时内核中)。

另一方面,在 Nicholas Wilt 所著的《the CUDA Handbook》一书中第 128 页指出:

不要尝试在映射的固定主机内存上使用原子,无论是用于主机(锁定比较交换)还是设备(atomicAdd())。在 CPU 方面,为锁定操作强制互斥的设施对于 PCI Express 总线上的外围设备是不可见的。相反,在 GPU 方面,原子操作仅适用于本地设备内存位置,因为它们是使用 GPU 的本地内存控制器实现的。

在 CUDA 内核中在映射的固定主机内存上执行原子操作是否安全?我们可以依靠PCI-e总线来保持atomics的read-modify-write的原子性吗?

【问题讨论】:

我不相信它可以工作。 Nick Wilt 在 SO 上发帖为 archaeasoftware。我希望他能找到这个问题并回答它。我很确定他会重申书中的内容。 好吧,my simple tests 不会失败,使用原子对于我的测试获得正确答案至关重要。我有兴趣看一个反例(从单个 GPU 对映射固定内存的原子更新失败)。 你还没有说你是在映射的固定主机内存上做 CPU 还是 GPU 原子。 我编辑了问题。 【参考方案1】:

此警告适用于使用映射固定内存来协调 CPU 和 GPU 之间或多个 GPU 之间的执行的用户。当我写这篇文章时,我没想到有人会在单 GPU 的情况下使用这种机制,因为 CUDA 提供了许多其他更好的方法来协调 CPU 和单个 GPU 之间的执行。

如果 CPU 和 GPU 之间存在严格的生产者/消费者关系(即生产者正在更新内存位置,而消费者正在被动地读取它),则可以预期在某些情况下可以正常工作。

如果 GPU 是生产者,CPU 会看到内存位置的更新,因为它们从 GPU 的 L2 缓存中发布。但 GPU 代码可能必须执行内存屏障才能强制执行此操作;即使该代码在 x86 上运行,它也很可能在 ARM 上中断,因为 ARM 不会窥探总线流量。

如果 CPU 是生产者,GPU 将不得不绕过 L2 缓存,因为它与 CPU 内存不一致。

如果 CPU 和 GPU 试图同时更新相同的内存位置,则没有机制可以确保两者之间的原子性。执行 CPU atomics 将确保更新相对于 CPU 代码是原子的,而执行 GPU atomics 将确保更新相对于正在执行更新的 GPU 是原子的。

上述所有讨论都假设只有一个 GPU;如果涉及多个 GPU,则所有赌注都将取消。尽管 PCI Express 3.0 总线规范中提供了原子,但我不相信 NVIDIA GPU 支持它们。而且底层平台的支持也没有保证。

在我看来,无论开发人员试图通过在映射的固定内存上执行原子操作来完成什么,都可能有一种更快、更有可能工作的方法,或两者​​兼而有之。

【讨论】:

问这个问题的原因是要找出当设备不能保存哈希表时Cuckoo hashing是否可能。 Cuckoo 散列主要依赖于表条目上的 64 位原子交换。 如果您只是想解决 GPU 的物理内存限制,它可能会起作用;但我预计它会很慢。如果您构建它,我很想知道结果! 我们实际上提出了一种适用于 GPU 的新散列方法,而 AFAIK 杜鹃散列是最先进的 GPU 解决方案可供比较。超过全局内存容量时变慢似乎是 GPU 上杜鹃散列的限制之一。 任何溢出全局内存的算法都会对性能造成很大影响。【参考方案2】:

是的,这可以通过单个 GPU 以原子方式工作。因此,如果没有其他 CPU 或 GPU 正在访问内存,它将是原子的。 Atomics 在 L2 缓存和 CROP(在各种 GPU 上)中实现,两者都可以处理系统内存访问。

不过会很慢。此内存未缓存在 GPU 上。

当 Nick 说“强制执行锁定操作互斥的设施对 PCI Express 总线上的外围设备不可见”时,我认为他指的是从两个处理器访问该内存时缺乏原子性,即正确。

【讨论】:

是的,我猜他指的是在运行内核期间 PCI-e 总线缺乏一致性 系统内存访问没有缓存在 GPU 上?这对我来说是个新闻。我相信如果有重用,L2 会很高兴地为系统内存的读取提供服务,就像它为设备内存提供服务一样。事实上,我至少可以想到一个严重依赖该功能的公开演示。

以上是关于CUDA 内核中映射固定主机内存上的原子操作:做还是不做?的主要内容,如果未能解决你的问题,请参考以下文章

#01

CUDA 如何处理内存地址的多次更新?

cuPrintf 啥都不做(程序使用固定+映射内存,CUBLAS 也是)

Cuda - 从设备全局内存复制到纹理内存

CUDA: 流

CUDA实例练习:页锁定主机内存