合并访问与广播访问 GPU 上的全局内存位置

Coalesced access vs broadcast access to a global memory location on GPU

我有一个应用程序,我需要在其中向所有线程广播全局内存中的单个(非常量,只是普通的旧数据)值。线程只需要读取值,而不是写入它。我不能明确告诉应用程序使用常量缓存(例如 cudaMemcpyToSymbol),因为我使用的是内存包装库,它不给我明确的低级控制。

我想知道这个广播是如何在幕后发生的,以及它与每个线程访问唯一全局内存位置的通常访问模式有何不同(为简单起见,假设这个 "usual" 访问模式是合并)。我对广播情况下可能发生的任何隐式序列化以及不同架构如何影响它特别感兴趣。

例如,对于 Fermi,大概第一个访问该值的线程会将它拉到 L2 缓存,然后到它的 SM 的 L1 缓存,此时驻留在 SM 上的每个线程都会尝试从一级缓存。当所有线程都尝试访问相同的 L1 缓存值时,是否存在任何序列化惩罚?

对于 Kepler,大概第一个访问该值的线程会将其拉入 L2 缓存(然后可能会或可能不会将其拉入 L1 缓存,具体取决于是否启用了 L1 缓存)。当所有线程都试图访问 L2 中的相同值时,是否存在任何序列化惩罚?

此外,分区露营是一个问题吗?

我发现另一个 couple of questions 解决了类似的主题,但不够详细,无法满足我的好奇心。

提前致谢!

I have an application where I need to broadcast a single (non-constant, just plain old data) value in global memory to all threads. The threads only need to read the value, not write to it.

顺便说一句,这几乎就是常量数据的定义,因为它与 CUDA 内核使用有关。你可能无法利用它,但这种访问被称为"uniform"访问,如果有这种类型的重复访问,对于线程only[=32=的值] read from and do not write to, 那么 __constant__ 内存是一个可以考虑的可能的优化。

I am wondering how this broadcast takes place under the hood

明确一点,广播and/or序列化只有在相同的线程时才有可能warp 正在访问特定的数据项。当不同 warp 中的线程访问同一位置时,这些术语不适用;这些将由单独的 warp 读取请求提供服务。

Is there any serialization penalty when all threads attempt to access the same L1 cache value?

没有序列化惩罚。同一 warp 中的线程可以 read the same location without additional cost;从同一位置读取的所有线程都将在同一周期内得到服务 ("broadcast")。读取 Fermi 上相同位置的单独 warp 中的线程将由单独的读取请求提供服务,就像您期望由单独的 warp 执行的任何指令一样。在这种情况下也没有额外或不寻常的费用。

Is there any serialization penalty when all threads attempt to access the same value in L2?

上面L1的same statements在这种情况下适用于L2。

Also, is partition camping a concern?

分区露营与从 L1 或 L2 缓存中检索的值无关。分区露营通常是指一种数据访问模式,该模式导致 DRAM 请求不成比例地由具有多个内存分区的 GPU 上的一个分区处理。对于多个 threads/warps 正在读取的单个位置,缓存将为此提供服务。至多,应该需要一个 DRAM 事务来服务所有在时间上彼此足够接近的请求(即忽略缓存抖动的可能性),针对单个位置。