Matlab、C/C++和GPU聯合編程環境配置

一、系統配置:

操作系統: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:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章