当我试图使用MATLAB的复制(懒散复制)机制从一个单元格数组中的多个单元格连接相同的大矩阵时,我想知道是否有一种方法可以判断我是否做得对。
例如:
img = randn(500);
[dx,dy] = gradient(img);
S = cell(2,2);
S{1,1} = dx.^2;
S{2,2} = dy.^2;
S{1,2} = dx.*dy;
S{2,1} = S{1,2}; % should be a reference, as long as not modified但是看看whos的输出
>> whos
Name Size Bytes Class Attributes
S 2x2 8000448 cell
dx 500x500 2000000 double
dy 500x500 2000000 double
img 500x500 2000000 double 我希望看到S占据6 MB,而不是8 MB。
有没有办法验证程序中没有错误,而这两个单元格在结尾仍然引用相同的数组?
我知道memory函数,但遗憾的是它只适用于MacOS平台(我在MacOS上)。
发布于 2018-05-02 20:38:25
编辑:
在编辑答案之前,我使用了一个无文档的函数,它具有意想不到的行为,而且它的签名在不同版本的MATLAB之间并不稳定,所以这里我提供了@CrisLuengo答案的扩展版本。
我们可以使用哈希映射在递归函数check_shared中存储数据元素及其关联的check_shared的唯一地址,并获取数据大小。请注意,在这里,我们可以检查单元格中的共享状态,也不能检查单元格之外的元素,它们的地址与单元格元素的地址相同。
#include "mex.h"
#include <unordered_map>
typedef std::unordered_map<void *,const mxArray *> TableType;
TableType check_shared(const mxArray* arr, TableType table = TableType())
{
switch (mxGetClassID(arr)) {
case mxCELL_CLASS:
for(int i = 0; i < mxGetNumberOfElements (arr); i++) {
table = check_shared(mxGetCell (arr,i), std::move(table));
}
break;
case mxSTRUCT_CLASS:
for (int i = 0; i < mxGetNumberOfFields (arr); i++) {
for (int j = 0; j < mxGetNumberOfElements (arr); j++) {
table = check_shared(mxGetFieldByNumber (arr, j, i), std::move(table));
}
}
break;
case mxVOID_CLASS:
case mxFUNCTION_CLASS:
case mxUNKNOWN_CLASS:
return table;
}
if (!mxIsEmpty (arr)) {
void* data = mxGetData(arr);
table[data] = arr;
}
return table;
}
uint64_t actual_size(const TableType& table)
{
uint64_t sz = 0;
for (const auto& entry : table) {
const mxArray * arr = entry.second;
sz += mxGetElementSize (arr) * mxGetNumberOfElements (arr);
}
return sz;
}
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
TableType table = check_shared(prhs[0]);
plhs[0] = mxCreateNumericMatrix(1,1, mxUINT64_CLASS, mxREAL );
uint64_t* result = static_cast<uint64_t*>(mxGetData (plhs[0]));
result[0] = actual_size(table);
}(*)支持基本数据类型,如cell、struct和数字数组。对于未知的数据结构和classdef对象,函数返回零。
发布于 2018-04-29 05:49:23
验证两个特定数组是否真正共享数据的一个可能的解决方案是使用以下从Yair的无文件的MATLAB博客修改的MEX文件
#include "mex.h"
#include <cstdint>
void mexFunction( int /*nlhs*/, mxArray* plhs[], int nrhs, mxArray const* prhs[]) {
if (nrhs < 1) mexErrMsgTxt("One input required.");
plhs[0] = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL);
std::uint64_t* out = static_cast<std::uint64_t*>(mxGetData(plhs[0]));
out[0] = reinterpret_cast<std::uint64_t>(mxGetData(prhs[0]));
}将其保存为getaddr.cpp并使用
mex getaddr.cpp允许进行以下测试:
img = randn(500);
[dx,dy] = gradient(img);
S = cell(2,2);
S{1,1} = dx.^2;
S{2,2} = dy.^2;
S{1,2} = dx.*dy;
S{2,1} = S{1,2}; % should be a reference, as long as not modified
assert(getaddr(S{1,2}) == getaddr(S{2,1}))这与获取结构S实际使用的内存的摘要不一样(我仍然认为这将是有用的),但它确实允许验证内存是共享的。
发布于 2018-05-01 12:01:55
“是否有一种方法可以验证程序中没有错误,而这两个单元格在结尾仍然引用相同的数组?”
我会试着测量它花了多少时间。因为复制指针比复制数据更快,所以它应该以不同的比例缩放。
这表明了不同之处:
i=500:500:5000;
t=zeros(2,length(i));
for ct=1:length(i)
img = randn(i(ct));
[dx,dy] = gradient(img);
S = cell(2,2);
S{1,1} = dx.^2;
S{2,2} = dy.^2;
S{1,2} = dx.*dy;
tic;
S{2,1} = S{1,2}; % should be a reference, as long as not modified
t(1,ct)=toc;
tic
S{2,1} = S{1,2}+1;
t(2,ct)=toc;
end
B=(i.^2)*8;
figure(1);clf
subplot(1,2,1);
plot(t(1,:),B,'.')
xlabel('time(s)');ylabel('Bytes');
title(sprintf('reference: no relation'))
subplot(1,2,2);
a=sum(B.*t(2,:))/sum(t(2,:).^2);
plot(t(2,:),B,'.',t(2,:),a*t(2,:))
xlabel('time(s)');ylabel('Bytes');
title(sprintf('datacopy: %.2f GB/s',a/1E9))

所以程序中没有错误。Matlab给出了单元格的错误内存使用量。
mex文件和内存
所以我读了这篇文章:http://undocumentedmatlab.com/blog/matlabs-internal-memory-representation
在MATLAB2018a中,我无法复制结果。printmem适用于从format debug获得的指针,但getaddr和printaddr似乎不再提供相同的指针。
A=1:10
>Structure address = 7d9a3eb0
>m = 1
>n = 10
>pr = 74ed5f20
printaddr(A)
>000000007D894640用它作为printaddr:
/* printaddr.cpp */
#include "mex.h"
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
if (nrhs < 1) mexErrMsgTxt("One input required.");
printf("%p\n", prhs[0]);
}https://stackoverflow.com/questions/50073860
复制相似问题