MEX - accessing structure of arrays
4 views (last 30 days)
Show older comments
Hi all,
I’m looking for some advice in a project in which speed and performance is of great importance.
I created a model which consists of an outer function with 1 for-loop (10 000 iterations) which invokes several custom-made functions. To increase model’s performance, I rewrote the custom-made functions into MEX-functions. This already gave a good speed-up. However, I would also like to place the outer for-loop in a MEX-function. But I have a problem passing data from MATLAB to the MEX-functions. (Note that it’s not possible to vectorize the for-loop).
The data which is known prior to the model’s simulation is saved to a large nested structure of arrays (built in the form of “data.Q.position1” with “position1” an array of 10000 doubles). All arrays containing doubles have the same length. The results of the model will also be written to this structure of arrays (different fieldnames of course, and pre-allocation is done before the for-loop)
So currently, the model is looking like this:
[data] = function model(data)
for i=1:10000
data.Q.position1(i) = MEX-function1(data.WL.position4(i), data.WL.position3(i), …);
data.Q.position2(i) = MEX-function1(data.WL.position6(i), data.WL.position12(i), …);
…
data.WL.position7(i) = MEX-function2(data.Q.position1(i), …);
…
end
I chose for the structure of arrays so I can point easily at the required variables for the function inputs.
So my question is, how can I place the for-loop in a MEX function and what do I have to do with the structure? Will I still by able to refer to the variables like data.WL.position1 etc? I’m really new to MEX and C-language as you will probably notice...
Secondly, and at least equally important, does this whole concept looks good with regard to performance, or are better solutions available?
Thanks in advance!
0 Comments
Accepted Answer
James Tursa
on 12 Feb 2013
Edited: James Tursa
on 12 Feb 2013
There will likely be some speed improvement if you put the loop inside a mex functions. At the m-file level, each time you pass data.WL.position4(i) etc as an argument MATLAB creates a temporary shared data copy of the actual variable and passes that. So there is overhead associated with calling the function in this manner. Inside a mex routine, however, these temporary shared data copies can be avoided by using mxGetField on the data variable directly (returns the actual variable pointer instead of creating a temporary shared data copy). So that part is fairly straightforward. The problem is going to be putting the results back into the data.Q.position1(i) etc positions. In order to do that inside the mex routine and have the for-loop inside the mex routine you will need to modify the data variable "in-place", which is (strictly speaking) against the official rules but can be done. The downside is that you risk unintended side effects if there is any variable sharing going on. Are all of the left-hand-side variables (e.g., data.Q.position1(i)) pristine and not shared with anything? If so, then you can safely modify them in place. An outline is below:
Calling syntax at m-file level:
mymodel(data); % Note: no left-hand-side
Mex function code snippet outline:
mxArray *Q, *WL, *position1, *position2, etc;
mwSize i;
double *pr1, *pr2, *pr3, *pr4, *pr5, *pr6, *pr7, etc;
:
Q = mxGetField(prhs[0],0,"Q");
WL = mxGetField(prhs[0],0,"WL");
position1 = mxGetField(Q,0,"position1");
position2 = mxGetField(Q,0,"position2");
position4 = mxGetField(Q,0,"position4");
position3 = mxGetField(WL,0,"position3");
position6 = mxGetField(WL,0,"position6");
position7 = mxGetField(WL,0,"position7");
etc
pr1 = mxGetPr(position1);
pr2 = mxGetPr(position2);
pr3 = mxGetPr(position3);
pr4 = mxGetPr(position4);
pr6 = mxGetPr(position6);
pr7 = mxGetPr(position7);
etc
for( i=0; i<10000; i++ ) {
pr1[i] = MEX_function1(pr4[i],pr3[i],etc);
pr2[i] = MEX_function1(pr6[i],pr12[i],etc);
etc
}
For a robust mex routine, you would need to check variable types and sizes etc before dereferencing any of the pointers (which I did not do above). I will again caution you that this will only work if the left-hand-side stuff has been pre-allocated properly so as not to be shared. Can you post how you are doing this pre-allocation?
2 Comments
James Tursa
on 12 Feb 2013
Edited: James Tursa
on 12 Feb 2013
The "sharing left-hand-side" caution is illustrated with this simple example:
C = cell(2,1);
C(1:2) = {zeros(10,1)};
In the above case, the cell array C has two elements, each of them a 10x1 double matrix of 0's. However, because of the way the initialization was done, C{1} and C{2} are physically the exact same variable (sharing the same memory). But MATLAB knows about this sharing and keeps track of it. When you alter either C{1} or C{2} at the m-file level, MATLAB will first make a deep copy of the variable and then alter that copy. So everything works. But if you were to pass C into a mex routine and alter C{1} it would also alter C{2} (the "side effect") since it is sharing the same memory as C{1}. To avoid that one would have to either (1) detect the sharing and manually create a deep copy to alter (like MATLAB does), or (2) pre-allocate C differently to ensure that each element had its own unshared variable. E.g.,
C = cell(2,1);
C(1) = {zeros(10,1)};
C(2) = {zeros(10,1)};
In the above code snippet, each C element ends up with a fresh unshared matrix of 0's. Detecting sharing can be difficult in a mex routine (in fact, there are no official API functions to do it ... you have to use undocumented functions and hack into the mxArray), so it is best to avoid sharing from the outset whenever possible.
For your particular case you are working with a struct array instead of a cell array, but behind the scenes they are stored almost exactly the same as cell arrays so the above caution applies. That being said, it looks like you will be OK with how you are doing the pre-allocation.
There is no issue with re-using a MEX_function1 output downstream in another calculation, as you surmise.
More Answers (0)
See Also
Categories
Find more on Multidimensional Arrays in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!