我有以下.m文件(名为testmemoryallocation.m
),目标是在Matlab Coder中生成代码。当然,这只是一个展示概念的测试文件。
function output = testmemoryallocation(dim) %#codegen
%TESTMEMORYALLOCATION Tests allocation of large 3D arrays
output = coder.nullcopy(zeros([dim, dim, dim]));
output(:) = 5;
end
我使用以下构建脚本(Coder应用程序的默认设置)构建它
%% 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}
此构建过程生成的C代码如下所示:
/*
* 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) */
问题是:MATLAB Coder(在testmemoryallocation.m
文件中)是否有办法验证内存是否实际分配?内存分配发生在emxEnsureCapacity函数中,该函数本身不返回有关成功分配的信息(据我所知)。如果没有&#39;,我希望能够优雅地退出调用函数。足够的系统内存来完成这个过程。例如,我想在testmemoryallocation中添加一个result
输出,指示是否发生了分配内存的错误。有没有办法做到这一点?
真的,问题归结为:有没有办法访问emxArrays来测试结构的data
字段不为空。也许用coder.ceval调用的.c文件?有没有办法指示coder.ceval传递emxArray类型而不是基类型(double或int),以便可以编写底层.c代码以与结构交互?
编辑:
接受的优秀答案解决了这个问题以及生成的c代码中(2015a)Coder中的底层错误。在_emxutil文件中,如果请求的元素数高于intmax/2
,则emxEnsureCapacity函数可能存在无限循环。
答案 0 :(得分:4)
很高兴看到你正在取得进步。关于emxEnsureCapacity问题,这是不幸的,这是一个错误。我会照顾它,以确保我们在即将发布的版本中修复它。同时,还有一种修补生成的源代码的方法。对于配置对象,存在'PostCodeGenCommand'选项,该选项在生成C代码后执行/评估。这允许您在编译之前应用补丁。例如,
cfg.PostCodeGenCommand = 'mypatch';
然后'mypatch.m'是:
function mypatch
cfiles = all_cfiles([pwd filesep 'codegen']);
for i = 1:numel(cfiles)
cfile = cfiles{i};
if strcmp(cfile(end-9:end), '_emxutil.c')
text = fileread(cfile);
text = regexprep(text, '(while \(i < newNumel\) \{\s+i <<= 1; (\s+\})', '$1 if (i < 0) i = 0x7fffffff; $2');
filewrite(cfile, text);
disp(cfiles{i});
end
end
function filewrite(filename, text)
f = fopen(filename, 'w');
fprintf(f, '%s', text);
fclose(f);
function files = all_cfiles(d)
files = {};
fs = dir(d);
for i = 1:numel(fs)
if (fs(i).name(1) == '.')
continue
end
if fs(i).isdir
files = [files all_cfiles([d filesep fs(i).name])];
else
if strcmp(fs(i).name(end-1:end), '.c')
files{end+1} = [d filesep fs(i).name];
end
end
end
关于将'emxArray'传递给外部C函数(在coder.ceval()调用中使用coder.ref()),这有点问题。这是因为'emxArray'表示可能存在也可能不存在,具体取决于矩阵的大小。还有一个阈值(在配置对象中),使您能够告诉何时切换到“完整”emxArrays或将它们保留为“上限分配”变量(在调用边界上将其拆分为数据和大小作为单独的变量。)更多可变大小数组的表示(例如,如果结构中有上限变量。)这是我们没有emxArrays直接接口的主要原因,因为类型兼容性可能会根据这些参数进行更改。因此,始终提取数据将使其符合类型。如果你需要访问这个大小,假设'x'是这里的向量,那么你可以明确地传递大小:
coder.ceval('foo', x, int32(numel(x)));
不幸的是,这不允许你改变'foo'里面'x'的大小。
你可以做另外一件事,但请直接联系我(电子邮件),我会告诉你更多。
Alexander Bottema
软件工程师
MATLAB编码器团队
Mathworks
答案 1 :(得分:0)
我已经解决了这个问题,我想我有一个很好的解决方案。我创建了一个名为isallocated
的MATLAB函数,它将一个可变大小的双精度浮点数作为输入,如果数组正确分配则输出1,否则输出0。如果在MATLAB环境中调用,它总是返回1.
function result = isallocated(inarray) %#codegen
%ISALLOCATED Returns true if the array memory is allocated properly.
% Will check the array to verify that the data pointer is not null.
if coder.target('MATLAB')
result = int32(1);
return;
end
result = int32(0);
coder.cinclude('emxArray_helpers.h');
coder.updateBuildInfo('addSourceFiles', 'emxArray_helpers.c');
result = coder.ceval('isallocated_helper', coder.ref(inarray));
end
这个函数只是isallocated_helper
的包装器,这里唯一的技巧是coder.ref
命令将在inarray中提取指向数据数组的指针。这具有获取emxArray结构的data
成员的值的效果。
c函数isallocated_helper
非常无聊;它只是一个测试,看看指针是否为空。为了完整起见,我会把代码放在这里:
// emxArray_helpers.c
// A set of helper functions for emxArray types
int isallocated_helper(double * arrayptr)
{
if (arrayptr)
return 1;
return 0;
}
就是这样。这提供了一个很好的测试,如果我更改testmemoryallocation.m
文件以使用它,它看起来像:
function [result, output] = testmemoryallocation(dim) %#codegen
%TESTMEMORYALLOCATION Tests allocation of large 3D arrays
output = coder.nullcopy(zeros([dim, dim, dim]));
result = isallocated(output);
if result == 1
output(:) = 5;
else
output = zeros([1,1,2]);
end
end
在生成的c代码的片段中,我们可以看到测试:
...
/* TESTMEMORYALLOCATION Tests allocation of large 3D arrays */
i0 = output->size[0] * output->size[1] * output->size[2];
output->size[0] = (int)dim;
output->size[1] = (int)dim;
output->size[2] = (int)dim;
emxEnsureCapacity((emxArray__common *)output, i0, (int)sizeof(double));
/* ISALLOCATED Returns true if the array memory is allocated properly. */
/* Will check the array to verify that the data pointer is not null. */
*result = isallocated_helper(&output->data[0]);
if (*result == 1) {
...