20

In the process of analyzing how fast a trivial loop could be, I encountered this strange phenomenon.

Doing nothing with a variable is much slower than doing something with it.

Of course this is not a real problem as you won't often feel the urge to write code that does nothing, but this surprised me so I wonder if anyone understands what is happening and whether this could be a problem in real situations.

Here is what I found:

     tic,for t= 1:1e6, x=x; end,toc %This runs very fast, about 0.07 sec
y=x; tic,for t= 1:1e6, y=x; end,toc %This runs fast, about 0.11 sec
     tic,for t= 1:1e6, x; end,toc   %This takes over half a second?!

I tried adding a trivial calculation in the loop to ensure the loop would not be optimized away but this did not change results.


To summarize, my question is:

What is happening and should I ever worry about it?

Dennis Jaheruddin
  • 21,208
  • 8
  • 66
  • 122
  • 2
    Strange, and interesting. Well spotted! – Luis Mendo Sep 19 '13 at 15:22
  • 2
    However, doing *nothing* (`for t= 1:1e6, end`) is actually the fastest. You are doing *something* when you invoke `x`. Consider changing the question title – Luis Mendo Sep 19 '13 at 15:26
  • 1
    Then again: `ticl;for t= 1:1e6, x(1); end,toc` is fast again – Nick Sep 19 '13 at 15:26
  • Can't it be that Matlab is trying to invoke `x` as a function i.s.o. seeing it as a variable? – Nick Sep 19 '13 at 15:27
  • 2
    @Nick but then `x(1)` would not prevent Matlab from invoking it as a function – Luis Mendo Sep 19 '13 at 15:28
  • @LuisMendo true, maybe the order of execution is different then. – Nick Sep 19 '13 at 15:31
  • @Nick Actually `x(1)` appears to be 10 times slower than `y=x(1)` (for `x=6`), so doing something is still faster than doing nothing. --- Also updated the title to be more accurate. – Dennis Jaheruddin Sep 19 '13 at 15:36
  • To add to the fun: `tic, for t= 1:1e6, [x]; end, toc` is fast again. On the other hand, `tic, for t= 1:1e6, []; end, toc` is pretty slow – Luis Mendo Sep 19 '13 at 15:38
  • It is funny to see that your question has many related questions that I couldn't find when I searched before doing [this question](http://stackoverflow.com/questions/18498749/looping-statements-performance-and-pre-allocating-the-looping-statement-itself). Once again JIT accelerator making things work as not expected. – Werner Sep 19 '13 at 17:33
  • "...should I ever worry about it?" Can you think of a case where just declaring a variable like this would have any use? It's probably the JIT not being invoked, because this just doesn't seem to be a useful or sensible case -maybe it should be though or maybe mlint should tell you to remove the line. – horchler Sep 19 '13 at 18:03

2 Answers2

11

The JIT accelerator is a moving target and trying to guess what it accelerates is nearly impossible. On my machine 64 bit Linux R2013a x=x and y=x take the same amount of time, but x is much slower. If I turn the JIT accelerator off feature accel off then x=x and y=x take more time, but x stays the same. In fact with the accelerator off, x=x takes the same time as x (y=x is a little slower). This suggests that the JIT accelerator doesn't work on x. As to why TMW chose not to accelerate x, your guess is as good as mine.

StrongBad
  • 869
  • 6
  • 16
  • 5
    They probably figured nobody would be crazy enough to try it... until Dennis came along! – Buck Thorn Sep 19 '13 at 18:07
  • 3
    What will really blow your mind is trying to guess _when_ MATLAB can accelerate. Try `tic,for t = 1:1e6, x; y=x; end,toc` It takes about 3x longer than just x! Why can it no longer accelerate `y=x;`? Works the same if you put `x;` after `y=x;`! – chappjc Sep 19 '13 at 20:40
7

I believe that you ran your code within a script or in the command line. If you run it within a function you will see that all 3 variants take almost exactly the same amount of time. In the command line, Matlab cannot employ all of its available optimizations and so the first 2 variants are optimized while the third is not. This is not very concerning, since Matlab code is typically run within functions, where the optimizations' effectiveness is maximized.

When comparing different execution paths for performance, you should always test within a function, as tempting and easy as it is to test in the command prompt.

p.s. - In this particular case, it is not the JIT that is at fault but rather the interpreter's other (non-JIT) set of accelerations. The behavior vis-a-vis command-line vs. function is the same as with JIT, namely that many optimizations available within functions are unavailable in the CL. You can see this by seeing that feature jit off makes no real difference regarding the timing variability (it makes variants #1+#2 slower, but they are still faster than variant #3) - but when you run feature accel off all the differences between the variants are eliminated and all of them run at the slow speed of variant #3 (0.5 secs in the CL, 0.25 secs in a function). JIT is a apparently subset of accel, so turning accel off also turns off JIT (but not vise versa).

Yair Altman
  • 5,704
  • 31
  • 34
  • Great advice regarding use of functions vs. scripts/command line for benchmarking. MathWorks [recommends use of functions to improve performance](http://www.mathworks.com/help/matlab/matlab_prog/techniques-for-improving-performance.html#btimcn8) although it seems that users seldom heed that advice. Thanks for the commentary regarding non-JIT acceleration features - the JIT is not only a moving target, it is all too often blamed for [various peculiarities](http://stackoverflow.com/q/19499239/2778484) like this. – chappjc Dec 25 '13 at 18:16