Extreme JavaScript Performance

Preview:

DESCRIPTION

Talk given at http://jsconf.eu 2009. You serve up your code gzipped. Your caches are properly configured. Your data (and scripts) are loaded on-demand. That's awesome—so don't stop there. Runtime is another source of slowdowns, and you can learn to conquer those, too. Learn how to benchmark your code to isolate performance issues, and what to do when you find them. The techniques you'll learn range from the normal (function inlining) to the extreme (unrolling loops).

Citation preview

Extreme JavaScript

Performance

Thomas Fuchs@thomasfuchs

DO NOT, EVER,OPTIMIZE

PREMATURELY

http://tr.im/extremejs

SpiderMonkey

SpiderMonkey

JavaScriptCore

SpiderMonkey

JavaScriptCore

JScript

SpiderMonkey

JavaScriptCore

JScript

V8

#1 avoid function calls

function  methodCall(){    function  square(n){  return  n*n  };    var  i=10000,  sum  =  0;    while(i-­‐-­‐)  sum  +=  square(i);}

function  inlinedMethod(){      var  i=10000,  sum  =  0;    while(i-­‐-­‐)  sum  +=  i*i;}

function  methodCall(){    function  square(n){  return  n*n  };    var  i=10000,  sum  =  0;    while(i-­‐-­‐)  sum  +=  square(i);}

function  inlinedMethod(){      var  i=10000,  sum  =  0;    while(i-­‐-­‐)  sum  +=  i*i;}

function  methodCall(){    function  square(n){  return  n*n  };    var  i=10000,  sum  =  0;    while(i-­‐-­‐)  sum  +=  square(i);}

function  inlinedMethod(){      var  i=10000,  sum  =  0;    while(i-­‐-­‐)  sum  +=  i*i;}

methodCall() inlinedMethod()

0.410s 0.150s

0.056s 0.045s

uhm,  hmm† 0.128s

0.027s 0.016s

methodCall() inlinedMethod()

0.410s 0.150s

0.056s 0.045s

uhm,  hmm† 0.128s

0.027s 0.016s

methodCall() inlinedMethod()

0.410s 0.150s

0.056s 0.045s

uhm,  hmm† 0.128s

0.027s 0.016s

methodCall() inlinedMethod()

0.410s 0.150s

0.056s 0.045s

uhm,  hmm† 0.128s

0.027s 0.016s

methodCall() inlinedMethod()

0.410s 0.150s

0.056s 0.045s

uhm,  hmm† 0.128s

0.027s 0.016s

IE8 throws this warning after 1 second

#2 embrace the

language

function  literals(){    var  a  =  [],  o  =  {};}

function  classic(){    var  a  =  new  Array,  o  =  new  Object;}

classic() literals()

0.291s 0.265s

0.020s 0.016s

0.220s 0.185s

0.024s 0.010s

classic() literals()

0.291s 0.265s

0.020s 0.016s

0.220s 0.185s

0.024s 0.010s

classic() literals()

0.291s 0.265s

0.020s 0.016s

0.220s 0.185s

0.024s 0.010s

classic() literals()

0.291s 0.265s

0.020s 0.016s

0.220s 0.185s

0.024s 0.010s

classic() literals()

0.291s 0.265s

0.020s 0.016s

0.220s 0.185s

0.024s 0.010s

>  parseInt(12.5);12

>  ~~(1  *  "12.5")12

1 * string coerces thestring into a float,

result = 12.5

double bitwise NOT*floors the number

>  ~~(1  *  "12.5")12

*good overview on http://tr.im/bitwise

parseInt() weird  stuff

0.003s 0.002s

0.088s 0.081s

uhm,  hmm† 0.547s

0.109s 0.282s

parseInt() weird  stuff

0.003s 0.002s

0.088s 0.081s

uhm,  hmm† 0.547s

0.109s 0.282s

parseInt() weird  stuff

0.003s 0.002s

0.088s 0.081s

uhm,  hmm† 0.547s

0.109s 0.282s

parseInt() weird  stuff

0.003s 0.002s

0.088s 0.081s

uhm,  hmm† 0.547s

0.109s 0.282s

parseInt() weird  stuff

0.003s 0.002s

0.088s 0.081s

uhm,  hmm† 0.547s

0.109s 0.282s

parseInt() weird  stuff

0.003s 0.002s

0.088s 0.081s

uhm,  hmm† 0.547s

0.109s 0.282s

Firefox is 30x faster than Safari

#3 loops

var  test  =  '';for  (var  i  =  0;i<10000;i++)  test  =  test  +  str;

var  test  =  '',  i  =  10000;while(i-­‐-­‐)  test  =  test  +  str;

for  loop while  loop

0.12s 0.12s

0.13s 0.13s

0.6s 0.6s

0.04s 0.04s

for  loop while  loop

0.12s 0.12s

0.13s 0.13s

0.6s 0.6s

0.04s 0.04s

for  loop while  loop

0.12s 0.12s

0.13s 0.13s

0.6s 0.6s

0.04s 0.04s

for  loop while  loop

0.12s 0.12s

0.13s 0.13s

0.6s 0.6s

0.04s 0.04s

for  loop while  loop

0.12s 0.12s

0.13s 0.13s

0.6s 0.6s

0.04s 0.04s

var  test  =  '';for  (var  i  =  0;i<10000;i++)  test  =  test  +  str;

var  test  =  '',  i  =  10000;while(i-­‐-­‐)  test  =  test  +  str;

3 expressions in “for”

1 expression in “while”(when i equals 0, expression will be false)

function  normalLoop(){    var  i=60,  j=0;    while(i-­‐-­‐)  j++;}

function  unrolledLoop(){    var  j=0;    j++;  j++;  j++;  j++;  j++;  j++;      j++;  j++;  j++;  j++;  j++;  j++;    j++;  j++;  j++;  j++;  j++;  j++;    j++;  j++;  j++;  j++;  j++;  j++;    j++;  j++;  j++;  j++;  j++;  j++;    j++;  j++;  j++;  j++;  j++;  j++;    j++;  j++;  j++;  j++;  j++;  j++;    j++;  j++;  j++;  j++;  j++;  j++;    j++;  j++;  j++;  j++;  j++;  j++;    j++;  j++;  j++;  j++;  j++;  j++;}

normalLoop() unrolledLoop()

0.023s 0.010s

0.003s 0.001s

0.032s 0.015s

0.005s 0.001s

normalLoop() unrolledLoop()

0.023s 0.010s

0.003s 0.001s

0.032s 0.015s

0.005s 0.001s

normalLoop() unrolledLoop()

0.023s 0.010s

0.003s 0.001s

0.032s 0.015s

0.005s 0.001s

normalLoop() unrolledLoop()

0.023s 0.010s

0.003s 0.001s

0.032s 0.015s

0.005s 0.001s

normalLoop() unrolledLoop()

0.023s 0.010s

0.003s 0.001s

0.032s 0.015s

0.005s 0.001s

#4 cache globals

function  uncached(){    var  i  =  10000;    while(i-­‐-­‐)  window.test  =  'test';}

function  cached(){    var  w  =  window,  i  =  10000;    while(i-­‐-­‐)  w.test  =  'test';}

uncached cached

1.440s 0.825s

0.07s 0.07s

2.22s 2.19s

0.48s 0.16s

uncached cached

1.440s 0.825s

0.07s 0.07s

2.22s 2.19s

0.48s 0.16s

uncached cached

1.440s 0.825s

0.07s 0.07s

2.22s 2.19s

0.48s 0.16s

uncached cached

1.440s 0.825s

0.07s 0.07s

2.22s 2.19s

0.48s 0.16s

uncached cached

1.440s 0.825s

0.07s 0.07s

2.22s 2.19s

0.48s 0.16s

uncached cached

1.440s 0.825s

0.07s 0.07s

2.22s 2.19s

0.48s 0.16s

Safari is 20x fasterthan Firefox

uncached cached

1.440s 0.825s

0.07s 0.07s

2.22s 2.19s

0.48s 0.16s

Now IE works with >1s durations. WTF?

#5 expression tuning

var  b  =  false,  n  =  99;

function(){    return  n*n  &&  b;}

function(){    return  b  &&  n*n;}

var  b  =  false,  n  =  99;

function(){    return  n*n  &&  b;}

function(){    return  b  &&  n*n;} b is false,

so n*n doesn’t needto get evaluated

not  tuned tuned

0.005s 0.004s

0.011s 0.010s

0.906s 0.391s

0.037s 0.021s

not  tuned tuned

0.005s 0.004s

0.011s 0.010s

0.906s 0.391s

0.037s 0.021s

not  tuned tuned

0.005s 0.004s

0.011s 0.010s

0.906s 0.391s

0.037s 0.021s

not  tuned tuned

0.005s 0.004s

0.011s 0.010s

0.906s 0.391s

0.037s 0.021s

not  tuned tuned

0.005s 0.004s

0.011s 0.010s

0.906s 0.391s

0.037s 0.021s

>>>  var  n  =  1;undefined>>>  if(true  &&  (n=2))  ...;>>>  n2>>>  if(true  ||  (n=3))  ...;>>>  n2

not a pure engine optimization,the execution actually stops

here, n=2 needs to be evaluated, so n is set to 2

here it doesn’t (expression must be true), so n is

NOT set to 3

#6what not to use

function(){    var  obj  =  {  prop:  'test',  str:  ''  };    with(obj){          var  i  =  10000;        while(i-­‐-­‐)  str  +=  prop;        return  str;    }}

function(){    var  obj  =  {  prop:  'test',  str:  ''  },  i  =  10000;    while(i-­‐-­‐)  obj.str  +=  obj.prop;    return  obj.str;}

with(obj){  p  } obj.p

0.071s 0.012s

0.039s 0.028s

0.078s 0.078s

0.077s 0.006s

with(obj){  p  } obj.p

0.071s 0.012s

0.039s 0.028s

0.078s 0.078s

0.077s 0.006s

with(obj){  p  } obj.p

0.071s 0.012s

0.039s 0.028s

0.078s 0.078s

0.077s 0.006s

with(obj){  p  } obj.p

0.071s 0.012s

0.039s 0.028s

0.078s 0.078s

0.077s 0.006s

with(obj){  p  } obj.p

0.071s 0.012s

0.039s 0.028s

0.078s 0.078s

0.077s 0.006s

var  a  =  0;

function(){    try{        a  +=  1;    }  catch(e)  {}}

function(){    a  +=  1;}

try/catch no  try/catch

0.006s 0.005s

0.287s 0.011s

0.460s 0.460s

0.123s 0.012s

try/catch no  try/catch

0.006s 0.005s

0.287s 0.011s

0.460s 0.460s

0.123s 0.012s

try/catch no  try/catch

0.006s 0.005s

0.287s 0.011s

0.460s 0.460s

0.123s 0.012s

try/catch no  try/catch

0.006s 0.005s

0.287s 0.011s

0.460s 0.460s

0.123s 0.012s

try/catch no  try/catch

0.006s 0.005s

0.287s 0.011s

0.460s 0.460s

0.123s 0.012s

Firefox 3.5

Safari 4.0

Chrome 3

IE 8

0 0,1 0,2 0,3 0,4 0,5

no try/catch try/catch

Firefox 3.5

Safari 4.0

Chrome 3

IE 8

0 0,1 0,2 0,3 0,4 0,5

no try/catch try/catch

Firefox 3.5

Safari 4.0

Chrome 3

IE 8

0 0,1 0,2 0,3 0,4 0,5

no try/catch try/catch

Firefox 3.5

Safari 4.0

Chrome 3

IE 8

0 0,1 0,2 0,3 0,4 0,5

no try/catch try/catch

Firefox 3.5

Safari 4.0

Chrome 3

IE 8

0 0,1 0,2 0,3 0,4 0,5

no try/catch try/catch

Modern JavaScript engines have JIT

compilers, which don’t support certain

features well

Avoid stuffthat’s not

available inECMA-2625th Edition

“strict” mode,see John’s blog

post

Avoid stuffthat’s not

available inECMA-2625th Edition

“strict” mode,see John’s blog

post

http://tr.im/ecma262

alert((function(){return"alert(("+arguments.callee.toString().replace(/\s/g,"")+")());";})());

alert((function(){return"alert(("+arguments.callee.toString().replace(/\s/g,"")+")());";})());

(function(){  return  2  *  3;  }).toString();

function  ()  {  return  2  *  3;  }

function  ()  {  return  2  *  3;  }

function  ()  {  return  2  *  3;  }

function  ()  {  return  2  *  3;  }

function  ()  {  return  2  *  3;  }

function  ()  {  return  2  *  3;  }

function  ()  {  return  2  *  3;  }

function  ()  {  return  2  *  3;  }

function  ()  {  return  2  *  3;  }

function  ()  {  return  6;  }

function  ()  {  return  2  *  3;  }

function  ()  {  return  2  *  3;  }

function  ()  {  return  2  *  3;  }

function  ()  {  return  6;  } WTF?

More inhttp://jsrocks.com

More inhttp://jsrocks.com

DO NOT, EVER,OPTIMIZE

PREMATURELY

Q&AAnd thanks!

http://javascriptrocks.com/@thomasfuchs on twitter