gpt4 book ai didi

c++ - 带有 mexCallMATLAB 的 Matlab mex 文件比相应的 m 文件慢近 300 倍

转载 作者:可可西里 更新时间:2023-11-01 18:06:02 35 4
gpt4 key购买 nike

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

我构建了以下示例,其中将在 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 文件中,但这是不可能的,因为我想将此代码提供给任何具有 vector 输入和实数输出的任何类型函数的用户。

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

如有任何帮助,我们将不胜感激。

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

fn = @(x) x'*x 

ma​​tlab调用matlab.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

最佳答案

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

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

MATLAB allocates dynamic memory to store the mxArrays in plhs. MATLAB automatically deallocates the dynamic memory when you clear the MEX-file. However, if heap space is at a premium, call mxDestroyArray when you are finished with the mxArrays plhs points to.

还是显式好于隐式...所以你的代码确实强调了 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 函数的开销。

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

关于c++ - 带有 mexCallMATLAB 的 Matlab mex 文件比相应的 m 文件慢近 300 倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18660433/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com