【问题标题】:How to pass non-static member function of a class into CUDA kernel function (__global__ function)如何将类的非静态成员函数传递给 CUDA 内核函数(__global__ 函数)
【发布时间】:2015-10-20 17:03:01
【问题描述】:

最后,我已经能够将主机函数作为函数指针传递给 CUDA 内核函数(__global__ 函数)。感谢 Robert Crovella 和 njuffa 的回答。我已经能够将类成员函数(cpu 函数)作为函数指针传递给 CUDA 内核。但是,主要问题是,我只能传递静态类成员函数。我无法传递未声明为静态的函数。

我的问题是:如何将非静态成员函数传递给 CUDA 内核

例如:

__host__ __device__ 
static int CellfunPtr(void*ptr, int a);

上述函数之所以起作用,是因为该成员函数被声明为静态成员函数。如果我不将该成员函数声明为静态成员,

__host__ __device__ 
in CellfunPtr(void*ptr, int a);

那就不行了。

完整的代码有四个文件。


fundef.h

typedef int (*pFunc_t)(void* ptr, int N);

solver.h 文件

class CalcVars {

   int eqnCount;
   int numCell;                      
   int numTri;
   int numTet;

public:
   double* cellVel; 
   double* cellPre;

/** Constructor */

CalcVars(
    const int eqnCount_,             
    const int numCell_,          
    const int numTri_,             
    const int numTet_                
);

/** Destructor */

~CalcVars(void);

public:

  void 
      CalcAdv();


  __host__ __device__ 
  static int 
      CellfunPtr(
      void*ptr, int a
);

};

solver.cu

#include "solver.h"
#include "fundef.h"
#include <stdio.h>

__device__ pFunc_t pF1_d = CalcVars::CellfunPtr;

pFunc_t pF1_h ;


__global__ void kernel(int*a, pFunc_t func, void* thisPtr_){
    int tid = threadIdx.x;
    a[tid] = (*func)(thisPtr_, a[tid]); 
};

/* Constructor */

CalcVars::CalcVars(
    const int eqnCount_,             
    const int numCell_,          
    const int numTri_,             
    const int numTet_   

)
{
    this->eqnCount = eqnCount_;
    this->numCell = numCell_;
    this->numTri = numTri_;

    this->cellVel = (double*) calloc((size_t) eqnCount, sizeof(double)); 
    this->cellPre = (double*) calloc((size_t) eqnCount, sizeof(double)); 

}

/* Destructor */

CalcVars::~CalcVars(void)
{
   free(this->cellVel);
   free(this->cellPre);

}


void 
CalcVars::CalcAdv(
){

    /*int b1 = 0;

    b1 = CellfunPtr(this, 1);*/

   int Num = 50;
   int *a1, *a1_dev;

    a1 = (int *)malloc(Num*sizeof(int));

    cudaMalloc((void**)&a1_dev, Num*sizeof(int));

    for(int i = 0; i <Num; i++){
        a1[i] = i;
    }

    cudaMemcpy(a1_dev, a1, Num*sizeof(int), cudaMemcpyHostToDevice);

    //copy addresses of device functions to host 
    cudaMemcpyFromSymbol(&pF1_h, pF1_d, sizeof(pFunc_t));


    kernel<<<1,42>>>(a1_dev, pF1_h, this);

    cudaDeviceSynchronize();

    cudaMemcpy(a1, a1_dev, Num*sizeof(int), cudaMemcpyDeviceToHost);


};


int 
CalcVars::CellfunPtr(
    void* ptr, int a
){
    //CalcVars* ClsPtr = (CalcVars*)ptr;
    printf("Printing from CPU function\n");
    //int eqn_size = ClsPtr->eqnCount;
    //printf("The number is %d",eqn_size);
    return a-1;

};

ma​​in.cpp 文件

#include "solver.h"

int main(){

    int n_Eqn, n_cell, n_tri, n_tetra;
    n_Eqn = 100;
    n_cell = 200;
    n_tri = 300;
    n_tetra = 400;

   CalcVars* calcvars;

   calcvars = new CalcVars(n_Eqn, n_cell, n_tri, n_tetra );

   calcvars->CalcAdv();

   system("pause");

}

【问题讨论】:

    标签: c++ cuda gpu function-pointers gpgpu


    【解决方案1】:

    成员函数的类型不同:

    typedef int (CalcVars::*MethodPtr)(int N);
    
    __device__ MethodPtr pF1_d = &CalcVars::CellfunPtr;
    

    然后你可以使用:

    __global__ void kernel(int*a, MethodPtr func, void* thisPtr_)
    {
        int tid = threadIdx.x;
        CalcVars* c = ((CalcVars*)thisPtr_);
        a[tid] = (c->*func)(a[tid]);
    };
    

    但是你传递给内核的this指针是一个host指针:

    kernel<<<1,42>>>(a1_dev, pF1_h, this);
    

    导致内核中的内存访问无效。

    您必须将 CalcVars 实例的 device 指针传递给内核才能使其工作。


    根据要求,一个完整的可编译示例,它是您的压缩版本,仍然存在我上面写的this 指针问题。

    demo.cu

    #include <stdio.h>
    
    struct CalcVars
    {
      void  CalcAdv();
      __host__ __device__
       int  CellfunPtr(int a);
    };
    
    typedef int (CalcVars::*MethodPtr)(int N);
    
    __device__ MethodPtr pF1_d = &CalcVars::CellfunPtr;
    MethodPtr pF1_h;
    
    __global__ void kernel(int* a, MethodPtr func, void* thisPtr_)
    {
        int tid = threadIdx.x;
        CalcVars* c = ((CalcVars*)thisPtr_);
        a[tid] = (c->*func)(a[tid]);
    };
    
    voidCalcVars::CalcAdv()
    {
       int Num = 50;
       int *a1, *a1_dev;
    
        a1 = (int *)malloc(Num*sizeof(int));
        cudaMalloc((void**)&a1_dev, Num*sizeof(int));
        for (int i = 0; i <Num; i++)
        {
            a1[i] = i;
        }
        cudaMemcpy(a1_dev, a1, Num*sizeof(int), cudaMemcpyHostToDevice);
        cudaMemcpyFromSymbol(&pF1_h, pF1_d, sizeof(MethodPtr));
    
        // DON'T pass the host this pointer here in real code
        kernel<<<1,42>>>(a1_dev, pF1_h, this);
        cudaDeviceSynchronize();
        cudaMemcpy(a1, a1_dev, Num*sizeof(int), cudaMemcpyDeviceToHost);
    };
    
    int CalcVars::CellfunPtr(int a)
    {
        printf("Printing from CPU function\n");
        return a-1;
    };
    
    int main()
    {
       CalcVars calcvars;
       calcvars.CalcAdv();
    }
    

    【讨论】:

    • 我试了一下,但出现以下错误,甚至无法编译代码。 错误:“int (*)(int)”类型的值不能用于初始化“MethodPtr”类型的实体。请您也发布完整的代码。
    • @sa112 我添加了一个可编译的例子
    • @m.s.,非常感谢。我运行了您发布的代码,它编译并运行良好。但是,我特别关心的是,我想访问类变量(例如上面代码中的 numCell、numTri)。基本上,我的要求是,将 CellfunPtr 作为函数指针传递给 cuda global 函数,并访问类变量并修改它们。在我上面发布的示例代码中,我能够通过 global 函数传递 CellfunPtr,但我无法访问 numCell 和 numTri 等变量。提前感谢您的回复。
    • @sa112 你读过上面的“但是你传递给内核的这个指针是一个主机指针:”吗?您不能将主机指针传递给内核并访问/修改其成员变量,这必须是在设备上分配的内存
    猜你喜欢
    • 1970-01-01
    • 2018-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-14
    • 1970-01-01
    • 2014-03-06
    • 2020-12-31
    相关资源
    最近更新 更多