R2018a complex interleaved data is the new memory model
Show older comments
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
Walter Roberson
on 22 Mar 2018
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.
James Tursa
on 22 Mar 2018
Edited: James Tursa
on 23 Mar 2018
James Tursa
on 23 Mar 2018
Edited: James Tursa
on 23 Mar 2018
Answers (2)
John Aspinall
on 26 Mar 2018
Edited: Steven Lord
on 27 Mar 2018
3 votes
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
Walter Roberson
on 26 Mar 2018
"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.
James Tursa
on 27 Mar 2018
Edited: James Tursa
on 27 Mar 2018
John Aspinall
on 27 Mar 2018
@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.
John Aspinall
on 27 Mar 2018
@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.
Walter Roberson
on 27 Mar 2018
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.
James Tursa
on 19 Apr 2018
Cris Luengo
on 2 May 2018
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.
James Tursa
on 8 Jul 2020
Bruno Luong
on 27 Mar 2018
Edited: Bruno Luong
on 27 Mar 2018
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
Find more on Write C Functions Callable from MATLAB (MEX Files) in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!