Matlab+CUDA混合编程(二)


1. 创建AddVectors.h文件

#ifndef __ADDVECTORS_H__
#define __ADDVECTORS_H_

extern void addVectors(float*A, float*B, float*C, int size);

#endif// ____ADDVECTORS_H_

2. 创建AddVectors.cu函数,这个是CUDA函数

#include "AddVectors.h"
#include "D:Matlab\extern\include\mex.h"

__global__ void addVectorsMask(float*A, float*B, float*C, int size)
{
    int i = threadIdx.x + blockIdx.x * blockDim.x;
    if(i!= size)
        return;

    C[i] = A[i] + B[i];
}

void addVectors(float*A, float*B, float*C, int size)
{
    float *devPtrA = 0,*devPtrB = 0,*devPtrC = 0;
    cudaMalloc(&devPtrA,sizeof(float)* size);
    cudaMalloc(&devPtrB,sizeof(float)* size);
    cudaMalloc(&devPtrC,sizeof(float)* size);

    cudaMemcpy(devPtrA,A, sizeof(float)* size, cudaMemcpyHostToDevice);
    cudaMemcpy(devPtrB,B, sizeof(float)* size, cudaMemcpyHostToDevice);
    addVectorsMask<<<int(size/1024),1024>>>(devPtrA,devPtrB, devPtrC, size);
    cudaMemcpy(C,devPtrC, sizeof(float)* size, cudaMemcpyDeviceToHost);

    cudaFree(devPtrA);
    cudaFree(devPtrB);
    cudaFree(devPtrC);

}

3. 用nvcc编译刚才生成的CUDA函数 执行命令:

system('nvcc  -c AddVectors.cu')

这是可能出现错误,如下:

nvcc : fatal error : Cannot find compiler 'cl.exe' in PATH

出现这个错误应该是环境没有配置好,不过不要紧,可以通过路径直接编译,如4所示

4. 修改步骤3

system('nvcc -c AddVectors.cu -ccbin "D:Visual Studio 2012\VC\bin"')

引号中的部分是”cl.exe”的路径,都在Visual Studio 2012文件夹下,安装路径不同,版本不同,具体的位置也不同,不过都大同小异。 这时是个问题解决了,但又出现下一个问题,如下:

AddVectors.cu(2) : fatal error C1083:无法打开包括文件:“mex.h”:No such file or directory

也就是说找不到mex.h文件,继续修改

5. 修改步骤4

上个问题应该也是环境配置的问题,但是由于懒得麻烦,这次我就用了比较暴力的方法 在AddVectors.cu的包含头文件处直接加上绝对路径:

#include "D:Matlab\extern\includemex.h"

6. 继续步骤4

system('nvcc -c AddVectors.cu -ccbin "D:Visual Studio 2012\VC\bin"')

再次出现错误:

d:matlab\extern\include\matrix.h(252) : fatal error C1083:无法打开包括文件:“tmwtypes.h”:No such file or directory 

意思是找不到tmwtypes.h路径,由于错误是发生在matrix.h文件的252行,因此决定看看到底为何

7. 在matrix.h文件中发现:

#include<tmwtypes.h>

怀疑是不是c编译的时候把tmwtypes.h当成库函数的头文件,所以为了保险起见,尝试将其修改为:

#include "tmwtypes.h" 

8. 继续步骤4

system('nvcc -c AddVectors.cu -ccbin "D:Visual Studio 2012\VC\bin"')  

返回结果0,并生产AddVectors.obj文件,表示操作成功,大功告成。

9. 创建AddVectorsCuda.cpp文件

#include"mex.h"
#include"AddVectors.h"
// nlhs: 输出变量的个数(lefthand side,调用语句的左手面)
// plhs:输出的mxArray矩阵的头指针
// nrhs: 输入变量个数(righthand side,调用语句的右手面)
// prhs:输入的mxArray矩阵的头指针
// 如果有两个输入变量,那么prhs[0]指向第一个变量
//prhs[1]指向第二个变量
// Matlab的array使用mxArray类型来表示。
//plhs和hrhs都是指向mxArray类型的指针数组

void mexFunction(intnlhs, mxArray *plhs[], int nrhs, mxArray *prhs[])
{
    // 判断输入参数个数是否满足条件

    if (nrhs != 2)
        mexErrMsgTxt("Invaidnumber of input arguments");

    if (nlhs != 1)
        mexErrMsgTxt("Invalidnumber of outputs");

    // 判断输入参数的类型是否满足条件
    if (!mxIsSingle(prhs[0])&amp;&amp; !mxIsSingle(prhs[1]))
        mexErrMsgTxt("inputvector data type must be single");

    // 获取输入参数维度
    // mxGetM:得到输入矩阵的行数
    // mxGetN:得到输入矩阵的列数
    int numRowsA = (int)mxGetM(prhs[0]);//那么prhs[0]指向第一个变量
    int numColsA = (int)mxGetN(prhs[0]);
    int numRowsB = (int)mxGetM(prhs[1]);//prhs[1]指向第二个变量
    int numColsB = (int)mxGetN(prhs[1]);

    // 判断输入参数维度是否满足条件
    if (numRowsA != numRowsB || numColsA != numColsB)
        mexErrMsgTxt("Invalidsize. The sizes of two vectors must be same");

    int minSize = (numRowsA &lt; numColsA) ? numRowsA : numColsA; 38 int maxSize = (numRowsA &gt; numColsA) ? numRowsA : numColsA;

    if (minSize != 1)
        mexErrMsgTxt("Invalidsize. The vector must be one dimentional");

    //mxGetData 获取数据阵列中的数据
    float*A = (float*)mxGetData(prhs[0]);
    float*B = (float*)mxGetData(prhs[1]);
    // 生成输入参数的mxArray结构体
    plhs[0]= mxCreateNumericMatrix(numRowsA,numColsB, mxSINGLE_CLASS, mxREAL);

    // 获取输出参数的指针
    float*C = (float*)mxGetData(plhs[0]);

    // 调用子程序
    addVectors(A, B, C, maxSize);
 } 

10. 编译AddVectorsCuda.cpp并与obj文件链接

mex AddVectorsCuda.cpp AddVectors.obj -lcudart -L"C:Program Files\NVIDIA GPU Computing Toolkit\CUDAv5.5\libx64"

生成AddVectorsCuda.mexw64文件。

表示成功。

测试。

11. 测试

A = single([1 2 3 4 5 6 7 8 9 10]); 
B = single([10 9 8 7 6 5 4 3 2 1]); 
C = AddVectorsCuda(A,B); 

得到: C = 11 11 11 11 11 11 11 11 11 11

大功告成。

注: mex命令中的参数:

% -lcudart 表明使用了CUDA运行时库

% -lcublas 表明使用了CUDABLAS库

% -L”…” 使用的库的库文件路径

% -L”…” 使用的库的头文件路径

虽然上述步骤成功了,但是看着步骤是相当繁琐的,因此我们可以考虑将其写到一个函数中,以后再使用的时候进行适当的修改就可。

下面生成runAddVectors.m

%runAddVectors.m
clc
clear all
close all

disp('1.nvccAddVectors.cu compiling...');
system('nvcc-c AddVectors.cu -ccbin "D:Visual Studio2012VCbin"')
disp('nvcccompiling done!');
disp('2.C/C++ compiling for AddVectorsCuda.cpp withAddVectors.obj...');
mex AddVectorsCuda.cpp AddVectors.obj -lcudar-L"C:Program Files\NVIDIA
GPU Computing Toolkit\CUDA\v5.5\libx64"
disp('C/C++compiling done!');
disp('3.TestAddVectorsCuda()...');
disp('Twoinput arrays:');

A = single([1 2 3 4 5 6 7 8 9 10]);
B = single([10 9 8 7 6 5 4 3 2 1]);
C = AddVectorsCuda(A,B);

如上所示,再编译其他文件的时候只用适当的修改文件名就可以了。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页