【发布时间】:2015-07-13 18:48:33
【问题描述】:
在执行 CUDA 代码期间,我经常需要一些实用程序函数,这些函数可以从设备调用,也可以从主机代码调用。所以我将这些函数声明为 __host__ __device__。这没关系,#ifdef CUDA_ARCH 可以处理可能的设备/主机不兼容问题。
当效用函数被模板化时,问题就来了。通过某种函子类型。如果模板实例调用 __host__ 函数,我会收到以下警告:
calling a __host__ function from a __host__ __device__ function is not allowed
detected during instantiation of "int foo(const T &) [with T=HostObject]"
我知道的唯一解决方案是定义函数两次 - 一次用于设备,一次用于具有不同名称的主机代码(我不能在 __host__ __device__ 上重载)。但这意味着存在代码重复,并且所有其他将调用它的 __host__ __device__ 函数也必须定义两次(甚至更多代码重复)。
简化示例:
#include <cuda.h>
#include <iostream>
struct HostObject {
__host__
int value() const { return 42; }
};
struct DeviceObject {
__device__
int value() const { return 3; }
};
template <typename T>
__host__ __device__
int foo(const T &obj) {
return obj.value();
}
/*
template <typename T>
__host__
int foo_host(const T &obj) {
return obj.value();
}
template <typename T>
__device__
int foo_device(const T &obj) {
return obj.value();
}
*/
__global__ void kernel(int *data) {
data[threadIdx.x] = foo(DeviceObject());
}
int main() {
foo(HostObject());
int *data;
cudaMalloc((void**)&data, sizeof(int) * 64);
kernel<<<1, 64>>>(data);
cudaThreadSynchronize();
cudaFree(data);
}
警告是由main() 函数内的foo(HostObject()); 调用引起的。
foo_host<> 和 foo_device<> 可以替代有问题的foo<>。
有没有更好的解决方案?我可以在设备端阻止foo() 的实例化吗?
【问题讨论】:
-
foo()内部没有调用构造函数。问题正是警告所说的。我在问是否可以在不定义通用函数两次的情况下以某种方式修复它。 -
警告是由主函数中的
foo(HostObject())引起的。构造函数没有问题,因为在我自己声明之前,都会自动生成构造函数(由主机和设备编译器)。 -
抱歉,现在我明白你的意思了——如果没有编译器,就很难看到错误的显示位置。因此,我相信在您的问题中提及它会很有用。
-
我猜这只是一个编译器问题。 Thrust 过度使用模板并使用
#pragma hd_warning_disable禁用此类警告,请参阅github.com/thrust/thrust/blob/master/thrust/detail/config/… -
想象一下 HostObject 不在你的控制之下——它可能来自不同的库或模块,所以你不能让它启用 CUDA。这也意味着 CUDA 编译器将处理该函数,如果 CUDA 编译器无法编译主体,则会产生错误消息。
标签: cuda