refactor(benchmarks): align tree benchmark with largetable benchmark
- add ng2_switch benchmark to track `ngFor` over `ngSwitch` - measure create only, createDestroy and update - simplify the created dom - always add a style binding
This commit is contained in:
parent
b4363bc8af
commit
df4c0a3d1f
|
@ -8,43 +8,70 @@
|
|||
|
||||
import {runBenchmark, verifyNoBrowserErrors} from 'e2e_util/perf_util';
|
||||
|
||||
interface Worker {
|
||||
id: string;
|
||||
prepare?(): void;
|
||||
work(): void;
|
||||
}
|
||||
|
||||
const CreateOnlyWorker: Worker = {
|
||||
id: 'createOnly',
|
||||
prepare: () => $('#destroyDom').click(),
|
||||
work: () => $('#createDom').click()
|
||||
};
|
||||
|
||||
const CreateAndDestroyWorker: Worker = {
|
||||
id: 'createDestroy',
|
||||
work: () => {
|
||||
$('#createDom').click();
|
||||
$('#destroyDom').click();
|
||||
}
|
||||
};
|
||||
|
||||
const UpdateWorker: Worker = {
|
||||
id: 'update',
|
||||
work: () => $('#createDom').click()
|
||||
};
|
||||
|
||||
describe('tree benchmark perf', () => {
|
||||
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
|
||||
[CreateOnlyWorker, CreateAndDestroyWorker, UpdateWorker].forEach((worker) => {
|
||||
describe(worker.id, () => {
|
||||
|
||||
it('should run for ng2', (done) => {
|
||||
runTreeBenchmark({
|
||||
id: 'deepTree.ng2',
|
||||
id: `deepTree.ng2.${worker.id}`,
|
||||
url: 'all/benchmarks/src/tree/ng2/index.html',
|
||||
}).then(done, done.fail);
|
||||
});
|
||||
|
||||
it('should run for ng2 static', (done) => {
|
||||
runTreeBenchmark({
|
||||
id: 'deepTree.ng2.static',
|
||||
id: `deepTree.ng2.static.${worker.id}`,
|
||||
url: 'all/benchmarks/src/tree/ng2_static/index.html',
|
||||
}).then(done, done.fail);
|
||||
});
|
||||
|
||||
it('should run for ng2 switch', (done) => {
|
||||
runTreeBenchmark({
|
||||
id: `deepTree.ng2_switch.${worker.id}`,
|
||||
url: 'all/benchmarks/src/tree/ng2_switch/index.html',
|
||||
}).then(done, done.fail);
|
||||
});
|
||||
|
||||
it('should run for the baseline', (done) => {
|
||||
runTreeBenchmark({
|
||||
id: 'deepTree.baseline',
|
||||
id: `deepTree.baseline.${worker.id}`,
|
||||
url: 'all/benchmarks/src/tree/baseline/index.html',
|
||||
ignoreBrowserSynchronization: true,
|
||||
}).then(done, done.fail);
|
||||
});
|
||||
|
||||
it('should run for the baseline dom', (done) => {
|
||||
it('should run for incremental-dom', (done) => {
|
||||
runTreeBenchmark({
|
||||
id: 'deepTree.baselineDom',
|
||||
url: 'all/benchmarks/src/tree/baseline_dom/index.html',
|
||||
ignoreBrowserSynchronization: true,
|
||||
}).then(done, done.fail);
|
||||
});
|
||||
|
||||
it('should run for the incremental dom', (done) => {
|
||||
runTreeBenchmark({
|
||||
id: 'deepTree.incrementalDom',
|
||||
id: `deepTree.incremental_dom.${worker.id}`,
|
||||
url: 'all/benchmarks/src/tree/incremental_dom/index.html',
|
||||
ignoreBrowserSynchronization: true,
|
||||
}).then(done, done.fail);
|
||||
|
@ -52,7 +79,7 @@ describe('tree benchmark perf', () => {
|
|||
|
||||
it('should run for polymer binary tree', (done) => {
|
||||
runTreeBenchmark({
|
||||
id: 'deepTree.polymer',
|
||||
id: `deepTree.polymer.${worker.id}`,
|
||||
url: 'all/benchmarks/src/tree/polymer/index.html',
|
||||
ignoreBrowserSynchronization: true,
|
||||
}).then(done, done.fail);
|
||||
|
@ -60,11 +87,13 @@ describe('tree benchmark perf', () => {
|
|||
|
||||
it('should run for polymer leaves', (done) => {
|
||||
runTreeBenchmark({
|
||||
id: 'deepTree.polymerLeaves',
|
||||
id: `deepTree.polymer_leaves.${worker.id}`,
|
||||
url: 'all/benchmarks/src/tree/polymer_leaves/index.html',
|
||||
ignoreBrowserSynchronization: true,
|
||||
}).then(done, done.fail);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function runTreeBenchmark(
|
||||
config: {id: string, url: string, ignoreBrowserSynchronization?: boolean}) {
|
||||
|
|
|
@ -24,6 +24,12 @@ describe('tree benchmark spec', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('should work for ng2 switch', () => {
|
||||
testTreeBenchmark({
|
||||
url: 'all/benchmarks/src/tree/ng2_switch/index.html',
|
||||
});
|
||||
});
|
||||
|
||||
it('should work for the baseline', () => {
|
||||
testTreeBenchmark({
|
||||
url: 'all/benchmarks/src/tree/baseline/index.html',
|
||||
|
@ -31,14 +37,7 @@ describe('tree benchmark spec', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('should work for the baseline dom', () => {
|
||||
testTreeBenchmark({
|
||||
url: 'all/benchmarks/src/tree/baseline_dom/index.html',
|
||||
ignoreBrowserSynchronization: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should work for the incremental dom', () => {
|
||||
it('should work for incremental dom', () => {
|
||||
testTreeBenchmark({
|
||||
url: 'all/benchmarks/src/tree/incremental_dom/index.html',
|
||||
ignoreBrowserSynchronization: true,
|
||||
|
@ -60,9 +59,15 @@ describe('tree benchmark spec', () => {
|
|||
});
|
||||
|
||||
function testTreeBenchmark(openConfig: {url: string, ignoreBrowserSynchronization?: boolean}) {
|
||||
openBrowser(openConfig);
|
||||
openBrowser({
|
||||
url: openConfig.url,
|
||||
ignoreBrowserSynchronization: openConfig.ignoreBrowserSynchronization,
|
||||
params: [{name: 'depth', value: 4}],
|
||||
});
|
||||
$('#createDom').click();
|
||||
expect($('#root').getText()).toContain('0');
|
||||
$('#createDom').click();
|
||||
expect($('#root').getText()).toContain('A');
|
||||
$('#destroyDom').click();
|
||||
expect($('#root').getText()).toEqual('');
|
||||
}
|
||||
|
|
|
@ -2,26 +2,26 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
<h2>Params</h2>
|
||||
<form>
|
||||
<h2>Params</h2>
|
||||
<form>
|
||||
Depth:
|
||||
<input type="number" name="depth" placeholder="depth" value="9">
|
||||
<br>
|
||||
<button>Apply</button>
|
||||
</form>
|
||||
</form>
|
||||
|
||||
<h2>Baseline tree benchmark</h2>
|
||||
<p>
|
||||
<button id="destroyDom">destroyDom</button>
|
||||
<button id="createDom">createDom</button>
|
||||
<button id="updateDomProfile">profile updateDom</button>
|
||||
<button id="createDomProfile">profile createDom</button>
|
||||
</p>
|
||||
<h2>Baseline Tree Benchmark</h2>
|
||||
<p>
|
||||
<button id="destroyDom">destroyDom</button>
|
||||
<button id="createDom">createDom</button>
|
||||
<button id="updateDomProfile">profile updateDom</button>
|
||||
<button id="createDomProfile">profile createDom</button>
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<tree id="root"></tree>
|
||||
</div>
|
||||
<div>
|
||||
<tree id="root"></tree>
|
||||
</div>
|
||||
|
||||
<script src="../../bootstrap_ng2.js"></script>
|
||||
<script src="../../bootstrap_plain.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,19 +1,18 @@
|
|||
import {bindAction, profile} from '../../util';
|
||||
import {TreeNode, buildTree, emptyTree} from '../util';
|
||||
import {BaseLineTreeComponent} from './tree';
|
||||
import {TreeComponent} from './tree';
|
||||
|
||||
export function main() {
|
||||
var app: BaseLineTreeComponent;
|
||||
var tree: TreeComponent;
|
||||
|
||||
function destroyDom() { app.update(emptyTree); }
|
||||
function destroyDom() { tree.data = emptyTree; }
|
||||
|
||||
function createDom() { app.update(buildTree()); }
|
||||
function createDom() { tree.data = buildTree(); }
|
||||
|
||||
function noop() {}
|
||||
|
||||
function init() {
|
||||
const tree: any = document.querySelector('tree');
|
||||
app = new BaseLineTreeComponent(tree);
|
||||
tree = new TreeComponent(document.querySelector('tree'));
|
||||
|
||||
bindAction('#destroyDom', destroyDom);
|
||||
bindAction('#createDom', createDom);
|
||||
|
|
|
@ -1,74 +1,61 @@
|
|||
import {__platform_browser_private__} from '@angular/platform-browser';
|
||||
import {TreeNode} from '../util';
|
||||
|
||||
// Note: We are using the DomAdapter also in the Baseline
|
||||
// so that Ng2 can actually reach the baseline. Once Ng2 is able to generate
|
||||
// code that does not use the DomAdapter any more, we should remove this.
|
||||
__platform_browser_private__.initDomAdapter();
|
||||
const getDOM = __platform_browser_private__.getDOM;
|
||||
export class TreeComponent {
|
||||
private _renderNodes: any[];
|
||||
|
||||
const BASELINE_TREE_TEMPLATE = document.createElement('template');
|
||||
BASELINE_TREE_TEMPLATE.innerHTML =
|
||||
'<span>_<template class="ng-provider"></template><template class="ng-provider"></template></span>';
|
||||
const BASELINE_IF_TEMPLATE = document.createElement('template');
|
||||
BASELINE_IF_TEMPLATE.innerHTML = '<span template="if"><tree></tree></span>';
|
||||
constructor(private _rootEl: any) {}
|
||||
|
||||
export class BaseLineTreeComponent {
|
||||
value: BaseLineInterpolation;
|
||||
left: BaseLineIf;
|
||||
right: BaseLineIf;
|
||||
constructor(public element: HTMLElement) {
|
||||
var clone = getDOM().clone(BASELINE_TREE_TEMPLATE.content.firstChild);
|
||||
getDOM().appendChild(element, clone);
|
||||
|
||||
var child = clone.firstChild;
|
||||
this.value = new BaseLineInterpolation(child);
|
||||
child = getDOM().nextSibling(child);
|
||||
this.left = new BaseLineIf(child);
|
||||
child = getDOM().nextSibling(child);
|
||||
this.right = new BaseLineIf(child);
|
||||
}
|
||||
update(value: TreeNode) {
|
||||
this.value.update(value.value);
|
||||
this.left.update(value.left);
|
||||
this.right.update(value.right);
|
||||
}
|
||||
}
|
||||
|
||||
export class BaseLineInterpolation {
|
||||
value: string;
|
||||
constructor(public textNode: Node) { this.value = null; }
|
||||
update(value: string) {
|
||||
if (this.value !== value) {
|
||||
this.value = value;
|
||||
getDOM().setText(this.textNode, value + ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class BaseLineIf {
|
||||
condition: boolean;
|
||||
component: BaseLineTreeComponent;
|
||||
constructor(public anchor: Node) {
|
||||
this.condition = false;
|
||||
this.component = null;
|
||||
}
|
||||
update(value: TreeNode) {
|
||||
var newCondition = !!value;
|
||||
if (this.condition !== newCondition) {
|
||||
this.condition = newCondition;
|
||||
if (this.component) {
|
||||
getDOM().remove(this.component.element);
|
||||
this.component = null;
|
||||
}
|
||||
if (this.condition) {
|
||||
var element = getDOM().firstChild((<any>getDOM().clone(BASELINE_IF_TEMPLATE)).content);
|
||||
this.anchor.parentNode.insertBefore(element, getDOM().nextSibling(this.anchor));
|
||||
this.component = new BaseLineTreeComponent(<HTMLElement>getDOM().firstChild(element));
|
||||
}
|
||||
}
|
||||
if (this.component) {
|
||||
this.component.update(value);
|
||||
set data(data: TreeNode) {
|
||||
if (!data.left) {
|
||||
this._destroy();
|
||||
} else if (this._renderNodes) {
|
||||
this._update(data, 0);
|
||||
} else {
|
||||
this._create(this._rootEl, data, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private _create(parentNode: any, dataNode: TreeNode, index: number) {
|
||||
if (!this._renderNodes) {
|
||||
this._renderNodes = new Array(dataNode.transitiveChildCount);
|
||||
}
|
||||
|
||||
const span = document.createElement('span');
|
||||
if (dataNode.depth % 2 === 0) {
|
||||
span.style.backgroundColor = 'grey';
|
||||
}
|
||||
parentNode.appendChild(span);
|
||||
this._renderNodes[index] = span;
|
||||
this._updateNode(span, dataNode);
|
||||
|
||||
if (dataNode.left) {
|
||||
const leftTree = document.createElement('tree');
|
||||
parentNode.appendChild(leftTree);
|
||||
this._create(leftTree, dataNode.left, index + 1);
|
||||
}
|
||||
if (dataNode.right) {
|
||||
const rightTree = document.createElement('tree');
|
||||
parentNode.appendChild(rightTree);
|
||||
this._create(rightTree, dataNode.right, index + dataNode.left.transitiveChildCount + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private _updateNode(renderNode: any, dataNode: TreeNode) {
|
||||
renderNode.textContent = ` ${dataNode.value} `;
|
||||
}
|
||||
|
||||
private _update(dataNode: TreeNode, index: number) {
|
||||
this._updateNode(this._renderNodes[index], dataNode);
|
||||
if (dataNode.left) {
|
||||
this._update(dataNode.left, index + 1);
|
||||
}
|
||||
if (dataNode.right) {
|
||||
this._update(dataNode.right, index + dataNode.left.transitiveChildCount + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private _destroy() {
|
||||
while (this._rootEl.lastChild) this._rootEl.lastChild.remove();
|
||||
this._renderNodes = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
import {bindAction, profile} from '../../util';
|
||||
import {TreeNode, buildTree, emptyTree} from '../util';
|
||||
import {createTreeTemplate, destroyTreeTemplate} from './tree';
|
||||
|
||||
export function main() {
|
||||
var app: any;
|
||||
|
||||
function destroyDom() { destroyTreeTemplate(app); }
|
||||
|
||||
function createDom() { createTreeTemplate(app, buildTree()); }
|
||||
|
||||
function noop() {}
|
||||
|
||||
function init() {
|
||||
app = document.querySelector('tree');
|
||||
|
||||
bindAction('#destroyDom', destroyDom);
|
||||
bindAction('#createDom', createDom);
|
||||
|
||||
bindAction('#updateDomProfile', profile(createDom, noop, 'update'));
|
||||
bindAction('#createDomProfile', profile(createDom, destroyDom, 'create'));
|
||||
}
|
||||
|
||||
init();
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
import {TreeNode} from '../util';
|
||||
|
||||
// template:
|
||||
// <span> {{data.value}} <span template='ngIf data.right != null'><tree
|
||||
// [data]='data.right'></tree></span><span template='ngIf data.left != null'><tree
|
||||
// [data]='data.left'></tree></span></span>
|
||||
export function createTreeTemplate(parentEl: any, data: TreeNode) {
|
||||
const rootSpan = document.createElement('span');
|
||||
parentEl.appendChild(rootSpan);
|
||||
rootSpan.appendChild(document.createTextNode(` ${data.value} `));
|
||||
|
||||
if (data.left) {
|
||||
const leftTreeSpan = document.createElement('span');
|
||||
rootSpan.appendChild(leftTreeSpan);
|
||||
const leftTree = document.createElement('tree');
|
||||
leftTreeSpan.appendChild(leftTree);
|
||||
createTreeTemplate(leftTree, data.left);
|
||||
}
|
||||
if (data.right) {
|
||||
const rightTreeSpan = document.createElement('span');
|
||||
rootSpan.appendChild(rightTreeSpan);
|
||||
const rightTree = document.createElement('tree');
|
||||
rightTreeSpan.appendChild(rightTree);
|
||||
createTreeTemplate(rightTree, data.right);
|
||||
}
|
||||
}
|
||||
|
||||
export function destroyTreeTemplate(el: any) {
|
||||
while (el.firstChild) el.removeChild(el.firstChild);
|
||||
}
|
|
@ -10,7 +10,7 @@
|
|||
<button>Apply</button>
|
||||
</form>
|
||||
|
||||
<h2>Baseline tree benchmark</h2>
|
||||
<h2>Incremental-Dom Tree Benchmark</h2>
|
||||
<p>
|
||||
<button id="destroyDom">destroyDom</button>
|
||||
<button id="createDom">createDom</button>
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import {bindAction, profile} from '../../util';
|
||||
import {TreeNode, buildTree, emptyTree} from '../util';
|
||||
import {render} from './tree';
|
||||
import {TreeComponent} from './tree';
|
||||
const {patch} = require('incremental-dom');
|
||||
|
||||
export function main() {
|
||||
var app: any;
|
||||
var tree: TreeComponent;
|
||||
|
||||
function destroyDom() { patch(app, () => render(emptyTree)); }
|
||||
function destroyDom() { tree.data = emptyTree; }
|
||||
|
||||
function createDom() { patch(app, () => render(buildTree())); }
|
||||
function createDom() { tree.data = buildTree(); }
|
||||
|
||||
function noop() {}
|
||||
|
||||
function init() {
|
||||
app = document.querySelector('tree');
|
||||
tree = new TreeComponent(document.querySelector('tree'));
|
||||
|
||||
bindAction('#destroyDom', destroyDom);
|
||||
bindAction('#createDom', createDom);
|
||||
|
|
|
@ -1,26 +1,29 @@
|
|||
import {TreeNode} from '../util';
|
||||
const {elementOpen, elementClose, text} = require('incremental-dom');
|
||||
const {patch, elementOpen, elementClose, elementOpenStart, elementOpenEnd, text, attr} =
|
||||
require('incremental-dom');
|
||||
|
||||
// template:
|
||||
// <span> {{data.value}} <span template='ngIf data.right != null'><tree
|
||||
// [data]='data.right'></tree></span><span template='ngIf data.left != null'><tree
|
||||
// [data]='data.left'></tree></span></span>
|
||||
export function render(data: TreeNode) {
|
||||
elementOpen('span', '', null);
|
||||
export class TreeComponent {
|
||||
constructor(private _rootEl: any) {}
|
||||
|
||||
set data(data: TreeNode) { patch(this._rootEl, () => this._render(data)); }
|
||||
|
||||
private _render(data: TreeNode) {
|
||||
elementOpenStart('span', '', null);
|
||||
if (data.depth % 2 === 0) {
|
||||
attr('style', 'background-color: grey');
|
||||
}
|
||||
elementOpenEnd();
|
||||
text(` ${data.value} `);
|
||||
if (data.left) {
|
||||
elementOpen('span', '', null);
|
||||
elementOpen('tree', '', null);
|
||||
render(data.left);
|
||||
elementClose('tree');
|
||||
elementClose('span');
|
||||
if (data.left) {
|
||||
elementOpen('tree', '', null);
|
||||
this._render(data.left);
|
||||
elementClose('tree');
|
||||
}
|
||||
if (data.right) {
|
||||
elementOpen('span', '', null);
|
||||
elementOpen('tree', '', null);
|
||||
render(data.right);
|
||||
this._render(data.right);
|
||||
elementClose('tree');
|
||||
elementClose('span');
|
||||
}
|
||||
elementClose('span');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,26 +2,26 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
<h2>Params</h2>
|
||||
<form>
|
||||
<h2>Params</h2>
|
||||
<form>
|
||||
Depth:
|
||||
<input type="number" name="depth" placeholder="depth" value="9">
|
||||
<br>
|
||||
<button>Apply</button>
|
||||
</form>
|
||||
</form>
|
||||
|
||||
<h2>Angular2 tree benchmark</h2>
|
||||
<p>
|
||||
<button id="destroyDom">destroyDom</button>
|
||||
<button id="createDom">createDom</button>
|
||||
<button id="updateDomProfile">profile updateDom</button>
|
||||
<button id="createDomProfile">profile createDom</button>
|
||||
</p>
|
||||
<h2>Ng2 Tree Benchmark</h2>
|
||||
<p>
|
||||
<button id="destroyDom">destroyDom</button>
|
||||
<button id="createDom">createDom</button>
|
||||
<button id="updateDomProfile">profile updateDom</button>
|
||||
<button id="createDomProfile">profile createDom</button>
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<tree id="root"></tree>
|
||||
</div>
|
||||
<div>
|
||||
<tree id="root"></tree>
|
||||
</div>
|
||||
|
||||
<script src="../../bootstrap_ng2.js"></script>
|
||||
<script src="../../bootstrap_ng2.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -7,7 +7,7 @@ import {TreeNode, emptyTree} from '../util';
|
|||
selector: 'tree',
|
||||
inputs: ['data'],
|
||||
template:
|
||||
`<span> {{data.value}} <span template='ngIf data.right != null'><tree [data]='data.right'></tree></span><span template='ngIf data.left != null'><tree [data]='data.left'></tree></span></span>`
|
||||
`<span [style.backgroundColor]="data.depth % 2 ? '' : 'grey'"> {{data.value}} </span><tree *ngIf='data.right != null' [data]='data.right'></tree><tree *ngIf='data.left != null' [data]='data.left'></tree>`
|
||||
})
|
||||
export class TreeComponent {
|
||||
data: TreeNode = emptyTree;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<button>Apply</button>
|
||||
</form>
|
||||
|
||||
<h2>Angular2 tree benchmark</h2>
|
||||
<h2>Ng2 Static Tree Benchmark</h2>
|
||||
<p>
|
||||
<button id="destroyDom">destroyDom</button>
|
||||
<button id="createDom">createDom</button>
|
||||
|
|
|
@ -5,9 +5,12 @@ import {TreeNode, emptyTree, maxDepth} from '../util';
|
|||
|
||||
function createTreeComponent(level: number, isLeaf: boolean) {
|
||||
const nextTreeEl = `tree${level+1}`;
|
||||
const template = isLeaf ?
|
||||
`<span> {{data.value}} </span>` :
|
||||
`<span> {{data.value}} <span><${nextTreeEl} [data]='data.right'></${nextTreeEl}></span><span><${nextTreeEl} [data]='data.left'></${nextTreeEl}></span></span>`;
|
||||
let template =
|
||||
`<span [style.backgroundColor]="data.depth % 2 ? '' : 'grey'"> {{data.value}} </span>`;
|
||||
if (!isLeaf) {
|
||||
template +=
|
||||
`<${nextTreeEl} [data]='data.right'></${nextTreeEl}><${nextTreeEl} [data]='data.left'></${nextTreeEl}>`;
|
||||
}
|
||||
|
||||
@Component({selector: `tree${level}`, template: template})
|
||||
class TreeComponent {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<button>Apply</button>
|
||||
</form>
|
||||
|
||||
<h2>Baseline tree benchmark</h2>
|
||||
<h2>Ng2 with NgSwitch Tree Benchmark</h2>
|
||||
<p>
|
||||
<button id="destroyDom">destroyDom</button>
|
||||
<button id="createDom">createDom</button>
|
|
@ -0,0 +1,40 @@
|
|||
import {ApplicationRef, NgModule, enableProdMode} from '@angular/core';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
|
||||
import {bindAction, profile} from '../../util';
|
||||
import {TreeNode, buildTree, emptyTree} from '../util';
|
||||
|
||||
import {AppModule, TreeComponent} from './tree';
|
||||
|
||||
export function main() {
|
||||
var tree: TreeComponent;
|
||||
var appRef: ApplicationRef;
|
||||
|
||||
function destroyDom() {
|
||||
tree.data = emptyTree;
|
||||
appRef.tick();
|
||||
}
|
||||
|
||||
function createDom() {
|
||||
tree.data = buildTree();
|
||||
appRef.tick();
|
||||
}
|
||||
|
||||
function noop() {}
|
||||
|
||||
function init() {
|
||||
enableProdMode();
|
||||
platformBrowserDynamic().bootstrapModule(AppModule).then((ref) => {
|
||||
const injector = ref.injector;
|
||||
appRef = injector.get(ApplicationRef);
|
||||
|
||||
tree = appRef.components[0].instance;
|
||||
bindAction('#destroyDom', destroyDom);
|
||||
bindAction('#createDom', createDom);
|
||||
bindAction('#updateDomProfile', profile(createDom, noop, 'update'));
|
||||
bindAction('#createDomProfile', profile(createDom, destroyDom, 'create'));
|
||||
});
|
||||
}
|
||||
|
||||
init();
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import {Component, Input, NgModule} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
|
||||
import {TreeNode, emptyTree, flattenTree} from '../util';
|
||||
|
||||
@Component({
|
||||
selector: 'tree',
|
||||
template: `<ng-container [ngSwitch]="data.depth % 2">
|
||||
<span *ngSwitchCase="0" style="background-color: grey"> {{data.value}} </span>
|
||||
<span *ngSwitchDefault> {{data.value}} </span>
|
||||
<tree *ngIf='data.right != null' [data]='data.right'></tree><tree *ngIf='data.left != null' [data]='data.left'></tree>`
|
||||
})
|
||||
export class TreeComponent {
|
||||
@Input()
|
||||
data: TreeNode = emptyTree;
|
||||
}
|
||||
|
||||
@NgModule({imports: [BrowserModule], bootstrap: [TreeComponent], declarations: [TreeComponent]})
|
||||
export class AppModule {
|
||||
}
|
|
@ -1,15 +1,13 @@
|
|||
<link rel="import" href="/all/benchmarks/vendor/polymer/polymer.html">
|
||||
<dom-module id="binary-tree">
|
||||
<template>
|
||||
<span>
|
||||
<span>{{data.value}}</span>
|
||||
<span style="[[data.style]]"> {{data.value}} </span>
|
||||
<template is="dom-if" if="[[data.left]]">
|
||||
<binary-tree data="[[data.left]]"></binary-tree>
|
||||
</template>
|
||||
<template is="dom-if" if="[[data.right]]">
|
||||
<binary-tree data="[[data.right]]"></binary-tree>
|
||||
</template>
|
||||
</span>
|
||||
</template>
|
||||
<script>
|
||||
Polymer({
|
||||
|
|
|
@ -1,29 +1,34 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<link rel="import" href="binary_tree.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h2>Params</h2>
|
||||
<form>
|
||||
<h2>Params</h2>
|
||||
<form>
|
||||
Depth:
|
||||
<input type="number" name="depth" placeholder="depth" value="9">
|
||||
<br>
|
||||
<button>Apply</button>
|
||||
</form>
|
||||
</form>
|
||||
|
||||
<h2>Polymer tree benchmark</h2>
|
||||
<p>
|
||||
<button id="destroyDom">destroyDom</button>
|
||||
<button id="createDom">createDom</button>
|
||||
</p>
|
||||
<h2>Polymer Tree Benchmark</h2>
|
||||
<p>
|
||||
<button id="destroyDom">destroyDom</button>
|
||||
<button id="createDom">createDom</button>
|
||||
<button id="updateDomProfile">profile updateDom</button>
|
||||
<button id="createDomProfile">profile createDom</button>
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<binary-tree id="root"></binary-tree>
|
||||
</div>
|
||||
<div>
|
||||
<binary-tree id="root"></binary-tree>
|
||||
</div>
|
||||
|
||||
<script src="../../bootstrap_plain.js"></script>
|
||||
<script src="../../bootstrap_plain.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,4 +1,4 @@
|
|||
import {bindAction} from '../../util';
|
||||
import {bindAction, profile} from '../../util';
|
||||
import {buildTree, emptyTree} from '../util';
|
||||
|
||||
declare var Polymer: any;
|
||||
|
@ -11,6 +11,11 @@ export function main() {
|
|||
|
||||
function createDom() { rootEl.data = buildTree(); }
|
||||
|
||||
function noop() {}
|
||||
|
||||
bindAction('#destroyDom', destroyDom);
|
||||
bindAction('#createDom', createDom);
|
||||
|
||||
bindAction('#updateDomProfile', profile(createDom, noop, 'update'));
|
||||
bindAction('#createDomProfile', profile(createDom, destroyDom, 'create'));
|
||||
}
|
||||
|
|
|
@ -1,29 +1,34 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<link rel="import" href="tree_leaf.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h2>Params</h2>
|
||||
<form>
|
||||
<h2>Params</h2>
|
||||
<form>
|
||||
Depth:
|
||||
<input type="number" name="depth" placeholder="depth" value="9">
|
||||
<br>
|
||||
<button>Apply</button>
|
||||
</form>
|
||||
</form>
|
||||
|
||||
<h2>Polymer leaves benchmark</h2>
|
||||
<p>
|
||||
<button id="destroyDom">destroyDom</button>
|
||||
<button id="createDom">createDom</button>
|
||||
</p>
|
||||
<h2>Polymer Leaves Benchmark</h2>
|
||||
<p>
|
||||
<button id="destroyDom">destroyDom</button>
|
||||
<button id="createDom">createDom</button>
|
||||
<button id="updateDomProfile">profile updateDom</button>
|
||||
<button id="createDomProfile">profile createDom</button>
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<binary-tree id="root"></binary-tree>
|
||||
</div>
|
||||
<div>
|
||||
<binary-tree id="root"></binary-tree>
|
||||
</div>
|
||||
|
||||
<script src="../../bootstrap_plain.js"></script>
|
||||
<script src="../../bootstrap_plain.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
import {bindAction} from '../../util';
|
||||
import {TreeNode, buildTree, emptyTree} from '../util';
|
||||
import {TreeNode, buildTree, emptyTree, flattenTree} from '../util';
|
||||
|
||||
declare var Polymer: any;
|
||||
|
||||
export function main() {
|
||||
const rootEl: any = document.querySelector('binary-tree');
|
||||
|
||||
rootEl.data = emptyTree;
|
||||
|
||||
function destroyDom() {
|
||||
while (rootEl.firstChild) rootEl.removeChild(rootEl.firstChild);
|
||||
}
|
||||
|
@ -16,7 +14,7 @@ export function main() {
|
|||
const flatTree = flattenTree(buildTree(), []);
|
||||
for (var i = 0; i < flatTree.length; i++) {
|
||||
const el: any = document.createElement('tree-leaf');
|
||||
el.value = flatTree[i];
|
||||
el.data = flatTree[i];
|
||||
rootEl.appendChild(el);
|
||||
}
|
||||
}
|
||||
|
@ -24,14 +22,3 @@ export function main() {
|
|||
bindAction('#destroyDom', destroyDom);
|
||||
bindAction('#createDom', createDom);
|
||||
}
|
||||
|
||||
function flattenTree(node: TreeNode, target: string[]): string[] {
|
||||
target.push(node.value);
|
||||
if (node.left) {
|
||||
flattenTree(node.left, target);
|
||||
}
|
||||
if (node.right) {
|
||||
flattenTree(node.right, target);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<link rel="import" href="/all/benchmarks/vendor/polymer/polymer.html">
|
||||
<dom-module id="tree-leaf">
|
||||
<template>
|
||||
<span>{{value}}</span>
|
||||
<span style="[[data.style]]"> {{data.value}} </span>
|
||||
</template>
|
||||
<script>
|
||||
Polymer({
|
||||
is: 'tree-leaf',
|
||||
properties: {
|
||||
value: ''
|
||||
data: {}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,36 +1,62 @@
|
|||
import {getIntParameter} from '../util';
|
||||
|
||||
export class TreeNode {
|
||||
constructor(public value: string, public left: TreeNode, public right: TreeNode) {}
|
||||
transitiveChildCount: number;
|
||||
children: TreeNode[];
|
||||
|
||||
constructor(
|
||||
public value: string, public depth: number, public maxDepth: number, public left: TreeNode,
|
||||
public right: TreeNode) {
|
||||
this.transitiveChildCount = Math.pow(2, (this.maxDepth - this.depth + 1)) - 1;
|
||||
this.children = this.left ? [this.left, this.right] : [];
|
||||
}
|
||||
|
||||
// Needed for Polymer as it does not support ternary nor modulo operator
|
||||
// in expressions
|
||||
get style(): string { return this.depth % 2 === 0 ? 'background-color: grey' : ''; }
|
||||
}
|
||||
|
||||
let treeCreateCount: number;
|
||||
export let maxDepth: number;
|
||||
let numberData: string[];
|
||||
let charData: string[];
|
||||
let numberData: TreeNode;
|
||||
let charData: TreeNode;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
maxDepth = getIntParameter('depth');
|
||||
treeCreateCount = 0;
|
||||
numberData = [];
|
||||
charData = [];
|
||||
for (let i = 0; i < maxDepth; i++) {
|
||||
numberData.push(i.toString());
|
||||
charData.push(String.fromCharCode('A'.charCodeAt(0) + i));
|
||||
}
|
||||
numberData = _buildTree(0, numberValues);
|
||||
charData = _buildTree(0, charValues);
|
||||
}
|
||||
|
||||
function _buildTree(values: string[], curDepth: number = 0): TreeNode {
|
||||
if (maxDepth === curDepth) return new TreeNode('', null, null);
|
||||
return new TreeNode(
|
||||
values[curDepth], _buildTree(values, curDepth + 1), _buildTree(values, curDepth + 1));
|
||||
function _buildTree(currDepth: number, valueFn: (depth: number) => string): TreeNode {
|
||||
const children = currDepth < maxDepth ? _buildTree(currDepth + 1, valueFn) : null;
|
||||
return new TreeNode(valueFn(currDepth), currDepth, maxDepth, children, children);
|
||||
}
|
||||
|
||||
export const emptyTree = new TreeNode('', null, null);
|
||||
export const emptyTree = new TreeNode('', 0, 0, null, null);
|
||||
|
||||
export function buildTree(): TreeNode {
|
||||
treeCreateCount++;
|
||||
return _buildTree(treeCreateCount % 2 ? numberData : charData);
|
||||
return treeCreateCount % 2 ? numberData : charData;
|
||||
}
|
||||
|
||||
function numberValues(depth: number): string {
|
||||
return depth.toString();
|
||||
}
|
||||
|
||||
function charValues(depth: number): string {
|
||||
return String.fromCharCode('A'.charCodeAt(0) + (depth % 26));
|
||||
}
|
||||
|
||||
export function flattenTree(node: TreeNode, target: TreeNode[] = []): TreeNode[] {
|
||||
target.push(node);
|
||||
if (node.left) {
|
||||
flattenTree(node.left, target);
|
||||
}
|
||||
if (node.right) {
|
||||
flattenTree(node.right, target);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue