将内核函数的参数作为C++结构传递

passing parameters of an kernel function as C++ struct?

本文关键字:C++ 结构 内核 函数 参数      更新时间:2023-10-16

我想将内核函数的参数作为给定的结构传递,如下所示

struct kernel_data {
    double *A;
    double *B;
    double *C;
    const int *A_dims;
    const int *B_dims;
    int C_dims[2];
};

为此,我需要用cudaMalloc()初始化设备指针,但我如何初始化它。 这个函数的这种结构包括我打算传递的这些参数。还是我必须单独通过它们?

只需按值将结构传递给内核,就像将任何其他参数一样:

struct kernel_data args;
cudaMalloc(&(args.A), sizeof(double)*.....);
cudaMalloc(&(args.B), sizeof(double)*.....);
cudaMalloc(&(args.C), sizeof(double)*.....);
cudaMalloc(&(args.A_dims), sizeof(int)*.....);
cudaMalloc(&(args.B_dims), sizeof(int)*.....);
kernel<<<....>>>(args);

参数列表大小有一个理论上的限制,从 256 字节到 4Kb,具体取决于您使用的硬件,如果超过它,请将args结构复制到设备分配并将其作为指针传递,或将其复制到常量内存指针。

要从主机初始化数组,只需使用标准cudaMemcpy调用:

cudaMemcpy(args.A, hostA, sizeof(double)*....., cudaMemcpyHostToDevice);

等。

您可以通过复制将此结构传递给内核。请记住,在费米预费米卡上 4KB 上传递给内核的参数的总大小不得超过 256B。

因此,您必须使用 cudaMalloc 来分配设备内存,而不是在结构中设置指向设备内存的指针。最后,你通过复制将你的结构传递给内核。

我强烈建议您避免在C++代码中使用此 struc。而不是

struct kernel_data {
    double *A;
    double *B;
    double *C;
    const int *A_dims;
    const int *B_dims;
    int C_dims[2];
};

你应该做这样的事情

class DeviceData{
public:   
    DeviceData(...){//Do cudaMalloc here}
    ~DeviceData(...){//Do cudaFree here}
private:
    double *_A;
    int _dims;    
};

此类将保存设备上可用的数据,并且异常安全。比你可以实现一个可以传递给内核的包装器

class DeviceDataWrapper{
public:
    __host__ DeviceDataWrapper(DeviceData& device):
        _A(device._A),
        _dims(device._dims)
        {}
    __forceinline__ __device__ double* data(){return _A;}
    __forceinline__ __device__ int dims()const{return _dims;}
private:
    double *_A;
    int _dims;  
}

然后以这种方式调用内核

__global__ void myKernel(DeviceDataWrapper a, DeviceDataWrapper b, DeviceData2Wrapper c){
 //do something like a.data()[0] = 1;
}
DeviceData A,B;
DeviceData2 C;
myKernel<<< >>>(A,B,C);