【问题标题】:Which atomics targetting pattern is better for a GPU warp: All-the-same or all-distinct?哪种原子目标模式更适合 GPU 扭曲:完全相同还是完全不同?
【发布时间】:2014-05-30 15:28:08
【问题描述】:

假设我们有:

  • 一根经线(32 根线)
  • 每个线程 t 都有 32 个 int 值 val t,0...val t,31,
  • 每个值 val t,i 需要以原子方式添加到位于(选项 1)中的变量 desti全局设备内存(选项 2)共享块内存。

哪种访问模式执行这些添加会更快:

  1. 所有线程原子添加 val t,1dest 1

    所有线程原子添加 val t,2dest 2

    等等

  2. 每个索引为 t 的线程将 val t,t 写入 dest t

    索引为 t 的每个线程将 val t, (t+1) mod 32 写入 dest (t+1) mod 32

    等等

换句话说,当一个warp的所有线程在同一个周期中进行原子写入时会更快,还是没有原子写入同时发生更好?我可以想到更快地执行任一选项的硬件,我想知道实际实现了什么。

想法:

  • GPU 有可能拥有将来自同一个 warp 的多个原子操作聚合到一个目标的硬件,因此它们实际上只是一个,或者至少可以一起调度,因此所有线程都将继续执行下一条指令同时执行,而不是等待所有其他操作完成后最后一个原子操作结束。

注意事项:

  • 此问题侧重于具有 CUDA 的 NVidia 硬件,但我希望能提供有关 AMD 和其他 GPU 的答案。
  • 别管线程是如何得到它们的。假设它们在寄存器中并且没有溢出,或者它们是在寄存器中完成的一些算术运算的结果。忘记任何内存访问来获取它们。

【问题讨论】:

  • 虽然我不知道确切的答案,但我的猜测是偏斜访问更可取。至少每个周期您将发出 32 个原子操作(在理想情况下),但在实际硬件中,您的算法可能会受到较差的内存访问模式的影响。
  • 这听起来只能通过大量仔细的基准测试来回答。是什么阻止你尝试它?
  • @talonmies: 1. 我只有一张(或两张)卡可以用来做基准测试。 2. 答案可能是“它可能取决于其他参数”,在这种情况下我会考虑它们。 3. 对于我正在处理的实际问题,我试图减少原子的使用而不是优化它
  • 我会选择第二个。对于所有通道,第一个访问模式在每个周期中具有相同的地址。当共享内存是目标时,它尤其会降低 Maxwell 之前的 CUDA 卡的性能(请参阅here)。另请查看herehere

标签: cuda opencl gpgpu atomic


【解决方案1】:

我是这样理解你的问题的:

你有一个 32x32 的 int 矩阵:

Val0'0, Val1'0,....Val31'0
Val1'0, Val1'1,....Val31'1
.
.
Val31'0, Val31'1,...,Val31'31

你需要对每一行求和:
Val0'0 + Val1'0 + ... Val31'0 = dest0
Val0'1 + Val1'1 + ... Val31'1 = dest1 等等。

问题是您的行值分布在不同的线程之间。 对于单个 warp,最简单的解决方法是让每个线程使用共享内存(在 32x32 共享内存数组中)共享它的值。在线程同步之后,线程 i 对第 i 行求和,并将结果写入 dest(i),它可以驻留在全局内存或共享内存中(取决于您的应用程序)。 这样,计算工作(31x31)加法在经线中的线程之间平均分配,您根本不需要原子操作(性能杀手)。 根据我的经验,原子操作通常可以而且应该通过线程之间不同的工作分配来避免。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-14
    • 2022-06-30
    • 1970-01-01
    • 1970-01-01
    • 2019-05-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多