我正在尝试实现双精度数组的经典点积内核,并通过各种块的最终总和的原子计算。我使用atomicAdd作为编程指南的第116页所述的双精度。可能是我做错了什么。每个块中线程的部分总和计算正确,但后缀的原子操作似乎没有正常工作因为每次我用相同的数据运行我的内核时,我收到不同的结果。如果有人能够发现错误或提供替代解决方案,我将不胜感激! 这里是我的内核:CUDA Dot产品
__global__ void cuda_dot_kernel(int *n,double *a, double *b, double *dot_res)
{
__shared__ double cache[threadsPerBlock]; //thread shared memory
int global_tid=threadIdx.x + blockIdx.x * blockDim.x;
int i=0,cacheIndex=0;
double temp = 0;
cacheIndex = threadIdx.x;
while (global_tid < (*n)) {
temp += a[global_tid] * b[global_tid];
global_tid += blockDim.x * gridDim.x;
}
cache[cacheIndex] = temp;
__syncthreads();
for (i=blockDim.x/2; i>0; i>>=1) {
if (threadIdx.x < i) {
cache[threadIdx.x] += cache[threadIdx.x + i];
}
__syncthreads();
}
__syncthreads();
if (cacheIndex==0) {
*dot_res=cuda_atomicAdd(dot_res,cache[0]);
}
}
这里是我的设备功能atomicAdd:
__device__ double cuda_atomicAdd(double *address, double val)
{
double assumed,old=*address;
do {
assumed=old;
old= __longlong_as_double(atomicCAS((unsigned long long int*)address,
__double_as_longlong(assumed),
__double_as_longlong(val+assumed)));
}while (assumed!=old);
return old;
}
共享内存原子很慢。这不是实现点积的好方法。 Jared指出,你最好使用Thrust。如果你坚持编写你自己的代码,并且你真的想在单个内核中完成它,请参阅CUDA SDK代码示例中的threadFenceReduction示例。它应该更有效率(它不是一个点积,只是一个总和减少,但添加最初的元素乘法应该是微不足道的。) – harrism 2012-02-26 11:25:35
@harrism:这个代码中共享内存原子的地方在哪里?这只是一个标准的共享内存减少与全局内存原子操作来完成块部分减少值的总和。 – talonmies 2012-02-26 11:52:47
对不起,我把原子论点转移到了我的脑海中!无论如何,如果你使用threadfence,你不应该需要原子来在单个内核中实现减少。 – harrism 2012-02-26 22:17:51