具有 CUDA 成员的 C++ class dll?

C++ class dll with CUDA member?

我有一个基于 C++ class 的 dll。我想将一些 class 成员转换为基于 CUDA 的操作。

我用的是VS2012,WINDOWS7,CUDA6.5,sm_20;

假设原始 SuperProjector.h 文件如下:

class __declspec(dllexport) SuperProjector 
{
public:
    SuperProjector(){}; 
    ~SuperProjector(){};
    void sumVectors(float* c, float* a, float* b, int N);
};

和 SuperProjector.cpp

中的原始 sumVector() 函数
void SuperProjector::sumVectors(float* c, float* a, float* b, int N)
{
    for (int n = 1; n < N; b++)
        c[n] = a[n] + b[n];
}

我不知道应该如何将 sumVector() 转换为 CUDA。具体来说:

  1. 我看到一些帖子说在前面添加 __global__ __device__ 关键字 class 个成员可以工作,但我需要更改后缀 cpp 文件到 cu?
  2. 我也试过从一开始就创建一个cuda项目,但是当我选择创建一个CUDA项目时,VS2012似乎没有给我创建一个dll的选项。

我很困惑将这个基于 C++ class 的 dll 的某些成员转换为某些 CUDA 内核函数的最佳方法是什么。我很感激任何人都可以提供一些想法,或者提供一些非常简单的例子。

  1. 创建CUDA项目,我们称之为cudaSuperProjector并添加两个文件SuperProjector.cuSuperProjector.h

    cudaSuperProjector.h

    class __declspec(dllexport) cudaSuperProjector {
    public:
        cudaSuperProjector(){ }
        ~cudaSuperProjector(){ }
        void sumVectors(float* c, float* a, float* b, int N);
    };
    

    cudaSuperProjector.cu

    #include <stdio.h>
    
    #include "cuda_runtime.h"
    #include "device_launch_parameters.h"
    
    #include "cudaSuperProjector.h"
    
    __global__ void addKernel(float *c, const float *a, const float *b) {
        int i = threadIdx.x;
        c[i] = a[i] + b[i];
    }
    
    // Helper function for using CUDA to add vectors in parallel.
    cudaError_t addWithCuda(float *c, const float *a, const float *b, unsigned int size) {
        float *dev_a = 0;
        float *dev_b = 0;
        float *dev_c = 0;
        cudaError_t cudaStatus;
    
        // Choose which GPU to run on, change this on a multi-GPU system.
        cudaStatus = cudaSetDevice(0);
    
        // Allocate GPU buffers for three vectors (two input, one output)    .
        cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(float));
        cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(float));
        cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(float));
    
        // Copy input vectors from host memory to GPU buffers.
        cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(float), cudaMemcpyHostToDevice);
        cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(float), cudaMemcpyHostToDevice);
    
        // Launch a kernel on the GPU with one thread for each element.
        addKernel << <1, size >> >(dev_c, dev_a, dev_b);
        // Check for any errors launching the kernel
        cudaStatus = cudaGetLastError();
        // cudaDeviceSynchronize waits for the kernel to finish, and returns
        // any errors encountered during the launch.
        cudaStatus = cudaDeviceSynchronize();
    
        // Copy output vector from GPU buffer to host memory.
        cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(float), cudaMemcpyDeviceToHost);
        return cudaStatus;
    }
    
    void cudaSuperProjector::sumVectors(float* c, float* a, float* b, int N) {
        cudaError_t cudaStatus = addWithCuda(c, a, b, N);
        if (cudaStatus != cudaSuccess) {
            fprintf(stderr, "cudaSuperProjector::sumVectors failed!");
        }
    }
    

    注意:在文件属性中 cudaSuperProjector.cu Item Type 应该是 CUDA C/C++.

  2. 转到项目的属性并在 General 中将 Configuration Type 的值设置为 Dynamic Library (.dll)。现在创建库的一切都准备好了。编译这个项目,在输出文件夹中你会发现 cudaSuperProjector.dllcudaSuperProjector.lib。创建目录 cudaSuperProjector\lib 并在其中复制 cudaSuperProjector.dllcudaSuperProjector.lib。同时创建 cudaSuperProjector\include 并在其中复制 cudaSuperProjector.h

  3. 创建另一个 Visual C++ 项目,我们称之为 SuperProjector。将文件 SuperProjector.cpp 添加到项目中。

    SuperProjector.cpp

    #include <stdio.h>
    
    #include "cudaSuperProjector/cudaSuperProjector.h"
    
    int main(int argc, char** argv) {
    
        float a[6] = { 0, 1, 2, 3, 4, 5 };
        float b[6] = { 1, 2, 3, 4, 5, 6 };
        float c[6] = {  };
    
        cudaSuperProjector csp;
        csp.sumVectors(c, a, b, 6);
        printf("c = {%f, %f, %f, %f, %f, %f}\n",
               c[0], c[1], c[2], c[3], c[4], c[5]);
    
        return 0;
    }
    
  4. 在项目的属性中将 dlllib 文件的路径添加到 VC++ Directories -> Library Directories,例如 D:\cudaSuperProjector\lib;,在 VC++ Directories -> Include Directories 将路径添加到 header,例如 D:\cudaSuperProjector\include;。然后转到 Linker -> Input 并添加 cudaSuperProjector.lib;.

  5. 现在您的项目应该可以正常编译,但是当您 运行 它会显示错误

    The program can't start because cudaSuperProjector.dll is missing from your computer. Try reinstalling the program to fix this problem.

    您需要将cudaSuperProjector.dll复制到项目的输出文件夹中,因此它将与SuperProjector.exe在同一文件夹下。您可以手动完成或添加

    copy D:\cudaSuperProjector\lib\cudaSuperProjector.dll $(SolutionDir)$(Configuration)\
    

    Build Events -> Post-Build Events -> Command Line中, 其中 $(SolutionDir)$(Configuration)\ 是解决方案的输出路径(参见 Configuration Properties -> General -> Output Directory)。