当我们减少总和时,cuda atomicAdd操作是否比启动另一个内核更快?

当我们减少总和时,cuda atomicAdd操作是否比启动另一个内核更快?,cuda,atomic,Cuda,Atomic,我需要求一个向量的和,它比cuda块中的线程数长。因此,我使用多个块来处理任务。我对每个块中的一部分向量求和,然后我有两个选项,一个是使用atomicAdd组合每个块的和,另一个是将结果写入一些全局内存并启动另一个内核进行求和。你建议我用哪种方法 当我们减少总和时,cuda atomicAdd操作是否比启动另一个内核更快 对于下面的测试用例,使用培训()中从16和17中提取的代码,速度似乎要快一点。区别在于内核启动开销的成本,这是有意义的: $ cat t1834.cu #include <

我需要求一个向量的和,它比cuda块中的线程数长。因此,我使用多个块来处理任务。我对每个块中的一部分向量求和,然后我有两个选项,一个是使用atomicAdd组合每个块的和,另一个是将结果写入一些全局内存并启动另一个内核进行求和。你建议我用哪种方法

当我们减少总和时,cuda atomicAdd操作是否比启动另一个内核更快

对于下面的测试用例,使用培训()中从16和17中提取的代码,速度似乎要快一点。区别在于内核启动开销的成本,这是有意义的:

$ cat t1834.cu
#include <time.h>
#include <sys/time.h>
#include <iostream>

const int BLOCK_SIZE = 1024;

template <typename T>
__global__ void reduce(const T * __restrict__ gdata, T * __restrict__ out, const int N){
     __shared__ T sdata[BLOCK_SIZE];
     int tid = threadIdx.x;
     sdata[tid] = 0.0;
     size_t idx = threadIdx.x+blockDim.x*blockIdx.x;

     while (idx < N) {  // grid stride loop to load data
        sdata[tid] += gdata[idx];
        idx += gridDim.x*blockDim.x;
        }

     for (unsigned int s=blockDim.x/2; s>0; s>>=1) {
        __syncthreads();
        if (tid < s)  // parallel sweep reduction
            sdata[tid] += sdata[tid + s];
        }
     if (tid == 0)
#ifndef USE_ATOMIC
         out[blockIdx.x] = sdata[0];
#else
         atomicAdd(out, sdata[0]);
#endif
}

#define USECPSEC 1000000ULL

unsigned long long dtime_usec(unsigned long long start){

  timeval tv;
  gettimeofday(&tv, 0);
  return ((tv.tv_sec*USECPSEC)+tv.tv_usec)-start;
}


typedef float mt;
const int ds = 1048576*8;
int main(){

  mt *h_gdata, *d_gdata, *h_out, *d_out;
  h_gdata = new mt[ds];
  cudaMalloc(&d_gdata, ds*sizeof(mt));
  const int nblocks = 160;
  h_out = new mt[1];
  cudaMalloc(&d_out, nblocks*sizeof(mt));
  for (int i = 0; i < ds; i++) h_gdata[i] = 1;
  cudaMemcpy(d_gdata, h_gdata, ds*sizeof(mt), cudaMemcpyHostToDevice);
  reduce<<<nblocks, BLOCK_SIZE>>>(d_gdata, d_out, ds); // warm-up
  cudaDeviceSynchronize();
  cudaMemset(d_out, 0, sizeof(mt));
  unsigned long long dt = dtime_usec(0);
  reduce<<<nblocks, BLOCK_SIZE>>>(d_gdata, d_out, ds);
#ifndef USE_ATOMIC
  reduce<<<1, BLOCK_SIZE>>>(d_out, d_out, nblocks);
#endif
  cudaDeviceSynchronize();
  dt = dtime_usec(dt);
  cudaMemcpy(h_out, d_out, sizeof(mt), cudaMemcpyDeviceToHost);
  cudaError_t err = cudaGetLastError();
  if (err != cudaSuccess) {std::cout << "CUDA error: " << cudaGetErrorString(err) << std::endl; return 0;}
  if (h_out[0] != ds) {std::cout << "Reduce Error: " <<  h_out[0] << std::endl;   return 0;}
  std::cout << "Timing: " << dt << "us" << std::endl;
  return 0;
}
$ nvcc -lineinfo -arch=sm_70 -O3  -o t1834 t1834.cu -std=c++14 -Wno-deprecated-gpu-targets
$ ./t1834
Timing: 69us
$ nvcc -lineinfo -arch=sm_70 -O3  -o t1834 t1834.cu -std=c++14 -Wno-deprecated-gpu-targets -DUSE_ATOMIC
$ ./t1834
Timing: 66us
$
$cat t1834.cu
#包括
#包括
#包括
const int BLOCK_SIZE=1024;
样板
__全局无效减少(常数T*\Uu限制\Uu数据,T*\Uu限制\Uu输出,常数int N){
__共享数据块[数据块大小];
int tid=threadIdx.x;
sdata[tid]=0.0;
size_t idx=threadIdx.x+blockDim.x*blockIdx.x;
而(idx0;s>>>=1){
__同步线程();
if(tidif(err!=cudaSuccess){std::cout@burmethebits:如果使用原子事务,则不需要同步。这就是整个过程point@BlameTheBits嗨,当我使用原子方法时,我只需要同步每个块并调用atomicAdd,当我使用启动另一个内核的方法时,SM会在第一个内核完成后自动同步f缩减、网格大小、块大小、内核设计和正在运行的GPU类型,以及可能许多其他因素都将影响总和缩减的最终性能结果。我的预期是,在大多数情况下,原子完成将比启动第二个内核快。但是您你能在几分钟内写下你自己的测试来回答这个问题吗?我怀疑没有一个答案是没有例外的。哦,对了,我很笨。Sorry@RobertCrovella谢谢回复!!!这是否意味着调用内核函数会给程序带来明显的开销am,所以我们最好仔细设计内核函数更少的程序(这意味着在单个内核中压缩更多的代码)?嗨,ds非常大的情况如何?当内核启动的开销变得恒定,而原子操作的开销线性增长时?