似乎您可能混淆了两件事 - 当 nvcc 处理 CUDA 代码时如何区分主机和设备编译轨迹,以及如何区分 CUDA 和非 CUDA 代码。两者之间存在细微差别。__CUDA_ARCH__
回答第一个问题,__CUDACC__
回答第二个问题。
考虑以下代码片段:
#ifdef __CUDACC__
#warning using nvcc
template <typename T>
__global__ void add(T *x, T *y, T *z)
{
int idx = threadIdx.x + blockDim.x * blockIdx.x;
z[idx] = x[idx] + y[idx];
}
#ifdef __CUDA_ARCH__
#warning device code trajectory
#if __CUDA_ARCH__ > 120
#warning compiling with double precision
template void add<double>(double *, double *, double *);
#else
#warning compiling with single precision
template void add<float>(float *, float *, float *);
#else
#warning nvcc host code trajectory
#endif
#else
#warning non-nvcc code trajectory
#endif
在这里,我们有一个模板化的 CUDA 内核,它具有依赖于 CUDA 体系结构的实例化,一个用于由 引导的主机代码的单独节nvcc
,以及一个用于编译不由 引导的主机代码的节nvcc
。其行为如下:
$ ln -s cudaarch.cu cudaarch.cc
$ gcc -c cudaarch.cc -o cudaarch.o
cudaarch.cc:26:2: warning: #warning non-nvcc code trajectory
$ nvcc -arch=sm_11 -Xptxas="-v" -c cudaarch.cu -o cudaarch.cu.o
cudaarch.cu:3:2: warning: #warning using nvcc
cudaarch.cu:14:2: warning: #warning device code trajectory
cudaarch.cu:19:2: warning: #warning compiling with single precision
cudaarch.cu:3:2: warning: #warning using nvcc
cudaarch.cu:23:2: warning: #warning nvcc host code trajectory
ptxas info : Compiling entry function '_Z3addIfEvPT_S1_S1_' for 'sm_11'
ptxas info : Used 4 registers, 12+16 bytes smem
$ nvcc -arch=sm_20 -Xptxas="-v" -c cudaarch.cu -o cudaarch.cu.o
cudaarch.cu:3:2: warning: #warning using nvcc
cudaarch.cu:14:2: warning: #warning device code trajectory
cudaarch.cu:16:2: warning: #warning compiling with double precision
cudaarch.cu:3:2: warning: #warning using nvcc
cudaarch.cu:23:2: warning: #warning nvcc host code trajectory
ptxas info : Compiling entry function '_Z3addIdEvPT_S1_S1_' for 'sm_20'
ptxas info : Used 8 registers, 44 bytes cmem[0]
从中得到的要点是:
__CUDACC__
定义是否nvcc
转向编译
__CUDA_ARCH__
在编译主机代码时总是未定义,由nvcc
或不控制
__CUDA_ARCH__
仅针对编译的设备代码轨迹定义nvcc
这三条信息总是足以将设备代码条件编译到不同的 CUDA 架构、主机端 CUDA 代码和根本未编译的代码nvcc
。nvcc
文档有时有点简洁,但所有这些都包含在关于编译轨迹的讨论中。