Step 1: 安装Visual Studio 2012(或以上版本)
Step 2: 安装CUDA 7.0
安装完毕后,可以看到系统中多了CUDA_PATH和CUDA_PATH_V6_0两个环境变量,接下来,还要在系统中添加以下几个环境变量:
CUDA_SDK_PATH = C:\ProgramData\NVIDIA Corporation\CUDA Samples\v7.0
CUDA_LIB_PATH = %CUDA_PATH%\lib\x64
CUDA_BIN_PATH = %CUDA_PATH%\bin
CUDA_SDK_BIN_PATH = %CUDA_SDK_PATH%\bin\win64
CUDA_SDK_LIB_PATH = %CUDA_SDK_PATH%\common\lib\x64
然后,在系统变量PATH的末尾添加:
;%CUDA_LIB_PATH%;%CUDA_BIN_PATH%;%CUDA_SDK_LIB_PATH%;%CUDA_SDK_BIN_PATH%;
注意:CUDA一定要在VS之后安装
Step 3: 安装Matlab R2014(或其他版本)
Step 4: c-mex配置,在Matlab的命令行窗口中输入如下命令
可以看到,Matlab已经自动选择了VC 2012的C编译器进行C语言的编译。
Step 5: 测试c-mex是否可用
1. 在当前文件夹下建立一个新的文件夹(也可以在任意位置下建立),如”HelloMex”。然后双击进入该文件夹
2. 新建一个Matlab脚本,然后保存为.cpp文件
注意:文件的保存类型要选择为“所有文件(*.*)
3. 在hellomex.cpp中键入以下代码,然后保存
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
mexPrintf("Hello, mex!\n");
}
4. 在Matlab命令行窗口中键入以下命令,编译文件hellomex.cpp
由上图可知,MEX文件编译成了。我们还可以看到在当前文件夹下,生成了目标文件”hellomex.mexw64"
5. 在Matlab中调用。在Matlab中,我们使用文件名调用Mex目标文件,如下:
到此,在Matlab中调用c-mex的一个简单的例子已经测试完毕。
Step 6: 测试CUDA是否可用
1. 在Matlab命令行窗口输入以下命令
出现以上提示说明CUDA环境是配置好了的,即系统中安装了nvcc编译器。
如果系统提示没有nvcc编译器,说明你没有安装CUDA。
2. 新建一个脚本,输入以下代码并保存为“AddVectors.h”
#ifndef __ADDVECTORS_H__
#define __ADDVECTORS_H__
extern void addVectors(float* A, float* B, float* C, int size);
#endif
3. 新建一个脚本,输入以下代码,并保存为“AddVectors.cu"(.cu代表CUDA代码)
#include "addVectors.h"
#include "mex.h"
//cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);
__global__ void addVectorsMask(float* a, float* b, float* c, int size)
{
int i = threadIdx.x;
if( i >= size ) return;
c[i] = a[i] + b[i];
}
// Helper function for using CUDA to add vectors in parallel.
void addVectors(float* a, float* b, float* c, 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);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaSetDevice failed! Do you have a CUDA-capable GPU installed?");
goto Error;
}
// Allocate GPU buffers for three vectors (two input, one output) .
cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(float));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
goto Error;
}
cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(float));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
goto Error;
}
cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(float));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
goto Error;
}
// Copy input vectors from host memory to GPU buffers.
cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(float), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
goto Error;
}
cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(float), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
goto Error;
}
// Launch a kernel on the GPU with one thread for each element.
addVectorsMask<<<1, size>>>(dev_c, dev_a, dev_b,size);
// Check for any errors launching the kernel
cudaStatus = cudaGetLastError();
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "addKernel launch failed: %s\n", cudaGetErrorString(cudaStatus));
goto Error;
}
// cudaDeviceSynchronize waits for the kernel to finish, and returns
// any errors encountered during the launch.
cudaStatus = cudaDeviceSynchronize();
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
goto Error;
}
// Copy output vector from GPU buffer to host memory.
cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(float), cudaMemcpyDeviceToHost);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
goto Error;
}
Error:
cudaFree(dev_c);
cudaFree(dev_a);
cudaFree(dev_b);
}
4. 新建一个脚本文件,输入以下代码,保存为”AddVectors.cpp“
#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("Invalid 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 sizes 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]);
//create the output vector
plhs[0] = mxCreateNumericMatrix(numRowsA, numColsB, mxSINGLE_CLASS, mxREAL);
float* C = (float*)mxGetData(plhs[0]);
addVectors(A, B, C, maxSize);
}
5. 使用nvcc编译器编译".cu"文件,
编译完成后,在当前文件夹下可以看到生成了".obj"目标文件。
这一步可能出现找不到编译器'cl.exe'的错误,如下:
出现这个错误的原因是在系统变量”PATH“中没有添加VC编译器”cl.exe"的路径,找到该路径并添加便可。
“cl.exe”在VS安装路径下的“VC\bin”中,将这个路径添加到系统变量“PATH”的末尾。
注意:要使环境变量生效,还需重启计算机或者注销用户。
6. 编译mex文件并链接到生成的CUDA目标文件,命令为“mex AddVectors.cpp addVectors.obj -lcudart -L"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.0\lib\x64"
命令行窗口提示”MEX 已成功完成“,在当前目录下,我们可以看到生成的文件”AddVectors.mexw64"
7. 在Matlab中调用,如下: