CUDA缩减-原子与单线程求和

CUDA缩减-原子与单线程求和,cuda,atomicity,reduction,Cuda,Atomicity,Reduction,我最近使用CUDA测试了该算法(例如,您可以在第16页找到该算法)。但最后,我遇到了不使用原子性的麻烦。所以基本上我计算每个块的和,并将其存储到共享数组中。然后我将其返回到全局数组x(tdx是threadIndex.x,I是全局索引) 然后我想对前x个元素求和(尽可能多的块)。 当使用原子性时,它工作正常(与cpu的结果相同),但是当我使用下面的注释行时,它不工作,并且经常产生“nan”: 如果(i==0){ 对于(int k=0;k

我最近使用CUDA测试了该算法(例如,您可以在第16页找到该算法)。但最后,我遇到了不使用原子性的麻烦。所以基本上我计算每个块的和,并将其存储到共享数组中。然后我将其返回到全局数组x(tdx是threadIndex.x,I是全局索引)

然后我想对前x个元素求和(尽可能多的块)。 当使用原子性时,它工作正常(与cpu的结果相同),但是当我使用下面的注释行时,它不工作,并且经常产生“nan”:

如果(i==0){
对于(int k=0;k
事实上,我直接使用atomicadd对共享的和求和,但我想理解为什么这不起作用。当将操作限制在单个线程时,原子add是毫无意义的。简单的求和应该很好

\uuuu syncthreads()
仅同步同一块中的线程,而不跨不同的块,CUDA在块之间没有安全的同步机制


不正确的结果是由于同步问题造成的。操作数
x[k]
是来自不同块的计算结果:
x[0]
是来自块
0
的结果,
x[1]
是来自块
1
的结果,等等。线程
0
可以在某些块真正完成计算之前开始将它们相加

您应该将第二个代码段放在不同的内核中,以便强制执行同步,并且行
sum[0]+=x[k]现在可以工作。

\uuu syncthreads()
只同步同一块中的线程,而不是跨不同的块,CUDA没有跨块的安全同步机制


不正确的结果是由于同步问题造成的。操作数
x[k]
是来自不同块的计算结果:
x[0]
是来自块
0
的结果,
x[1]
是来自块
1
的结果,等等。线程
0
可以在某些块真正完成计算之前开始将它们相加


您应该将第二个代码段放在不同的内核中,以便强制执行同步,并且行
sum[0]+=x[k]现在可以工作。

正如已经指出的,您的问题是由于在第一次通过后缺少同步,因为您无法在块之间同步。工具包中提供的数据量有很好的减少

话虽如此,我强烈建议人们不要在库代码中存在缩减内核(或其他原语,如扫描)的地方编写缩减内核。最好将精力投入到其他地方,并在可用的地方重用现有的优化代码。当然,如果你这样做是为了学习,这不适用


我建议您查看和。

正如已经指出的,您的问题是由于在第一次传递后缺少同步,因为您无法在块之间同步。工具包中提供的数据量有很好的减少

话虽如此,我强烈建议人们不要在库代码中存在缩减内核(或其他原语,如扫描)的地方编写缩减内核。最好将精力投入到其他地方,并在可用的地方重用现有的优化代码。当然,如果你这样做是为了学习,这不适用


我建议您查看和。

\uu syncthreads()
仅同步同一块中的线程,而不是跨不同的块。我认为不正确的结果是由于同步问题造成的。通过
atomicAdd
可以在
\uuu syncthreads()
缺少的不同块之间强制执行同步。事实上,当我在for循环中添加一个uu syncthreads()时,简单的求和就起作用了!但我不明白。我在一个全局数组中只使用一个线程进行求和,那么为什么我要关心for循环中的同步呢?好的,我想我知道了!全局数组在进入循环时不一定会被写入,因为所有的块都不会被同步。那么,“全局”同步线程的命令是什么呢?操作数
x[k]
是不同块的计算结果:
x[0]
是块
0
的结果,
x[1]
是块
1
的结果,我怀疑线程
0
可能在某些块真正完成计算之前就开始添加它们。尝试以下方法。将第二个代码段放在另一个内核中,以便强制执行同步,然后在行
sum[0]+=x[k]时重试有效。关于你的新问题,CUDA没有跨块的安全同步机制。
\uu syncthreads()
只同步同一块中的线程,而不同步不同块中的线程。我认为不正确的结果是由于同步问题造成的。通过
atomicAdd
可以在
\uuu syncthreads()
缺少的不同块之间强制执行同步。事实上,当我在for循环中添加一个uu syncthreads()时,简单的求和就起作用了!但我不明白。我在一个全局数组中只使用一个线程进行求和,那么为什么我要关心for循环中的同步呢?好的,我想我知道了!全局数组在进入循环时不一定会被写入,因为所有的块都不会被同步。那么,“全局”同步线程的命令是什么呢?操作数
x[k]
是来自不同块的计算结果:
x[0]
是来自块
0
的结果,
x[1]
是来自块
1
的结果,等等。我怀疑线程
0
可能会启动
if(i==0){
        *sum = 0.; // Initialize to 0
    }
__syncthreads();
if (tdx == 0){       
    x[blockIdx.x] = s_x[tdx]; //get the shared sums in global memory
}
__syncthreads();
if(i == 0){    
    for(int k = 0; k < gridDim.x; k++){
        atomicAdd(sum, x[k]); //Works good
       //sum[0] += x[k]; //or *sum += x[k]; //Does not work, often results in nan
    }
}