一、系統配置:
操作系統: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: