From 0867e851635162af2a033616098b4653cafaf14f Mon Sep 17 00:00:00 2001 From: Marc Laval Date: Mon, 11 Dec 2017 18:15:57 +0100 Subject: [PATCH] perf: add large table and deep tree benchmarks for render3 (#20855) PR Close #20855 --- .../benchmarks/e2e_test/largetable_perf.ts | 9 ++ .../benchmarks/e2e_test/largetable_spec.ts | 7 + modules/benchmarks/e2e_test/tree_data.ts | 6 + .../src/largetable/render3/index.html | 34 +++++ .../src/largetable/render3/index.ts | 28 ++++ .../src/largetable/render3/table.ts | 81 ++++++++++ .../benchmarks/src/tree/render3/index.html | 36 +++++ modules/benchmarks/src/tree/render3/index.ts | 29 ++++ modules/benchmarks/src/tree/render3/tree.ts | 139 ++++++++++++++++++ 9 files changed, 369 insertions(+) create mode 100644 modules/benchmarks/src/largetable/render3/index.html create mode 100644 modules/benchmarks/src/largetable/render3/index.ts create mode 100644 modules/benchmarks/src/largetable/render3/table.ts create mode 100644 modules/benchmarks/src/tree/render3/index.html create mode 100644 modules/benchmarks/src/tree/render3/index.ts create mode 100644 modules/benchmarks/src/tree/render3/tree.ts diff --git a/modules/benchmarks/e2e_test/largetable_perf.ts b/modules/benchmarks/e2e_test/largetable_perf.ts index bc021e4578..2ae7629600 100644 --- a/modules/benchmarks/e2e_test/largetable_perf.ts +++ b/modules/benchmarks/e2e_test/largetable_perf.ts @@ -56,6 +56,15 @@ describe('largetable benchmark perf', () => { }).then(done, done.fail); }); + it('should run for render3', (done) => { + runTableBenchmark({ + id: `largeTable.render3.${worker.id}`, + url: 'all/benchmarks/src/largetable/render3/index.html', + ignoreBrowserSynchronization: true, + worker: worker + }).then(done, done.fail); + }); + it('should run for the baseline', (done) => { runTableBenchmark({ id: `largeTable.baseline.${worker.id}`, diff --git a/modules/benchmarks/e2e_test/largetable_spec.ts b/modules/benchmarks/e2e_test/largetable_spec.ts index 46510bd447..b764b07ff9 100644 --- a/modules/benchmarks/e2e_test/largetable_spec.ts +++ b/modules/benchmarks/e2e_test/largetable_spec.ts @@ -25,6 +25,13 @@ describe('largetable benchmark spec', () => { }); }); + it('should work for render3', () => { + testTableBenchmark({ + url: 'all/benchmarks/src/largetable/render3/index.html', + ignoreBrowserSynchronization: true, + }); + }); + it('should work for the baseline', () => { testTableBenchmark({ url: 'all/benchmarks/src/largetable/baseline/index.html', diff --git a/modules/benchmarks/e2e_test/tree_data.ts b/modules/benchmarks/e2e_test/tree_data.ts index 8aff156795..590f0837d4 100644 --- a/modules/benchmarks/e2e_test/tree_data.ts +++ b/modules/benchmarks/e2e_test/tree_data.ts @@ -49,6 +49,12 @@ export const Benchmarks: Benchmark[] = [ url: 'all/benchmarks/src/tree/ng2_switch/index.html', buttons: CreateDestroyButtons, }, + { + id: `deepTree.ng2.render3`, + url: 'all/benchmarks/src/tree/render3/index.html', + buttons: CreateDestroyDetectChangesButtons, + ignoreBrowserSynchronization: true, + }, { id: `deepTree.baseline`, url: 'all/benchmarks/src/tree/baseline/index.html', diff --git a/modules/benchmarks/src/largetable/render3/index.html b/modules/benchmarks/src/largetable/render3/index.html new file mode 100644 index 0000000000..107b8eb69c --- /dev/null +++ b/modules/benchmarks/src/largetable/render3/index.html @@ -0,0 +1,34 @@ + + + + +

Params

+
+ Cols: + +
+ Rows: + +
+ +
+ +

Render3 Largetable Benchmark

+

+ + + + +

+ +
+ +
+ + + + diff --git a/modules/benchmarks/src/largetable/render3/index.ts b/modules/benchmarks/src/largetable/render3/index.ts new file mode 100644 index 0000000000..3842977194 --- /dev/null +++ b/modules/benchmarks/src/largetable/render3/index.ts @@ -0,0 +1,28 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {renderComponent} from '@angular/core/src/render3/index'; + +import {bindAction, profile} from '../../util'; + +import {LargeTableComponent, createDom, destroyDom} from './table'; + +function noop() {} + +export function main() { + let component: LargeTableComponent; + if (typeof window !== 'undefined') { + component = renderComponent(LargeTableComponent, {renderer: document}); + bindAction('#createDom', () => createDom(component)); + bindAction('#destroyDom', () => destroyDom(component)); + bindAction('#updateDomProfile', profile(() => createDom(component), noop, 'update')); + bindAction( + '#createDomProfile', + profile(() => createDom(component), () => destroyDom(component), 'create')); + } +} diff --git a/modules/benchmarks/src/largetable/render3/table.ts b/modules/benchmarks/src/largetable/render3/table.ts new file mode 100644 index 0000000000..f6e26af45e --- /dev/null +++ b/modules/benchmarks/src/largetable/render3/table.ts @@ -0,0 +1,81 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {C, E, T, V, a, b, b1, c, defineComponent, detectChanges, e, rC, rc, t, v} from '@angular/core/src/render3/index'; +import {ComponentDef} from '@angular/core/src/render3/public_interfaces'; + +import {TableCell, buildTable, emptyTable} from '../util'; + +export class LargeTableComponent { + data: TableCell[][] = emptyTable; + + /** @nocollapse */ + static ngComponentDef: ComponentDef = defineComponent({ + type: LargeTableComponent, + tag: 'largetable', + template: function(ctx: LargeTableComponent, cm: boolean) { + if (cm) { + E(0, 'table'); + { + E(1, 'tbody'); + { + C(2); + c(); + } + e(); + } + e(); + } + rC(2); + { + for (let row of ctx.data) { + let cm1 = V(1); + { + if (cm1) { + E(0, 'tr'); + C(1); + c(); + e(); + } + rC(1); + { + for (let cell of row) { + let cm2 = V(2); + { + if (cm2) { + E(0, 'td'); + { T(1); } + e(); + } + a(0, 'style', b1('background-color:', cell.row % 2 ? '' : 'grey', '')); + t(1, b(cell.value)); + } + v(); + } + } + rc(); + } + v(); + } + } + rc(); + }, + factory: () => new LargeTableComponent(), + inputs: {data: 'data'} + }); +} + +export function destroyDom(component: LargeTableComponent) { + component.data = emptyTable; + detectChanges(component); +} + +export function createDom(component: LargeTableComponent) { + component.data = buildTable(); + detectChanges(component); +} diff --git a/modules/benchmarks/src/tree/render3/index.html b/modules/benchmarks/src/tree/render3/index.html new file mode 100644 index 0000000000..0b55e523e9 --- /dev/null +++ b/modules/benchmarks/src/tree/render3/index.html @@ -0,0 +1,36 @@ + + + + +

Params

+
+ Depth: + +
+ +
+ +

Render3 Tree Benchmark

+

+ + + + + + +

+ +
+ Change detection runs: +
+
+ +
+ + + + diff --git a/modules/benchmarks/src/tree/render3/index.ts b/modules/benchmarks/src/tree/render3/index.ts new file mode 100644 index 0000000000..fb3be88db1 --- /dev/null +++ b/modules/benchmarks/src/tree/render3/index.ts @@ -0,0 +1,29 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {renderComponent} from '@angular/core/src/render3/index'; +import {bindAction, profile} from '../../util'; +import {TreeComponent, createDom, destroyDom, detectChanges} from './tree'; + +function noop() {} + +export function main() { + let component: TreeComponent; + if (typeof window !== 'undefined') { + component = renderComponent(TreeComponent, {renderer: document}); + bindAction('#createDom', () => createDom(component)); + bindAction('#destroyDom', () => destroyDom(component)); + bindAction('#detectChanges', () => detectChanges(component)); + bindAction( + '#detectChangesProfile', profile(() => detectChanges(component), noop, 'detectChanges')); + bindAction('#updateDomProfile', profile(() => createDom(component), noop, 'update')); + bindAction( + '#createDomProfile', + profile(() => createDom(component), () => destroyDom(component), 'create')); + } +} diff --git a/modules/benchmarks/src/tree/render3/tree.ts b/modules/benchmarks/src/tree/render3/tree.ts new file mode 100644 index 0000000000..78a34fba19 --- /dev/null +++ b/modules/benchmarks/src/tree/render3/tree.ts @@ -0,0 +1,139 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {C, D, E, T, V, a, b, b1, c, defineComponent, detectChanges as _detectChanges, e, p, rC, rc, t, v} from '@angular/core/src/render3/index'; +import {ComponentDef} from '@angular/core/src/render3/public_interfaces'; + +import {TreeNode, buildTree, emptyTree} from '../util'; + +export function destroyDom(component: TreeComponent) { + component.data = emptyTree; + _detectChanges(component); +} + +export function createDom(component: TreeComponent) { + component.data = buildTree(); + _detectChanges(component); +} + +const numberOfChecksEl = document.getElementById('numberOfChecks') !; +let detectChangesRuns = 0; +export function detectChanges(component: TreeComponent) { + for (let i = 0; i < 10; i++) { + _detectChanges(component); + } + detectChangesRuns += 10; + numberOfChecksEl.textContent = `${detectChangesRuns}`; +} + +export class TreeComponent { + data: TreeNode = emptyTree; + + /** @nocollapse */ + static ngComponentDef: ComponentDef = defineComponent({ + type: TreeComponent, + tag: 'tree', + template: function(ctx: TreeComponent, cm: boolean) { + if (cm) { + E(0, 'span'); + { T(1); } + e(); + C(2); + c(); + C(3); + c(); + } + a(0, 'style', b1('background-color:', ctx.data.depth % 2 ? '' : 'grey', '')); + t(1, b1(' ', ctx.data.value, ' ')); + rC(2); + { + if (ctx.data.left != null) { + let cm0 = V(0); + { + if (cm0) { + E(0, TreeComponent.ngComponentDef); + { D(0, TreeComponent.ngComponentDef.n(), TreeComponent.ngComponentDef); } + e(); + } + p(0, 'data', b(ctx.data.left)); + TreeComponent.ngComponentDef.r(0, 0); + } + v(); + } + } + rc(); + rC(3); + { + if (ctx.data.right != null) { + let cm0 = V(0); + { + if (cm0) { + E(0, TreeComponent.ngComponentDef); + { D(0, TreeComponent.ngComponentDef.n(), TreeComponent.ngComponentDef); } + e(); + } + p(0, 'data', b(ctx.data.right)); + TreeComponent.ngComponentDef.r(0, 0); + } + v(); + } + } + rc(); + }, + factory: () => new TreeComponent, + inputs: {data: 'data'} + }); +} + +export class TreeFunction extends TreeComponent { + data: TreeNode = emptyTree; + + /** @nocollapse */ + static ngComponentDef: ComponentDef = defineComponent({ + type: TreeFunction, + tag: 'tree', + template: function(ctx: TreeFunction, cm: boolean) { + // bit of a hack + TreeTpl(ctx.data, cm); + }, + factory: () => new TreeFunction, + inputs: {data: 'data'} + }); +} + +export function TreeTpl(ctx: TreeNode, cm: boolean) { + if (cm) { + E(0, 'span'); + { T(1); } + e(); + C(2); + c(); + C(3); + c(); + } + a(0, 'style', b1('background-color:', ctx.depth % 2 ? '' : 'grey', '')); + t(1, b1(' ', ctx.value, ' ')); + rC(2); + { + if (ctx.left != null) { + let cm0 = V(0); + { TreeTpl(ctx.left, cm0); } + v(); + } + } + rc(); + rC(3); + { + if (ctx.right != null) { + let cm0 = V(0); + { TreeTpl(ctx.right, cm0); } + v(); + } + } + rc(); +}