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<<>>(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
怀疑是不是c编译的时候把tmwtypes.h当成库函数的头文件,所以为了保险起见,尝试将其修改为:
#include"tmwtypes.h"
新版的Matlab已经修正此问题
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])&& !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 < numColsA) ? numRowsA : numColsA; 38 int maxSize = (numRowsA > 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);
如上所示,再编译其他文件的时候只用适当的修改文件名就可以了。