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