Improvement the speed of array filling
19 vues (au cours des 30 derniers jours)
Afficher commentaires plus anciens
I am performing some intensive array work for a simulation . Esentially , I have a 40X27000 (X) array which at first is filled with initial values and after doing some operations is updated , all this procedure is done inside a for loop . After doing profiling , it can be seen that the lines of code used for updating the values are considerably slow.
(As I am not providing all the code , please consider that not described variables are auxilliary variables of compatible size that come from intermediate computing steps )
Inside the for loop I have considered the following options I have not noticed any improvement :
Option A
A = (MM-X(8,:))./VV;
B = (LL-X(3,:))./FF;
C = G.*(-I)./(1.0+(1.5./X(9,:)).^8.0); %This is slow , but expected
%Continues for C D E ...%
X = X + W .* [A; B; C; D; E] %This last array [A; B; C; D; E] is made up of 40 elements , just showing some for simplicity purposes.
Option B
A = (MM-X(8,:))./VV;
B = (LL-X(3,:))./FF;
C = G.*(-I)./(1.0+(1.5./X(9,:)).^8.0);
%Continues for C D E ...%
X(1,:) = X(1,:) + W .* A
X(2,:) = X(2,:) + W .* B
X(3,:) = X(3,:) + W .* C
X(4,:) = X(4,:) + W .* D
% ... Continues for all variables %
Option C
X(1,:) = X(1,:) + W .* (MM-X(8,:))./VV;
X(2,:) = X(2,:) + W .* (LL-X(3,:))./FF;
X(3,:) = X(3,:) + W .* G .*(-I)./(1.0+(1.5./X(9,:)).^8.0);
% ... Continues for all variables%
Furthermore , I have tried initializing X as a gpuArray() without any improvement . Thanks for your help
7 commentaires
Walter Roberson
le 4 Sep 2022
Also, you would improve performance by working with the transpose of your array, so that you are working on columns instead of rows. Memory for any individual column is consecutive and so faster.
dpb
le 4 Sep 2022
Modifié(e) : dpb
le 4 Sep 2022
It's tmp that's the bottleneck, not X, it is the one that needs preallocation and direct addressing into when each row/column(*) is defined.
If you were to also follow Walter's point regarding internal array storage order and reorient as column vectors (thus writing contiguous memory as much as possible), it would seem most probable, yes. I was thinking about A with the large array preallocated first. Not sure there whether there would/would not be difference between the two; would have to test to see; the larger memory footprint might override the internal array operations.
@Matt J's idea of the cell array is interesting to do similar with the "divide and conquer" idea although I'd think the cell addressing would add a little over the direct array addressing mode if the vectors were, again, column oriented. Again, probably only profiling/timing will really prove it one way or t'other; you can't predict the outcome of the optimizer's output.
Whether this would end up being a candidate for mex'ing I dunno, either...possibly.
Réponse acceptée
Matt J
le 4 Sep 2022
Modifié(e) : Matt J
le 4 Sep 2022
Furthermore , I have tried initializing X as a gpuArray() without any improvement.
There should be some improvement. If there isn't, the bottleneck is somewhere else.
% Problematic Line %
X = X + W .* [A; B; C; A; B; C; A; B; C; A; B; C; A; B; C; A; B; C; A; B; C; A; B; C; A; B; C; A; B; C; A; B; C; A; B; C; A; B; C;A; B; C;A; B; C;] ;
Do you really have such substantial repetition in the update matrix A,B,C,A,B,C... If so, that can be exploited.
[m,n]=size(X);
X=reshape(X,3,n,[]) + W.*[A;B;C]
If not, and if you really do have 40 different expressions for all 40 rows, (I would find it strange/surprising to have so many), the fastest thing would then be to keep the rows of X as a cell array:
X{1} = X{1} + W .* (MM-X{8})./VV;
X{2} = X{2} + W .* (LL-X{3})./FF;
X{3} = X{3} + W .* G .*(-I)./(1.0+(1.5./X{9}).^8.0);
9 commentaires
Matt J
le 4 Sep 2022
OK. Need to put the code inside a function to see full optimization:
runTest()
Still, though, it's important to realize there will be scenarios where in-place updates are not optimized and cell array access turns out to be better, like in this second test:
runTest2()
function runTest()
X=rand(40,27e5);
dX=rand(40,27e5);
tic;
for i=1:40
X(i,:)=X(i,:)+dX(i,:);
end
toc;
Xt=X';dXt=dX';
tic;
for i=1:40
Xt(:,i)=Xt(:,i)+dXt(:,i);
end
toc;
X=num2cell(X,2);
dX=num2cell(dX,2);
tic;
for i=1:40
X{i}=X{i}+dX{i};
end
toc;
end
function runTest2()
X=rand(40,27e5);
dX=rand(40,27e5);
I=speye(27e5);
tic;
for i=1:40
X(i,:)=X(i,:)*I;
end
toc;
Xt=X';dXt=dX';
tic;
for i=1:40
Xt(:,i)=I*Xt(:,i);
end
toc;
X=num2cell(X,2);
dX=num2cell(dX,2);
tic;
for i=1:40
X{i}=X{i}*I;
end
toc;
end
Bruno Luong
le 4 Sep 2022
Modifié(e) : Bruno Luong
le 4 Sep 2022
"it's important to realize there will be scenarios where in-place updates are not optimized "
I don't think your second test show the penalty is due to inplace. IMO the speec reduction is because that the Xt(:,i) on the RHS has to be extracted from the original vector to form a new vector for matrix x vector multiplication. Matlab JIT does not go yet into inplace-pointer in operation/function. Where as the cell array loop, no such extraction is needed.
Plus de réponses (0)
Voir également
Catégories
En savoir plus sur Performance and Memory dans Help Center et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!