Understanding V8
Vyacheslav Egorov
Vyacheslav Egorov
| data length | \u0000 | data bytes |
| 1 | 1 | \u0000 | n | o | d | e | c | a | m | p | . | e | u |
Parser.prototype.parse = function (s) {
var l = '';
for (var i = 0; i < s.length; i++) {
if (s[i] == '\u0000') {
l = Number(l);
this.emit('data', s.substr(i + 1, l));
return this.parse(s.substr(i + 1 + l));
} else {
l += s[i];
}
}
return s;
};
function makeFakePacket() {
var l = randomBetween(MIN_PACKET_LENGTH,
MAX_PACKET_LENGTH);
var p = l + '\u0000';
for (var i = 0; i < l; ++i) p += ' ';
return p;
}
var fakeInput = '';
for (var i = 0; i < NOF_PACKETS; i++) {
fakeInput += makeFakePacket();
}
var p = new Parser();
var start = Date.now();
for (var j = 0; j < NOF_RUNS; j++) {
p.parse(fakeInput);
}
var end = Date.now();
var timeSpent = end - start;
var totalBytes = fakeInput.length * NOF_RUNS;
console.log(timeSpent + ' ms');
console.log(totalBytes/timeSpent + ' bytes/ms');
var MIN_PACKET_LENGTH = 10; var MAX_PACKET_LENGTH = 100; var NOF_PACKETS = 1000; var NOF_RUNS = 10;
% node parser.js 806 ms 711.4267990074442 bytes/ms
% node --prof parser.js
806 ms
711.4267990074442 bytes/ms
Builtin sampling profiler
% node --prof parser.js
806 ms
711.4267990074442 bytes/ms
% deps/v8/tools/mac-tick-processor
[GC]:
ticks total nonlib name
576 79.0%
GC cost is proportional to the number of long lived objects
Parser.prototype.parse = function (s) {
var l = '';
for (var i = 0; i < s.length; i++) {
if (s[i] == '\u0000') {
l = Number(l);
this.emit('data', s.substr(i + 1, l));
return this.parse(s.substr(i + 1 + l));
} else {
l += s[i];
}
}
return s;
};
Parser.prototype.parse = function (s) {
var l = '';
for (var i = 0; i < s.length; i++) {
if (s[i] == '\u0000') {
l = Number(l);
this.emit('data', s.substr(i + 1, l)); s = s.substr(i + 1 + l);
i = 0;
l = ''; } else {
l += s[i];
}
}
return s;
};
% node --prof parser.js
183 ms
3133.3879781420765 bytes/ms
% deps/v8/tools/mac-tick-processor
[JavaScript]:
ticks total nonlib name
124 64.2% 87.3% Stub: SubString
[GC]:
ticks total nonlib name
8 4.1%
c = a + b
Don't mix indexing and concatenation
while (smth) {
s = s + s.substr(x, y);
}
Use arrays instead.
Substring cost is proportional to it's length
Parser.prototype.parse = function (s) {
var l = '';
for (var i = 0; i < s.length; i++) {
if (s[i] == '\u0000') {
l = Number(l);
this.emit('data', s.substr(i + 1, l)); s = s.substr(i + 1 + l);
i = 0; l = '';
} else {
l += s[i];
}
}
return s;
};
Parser.prototype.parse = function (s) {
var l = '', j = 0;
for (var i = 0; i < s.length; i++) {
if (s[i] == '\u0000') {
l = Number(l);
this.emit('data', s.substr(i + 1, l)); i += l;
j = i + 1; l = '';
} else {
l += s[i];
}
} return s.substr(j);};
% node --prof parser.js
6 ms
95568.33333333333 bytes/ms
% deps/v8/tools/mac-tick-processor [JavaScript]: 4 9.8% 9.8% Stub: StringAdd
% node --prof parser.js
6 ms
95568.33333333333 bytes/ms
% deps/v8/tools/mac-tick-processor [JavaScript]: 4 9.8% 9.8% Stub: StringAdd
% node --prof parser.js
194 ms
295572.1649484536 bytes/ms
% deps/v8/tools/mac-tick-processor [JavaScript]:47 20.4% 20.4% LazyCompile: *Parser.parse33 14.3% 14.3% Stub: SubString 21 9.1% 9.1% LazyCompile: *substr native 14 6.1% 6.1% LazyCompile: ~ToNumber native 14 6.1% 6.1% LazyCompile: b native 12 5.2% 5.2% Stub: StringAdd
Parser.parse
String.substr
makeFakePacket
randomBetween
Parser.parse
String.substr
makeFakePacket
randomBetween
*Parser.parse
*String.substr
makeFakePacket
randomBetween
--trace-opt
log names of optimized functions to stdout
Not all constructs are supported by optimizing compiler
--trace-bailout
log optimizing compiler bailouts
Optimizations are:
--trace-deopt
log deoptimizations
% node --prof parser.js
194 ms
295572.1649484536 bytes/ms
% deps/v8/tools/mac-tick-processor [JavaScript]: 47 20.4% 20.4% LazyCompile: *Parser.parse 33 14.3% 14.3% Stub: SubString 21 9.1% 9.1% LazyCompile: *substr native 14 6.1% 6.1% LazyCompile: ~ToNumber native 14 6.1% 6.1% LazyCompile: b native12 5.2% 5.2% Stub: StringAdd
Parser.prototype.parse = function (s) {
var l = '', j = 0;
for (var i = 0; i < s.length; i++) {
if (s[i] == '\u0000') { l = Number(l); this.emit('data', s.substr(i + 1, l));
i += l;
j = i + 1;
l = '';
} else { l += s[i]; }
}
return s.substr(j);
};
Parser.prototype.parse = function (s) { var l = 0, j = 0, ch0 = "0".charCodeAt(0); for (var i = 0; i < s.length; i++) { var ch = s.charCodeAt(i);
if (ch === 0) { this.emit('data', s.substr(i + 1, l));
i += l;
j = i + 1; l = 0; } else { l = l * 10 + (ch - ch0); }
}
return s.substr(j);
};
% node parser.js 125 ms 458728 bytes/ms
% node parser.js 806 ms 711.4267990074442 bytes/ms


Use WebGL typed arrays
Float32Array
Float64Array
|
function Point(x, y) {
|
|
function Point(x, y) {
this.x = x;
|
|
function Point(x, y) {
this.x = x;
this.y = y;
|
|
|
function Point(x, y) {
|
|
function Point(x, y) {
this.x = x;
|
|
function Point(x, y) {
this.x = x;
this.y = y;
|
|
function Point(x, y) {
this.x = x;
this.y = y;
}
var p1 = new Point(11, 22);
var p2 = new Point(33, 44);
p2.z = 55;
|
|
v = obj.x
v = Runtime_GetProperty(obj, 'x');
function Runtime_GetProperty(obj, f) {
var clazz = HiddenClass(obj);
return obj[clazz.IndexOfField(f)];
}
v = obj.x
if (HiddenClass(obj) == cache.clazz) {
v = obj[cache.index];
} else {
v = Runtime_LoadCache_Miss(cache, obj, 'x');
}
function Runtime_LoadCache_Miss(cache, obj, f) {
var clazz = HiddenClass(obj);
var index = clazz.IndexOfField(f);
cache.clazz = clazz;
cache.index = index;
return obj[index];
}
Monomorphic sites are better than polymorphic
delete obj.prop
Object.seal(obj)
Object.freeze(obj)
obj.__defineGetter__(...)
obj.__defineSetter__(...)
Object.defineProperty(obj, ...)
obj = { get prop () { }, set prop() { } }
arguments objectarguments.length arguments[i] f.apply(obj, arguments)
function f() {
var v1; // real local variable
var v2; // context allocated
var v3; // context allocated
function g() { use(v2); }
function h() { use(v3); }
}
Contexts are created eagerly
function foo(arg1, arg2, arg3) {
/* V8 allocates context, copies arg2 to it */
if (almostAlwaysFalse()) {
return function () { return arg2; }
}
/* Context is not used */
}
Avoid global eval
Function constructorAvoid with
try {} catch (e) {} for nowAvoid const
Thank you!
Questions?