【问题标题】:Passing arguments from mexfunction to kernel and wrapper function将参数从 mexfunction 传递给内核和包装函数
【发布时间】:2013-10-04 07:05:42
【问题描述】:

我在 Visual Studio 2010 中构建了一个项目,该项目使用一个 mexfunction 和一个在 Cuda 中调用内核函数的包装函数。我的问题是,当我尝试读取传递给包装函数的数据时,程序崩溃了。我在下面粘贴了一些代码,并在出现问题的确切位置添加了一些注释。

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // input validation
    if (nrhs != 2 || nlhs > 1) {
        mexErrMsgTxt("Wrong number of input/output arguments.");
    }
    if (!mxIsSingle(prhs[0]) || !mxIsSingle(prhs[1])) {
        mexErrMsgTxt("Inputs must be single arrays.");
    }
    if (mxIsComplex(prhs[0]) || mxIsComplex(prhs[1])) {
        mexErrMsgTxt("Inputs must be real arrays.");
    }
    if (mxIsSparse(prhs[0]) || mxIsSparse(prhs[1])) {
        mexErrMsgTxt("Inputs must be dense arrays.");
    }
    if (mxGetNumberOfElements(prhs[0]) != mxGetNumberOfElements(prhs[1])) {
        mexErrMsgTxt("Inputs must have the same size.");
    }

    // create ouput array
    mwSize numel = mxGetNumberOfElements(prhs[0]);
    mwSize ndims = mxGetNumberOfDimensions(prhs[0]);
    const mwSize *dims = mxGetDimensions(prhs[0]);
    int rows = mxGetM(prhs[0]); /* Get the dimensions of A */
    int cols = mxGetN(prhs[0]);
    //plhs[0] = mxCreateNumericArray(1, dims, mxSINGLE_CLASS, mxREAL);
    //plhs[0] = mxCreateDoubleMatrix(rows,1,mxREAL);
    // Create a rows-by-3 real float
    plhs[0] = mxCreateNumericMatrix(rows, 1, mxSINGLE_CLASS, mxREAL);

    // get pointers to data
    float *h_c = (float*) mxGetData(plhs[0]);
    float *h_a = (float*) mxGetData(prhs[0]);
    float *h_b = (float*) mxGetData(prhs[1]);

    myGPU::cudaFunction_wrapper(h_a, h_b, h_c, rows, cols);  

.cu文件中存在以下代码。

namespace myGPU
{//begin namespace

extern "C++" void cudaFunction_wrapper( float* h_A, float* h_B, float* h_C, int rows, int cols );

__global__ void cudaFunction( float* A, float* B, float* C, int rows, int cols )
{
    int j = blockDim.x * blockIdx.x + threadIdx.x;
    int i = blockDim.y * blockIdx.y + threadIdx.y;

    int m,n;
    for(m = 0; m < rows; m++)
        for(n = 0; n < cols; n++)
             C[m] = A[m + rows*n];
}

void cudaFunction_wrapper( float* h_A, float* h_B, float* h_C, int rows, int cols )
{

     // Error code to check return values for CUDA calls
    cudaError_t err = cudaSuccess;
    int numElements =  rows * cols;
    size_t size = numElements * sizeof(float);

    // Allocate the device input matrix B
    float *d_A = NULL;
    err = cudaMalloc((void **)&d_A, size);
    if (err != cudaSuccess)
    {
        fprintf(stderr, "Failed to allocate device vector A (error code %s)!\n", cudaGetErrorString(err));
        exit(EXIT_FAILURE);
    }

    // Allocate the device input matrix B
    float *d_B = NULL;
    err = cudaMalloc((void **)&d_B, size);

    if (err != cudaSuccess)
    {
        fprintf(stderr, "Failed to allocate device vector B (error code %s)!\n", cudaGetErrorString(err));
        exit(EXIT_FAILURE);
    }

    // Allocate the device output matrix C
    float *d_C = NULL;

    //the returnen value is a vector
    err = cudaMalloc((void **)&d_C, rows * sizeof(float) );

    if (err != cudaSuccess)
    {
        fprintf(stderr, "Failed to allocate device vector C (error code %s)!\n", cudaGetErrorString(err));
        exit(EXIT_FAILURE);
    }

    printf("Copy input data from the host memory to the CUDA device\n");
    err = cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice);

    if (err != cudaSuccess)
    {
        fprintf(stderr, "Failed to copy vector A from host to device (error code %s)!\n", cudaGetErrorString(err));
        exit(EXIT_FAILURE);
    }

    err = cudaMemcpy(d_B, h_B, size, cudaMemcpyHostToDevice);

    if (err != cudaSuccess)
    {
        fprintf(stderr, "Failed to copy vector B from host to device (error code %s)!\n", cudaGetErrorString(err));
        exit(EXIT_FAILURE);
    }

    // Launch the Vector Add CUDA Kernel
    int threadsPerBlock = 256;
    int blocksPerGrid =(numElements + threadsPerBlock - 1) / threadsPerBlock;

    printf("CUDA kernel launch with %d blocks of %d threads\n", blocksPerGrid, threadsPerBlock);

   /* 
    /////////////////////////////////////////////////////
    ///////////// Works WHEN ACCESS h_A /////////////////
    /////////////////////////////////////////////////////

    int m,n;
    for(m = 0; m < rows; m++)
        for(n = 0; n < cols; n++)
             mexPrintf("%f \n", h_A[m + rows*n]) ;

    /////////////////////////////////////////////////////
    ///////////// IT CRASHES HERE WHEN ACCESS d_B ///////
    /////////////////////////////////////////////////////
        for(m = 0; m < rows; m++)
        for(n = 0; n < cols; n++)
             mexPrintf("%f \n", d_B[m + rows*n]) ;

    */

    cudaFunction<<<blocksPerGrid, threadsPerBlock>>>( d_A, d_B, d_C, rows, cols );


    err = cudaGetLastError();

    if (err != cudaSuccess)
    {
        fprintf(stderr, "Failed to launch vectorAdd kernel (error code %s)!\n", cudaGetErrorString(err));
        exit(EXIT_FAILURE);
    }


    // Copy the device result vector in device memory to the host result vector
    // in host memory.
    printf("Copy output data from the CUDA device to the host memory\n");
    err = cudaMemcpy(h_C, d_C, rows * sizeof(float) , cudaMemcpyDeviceToHost);

    if (err != cudaSuccess)
    {
        fprintf(stderr, "Failed to copy vector C from device to host (error code %s)!\n", cudaGetErrorString(err));
        exit(EXIT_FAILURE);
    }


    // Free device global memory
    err = cudaFree(d_A);

    if (err != cudaSuccess)
    {
        fprintf(stderr, "Failed to free device vector A (error code %s)!\n", cudaGetErrorString(err));
        exit(EXIT_FAILURE);
    }
    err = cudaFree(d_B);

    if (err != cudaSuccess)
    {
        fprintf(stderr, "Failed to free device vector B (error code %s)!\n", cudaGetErrorString(err));
        exit(EXIT_FAILURE);
    }

    err = cudaFree(d_C);

    if (err != cudaSuccess)
    {
        fprintf(stderr, "Failed to free device vector C (error code %s)!\n", cudaGetErrorString(err));
        exit(EXIT_FAILURE);
    }

    // Reset the device and exit
    err = cudaDeviceReset();

    if (err != cudaSuccess)
    {
        fprintf(stderr, "Failed to deinitialize the device! error=%s\n", cudaGetErrorString(err));
        exit(EXIT_FAILURE);
    }


}


}//end namespace 

我还想问的第二个问题是,我们如何通过附加Nsight 来调试VS 中的进程。我按照http://http.developer.nvidia.com/NsightVisualStudio/2.2/Documentation/UserGuide/HTML/Content/Attach_CUDA_to_Process.htm 中的说明进行操作,但无法启用附加按钮。顺便说一句,Matlab 是我想附上的程序。

提前谢谢你。

PS:Win 7 84x、CUDA SDK 5.5、Visual Studio 2010、Matlab 2011a

【问题讨论】:

  • 你不想把这个plhs[0] = mxCreateNumericMatrix(rows, 1, mxSINGLE_CLASS, mxREAL); 变成plhs[0] = mxCreateNumericMatrix(rows, cols, mxSINGLE_CLASS, mxREAL);吗?
  • 那是因为输出是一个向量,这就是为什么我使用 err = cudaMalloc((void **)&d_C, rows);
  • 好的,但是在cudaFunction 中,您正在迭代该内存,就好像它是一个矩阵C[m + rows*n] = A[m + rows*n];C 没有分配足够的内存,并且您超出了界限。这应该是什么cudaFunctio&lt;&lt;&lt;blocksPerGrid, threadsPerBlock&gt;&gt;&gt;(...);
  • @Praetorian: 这是 cudaFunction( float* A, float* B, float* C, int rows, int cols ),拼写错误。我认为问题在于分配内存。因为它在 d_B 中崩溃,在进入内核(cmets)之前。
  • 您是否在这里看到过 Nsight+MATLAB 的解决方案:stackoverflow.com/questions/11732840/…

标签: visual-studio-2010 matlab cuda gpu mex


【解决方案1】:

对于d_C,您不应该使用cudaMalloc((void **)&amp;d_C, rows*sizeof(float)); 而不是cudaMalloc((void **)&amp;d_C, rows);吗?

关于mexPrintf("%f \n", d_B[m + rows*n]) 上的崩溃,d_B 是设备 (GPU) 内存的事实在这里不是问题吗?

此外,Praetorian 所说的plhs[0] 创建对于h_c 所需的缓冲区来说太小了。

【讨论】:

  • 刚刚添加了一条关于mexPrintf 崩溃与d_B 的注释。也许这是不正确的,但自从您查看 h_A 和另一个 mexPrintf 测试后,这似乎很可疑......
  • 我按照您和 Praetorian 的建议进行了以下更改,并且有效。 C[m + rows*n] = A[m + rows*n]; -&gt; C[m] = A[m + rows*n];err = cudaMalloc((void **)&amp;d_C, rows ); -&gt; err = cudaMalloc((void **)&amp;d_C, rows * sizeof(float) ); 当然还有当我们复制内存时err = cudaMemcpy(h_C, d_C, rows , cudaMemcpyDeviceToHost); -&gt; err = cudaMemcpy(h_C, d_C, rows * sizeof(float) , cudaMemcpyDeviceToHost);。另外关于调试过程,我想在 GPU 中进行简单的调试,断点在 VS 上附加了 matlab,而不是分析代码。任何建议都会有所帮助。
  • 我不确定 Nsight 是否适用于 GPU,但是当我从 VS IDE 构建 MEX 文件时,我可以附加到 MATLAB.exe 进行调试。我不确定为什么它对 Nsight 不起作用......对不起。
  • 好的,谢谢。因为关于 Nsight 的问题是稍后添加的,所以我将把这篇文章作为已回答的内容停放,我将发布一篇关于使用 Nsight 进行调试的独立帖子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-21
  • 2019-01-16
  • 2015-01-30
  • 2015-07-22
  • 1970-01-01
相关资源
最近更新 更多