I have the following .m file (named testmemoryallocation.m
), targeted for code generation in Matlab Coder. This is just a test file demonstrating the concept, of course.
function output = testmemoryallocation(dim) %#codegen
%TESTMEMORYALLOCATION Tests allocation of large 3D arrays
output = coder.nullcopy(zeros([dim, dim, dim]));
output(:) = 5;
end
I build this using the following build script (default settings from the Coder app)
%% Create configuration object of class 'coder.CodeConfig'.
cfg = coder.config('lib','ecoder',false);
cfg.GenerateReport = true;
cfg.GenCodeOnly = true;
cfg.HardwareImplementation = coder.HardwareImplementation;
cfg.HardwareImplementation.ProdIntDivRoundTo = 'Undefined';
cfg.HardwareImplementation.TargetIntDivRoundTo = 'Undefined';
%% Define argument types for entry-point 'testmemoryallocation'.
ARGS = cell(1,1);
ARGS{1} = cell(1,1);
ARGS{1}{1} = coder.typeof(0);
%% Invoke MATLAB Coder.
codegen -config cfg testmemoryallocation -args ARGS{1}
The resulting generated C code from this build process looks like this:
/*
* testmemoryallocation.c
*
* Code generation for function 'testmemoryallocation'
*
*/
/* Include files */
#include "rt_nonfinite.h"
#include "testmemoryallocation.h"
#include "testmemoryallocation_emxutil.h"
/* Function Definitions */
void testmemoryallocation(double dim, emxArray_real_T *output)
{
int i0;
int loop_ub;
/* TESTMEMORYALLOCATION Tests allocation of large 3D arrays */
i0 = output->size[0] * output->size[1] * output->size[2];
output->size[0] = (int)dim;
emxEnsureCapacity((emxArray__common *)output, i0, (int)sizeof(double));
i0 = output->size[0] * output->size[1] * output->size[2];
output->size[1] = (int)dim;
emxEnsureCapacity((emxArray__common *)output, i0, (int)sizeof(double));
i0 = output->size[0] * output->size[1] * output->size[2];
output->size[2] = (int)dim;
emxEnsureCapacity((emxArray__common *)output, i0, (int)sizeof(double));
loop_ub = (int)dim * (int)dim * (int)dim;
for (i0 = 0; i0 < loop_ub; i0++) {
output->data[i0] = 5.0;
}
}
/* End of code generation (testmemoryallocation.c) */
The question is: is there a way in MATLAB Coder (in the testmemoryallocation.m
file) to verify that the memory was actually allocated? The memory allocation occurs in the emxEnsureCapacity function, which itself does not return information about a successful allocation (as far as I can tell.) I'd like to be able to gracefully exit from the calling function if there isn't enough system memory to complete the process. For instance, I'd like to add a result
output to testmemoryallocation that indicated if an error occurred allocating memory. Is there a way to do this?
Really, the question comes down to: is there a way to access emxArrays to test that the data
field of the struct is not null. Perhaps a .c file called with coder.ceval? Is there a way to instruct coder.ceval to pass an emxArray type instead of base types (double or int) so the underlying .c code can be written to interact with the structure?
EDIT:
The excellent answer accepted addresses both this question and an underlying bug in (2015a) Coder in the generated c code. In the _emxutil file, the emxEnsureCapacity function has a possible infinite loop if the requested number of elements is above intmax/2
.
It's good to see that you're making progress. Regarding the emxEnsureCapacity issue it is unfortunate and it is a bug. I'll take care of it to ensure we fix it in a forthcoming release. Meanwhile, there's a way of patching the generated source code. For config objects there's the 'PostCodeGenCommand' option which is executed/evaluated after the C code has been generated. This allows you to apply a patch before it gets compiled. For example,
and then 'mypatch.m' is:
Regarding passing 'emxArray' to an external C function (with coder.ref() in a coder.ceval() call) it is somewhat problematic. This is because the 'emxArray' representation may or may not exist depending on how big the matrix is. There's also a threshold (in the config object) that enables you to tell when to switch to "full" emxArrays or keep them as "upperbound allocated" variables (which on call boundaries are split into data and size as separate variables.) There are even more representations for variable size arrays (e.g. if you have upperbound variables in structures.) This is the main reason why we don't have a direct interface for emxArrays as type compatibility could change based on these parameters. Thus, always extracting the data will make it type compliant. If you need to access the size, assuming 'x' is a vector here, then you can just pass the size explicitly:
Unfortunately, this doesn't allow you to change the size of 'x' inside 'foo'.
There's another thing you can do, but please contact me directly (email) and I'll tell you some more.
Alexander Bottema
Software Engineer
MATLAB Coder Team
Mathworks