refactor(benchmarks): add cloud reporter, add params

- adds console and cloud reporter (via Google BigQuery).
- makes parameters of tests explicit and modifiable.
- removes `detect` and `ignoreGc` mode from benchpress
  as these can result in unstable numbers.
This commit is contained in:
Tobias Bosch
2015-01-09 18:00:04 -08:00
parent af02f2beb1
commit d02c0accbb
53 changed files with 981 additions and 599 deletions

View File

@ -2,8 +2,19 @@
<html>
<body>
<h2>Params</h2>
<form>
Iterations:
<input type="number" name="iterations" placeholder="iterations" value="500000">
<br>
<button>Apply</button>
</form>
<h2>Actions</h2>
<p>
<button id="ng2DetectChanges">Ng2 detect changes</button>
<button id="baselineDetectChanges">baseline detect changes</button>
<button id="baselineDetectChanges">baselineDetectChanges</button>
</p>
$SCRIPTS$

View File

@ -1,7 +1,7 @@
import {ListWrapper, MapWrapper} from 'facade/collection';
import {reflector} from 'reflection/reflection';
import {isPresent} from 'facade/lang';
import {document, DOM} from 'facade/dom';
import {getIntParameter, bindAction} from 'e2e_test_lib/benchmark_util';
import {
Lexer,
@ -12,8 +12,6 @@ import {
} from 'change_detection/change_detection';
var ITERATIONS = 500000;
class Obj {
field0;
field1;
@ -77,7 +75,7 @@ function setUpReflector() {
});
}
function setUpBaseline() {
function setUpBaseline(iterations) {
function createRow(i) {
var obj = new Obj();
var index = i % 10;
@ -92,7 +90,7 @@ function setUpBaseline() {
var head = createRow(0);
var current = head;
for (var i = 1; i < ITERATIONS; i++) {
for (var i = 1; i < iterations; i++) {
var newRow = createRow(i);
current.next = newRow;
current = newRow;
@ -100,7 +98,7 @@ function setUpBaseline() {
return head;
}
function setUpChangeDetection() {
function setUpChangeDetection(iterations) {
var dispatcher = new DummyDispatcher();
var parser = new Parser(new Lexer());
@ -139,7 +137,7 @@ function setUpChangeDetection() {
proto(9)
];
for (var i = 0; i < ITERATIONS; ++i) {
for (var i = 0; i < iterations; ++i) {
var obj = new Obj();
var index = i % 10;
obj.setField(index, i);
@ -154,11 +152,13 @@ function setUpChangeDetection() {
}
export function main () {
setUpReflector();
var baselineHead = setUpBaseline();
var ng2ChangeDetector = setUpChangeDetection();
var iterations = getIntParameter('iterations');
function baselineDetectChanges(_) {
setUpReflector();
var baselineHead = setUpBaseline(iterations);
var ng2ChangeDetector = setUpChangeDetection(iterations);
function baselineDetectChanges() {
var current = baselineHead;
while (isPresent(current)) {
if (current.getter(current.obj) !== current.previousValue) {
@ -168,12 +168,12 @@ export function main () {
}
}
function ng2DetectChanges(_) {
function ng2DetectChanges() {
ng2ChangeDetector.detectChanges();
}
DOM.on(DOM.querySelector(document, '#ng2DetectChanges'), 'click', ng2DetectChanges);
DOM.on(DOM.querySelector(document, '#baselineDetectChanges'), 'click', baselineDetectChanges);
bindAction('#ng2DetectChanges', ng2DetectChanges);
bindAction('#baselineDetectChanges', baselineDetectChanges);
}

View File

@ -2,8 +2,19 @@
<html>
<body>
<button id="compileWithBindings">Compile template with bindings</button>
<button id="compileNoBindings">Compile template without bindings</button>
<h2>Params</h2>
<form>
Elements:
<input type="number" name="elements" placeholder="elements" value="150">
<br>
<button>Apply</button>
</form>
<h2>Actions</h2>
<p>
<button id="compileWithBindings">CompileWithBindings</button>
<button id="compileNoBindings">CompileNoBindings</button>
</p>
<template id="templateNoBindings">
<div class="class0 class1 class2 class3 class4 " nodir0="" attr0="value0" nodir1="" attr1="value1" nodir2="" attr2="value2" nodir3="" attr3="value3" nodir4="" attr4="value4">

View File

@ -13,8 +13,7 @@ import {Decorator} from 'core/annotations/annotations';
import {TemplateConfig} from 'core/annotations/template_config';
import {reflector} from 'reflection/reflection';
var COUNT = 30;
import {getIntParameter, bindAction} from 'e2e_test_lib/benchmark_util';
function setupReflector() {
reflector.registerType(BenchmarkComponent, {
@ -75,31 +74,33 @@ function setupReflector() {
}
export function main() {
var count = getIntParameter('elements');
setupReflector();
var reader = new DirectiveMetadataReader();
var cache = new CompilerCache();
var compiler = new Compiler(null, reader, new Parser(new Lexer()), cache);
var annotatedComponent = reader.read(BenchmarkComponent);
var templateNoBindings = loadTemplate('templateNoBindings', COUNT);
var templateWithBindings = loadTemplate('templateWithBindings', COUNT);
var templateNoBindings = loadTemplate('templateNoBindings', count);
var templateWithBindings = loadTemplate('templateWithBindings', count);
function compileNoBindings(_) {
function compileNoBindings() {
// Need to clone every time as the compiler might modify the template!
var cloned = DOM.clone(templateNoBindings);
cache.clear();
compiler.compileAllLoaded(null, annotatedComponent, cloned);
}
function compileWithBindings(_) {
function compileWithBindings() {
// Need to clone every time as the compiler might modify the template!
var cloned = DOM.clone(templateWithBindings);
cache.clear();
compiler.compileAllLoaded(null, annotatedComponent, cloned);
}
DOM.on(DOM.querySelector(document, '#compileNoBindings'), 'click', compileNoBindings);
DOM.on(DOM.querySelector(document, '#compileWithBindings'), 'click', compileWithBindings);
bindAction('#compileNoBindings', compileNoBindings);
bindAction('#compileWithBindings', compileWithBindings);
}
function loadTemplate(templateId, repeatCount) {

View File

@ -2,9 +2,20 @@
<html>
<body>
<h2>Params</h2>
<form>
Selectors:
<input type="number" name="selectors" placeholder="selectors" value="10000">
<br>
<button>Apply</button>
</form>
<h2>Actions</h2>
<p>
<button id="parse">Selector.parse</button>
<button id="addSelectable">Selector.addSelectable</button>
<button id="match">Selector.match</button>
</p>
$SCRIPTS$

View File

@ -1,46 +1,45 @@
import {document, DOM} from 'facade/dom';
import {SelectorMatcher} from "core/compiler/selector";
import {CssSelector} from "core/compiler/selector";
import {StringWrapper, Math} from 'facade/lang';
import {ListWrapper} from 'facade/collection';
var COUNT = 1000;
import {getIntParameter, bindAction} from 'e2e_test_lib/benchmark_util';
export function main() {
var count = getIntParameter('selectors');
var fixedMatcher;
var fixedSelectorStrings = [];
var fixedSelectors = [];
for (var i=0; i<COUNT; i++) {
for (var i=0; i<count; i++) {
ListWrapper.push(fixedSelectorStrings, randomSelector());
}
for (var i=0; i<COUNT; i++) {
for (var i=0; i<count; i++) {
ListWrapper.push(fixedSelectors, CssSelector.parse(fixedSelectorStrings[i]));
}
fixedMatcher = new SelectorMatcher();
for (var i=0; i<COUNT; i++) {
for (var i=0; i<count; i++) {
fixedMatcher.addSelectable(fixedSelectors[i], i);
}
function parse(_) {
function parse() {
var result = [];
for (var i=0; i<COUNT; i++) {
for (var i=0; i<count; i++) {
ListWrapper.push(result, CssSelector.parse(fixedSelectorStrings[i]));
}
return result;
}
function addSelectable(_) {
function addSelectable() {
var matcher = new SelectorMatcher();
for (var i=0; i<COUNT; i++) {
for (var i=0; i<count; i++) {
matcher.addSelectable(fixedSelectors[i], i);
}
return matcher;
}
function match(_) {
function match() {
var matchCount = 0;
for (var i=0; i<COUNT; i++) {
for (var i=0; i<count; i++) {
fixedMatcher.match(fixedSelectors[i], (selected) => {
matchCount += selected;
});
@ -48,9 +47,9 @@ export function main() {
return matchCount;
}
DOM.on(DOM.querySelector(document, '#parse'), 'click', parse);
DOM.on(DOM.querySelector(document, '#addSelectable'), 'click', addSelectable);
DOM.on(DOM.querySelector(document, '#match'), 'click', match);
bindAction('#parse', parse);
bindAction('#addSelectable', addSelectable);
bindAction('#match', match);
}
function randomSelector() {

View File

@ -2,10 +2,21 @@
<html>
<body>
<button id="getByToken">Injector.get (token)</button>
<button id="getByKey">Injector.get (key)</button>
<button id="getChild">Injector.get (grand x 5 child)</button>
<button id="instantiate">Injector.instantiate</button>
<h2>Params</h2>
<form>
Iterations:
<input type="number" name="iterations" placeholder="iterations" value="20000">
<br>
<button>Apply</button>
</form>
<h2>Actions</h2>
<p>
<button id="getByToken">getByToken</button>
<button id="getByKey">getByKey</button>
<button id="getChild">getChild</button>
<button id="instantiate">instantiate</button>
</div>
$SCRIPTS$
</body>

View File

@ -1,6 +1,6 @@
import {Injector, Key} from "di/di";
import {reflector} from 'reflection/reflection';
import {document, DOM} from 'facade/dom';
import {getIntParameter, bindAction} from 'e2e_test_lib/benchmark_util';
var count = 0;
@ -33,6 +33,8 @@ function setupReflector() {
}
export function main() {
var iterations = getIntParameter('iterations');
setupReflector();
var bindings = [A, B, C, D, E];
var injector = new Injector(bindings);
@ -46,37 +48,37 @@ export function main() {
createChild([]).
createChild([]);
function getByToken (_) {
for (var i = 0; i < 20000; ++i) {
function getByToken () {
for (var i = 0; i < iterations; ++i) {
injector.get(D);
injector.get(E);
}
}
function getByKey(_) {
for (var i = 0; i < 20000; ++i) {
function getByKey() {
for (var i = 0; i < iterations; ++i) {
injector.get(D_KEY);
injector.get(E_KEY);
}
}
function getChild (_) {
for (var i = 0; i < 20000; ++i) {
function getChild () {
for (var i = 0; i < iterations; ++i) {
childInjector.get(D);
childInjector.get(E);
}
}
function instantiate (_) {
for (var i = 0; i < 5000; ++i) {
function instantiate () {
for (var i = 0; i < iterations; ++i) {
var child = injector.createChild([E]);
child.get(E);
}
}
DOM.on(DOM.querySelector(document, '#getByToken'), 'click', getByToken);
DOM.on(DOM.querySelector(document, '#getByKey'), 'click', getByKey);
DOM.on(DOM.querySelector(document, '#getChild'), 'click', getChild);
DOM.on(DOM.querySelector(document, '#instantiate'), 'click', instantiate);
bindAction('#getByToken', getByToken);
bindAction('#getByKey', getByKey);
bindAction('#getChild', getChild);
bindAction('#instantiate', instantiate);
}

View File

@ -2,8 +2,19 @@
<html>
<body>
<button id="instantiate">ElementInjector.instantiate</button>
<button id="instantiateDirectives">ElementInjector.instantiateDirectives</button>
<h2>Params</h2>
<form>
Iterations:
<input type="number" name="iterations" placeholder="iterations" value="20000">
<br>
<button>Apply</button>
</form>
<h2>Actions</h2>
<p>
<button id="instantiate">instantiate</button>
<button id="instantiateDirectives">instantiateDirectives</button>
</p>
$SCRIPTS$
</body>

View File

@ -1,10 +1,9 @@
import {reflector} from 'reflection/reflection';
import {Injector} from 'di/di';
import {ProtoElementInjector} from 'core/compiler/element_injector';
import {document, DOM} from 'facade/dom';
import {getIntParameter, bindAction} from 'e2e_test_lib/benchmark_util';
var count = 0;
var ITERATIONS = 20000;
function setupReflector() {
reflector.registerType(A, {
@ -25,6 +24,8 @@ function setupReflector() {
}
export function main() {
var iterations = getIntParameter('iterations');
setupReflector();
var appInjector = new Injector([]);
@ -32,22 +33,22 @@ export function main() {
var proto = new ProtoElementInjector(null, 0, bindings);
var elementInjector = proto.instantiate(null,null);
function instantiate (_) {
for (var i = 0; i < ITERATIONS; ++i) {
function instantiate () {
for (var i = 0; i < iterations; ++i) {
var ei = proto.instantiate(null, null);
ei.instantiateDirectives(appInjector, null, null);
}
}
function instantiateDirectives (_) {
for (var i = 0; i < ITERATIONS; ++i) {
function instantiateDirectives () {
for (var i = 0; i < iterations; ++i) {
elementInjector.clearDirectives();
elementInjector.instantiateDirectives(appInjector, null, null);
}
}
DOM.on(DOM.querySelector(document, '#instantiate'), 'click', instantiate);
DOM.on(DOM.querySelector(document, '#instantiateDirectives'), 'click', instantiateDirectives);
bindAction('#instantiate', instantiate);
bindAction('#instantiateDirectives', instantiateDirectives);
}
class A {

View File

@ -2,6 +2,14 @@
<html>
<body>
<h2>Params</h2>
<form>
Depth:
<input type="number" name="depth" placeholder="depth" value="9">
<br>
<button>Apply</button>
</form>
<h2>Angular2 tree benchmark</h2>
<p>
<button id="ng2DestroyDom">destroyDom</button>

View File

@ -10,8 +10,7 @@ import {LifeCycle} from 'core/life_cycle/life_cycle';
import {reflector} from 'reflection/reflection';
import {DOM, document, window, Element, gc} from 'facade/dom';
import {isPresent} from 'facade/lang';
var MAX_DEPTH = 9;
import {getIntParameter, bindAction} from 'e2e_test_lib/benchmark_util';
function setupReflector() {
// TODO: Put the general calls to reflector.register... in a shared file
@ -121,14 +120,16 @@ function setupReflector() {
}
export function main() {
setupReflector();
var maxDepth = getIntParameter('depth');
setupReflector();
var app;
var changeDetector;
var baselineRootTreeComponent;
var count = 0;
function ng2DestroyDom(_) {
function ng2DestroyDom() {
// TODO: We need an initial value as otherwise the getter for data.value will fail
// --> this should be already caught in change detection!
app.initData = new TreeNode('', null, null);
@ -136,16 +137,16 @@ export function main() {
}
function profile(create, destroy, name) {
return function(_) {
return function() {
window.console.profile(name + ' w GC');
var duration = 0;
var count = 0;
while(count++ < 150) {
gc();
var start = window.performance.now();
create(_);
create();
duration += window.performance.now() - start;
destroy(_);
destroy();
}
window.console.profileEnd(name + ' w GC');
window.console.log(`Iterations: ${count}; time: ${duration / count} ms / iteration`);
@ -155,21 +156,21 @@ export function main() {
count = 0;
while(count++ < 150) {
var start = window.performance.now();
create(_);
create();
duration += window.performance.now() - start;
destroy(_);
destroy();
}
window.console.profileEnd(name + ' w/o GC');
window.console.log(`Iterations: ${count}; time: ${duration / count} ms / iteration`);
};
}
function ng2CreateDom(_) {
function ng2CreateDom() {
var values = count++ % 2 == 0 ?
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] :
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-'];
app.initData = buildTree(MAX_DEPTH, values, 0);
app.initData = buildTree(maxDepth, values, 0);
changeDetector.detectChanges();
}
@ -179,33 +180,35 @@ export function main() {
bootstrap(AppComponent).then((injector) => {
changeDetector = injector.get(ChangeDetector);
app = injector.get(AppComponent);
DOM.on(DOM.querySelector(document, '#ng2DestroyDom'), 'click', ng2DestroyDom);
DOM.on(DOM.querySelector(document, '#ng2CreateDom'), 'click', ng2CreateDom);
DOM.on(DOM.querySelector(document, '#ng2UpdateDomProfile'), 'click', profile(ng2CreateDom, noop, 'ng2-update'));
DOM.on(DOM.querySelector(document, '#ng2CreateDomProfile'), 'click', profile(ng2CreateDom, ng2DestroyDom, 'ng2-create'));
bindAction('#ng2DestroyDom', ng2DestroyDom);
bindAction('#ng2CreateDom', ng2CreateDom);
bindAction('#ng2UpdateDomProfile', profile(ng2CreateDom, noop, 'ng2-update'));
bindAction('#ng2CreateDomProfile', profile(ng2CreateDom, ng2DestroyDom, 'ng2-create'));
});
}
function baselineDestroyDom(_) {
function baselineDestroyDom() {
baselineRootTreeComponent.update(new TreeNode('', null, null));
}
function baselineCreateDom(_) {
function baselineCreateDom() {
var values = count++ % 2 == 0 ?
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] :
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-'];
baselineRootTreeComponent.update(buildTree(MAX_DEPTH, values, 0));
baselineRootTreeComponent.update(buildTree(maxDepth, values, 0));
}
function initBaseline() {
var tree = DOM.createElement('tree');
DOM.appendChild(DOM.querySelector(document, 'baseline'), tree);
baselineRootTreeComponent = new BaseLineTreeComponent(tree);
DOM.on(DOM.querySelector(document, '#baselineDestroyDom'), 'click', baselineDestroyDom);
DOM.on(DOM.querySelector(document, '#baselineCreateDom'), 'click', baselineCreateDom);
DOM.on(DOM.querySelector(document, '#baselineUpdateDomProfile'), 'click', profile(baselineCreateDom, noop, 'baseline-update'));
DOM.on(DOM.querySelector(document, '#baselineCreateDomProfile'), 'click', profile(baselineCreateDom, baselineDestroyDom, 'baseline-create'));
bindAction('#baselineDestroyDom', baselineDestroyDom);
bindAction('#baselineCreateDom', baselineCreateDom);
bindAction('#baselineUpdateDomProfile', profile(baselineCreateDom, noop, 'baseline-update'));
bindAction('#baselineCreateDomProfile', profile(baselineCreateDom, baselineDestroyDom, 'baseline-create'));
}
initNg2();