Allocating elements in a large matrix takes a VERY long time. Why?

MATLAB is doing something I have never seen before. Can anyone explain to me the following behaviour:
I have some code:
function myFuncMain()
myMat = NaN(1E5, 5E2);
for t = 1: T
%carry out some tests
%allocate elements to the matrix, eg
myMat(i, j) = 10;
myMat(z,y) = now;
%etc
%Now go into an external function
myMat = myFunc(myMat, variables);
end
end
function myMat = myFunc(myMat, variables)
%carry out some more tests
%allocate some more elements to the matrix, eg
myMat(ii, jj) = 10;
myMat(zz,yy) = now;
%etc
end
When I look at this code in the profiler, I see that >99.99% of the time is spent on the first allocation to the matrix in myFunc.m
Everytime, this function is called it takes a HUGE amount of time, according to the profiler, for the first element to be assigned to the matrix. Then according to the profiler, all the other assignations are instantaneous as expected.
whats going on? Is this something to do with the size of the matrix? Is it be copied somewhere behind the scenes?
I use a 64bit, 16GB machine.

 Accepted Answer

Matt J
Matt J on 14 Feb 2013
Edited: Matt J on 14 Feb 2013
Because you are changing myMat inside myFunc, MATLAB assumes that a new copy of the entire myMat matrix is required. This happens the instant myFunc makes the first change, resulting in the large memory allocation time that you see.
If MATLAB knew that you were planning to overwrite your original myMat in the calling workspace with the one generated inside myFunc, it would not need to create a new copy, but its parsing mechanism isn't smart enough to know that.

4 Comments

oh. I feel like I should have known that. thank you.
What do you recommend doing? Remove the function and put all the code that is inside myFunc.m inside the "for t:T" loop?
I seem to remember that C++ allows you to do inline functions, but I dont think Matlab supports these (clarification: matlab uses the word inline differently from C++)?
thank you!
Eliminating function calls from for-loops tends to make them faster, so if this is speed critical, I tend to think that would be the most optimal course. However, you could also use my Reference class below, which I created as a workaround to this kind of thing.
classdef Reference < handle
%Reference - a handle class with basic struct-like assignment capabilities.
%
% obj=Reference(inputStruct)
%
%will turn an ordinary structure inputStruct into a handle object
%having much the same behavior as the original struct, i.e., fields can be
%dynamically added to it via
%
% obj.field1=...;
% obj.field2=...;
% etc...
%
%However, because it is a handle object, the field data it carries gets passed
%around by reference.
%
%This is useful, for example, if we want a variable X to be processed by
%reference in a function call, i.e.,
%
% obj=Reference;
% obj.X=X;
% clear X
% func(obj,...)
%
%would allow func() to process obj.X arbitrarily, without making a 2nd deep
%copy of X, and so that obj.X in the base workspace would feel the
%changes made by func.
properties
data;
end
methods
function obj=Reference(dataInput)
if nargin==0, return; end
obj.data=dataInput;
end
function out=subsref(obj,S)
if isequal(S(1).type,'.')
out=builtin('subsref',obj.data,S);
else
disp 'Indexing method unimplemented'
keyboard
end
end
function obj=subsasgn(obj,S,rhs)
if isequal(S(1).type,'.')
obj.data=builtin('subsasgn',obj.data,S,rhs);
else
disp 'Indexing method unimplemented'
keyboard
end
end
function obj=display(obj)
lbl=inputname(1);
if isempty(lbl), lbl='ans'; end
lbl=[lbl ' ='];
T=evalc('obj.data');
T=strrep(T,'ans =', lbl);
jj=find(T~=sprintf('\n'),1,'last');
T=T(1:jj);
disp(T), disp ' '
end
end
end
Just to elaborate a little on my previous Comment, using the Reference class, your code would get modified as follows
function myFuncMain()
obj=Reference;
myMat = NaN(1E5, 5E2);
for t = 1: T
myMat(i, j) = 10;
myMat(z,y) = now;
%etc
%Now go into an external function
obj.X=myMat; clear myMat
myMat = myFunc(obj, variables);
end
end
function myMat = myFunc(obj, variables)
%carry out some more tests
%allocate some more elements to the matrix, eg
myMat=obj.X; obj.X=[];
myMat(ii, jj) = 10;
myMat(zz,yy) = now;
%etc
end

Sign in to comment.

More Answers (1)

You might also consider using this fast matrix allocation function UNINIT from the FEX:
The UNINT function allocates arrays of uninitialized values and can be useful in cases where you know the values will be overwritten downstream before their use.

Categories

Find more on Function Creation in Help Center and File Exchange

Tags

Community Treasure Hunt

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

Start Hunting!