extreme javascript performance
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).TRANSCRIPT
Extreme JavaScript
Performance
Thomas Fuchs@thomasfuchs
DO NOT, EVER,OPTIMIZE
PREMATURELY
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?
DO NOT, EVER,OPTIMIZE
PREMATURELY
Q&AAnd thanks!
http://javascriptrocks.com/@thomasfuchs on twitter