MATLAB: Editing elements of vector inside mex function slow

cmexmxarrayslow

Consider the following mex function written in C, which returns a column vector:
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
int x = *mxGetPr(prhs[0]);
int length = *mxGetPr(prhs[1]);
plhs[0] = mxCreateDoubleMatrix(x, 1, mxREAL);
double *output_vector = mxGetPr(plhs[0]);
int i;
for(i = 0; i < length; ++i) {
output_vector[i % x] += 1;

}
}
If I compile this code in Matlab and then run the function with inputs (5, 1000000000), it takes 3.228 s. Consider now the following altered code:
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
int x = *mxGetPr(prhs[0]);
int length = *mxGetPr(prhs[1]);
plhs[0] = mxCreateDoubleMatrix(x, 1, mxREAL);
//double *output_vector = mxGetPr(plhs[0]);
double *output_vector = malloc(x*sizeof(double));
int i;
for(i = 0; i < length; ++i) {
output_vector[i] = 0.0;
}
for(i = 0; i < length; ++i) {
output_vector[i % x] += 1;
}
free(output_vector);
}
If I compile and run the function with the same inputs as before, it takes only 0.627 s.
It seems like editing elements of an mxArray is much slower than editing elements of a double array. It seems like there should be no issues with MATLABs column-major order vs the row-major order in C since I am only using a vector here.
Any ideas why I am seeing this time difference?
Here is some further information:
  • OS: 64-bit Windows 10.
  • Compiler: MinGW64 Compiler (C), with the additional compile flags -std=c99 and -pedantic.
  • MATLAB version: R2016b
Update: For the simple example above, updating the mxArray takes about 5 times as long. In another code which I am using for an actual application, updating an mxArray instead of a double array takes 30 times as long.
Update 2: Please see my new timings in my comment below after incorporating the helpful suggestions by Walter and James. After fixing an error in the second code above, writing to an mxArray is now 10x slower than a double array for this simple example.

Best Answer

I can think of no reason why writing to memory from a mxArray (off of the heap) should take a significantly different amount of time than writing to memory from malloc or calloc (also off of the heap). I ran the following two sets of code on R2017a Win64 and see no significant differences:
/* double_write_test1.c */
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
int x = *mxGetPr(prhs[0]);
int length = *mxGetPr(prhs[1]);
double *output_vector;
int i;
plhs[0] = mxCreateDoubleMatrix(x, 1, mxREAL);
output_vector = mxGetPr(plhs[0]);
for(i = 0; i < length; ++i) {
output_vector[i % x] += 1;

}
}
and
/* double_write_test2.c */
#include <stdlib.h> /* malloc , free */
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
int x = *mxGetPr(prhs[0]);
int length = *mxGetPr(prhs[1]);
double *output_vector;
int i;
// plhs[0] = mxCreateDoubleMatrix(x, 1, mxREAL);
//double *output_vector = mxGetPr(plhs[0]);
output_vector = malloc(x*sizeof(double));
for(i = 0; i < length; ++i) {
output_vector[i % x] += 1;
}
free(output_vector);
}
The timing results:
>> tic;double_write_test1(5, 1000000000);toc
Elapsed time is 3.263384 seconds.
>> tic;double_write_test1(5, 1000000000);toc
Elapsed time is 3.004800 seconds.
>> tic;double_write_test1(5, 1000000000);toc
Elapsed time is 3.098912 seconds.
>>
>>
>> tic;double_write_test2(5, 1000000000);toc
Elapsed time is 3.071897 seconds.
>> tic;double_write_test2(5, 1000000000);toc
Elapsed time is 3.091942 seconds.
>> tic;double_write_test2(5, 1000000000);toc
Elapsed time is 3.056829 seconds.
So, timing is pretty much the same. This is all as expected on my machine. I don't know what might be happening on your machine.
I would point out that MATLAB seems to keep a store of 0'ed memory to the side for use in some circumstances. E.g., if you call mxCalloc the pointer returned may be to a memory block that has already been previously set to all 0's prior to your mxCalloc call. So you can't necessarily conclude that any timings associated with the call also included the time it took to set all of the memory to 0's since that might have been done prior to the call.
Side Note: I don't know what all "mex.h" includes, but I wouldn't necessarily trust it to include the files that have the native C function prototypes. In particular, since you are using malloc etc you should probably explicitly include a header file like stdlib.h to get the proper prototypes for the functions you are using.