繁体   English   中英

使用mexCallMATLAB的matlab mex文件比相应的m文件慢近300倍

[英]Matlab mex-file with mexCallMATLAB is almost 300 times slower than the corresponding m-file

我开始用C ++实现一些m文件,以减少运行时间。 m文件产生n维点并在这些点评估函数值。 这些函数是用户定义的,它们作为函数句柄传递给m文件和mex文件。 mex文件使用mexCallMATLAB和feval来查找函数值。

我构造了下面的例子,其中在Matlab命令行中构造的函数句柄fn被传递给matlabcallingmatlab.m和mexcallingmatlab.cpp例程。 使用新开放的Matlab,mexcallingmatlab在241.5秒内评估此功能200000,而matlabcallingmatlab在0.81522秒内评估它,因此使用mex实现减慢296倍。 这些时间是第二次运行的结果,因为第一次运行似乎更大可能是由于第一次加载程序等相关的一些开销。

我花了很多天在网上搜索这个问题并尝试了一些建议。 我尝试了不同的mex编译标志来优化mex,但性能几乎没有差异。 Stackoverflow上的一篇文章指出,升级Matlab是解决方案,但我在Mac OS X版本:10.8.4上使用的最新版本MATLAB版本:8.1.0.604(R2013a)。 我使用和不使用-largeArrayDims标志编译了mex文件,但这也没有任何区别。 有人建议函数句柄的内容可以直接在cpp文件中编码,但这是不可能的,因为我想将此代码提供给具有矢量输入和实数输出的任何类型函数的任何用户。

据我所知,mex文件需要通过feval函数来使用函数句柄,而m文件可以直接调用函数句柄,前提是Matlab版本比某些版本更新。

任何帮助将不胜感激。

在Matlab命令行中创建的简单函数句柄

fn = @(x) x'*x 

matlabcallingmatlab.m

function matlabcallingmatlab( fn )
x = zeros(2,1); 
for i = 0 : 199999
    x(2) = i; 
    f = fn( x ); 
end

mexcallingmatlab.cpp

#include "mex.h"
#include <cstring>

void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[] )
{
    mxArray *lhs[1], *rhs[2]; //parameters to be passed to feval
    double f, *xptr, x[] = {0.0, 0.0}; // x: input to f and f=f(x)
    int n = 2, nbytes = n * sizeof(double);  // n: dimension of input x to f

    // prhs[0] is the function handle as first argument to feval
    rhs[0] = const_cast<mxArray *>( prhs[0] );

    // rhs[1] contains input x to the function
    rhs[1] = mxCreateDoubleMatrix( n, 1, mxREAL);
    xptr = mxGetPr( rhs[1] );

    for (int i = 0; i < 200000; ++i)
    {
        x[1] = double(i);   // change input 
        memcpy( xptr, x, nbytes );  // now rhs[1] has new x
        mexCallMATLAB(1, lhs, 2, rhs, "feval");
        f = *mxGetPr( lhs[0] );
    }
}

编译mex文件

>> mex -v -largeArrayDims mexcallingmatlab.cpp

所以我试着自己实现这个,我想我找到了缓慢的原因。

基本上,你的代码有,你没有释放的一个小的内存泄漏lhs mxArray从调用返回mexCallMATLAB 它不完全是内存泄漏,看到MATLAB内存管理器在MEX文件退出时负责释放内存:

MATLAB分配动态内存以在mxArrays中存储plhs 清除MEX文件时,MATLAB会自动释放动态内存。 但是,如果堆空间非常mxDestroyArray ,请在完成mxArrays plhs指向后调用mxDestroyArray

仍然显式优于隐式...所以你的代码真的强调MATLAB内存管理器的解除分配器:)

mexcallingmatlab.cpp

#include "mex.h"

#ifndef N
#define N 100
#endif

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // validate input/output arguments
    if (nrhs != 1) {
        mexErrMsgTxt("One input argument required.");
    }
    if (mxGetClassID(prhs[0]) != mxFUNCTION_CLASS) {
        mexErrMsgTxt("Input must be a function handle.");
    }
    if (nlhs > 1) {
        mexErrMsgTxt("Too many output arguments.");
    }

    // allocate output
    plhs[0] = mxCreateDoubleMatrix(N, 1, mxREAL);
    double *out = mxGetPr(plhs[0]);

    // prepare for mexCallMATLAB: val = feval(@fh, zeros(2,1))
    mxArray *lhs, *rhs[2];
    rhs[0] = mxDuplicateArray(prhs[0]);
    rhs[1] = mxCreateDoubleMatrix(2, 1, mxREAL);
    double *xptr = mxGetPr(rhs[1]) + 1;

    for (int i=0; i<N; ++i) {
        *xptr = i;
        mexCallMATLAB(1, &lhs, 2, rhs, "feval");
        out[i] = *mxGetPr(lhs);
        mxDestroyArray(lhs);
    }

    // cleanup
    mxDestroyArray(rhs[0]);
    mxDestroyArray(rhs[1]);
}

MATLAB

fh = @(x) x'*x;
N = 2e5;

% MATLAB
tic
out = zeros(N,1);
for i=0:N-1
    out(i+1) = feval(fh, [0;i]);
end
toc

% MEX
mex('-largeArrayDims', sprintf('-DN=%d',N), 'mexcallingmatlab.cpp')
tic
out2 = mexcallingmatlab(fh);
toc

% check results
assert(isequal(out,out2))

运行上述基准测试几次(为了加热),我得到以下一致的结果:

Elapsed time is 0.732890 seconds.    % pure MATLAB
Elapsed time is 1.621439 seconds.    % MEX-file

没有你最初的慢速时间附近! 纯MATLAB部分仍然快两倍,可能是因为调用外部MEX函数的开销。

(我的系统:Win8运行64位R2013a)

通常,没有理由期望MEX文件比M文件更快。 这通常是正确的唯一原因是MATLAB中的许多循环会产生大量的函数调用开销,以及参数检查等。 在C中重写可以消除开销,并为您的C编译器提供优化代码的机会。

在这种情况下,C编译器没有任何优化...它必须为每次迭代调用MATLAB接口。 实际上,MATLAB优化器会做得更好,因为在某些情况下它可以“​​看到”函数。

换句话说,忘记使用MEX来加速这个程序。

从mex到Matlab的调用有一些开销成本,反之亦然。 每次调用的开销很小,但它确实在这样的紧密循环中加起来。 正如您的测试所示,在这种情况下,纯Matlab可以更快! 您的另一个选择是消除mexCallMATLAB调用并在纯C ++中执行所有操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM