目录
一. 环境配置
1. GPU+VisualStudio+Matlab版本适配性查看
2. Matlab环境配置
二. 使用Matlab编译CUDA工程
1. 建立CUDA工程并编写GPU代码
2. 编写可供Matlab编译的CUDA代码
2.1 包含的头文件
2.2 程序入口函数mexFunction
3. 使用Matlab编译CUDA工程并调用
3.1 mexcuda编译指令
3.2 调用方法
总结一下之前做的工作,想到哪里写到哪里,以后遇到问题会继续更新~~~~
———————————————————以下为正式内容—————————————————
一. 环境配置
1. GPU+VisualStudio+Matlab版本适配性查看
查看本机matlab支持的vs版本信息:Matlab安装路径\bin\win64\mexopts
查看本机Matlab支持哪个版本的GPU:GPU Support by Release- MATLAB & Simulink- MathWorks 中国https://ww2.mathworks.cn/help/parallel-computing/gpu-support-by-release.html
2. Matlab环境配置
首先在matlab命令行输入
mex -setup C++
使用适合本机的Vs编译Cuda程序
二. 使用Matlab编译CUDA工程
1. 建立CUDA工程并编写GPU代码
1.1 点击VisualStudio图标,点击创建新项目
1.2. 选择CUDA 11.3 Runtime(11.3为本机安装的CUDA ToolKit版本)
1.3. 编写GPU代码。
1.4 几点建议
(1)为了便于确定代码执行的正确性,建议先用一般的c语言标准编写代码并验证正确性 。
(2)编写头文件时,规范使用#ifdef、#define、#endif防止头文件嵌套包含时的重复调用,不建议使用#pragma once,因为#ifdef、#define、#endif受C/C++语言标准支持,不受编译器的限制,而#pragma once受编译器的限制,mexcuda编译器不一定支持#pragma once。
#ifndef _HeadFileName_H // _HeadFileName为当前头文件的名称
#define _HeadFileName_H
/*** 头文件内容 ***/
#endif
(3)在核函数中使用pow函数时,最好使用powf(CUDA内置的加速函数)代替,防止后续Matlab端编译错误
(4)如果在代码中使用了动态并行,需要将属性-> CUDA C/C++ -> Generate Relocatable Device Code设置为 是(-rdc=true)
2. 编写可供Matlab编译的CUDA代码
2.1 包含的头文件
在项目中添加新建项 mexFunction.h,头文件内容如下
#ifndef _mexFunction_H
#define _mexFunction_H
#include "MatlabPath\extern\include\mex.h"
#include "MatlabPath\toolbox\parallel\gpu\extern\include\gpu\mxGPUArray.h"
#endif
MatlabPath是本机Matlab的安装目录,需要注意的是,因为matlab版本的更新,mex和mxGPUArray的文件路径可能与上述不符,此时在Matlab安装目录中搜索mex.h和mxGPUArray.h,将搜索结果所在的路径复制过来即可。
2.2 程序入口函数mexFunction
与c语言不同,使用Matlab编译代码时的程序入口函数为mexFunction函数,函数定义规范为
void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
/**** 程序内容 ****/
}
文件中需要包含2.1中定义的“mexFunction.h”头文件。
1.接口参数定义
参数名称 | 参数含义 |
nlhs | 输出变量个数 |
plhs | 输入变量指针数组 |
nrhs | 输入变量个数 |
prhs | 输入变量指针数组 |
2.参数传递方法为
(1)获取实数输入变量
//获取实数指针
AfterRvpDataReal = (float*)mxGetPr(prhs[0]);// float或int或double
(2)获取复数输入变量
//获取实部指针
double* real = (double*)mxGetPr(prhs[0]);
//获取虚部指针:
double* imag = (double*)mxGetPi(prhs[0]);
(3)获取字符串输入变量
需要使用mxArrayToString对输入变量类型进行转化。
char* path = mxArrayToString(prhs[5]);
(4)获取矩阵大小
//输入矩阵的行数
row = mxGetM(prhs[0]);
//输入矩阵的列数
column = mxGetN(prhs[0]);
(5)初始化实数输出变量
plhs[0] = mxCreateNumericMatrix(DistanceNum*AzimuthNum, 1, mxSINGLE_CLASS, mxREAL);
real = (float*)mxGetPr(plhs[0]);
plhs[1] = mxCreateNumericMatrix(DistanceNum*AzimuthNum, 1, mxSINGLE_CLASS, mxREAL);
imag = (float*)mxGetPr(plhs[1]);
(6)初始化复数输出变量
plhs[0] = mxCreateNumericMatrix(rawNum, columnNum, mxSINGLE_CLASS, mxCOMPLEX);
real = (float*)mxGetPr(plhs[0]);
imag = (float*)mxGetPi(plhs[0]);
假设是2*5矩阵(rawNum = 2,columnNum = 5)
real[6] = {1,2,3,4,5,6,7,8,9,10};imag[6] = {1,3,5,7,9,11,13,15,17,19}
则传回matlab的矩阵是:
(7)一个例程:
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, mxArray const *prhs[])
{
double* a = (double*)mxGetPr(prhs[0]);
double* b = (double*)mxGetPi(prhs[0]);
int c = mxGetM(prhs[0]);
double* real;
double* image;
plhs[0] = mxCreateNumericMatrix(2, 5, mxDOUBLE_CLASS, mxCOMPLEX);
real = (double*)mxGetPr(plhs[0]);
image = (double*)mxGetPi(plhs[0]);
for (int i = 0; i < 10; i++)
{
real[i] = i;
image[i] = 2 * i + 1;
}
printf("------------------\n");
printf("%f,%f,%f,%f\n", a[0],a[1],a[2],a[3]);
printf("%f,%f,%f,%f\n", b[0], b[1], b[2], b[3]);
printf("%d\n",c);
printf("------------------");
}
3. 使用Matlab编译CUDA工程并调用
3.1 mexcuda编译指令
Matlab编译CUDA工程使用mexcuda指令,该指令的说明文档在
Compile MEX-function for GPU computation - MATLAB mexcuda - MathWorks 中国https://ww2.mathworks.cn/help/parallel-computing/mexcuda.html接下来对该指令的应用进行简单的说明。
(1)如果工程中有多个源文件option1,option2,……,optionN,则需要输出使用到的所有源文件的路径,此处建议输入文件的完整路径(绝对路径),而非相对路径,例如:
mexcuda E:\Work\cudaSource1.cu E:\Work\cudaSource2.cu E:\Work\cSource1.cpp...
E:\Work\cSource2.cpp
(2)如果文件中使用了动态并行,则需要在对应的文件前面加上-dynamic,例如:
mexcuda -dynamic E:\Work\cudaDynamicSource1.cu ...
E:\Work\cudaNoDynamicSource2.cu ...
-dynamic E:\Work\cudaDynamicSource3.cu ...
E:\Work\cSource1.cpp ...
(3) 如果文件中使用了CUDA库函数(cufft、cublas等),则需要加入库函数路径,格式是
‘库函数完整文件路径’ -l+库函数名称,例如:
mexcuda 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.3\lib\x64\cufft.lib' -lcufft ...
-dynamic E:\Work\cudaDynamicSource1.cu ...
E:\Work\cudaNoDynamicSource2.cu ...
-dynamic E:\Work\cudaDynamicSource3.cu ...
E:\Work\cSource1.cpp ...
(4)按回车后,出现MEX已成功完成证明编译成功,此时文件夹中应该出现.mexw64执行文件,该文件名称与mexcuda指令后的第一个文件名保持一致,例如,(3)中生成的文件名称为cudaDynamicSource1.mewx64。
(5) 可能出现的问题以及修正方法
解决方法:将printf函数更换为mexPrintf函数,使用时同样需要包含头文件"mex.h"和"mxGPUArray.h"两个头文件,即2.1中定义的“mexFunction.h”头文件。
改正方法:按照 2. 编写可供Matlab编译的CUDA代码 中的方法编写mexFucntion函数
出现原因:在核函数中使用了cpu函数pow()
改正方法:将核函数中的pow改为powf
- 错误信息:redefine/无法重载仅以返回类型区分的函数
出现原因:头文件重复定义
改正方法:在头文件开头和结尾加入:#ifndef,#define,#endif
F:\HSCdownload\Matlab\R2020b\extern\include\matrix.h(756): error C2143: 语法错误: 缺少“)”(在“常数”的前面)
F:\HSCdownload\Matlab\R2020b\extern\include\matrix.h(756): error C2143: 语法错误: 缺少“;”(在“常数”的前面)
F:\HSCdownload\Matlab\R2020b\extern\include\matrix.h(756): error C2059: 语法错误:“常数”
F:\HSCdownload\Matlab\R2020b\extern\include\matrix.h(757): error C2059: 语法错误:“)”
出现原因:具体的咱也不清楚
改正方法:把“mex.h”和“mxGPUArray.h”的头文件包含放在自定义头文件的前面,例如:将下方代码段
-
//标准库部分
#include <stdio.h>
#include <stdlib.h>
//自定义头文件
#include "a.h"
//mexFuntion头文件
#include "F:\HSCdownload\Matlab\R2020b\extern\include\mex.h"
#include "F:\HSCdownload\Matlab\R2020b\toolbox\parallel\gpu\extern\include\gpu\mxGPUArray.h"
改为:
//标准库部分
#include <stdio.h>
#include <stdlib.h>
//mexFuntion头文件
#include "F:\HSCdownload\Matlab\R2020b\extern\include\mex.h"
#include "F:\HSCdownload\Matlab\R2020b\toolbox\parallel\gpu\extern\include\gpu\mxGPUArray.h"
//自定义头文件
#include "a.h"
-
错误信息
error C2059: 语法错误:“<”
出现原因:出现错误的位置是核函数调用时候的<<< >>>,所以是因为在c/c++文件中调用了核函数
改正方法:对应的文件由.cpp改为.cu即可
3.2 调用方法
调用mexw64文件的方法与函数调用方法相同,但是要注意,如果cuda代码中的参数精度为float、int等,需要先在matlab中进行类型转化,转化方法为:
单精度参数:single(var)
整型参数:int32(var)
将参数传回matlab端后,需要使用gather()函数将结果转化为matlab中的数据类型以便进行后续处理。
% 调用cudaDynamicSource1.mmexw64程序
% cuda代码中matInPutVar1为双精度类型,matInPutVar2为单精度类型,matInPutVar3为整型
cudaInPutVar1 = matInPutVar1;
cudaInPutVar2 = single(matInPutVar2);
cudaInPutVar3 = int32(matInPutVar3);
[cudaOut1, cudaOut2] = cudaDynamicSource1(cudaInPutVar1 , cudaInPutVar2 , cudaInPutVar2 );
% 将cuda输出转化为Matlab的数据类型
matOut1 = double(gather(cudaOut1);
matOut2 = double(gather(cudaOut2);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)