Incredibly fast JS loop? - javascript

Today I've got an idea to check performance of loop which I have called "scoped for". The idea is simply. This loop has two variables, "i" and "l" which are defined "one scope higher" than loop itself.
There's nothing else in those two scopes.
I've created jsPerf and got amazing results.
http://jsperf.com/variable-scoped-loop/6
I decided to create my local test, and results are even better ( 1000x1000 loops average time of 5s for "standard for" and under 0.01s for "scoped for" ).
So now I am wondering why this loop is so damn fast. I`m assuming that it's all about V8, but you never know.
So anyone willing to explain?
TLDR :
Why this loop is so damn fast?
var loop = ( function() {
var i, l;
return function( length, action ) {
for( i = 0, l = length ; i < l ; ++i ) {
action();
}
};
}() );

Unfortunately, there's no magic here: your test is faulty.
For varInFor, the empty function is correctly called 9999^2 times, whereas with varInScope, it's only called 9999 times. That's why it finishes a lot quicker. You can test this easily by making the empty function print something.
The reason why is the fact that variables i and l are shared between the outer and inner call of varInScope. So after the inner loop finishes, i is already equal l and the outer loop immediately exits.
See another JSPerf for a fixed version that initializes the functions every time (to create a new set of variables in the closure) and it is, indeed, up to 20% slower than the "normal" for loop.

Related

Why JavaScript loops do not overflow stack?

I've got a couple of questions about memory allocation in JavaScript
As far as I know, JavaScript primitives are immutable and stored in the stack. If we change the value of a primitive or if we assign a new variable to the old variable, it creates a new memory location for each case.
let x = 2
let y = x
x = 3
console.log(y) // 2
When we run a large loop just as the example bellow, 99999999 times 8bytes needed in stack to allocate space for i. So, why the stack is not overflown?
for(let i = 0; i<99999999; i++){
let x = i
}
If millions of objects are created simultaneously (in a real world app), is the stack enough to hold references to all the objects in the heap?
(V8 developer here.)
When we run a large loop just as the example bellow, 99999999 times 8bytes needed in stack to allocate space for i. So, why the stack is not overflown?
The premise is incorrect. There's only one stack slot for i. Each iteration of the loop reuses it. Whether this loop runs once, or twice, or 100 times, or 9999... times therefore doesn't change how much stack space it needs.
If millions of objects are created simultaneously (in a real world app), is the stack enough to hold references to all the objects in the heap?
The usable stack size is a little less than a megabyte (this is determined by the operating system); on a 64-bit platform that's enough for around 100K pointers, which (very roughly) translates to several tens of thousand local variables distributed across all functions that currently have an activation (there's no specific number because "it depends"). So it's certainly possible to have more objects on the heap than can be referred to directly from the stack, but this is not typically a limitation that code runs into: for example, you could have a local variable pointing at an array, and that array can in turn refer to thousands of other objects. That way, a single stack slot can keep many objects easily accessible.
(Nitpick: millions of objects are never created "simultaneously", they're always allocated after each other, maybe in quick succession.)
the key point here is that the code includes a garbage collector,
once a memory allocation has been narked as not required, the GC is allowed to reallocated for a different use
this is a little oversimplified but lets looks at what's happening at each stage
let x = 3;
let y = x;
x = 2;
**sudo**
allocate x;
set x = 3;
allocate y;
set y = read x
set x = 2
so the stack never exceeds a single state that is scoped to 2 allocuted variables
for your loop example
for(let i = 0; i<99999999; i++){ //
let x = i
}
**sudo**
label forloop;
allocate i;
set i = 0;
allocate x;
set x = read i;
if i < 99999999
set i = read i + 1
goto forloop
else
deallocate x;
deallocate i;
here their may be some growth in the memory usage from the allocation of the x variable in the loop however GC can easily clean this up
now for the issue you haven't considered functions and recursion
function doSomething(i){
if(i>99999999){
return i;
else
return doSomething(i+1);
}
doSomething(0)
**sudo**
goto main;
label doSomething;
if read current_state_i < 99999999
allocate new_state;
allocate i in new_state;
set new_state_i = read current_state_i + 1
stack_push doSomething using new_state
//stack_pop returns here
set current_state_return = read new_state_return
else
set current_state_return = current_state_i
deallocate new_state
goto stack_pop
label main;
allocate dosomething_state;
allocate i in dosomething_state;
set dosomething_state_i = 0;
stack_push doSomething using dosomething_state
//stack_pop returns here
for this one every time you call the function doSomething the stack has an state added to it this state is a memory slot that stores the passed in value and any variables created in scope and the return
when doSomething is completed this state is marked as no required
however until the code can return the system has to keep allocating more and more room on the stack for each calls state this is why recursion is much less safe than normal loops
As commenters have already said, there is no stack involved in your example, or at least not how you imagine there is.
If you want to break your stack, try this instead:
function Overflow(count){
console.log('count:', count)
return Overflow(count + 1)
}
Overflow(0)

Heap's Algorithm Permutation JavaScript and Recursions' Stack?

I have an assignment to count repeated strings base on a Heap's Algorithm Permutation.The first thing I want to do is output the swapped strings, I found this code from jake's answer Can someone please help me understand recursion within this code in a loop? The output of this function are swapped strings.
function permAlone(string) {
var arr = string.split(''), // Turns the input string into a letter array.
permutations = []; // results
function swap(a, b) {
debugger; // This function will simply swap positions a and b inside the input array.
var tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
}
function gen(n) {
debugger;
if (n === 1) {
var x =arr.join('');
permutations.push(x);
} else {
for (var i = 0; i != n; i++) { // how does this loop executes within the call stack?
gen(n - 1);
debugger;
swap(n % 2 ? 0 : i, n - 1); // i don't understand this part. i understand the swap function, but I don't get how indexes are swapped here
}
}
}
gen(arr.length);
return permutations;
}
permAlone('xyz'); // output -> ["xyz","yxz","zxy","xzy","yzx","zyx"]
I have been experimenting it on debugger but still can't get what's happening.
I'm not sure what you mean by
understand recursion within this code in a loop
If you mean you want to see the algorithm in a loop form rather than a recursion version you can see them one by side in pseudocode in the wikipedia page here.
For your questions within the code:
how does this loop executes within the call stack?
You are right to refer to the call stack, and this is a general question regarding recursion. If you don't understand how recursion works with the stack you can refer to this really nice and simple video that demonstrates recursive calls using factorial calculation in java (start around min 4:00).
The line you look at is no different than any other line in the recursive function. We start by defining i and assigning the value 0 to it. We continue to check if it satisfies the condition of the for loop. If it does we step into the loop and execute the first line inside the loop which is the recursive call. Inside the recursive call we have a new stack frame which has no knowledge of the i variable we defined before executing the recursive call, because it is a local variable. So when we get to the loop in the new call we define a new variable i, assigning it 0 at first and incrementing it as the loop repeats in this stack frame/call instance. When this call finishes we delete the stack frame and resume to the previous stack frame (the one we started with) where i=0 still, and we continue to the next line.
All the calls have access to the arr and permutations variables since the function is defined in the same scope as the variables (inside the function permAlone) so within each call - no matter what the stack frame we are in, the changes made to those are made to the same instances. That's why every push done to permutations adds to the existing results and will be there when the function returns the variable at the end.
i don't understand this part. i understand the swap function, but I don't get how indexes are swapped here
Indexes are not swapped here. It is merely a call for the swap function with the correct indices.
swap(n % 2 ? 0 : i, n - 1);
is just
swap(a, b);
with
a = n% 2 ? 0 : i;
b = n - 1;
If the a part is what confuses you, then this is a use of the ternary operator for conditional value. That is, it's symbols used to form an expression that is evaluated differently according to the circumstances. The use is by
<<i>boolean epression</i>> ? <<i>value-if-true</i>> : <<i>value-if-false</i>>
to evaluate the above, first <boolean expression> is evaluated. If it's value it true then the whole expression is evaluated as <value-if-true>. Otherwise, the whole expression is evaluated as <value-if-false>.
In the code itself, for a, n % 2 is the boolean expression - js divides n by 2 and takes the remainder. The remainder is either 1 or 0. js implicitly converts those to true and false respectively. So if n is odd we get
a = 0
and if it's even we get
a = i
as the algorithm requires.

How strict is the syntax of a for-loop

So I have a fairly good amount of experience in coding. I've dabbled in Basic, HTML, Javascript, C, and C++, though the ones I've been using most recently are HTML and Javascript.
I am incredibly familiar with the for-loop. I've used it many times to loop through arrays, to operate recursive functions, etc. I know what it does and how to use it, but my question is about how it works.
Premise
In most languages, the basic syntax of a for loop is such:
var upperLimit = 10;
for(var i = 0; i < upperLimit; i++) {
/*Code to be executed*/
console.log(i);
}
In Javascript, this will output the numbers from 0 to 9 in the console.
I know that the parentheses contains 3 parts, each separated by semicolons.
The first is the initialization, which typically sets up the variables to be used to loop the statements.
The second is the condition, which runs before any of the code between the curly braces is executed. If it results in a True, the code is executed. Otherwise, the for-loop stops.
The third is the increment, which contains the last bit of code to be executed in the loop, and, by extension, the last thing executed before the next condition check.
Question
So, again, my question is how strict are these definitions?
The initialization's definition doesn't allow for much. It just says that that line is executed once, it's executed before anything else in the loop, and it's scope is limited to the loop. I can't think of much else you'd want to put in that position other than an iterative variable.
But what about the other two? I've seen codes where the condition is simply a variable, and as long as it's positive (since positive numbers taken as a boolean just covert to true), the loop continues.
Then there's the increment, which seems to be the loosest of these parts. Is it really just the last thing to be executed in a code, or does it explicitly need to iterate the variable declared in the initialization? It seems to be the former for the languages I'm familiar with.
For example, I decided to make a non-standard for-loop, and I came up with this routine:
var numbers = [0,1,2,3,4,5,6,7,8,9];
for(var i = 0;
numbers.length;
console.log(numbers.pop())) {}
It runs exactly as I expected: It outputs each member of the numbers array in the console in descending order, leaving an empty numbers array afterwards, and it's done using what is basically an empty for-loop.
Ending
So are my assumptions correct? If so, are there any practical applications for using a for-loop in a format apart from the one I wrote at the top of this question (possibly closer to he second format)?
Before all, you give a array
var numbers = [0,1,2,3,4,5,6,7,8,9];
The codes below is a correct for loop.
for(var i = 0;
numbers.length;
console.log(numbers.pop())) {}
Javascript defined for like this
for ([initialization]; [condition]; [final-expression])
statement
For you code initialization is 'var i = 0', and execute once at start of loop.
The condition is 'numbers.length', and value is 10. When a number not 0, Javascript will convert it to boolean true. So condition is true.
The final-expression is 'console.log(numbers.pop())'. When execute 'numbers.pop()', numbers.length change to 9. But it still is true.
At second time, condition will return true again. The final-expression is execute too.
Until numbers.length become 0, Javascript convert it to boolean false. The loop will end.
The scope of the initialized variable is not limited to the loop, it's valid for the whole function (undefined before that line). You can initialize multiple variables using a comma. for (var i=0, j=1; i < 10; i++)
The second part, anything that evaluates to a truthy value will cause the loop to keep going:
Truthy: 1, -1, true, "something", {a: 2}
Falsey: 0, false, null, undefined
You could omit this and rely on a break in your code
The third part just lets you update the looping variable, you could omit it and do it within the for loop body.
Here's an answer that provides a nice way to loop that is non-standard, and comes with caveats, please see the link.
var list = [{a:1,b:2}, {a:3,b:5}, {a:8,b:2}, {a:4,b:1}, {a:0,b:8}];
for (var i=0, item; item = list[i]; i++) {
// Look no need to do list[i] in the body of the loop
console.log("Looping: index ", i, "item" + item);
}
In most languages, the basic syntax of a for loop is such:
for(initialization; condition; iteration) {
/*Code to be executed*/
}
Both three are usual expressions and you can use any valid expressions here:
for(
var i=arr.length, othercond=true;
i;
othercond?i--:i++, console.log(i),updateothercond()
);

Why is recursion faster than a flat for loop for a summation function on JavaScript?

I'm working in a language that translates to JavaScript. In order to avoid some stack overflows, I'm applying tail call optimization by converting certain functions to for loops. What is surprising is that the conversion is not faster than the recursive version.
http://jsperf.com/sldjf-lajf-lkajf-lkfadsj-f/5
Recursive version:
(function recur(a0,s0){
return a0==0 ? s0 : recur(a0-1, a0+s0)
})(10000,0)
After tail call optimization:
ret3 = void 0;
a1 = 10000;
s2 = 0;
(function(){
while (!ret3) {
a1 == 0
? ret3 = s2
: (a1_tmp$ = a1 - 1 ,
s2_tmp$ = a1 + s2,
a1 = a1_tmp$,
s2 = s2_tmp$);
}
})();
ret3;
After some cleanup using Google Closure Compiler:
ret3 = 0;
a1 = 1E4;
for(s2 = 0; ret3 == 0;)
0 == a1
? ret3 = s2
: (a1_tmp$ = a1 - 1 ,
s2_tmp$ = a1 + s2,
a1 = a1_tmp$,
s2 = s2_tmp$);
c=ret3;
The recursive version is faster than the "optimized" ones! How can this be possible, if the recursive version has to handle thousands of context changes?
There's more to optimising than tail-call optimisation.
For instance, I notice you're using two temporary variables, when all you need is:
s2 += a1;
a1--;
This alone practically reduces the number of operations by a third, resulting in a performance increase of 50%
In the long run, it's important to optimise what operations are being performed before trying to optimise the operations themselves.
EDIT: Here's an updated jsperf
as Kolink say what your piece of code do is simply adding n to the total, reduce n by 1, and loop until n not reach 0
so just do that :
n = 10000, o = 0; while(n) o += n--;
it's more faster and lisible than the recursive version, and off course output the same result
There are not so much context changes inside the recursive version as you expect, since the named function recur is contained in the scope of recur itself/they share the same scope. The reason for that has to do with the way the JavaScript engines evaluate scope, and there are plenty of websites out there which explain this topic, so I will not do it here. At a second look you will notice that recur is also a so called "pure" function, which basically means it never has to leave it's own scope as long as the internal execution runs (simply put: until it returns a value). These two facts make it basically fast. I just want to mention here, the first example is the only tail call optimized one of all three – a tc optimization can only be done in recursive functions and this is the only recursive one.
However, a second look at the second example (no pun intended) reveals, that the "optimizer" made things worse for you, since it introduced scopes into the former pure function by splitting the operation into
variables instead of arguments
a while loop
a IIFE (immediatly invoked function expression) that separates the introduced inner and outer variables
Which leads to poorer performance since now the engine has to handle 10000 context changes.
To tell you the truth I do not know why the third example is poorer in performance than the recursive one, so maybe it has to do with:
the browser you use (ever tried another one and compared the results?)
the number of variables
stack frames created by for-loops (never heard of though), which
would have to do with the first example: the JS engines interpret a
pure recursive function until it finds a return statement. If the last thing following the statement is a function call, then evaluate any expressions (if any) and variables to pass as arguments, call the function and throw away the frame
something, only the browser-vendors can truly tell you :)

Is not having local functions a micro optimisation?

Would moving the inner function outside of this one so that its not created everytime the function is called be a micro-optimisation?
In this particular case the doMoreStuff function is only used inside doStuff. Should I worry about having local functions like these?
function doStuff() {
var doMoreStuff = function(val) {
// do some stuff
}
// do something
for (var i = 0; i < list.length; i++) {
doMoreStuff(list[i]);
for (var j = 0; j < list[i].children.length; j++) {
doMoreStuff(list[i].children[j]);
}
}
// do some other stuff
}
An actaul example would be say :
function sendDataToServer(data) {
var callback = function(incoming) {
// handle incoming
}
ajaxCall("url", data, callback);
}
Not sure if this falls under the category "micro-optimization". I would say no.
But it depends on how often you call doStuff. If you call it often, then creating the function over and over again is just unnecessary and will definitely add overhead.
If you don't want to have the "helper function" in global scope but avoid recreating it, you can wrap it like so:
var doStuff = (function() {
var doMoreStuff = function(val) {
// do some stuff
}
return function() {
// do something
for (var i = 0; i < list.length; i++) {
doMoreStuff(list[i]);
}
// do some other stuff
}
}());
As the function which is returned is a closure, it has access to doMoreStuff. Note that the outer function is immediately executed ( (function(){...}()) ).
Or you create an object that holds references to the functions:
var stuff = {
doMoreStuff: function() {...},
doStuff: function() {...}
};
More information about encapsulation, object creation patterns and other concepts can be found in the book JavaScript Patterns.
For optimal speed with a nested function (function within internal scope of an outer function), I suspect you should use declarations, not expressions.
The question asks about "local functions" and optimization, but doesn't specify how the local functions are created. But it should, because the question's answer probably is different for the different techniques by which the "inner function" can be created.
Looking at the answer and test results by #cleong, I suspect that only his answer is using the optimal technique for function creation. There are three ways to create a function, and #cleong is showing us the one that provides fast execution. The three techniques are:
constructor
declaration
expression
Constructor isn't used much, it requires a string that has the text of the function body. This would be useful in reflective programming, where you do a "toString()" to get the function body, modify, then construct a new function. And that, of course, is more-or-less never done.
Declaration is used, but mostly for outer functions, not inner functions (by "inner function" I mean a function nested within another). Yet, based upon #cleong tests, it seems to be very fast; just as fast as an outer function.
Expressions are what everyone uses. This might not be the best idea; but it's what everyone does.
One major difference between function declarations and function expressions is that the declarations are subject to hoisting. Everyone knows that "var" declarations are hoisted; but so are "function" declarations. For things that are hoisted, computations are performed at compile time to determine the memory space that will be needed for the thing. Presumably, one would expect that the inner function is compiled at compile time, and can run much as would a compiled outer function.
I have a copy of Flannigan's "The Definitive Guide" book from about six years ago, and I remember reading the reverse of what I just wrote here. He said something like: expressions are compiled, and declarations are not. While he is the world's "definitive guide" to JavaScript, I have always suspected he might have gotten this one mixed up and backwards. I suspect that function inner declarations are more "ready to go" than are function expressions. The test results on this stackOverflow page seem to confirm my long held suspicions.
Looking at the #cleong test results, it just seems that declaration, not expression, is the way to go for inner functions, if optimal execution speed is a concern.
The original question was asked in 2011. Given the rise of Node.js since then, I thought it's worth revisiting the issue. In a server environment, a few milliseconds here and there can matter a lot. It could be difference between remaining responsive under load or not.
While inner functions are nice conceptually, they can pose problems for the JavaScript engine's code optimizer. The following example illustrate this:
function a1(n) {
return n + 2;
}
function a2(n) {
return 2 - n;
}
function a() {
var k = 5;
for (var i = 0; i < 100000000; i++) {
k = a1(k) + a2(k);
}
return k;
}
function b() {
function b1(n) {
return n + 2;
}
function b2(n) {
return 2 - n;
}
var k = 5;
for (var i = 0; i < 100000000; i++) {
k = b1(k) + b2(k);
}
return k;
}
function measure(label, fn) {
var s = new Date();
var r = fn();
var e = new Date();
console.log(label, e - s);
}
for (var i = 0; i < 4; i++) {
measure('A', a);
measure('B', b);
}
The command for running the code:
node --trace_deopt test.js
The output:
[deoptimize global object # 0x2431b35106e9]
A 128
B 130
A 132
[deoptimizing (DEOPT eager): begin 0x3ee3d709a821 b (opt #5) #4, FP to SP delta: 72]
translating b => node=36, height=32
0x7fffb88a9960: [top + 64] <- 0x2431b3504121 ; rdi 0x2431b3504121 <undefined>
0x7fffb88a9958: [top + 56] <- 0x17210dea8376 ; caller's pc
0x7fffb88a9950: [top + 48] <- 0x7fffb88a9998 ; caller's fp
0x7fffb88a9948: [top + 40] <- 0x3ee3d709a709; context
0x7fffb88a9940: [top + 32] <- 0x3ee3d709a821; function
0x7fffb88a9938: [top + 24] <- 0x3ee3d70efa71 ; rcx 0x3ee3d70efa71 <JS Function b1 (SharedFunctionInfo 0x361602434ae1)>
0x7fffb88a9930: [top + 16] <- 0x3ee3d70efab9 ; rdx 0x3ee3d70efab9 <JS Function b2 (SharedFunctionInfo 0x361602434b71)>
0x7fffb88a9928: [top + 8] <- 5 ; rbx (smi)
0x7fffb88a9920: [top + 0] <- 0 ; rax (smi)
[deoptimizing (eager): end 0x3ee3d709a821 b #4 => node=36, pc=0x17210dec9129, state=NO_REGISTERS, alignment=no padding, took 0.203 ms]
[removing optimized code for: b]
B 1000
A 125
B 1032
A 132
B 1033
As you can see, function A and B ran at the same speed initially. Then for some reason a deoptimization event occurred. From then on B is nearly an order of magnitude slower.
If you're writing code where performance is importantly, it's best to avoid inner functions.
It completely depends on how often the function is called. If it's a OnUpdate function that is called 10 times per second it is a decent optimalisation. If it's called three times per page, it is a micro optimalisation.
Though handy, nested function definitions are never needed (they can be replaced by extra arguments for the function).
Example with nested function:
function somefunc() {
var localvar = 5
var otherfunc = function() {
alert(localvar);
}
otherfunc();
}
Same thing, now with argument instead:
function otherfunc(localvar) {
alert(localvar);
}
function somefunc() {
var localvar = 5
otherfunc(localvar);
}
It is absolutely a micro-optimization. The whole reason for having functions in the first place is so that you make your code cleaner, more maintainable and more readable. Functions add a semantic boundary to sections of code. Each function should only do one thing, and it should do it cleanly. So if you find your functions performing multiple things at the same time, you've got a candidate for refactoring it into multiple routines.
Only optimize when you've got something working that's too slow (If it's not working yet, it's too early to optimize. Period). Remember, nobody ever paid extra for a program that was faster than their needs/requirements...
Edit: Considering that the program isn't finished yet, it's also a premature optimization. Why is that bad? Well, first you're spending time working on something that may not matter in the long run. Second, you don't have a baseline to see if your optimizations improved anything in a realistic sense. Third, you're reducing maintainability and readability before you've even got it running, so it'll be harder to get running than if you went with clean concise code. Fourth, you don't know if you'll need doMoreStuff somewhere else in the program until you've finished it and understand all your needs (perhaps a longshot depending on the exact details, but not outside the realm of possibility).
There's a reason that Donnald Knuth said Premature optimization is the root of all evil...
A quick "benchmark" run on an average PC (i know there are lots of unaccounted-for variables, so dont comment on the obvious, but it's interesting in any case):
count = 0;
t1 = +new Date();
while(count < 1000000) {
p = function(){};
++count;
}
t2 = +new Date();
console.log(t2-t1); // milliseconds
It could be optimised by moving the increment to the condition for example (brings running time down by about 100 milliseconds, although it doesn't affect the difference between with and without function creation, so it isn't really relevant)
Running 3 times gave:
913
878
890
Then comment out the function creation line, 3 runs gave:
462
458
464
So purely on 1000,000 empty function creations you add about half a second. Even assuming your original code is running 10 times a second on a handheld device (let's say that devices overall performance is 1/100 of this laptop, which is exaggerated - it's probably closer to 1/10, although will provide a nice upper bound), that's equivalent to 1000 function creations/sec on this computer, which happens in 1/2000 of a second. So every second the handheld device is adding overhead of 1/2000 second of processing... half a millisecond every second isn't very much.
From this primitive test I would conclude that on a PC this is definitely a micro-optimisation, and if you're developing for weaker devices, it is almost certainly as well.

Categories