CUDA与C++联合编程很常见,在Matlab工程中很少出现,当Matlab工程很庞大时,将Matlab库函数移动到C++工作量非常大,并且数值精度也无法保证。本文介绍在Matlab环境下CUDA编程。

首先确定有支持CUDA的Nvidia显卡,并且已经正确安装好驱动和SDK等,网上有许多CUDA安装与配置环境的教程。Matlab与CUDA混合编程,首先使用Matlab,C++混合编程,最后C++作为中间介质与CUDA进行调用。(本文测试环境:Win7x64,Matlab2012b,CUDAv6.5)

1、Matlab与C++混合编程

  • 在matlab的CommandWindow里输入mex –setup,选择C++编译器;
  • 测试example
    #include "mex.h"
    // nlhs:输出变量的个数
    // plhs:输出的mxArray矩阵的头指针
    // nrhs:输入变量个数
    // prhs:输入的mxArray矩阵的头指针
    void mexFunction(int nlhs,mxArray* plhs[],int nrhs,const mxArray* prhs[])
    { 
       mexPrintf("Hello, matlab with cuda!\n");
    }
  • 编译C++代码:mex helloMex.cpp,如果成功的话,将产生helloMex.mexw64(或helloMex.mexw32),在Matlab命令行输入helloMex则会输出结果。

mexFunction()是Matlab混合编程必须的函数,作为接口函数,进行参数的传递。

2、Matlab与CUDA混合编程

  1. 创建AddVectors.h & AddVectors.cu(计算核心)
// AddVectors.h
#ifndef __ADDVECTORS_H__
#define __ADDVECTORS_H_
extern void addVectors(float*A, float*B, float*C, int size);
#endif// ____ADDVECTORS_H_
// AddVectors.cu
#include "AddVectors.h"
// mex.h绝对路径,否则识别不了
#include "D:\Program Files\MATLAB\R2012b\extern\include\mex.h"
__global__ void addVectorsMask(float* A, float* B, float* C,int size)
{
        int i=blockIdx.x;
        if(i>=size)
        return;

        C[i]=A[i]+B[i];
}
void addVectors(float* A, float* B, float* C,int size)
{
        float *devPtrA=0;
        float *devPtrB=0;
        float *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);
        mexPrintf("size:%d\n",size);
        mexPrintf("A[0]:%f\n",A[0]);
        mexPrintf("B[0]:%f\n",B[0]);
        mexPrintf("cuda s\n");
        addVectorsMask<<<size,1>>>(devPtrA,devPtrB,devPtrC,size);
        mexPrintf("cuda e\n");
        cudaMemcpy(C,devPtrC,sizeof(float)*size,cudaMemcpyDeviceToHost);
        mexPrintf("C[0]:%f\n",C[0]);
        cudaFree(devPtrA);
        cudaFree(devPtrB);
        cudaFree(devPtrC);
}
  1. 编译AddVectors.cu

system('nvcc -c AddVectors.cu -ccbin "E:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin"')

注意:引号中的部分是”cl.exe”的路径,都在Visual Studio 2010文件夹下,安装路径不同,版本不同,具体的位置也不同,不过都大同小异;还需要将matlab\extern\include\matrix.h#include<tmwtypes.h>修改成#include "tmwtypes.h"

编译后,返回结果0,并生产AddVectors.obj文件,表示操作成功

  1. 创建AddVectorsCuda.cpp(mexFunction),调用计算核心
# include "mex.h"
# include "AddVectors.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[])
{
        if(nrhs !=2)
        mexErrMsgTxt("Invaid number of input arguments");
        
        if(nlhs !=1)
        mexErrMsgTxt("Invaid number of outputs ");

        if(!mxIsSingle(prhs[0])&&!mxIsSingle(prhs[1]))
        mexErrMsgTxt("Input vector data type must be single");

        int numRowsA=(int)mxGetM(prhs[0]);
        int numColsA=(int)mxGetN(prhs[0]);
        int numRowsB=(int)mxGetM(prhs[1]);
        int numColsB=(int)mxGetN(prhs[1]);

        if(numRowsA !=numRowsB || numColsA !=numColsB)
                mexErrMsgTxt("Invalid size. The size of two vectors must be same");
        
        int minSize=(numRowsA<numColsA)?numRowsA:numColsA;
        int maxSize=(numRowsA>numColsA)?numRowsA:numColsA;

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

        float* A=(float*)mxGetData(prhs[0]);
        float* B=(float*)mxGetData(prhs[1]);

        plhs[0]=mxCreateNumericMatrix(numRowsA,numColsB,mxSINGLE_CLASS,mxREAL);
        float* C=(float*)mxGetData(plhs[0]);

        addVectors(A,B,C,maxSize);
}
  1. 联合编译AddVectorsCuda.cpp与AddVectors.obj

mex AddVectorsCuda.cpp AddVectors.obj -lcudart -L"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v6.5\lib\x64"

-L后面接CUDA Toolkit lib目录,调用成功则会生成AddVectorsCuda.mexw64文件,Matlab可以调用AddVectorsCuda。

3、编译过程整合

% runAddVectors.m
clc
clear all
close all

disp('1.nvccAddVectors.cu compiling...');
system('nvcc -c AddVectors.cu -ccbin "E:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin"')
disp('2.C/C++ compiling for AddVectorsCuda.cpp with AddVectors.obj...');
mex AddVectorsCuda.cpp AddVectors.obj -lcudart -L"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v6.5\lib\x64";
disp('3.TestAddVectorsCuda()...');
disp('compile finish!');

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);

相关文章:VC调用Matlab生成的dll文件

引用于:http://blog.csdn.net/endlch/article/details/44561535

标签: GPU, CUDA, Matlab

评论已关闭