R2018a complex interleaved data is the new memory model

This is a heads up for mex programmers that work with complex data. According to the Release Notes, it appears that MATLAB R2018a has undergone a major change in the way it stores complex data. It used to be separate memory blocks for the real and imag data. Now it is interleaved real & imag data elements. This brings the MATLAB complex data memory model in line with other languages and libraries built around the Fortran/C/C++ etc standards.
But it also means that all of your current mex code that works with complex data may be broken in R2018a. E.g., mxGetPr will now generate an error if the mxArray is complex and you compile with the -R2018a flag. Similar comments for the other related functions such as mxGetPi, mxGetData, mxGetImagData. If you currently use these data pointers to access complex variables inplace ... that just went out the window.
I will know more once I get R2018a, but for now I will just caution you that you may have to redo all of your mex source code to work with the new internal complex memory model. Your current code may not work at all. And the internal mxArray hacks that you have been using may not work either.
I've got a lot of FEX code that is suddenly broken in R2018a and will have to be rewritten ...

3 Comments

If I recall from the release notes, there is a compile flag you can set to use the old memory model. In pre-release I griped to them that the name of the flag was not well chosen, since it was named by year rather than by functionality affected.
To my reading of the Release Notes, the memory model of the underlying mxArray in R2018a is fixed ... it is the interleaved complex data model. That cannot be changed and there is no other memory model available. That being said, it is unclear if the old separate complex memory model is actually supported within MATLAB, or if such variables used in mex routines are simply converted to/from the interleaved model on entry/exit from the mex routine (i.e. copy-in/copy-out), or maybe something else.
The -R2017b compile flag you are referring to appears to me to simply cause linking to a library that provides an interface for the old function signatures (mxGetPr etc) into the new memory model. But the functionality of these functions has changed as noted above and more detailed in the Release Notes. The only way mxGetPr could work with a complex variable in R2018a is if a copy of the real data were made and a pointer to that copy were returned by mxGetPr. I don't see any other way it could work. If the -R2018a compile flag were used, using mxGetPr on a complex variable generates an error.
The Release Notes don't have a lot of information on this, and in some cases are contradictory, so I am guessing a bit on this. E.g., when I see the phrase "... you might notice a performance impact as MATLAB accesses the compatibility interface ..." I jump to the conclusion that there is data copying going on in the background when using the old mxGetPr and friends with complex variables.
I'll update my findings once I get a copy of R2018a to test with ...
It is also unclear what this Release Note means:
"... MATLAB does not support the interleaved complex API for Fortran functions ..."
Will all future Fortran complex mxArray data access be forced to be data copies unless a hack is used?

Sign in to comment.

Answers (2)

John Aspinall
John Aspinall on 26 Mar 2018
Edited: Steven Lord on 27 Mar 2018
1. Primary memory model.
James is correct that the primary memory model for complex data is interleaved in 18a. What "primary model" means is that anywhere where arrays are running around in core MATLAB code, the core code has been built with the assumption of this memory model.
2. Compatibility of older mex files, both binary and source.
We support the compatibility of old MEX files, both old binaries, and old source rebuilt by an 18a MATLAB. But switching representations of complex data is not free. That's the "performance impact" that we're talking about here.
For a user who is passing large complex arrays across the MEX interface, they probably want to move to using the interleaved complex APIs as soon as they can. But there are many other use cases where computing on a small piece of complex data is a tiny part of the larger computation in the MEX file. In these cases, the overhead may be negligible, and those users can postpone conversion until convenient.
It's hard to talk about converting to interleaved complex without a specific use case, but we've tried to capture some common idioms here.
Bottom line is that you shouldn't have broken mex files, unless you're stepping outside the published APIs. Also, as James notes, choosing the 18a interface at the command line is an "opt-in" operation; with no choice of API specified on the command line it will default to 17b, which means you're getting the compatible option so that even if you've got your mex command stored in a makefile, it should continue to work.
3. Fortran.
We can't promise anything about future development, but let me reassure you that we hear you, and we are not abandoning Fortran.
4. MEX command line.
Finally, a word about the change in the MEX command line flags for choosing compatibility options. Walter is quite correct that we have changed from flagging by functionality affected, to flagging by release number.
We did deliberately choose control by release. We chose release numbers because of the importance of being able to build a MEX file that works in a particular MATLAB release and because the combinations of functionality were growing too large.
5. For more information.
We're planning a guest post in Steve's or Loren's blog, covering more detail about move to interleaved complex.
[SL: edited to correct one of the URLs, to hyperlink the URLs, and to fix one typo.]

8 Comments

"We chose release numbers because of the importance of being able to build a MEX file that works in a particular MATLAB release and because the combinations of functionality were growing too large."
#ifdef _MW_R2018a
#ifdef _MW_compatibleArrayDims
#error R2018a incompatible with compatibleArrayDims
#end
#ifndef _MW_largeArrayDims
#define _MW_largeArrayDims 1
end
#ifndef MX_HAS_INTERLEAVED_COMPLEX
#define MX_HAS_INTERLEAVED_COMPLEX 1
#end
#end
Switching from functionality to release number makes it impossible for something to incrementally upgrade their code to match sets of changes. It becomes an all or nothing upgrade: you have to bring everything up to current Best Practices at the same time, or else you cannot use any new functionality at all.
@John: Thanks for the response. Some info I will hope to be getting out of Steve's or Lauren's blog with regards to the complex interleaved memory model:
- Does the -R2017b with complex variables do a deep copy-in/copy-out for the mex routines? E.g., that would explain the "performance hit" comment in the Release Notes. And is it only the complex variables that this affects, or would real variables (or char or logical) also be copy-in/copy-out?
- I don't see mexGetVariable or mexGetVariablePtr or MexCallMATLAB mentioned in the Release Notes. It seems that these might be affected as well by the new memory model under the -R2017b flag. E.g., how could you get a pointer to a caller workspace complex variable and work with it directly using the old routines? It doesn't seem like this could possibly work.
"Broken" may have been too strong a word for me to use above. However, if the -R2017b style mex routines use a copy-in/copy-out for complex variables, as I suspect, then all memory and speed gains from the mex routine (which may have been the sole reason the mex routine was written in the first place) may be gone for all practical purposes, and a low level rewrite for -R2018a would be necessary to regain the memory and speed advantages. So, maybe not functionally broken but useless for the purpose they were written. Also, any inplace operations in -R2017b mex routines (which I know are not officially sanctioned) would simply not work at all in R2018a if copy-in/copy-out were the case because one would not expect MATLAB to copy-out the prhs[] variables.
@Walter: Let's suppose a user has a really old MEX file, with 32-bit indexing. Nothing prevents this user from upgrading 32-bit to 64-bit indexing first, and then upgrading separate to interleaved complex later.
What this user cannot do, however, is mix interleaved complex with 32-bit indexing. This combination was never supported in a released MATLAB. The goal of specifying by version is to make these unsupported combinations obviously "un-selectable", rather than having to issue potentially confusing error messages.
@James: Briefly...
- Yes, there's a copy of the data. It only happens for complex numerics, although we do need to cope with the possibility that a user creates a real matrix and later modifies it to be complex.
- While mexGetVariable (and ...Ptr) aren't mentioned specifically in the Release Notes, they're handled too.
- With regards to the "not officially sanctioned" operations: I will warn you that the consequences of stepping outside the published API can be greater when you're using this compatibility layer. Translated into implementation language: there's a reason why we're warning you against modifying RHS args.
John: see my #ifdef that #error's the combination. You do not need to restrict flexibility unduly. You do not need to push all of the functionality selection into one switch: you can, as I illustrate, provide a switch that acts as an abbreviation for setting a series of settings.

Just found out that the R2018a mex situation is much worse that I thought ...

https://www.mathworks.com/matlabcentral/answers/396103-mxcreateshareddatacopy-no-longer-supported-in-r2018a

Basically, not being able to create a shared data copy in a mex routine torpedoes most of my important mex code (as well as the mex code of many other FEX posters).

I have been waiting for this particular change for 20 years. Separate real and imaginary planes was a ridiculous idea to start with. But somehow this change is painful, needing to do major rewrites now.
FYI,
See this FEX submission for reading and writing interleaved complex data in R2018a or later without extra data copies:
See this FEX submission for reinterpreting an existing real variable as interleaved complex or vice-versa in R2018a or later:

Sign in to comment.

I have not noticed the change before reading this post, since all my MEX are still working in 2018a.
I guess there is a conversion back/and forth between interleaved (internal storage) and separate Pr/Pi pointers in compatibility mode (-R2017b). In my benchmark test of this simple MEX file, the speed is decrease by half in compatibility mode, so IMO in worth to do the conversion.
/*************************************************************************
* MATLAB MEX ROUTINE zeropad_mex.c
*
* function B = zeropad_mex(A, nhead, ntail)
* perform
* >> B = cat(1, zeros(nhead,1), A(:), zeros(ntail,1));
*
* A must be array double, real or complex
*
* >> mex -O -R2018a zeropad_mex.c
* For compatibility:
* >> mex -O -R2017b zeropad_mex.c
*
* Author: Bruno Luong <b.luong@fogale.com>
* History
* Original: 16/Mars/2018
************************************************************************/
#include "mex.h"
#include "matrix.h"
#include "math.h"
#include <string.h>
#define A_IN prhs[0]
#define NHEAD_IN prhs[1]
#define NTAIL_IN prhs[2]
#define B_OUT plhs[0]
#define CHECK_ARG 0
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[]) {
size_t m, nhead, ntail;
#if MX_HAS_INTERLEAVED_COMPLEX
mxComplexDouble *Ac, *Bc;
#endif
double *Ar, *Ai, *Br, *Bi;
mxComplexity mC;
#if (CHECK_ARG == 1)
if (nrhs != 3)
mexErrMsgTxt("zeropad_mex requires 2 inputs");
if (mxGetClassID(A_IN) != mxDOUBLE_CLASS)
mexErrMsgTxt("zeropad_mex A must be double");
#endif
nhead = (size_t)mxGetScalar(NHEAD_IN);
ntail = (size_t)mxGetScalar(NTAIL_IN);
#if MX_HAS_INTERLEAVED_COMPLEX
if (mxIsComplex(A_IN))
{
Ac = mxGetComplexDoubles(A_IN);
mC = mxCOMPLEX;
}
else
{
Ar = mxGetDoubles(A_IN);
mC = mxREAL;
}
Ai = NULL;
#else
Ar = mxGetPr(A_IN);
Ai = mxGetPi(A_IN);
if (Ai == NULL)
mC = mxREAL;
else
mC = mxCOMPLEX;
#endif
m = mxGetNumberOfElements(A_IN);
B_OUT = mxCreateNumericMatrix(m+nhead+ntail, 1, mxDOUBLE_CLASS, mC);
#if MX_HAS_INTERLEAVED_COMPLEX
if (mxIsComplex(B_OUT))
{
Bc = mxGetComplexDoubles(B_OUT);
memcpy(Bc+nhead,Ac,sizeof(mxComplexDouble)*m);
}
else
{
Br = mxGetDoubles(B_OUT);
memcpy(Br+nhead,Ar,sizeof(double)*m);
}
#else
Br = mxGetPr(B_OUT);
Bi = mxGetPi(B_OUT);
memcpy(Br+nhead,Ar,sizeof(double)*m);
if (Ai != NULL) memcpy(Bi+nhead,Ai,sizeof(double)*m);
#endif
} /* mexFunction */

Categories

Tags

Asked:

on 22 Mar 2018

Commented:

on 8 Jul 2020

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!