refactor(perf): use webdriver to execute benchmarks

- use performance log of chromedriver / appium to get timeline data
  for calculating metrics for benchmarks
- change all benchmarks to be made of a standalone application
  and a protractor test that collectes timeline data
- fix and simplify benchmarks
- add dart2js to build
- remove benchpress

Closes #330
This commit is contained in:
Tobias Bosch
2014-12-22 17:50:10 -08:00
parent d642c6afb5
commit df4ac0dd33
66 changed files with 1146 additions and 985 deletions
-2
View File
@@ -12,6 +12,4 @@ dependencies:
path: ../core
change_detection:
path: ../change_detection
benchpress:
path: ../benchpress
browser: '>=0.10.0 <0.11.0'
@@ -0,0 +1,10 @@
<!doctype html>
<html>
<body>
<button id="ng2DetectChanges">Ng2 detect changes</button>
<button id="baselineDetectChanges">baseline detect changes</button>
$SCRIPTS$
</body>
@@ -3,7 +3,7 @@ import {Parser} from 'change_detection/parser/parser';
import {Lexer} from 'change_detection/parser/lexer';
import {reflector} from 'reflection/reflection';
import {isPresent} from 'facade/lang';
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
import {document, DOM} from 'facade/dom';
import {
ChangeDetector,
@@ -12,7 +12,7 @@ import {
} from 'change_detection/change_detector';
var ITERATIONS = 200000;
var ITERATIONS = 500000;
class Obj {
field0;
@@ -155,28 +155,25 @@ function setUpChangeDetection() {
export function main () {
setUpReflector();
var baselineHead = setUpBaseline();
var ng2ChangeDetector = setUpChangeDetection();
benchmark(`Baseline`, function () {
var head = setUpBaseline();
benchmarkStep('run', function () {
var current = head;
while (isPresent(current)) {
if (current.getter(current.obj) !== current.previousValue) {
throw "should not happen";
}
current = current.next;
function baselineDetectChanges(_) {
var current = baselineHead;
while (isPresent(current)) {
if (current.getter(current.obj) !== current.previousValue) {
throw "should not happen";
}
});
});
current = current.next;
}
}
benchmark(`Change Detection`, function() {
var cd = setUpChangeDetection();
function ng2DetectChanges(_) {
ng2ChangeDetector.detectChanges();
}
benchmarkStep('run', function() {
cd.detectChanges();
});
});
DOM.on(DOM.querySelector(document, '#ng2DetectChanges'), 'click', ng2DetectChanges);
DOM.on(DOM.querySelector(document, '#baselineDetectChanges'), 'click', baselineDetectChanges);
}
@@ -1 +0,0 @@
$SCRIPTS$
@@ -1,5 +0,0 @@
import * as change_detection_benchmark from './change_detection_benchmark';
export function main() {
change_detection_benchmark.main();
}
@@ -1,4 +1,9 @@
$SCRIPTS$
<!doctype html>
<html>
<body>
<button id="compileWithBindings">Compile template with bindings</button>
<button id="compileNoBindings">Compile template without bindings</button>
<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">
@@ -30,3 +35,8 @@ $SCRIPTS$
</div>
</div>
</template>
$SCRIPTS$
</body>
</html>
@@ -1,5 +1,3 @@
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
import {DOM, document} from 'facade/dom';
import {isBlank, Type} from 'facade/lang';
import {MapWrapper} from 'facade/collection';
@@ -20,10 +18,7 @@ import {reflector} from 'reflection/reflection';
var COUNT = 30;
var compiler;
var annotatedComponent;
function setup() {
function setupReflector() {
reflector.registerType(BenchmarkComponent, {
"factory": () => new BenchmarkComponent(),
"parameters": [],
@@ -79,47 +74,34 @@ function setup() {
"prop": (a,v) => a.prop = v
});
var reader = new CachingDirectiveMetadataReader();
compiler = new Compiler(null, reader, new Parser(new Lexer()), new CompilerCache());
annotatedComponent = reader.annotatedType(BenchmarkComponent);
}
export function main() {
setup();
setupReflector();
var reader = new DirectiveMetadataReader();
var cache = new CompilerCache();
var compiler = new Compiler(null, reader, new Parser(new Lexer()), cache);
var annotatedComponent = reader.annotatedType(BenchmarkComponent);
benchmark(`Compiler.compile 5*${COUNT} element no bindings`, function() {
var template = loadTemplate('templateNoBindings', COUNT);
var templateNoBindings = loadTemplate('templateNoBindings', COUNT);
var templateWithBindings = loadTemplate('templateWithBindings', COUNT);
benchmarkStep('run', function() {
// Need to clone every time as the compiler might modify the template!
var cloned = DOM.clone(template);
compiler.compileAllLoaded(null, annotatedComponent, cloned);
});
});
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);
}
benchmark(`Compiler.compile 5*${COUNT} element with bindings`, function() {
var template = loadTemplate('templateWithBindings', COUNT);
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);
}
benchmarkStep('run', function() {
// Need to clone every time as the compiler might modify the template!
var cloned = DOM.clone(template);
compiler.compileAllLoaded(null, annotatedComponent, cloned);
});
});
benchmark(`instantiate 5*${COUNT} element with bindings`, function() {
var template = loadTemplate('templateWithBindings', COUNT);
var protoView = compiler.compileWithCache(null, annotatedComponent, template);
var rootRecordRange = new ProtoRecordRange().instantiate(null, null);
benchmarkStep('run', function() {
var view = protoView.instantiate(null, null, null);
// also include adding / removing the RecordRange from the parent in the benchmark.
rootRecordRange.addRange(view.recordRange);
view.recordRange.remove();
});
});
DOM.on(DOM.querySelector(document, '#compileNoBindings'), 'click', compileNoBindings);
DOM.on(DOM.querySelector(document, '#compileWithBindings'), 'click', compileWithBindings);
}
function loadTemplate(templateId, repeatCount) {
@@ -132,22 +114,6 @@ function loadTemplate(templateId, repeatCount) {
return DOM.createTemplate(result);
}
// Caching reflector as reflection in Dart using Mirrors
class CachingDirectiveMetadataReader extends DirectiveMetadataReader {
_cache: Map;
constructor() {
this._cache = MapWrapper.create();
}
annotatedType(type:Type):AnnotatedType {
var result = MapWrapper.get(this._cache, type);
if (isBlank(result)) {
result = super.annotatedType(type);
MapWrapper.set(this._cache, type, result);
}
return result;
}
}
@Decorator({
selector: '[dir0]',
bind: {
-7
View File
@@ -1,7 +0,0 @@
import * as sbm from './selector_benchmark';
import * as cbm from './compiler_benchmark';
export function main() {
sbm.main();
cbm.main();
}
@@ -0,0 +1,12 @@
<!doctype html>
<html>
<body>
<button id="parse">Selector.parse</button>
<button id="addSelectable">Selector.addSelectable</button>
<button id="match">Selector.match</button>
$SCRIPTS$
</body>
</html>
@@ -1,63 +1,56 @@
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
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 fixedMatcher;
var fixedSelectorStrings = [];
var fixedSelectors = [];
var COUNT = 1000;
export function main() {
setup(COUNT);
benchmark(`cssSelector.parse * ${COUNT}`, function() {
benchmarkStep(`run`, function() {
var result = [];
for (var i=0; i<COUNT; i++) {
ListWrapper.push(result, CssSelector.parse(fixedSelectorStrings[i]));
}
return result;
});
});
benchmark(`cssSelector.addSelectable * ${COUNT}`, function() {
benchmarkStep(`run`, function() {
var matcher = new SelectorMatcher();
for (var i=0; i<COUNT; i++) {
matcher.addSelectable(fixedSelectors[i], i);
}
return matcher;
});
});
benchmark(`cssSelector.match * ${COUNT}`, function() {
benchmarkStep(`run`, function() {
var matchCount = 0;
for (var i=0; i<COUNT; i++) {
fixedMatcher.match(fixedSelectors[i], (selected) => {
matchCount += selected;
});
}
return matchCount;
});
});
}
function setup(count) {
for (var i=0; i<count; i++) {
var fixedMatcher;
var fixedSelectorStrings = [];
var fixedSelectors = [];
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(_) {
var result = [];
for (var i=0; i<COUNT; i++) {
ListWrapper.push(result, CssSelector.parse(fixedSelectorStrings[i]));
}
return result;
}
function addSelectable(_) {
var matcher = new SelectorMatcher();
for (var i=0; i<COUNT; i++) {
matcher.addSelectable(fixedSelectors[i], i);
}
return matcher;
}
function match(_) {
var matchCount = 0;
for (var i=0; i<COUNT; i++) {
fixedMatcher.match(fixedSelectors[i], (selected) => {
matchCount += selected;
});
}
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);
}
function randomSelector() {
@@ -0,0 +1,12 @@
<!doctype html>
<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>
$SCRIPTS$
</body>
</html>
+113
View File
@@ -0,0 +1,113 @@
import {Injector, Key} from "di/di";
import {reflector} from 'reflection/reflection';
import {document, DOM} from 'facade/dom';
var count = 0;
function setupReflector() {
reflector.registerType(A, {
'factory': () => new A(),
'parameters': [],
'annotations' : []
});
reflector.registerType(B, {
'factory': (a) => new B(a),
'parameters': [[A]],
'annotations' : []
});
reflector.registerType(C, {
'factory': (b) => new C(b),
'parameters': [[B]],
'annotations' : []
});
reflector.registerType(D, {
'factory': (c,b) => new D(c,b),
'parameters': [[C],[B]],
'annotations' : []
});
reflector.registerType(E, {
'factory': (d,c) => new E(d,c),
'parameters': [[D],[C]],
'annotations' : []
});
}
export function main() {
setupReflector();
var bindings = [A, B, C, D, E];
var injector = new Injector(bindings);
var D_KEY = Key.get(D);
var E_KEY = Key.get(E);
var childInjector = injector.
createChild([]).
createChild([]).
createChild([]).
createChild([]).
createChild([]);
function getByToken (_) {
for (var i = 0; i < 20000; ++i) {
injector.get(D);
injector.get(E);
}
}
function getByKey(_) {
for (var i = 0; i < 20000; ++i) {
injector.get(D_KEY);
injector.get(E_KEY);
}
}
function getChild (_) {
for (var i = 0; i < 20000; ++i) {
childInjector.get(D);
childInjector.get(E);
}
}
function instantiate (_) {
for (var i = 0; i < 5000; ++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);
}
class A {
constructor() {
count++;
}
}
class B {
constructor(a:A) {
count++;
}
}
class C {
constructor(b:B) {
count++;
}
}
class D {
constructor(c:C, b:B) {
count++;
}
}
class E {
constructor(d:D, c:C) {
count++;
}
}
@@ -1,43 +0,0 @@
import {Injector} from "di/di";
var count = 0;
export function run () {
var bindings = [A, B, C, D, E];
var injector = new Injector(bindings);
for (var i = 0; i < 20000; ++i) {
injector.get(D);
injector.get(E);
}
}
class A {
constructor() {
count++;
}
}
class B {
constructor(a:A) {
count++;
}
}
class C {
constructor(b:B) {
count++;
}
}
class D {
constructor(c:C, b:B) {
count++;
}
}
class E {
constructor(d:D, c:C) {
count++;
}
}
@@ -1,46 +0,0 @@
import {Injector, Key} from "di/di";
var count = 0;
export function run () {
var bindings = [A, B, C, D, E];
var injector = new Injector(bindings);
var D_KEY = Key.get(D);
var E_KEY = Key.get(E);
for (var i = 0; i < 20000; ++i) {
injector.get(D_KEY);
injector.get(E_KEY);
}
}
class A {
constructor() {
count++;
}
}
class B {
constructor(a:A) {
count++;
}
}
class C {
constructor(b:B) {
count++;
}
}
class D {
constructor(c:C, b:B) {
count++;
}
}
class E {
constructor(d:D, c:C) {
count++;
}
}
@@ -1,49 +0,0 @@
import {Injector, Key} from "di/di";
var count = 0;
export function run () {
var bindings = [A, B, C, D, E];
var injector = new Injector(bindings);
var childInjector = injector.
createChild([]).
createChild([]).
createChild([]).
createChild([]).
createChild([]);
for (var i = 0; i < 20000; ++i) {
childInjector.get(D);
childInjector.get(E);
}
}
class A {
constructor() {
count++;
}
}
class B {
constructor(a:A) {
count++;
}
}
class C {
constructor(b:B) {
count++;
}
}
class D {
constructor(c:C, b:B) {
count++;
}
}
class E {
constructor(d:D, c:C) {
count++;
}
}
@@ -1,43 +0,0 @@
import {Injector, Key} from "di/di";
var count = 0;
export function run () {
var bindings = [A, B, C, D];
var injector = new Injector(bindings);
for (var i = 0; i < 1000; ++i) {
var child = injector.createChild([E]);
child.get(E);
}
}
class A {
constructor() {
count++;
}
}
class B {
constructor(a:A) {
count++;
}
}
class C {
constructor(b:B) {
count++;
}
}
class D {
constructor(c:C, b:B) {
count++;
}
}
class E {
constructor(d:D, c:C) {
count++;
}
}
-1
View File
@@ -1 +0,0 @@
$SCRIPTS$
-24
View File
@@ -1,24 +0,0 @@
import * as injector_get_benchmark from './injector_get_benchmark';
import * as injector_get_by_key_benchmark from './injector_get_by_key_benchmark';
import * as injector_get_child_benchmark from './injector_get_child_benchmark';
import * as injector_instantiate_benchmark from './injector_instantiate_benchmark';
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
export function main() {
benchmark(`Injector.get (token)`, function() {
benchmarkStep('run', injector_get_benchmark.run);
});
benchmark(`Injector.get (key)`, function() {
benchmarkStep('run', injector_get_by_key_benchmark.run);
});
benchmark(`Injector.get (grand x 5 child)`, function() {
benchmarkStep('run', injector_get_child_benchmark.run);
});
benchmark(`Injector.instantiate`, function() {
benchmarkStep('run', injector_instantiate_benchmark.run);
});
}
@@ -0,0 +1,10 @@
<!doctype html>
<html>
<body>
<button id="instantiate">ElementInjector.instantiate</button>
<button id="instantiateDirectives">ElementInjector.instantiateDirectives</button>
$SCRIPTS$
</body>
</html>
@@ -0,0 +1,69 @@
import {reflector} from 'reflection/reflection';
import {Injector} from 'di/di';
import {ProtoElementInjector} from 'core/compiler/element_injector';
import {document, DOM} from 'facade/dom';
var count = 0;
var ITERATIONS = 20000;
function setupReflector() {
reflector.registerType(A, {
'factory': () => new A(),
'parameters': [],
'annotations' : []
});
reflector.registerType(B, {
'factory': () => new B(),
'parameters': [],
'annotations' : []
});
reflector.registerType(C, {
'factory': (a,b) => new C(a,b),
'parameters': [[A],[B]],
'annotations' : []
});
}
export function main() {
setupReflector();
var appInjector = new Injector([]);
var bindings = [A, B, C];
var proto = new ProtoElementInjector(null, 0, bindings);
var elementInjector = proto.instantiate(null,null);
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) {
elementInjector.clearDirectives();
elementInjector.instantiateDirectives(appInjector, null, null);
}
}
DOM.on(DOM.querySelector(document, '#instantiate'), 'click', instantiate);
DOM.on(DOM.querySelector(document, '#instantiateDirectives'), 'click', instantiateDirectives);
}
class A {
constructor() {
count++;
}
}
class B {
constructor() {
count++;
}
}
class C {
constructor(a:A, b:B) {
count++;
}
}
@@ -1,34 +0,0 @@
import {Injector} from 'di/di';
import {ProtoElementInjector} from 'core/compiler/element_injector';
var ITERATIONS = 20000;
var count = 0;
export function run () {
var appInjector = new Injector([]);
var bindings = [A, B, C];
var proto = new ProtoElementInjector(null, 0, bindings);
for (var i = 0; i < ITERATIONS; ++i) {
var ei = proto.instantiate(null, null);
ei.instantiateDirectives(appInjector, null, null);
}
}
class A {
constructor() {
count++;
}
}
class B {
constructor() {
count++;
}
}
class C {
constructor(a:A, b:B) {
count++;
}
}
@@ -1,42 +0,0 @@
import {Binding, Dependency, Key, Injector} from 'di/di';
import {ProtoElementInjector} from 'core/compiler/element_injector';
var ITERATIONS = 20000;
var count = 0;
export function run () {
var appInjector = new Injector([]);
var bindings = [
new Binding(Key.get(A), () => new A(), [], false),
new Binding(Key.get(B), () => new B(), [], false),
new Binding(Key.get(C), (a,b) => new C(a,b), [
new Dependency(Key.get(A), false, false, []),
new Dependency(Key.get(B), false, false, [])
], false)];
var proto = new ProtoElementInjector(null, 0, bindings);
for (var i = 0; i < ITERATIONS; ++i) {
var ei = proto.instantiate(null,null);
ei.instantiateDirectives(appInjector, null, null);
}
}
class A {
constructor() {
count++;
}
}
class B {
constructor() {
count++;
}
}
class C {
constructor(a:A, b:B) {
count++;
}
}
@@ -1,36 +0,0 @@
import {Injector} from 'di/di';
import {ProtoElementInjector} from 'core/compiler/element_injector';
var ITERATIONS = 20000;
var count = 0;
export function run () {
var appInjector = new Injector([]);
var bindings = [A, B, C];
var proto = new ProtoElementInjector(null, 0, bindings);
var ei = proto.instantiate(null,null);
for (var i = 0; i < ITERATIONS; ++i) {
ei.clearDirectives();
ei.instantiateDirectives(appInjector, null, null);
}
}
class A {
constructor() {
count++;
}
}
class B {
constructor() {
count++;
}
}
class C {
constructor(a:A, b:B) {
count++;
}
}
@@ -1 +0,0 @@
$SCRIPTS$
@@ -1,19 +0,0 @@
import * as instantiate_benchmark from './instantiate_benchmark';
import * as instantiate_directive_benchmark from './instantiate_directive_benchmark';
import * as instantiate_benchmark_codegen from './instantiate_benchmark_codegen';
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
export function main() {
benchmark(`ElementInjector.instantiate + instantiateDirectives`, function() {
benchmarkStep('run', instantiate_benchmark.run);
});
benchmark(`ElementInjector.instantiateDirectives`, function() {
benchmarkStep('run', instantiate_directive_benchmark.run);
});
benchmark(`ElementInjector.instantiate + instantiateDirectives (codegen)`, function() {
benchmarkStep('run', instantiate_benchmark_codegen.run);
});
}
+25
View File
@@ -0,0 +1,25 @@
<!doctype html>
<html>
<body>
<ul>
<li>
<a href="di/di_benchmark.html">DI benchmark</a>
</li>
<li>
<a href="change_detection/change_detection_benchmark.html">Change detection benchmark</a>
</li>
<li>
<a href="compiler/selector_benchmark.html">Selector benchmark</a>
</li>
<li>
<a href="compiler/compiler_benchmark.html">Compiler benchmark</a>
</li>
<li>
<a href="element_injector/element_injector_benchmark.html">Element injector benchmark</a>
</li>
<li>
<a href="tree/tree_benchmark.html">Tree benchmark</a>
</li>
</ul>
</body>
</html>
-5
View File
@@ -1,5 +0,0 @@
$SCRIPTS$
<app></app>
<baseline></baseline>
-5
View File
@@ -1,5 +0,0 @@
import * as tree_benchmark from './tree_benchmark';
export function main() {
tree_benchmark.main();
}
@@ -0,0 +1,27 @@
<!doctype html>
<html>
<body>
<h2>Angular2 tree benchmark</h2>
<p>
<button id="ng2DestroyDom">destroyDom</button>
<button id="ng2CreateDom">createDom</button>
</p>
<h2>Baseline tree benchmark</h2>
<p>
<button id="baselineDestroyDom">destroyDom</button>
<button id="baselineCreateDom">createDom</button>
</p>
<div>
<app></app>
</div>
<div>
<baseline></baseline>
</div>
$SCRIPTS$
</body>
</html>
+51 -45
View File
@@ -1,5 +1,3 @@
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
import {ChangeDetector} from 'change_detection/change_detector';
import {Parser} from 'change_detection/parser/parser';
import {Lexer} from 'change_detection/parser/lexer';
@@ -9,6 +7,7 @@ import {bootstrap, Component, Template, TemplateConfig, ViewPort, Compiler} from
import {CompilerCache} from 'core/compiler/compiler';
import {DirectiveMetadataReader} from 'core/compiler/directive_metadata_reader';
import {TemplateLoader} from 'core/compiler/template_loader';
import {LifeCycle} from 'core/life_cycle/life_cycle';
import {reflector} from 'reflection/reflection';
import {DOM, document, Element} from 'facade/dom';
@@ -16,7 +15,7 @@ import {isPresent} from 'facade/lang';
var MAX_DEPTH = 9;
function setup() {
function setupReflector() {
// TODO: Put the general calls to reflector.register... in a shared file
// as they are needed in all benchmarks...
@@ -98,6 +97,12 @@ function setup() {
'annotations': []
});
reflector.registerType(LifeCycle, {
"factory": (cd) => new LifeCycle(cd),
"parameters": [[ChangeDetector]],
"annotations": []
});
reflector.registerGetters({
'value': (a) => a.value,
@@ -115,61 +120,62 @@ function setup() {
'data': (a,v) => a.data = v,
'ngIf': (a,v) => a.ngIf = v
});
return bootstrap(AppComponent);
}
export function main() {
setupReflector();
var app;
var changeDetector;
setup().then((injector) => {
changeDetector = injector.get(ChangeDetector);
app = injector.get(AppComponent);
});
var baselineRootTreeComponent;
var count = 0;
benchmark(`tree benchmark`, function() {
var count = 0;
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);
changeDetector.detectChanges();
}
benchmarkStep(`destroyDom binary tree of depth ${MAX_DEPTH}`, function() {
// 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);
changeDetector.detectChanges();
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);
changeDetector.detectChanges();
}
function initNg2() {
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);
});
}
benchmarkStep(`createDom binary tree of depth ${MAX_DEPTH}`, function() {
var maxDepth = 9;
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', '-'];
function baselineDestroyDom(_) {
baselineRootTreeComponent.update(new TreeNode('', null, null));
}
app.initData = buildTree(maxDepth, values, 0);
changeDetector.detectChanges();
});
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));
}
benchmark(`baseline tree benchmark`, function() {
var baselineAppElement = DOM.querySelectorAll(document, 'baseline')[0];
var rootTreeComponent = new BaseLineTreeComponent();
DOM.appendChild(baselineAppElement, rootTreeComponent.element);
function initBaseline() {
baselineRootTreeComponent = new BaseLineTreeComponent();
DOM.appendChild(DOM.querySelector(document, 'baseline'), baselineRootTreeComponent.element);
DOM.on(DOM.querySelector(document, '#baselineDestroyDom'), 'click', baselineDestroyDom);
DOM.on(DOM.querySelector(document, '#baselineCreateDom'), 'click', baselineCreateDom);
}
var count = 0;
benchmarkStep(`destroyDom binary tree of depth ${MAX_DEPTH}`, function() {
rootTreeComponent.update(new TreeNode('', null, null));
});
benchmarkStep(`createDom binary tree of depth ${MAX_DEPTH}`, function() {
var maxDepth = 9;
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', '-'];
rootTreeComponent.update(buildTree(maxDepth, values, 0));
});
});
initNg2();
initBaseline();
}
class TreeNode {
@@ -0,0 +1,26 @@
"use strict";
var util = require('../../../../tools/perf/util.js');
describe('ng2 change detection benchmark', function () {
var URL = 'benchmarks/web/change_detection/change_detection_benchmark.html';
afterEach(util.verifyNoErrors);
it('should log ng stats', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#ng2DetectChanges'],
name: browser.params.lang+'.ng2.changeDetection'
});
});
it('should log baseline stats', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#baselineDetectChanges'],
name: browser.params.lang+'.baseline.changeDetection'
});
});
});
@@ -0,0 +1,26 @@
"use strict";
var util = require('../../../../tools/perf/util.js');
describe('ng2 compiler benchmark', function () {
var URL = 'benchmarks/web/compiler/compiler_benchmark.html';
afterEach(util.verifyNoErrors);
it('should log withBindings stats', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#compileWithBindings'],
name: browser.params.lang+'.ng2.compile.withBindings'
});
});
it('should log noBindings stats', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#compileNoBindings'],
name: browser.params.lang+'.ng2.compile.noBindings'
});
});
});
+42
View File
@@ -0,0 +1,42 @@
"use strict";
var util = require('../../../../tools/perf/util.js');
describe('ng2 di benchmark', function () {
var URL = 'benchmarks/web/di/di_benchmark.html';
afterEach(util.verifyNoErrors);
it('should log the stats for getByToken', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#getByToken'],
name: browser.params.lang+'.ng2.di.getByToken'
});
});
it('should log the stats for getByKey', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#getByKey'],
name: browser.params.lang+'.ng2.di.getByKey'
});
});
it('should log the stats for getChild', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#getChild'],
name: browser.params.lang+'.ng2.di.getChild'
});
});
it('should log the stats for instantiate', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#instantiate'],
name: browser.params.lang+'.ng2.di.instantiate'
});
});
});
@@ -0,0 +1,26 @@
"use strict";
var util = require('../../../../tools/perf/util.js');
describe('ng2 element injector benchmark', function () {
var URL = 'benchmarks/web/element_injector/element_injector_benchmark.html';
afterEach(util.verifyNoErrors);
it('should log the stats for instantiate', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#instantiate'],
name: browser.params.lang+'.ng2.elementInjector.instantiate'
});
});
it('should log the stats for instantiateDirectives', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#instantiateDirectives'],
name: browser.params.lang+'.ng2.elementInjector.instantiateDirectives'
});
});
});
+26
View File
@@ -0,0 +1,26 @@
"use strict";
var util = require('../../../../tools/perf/util.js');
describe('ng2 tree benchmark', function () {
var URL = 'benchmarks/web/tree/tree_benchmark.html';
afterEach(util.verifyNoErrors);
it('should log the ng stats', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#ng2DestroyDom', '#ng2CreateDom'],
name: browser.params.lang+'.ng2.tree'
});
});
it('should log the baseline stats', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#baselineDestroyDom', '#baselineCreateDom'],
name: browser.params.lang+'.baseline.tree'
});
});
});
+1 -2
View File
@@ -3,7 +3,6 @@ environment:
sdk: '>=1.4.0'
dependencies:
angular: ">=1.0.0 <2.0.0"
benchpress:
path: ../benchpress
browser: '>=0.10.0 <0.11.0'
transformers:
- angular
@@ -1,8 +1,8 @@
// compiler benchmark in AngularDart 1.x
library compiler_benchmark_ng10;
import 'package:angular/angular.dart';
import 'package:angular/application_factory.dart';
import 'package:benchpress/benchpress.dart';
import 'dart:html';
var COUNT = 30;
@@ -16,42 +16,26 @@ main() {
..bind(Dir3)
..bind(Dir4);
benchmark("AngularDart 1.0 Compiler.compile 5*${COUNT} element with bindings", () {
var template = loadTemplate('templateWithBindings', COUNT);
var templateWithBindings = loadTemplate('templateWithBindings', COUNT);
var templateNoBindings = loadTemplate('templateWithBindings', COUNT);
final injector = applicationFactory().addModule(m).run();
final injector = applicationFactory().addModule(m).run();
final compiler = injector.get(Compiler);
final directiveMap = injector.get(DirectiveMap);
final compiler = injector.get(Compiler);
final directiveMap = injector.get(DirectiveMap);
final di = injector.get(DirectiveInjector);
final rootScope = injector.get(Scope);
compileWithBindings(_) {
final cloned = templateWithBindings.clone(true);
compiler([cloned], directiveMap);
}
benchmarkStep('run', () {
final cloned = template.clone(true);
final scope = rootScope.createChild({});
final viewFactory = compiler([cloned], directiveMap);
viewFactory(scope, di);
scope.destroy();
});
});
compileNoBindings(_) {
final cloned = templateNoBindings.clone(true);
compiler([cloned], directiveMap);
}
benchmark("AngularDart 1.0 instantiate 5*${COUNT} element with bindings", () {
var template = loadTemplate('templateWithBindings', COUNT);
document.querySelector('#compileWithBindings').addEventListener('click', compileWithBindings);
document.querySelector('#compileNoBindings').addEventListener('click', compileNoBindings);
final injector = applicationFactory().addModule(m).run();
final compiler = injector.get(Compiler);
final directiveMap = injector.get(DirectiveMap);
final di = injector.get(DirectiveInjector);
final rootScope = injector.get(Scope);
final viewFactory = compiler([template], directiveMap);
benchmarkStep('run', () {
var scope = rootScope.createChild({});
viewFactory(scope, di);
scope.destroy();
});
});
}
loadTemplate(templateId, repeatCount) {
@@ -1,46 +1,7 @@
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
// compiler benchmark in AngularJS 1.x
var COUNT = 30;
var $compile;
var $rootScope;
export function main() {
benchmark(`Ng 1.3 Compiler.compile 5*${COUNT} element no bindings`, function() {
var template = loadTemplate('templateNoBindings', COUNT);
benchmarkStep('run', function() {
// Need to clone every time as the compiler might modify the template!
var cloned = template.cloneNode(true);
$compile(cloned);
});
});
benchmark(`Ng 1.3 Compiler.compile 5*${COUNT} element with bindings`, function() {
var template = loadTemplate('templateWithBindings', COUNT);
benchmarkStep('run', function() {
// Need to clone every time as the compiler might modify the template!
var cloned = template.cloneNode(true);
$compile(cloned);
});
});
benchmark(`Ng 1.3 instantiate 5*${COUNT} element with bindings`, function() {
var linkFn;
setTimeout(function() {
var template = loadTemplate('templateWithBindings', COUNT);
linkFn = $compile(template);
});
benchmarkStep('run', function() {
var scope = $rootScope.$new();
linkFn(scope);
scope.$destroy();
});
});
var ngEl = document.createElement('div');
angular.bootstrap(ngEl, ['app']);
}
@@ -62,7 +23,7 @@ function loadTemplate(templateId, repeatCount) {
}
angular.module('app', [])
.directive('dir0', function($parse) {
.directive('dir0', ['$parse', function($parse) {
return {
compile: function($element, $attrs) {
var expr = $parse($attrs.attr0);
@@ -71,8 +32,8 @@ angular.module('app', [])
}
}
};
})
.directive('dir1', function($parse) {
}])
.directive('dir1', ['$parse', function($parse) {
return {
compile: function($element, $attrs) {
var expr = $parse($attrs.attr1);
@@ -81,8 +42,8 @@ angular.module('app', [])
}
}
};
})
.directive('dir2', function($parse) {
}])
.directive('dir2', ['$parse', function($parse) {
return {
compile: function($element, $attrs) {
var expr = $parse($attrs.attr2);
@@ -91,8 +52,8 @@ angular.module('app', [])
}
}
};
})
.directive('dir3', function($parse) {
}])
.directive('dir3', ['$parse', function($parse) {
return {
compile: function($element, $attrs) {
var expr = $parse($attrs.attr3);
@@ -101,8 +62,8 @@ angular.module('app', [])
}
}
};
})
.directive('dir4', function($parse) {
}])
.directive('dir4', ['$parse', function($parse) {
return {
compile: function($element, $attrs) {
var expr = $parse($attrs.attr4);
@@ -111,9 +72,24 @@ angular.module('app', [])
}
}
};
})
.run(function(_$compile_, _$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
});
}])
.run(['$compile', function($compile) {
var templateNoBindings = loadTemplate('templateNoBindings', COUNT);
var templateWithBindings = loadTemplate('templateWithBindings', COUNT);
document.querySelector('#compileWithBindings').addEventListener('click', compileWithBindings, false);
document.querySelector('#compileNoBindings').addEventListener('click', compileNoBindings, false);
function compileNoBindings(_) {
// Need to clone every time as the compiler might modify the template!
var cloned = templateNoBindings.cloneNode(true);
$compile(cloned);
}
function compileWithBindings(_) {
// Need to clone every time as the compiler might modify the template!
var cloned = templateWithBindings.cloneNode(true);
$compile(cloned);
}
}]);
@@ -1,4 +1,9 @@
$SCRIPTS$
<!doctype html>
<html>
<body>
<button id="compileWithBindings">Compile template with bindings</button>
<button id="compileNoBindings">Compile template without bindings</button>
<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">
@@ -30,3 +35,8 @@ $SCRIPTS$
</div>
</div>
</template>
$SCRIPTS$
</body>
</html>
@@ -1,7 +0,0 @@
library compiler_benchmark;
import './compiler_benchmark_ng10.dart' as cbm;
main () {
cbm.main();
}
@@ -1 +0,0 @@
export {main} from './compiler_benchmark_ng13';
@@ -0,0 +1,13 @@
<!doctype html>
<html>
<body>
<ul>
<li>
<a href="compiler/compiler_benchmark.html">Compiler benchmark</a>
</li>
<li>
<a href="tree/tree_benchmark.html">Tree benchmark</a>
</li>
</ul>
</body>
</html>
@@ -1,7 +0,0 @@
library tree_benchmark;
import './tree_benchmark_ng10.dart' as bm;
main () {
bm.main();
}
@@ -1 +0,0 @@
export {main} from './tree_benchmark_ng13';
@@ -1,3 +0,0 @@
$SCRIPTS$
<tree data="initData"></tree>
@@ -1,8 +1,8 @@
// tree benchmark in AngularDart 1.x
library tree_benchmark_ng10;
import 'package:angular/angular.dart';
import 'package:angular/application_factory.dart';
import 'package:benchpress/benchpress.dart';
import 'dart:html';
var MAX_DEPTH = 9;
@@ -23,28 +23,26 @@ main() {
final injector = setup();
final zone = injector.get(VmTurnZone);
final rootScope = injector.get(Scope);
var count = 0;
benchmark("tree benchmark", () {
var count = 0;
benchmarkStep("AngularDart destroyDom binary tree of depth ${MAX_DEPTH}", () {
zone.run(() {
rootScope.context['initData'] = new TreeNode('');
});
destroyDom(_) {
zone.run(() {
rootScope.context['initData'] = new TreeNode('');
});
}
benchmarkStep("AngularDart createDom binary tree of depth ${MAX_DEPTH}", () {
zone.run(() {
var maxDepth = 9;
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', '-'];
createDom(_) {
zone.run(() {
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', '-'];
rootScope.context['initData'] = buildTree(maxDepth, values, 0);
});
rootScope.context['initData'] = buildTree(MAX_DEPTH, values, 0);
});
}
});
document.querySelector('#destroyDom').addEventListener('click', destroyDom);
document.querySelector('#createDom').addEventListener('click', createDom);
}
@Component(
@@ -0,0 +1,102 @@
// tree benchmark in AngularJS 1.x
var MAX_DEPTH = 9;
export function main() {
angular.bootstrap(document.body, ['app']);
}
angular.module('app', [])
.directive('tree', function() {
return {
scope: {
data: '='
},
template:
'<span> {{data.value}}'+
' <span tree-if="data.left"></span>'+
' <span tree-if="data.right"></span>'+
'</span>'
};
})
// special directive for "if" as angular 1.3 does not support
// recursive components.
.directive('treeIf', ['$compile', '$parse', function($compile, $parse) {
var transcludeFn;
return {
compile: function(element, attrs) {
var expr = $parse(attrs.treeIf);
var template = '<tree data="'+attrs.treeIf+'"></tree>';
var transclude;
return function($scope, $element, $attrs) {
if (!transclude) {
transclude = $compile(template);
}
var childScope;
var childElement;
$scope.$watch(expr, function(newValue) {
if (childScope) {
childScope.$destroy();
childElement.remove();
childScope = null;
childElement = null;
}
if (newValue) {
childScope = $scope.$new();
childElement = transclude(childScope, function(clone) {
$element.append(clone);
});
}
});
}
}
}
}])
.config(['$compileProvider', function($compileProvider) {
$compileProvider.debugInfoEnabled(false);
}])
.run(['$rootScope', function($rootScope) {
var count = 0;
document.querySelector('#destroyDom').addEventListener('click', destroyDom, false);
document.querySelector('#createDom').addEventListener('click', createDom, false);
function destroyDom(_) {
$rootScope.$apply(function() {
$rootScope.initData = new TreeNode('', null, null);
});
}
function createDom(_) {
var maxDepth = MAX_DEPTH;
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', '-'];
$rootScope.$apply(function() {
$rootScope.initData = buildTree(MAX_DEPTH, values, 0);
});
}
}]);
class TreeNode {
value:string;
left:TreeNode;
right:TreeNode;
constructor(value, left, right) {
this.value = value;
this.left = left;
this.right = right;
}
}
function buildTree(maxDepth, values, curDepth) {
if (maxDepth === curDepth) return new TreeNode('', null, null);
return new TreeNode(
values[curDepth],
buildTree(maxDepth, values, curDepth+1),
buildTree(maxDepth, values, curDepth+1));
}
@@ -0,0 +1,17 @@
<!doctype html>
<html>
<body>
<h2>AngularJS/Dart 1.x tree benchmark</h2>
<p>
<button id="destroyDom">destroyDom</button>
<button id="createDom">createDom</button>
</p>
<div>
<tree data="initData"></tree>
</div>
$SCRIPTS$
</body>
</html>
@@ -1,112 +0,0 @@
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
var MAX_DEPTH = 9;
function setup() {
var $rootScope;
angular.module('app', [])
.directive('tree', function() {
return {
scope: {
data: '='
},
template:
'<span> {{data.value}}'+
' <span tree-if="data.left"></span>'+
' <span tree-if="data.right"></span>'+
'</span>'
};
})
// special directive for "if" as angular 1.3 does not support
// recursive components.
.directive('treeIf', ['$compile', '$parse', function($compile, $parse) {
var transcludeFn;
return {
compile: function(element, attrs) {
var expr = $parse(attrs.treeIf);
var template = '<tree data="'+attrs.treeIf+'"></tree>';
var transclude;
return function($scope, $element, $attrs) {
if (!transclude) {
transclude = $compile(template);
}
var childScope;
var childElement;
$scope.$watch(expr, function(newValue) {
if (childScope) {
childScope.$destroy();
childElement.remove();
childScope = null;
childElement = null;
}
if (newValue) {
childScope = $scope.$new();
childElement = transclude(childScope, function(clone) {
$element.append(clone);
});
}
});
}
}
}
}])
.config(['$compileProvider', function($compileProvider) {
$compileProvider.debugInfoEnabled(false);
}])
.run(['$rootScope', function(_$rootScope_) {
$rootScope = _$rootScope_;
}])
angular.bootstrap(document.body, ['app']);
return $rootScope;
}
export function main() {
var $rootScope = setup();
benchmark(`tree benchmark`, function() {
var count = 0;
benchmarkStep(`AngularJS destroyDom binary tree of depth ${MAX_DEPTH}`, function() {
$rootScope.$apply(function() {
$rootScope.initData = new TreeNode('', null, null);
});
});
benchmarkStep(`AngularJS createDom binary tree of depth ${MAX_DEPTH}`, function() {
var maxDepth = 9;
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', '-'];
$rootScope.$apply(function() {
$rootScope.initData = buildTree(maxDepth, values, 0);
});
});
});
}
class TreeNode {
value:string;
left:TreeNode;
right:TreeNode;
constructor(value, left, right) {
this.value = value;
this.left = left;
this.right = right;
}
}
function buildTree(maxDepth, values, curDepth) {
if (maxDepth === curDepth) return new TreeNode('', null, null);
return new TreeNode(
values[curDepth],
buildTree(maxDepth, values, curDepth+1),
buildTree(maxDepth, values, curDepth+1));
}
@@ -0,0 +1,26 @@
"use strict";
var util = require('../../../../tools/perf/util.js');
describe('ng1.x compiler benchmark', function () {
var URL = 'benchmarks_external/web/compiler/compiler_benchmark.html';
afterEach(util.verifyNoErrors);
it('should log withBinding stats', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#compileWithBindings'],
name: browser.params.lang+'.ng1.compile.withBindings'
});
});
it('should log noBindings stats', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#compileNoBindings'],
name: browser.params.lang+'.ng1.compile.noBindings'
});
});
});
@@ -0,0 +1,18 @@
"use strict";
var util = require('../../../../tools/perf/util.js');
describe('ng1.x tree benchmark', function () {
var URL = 'benchmarks_external/web/tree/tree_benchmark.html';
afterEach(util.verifyNoErrors);
it('should log the stats', function() {
util.runSimpleBenchmark({
url: URL,
buttons: ['#destroyDom', '#createDom'],
name: browser.params.lang+'.ng1.tree'
});
});
});
-4
View File
@@ -1,4 +0,0 @@
name: benchpress
environment:
sdk: '>=1.4.0'
dependencies:
-63
View File
@@ -1,63 +0,0 @@
library benchmarks.benchpress;
import 'dart:js' as js;
import 'dart:html';
import 'dart:async';
// TODO: move the functionality of this module into benchpress and replace this
// file with a Dart wrapper!
var _benchmarkNames = [];
_benchmarkId(index) {
return "benchmark${index}";
}
_useBenchmark(index) {
var search = window.location.search;
if (search.length > 0) {
search = search.substring(1);
}
if (search.length > 0) {
return search == _benchmarkId(index);
} else {
return true;
}
}
_onLoad(callback) {
var isReady = document.readyState == 'complete';
if (isReady) {
Timer.run(callback);
} else {
window.addEventListener('load', (event) => callback(), false);
}
}
_createBenchmarkMenu() {
var div = document.createElement('div');
div.innerHtml += '<h1>Benchmarks:</h1><a class="btn btn-default" href="?">All</a>';
for (var i=0; i<_benchmarkNames.length; i++) {
var activeClass = _useBenchmark(i) ? 'active' : '';
div.innerHtml += '<a class="btn btn-default ${activeClass}" href="?${_benchmarkId(i)}">${_benchmarkNames[i]}</a>';
}
document.body.insertBefore(div, document.body.childNodes[0]);
}
benchmark(name, stepsCreationCallback) {
_benchmarkNames.add(name);
if (_benchmarkNames.length == 2) {
_onLoad(_createBenchmarkMenu);
}
if (_useBenchmark(_benchmarkNames.length-1)) {
stepsCreationCallback();
}
}
benchmarkStep(name, callback) {
var benchmarkName = _benchmarkNames[_benchmarkNames.length-1];
js.context['benchmarkSteps'].add(new js.JsObject.jsify({
"name": benchmarkName + '#' + name,
"fn": new js.JsFunction.withThis((_) => callback())
}));
}
-55
View File
@@ -1,55 +0,0 @@
// TODO: move the functionality of this module into benchpress itself!
var benchmarkNames = [];
function benchmarkId(index) {
return 'benchmark' + index;
}
function useBenchmark(index) {
var search = window.location.search;
if (search.length > 0) {
search = search.substring(1);
}
if (search.length > 0) {
return search == benchmarkId(index);
} else {
return true;
}
}
function onLoad(callback) {
var isReady = document.readyState === 'complete';
if (isReady) {
window.setTimeout(callback);
} else {
window.addEventListener('load', callback, false);
}
}
function createBenchmarkMenu() {
var div = document.createElement('div');
div.innerHTML += '<h1>Benchmarks:</h1><a class="btn btn-default" href="?">All</a>';
for (var i=0; i<benchmarkNames.length; i++) {
var activeClass = useBenchmark(i) ? 'active' : '';
div.innerHTML += ('<a class="btn btn-default '+activeClass+'" href="?'+benchmarkId(i)+'">'+benchmarkNames[i]+'</a>');
}
document.body.insertBefore(div, document.body.childNodes[0]);
}
export function benchmark(name, stepsCreationCallback) {
benchmarkNames.push(name);
if (benchmarkNames.length === 2) {
onLoad(createBenchmarkMenu);
}
if (useBenchmark(benchmarkNames.length-1)) {
stepsCreationCallback();
}
}
export function benchmarkStep(name, callback) {
var benchmarkName = benchmarkNames[benchmarkNames.length-1];
window.benchmarkSteps.push({
name: benchmarkName + '#' + name, fn: callback
});
}
+4
View File
@@ -36,6 +36,10 @@ export class CompilerCache {
}
return result;
}
clear() {
this._cache = MapWrapper.create();
}
}
/**