Document

Basic Web Pages
Page Load Time
Web Applications
HTML5 Games
Windows 8 HTML Apps
JavaScript Execution Speed
DOM Interactions
Accelerated Graphics
Stress Multiple Browser Subsystems
setInterval(animate, 1000/60)
bs[i] = new Bubble(0, 1);
for (var i = 0; i < 1000; i++) {
bs[i].move();
for (var j = 0; j < i + 1; j++) {
Bubbles.collide(bs[i], bs[j]);
}
}
var distance2 = (b1.x–b2.x)*(b1.x–b2.x)+(b1.x–b2.x)*(b1.x–b2.x);
var magnitude = (dvx * dx + dvy * dy) / d2;
Bubbles
this.elem.style.left = this.x + "px";
this.elem.style.top = this.y + "px";
this.canvas.getContext("2d").putImageData(canvasImageData, 0, 0);
Is JavaScript your bottleneck?
Rendering
Layout
Block Building
Formatting
DOM
Marshalling
JavaScript
Collections
CSS
HTML
Networking
Chakra
Your Code
Other Subsystems
requestAnimationFrame(draw);
setInterval(draw,
0);
setTimeout(draw, 1000
0); / 60);
for (var i = 0; i < this.nOfBubbles; i++) {
document.body.box.getElementById("ball0").style.left = b.x + "px";
document.body.box.getElementById("ball0").style.top = b.y + "px";
}
JavaScript
DOM
this.nOfBubbles = document.getElementById(“dropDown").value;
Slow Operations
11%
Value Conversions
18%
GC 17%
Your Code 45%
30%
of rendering time in string conversion
this.nOfBubbles
this.nOfBubbles
= parseInt(document.getElementById(“dropDown").value);
= document.getElementById(“dropDown").value;
“128”
128
BubbleTest.prototype.moveBubbles = function() {
for (var i = 0; i < this.nOfBubbles; i++) {
this.bubbles[i].move();
}
for (var i = 0; i < this.nOfBubbles; i++) {
for (var j = i + 1; j < this.nOfBubbles; j++) {
Bubble.prototype.collide(this.bubbles[i], this.bubbles[j]);
}
}
}
this.nOfBubbles = parseInt(document.getElementById(“dropDown").value);
Your Code 64%
GC 28%
var r = 3 * "10";
// r == 300
var r = 3 * parseInt("10");
var a = new Array();
a.push(10);
var a = new Array(100);
a[0] = 10;
var p = {x: 0, y: 0};
p.z = 5;
p["some text"] = 1;
p[1] = 2;
eval("var s = p[1] * a[0]");
var p = new Point(0, 0, 0);
p.z = 5;
Simple Websites
Flexibility
“Think Script”
// s == 20
Complex Apps, Games
Performance
“Think C++”
Core #1
Foreground
Core #2
Background
Source Code
Parser
AST
Byte Code
Interpreter
Background
Compiler
Native Code
if (b1.bubbleBounceCounter >= 10) {
delete b1.bubbleBounceCounter;
b1.bubbleBounceCounter
= 0;
}
Slow Property Access
41%
var base = { color: "red" };
base.x = 10;
base["any string"] = 0;
for (var p in base) {...}
function Bubble() {...}
Bubble.prototype = base;
var b = new Bubble();
var c = b.color; // c == "red“
b.y = 20;
var x = b.x;
delete base.x;
var u = b.x;
// x == 10
// u == undefined
property bags, no classes
add properties on the fly
use as dictionaries
enumerate properties
class-like pattern
prototypal inheritance
but still just property bags
even remove properties
function
this.x
this.y
}
var b1 =
var b2 =
Bubble(x, y) {
= x;
= y;
new Bubble(0, 1);
new Bubble(10, 11);
Bubble
b1
Bubble
0
“x”
1
b2
Bubble
“x”
“y”
b1.type
b2.type
10
11
function Bubble(x, y) {
this.x = x;
this.y = y;
}
var b1 = new Bubble(0, 1);
var b2 = new Bubble(10, 11);
b2.c = "red";
Bubble
b1
Bubble
0
“x”
1
b2
Bubble
“x”
“y”
b1.type
b2.type
10
11
“red”
Bubble
“x”
“y”
“c”
Avoid slow property bags
function Point() {
this.x = 0;
this.y = 0;
}
var p1 = new Point();
p1.prop01 = 1;
...
p1.prop99 = 99;
b1.type =
fast-type({x,y})
too many properties?
b1.type =
slow-property-bag
Avoid slow property bags
function Point() {
this.x = 0;
this.y = 0;
}
var p1 = new Point();
delete p1.y;
b1.y = undefined;
b1.type =
fast-type({x,y})
deleting properties?
b1.type =
slow-property-bag
b1.type ==
fast-type({x,y})
Avoid slow property bags
function Point() {
this.x = 0;
this.y = 0;
}
b1.type =
fast-type({x,y})
var p1 = new Point();
p1["some text"] = 1;
non-identifier properties?
b1.type =
slow-property-bag
Avoid slow property bags
function Bubble(x, y) {
Object.defineProperty(this, "x", {
get : function() { return x; },
set : function(value) { x = value; },
});
Object.defineProperty(this, "y", {
get : function() { return y; },
set : function(value) { y = value; },
});
}
var b = new Bubble(0, 1);
var x = b.x;
b.y = 5;
getters & setters?
b.type =
slow-property-bag
Avoid Fast Type Mismatches
function Color(alpha) {
this.r = 0;
this.g = 0;
this.b = 0;
if (alpha) {
this.a = 0;
}
}
c1.type = {r,g,b,a}
c2.type = {r,g,b}
var c1 = new Color(true);
var c2 = new Color(false);
Avoid Fast Type Mismatches
function TreeNode(key, value) {
this.key = key;
this.value = value;
};
TreeNode.prototype.left = null;
TreeNode.prototype.right = null;
var t1 = new TreeNode("k1", "v1");
var t2 = new TreeNode("k2", "v2");
var t3 = new TreeNode("k3", "v3");
t1.left = t2;
t2.right = t3;
class Bubble {
public int x;
public int y;
}
class Program {
static void Reset(Bubble b) {
b.x = 0;
b.y = 0;
}
}
mov
edx, 0
mov
eax, [p]
mov
[p+4], edx
function Bubble(x, y) {
this.x = x;
this.y = y;
}
inline cache
function Bubble.prototype.reset() {
this.x = 0;
this.y = 0;
}
mov
eax, 0x00000001
// 100s of assembly instructions
mov
ebx, [this]
engine.LookUpProperty(this, x)
mov
ecx, [this.type]
engine.SetProperty(this, x, 0)
cmp
ecx, [ic.type]
jne
$callSetProperty
mov
ecx, [this.propArray]
mov
edx, [ic.index]
mov
[p.propArray[ic.index]], eax
For objects of matching fast types
inline cache
function
function
this.x
this.y
}
Bubble(x, y) {...}
Bubble.prototype.reset() {
= 0;
= 0;
var b1 = new Bubble(0, 1);
var b2 = new Bubble(10, 11);
for (var i = 0; i < 1000; i++) {
bubbles[i].reset();
}
mov
mov
mov
cmp
jne
mov
mov
mov
b1.type = “{x,y}”
b2.type = “{x,y}”
eax, 0x00000001
ebx, [this]
ecx, [this.type]
ecx, [ic.type]
$callSlowSetProperty
ecx, [this.propArray]
edx, [ic.index]
[p.propArray[ic.index]], eax
For objects of mismatched fast types or property bags
inline cache
function
function
this.x
this.y
}
Bubble(x, y) {...}
Bubble.prototype.reset() {
= 0;
= 0;
var b1 = new Bubble(0, 1);
var b2 = new Bubble(10, 11);
b2.c = "red";
for (var i = 0; i < 1000; i++) {
bubbles[i].reset();
}
mov
mov
mov
cmp
jne
mov
mov
mov
b1.type = “{x,y}”
b2.type = “{x,y,c}”
eax, 0x00000001
ebx, [this]
ecx, [this.type]
ecx, [ic.type]
$callSlowSetProperty
ecx, [this.propArray]
edx, [ic.index]
[p.propArray[ic.index]], eax
Bubble.prototype.move = function(elapsedTime) {
this.x += this.vx * elapsedTime / model.animationFrameDuration;
this.y += this.vy * elapsedTime / model.animationFrameDuration;
}
Garbage Collection
25%
Extreme flexibility + …
function doMath(a, b, c, d) {
return a * b + c * d;
}
var
var
var
var
a
b
c
d
=
=
=
=
3;
"10";
new Date();
{valueOf: function() { return 5; }}
var r = doMath(a, b, c, d);
Flexible? Yes
Fast? No
r == 6640403003390
Extreme flexibility + dynamic typing = …
var
a =
a =
a =
a =
var
var
a = 3;
2.5;
"text";
{ x: 0, y: 1};
new Date();
b = getSomeValue();
c = someObject.c;
function doSomething(a, b, c) {
global.r = a + b + c;
}
heap
Number
3
Number
stack
2.5
a
String
b
“text”
c
Object
0
1
Date
…
Extreme flexibility + dynamic typing = slow & complex algorithm
return a + b + c;
at = getType(a)
bt = getType(b)
r1 = doPlus(a, b)
av = getValueFromHeap(a)
r2 = doPlus(r1, c)
bv = getValueFromHeap(b)
return r2
op = selectOperation(at, bt)
rv1 = op(av, bv)
r1 = boxOnHeap(rv1)
heap
var
var
var
var
a
b
c
d
=
=
=
=
3;
"text";
2.5;
0x80000000;
function doSomething(a, b, c, d) {
global.r = a + b + c + d;
}
Number
stack
3
a:
0x00000007
String
b:
0x005e4148
“text”
c:
0x005e4160
d:
0x005e4170
Number
2.5
doSomething(a, b, c, d);
Number
0x005e4148:
0x07 represents 3:
0…01001000
0…00000111
0x80000000
var a = 5;
var b = 2;
var r = (a + b) / 2);
stack
r:
0x005e4148
// r = 3.5
heap
Number
3.5
var
var
var
var
a
b
r
r
=
=
=
=
5;
2;
((a + b) / 2) | 0;
// r = 3
Math.round((a + b) / 2); // r = 4
r:
0x00000007
r:
0x00000009
Generic
Machine Code
Chakra
Helper Code
Chakra
Interpreter
But require consistent input arguments
function (b1, b2) {
var dx = b1.x - b2.x;
var dy = b1.y - b2.y;
var dvx = b1.vx - b2.vx;
var dvy = b1.vy - b2.vy;
var d2 = dx * dx + dy * dy;
var mag = (dvx * dx + dvy * dy) / d2;
var delta_vx = dx * mag;
var delta_vy = dy * mag;
b1.vx
b1.vy
b2.vx
b2.vy
}
-=
-=
+=
+=
delta_vx;
delta_vy;
delta_vx;
delta_vy;
registers
2.70
eax(dx)
10.50
1.00
0.55
ebx(dy)
ecx(dvx)
edx(dvy)
stack
0.10
d2
2.49
0.05
mag
delta_vx
0.25
delta_vy
function
(...)
var dx
var dy
...
var d2
...
}
(b1, b2) {
= b1.x - b2.x;
= b1.y - b2.y;
= dx * dx + dy * dy;
if (b1.type != Bubble) bail out;
if (b1.x.type != “float”) bail out;
if (b2.type != Bubble) bail out;
if (b2.x.type != “float”) bail out;
...
Bubble.prototype.collide(b1, b2);
for (var i = 0; i < nOfBubbles; i++) {
for (var j = i + 1; j < nOfBubbles; j++) {
Bubble.prototype.collide(bs[i], bs[j]);
}
}
MOV
MOV
MUL
MUL
ADD
eax,
ebx,
eax,
ebx,
eax,
dx
dy
eax
ebx
ebx
// d2 in eax now
this.gaussianMask = new Float64Array(maskSize
Array(maskSize * maskSize);
* maskSize);
this.occlusionMask = new Float64Array(canvasWidth
Array(canvasWidth * canvasHeight);
* canvasHeight);
Garbage Collection
90% of 1 CPU
performance
flexibility
var value = 5;
var a = new Array(100);
a[0] = value;
// a[0] == 5 (tagged)
a[1] = value / 2; // a[1] == 2.5 (boxed)
a[2] = "text";
// a[2] == "text"
var a = new Uint32Array(100);
a[0] = value;
// a[0] == 5 ("naked", no tagging required)
a[1] = value / 2; // a[1] == 2 ("naked", no tagging required)
a[2] = "text";
// a[2] == 0
var a = new Float64Array(100);
a[0] = value;
// a[0] == 5 ("naked", no tagging required)
a[1] = value / 2; // a[1] == 2.5 ("naked", no boxing required!)
a[2] = "text";
// a[2] == 0
convenience
performance
var b = new Bubble(0, 1);
for (var i = 0; i < 100; i++) {
b[i] = i + 2;
}
var a = new Array(100);
for (var i = 0; i < 100; i++) {
a[i] = i + 2;
}
convenience
performance
var a = new Array();
for (var i = 0; i < 100; i++) {
a.push(i + 2);
}
var a = new Array(100);
for (var i = 0; i < 100; i++) {
a[i] = i + 2;
}
0
?
?+1
0
??
…
100
convenience
var a = new Array(100);
var total = 0;
for (var item in a) {
total += item;
};
performance
a.forEach(function(item) { total += item; });
for (var i = 0; i < a.length; i++) {
total += a[i];
}
for (var i = 0, len = a.length; i < len; i++) {
total += a[i];
}
jsperf.com
blogs.msdn.com/b/ie/