在以前的CUDA版本中,atomicAdd没有为双打实现,所以通常像here那样实现它。使用新的CUDA 8 RC,当我尝试编译包含这样一个函数的代码时,我遇到了麻烦。我想这是因为使用Pascal和Compute Capability 6.0,添加了原生双重版本的atomicAdd,但不知何故,以前的Compute Capabilities没有正确忽略它。
下面的代码用于编译和运行以前的CUDA版本,但现在我得到了这个编译错误:
test.cu(3): error: function "atomicAdd(double *, double)" has already been defined
但如果删除我的实现,我会收到此错误:
test.cu(33): error: no instance of overloaded function "atomicAdd" matches the argument list
argument types are: (double *, double)
我应该补充一点,如果我使用-arch=sm_35
或类似代码编译,我只能看到这个。如果我使用-arch=sm_60
进行编译,我会得到预期的行为,即只有第一个错误,并在第二种情况下成功编译。
编辑:此外,它特定于atomicAdd
- 如果我更改名称,则效果很好。
它看起来像编译错误。其他人可以确认是这种情况吗?
示例代码:
__device__ double atomicAdd(double* address, double val)
{
unsigned long long int* address_as_ull = (unsigned long long int*)address;
unsigned long long int old = *address_as_ull, assumed;
do {
assumed = old;
old = atomicCAS(address_as_ull, assumed,
__double_as_longlong(val + __longlong_as_double(assumed)));
} while (assumed != old);
return __longlong_as_double(old);
}
__global__ void kernel(double *a)
{
double b=1.3;
atomicAdd(a,b);
}
int main(int argc, char **argv)
{
double *a;
cudaMalloc(&a,sizeof(double));
kernel<<<1,1>>>(a);
cudaFree(a);
return 0;
}
编辑:我从Nvidia那里得到了一个认识到这个问题的答案,这就是开发人员对此的看法:
CUDA 8.0新支持的sm_60架构具有 原生fp64 atomicAdd函数。由于我们的局限性 工具链和CUDA语言,这个函数的声明需要 即使没有专门编译代码也存在 sm_60。这会导致代码出现问题,因为您还定义了一个 fp64 atomicAdd函数。
CUDA内置函数(例如atomicAdd)是实现定义的 并且可以在CUDA版本之间进行更改。用户不应该定义 与任何CUDA内置函数同名的函数。我们会 建议你将atomicAdd函数重命名为不是的函数 与任何CUDA内置函数相同。
答案 0 :(得分:11)
atomicAdd的味道是为计算能力6.0引入的新方法。您可以保留以前使用宏定义保护它的其他计算功能
#if !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 600
#else
<... place here your own pre-pascal atomicAdd definition ...>
#endif
此宏命名架构标识宏记录在here:
5.7.4。虚拟架构识别宏
在编译compute_xy的每个nvcc编译阶段1期间,为体系结构标识宏
__CUDA_ARCH__
分配一个三位数值字符串xy0(以字面0结尾)。此宏可用于实现GPU功能,以确定当前正在编译的虚拟体系结构。主机代码(非GPU代码)不得依赖它。
我认为NVIDIA没有将它放在以前的CC中,以避免用户定义冲突而不转移到Compute Capability&gt; = 6.x.我不认为它是一个BUG,而是一个发布交付实践。
编辑:宏观警卫不完整(已修复) - 这是一个完整的例子。
#if !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 600
#else
__device__ double atomicAdd(double* a, double b) { return b; }
#endif
__device__ double s_global ;
__global__ void kernel () { atomicAdd (&s_global, 1.0) ; }
int main (int argc, char* argv[])
{
kernel<<<1,1>>> () ;
return ::cudaDeviceSynchronize () ;
}
编译:
$> nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2016 NVIDIA Corporation
Built on Wed_May__4_21:01:56_CDT_2016
Cuda compilation tools, release 8.0, V8.0.26
命令行(均成功):
$> nvcc main.cu -arch=sm_60
$> nvcc main.cu -arch=sm_35
您可能会发现为什么它适用于包含文件:sm_60_atomic_functions.h
,如果__CUDA_ARCH__
低于600,则不会声明该方法。