3

Have I done something wrong or is vector-by-scalar multiplication really so costly? Doesn't MATLAB (ver 2012a or higher) optimize the code somehow to prevent such curiosities?

>> tic; for i=1:100000; x = sin(i)*[1; 1]; end; toc;
Elapsed time is 1.338225 seconds.
>> tic; for i=1:100000; x = sin(i).*[1; 1]; end; toc;
Elapsed time is 1.228331 seconds.
>> tic; for i=1:100000; x = [sin(i); sin(i)]; end; toc;
Elapsed time is 0.073888 seconds.
>> tic; for i=1:100000; tmp=sin(i); x = [tmp; tmp]; end; toc;
Elapsed time is 0.072120 seconds.

What guidelines could you give me to make FLOPS in MATLAB take the time they really need.

PS. This is a sample code only, what I do is solving systems of odes and I want to optimize runtime when calculating needed differentials. The above is giving me worries that I might be doing something in a non-optimal way.

Przemek M
  • 55
  • 6
  • 1
    Why not use vectorization? Like `x = sin(1:100000).'*[1;1].';` for the first case and so on. – Divakar Jul 10 '14 at 10:05
  • `>> tic; x = [1;1]*sin(1:100000); toc; Elapsed time is 0.003739 seconds.` I find matrix multiplication nicer then Divakar; BUT when I solve an ODE I cannot vectorize as the next step of the _for_ loop depends on the previous one. I understand that that vectorization will use a lot of multi-core CPU optimization, as the calculations are independent from each other. This is sadly not the case when solving an ODE. Additionally, my question is more for an explanation to this crazy times. – Przemek M Jul 10 '14 at 10:35
  • 2
    I guess if we take a look into your actual ODE case, it might make a lot more sense and `vectorization` *might* be possible. Using so many iterations is really the bottleneck and would be more so with dependencies between iterations. Manual optimization looks like the only way out, unless there are some built-in functions that exactly match your needs. – Divakar Jul 10 '14 at 10:47

3 Answers3

3

"Doesn't MATLAB (ver 2012a or higher) optimize the code somehow to prevent such curiosities?"

Yes, it does if the code is within a function m-file, due to the JIT compiler (Just in time compiler) and/or accelerator

However as mentioned in comments and other answers vectorisation is still generally a better option if possible

Straight on command line:

tic; for i=1:100000; x1 = sin(i)*[1; 1]; end; toc;
tic; for i=1:100000; x2 = sin(i).*[1; 1]; end; toc;
tic; for i=1:100000; x3 = [sin(i); sin(i)]; end; toc;
tic; for i=1:100000; tmp=sin(i); x4 = [tmp; tmp]; end; toc;
Elapsed time is 1.795528 seconds.
Elapsed time is 1.606081 seconds.
Elapsed time is 0.072672 seconds.
Elapsed time is 0.065904 seconds.

Within a function;

[x1,x2,x3,x4]=foo();
Elapsed time is 0.029698 seconds.
Elapsed time is 0.035248 seconds.
Elapsed time is 0.064080 seconds.
Elapsed time is 0.054499 seconds.

with the function foo saved as:

function [x1,x2,x3,x4]=foo()

tic; for i=1:100000; x1 = sin(i)*[1; 1]; end; toc;
tic; for i=1:100000; x2 = sin(i).*[1; 1]; end; toc;
tic; for i=1:100000; x3 = [sin(i); sin(i)]; end; toc;
tic; for i=1:100000; tmp=sin(i); x4 = [tmp; tmp]; end; toc;

end

Edit

While trying to find documentation to support the claims above I realised I had made a mistake it also accelerates script m-files, hence function being redacted above

Within a script;

fooscript;
Elapsed time is 0.033536 seconds.
Elapsed time is 0.033720 seconds.
Elapsed time is 0.066050 seconds.
Elapsed time is 0.058428 seconds.

with the script fooscript containing:

tic; for i=1:100000; x1 = sin(i)*[1; 1]; end; toc;
tic; for i=1:100000; x2 = sin(i).*[1; 1]; end; toc;
tic; for i=1:100000; x3 = [sin(i); sin(i)]; end; toc;
tic; for i=1:100000; tmp=sin(i); x4 = [tmp; tmp]; end; toc;

Sadly there is not a huge amount of documentation on JIT and accelerator (if any). However for comparison you can disable JIT or acceleration using feature('accel','on'/'off') and feature('jit','on'/'off'). (note: disabling accel also disables jit as it seems it is a part of accel.)

The performance improvement is reduced if accel is disabled however both function and script performance are still similar and both still noticeably faster than command line.

Disabling JIT had no noticeable effect on performance so the original statement was wrong.

RTL
  • 3,437
  • 13
  • 24
  • Oh that is cool, so the optimization will take place for saved .m files with functions. So I did as you told, and on the very same machine this `tic; for i=1:100000; x1 = sin(i)*[1; 1]; end; toc;` `tic; for i=1:100000; x2 = sin(i).*[1; 1]; end; toc;` `tic; for i=1:100000; x3 = [sin(i); sin(i)]; end; toc;` `tic; for i=1:100000; tmp=sin(i); x4 = [tmp; tmp]; end; toc;` in a script file yields `Elapsed time is 0.024564 seconds.` `Elapsed time is 0.023461 seconds.` `Elapsed time is 0.052010 seconds.` `Elapsed time is 0.051315 seconds.` So the first two solutions are now WAAAYS faster. – Przemek M Jul 10 '14 at 12:05
  • yes, maybe in my comment the tip about the script file was not to be seen easily, I immediately checked if scripts were accelerated the same way as functions, and TY again – Przemek M Jul 10 '14 at 13:44
  • @RTL, still -- in command line we are 100x slower than in .m file, is that another puzzle or am I missing something? maybe it is not JIT optimalization, but sort of 'core-optimalization', rly built in in the architecture of MATLAB and not to be turned-off – Przemek M Jul 10 '14 at 14:50
  • I don't know of any documented reasons however I believe I have read that Matlab was designed to run functions and scripts hence the better performance (possibly somewhere in [The art of Matlab blog](http://blogs.mathworks.com/loren/)) – RTL Jul 10 '14 at 15:03
2

Your for loops are killing you

This is the timings of your code on my machine:

tic; for i=1:100000; x = sin(i)*[1; 1]; end; toc;
tic; for i=1:100000; x = sin(i).*[1; 1]; end; toc;
tic; for i=1:100000; x = [sin(i); sin(i)]; end; toc;

Elapsed time is 0.799754 seconds.
Elapsed time is 0.819284 seconds.
Elapsed time is 1.90613 seconds.


If you vectorise it , you get

t=1:100000; 

tic;     t=1:100000;   x = sin(t).'*[1; 1].'; toc;

tic;     t=1:100000;   sin(t).*[1;1] ; toc;

tic;     t=1:100000;  [sin(t);sin(t)] ; toc;

Elapsed time is 0.015624 seconds.
Elapsed time is 0.0380838 seconds.
Elapsed time is 0.0322251 seconds.

tmp=sin(i); x = [tmp; tmp]; is the same as [sin(t);sin(t)];

kkuilla
  • 2,143
  • 3
  • 28
  • 36
  • 1
    1) you should include the memory assignment t=1:100000 into your tic-toc if you want your benchmark to be equivalent 2) I did not ask a lesson about vectorization, I specifically stated that FOR-loop is needed to solve AN ODE (ord diff eq), and you CANNOT vectorize. What puzzles me is that sin(i)*[1;1] takes so much more time than [sin(t),sin(t)] -- which could involve TWO function calls. 3) that "`tmp=sin(i); x = [tmp; tmp];` _is the same as_ `[sin(t);sin(t)];`" is obvious, BUT it involves code optimization, naively there would be two function calls. – Przemek M Jul 10 '14 at 11:40
  • @PrzemekM Modified according to 1) – kkuilla Jul 10 '14 at 11:54
  • @PrzemekM You didn't include an example of your ODE. Your comment after my answer stated that you must use a `for` loop. To be honest, I think the question asked doesn't really reflect the question you **really** want an answer to. – kkuilla Jul 10 '14 at 12:02
  • 4
    @PrzemekM I don't like the tone of your comment. Please remember that people voluntarily try to answer. – kkuilla Jul 10 '14 at 12:02
  • 1
    @PrzemekM There isn't a final word that dependencies between iterations CANNOT be vectorized. If the depenedency is traceable by following a pattern or something like it, vectorization might be possible. – Divakar Jul 10 '14 at 12:06
0

MATLAB is optimized for operations involving matrices and vectors. In many case you can rewrite your loop-based, scalar-oriented code to use MATLAB matrix and vector operations, a process called vectorization. Vectorized code often runs much faster than the corresponding code containing loops.

For example:

>> tic; for i=1:100000; x = sin(i)*[1; 1]; end; toc;
Elapsed time is 2.859756 seconds.

The same calculations can be performed using matrix operations as:

>> tic; x = [1;1]*sin(1:100000); toc
Elapsed time is 0.007731 seconds.
Pablo EM
  • 4,960
  • 3
  • 21
  • 35
  • TY for a wiki on vectorization. Obviously I was unaware of it. – Przemek M Jul 10 '14 at 11:44
  • Let me also teach you "_matrix multiplication_", instead of `sin(1:100000).'*[1;1].'` write `[1;1]*sin(1:100000)`. Kinda easier to understand if you know (linear) algebra... – Przemek M Jul 10 '14 at 11:46
  • I preferred to maintain the original order of the matrices, but maybe your solution is more easy to understand... – Pablo EM Jul 10 '14 at 12:47