CUDA:使用类成员将类传递给设备是一个指针函数

时间:2017-07-04 13:54:30

标签: c++11 cuda

我想编写一个c ++ CUDA程序,我将一个类传递给内核。该类只通过调用operator()计算内核上的函数。如果我在课堂上硬连接这个功能,一切都像我一样有效。但是我希望课程有一些灵活性,所以我希望这个类能够用不同的函数进行实例化。通过传入指针函数来说。我无法使指针功能实现起作用。下面我定义了两个类,一个具有定义的函数(fixedFunction),另一个带有指向函数的指针(genericFunction)

//Functions.hh
#include <iostream>
#include <stdio.h>

class fixedFunction{
public:
 __host__ fixedFunction() {}
 __host__ __device__ double operator()(double x) {
    return x*x;
 }
};

double f1(double x){
  return x*x;
}

typedef double (*pf) (double var);

class genericFunction{
public:
  __host__ genericFunction(double (*infunc)(double)) : func(infunc){}
  __host__ __device__ double operator()(double x) {
    return func(x);
  }
private:
  pf func;
};

__global__ void kernel1(fixedFunction* g1){
  unsigned int tid = blockIdx.x *blockDim.x + threadIdx.x;
  printf("Func val is: %f\n", (*g1)(tid));
}

__global__ void kernel2(genericFunction* g1){
  unsigned int tid = blockIdx.x *blockDim.x + threadIdx.x;
  printf("Func val is: %f\n", (*g1)(tid));
}

实例化这两个类并在主机上运行它们。传递给相关的内核,我看到该类调用指针函数的kernel2失败

#include "Functions.hh"

int main(){

  fixedFunction h_g1;
  fixedFunction* d_g1;
  cudaMallocManaged(&d_g1, sizeof(h_g1));

  //Host call
  std::cout << h_g1(2.0) << "\n";

  //device call
  kernel1<<<1,32>>>(d_g1);
  cudaDeviceSynchronize();

  genericFunction h_g2(f1);
  genericFunction* d_g2;
  cudaMallocManaged(&d_g2, sizeof(h_g2));

  //Host call
  std::cout << h_g2(3.0) << "\n";

  //device call
  kernel2<<<1,32>>>(d_g2);
  cudaDeviceSynchronize();

我可以看到指针功能中的问题可以是任何大小,并且在设备上没有考虑到。那么有没有办法将指针函数传递给类并在设备上运行它?

由于

1 个答案:

答案 0 :(得分:4)

这大约是最小的&#34;我可以对您的代码进行的更改次数,以使其大致按照您的意图运行。另请注意,关于CUDA中的函数指针还有许多其他问题,this answer链接到几个。

  1. 使用f1装饰__host__ __device__。这是使编译器为其生成设备可调用例程所必需的。否则,仅生成主机代码。

  2. 我们需要捕获上面1中创建的f1设备可调用版本的设备入口地址。有很多方法可以做到这一点。我将捕获它&#34;静态&#34;使用其他__device__变量(f1_d),然后使用cudaMemcpyFromSymbol将其拉入主机代码。

  3. 您的genericFunction类被修改为能够同时保存所需函数的__host__和单独的__device__入口点(函数指针)。此外,根据我们是否正在编译类的主机或设备版本(__CUDA_ARCH__宏),修改类以选择正确的类,并修改类构造函数以接受并分配两个入口点。 / p>

  4. 最后,我们还需要初始化设备上的d_g2对象。在d_g1对象的情况下,该对象没有类数据成员,因此我们可以&#34;逃避&#34;创造一个&#34;空&#34; d_g1指向的对象,它可以正常工作,因为该对象的类成员函数的入口点在设备代码中已知。但是,在d_g2的情况下,我们通过类数据成员间接访问函数,类成员是指向函数的相应主机和设备版本(入口点)的指针。因此,在主机代码中初始化h_g2对象并在设备代码中为d_g2对象建立存储后,我们必须使用{{d_g2的内容初始化h_g2 1 {} cudaMemcpy之后的cudaMallocManaged

  5. 通过这些更改,您的代码按照我的测试编写:

    d_g2