feat(benchmark): add static_tree benchmark
Static binary component tree of depth 10, i.e. 1024 components. Current numbers for `pureScriptTime` are: JavaScript: Baseline: 27.10+-9% Ng2: 26.84+-8% Ng1: 55.30+-14% Dart: Baseline: 30.13+-4% Ng2: 45.94+-3% Ng1: 128.88+-10% I.e. in JS we are same speed as baseline right now! Some background: We had a recent change in the compiler that merges components into their parents already during compilation (#2529). This made Ng2 2x faster in this benchmark (before the Ng2 JS time was 49.59+-14%ms). Closes #3196
This commit is contained in:
parent
231962aaf7
commit
854b5b7da8
|
@ -0,0 +1,5 @@
|
||||||
|
library benchmarks.e2e_test.static_tree_perf;
|
||||||
|
|
||||||
|
main() {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
import {runClickBenchmark, verifyNoBrowserErrors} from 'angular2/src/test_lib/perf_util';
|
||||||
|
|
||||||
|
describe('ng2 static tree benchmark', function() {
|
||||||
|
|
||||||
|
var URL = 'benchmarks/src/static_tree/tree_benchmark.html';
|
||||||
|
|
||||||
|
afterEach(verifyNoBrowserErrors);
|
||||||
|
|
||||||
|
it('should log the ng stats with viewcache', function(done) {
|
||||||
|
runClickBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#ng2DestroyDom', '#ng2CreateDom'],
|
||||||
|
id: 'ng2.static.tree.create.viewcache',
|
||||||
|
params: [{name: 'viewcache', value: 'true'}]
|
||||||
|
}).then(done, done.fail);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log the ng stats without viewcache', function(done) {
|
||||||
|
runClickBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#ng2DestroyDom', '#ng2CreateDom'],
|
||||||
|
id: 'ng2.static.tree.create.plain',
|
||||||
|
params: [{name: 'viewcache', value: 'false'}]
|
||||||
|
}).then(done, done.fail);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log the ng stats (update)', function(done) {
|
||||||
|
runClickBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#ng2CreateDom'],
|
||||||
|
id: 'ng2.static.tree.update',
|
||||||
|
params: [{name: 'viewcache', value: 'true'}]
|
||||||
|
}).then(done, done.fail);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log the baseline stats', function(done) {
|
||||||
|
runClickBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#baselineDestroyDom', '#baselineCreateDom'],
|
||||||
|
id: 'baseline.tree.create',
|
||||||
|
params: [{name: 'depth', value: 9, scale: 'log2'}]
|
||||||
|
}).then(done, done.fail);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log the baseline stats (update)', function(done) {
|
||||||
|
runClickBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#baselineCreateDom'],
|
||||||
|
id: 'baseline.tree.update',
|
||||||
|
params: [{name: 'depth', value: 9, scale: 'log2'}]
|
||||||
|
}).then(done, done.fail);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -20,6 +20,9 @@
|
||||||
<li>
|
<li>
|
||||||
<a href="tree/tree_benchmark.html">Tree benchmark</a>
|
<a href="tree/tree_benchmark.html">Tree benchmark</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="static_tree/tree_benchmark.html">Static tree benchmark</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="naive_infinite_scroll/index.html">Naive infinite scroll benchmark</a>
|
<a href="naive_infinite_scroll/index.html">Naive infinite scroll benchmark</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h2>Params</h2>
|
||||||
|
<form>
|
||||||
|
<br>
|
||||||
|
Use Viewcache:
|
||||||
|
<label>
|
||||||
|
Yes<input type="radio" name="viewcache" placeholder="use viewcache" value="true" checked="checked">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
No<input type="radio" name="viewcache" placeholder="use viewcache" value="false">
|
||||||
|
</label>
|
||||||
|
<br>
|
||||||
|
<button>Apply</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<h2>Angular2 static tree benchmark (depth 10)</h2>
|
||||||
|
<p>
|
||||||
|
<button id="ng2DestroyDom">destroyDom</button>
|
||||||
|
<button id="ng2CreateDom">createDom</button>
|
||||||
|
<button id="ng2UpdateDomProfile">profile updateDom</button>
|
||||||
|
<button id="ng2CreateDomProfile">profile createDom</button>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Baseline static tree benchmark (depth 10)</h2>
|
||||||
|
<p>
|
||||||
|
<button id="baselineDestroyDom">destroyDom</button>
|
||||||
|
<button id="baselineCreateDom">createDom</button>
|
||||||
|
<button id="baselineUpdateDomProfile">profile updateDom</button>
|
||||||
|
<button id="baselineCreateDomProfile">profile createDom</button>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<app></app>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<baseline></baseline>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
$SCRIPTS$
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,316 @@
|
||||||
|
import {bootstrap, Compiler, Component, Directive, View, ViewContainerRef} from 'angular2/angular2';
|
||||||
|
|
||||||
|
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
|
||||||
|
import {reflector} from 'angular2/src/reflection/reflection';
|
||||||
|
import {ReflectionCapabilities} from 'angular2/src/reflection/reflection_capabilities';
|
||||||
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
import {List} from 'angular2/src/facade/collection';
|
||||||
|
import {window, document, gc} from 'angular2/src/facade/browser';
|
||||||
|
import {
|
||||||
|
getIntParameter,
|
||||||
|
getStringParameter,
|
||||||
|
bindAction,
|
||||||
|
windowProfile,
|
||||||
|
windowProfileEnd
|
||||||
|
} from 'angular2/src/test_lib/benchmark_util';
|
||||||
|
import {NgIf} from 'angular2/directives';
|
||||||
|
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
|
||||||
|
import {APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool';
|
||||||
|
import {bind, Binding} from 'angular2/di';
|
||||||
|
|
||||||
|
function createBindings(): List<Binding> {
|
||||||
|
var viewCacheCapacity = getStringParameter('viewcache') == 'true' ? 10000 : 0;
|
||||||
|
return [bind(APP_VIEW_POOL_CAPACITY).toValue(viewCacheCapacity)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupReflector() {
|
||||||
|
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_DEPTH = 10;
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
BrowserDomAdapter.makeCurrent();
|
||||||
|
|
||||||
|
setupReflector();
|
||||||
|
|
||||||
|
var app;
|
||||||
|
var lifeCycle;
|
||||||
|
var baselineRootTreeComponent;
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
function profile(create, destroy, name) {
|
||||||
|
return function() {
|
||||||
|
windowProfile(name + ' w GC');
|
||||||
|
var duration = 0;
|
||||||
|
var count = 0;
|
||||||
|
while (count++ < 150) {
|
||||||
|
gc();
|
||||||
|
var start = window.performance.now();
|
||||||
|
create();
|
||||||
|
duration += window.performance.now() - start;
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
windowProfileEnd(name + ' w GC');
|
||||||
|
window.console.log(`Iterations: ${count}; time: ${duration / count} ms / iteration`);
|
||||||
|
|
||||||
|
windowProfile(name + ' w/o GC');
|
||||||
|
duration = 0;
|
||||||
|
count = 0;
|
||||||
|
while (count++ < 150) {
|
||||||
|
var start = window.performance.now();
|
||||||
|
create();
|
||||||
|
duration += window.performance.now() - start;
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
windowProfileEnd(name + ' w/o GC');
|
||||||
|
window.console.log(`Iterations: ${count}; time: ${duration / count} ms / iteration`);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function noop() {}
|
||||||
|
|
||||||
|
function createData(): TreeNode {
|
||||||
|
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', '-'];
|
||||||
|
return buildTree(MAX_DEPTH, values, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ng2DestroyDom() {
|
||||||
|
app.initData = null;
|
||||||
|
lifeCycle.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ng2CreateDom() {
|
||||||
|
app.initData = createData();
|
||||||
|
lifeCycle.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
function initNg2() {
|
||||||
|
bootstrap(AppComponentWithStaticTree, createBindings())
|
||||||
|
.then((ref) => {
|
||||||
|
var injector = ref.injector;
|
||||||
|
lifeCycle = injector.get(LifeCycle);
|
||||||
|
|
||||||
|
app = ref.hostComponent;
|
||||||
|
bindAction('#ng2DestroyDom', ng2DestroyDom);
|
||||||
|
bindAction('#ng2CreateDom', ng2CreateDom);
|
||||||
|
bindAction('#ng2UpdateDomProfile', profile(ng2CreateDom, noop, 'ng2-update'));
|
||||||
|
bindAction('#ng2CreateDomProfile', profile(ng2CreateDom, ng2DestroyDom, 'ng2-create'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function baselineDestroyDom() { baselineRootTreeComponent.update(null); }
|
||||||
|
|
||||||
|
function baselineCreateDom() { baselineRootTreeComponent.update(createData()); }
|
||||||
|
|
||||||
|
function initBaseline() {
|
||||||
|
var tree = DOM.createElement('tree');
|
||||||
|
DOM.appendChild(DOM.querySelector(document, 'baseline'), tree);
|
||||||
|
baselineRootTreeComponent = new BaselineAppComponent(tree, MAX_DEPTH);
|
||||||
|
|
||||||
|
bindAction('#baselineDestroyDom', baselineDestroyDom);
|
||||||
|
bindAction('#baselineCreateDom', baselineCreateDom);
|
||||||
|
|
||||||
|
bindAction('#baselineUpdateDomProfile', profile(baselineCreateDom, noop, 'baseline-update'));
|
||||||
|
bindAction('#baselineCreateDomProfile',
|
||||||
|
profile(baselineCreateDom, baselineDestroyDom, 'baseline-create'));
|
||||||
|
}
|
||||||
|
|
||||||
|
initNg2();
|
||||||
|
initBaseline();
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://jsperf.com/nextsibling-vs-childnodes
|
||||||
|
|
||||||
|
class BaselineAppComponent {
|
||||||
|
tree: BaseLineTreeComponent = null;
|
||||||
|
constructor(public element, public depth: number) {}
|
||||||
|
update(value: TreeNode) {
|
||||||
|
if (value === null) {
|
||||||
|
this.tree = null;
|
||||||
|
DOM.clearNodes(this.element);
|
||||||
|
} else {
|
||||||
|
if (this.tree === null) {
|
||||||
|
this.tree = new BaseLineTreeComponent(this.element, this.depth);
|
||||||
|
}
|
||||||
|
this.tree.update(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var BASELINE_TREE_TEMPLATE = null;
|
||||||
|
class BaseLineTreeComponent {
|
||||||
|
static getTemplate() {
|
||||||
|
if (BASELINE_TREE_TEMPLATE === null) {
|
||||||
|
BASELINE_TREE_TEMPLATE = DOM.createTemplate('<span>_<tree></tree><tree></tree></span>');
|
||||||
|
}
|
||||||
|
return BASELINE_TREE_TEMPLATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
value: BaseLineInterpolation;
|
||||||
|
left: BaseLineTreeComponent;
|
||||||
|
right: BaseLineTreeComponent;
|
||||||
|
terminal: boolean;
|
||||||
|
|
||||||
|
constructor(public element, remainingDepth: number) {
|
||||||
|
var clone = DOM.firstChild(DOM.importIntoDoc(BaseLineTreeComponent.getTemplate().content));
|
||||||
|
DOM.appendChild(this.element, clone);
|
||||||
|
var child = clone.firstChild;
|
||||||
|
this.value = new BaseLineInterpolation(child);
|
||||||
|
this.terminal = remainingDepth === 0;
|
||||||
|
if (!this.terminal) {
|
||||||
|
child = DOM.nextSibling(child);
|
||||||
|
this.left = new BaseLineTreeComponent(child, remainingDepth - 1);
|
||||||
|
child = DOM.nextSibling(child);
|
||||||
|
this.right = new BaseLineTreeComponent(child, remainingDepth - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update(value: TreeNode) {
|
||||||
|
this.value.update(value.value);
|
||||||
|
if (!this.terminal) {
|
||||||
|
this.left.update(value.left);
|
||||||
|
this.right.update(value.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BaseLineInterpolation {
|
||||||
|
value: string;
|
||||||
|
textNode;
|
||||||
|
constructor(textNode) {
|
||||||
|
this.value = null;
|
||||||
|
this.textNode = textNode;
|
||||||
|
}
|
||||||
|
update(value: string) {
|
||||||
|
if (this.value !== value) {
|
||||||
|
this.value = value;
|
||||||
|
DOM.setText(this.textNode, value + ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StaticTreeComponentBase {
|
||||||
|
_value: TreeNode;
|
||||||
|
constructor() { this.data = null; }
|
||||||
|
set data(value: TreeNode) {
|
||||||
|
// TODO: We need an initial value as otherwise the getter for data.value will fail
|
||||||
|
// --> this should be already caught in change detection!
|
||||||
|
value = value !== null ? value : new TreeNode('', null, null);
|
||||||
|
this._value = value;
|
||||||
|
}
|
||||||
|
get data() { return this._value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'tree', properties: ['data']})
|
||||||
|
@View({directives: [], template: '<span>{{data.value}} </span>'})
|
||||||
|
class StaticTreeComponent0 extends StaticTreeComponentBase {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'tree', properties: ['data']})
|
||||||
|
@View({
|
||||||
|
directives: [StaticTreeComponent0],
|
||||||
|
template:
|
||||||
|
`<span> {{data.value}} <tree [data]='data.right'></tree><tree [data]='data.left'></tree></span>`
|
||||||
|
})
|
||||||
|
class StaticTreeComponent1 extends StaticTreeComponentBase {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'tree', properties: ['data']})
|
||||||
|
@View({
|
||||||
|
directives: [StaticTreeComponent1],
|
||||||
|
template:
|
||||||
|
`<span> {{data.value}} <tree [data]='data.right'></tree><tree [data]='data.left'></tree></span>`
|
||||||
|
})
|
||||||
|
class StaticTreeComponent2 extends StaticTreeComponentBase {
|
||||||
|
data: TreeNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'tree', properties: ['data']})
|
||||||
|
@View({
|
||||||
|
directives: [StaticTreeComponent2],
|
||||||
|
template:
|
||||||
|
`<span> {{data.value}} <tree [data]='data.right'></tree><tree [data]='data.left'></tree></span>`
|
||||||
|
})
|
||||||
|
class StaticTreeComponent3 extends StaticTreeComponentBase {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'tree', properties: ['data']})
|
||||||
|
@View({
|
||||||
|
directives: [StaticTreeComponent3],
|
||||||
|
template:
|
||||||
|
`<span> {{data.value}} <tree [data]='data.right'></tree><tree [data]='data.left'></tree></span>`
|
||||||
|
})
|
||||||
|
class StaticTreeComponent4 extends StaticTreeComponentBase {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'tree', properties: ['data']})
|
||||||
|
@View({
|
||||||
|
directives: [StaticTreeComponent4],
|
||||||
|
template:
|
||||||
|
`<span> {{data.value}} <tree [data]='data.right'></tree><tree [data]='data.left'></tree></span>`
|
||||||
|
})
|
||||||
|
class StaticTreeComponent5 extends StaticTreeComponentBase {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'tree', properties: ['data']})
|
||||||
|
@View({
|
||||||
|
directives: [StaticTreeComponent5],
|
||||||
|
template:
|
||||||
|
`<span> {{data.value}} <tree [data]='data.right'></tree><tree [data]='data.left'></tree></span>`
|
||||||
|
})
|
||||||
|
class StaticTreeComponent6 extends StaticTreeComponentBase {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'tree', properties: ['data']})
|
||||||
|
@View({
|
||||||
|
directives: [StaticTreeComponent6],
|
||||||
|
template:
|
||||||
|
`<span> {{data.value}} <tree [data]='data.right'></tree><tree [data]='data.left'></tree></span>`
|
||||||
|
})
|
||||||
|
class StaticTreeComponent7 extends StaticTreeComponentBase {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'tree', properties: ['data']})
|
||||||
|
@View({
|
||||||
|
directives: [StaticTreeComponent7],
|
||||||
|
template:
|
||||||
|
`<span> {{data.value}} <tree [data]='data.right'></tree><tree [data]='data.left'></tree></span>`
|
||||||
|
})
|
||||||
|
class StaticTreeComponent8 extends StaticTreeComponentBase {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'tree', properties: ['data']})
|
||||||
|
@View({
|
||||||
|
directives: [StaticTreeComponent8],
|
||||||
|
template:
|
||||||
|
`<span> {{data.value}} <tree [data]='data.right'></tree><tree [data]='data.left'></tree></span>`
|
||||||
|
})
|
||||||
|
class StaticTreeComponent9 extends StaticTreeComponentBase {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'app'})
|
||||||
|
@View({
|
||||||
|
directives: [StaticTreeComponent9, NgIf],
|
||||||
|
template: `<tree *ng-if="initData != null" [data]='initData'></tree>`
|
||||||
|
})
|
||||||
|
class AppComponentWithStaticTree {
|
||||||
|
initData: TreeNode;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
library benchmarks_external.e2e_test.static_tree_perf;
|
||||||
|
|
||||||
|
main() {}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import {runClickBenchmark, verifyNoBrowserErrors} from 'angular2/src/test_lib/perf_util';
|
||||||
|
|
||||||
|
describe('ng1.x tree benchmark', function() {
|
||||||
|
|
||||||
|
var URL = 'benchmarks_external/src/static_tree/tree_benchmark.html';
|
||||||
|
|
||||||
|
afterEach(verifyNoBrowserErrors);
|
||||||
|
|
||||||
|
it('should log the stats', function(done) {
|
||||||
|
runClickBenchmark(
|
||||||
|
{url: URL, buttons: ['#destroyDom', '#createDom'], id: 'ng1.static.tree', params: []})
|
||||||
|
.then(done, done.fail);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -8,6 +8,9 @@
|
||||||
<li>
|
<li>
|
||||||
<a href="tree/tree_benchmark.html">Tree benchmark</a>
|
<a href="tree/tree_benchmark.html">Tree benchmark</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="static_tree/tree_benchmark.html">Static tree benchmark</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="tree/polymer/index.html">Polymer Tree benchmark</a>
|
<a href="tree/polymer/index.html">Polymer Tree benchmark</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
// static tree benchmark in AngularDart 1.x
|
||||||
|
library static_tree_benchmark_ng10;
|
||||||
|
|
||||||
|
import 'package:angular/angular.dart';
|
||||||
|
import 'package:angular/application_factory.dart';
|
||||||
|
import 'package:angular2/src/test_lib/benchmark_util.dart';
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
var m = new Module()
|
||||||
|
..bind(CompilerConfig,
|
||||||
|
toValue: new CompilerConfig.withOptions(elementProbeEnabled: false))
|
||||||
|
..bind(ScopeDigestTTL,
|
||||||
|
toFactory: () => new ScopeDigestTTL.value(15), inject: [])
|
||||||
|
..bind(TreeComponent0)
|
||||||
|
..bind(TreeComponent1)
|
||||||
|
..bind(TreeComponent2)
|
||||||
|
..bind(TreeComponent3)
|
||||||
|
..bind(TreeComponent4)
|
||||||
|
..bind(TreeComponent5)
|
||||||
|
..bind(TreeComponent6)
|
||||||
|
..bind(TreeComponent7)
|
||||||
|
..bind(TreeComponent8)
|
||||||
|
..bind(TreeComponent9);
|
||||||
|
|
||||||
|
final injector = applicationFactory().addModule(m).run();
|
||||||
|
|
||||||
|
return injector;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_DEPTH = 10;
|
||||||
|
|
||||||
|
main() {
|
||||||
|
final injector = setup();
|
||||||
|
final zone = injector.get(VmTurnZone);
|
||||||
|
final rootScope = injector.get(Scope);
|
||||||
|
rootScope.context['initData'] = null;
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
TreeNode createData() {
|
||||||
|
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', '-'];
|
||||||
|
return buildTree(MAX_DEPTH, values, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyDom() {
|
||||||
|
zone.run(() {
|
||||||
|
rootScope.context['initData'] = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createDom() {
|
||||||
|
zone.run(() {
|
||||||
|
rootScope.context['initData'] = createData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bindAction('#destroyDom', destroyDom);
|
||||||
|
bindAction('#createDom', createDom);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'tree0',
|
||||||
|
map: const {'data': '=>data'},
|
||||||
|
template: '<span> {{data.value}} '
|
||||||
|
)
|
||||||
|
class TreeComponent0 {
|
||||||
|
var data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'tree1',
|
||||||
|
map: const {'data': '=>data'},
|
||||||
|
template: '<span> {{data.value}} <tree0 data=data.right></tree0><tree0 data=data.left></tree0>'
|
||||||
|
)
|
||||||
|
class TreeComponent1 {
|
||||||
|
var data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'tree2',
|
||||||
|
map: const {'data': '=>data'},
|
||||||
|
template: '<span> {{data.value}} <tree1 data=data.right></tree1><tree1 data=data.left></tree1>'
|
||||||
|
)
|
||||||
|
class TreeComponent2 {
|
||||||
|
var data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'tree3',
|
||||||
|
map: const {'data': '=>data'},
|
||||||
|
template: '<span> {{data.value}} <tree2 data=data.right></tree2><tree2 data=data.left></tree2>'
|
||||||
|
)
|
||||||
|
class TreeComponent3 {
|
||||||
|
var data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'tree4',
|
||||||
|
map: const {'data': '=>data'},
|
||||||
|
template: '<span> {{data.value}} <tree3 data=data.right></tree3><tree3 data=data.left></tree3>'
|
||||||
|
)
|
||||||
|
class TreeComponent4 {
|
||||||
|
var data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'tree5',
|
||||||
|
map: const {'data': '=>data'},
|
||||||
|
template: '<span> {{data.value}} <tree4 data=data.right></tree4><tree4 data=data.left></tree4>'
|
||||||
|
)
|
||||||
|
class TreeComponent5 {
|
||||||
|
var data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'tree6',
|
||||||
|
map: const {'data': '=>data'},
|
||||||
|
template: '<span> {{data.value}} <tree5 data=data.right></tree5><tree5 data=data.left></tree5>'
|
||||||
|
)
|
||||||
|
class TreeComponent6 {
|
||||||
|
var data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'tree7',
|
||||||
|
map: const {'data': '=>data'},
|
||||||
|
template: '<span> {{data.value}} <tree6 data=data.right></tree6><tree6 data=data.left></tree6>'
|
||||||
|
)
|
||||||
|
class TreeComponent7 {
|
||||||
|
var data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'tree8',
|
||||||
|
map: const {'data': '=>data'},
|
||||||
|
template: '<span> {{data.value}} <tree7 data=data.right></tree7><tree7 data=data.left></tree7>'
|
||||||
|
)
|
||||||
|
class TreeComponent8 {
|
||||||
|
var data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'tree9',
|
||||||
|
map: const {'data': '=>data'},
|
||||||
|
template: '<span> {{data.value}} <tree8 data=data.right></tree8><tree8 data=data.left></tree8>'
|
||||||
|
)
|
||||||
|
class TreeComponent9 {
|
||||||
|
var data;
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTree(maxDepth, values, curDepth) {
|
||||||
|
if (maxDepth == curDepth) return new TreeNode('');
|
||||||
|
return new TreeNode(values[curDepth],
|
||||||
|
buildTree(maxDepth, values, curDepth + 1),
|
||||||
|
buildTree(maxDepth, values, curDepth + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
class TreeNode {
|
||||||
|
var value;
|
||||||
|
TreeNode left;
|
||||||
|
TreeNode right;
|
||||||
|
TreeNode([this.value, this.left, this.right]);
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h2>AngularJS/Dart 1.x static tree benchmark (depth 10)</h2>
|
||||||
|
<p>
|
||||||
|
<button id="destroyDom">destroyDom</button>
|
||||||
|
<button id="createDom">createDom</button>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<tree9 data="initData" ng-if="initData != null" class="app"></tree9>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
$SCRIPTS$
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,70 @@
|
||||||
|
// static tree benchmark in AngularJS 1.x
|
||||||
|
import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util';
|
||||||
|
import angular = require("angular");
|
||||||
|
|
||||||
|
const MAX_DEPTH = 10;
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
angular.bootstrap(document.querySelector('.app'), ['app']);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addTreeDirective(module, level: number) {
|
||||||
|
var template;
|
||||||
|
if (level <= 0) {
|
||||||
|
template = `<span> {{data.value}}</span>`
|
||||||
|
} else {
|
||||||
|
template =
|
||||||
|
`<span> {{data.value}} <tree${level-1} data='data.right'></tree${level-1}><tree${level-1} data='data.left'></tree${level-1}></span>`;
|
||||||
|
}
|
||||||
|
module.directive(`tree${level}`, function() { return {scope: {data: '='}, template: template}; });
|
||||||
|
}
|
||||||
|
|
||||||
|
var module = angular.module('app', []);
|
||||||
|
for (var depth = 0; depth < MAX_DEPTH; depth++) {
|
||||||
|
addTreeDirective(module, depth);
|
||||||
|
}
|
||||||
|
module.config([
|
||||||
|
'$compileProvider',
|
||||||
|
function($compileProvider) { $compileProvider.debugInfoEnabled(false); }
|
||||||
|
])
|
||||||
|
.run([
|
||||||
|
'$rootScope',
|
||||||
|
function($rootScope) {
|
||||||
|
var count = 0;
|
||||||
|
$rootScope.initData = null;
|
||||||
|
|
||||||
|
bindAction('#destroyDom', destroyDom);
|
||||||
|
bindAction('#createDom', createDom);
|
||||||
|
|
||||||
|
function createData(): TreeNode {
|
||||||
|
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', '-'];
|
||||||
|
return buildTree(MAX_DEPTH, values, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyDom() {
|
||||||
|
$rootScope.$apply(function() { $rootScope.initData = null; });
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDom() {
|
||||||
|
$rootScope.$apply(function() { $rootScope.initData = createData(); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ const kServedPaths = [
|
||||||
'benchmarks/src/largetable',
|
'benchmarks/src/largetable',
|
||||||
'benchmarks/src/naive_infinite_scroll',
|
'benchmarks/src/naive_infinite_scroll',
|
||||||
'benchmarks/src/tree',
|
'benchmarks/src/tree',
|
||||||
|
'benchmarks/src/static_tree',
|
||||||
|
|
||||||
// Relative (to /modules) paths to external benchmark directories
|
// Relative (to /modules) paths to external benchmark directories
|
||||||
'benchmarks_external/src',
|
'benchmarks_external/src',
|
||||||
|
@ -36,6 +37,7 @@ const kServedPaths = [
|
||||||
'benchmarks_external/src/naive_infinite_scroll',
|
'benchmarks_external/src/naive_infinite_scroll',
|
||||||
'benchmarks_external/src/tree',
|
'benchmarks_external/src/tree',
|
||||||
'benchmarks_external/src/tree/react',
|
'benchmarks_external/src/tree/react',
|
||||||
|
'benchmarks_external/src/static_tree',
|
||||||
|
|
||||||
// Relative (to /modules) paths to example directories
|
// Relative (to /modules) paths to example directories
|
||||||
'examples/src/benchpress',
|
'examples/src/benchpress',
|
||||||
|
|
Loading…
Reference in New Issue