对于GPU warp,哪种原子目标模式更好:全部相同或全部不同?

时间:2014-05-30 15:28:09

标签: cuda opencl gpgpu atomic

假设我们有:

  • 单个warp(32个线程)
  • 每个线程t有32个int值 val t,0 ... val t,31
  • 每个值val t,i 需要原子地添加到变量 dest i ,它位于(选项1)全局设备内存(选项2)共享块内存。

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

  1. 所有线程将 val t,1 添加到 dest 1

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

  2. 每个具有索引t的线程将 val t,t 写入 dest t < / p>

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

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

    思想:

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

    备注:

    • 这个问题主要关注使用CUDA的NVidia硬件,但我很欣赏有关AMD和其他GPU的答案。
    • 别介意线程如何获得它们。假设它们在寄存器中并且没有溢出,或者它们是在寄存器中完成的某些算术运算的结果。忘掉任何内存访问来获取它们。

1 个答案:

答案 0 :(得分: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)的添加在warp中的线程之间平均分配,并且根本不需要原子操作(性能杀手)。 根据我的经验,原子操作通常可以而且应该通过线程之间不同的工作分配来避免。