一、系统配置:
操作系统:Microsoft Windows [版本 10.0.17763.529]
Matlab版本:Matlab 2017b 64位
CUDA版本:CUDA 10
VS版本:Visual Studio 2017(以下简称VS2017)
GPU:RTX 2070
二、应用场景描述:
最近在探索学习Matlab + C/C++ + GPU联合编程。该编程方法,依靠Matlab平台编写运行能调用GPU运算的C/C++程序,从而达到加速程序运行的效果。
采用C/C++语言编写的MATLAB函数称为c-mex文件,其相对于Matlab使用的解释性编程语言,可以被提前编译成字节文件以加速运行。并且c-mex文件能无限封装成函数相互调用,增强了MATLAB编程中的可扩展能力。
使用NVIDIA公司提供的GPU硬件和软件支持,能编程实现cu文件运行到GPU上。合理使用GPU资源能将程序计算耗时成倍降低。
三、环境搭建
1. 环境预配置
VS+CUDA的搭建方法详见另一篇博客(https://blog.csdn.net/weixin_40106401/article/details/89929816) ,这里强调使用VS2017,并且应先安装VS再安装CUDA。
2. C/C++编译器选择
这里因为不仅仅使用Matlab编译运行C/C++程序,还要编译运行GPU程序,所以在选择C/C++编译器时参考下表,官方提供Matlab针对不同编译场景推荐的编译器(Complier)。由于我们需要用到GPU,所以建议选择VS2017,并配置好VS2017+CUDA联合编程环境。
查询链接:https://ww2.mathworks.cn/support/requirements/supported-compilers.html
所以,VS2017+CUDA预先配置好极为重要!预先配置好的VS2017+CUDA包含Matlab编译c-mex用到的编译器。
3. Matlab设置
mex -setup
设置测试:
以上代码可以复制粘贴如下:
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
mexPrintf("mahello,mex!\n");
}
进行编译:mex helloMex.cpp
运行:helloMex
四、实例测试:
接下来进行向量求和的实例测试,步骤和代码如下:
1.创建头文件AddVectors.h,并写入代码:
#ifndef __ADDVECTORS_H__
#define __ADDVECTORS_H__
extern void addVectors(float* A, float* B, float* C, int size);
#endif
2.创建文件AddVectors.cu,并写入代码:
#include "AddVectors.h"
__global__ void addVectorsKernel(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, *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);
addVectorsKernel<<<size, 1>>>(devPtrA, devPtrB, devPtrC, size);
cudaMemcpy(C, devPtrC, sizeof(float) * size, cudaMemcpyDeviceToHost);
cudaFree(devPtrA);
cudaFree(devPtrB);
cudaFree(devPtrC);
}
3.编译cu文件生成obj文件,编译指令:
system('nvcc -c AddVectors.cu')
显示如下表示成果:
4.创建AddVectorsCuda.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]);
plhs[0] = mxCreateNumericMatrix(numRowsA, numColsB, mxSINGLE_CLASS, mxREAL);
float* C = (float*)mxGetData(plhs[0]);
addVectors(A, B, C, maxSize);
}
4.编译mex,指令为:
mex AddVectorsCuda.cpp AddVectors.obj -lcudart -L"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\lib\x64"
可以得到.mexw64文件,所有文件可以被展示为:
以上内容为mex生成全部步骤,可以被描述为下图:
需要注意,以上操作生成的结果为mexw64文件,其函数调用入口为:mexw64文件的文件名(不包含后缀)
5.测试效果
编译可能报错1:
system(‘nvcc -c AddVectors.cu’)
nvcc fatal : Cannot find compiler ‘cl.exe’ in PATH
解决方法:
将VS2017内 cl.exe编译器对应的位置添加到系统环境变量中,并重启Matlab。
寻找cl.exe建议使用Everything: