3

function* test() {
  console.time("function-call")
  loop();
  console.timeEnd("function-call");

  console.time("in-function");
  var i, j;
  i = 0;
  while (i < 10000) {
    j = 0;
    while (j < 10000) {
      j++
    }
    i++;
  }
  console.timeEnd("in-function");
}

function loop() {
  var i, j;
  i = 0;
  while (i < 10000) {
    j = 0;
    while (j < 10000) {
      j++
    }
    i++;
  }
}

test().next();

I copied the code block in the 'loop', and pasted into 'test' function to compare time.

function-call: 84ms 
in-function: 596ms

calling a function is much faster than looping inside the function. Why is that so?

Daniel
  • 7,684
  • 7
  • 52
  • 76
Cory
  • 929
  • 12
  • 19
  • 2
    My guesstimate is that the optimizer realizes that your loop function doesn't do anything (`i` and `j` can't be accessed outside the loop and nothing happens in the loop), so it's optimized away. But for some reason that same optimization doesn't catch when the loop is in a bigger context. – Joachim Sauer Jan 24 '19 at 11:37
  • On Chrome (v8 engine), the in-function is slightly faster. On firefox I reproduced your result. Interesting question – Christian Vincenzo Traina Jan 24 '19 at 11:39
  • @JoachimSauer actually, i have similar code block that does something. i prepared a simplified version of it to ask. – Cory Jan 24 '19 at 11:40
  • Tested on node js function-call: 154.183ms, in-function: 152.907ms, @Cory, can you append your original code. – Daniel Jan 24 '19 at 11:40
  • @Daniel NodeJs uses V8 engine. I guess V8 optimizes both because of TurboFan – Christian Vincenzo Traina Jan 24 '19 at 11:44
  • 1
    The interesting thing is that enclosing the `in-function` function inside an IIFE, it runs way faster. So probably the @JoachimSauer guess is 100% right. And maybe we shouldn't ask why `function-call` is faster, but why `in-function` is slower – Christian Vincenzo Traina Jan 24 '19 at 11:49
  • Both giving me around 50ms on chrome v71. – TheChetan Jan 24 '19 at 12:00

1 Answers1

1

@Cristian Traìna Node does not allow to skip empty loops. These optimizations are allowed only in compiled languages like Pascal or C/C++ with flags like -O2.

For this program

var max=process.argv[2];
for(var i=0;i<=max;i++){} // with let results is the same

We can get the following dependency of time of execution from a number of loops. It is a LogLog chart. The first flat area it domain when dominating part of execution time is starting of NodeJs. After 1M loops, you can see that increasing number of iteration scaling with time linearly. Highest measurement takes about 1000 seconds so definitely, V8 does not skip the empty loop.


(source: gustawdaniel.pl)

Coming back to script from question:

  • Chrome 71.0.3578.98
function-call: 154.878662109375ms
in-function: 153.7490234375ms
  • Node v10.15.0
function-call: 154.183ms
in-function: 152.907ms
  • Firefox Quantum 64.0
function-call: 156 ms debugger eval code:4:3
in-function: 1519 ms
  • Chromium 71.0.3578.98
function-call: 158.954345703125ms
in-function: 153.663818359375ms
  • Vivaldi 2.2
function-call: 153.548095703125ms
in-function: 153.755126953125ms
  • Opera 58.0.3135.47
function-call: 154.34814453125ms
in-function: 154.729248046875ms

The computer of my Friend tests:

  • Edge
function-call: 3 496,6 ms
in-function: 2 330,9 ms
  • Chrome
function-call: 70.69580078125ms
in-function: 70.43310546875ms

So now it seems to be a problem with Firefox and Edge.

Any of these browsers except Firefox and Edge uses V8 engine. Firefox is described here:

https://www.digitaltrends.com/web/mozilla-firefox-new-browser-engine-quantum-2017/

and uses Quantum Flow:.

Edge team think about adopting Chromium engine

https://www.pcmag.com/news/365345/microsofts-edge-browser-to-adopt-googles-chromium-engine

From this article

https://blog.mozilla.org/blog/2018/12/06/goodbye-edge/

We can see that only Chromium from Google and Gecko Quantum from Mozilla will be supported in the future.

If anyone has access to Safari or Edge, please append tests.

Community
  • 1
  • 1
Daniel
  • 7,684
  • 7
  • 52
  • 76
  • 1
    Ok, I never said that V8 skips empty loops, but even if I didn't say it, it **could** still be true. Even if JavaScript isn't a compiled language, the most modern engines perform some just-in-time compilation and watch the code ahead in order to make some prevision and optimize the code. If I don't get wrong, V8 uses *at least* two threads, one to optimize and one to execute – Christian Vincenzo Traina Jan 24 '19 at 13:20
  • I agree with both `you did not say it` and it potentially **could** be true. I observed skipping empty loops only in compiled languages, and only with special flags. – Daniel Jan 24 '19 at 13:25
  • I mean that Node is not specially optimized in this task because of his speed is typical speed in empty loops for many script languages like php, perl, python, ruby, and node is in this group. This is a chart with the logarithm of time of execution one loop without this special flasg (smaller values - faster) https://blog.gustawdaniel.pl/content/images/2019/01/speed-2.png – Daniel Jan 24 '19 at 13:31