更新2018.06.14
最近有使用Matlab通过mex调用CUDA加速视频处理的需求,于是折腾了一下,网上的说法可谓千奇百怪众说纷纭,却没有能用的。经过六个多小时的反复搜索和尝试,本人终于成功编译运动了了matlab的mexCUDA例程:mexGPUExample.cu。
1.软件环境
这个过程涉及三个环境:Visual Studio、Cuda Toolkit和Matlab。其中Cuda依赖Visual Studio、Matlab依赖Cuda和Visual Studio。官方正式支持的版本关系如下表:
Matlab版本 | CUDA版本 | Visual Studio版本 |
---|---|---|
2016a | 8.0 | 2013 |
2017b | 8.0 | 2013 |
本人用的Win7系统(64位),Matlab2017b、Cuda 8.0和VS2013。
2.步骤
-
Matlab通过mex使用CUDA可以分为三步:
-
1 首先准备好cuda kernel文件(Matlab 自带,我的在下面的位置):
“D:\Program Files\MATLAB\R2014b\toolbox\distcomp\gpu\extern\src\mex\mexGPUExample.cu” - 2 编写一个testMexCuda.m文件,内容如下:
#设置环境变量
setenv(‘CUDA_PATH’, ‘C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5’);
setenv(‘CUDA_BIN_PATH’,‘C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\bin’);
setenv(‘CUDA_LIB_PATH’, ‘C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\lib’);
编译(-v为显示详细信息,利于查错)
mex -v mexGPUExample.cu
运行测试程序
x = ones(4,4,‘gpuArray’);
y = mexGPUExample(x)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-
注意如果你使用的CUDA版本不是8.0,请将8.0改为你的版本号(如7.5,6.5,6.0等)。
-
3 将mex_CUDA_win64.xml文件复制到testMexCuda.m文件所在的目录,并修改为内容如下
(”D:\Program Files\MATLAB\R2014b\toolbox\distcomp\gpu\extern\src\mex\win64\mex_CUDA_win64.xml”)
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Copyright 2013-2014 The MathWorks, Inc. -->
<config
Name="NVIDIA CUDA Compiler"
ShortName="nvcc"
Manufacturer="NVIDIA"
Version="7.5"
Language="CUDA"
Priority="A"
Location="$NVCC" >
<Details
CompilerExecutable="$COMPILER"
CompilerDefines="$COMPDEFINES"
CompilerFlags="$COMPFLAGS"
OptimizationFlags="$OPTIMFLAGS"
DebugFlags="$DEBUGFLAGS"
IncludeFlags="$INCLUDE"
LinkerExecutable="$LINKER"
LinkerFlags="$LINKFLAGS"
LinkerLibraries="$LINKLIBS"
LinkerOptimizationFlags="$LINKOPTIMFLAGS"
LinkerDebugFlags="$LINKDEBUGFLAGS"
CommandLineShell="$VCVARSALLDIR\VCVARSALL.BAT "
CommandLineShellArg=" amd64 "
CompilerDefineFormatter="--compiler-options=/D%s"
LinkerLibrarySwitchFormatter="lib%s.lib;%s.lib"
LinkerPathFormatter="/LIBPATH:%s"
LibrarySearchPath="$$LIB;$$LIBPATH;$$PATH;$$INCLUDE;$MATLABROOT\extern\lib\$ARCH\microsoft"
/>
<!-- Switch guide: http://msdn.microsoft.com/en-us/library/fwkeyyhe(v=vs.71).aspx -->
<vars
CMDLINE100="$COMPILER -c $COMPFLAGS $OPTIM $COMPDEFINES $INCLUDE $SRC -o $OBJ"
CMDLINE200="$LINKER $LINKFLAGS $LINKTYPE $LINKOPTIM $LINKEXPORT $LINKLIBS $OBJS /out:$EXE"
CMDLINE250="mt -outputresource:$EXE;2 -manifest $MANIFEST"
CMDLINE300="del $OBJ $EXP $LIB $MANIFEST $ILK"
COMPILER="nvcc"
COMPFLAGS="-gencode=arch=compute_20,code=sm_20 -gencode=arch=compute_30,code=sm_30 -gencode=arch=compute_50,code=\"sm_50,compute_50\" --compiler-options=/c,/GR,/W3,/EHs,/nologo,/MD"
COMPDEFINES="--compiler-options=/D_CRT_SECURE_NO_DEPRECATE,/D_SCL_SECURE_NO_DEPRECATE,/D_SECURE_SCL=0,$MATLABMEX"
MATLABMEX="/DMATLAB_MEX_FILE"
OPTIMFLAGS="--compiler-options=/O2,/Oy-,/DNDEBUG"
INCLUDE="-I"$MATLABROOT\extern\include&quot; -I&quot;$MATLABROOT\simulink\include""
DEBUGFLAGS="--compiler-options=/Z7"
LINKER="link"
LINKFLAGS="/nologo /manifest"
LINKTYPE="/DLL "
LINKEXPORT="/EXPORT:mexFunction"
LINKLIBS="/LIBPATH:"$MATLABROOT\extern\lib\$ARCH\microsoft" libmx.lib libmex.lib libmat.lib gpu.lib cudart.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib"
LINKDEBUGFLAGS="/debug /PDB:"$TEMPNAME$LDEXT.pdb""
LINKOPTIMFLAGS=""
OBJEXT=".obj"
LDEXT=".mexw64"
SETENV="set COMPILER=$COMPILER
set COMPFLAGS=$COMPFLAGS $COMPDEFINES
set OPTIMFLAGS=$OPTIMFLAGS
set DEBUGFLAGS=$DEBUGFLAGS
set LINKER=$LINKER
set LINKFLAGS=$LINKFLAGS /export:%ENTRYPOINT% $LINKTYPE $LINKLIBS $LINKEXPORT
set LINKDEBUGFLAGS=/debug /PDB:"%OUTDIR%%MEX_NAME%$LDEXT.pdb"
set NAME_OUTPUT=/out:"%OUTDIR%%MEX_NAME%%MEX_EXT%""
/>
<locationFinder>
<VSROOT>
<and>
<envVarExists name="VS120COMNTOOLS" />
<fileExists name="$$\..\..\VC\bin\amd64\cl.exe"</span> /></span>
<span class="hljs-tag"><<span class="hljs-title">dirExists</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"$$\..\..\.." />
</and>
</VSROOT>
<SDKROOT>
<or>
<hklmExists path="SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" name="InstallationFolder" />
<hkcuExists path="SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" name="InstallationFolder" />
</or>
</SDKROOT>
<PROF_ENV>
<and>
<envVarExists name="VS120COMNTOOLS" />
<fileExists name="$$\..\IDE\devenv.exe"</span> /></span>
<span class="hljs-tag"><<span class="hljs-title">not</span>></span>
<span class="hljs-tag"><<span class="hljs-title">fileExists</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"$$\..\IDE\VCExpress.exe" />
</not>
</and>
</PROF_ENV>
<VCVARSALLDIR>
<and>
<envVarExists name="VS120COMNTOOLS" />
<fileExists name="$$\..\..\VC\vcvarsall.bat"</span> /></span>
<span class="hljs-tag"><<span class="hljs-title">dirExists</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"$$"/>
</and>
</VCVARSALLDIR>
<CUDA_LIB_PATH>
<or>
<and>
<envVarExists name="CUDA_LIB_PATH"/>
<fileExists name="$$\cudart.lib"</span> /></span>
<span class="hljs-tag"><<span class="hljs-title">dirExists</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"$$" />
</and>
<and>
<envVarExists name="CUDA_PATH"/>
<fileExists name="$$\lib\x64\cudart.lib"</span> /></span>
<span class="hljs-tag"><<span class="hljs-title">dirExists</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"$$" />
</and>
</or>
</CUDA_LIB_PATH>
<CUDA_BIN_PATH>
<or>
<and>
<envVarExists name="CUDA_BIN_PATH"/>
<fileExists name="$$\nvcc.exe"</span> /></span>
<span class="hljs-tag"><<span class="hljs-title">dirExists</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"$$" />
</and>
<and>
<envVarExists name="CUDA_PATH"/>
<fileExists name="$$\bin\nvcc.exe"</span> /></span>
<span class="hljs-tag"><<span class="hljs-title">dirExists</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"$$" />
</and>
<and>
<envVarExists name="MW_NVCC_PATH"/>
<fileExists name="$$\nvcc.exe"</span> /></span>
<span class="hljs-tag"><<span class="hljs-title">dirExists</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"$$" />
</and>
<and>
<fileExists name="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\bin\nvcc.exe" />
<dirExists name="$$" />
</and>
</or>
</CUDA_BIN_PATH>
</locationFinder>
<env
PATH="$CUDA_BIN_PATH;$VSROOT\VC\Bin\amd64;$VSROOT\VC\Bin\VCPackages;$VSROOT\Common7\IDE;$VSROOT\Common7\Tools;$VSROOT\Common7\Tools\bin;$SDKROOT\Bin\x64;$SDKROOT\Bin\win64\x64;$SDKROOT\Bin;$PATH"
INCLUDE="$VSROOT\VC\ATLMFC\INCLUDE;$VSROOT\VC\INCLUDE;$SDKROOT\include;$MATLABROOT\extern\include;$MATLABROOT\toolbox\distcomp\gpu\extern\include"
LIB="$VSROOT\VC\ATLMFC\LIB\amd64;$VSROOT\VC\Lib\amd64;$SDKROOT\Lib\X64;$MATLABROOT\lib\$ARCH;$CUDA_LIB_PATH;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Lib\x64"
LIBPATH="$VSROOT\VC\Lib\amd64;"
/>
</config>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
-
具体修改方式:
- (1)VS环境变量: VS100COMNTOOLS=>VS120COMNTOOLS (141是VS2017,140是VS2015,120是VS2013,110是VS2012,100是VS2010)
- (2)两个注册表值: “SOFTWARE\Microsoft\Microsoft SDKs\Windows\v6.0A” => “…\Windows\v7.1A”;如果用与本文不同的VS版本,请用注册表编辑器展开相应的注册表路径查看正确的版本号。
-
(3)两个变量值:最后的LIB和LIBPATH直接更改为上面文件中的值。
(4)CUDA版本号:将所有8.0修改为你的CUDA版本号,如7.5,6.5,6.0。
(5)CUDA计算能力兼容性:CUDA 8.0以上的nvcc编译器需要删掉-gencode=arch=compute_20,code=sm_20
;另外,GTX 980Ti可以添加-gencode=arch=compute_52,code=sm_52
,GTX 1080Ti可以添加-gencode=arch=compute_61,code=sm_61
以获得更好的性能。具体需要自己查询你的显卡计算能力兼容性(CUDA Compute Compability)。
以上的第三点修改很重要,如果不修改,编译时会出现如下错误:
错误使用 mex
nvcc fatal : Could not set up the environment for Microsoft Visual Studio using 'D:/Program Files (x86)/Microsoft Visual Studio
12.0/VC/Bin/amd64/../../../VC/bin/amd64/vcvars64.bat'
- 1
- 2
- 3
如果你编译的时候还有错,注意具体问题具体分析了,一般是版本号的问题。
运行成功后的结果如下:
>> testMexCuda
>> y
y =
2 2 2 2
2 2 2 2
2 2 2 2
2 2 2 2
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
3.总结
- 用mex调用CUDA是Matlab利用CUDA最简单的方式。在探索过程中,本人也看到了网上所说的用VS生成lib或dll的方法,经试验没有一个是成功的。自己做lib依赖项很难控制,mex的时候还是会产生一大堆LNK2001错误。
- mex调用CUDA的关键在于配置文件mex_CUDA_win64.xml。每次用mex编译时将修改好的xml文件放在当前目录下,那么编译.cu文件与编译.cpp文件操作完全相同。还有一种方法,将修改好的mex_CUDA_win64.xml复制到D:\Program Files\MATLAB\R2014b\bin\win64\mexopts,这样一劳永逸,每次mex编译时不必再将xml文件带着了。
- 解决了编译问题,剩下的就是如何利用好CUDA加速你的程序了。