为什么我们不能拆分 __host__ 和 __device__ 实现?
Why can't we split __host__ and __device__ implementations?
如果我们在 CUDA 中有一个 __host__ __device__
函数,我们可以在其实现中使用宏为主机端和设备端代码选择不同的代码路径,例如:
__host__ __device__ int foo(int x)
{
#ifdef CUDA_ARCH
return x * 2;
#else
return x;
#endif
}
但是为什么我们不能写:
__host__ __device__ int foo(int x);
__device__ int foo(int x) { return x * 2; }
__host__ int foo(int x) { return x; }
代替?
CUDA C++ 的 Clang 实现实际上支持 __host__
和
__device__
因为它将执行 space 限定符视为函数签名的一部分。但是请注意,即使在那里,您也必须分别声明这两个函数:
__device__ int foo(int x);
__host__ int foo(int x);
__device__ int foo(int x) { return x * 2; }
__host__ int foo(int x) { return x; }
就我个人而言,我不确定 desirable/important 这到底是怎么回事。考虑到您可以在 CUDA 源代码之外的主机代码中定义一个 foo(int x)
。如果有人告诉我他们需要对主机和设备使用相同功能的不同实现,其中出于某种原因需要将主机版本定义为 CUDA 源的一部分,我最初的直觉是可能会发生一些事情一个奇怪的方向。如果主机版本做了一些不同的事情,它不应该有一个不同的名字吗?如果它在逻辑上只是不使用 GPU 做同样的事情,那么为什么它必须是 CUDA 源的一部分?我通常提倡在主机和设备代码之间尽可能保持干净和严格的分离,并将 CUDA 源代码中的任何主机代码保持在最低限度。即使您不关心代码的整洁度,这样做也至少可以最大限度地减少被幕后运行的所有编译器魔法伤害的可能性……
如果我们在 CUDA 中有一个 __host__ __device__
函数,我们可以在其实现中使用宏为主机端和设备端代码选择不同的代码路径,例如:
__host__ __device__ int foo(int x)
{
#ifdef CUDA_ARCH
return x * 2;
#else
return x;
#endif
}
但是为什么我们不能写:
__host__ __device__ int foo(int x);
__device__ int foo(int x) { return x * 2; }
__host__ int foo(int x) { return x; }
代替?
CUDA C++ 的 Clang 实现实际上支持 __host__
和
__device__
因为它将执行 space 限定符视为函数签名的一部分。但是请注意,即使在那里,您也必须分别声明这两个函数:
__device__ int foo(int x);
__host__ int foo(int x);
__device__ int foo(int x) { return x * 2; }
__host__ int foo(int x) { return x; }
就我个人而言,我不确定 desirable/important 这到底是怎么回事。考虑到您可以在 CUDA 源代码之外的主机代码中定义一个 foo(int x)
。如果有人告诉我他们需要对主机和设备使用相同功能的不同实现,其中出于某种原因需要将主机版本定义为 CUDA 源的一部分,我最初的直觉是可能会发生一些事情一个奇怪的方向。如果主机版本做了一些不同的事情,它不应该有一个不同的名字吗?如果它在逻辑上只是不使用 GPU 做同样的事情,那么为什么它必须是 CUDA 源的一部分?我通常提倡在主机和设备代码之间尽可能保持干净和严格的分离,并将 CUDA 源代码中的任何主机代码保持在最低限度。即使您不关心代码的整洁度,这样做也至少可以最大限度地减少被幕后运行的所有编译器魔法伤害的可能性……