模板__host__ __device__调用主机定义的函数

时间:2015-05-04 11:37:41

标签: cuda

在实现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);
}

警告是由foo(HostObject());功能内的main()电话引起的。

foo_host<>foo_device<>可能是有问题的foo<>的替代品。

有更好的解决方案吗?我可以阻止设备端foo()的实施吗?

1 个答案:

答案 0 :(得分:6)

您无法阻止实例化__host__ __device__函数模板实例化的任何一半。如果通过在主机(设备)上调用它来实例化该函数,编译器也会将设备(主机)实例化一半。

从CUDA 7.0起,您可以为您的用例做的最好的事情是使用#pragma hd_warning_disable来抑制警告,如下例所示,并确保未正确调用该函数。

#include <iostream>
#include <cstdio>

#pragma hd_warning_disable
template<class Function>
__host__ __device__
void invoke(Function f)
{
  f();
}

struct host_only
{
  __host__
  void operator()()
  {
    std::cout << "host_only()" << std::endl;
  }
};

struct device_only
{
  __device__
  void operator()()
  {
    printf("device_only(): thread %d\n", threadIdx.x);
  }
};

__global__
void kernel()
{
  // use from device with device functor
  invoke(device_only());

  // XXX error
  // invoke(host_only());
}

int main()
{
  // use from host with host functor
  invoke(host_only());

  kernel<<<1,1>>>();
  cudaDeviceSynchronize();

  // XXX error
  // invoke(device_only());

  return 0;
}