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

I started embedding a few m files in C ++ to shorten the execution time. M files produce n-dimensional points and evaluate the values โ€‹โ€‹of the functions at these points. Functions are user-defined, and they are transferred to m files and mex files as functions. Mex files use mexCallMATLAB with feval to search for function values.

I built the example below, where the fn function descriptor built on the Matlab command line is passed to matlabcallingmatlab.m and mexcallingmatlab.cpp procedures. Thanks to the recently opened Matlab, mexcallingmatlab evaluates this feature to 200,000 in 241.5 seconds, while matlabcallingmatlab evaluates it at 0.81522 seconds, so it slows down 296 times using mex. These times are the result of the second runs, as the first runs are apparently longer, probably due to some associated with the service data of the first program load, etc.

For many days I searched the Internet for this problem and tried some suggestions on it. I tried various mex compiling flags to optimize mex, but there was practically no difference in performance. A previous post on Stackoverflow stated that updating Matlab was a solution, but I'm probably using the latest version of MATLAB Version: 8.1.0.604 (R2013a) on Mac OS X Version: 10.8.4. I compiled the mex file with and without flag -largeArrayDims, but that didn't matter either. Some have suggested that the contents of a function descriptor can be directly encoded in a cpp file, but this is not possible because I would like to provide this code to any user with any type of function with vector input and a valid number.

As far as I know, mex files must go through the feval function to use the function descriptor, while m files can directly call function descriptors, provided that the version of Matlab is newer than any version.

Any help would be greatly appreciated.

simple function descriptor created on the matlab command line :

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] ); } } 

Compiling the mex file :

 >> mex -v -largeArrayDims mexcallingmatlab.cpp 
+7
c ++ performance matlab mex function-handle
source share
3 answers

So, I tried to implement this myself, and I think I found the reason for the slowness.

Basically your code has a small memory leak when you do not release the lhs mxArray returned from the mexCallMATLAB call. This is not quite a memory leak, since MATLAB's memory manager takes care of freeing memory when exiting a MEX file:

MATLAB allocates dynamic memory for storing mxArrays in plhs . MATLAB automatically frees dynamic memory when clearing a MEX file. However, if the heap space is ok, call mxDestroyArray when you are mxArrays with the items mxArrays plhs .

Still explicit is better than implicit ... So your code really emphasizes the release of the MATLAB memory manager :)

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)) 

By doing the above test a couple of times (to warm it up), I get the following consistent results:

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

No where near the slow times you originally had! However, the clean part of MATLAB is about two times faster, probably due to the overhead of calling an external MEX function.

(My system: Win8 works with 64-bit R2013a)

+17
source share

There is absolutely no reason to expect that the MEX file is, in general, faster than the M. .d. Rewriting that in C eliminates overhead and gives your C compiler the ability to optimize code.

In this case, nothing needs to be optimized for the C compiler ... it MUST make a MATLAB interface call for each iteration. In fact, the MATLAB optimizer will work better because it can in some cases โ€œseeโ€ in a function.

In other words, forget to use MEX to speed up this program.

+4
source share

There are several overheads for calls from mex to Matlab and vice versa. The overhead per call is small, but it does add up in such a closed loop. As your testing shows, pure Matlab can be much faster in this case! Another option is to exclude the mexCallMATLAB call and do everything in pure C ++.

+1
source share

All Articles