JavaScript for Modern Engines Amanda Silver JohnDavid Dalton JavaScript Team Dev 4000 fast and fluid The best apps are The Reach of JavaScript is expanding Web Applications HTML5 Games ID: 495994
Download Presentation The PPT/PDF document "High-Performing" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
High-Performing JavaScript for Modern Engines
Amanda Silver, John-David Dalton
JavaScript Team
Dev
4-000Slide2
fast and fluid.
The best apps are…Slide3
The Reach of JavaScript is expanding
Web Applications
HTML5 Games
Windows 8 HTML Apps
Basic Web Pages
JavaScript Execution Speed
DOM Interactions
Accelerated Graphics
Page Load TimeSlide4
WebKit’s JavaScript benchmarkSlide5
Measuring JavaScript performance
JavaScript Execution Performance
Performance of Other
Browser SubsystemsSlide6
HTML5 gamesStress Multiple Browser Subsystems
Bubbles
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;
this.elem.style.left = this
.x + "px";
this
.elem.style.top
=
this
.y
+
"
px
"
;
this
.canvas.getContext
(
"2d")
.
putImageData
(
canvasImageData
, 0, 0);Slide7
Bubbles overviewSlide8
JavaScript in ContextIs Javascript your Bottleneck?Slide9
Is JavaScript the bottleneck?
Networking
HTML
CSS
Collections
JavaScript
Marshalling
DOM
Formatting
Block Building
Layout
Rendering
Is JavaScript your bottleneck?Slide10
Is JavaScript the bottleneck?
Chakra
Your Code
Other SubsystemsSlide11
Do use a good profilerSlide12
Benchmarking with jsPerfSlide13
Do use jsPerf to write micro-benchmarks
Function
declarations go in
preparation
code
or
setupInclude only the bare minimum in each test bodyReset reused shared variables
Don’t introduce randomness in your testDon’t test asynchronous things synchronouslyKnow preparation,
setup, and teardown stagesSlide14
demoEfficient animationSlide15
Don’t do useless work
setInterval
(draw,
0
);
setTimeout
(draw,
0
);requestAnimationFrame(draw);setTimeout
(draw, 1000 / 60);Slide16
Do avoid chattiness with the DOM
JavaScript
DOM
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";}Slide17
demoDOM interactionSlide18
Do check types of values from DOM
this
.nOfBubbles
=
document.getElementById
(“
dropDown
").value;
30%of rendering time in string conversionSlow Operations 11%Value Conversions 18%
GC 17%Your Code 45%Slide19
Don’t
use
a
utomatic
t
ype
c
onversions
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
=
document.getElementById
(“
dropDown
").value;
this
.nOfBubbles
=
parseInt
(
document.getElementById
(
“
dropDown
"
).value);
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]); } }}“128”128Slide20
Do
parse
n
umbers from strings
this
.nOfBubbles
=
parseInt
(document.getElementById(“dropDown").value);GC 28%
Your Code 64%Slide21
JavaScript: Flexibility or performance
Flexibility
Performance
“Think C++”
“Think Script”
Simple Websites
Complex Apps, Games
var
r = 3 * "10"; // r == 300var a = new Array();a.push(10);var p = {x: 0, y: 0};p.z = 5;
p["some text"] = 1;p[1] = 2;eval("var s = p[1] * a[0]"); // s == 20var r = 3 * parseInt("10"); var a = new Array(100);a[0] = 10;
var p = new Point(0, 0, 0);p.z
= 5;Slide22
Lifecycle of your JavaScript code
Core #1
Foreground
Interpreter
Byte Code
AST
Parser
Source Code
Core #2
BackgroundNative Code
Background CompilerSlide23
Create fast objectsSlide24
demoFast property accessSlide25
Fast property access
if
(b1.bubbleBounceCounter >= 10) {
delete
b1.bubbleBounceCounter;
}
Slow Property Access 41%
if
(b1.bubbleBounceCounter >= 10) { b1.bubbleBounceCounter = 0;}Slide26
Objects in JavaScript
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; // x == 10delete base.x;var u =
b.x; // u == undefinedproperty bags, no classesadd properties on the flyclass-like patternprototypal inheritance
even remove properties
enumerate propertiesuse as dictionaries
but still just property bags
Flexibility
Performance
Use Property Bags
Think: “Objects and Classes”Slide27
b1.type
b2.type
Bubble
“x”
“y”
y
Bubble
“x”
x
Bubble
10
11
10
b2
0
1
0
b1
function
Bubble(x, y) {
this
.x
= x;
this
.y
= y;
}
var
b1 =
new
Bubble(0, 1);
var
b2 =
new
Bubble(10, 11);
Internal fast
t
ype
s
ystemSlide28
b1.type
b2.type
Bubble
“x”
“y”
“c”
c
Bubble
“x”
“y”
y
Bubble
“x”
x
Bubble
10
11
“red”
10
11
b2
0
1
b1
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"
;
Internal fast
t
ype
s
ystemSlide29
Do add all properties
in c
onstructor
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-bagSlide30
Don’t delete properties
Avoid
slow
p
roperty
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})Slide31
Do use identifiers
for
property
n
ames
Avoid slow property b
ags
function Point() { this.x = 0;
this.y = 0;}var p1 = new Point();p1["some text"] = 1;
b1.type = fast-type({x,y})non-identifier properties?b1.type = slow-property-bagSlide32
Don’t use getters & s
etters
e
xcessively
Avoid
slow property b
agsfunction
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-bagSlide33
Don’t add properties c
onditionally
Avoid Fast Type Mismatches
function
Color(alpha) {
this.r = 0;
this.g = 0; this
.b = 0; if (alpha) { this.a = 0; }}var c1 = new Color(true);var c2 = new Color(false);
c1.type = {r,g,b,a}c2.type = {r,g,b
}Slide34
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;
Don’t default properties on prototypes
Avoid Fast Type MismatchesSlide35
Property access works in C++ or C#
class
Bubble
{
public int
x; public int y;
}class Program { static void Reset(Bubble b) { b.x = 0; b.y = 0; }}
mov edx, 0mov eax, [p]mov [p+4],
edxSlide36
Fast property access in JavaScript
function
Bubble(x, y) {
this
.x
= x; this
.y = y;}function
Bubble.prototype.reset() { this.x = 0; this.y = 0;}
mov eax, 0x00000001mov ebx
, [this]
mov ecx
, [this.type]cmp
ecx, [
ic.type
]
jne
$
callSetProperty
mov
ecx
, [
this.propArray
]
mov
edx
, [
ic.index
]
mov
[
p.propArray
[
ic.index
]
],
eax
// 100s of assembly instructions
engine.LookUpProperty
(this, x)
engine.SetProperty
(this, x, 0)
inline cache
type
prop indexSlide37
function
Bubble(x, y) {...}
function
Bubble.prototype.reset
() {
this.x = 0; this
.y = 0;}var b1 =
new Bubble(0, 1);var b2 = new Bubble(10, 11);for (var i = 0; i < 1000; i++) { bubbles[i].reset();}Fast property access works
For objects of matching fast types
inline cache
0
0
mov
eax
, 0x00000001
mov
ebx
, [this]
mov
ecx
, [
this.type
]
cmp
ecx
, [
ic.type
]
jne
$
callSlowSetProperty
mov
ecx
, [
this.propArray
]
mov
edx
, [
ic.index
]
mov
[
p.propArray
[ic.index]], eax
b1.type = “{x,y}”
b2.type = “{x,y}”b1.type = “{x,y}”
b2.type = “{x,y}”“{x, y}”1Slide38
function
Bubble(x, y) {...}
function
Bubble.prototype.reset
() {
this.x = 0; this
.y = 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();}
Fast property access failsFor objects of mismatched fast types or property bags
inline cache
0
0
mov
eax
, 0x00000001
mov
ebx
, [
this
]
mov
ecx
, [
this.type
]
cmp
ecx
, [
ic.type
]
jne
$
callSlowSetProperty
mov
ecx
, [
this.propArray
]
mov
edx
, [
ic.index
]
mov
[p.propArray[ic.index]], eax
b1.type = “{
x,y}”b2.type = “{x,y,c}”
b1.type = “{x,y}”b2.type = “{x,y,c}”“{x, y}”
1
“{x, y, c}”Slide39
Do write fast objects
Add all properties in constructor
Don’t delete properties
Use identifiers for property names
Use getters and setters sparingly
Avoid conditionally adding propertiesAvoid default property values on prototype objectsSlide40
JavaScript ArithmeticSlide41
What is causing garbage collection?
Bubble.prototype.move
=
function
(
elapsedTime
) { this
.x += this
.vx * elapsedTime / model.animationFrameDuration; this.y += this.vy * elapsedTime / model.animationFrameDuration;}
Garbage Collection25%Slide42
JavaScript arithmetic is very permissiveExtreme
f
lexibility
+ …
function
doMath(a, b, c, d) {
return a * b + c * d;}var
a = 3;var b = "10";var c = new Date();var d = {valueOf: function() { return 5; }}var r = doMath(a, b, c, d);
r == 6640403003390Flexible? YesFast? NoSlide43
JavaScript values are dynamically typedExtreme
f
lexibility
+
dynamic typing
= …var
a = 3;a = 2.5;a = "text";
a = { x: 0, y: 1};a = new Date();var b = getSomeValue();var c = someObject.c;function doSomething(a, b, c) { global.r = a + b + c;}a
b
c
Number
3
Object
0
1
Number
2.5
String
“text”
Date
…
heap
stackSlide44
Generic JavaScript arithmetic is slowExtreme
f
lexibility
+
dynamic typing =
slow & complex algorithm
return a + b + c;
av = getValueFromHeap(a)bv = getValueFromHeap(b)at = getType
(a)bt = getType(b)op = selectOperation(at, bt)
rv1 = op(
av, bv)
r1 =
boxOnHeap(rv1)
r1 =
doPlus
(a, b)
r2 =
doPlus
(r1, c)
return r2Slide45
Do use integer math to avoid
b
oxing
var
a = 3;
var
b = "text";var
c = 2.5;var d = 0x80000000;function
doSomething(a, b, c, d) { global.r = a + b + c + d;}doSomething(a, b, c, d);stack0x00000007a:0x005e4148
b:0x005e4160c:String“text”
Number
2.5
Number
0x80000000
0x005e4170
d:
Number
3
heap
0x005e4148: 0…01001
000
0x07 represents 3: 0…0000011
1Slide46
Do use floating p
oint
m
ath
j
udiciously
var a = 5;var b = 2;var
r = ((a + b) / 2) | 0; // r = 3var r =
Math.round((a + b) / 2); // r = 4var a = 5;var b = 2;var r = (a + b) / 2); // r = 3.5stack0x005e4148r:
0x00000007r:0x00000009r:Number
3.5
heapSlide47
Type-specialized code generation
Generic
Machine Code
Chakra
Helper Code
Type Specialized
Machine Code
Chakra
InterpreterSlide48
Type specialized functions are f
ast
But
r
equire 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 -= delta_vx; b1.vy -= delta_vy;
b2.vx += delta_vx; b2.vy += delta_vy
;}stack
0.10
d2
2.49
mag
0.05
delta_vx
0.25
delta_vy
registers
2.70
eax
(dx)
10.50
1.00
0.55
ebx
(
dy
)
ecx
(
dvx
)
edx
(
dvy
)Slide49
Do use arguments of
consistent
t
ypes
function
(b1, b2) {
(...) var dx = b1.x - b2.x;
var dy = b1.y - b2.y; ...
var d2 = dx * dx + dy * dy; ...}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
eax, dxMOV ebx
, dy
MUL eax, eax
MUL
ebx
,
ebx
ADD
eax
,
ebx
// d2 in
eax
now
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;
...Slide50
Do use fast type-specialized arithmetic
Be
aware of number
boxing
Avoid unnecessary floating point math
Enable type-specializing JIT compilersSlide51
JavaScript ArraysSlide52
Number boxing in JavaScript arrays
this
.gaussianMask
=
new
Array
(
maskSize * maskSize);this.occlusionMask = new Array(canvasWidth * canvasHeight);Garbage Collection90% of 1 CPU
this.gaussianMask = new Float64Array(maskSize * maskSize);this.occlusionMask = new Float64Array(canvasWidth *
canvasHeight);Slide53
DemoTyped arrays and boxingSlide54
Do take advantage of typed arrays
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] == 0var 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] == 0flexibilityperformanceSlide55
Don’t use objects as arraysOr
vice
v
ersa
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;}
convenienceperformanceSlide56
Do pre-allocate arrays
var
a =
new
Array(100);
for
(var i = 0; i < 100; i++) { a[
i] = i + 2;}
var a = new Array();for (var i = 0; i < 100; i++) { a.push(i + 2);}convenience
performance
0
?
?+1
??
…
0
100Slide57
Do enumerate arrays efficiently
var
a =
new
Array(100);
var
total = 0;
for (var item in
a) { total += item;};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];}convenienceperformanceSlide58
Do use arrays efficiently
Don’t use objects as arrays and vice
versa
Pre-allocate on
creation
Enumerate efficiently
Use typed arrays to avoid float boxingSlide59
In-review: Write fast JavaScript
Use good performance tools
Identify and focus on your bottlenecks
Understand and target modern engines
Create fast objects
Write fast arithmeticUse arrays efficientlySlide60
Go forth and code it! 3-012: Introducing TypeScript: A language for application-scale JavaScript development
3-020: Building
apps for Office and SharePoint 2013 using the web technologies you know and
love
3-115: Intro to creating Windows Store apps using HTML and JavaScript
4-101: Deep dive into WinJS
3-008: Diagnosing perf and memory issues in JavaScript-based Windows Store apps3-014: Modern JavaScript3-018:
TouchDevelop: A touch-first IDE for the Web created with TypeScript3-041: Javascript from client to cloud with Windows 8, Node.js, and Windows Azure
3-130: Writing Windows Store apps with jQuery2-015: Windows Phone 8: HTML5/IE10 for Developers jsperf.com blogs.msdn.com/b/ie/ Slide61