MATLAB下使用CUDA。
#@author: gr
#@date: 2014-04-08
#@email: forgerui@gmail.com
一、 Matlab & C
1. 概念
Matlab
与 C
混编可以提高程序运行效率。
2. C文件
C文件需要在引入头文件mex.h
,我的mex.h
位置在/opt/MATLAB/R2013a/extern/include/mex.h
。
#include <mex.h>
Matlab与C文件的接口函数是mexFunction
。
mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]){
// entry
}
mexFunciton
就像main
函数一样,是Matlab
调用的入口。其中,nlhs
是输出参数个数,plhs
是输出参数;nrhs
是输入参数个数,prhs
是输入参数,它是一个只读的变量。
3. 常用函数
4. 编译
需要将C
语言源文件编译成可执行文件才能被Matlab
调用,并且编译出来的文件比同名的.m
文件执行优先级更高,即如果两个同名先执行编译出来的文件。
编译分两个步骤,先编译生成.o
中间文件(windows下是.obj
),再链接生成.mexa64
文件(linux32位是.mexglx
,windows是.mexw64
),这个.mexa64
文件可以直接被Matlab
使用。
具体操作是打开Matlab
,进入要编译文件的文件夹,要先配置一下编译器。
# configure the compiler
mex -setup
# compile
mex -c hello.c -o hello.o
# link
mex -O hello.o
之后在Matlab
中直接敲hello
便可以调用hello
程序。
二、Matlab & CUDA
1. Cuda的kernel函数
代码分为两部分,一部分代码在主机(host)上执行,另一部分则在设备(device)上执行,kernel
函数是在GPU上执行的函数。
进行Cuda
编译的一般步骤:
- 在主机上申请device内存
- 将主机数据拷贝到设备上
- 在设备上进行运算
- 主机将设备上的运算结果拷贝回主机内存
- 释放设备内存
如下定义kernel
函数:
__global__ static void kernel_function(int* a, int* b, int* c){
// realted code
}
2. Cuda的启动
在主机上通过调用kernel
函数名进行启动。
# 启动
kernel_function<<<block, thread>>>(a, b, c);
其中thread是一个block
中启动的线程数,而block
是需要划分为多少个block
.块内的thread
可以时行数据同步和共享内存,不同的block
之间无法进行同步。a, b, c是相关的参数。
具体CUDA相关知识请看博客。
3. 编译
因为Cuda
有自己的编译器nvcc
,所以需要调用这个编译器去编译C文件。我们可以在Matlab
中利用一个脚本进行编译。
nvmex('hello.c');
function [ path, filename, zaet, fd ] = nvmex( cuFileName )
%NVMEX Summary of this function goes here
% Detailed explanation goes here
file_split = regexp(cuFileName, '.', 'split');
filename = file_split{1};
if ispc % Windows
CUDA_LIB_LOCATION = 'C:CUDAlib';
Host_Compiler_Location = '-ccbin "D:Program FilesMicrosoft Visual Studio 9.0VCin"';
PIC_Option = '';
else % Mac and Linux
CUDA_LIB_Location = '/usr/local/cuda/lib64';
Host_Compiler_Location = '';
PIC_Option = '--compiler-options -fPIC';
end
% compile .o file
nvccCommandLine = [ ...
'nvcc --compile ' cuFileName ' ' Host_Compiler_Location ' ' ...
' -o ' filename '.o ' ...
PIC_Option ...
' -I' matlabroot '/extern/include ' ...
];
disp(nvccCommandLine);
status = system(nvccCommandLine);
if status < 0
error 'Error invoking nvcc';
end
% link .mexa64 file
mexCommandLine = ['mex (''' filename '.o'', ''-L' CUDA_LIB_Location ''', ''-lcudart'')'];
disp(mexCommandLine);
eval(mexCommandLine);
end