- 内部线程束访问局部性的情况,例如每个线程束访问的内存位置总数很小,并且其中大部分确实由多个lane访问。
- 访问反局部性的情况,其中所有lane通常访问不同的位置(并且可能会尽力避免银行冲突)?
在SM5.0(Maxwell)及以上的GPU上,共享内存原子操作(假设添加)由于地址冲突(两个具有相同地址的通道)而需要重播指令。普通的Bank冲突重播也适用。在Maxwell / Pascal上,共享内存单元在两个SM分区之间固定轮换访问(每个分区有2个调度程序)。对于每个分区,共享内存单元将完成所有的指令重播,然后再移动到下一个指令。Volta SM将在任何其他共享内存指令之前完成该指令。
在Fermi和Kepler架构中,在读取修改写入操作之前必须执行共享内存锁定操作。这会阻塞所有其他线程指令。
Maxwell和更新的GPU具有比Fermi / Kepler更快的共享内存原子性能。
可以编写非常简单的内核来微基准测试您的两种不同情况。CUDA分析器提供了共享内存访问的指令执行计数和重播计数,但不区分由于原子操作和由于负载/存储冲突或向量访问而重播的指令。
即使不需要了解CUDA硬件中如何实现共享内存原子操作,也可以提出一个非常简单的论点:归根结底,原子操作必须以某种方式在某个时刻进行序列化。这在一般情况下都是正确的,无论你在哪个平台或硬件上运行。由于原子性的本质特征,这是必须的。如果你有多个原子操作并行发出,你必须以某种方式执行它们以确保原子性。这意味着,无论是GPU还是CPU,随着争用的增加,原子操作总是会变得更慢。唯一的问题是:减慢的程度。这取决于具体的实现。
因此,通常情况下,您希望尽可能地降低争用级别,即尝试以并行方式在同一内存位置上执行原子操作的线程数。
这只是一个推测性的部分答案。
考虑相关问题:共享内存上原子操作的性能及其被接受的答案。
如果那里的被接受的答案是正确的(即使到今天仍然正确),那么在更局部化的访问中,warp线程会相互干扰,使得许多lane进行原子操作变慢,即提高了warp原子操作的反局部性。
但说实话 - 我不确定我完全赞同这种论证方式,也不知道自那个答案写下以来是否有所改变。