From d573a14119b8bee68b07a131cad502900651c3e7 Mon Sep 17 00:00:00 2001 From: Kara Erickson Date: Fri, 19 Oct 2018 19:45:24 -0700 Subject: [PATCH] fix(ivy): update tree benchmark to use ngIf (#26608) PR Close #26608 --- modules/benchmarks/e2e_test/tree_data.ts | 6 - .../src/largetable/render3/BUILD.bazel | 2 +- .../render3/protractor.on-prepare.js | 21 --- .../render3/protractor.on_prepare.js | 22 +++ modules/benchmarks/src/tree/BUILD.bazel | 12 ++ .../benchmarks/src/tree/render3/BUILD.bazel | 51 ++++++- .../benchmarks/src/tree/render3/index.html | 5 +- modules/benchmarks/src/tree/render3/index.ts | 3 + .../src/tree/render3/protractor.on_prepare.js | 22 +++ modules/benchmarks/src/tree/render3/tree.ts | 128 ++---------------- .../src/tree/render3_function/BUILD.bazel | 2 +- .../src/tree/render3_function/index.ts | 75 ++++++++-- modules/benchmarks/src/tree/tree_perf.spec.ts | 101 ++++++++++++++ 13 files changed, 291 insertions(+), 159 deletions(-) delete mode 100644 modules/benchmarks/src/largetable/render3/protractor.on-prepare.js create mode 100644 modules/benchmarks/src/largetable/render3/protractor.on_prepare.js create mode 100644 modules/benchmarks/src/tree/render3/protractor.on_prepare.js create mode 100644 modules/benchmarks/src/tree/tree_perf.spec.ts diff --git a/modules/benchmarks/e2e_test/tree_data.ts b/modules/benchmarks/e2e_test/tree_data.ts index ca3fe381d6..d33c597f54 100644 --- a/modules/benchmarks/e2e_test/tree_data.ts +++ b/modules/benchmarks/e2e_test/tree_data.ts @@ -49,12 +49,6 @@ 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.ng2.render3_function`, url: 'all/benchmarks/src/tree/render3_function/index.html', diff --git a/modules/benchmarks/src/largetable/render3/BUILD.bazel b/modules/benchmarks/src/largetable/render3/BUILD.bazel index 776f12259b..848128851c 100644 --- a/modules/benchmarks/src/largetable/render3/BUILD.bazel +++ b/modules/benchmarks/src/largetable/render3/BUILD.bazel @@ -60,7 +60,7 @@ protractor_web_test( "@ngdeps//reflect-metadata", "@ngdeps//yargs", ], - on_prepare = ":protractor.on-prepare.js", + on_prepare = ":protractor.on_prepare.js", server = ":devserver", tags = ["ivy-only"], deps = [ diff --git a/modules/benchmarks/src/largetable/render3/protractor.on-prepare.js b/modules/benchmarks/src/largetable/render3/protractor.on-prepare.js deleted file mode 100644 index 6671d2d233..0000000000 --- a/modules/benchmarks/src/largetable/render3/protractor.on-prepare.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @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 - */ - -const protractorUtils = require('@angular/bazel/protractor-utils'); -const protractor = require('protractor'); - -module.exports = function(config) { - return protractorUtils.runServer(config.workspace, config.server, '-port', []) - .then(serverSpec => { - const serverUrl = `http://localhost:${serverSpec.port}`; - // Since the browser restarts in this benchmark we need to set both the browser.baseUrl - // for the first test and the protractor config.baseUrl for the subsequent tests - protractor.browser.baseUrl = serverUrl; - return protractor.browser.getProcessedConfig().then((config) => config.baseUrl = serverUrl); - }); -}; diff --git a/modules/benchmarks/src/largetable/render3/protractor.on_prepare.js b/modules/benchmarks/src/largetable/render3/protractor.on_prepare.js new file mode 100644 index 0000000000..509208c84e --- /dev/null +++ b/modules/benchmarks/src/largetable/render3/protractor.on_prepare.js @@ -0,0 +1,22 @@ +/** + * @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 + */ + +const protractorUtils = require('@angular/bazel/protractor-utils'); +const protractor = require('protractor'); + +module.exports = async function(config) { + const serverSpec = await protractorUtils.runServer(config.workspace, config.server, '-port', []); + + const serverUrl = `http://localhost:${serverSpec.port}`; + // Since the browser restarts in this benchmark we need to set both the browser.baseUrl + // for the first test and the protractor config.baseUrl for the subsequent tests + protractor.browser.baseUrl = serverUrl; + + const processedConfig = await protractor.browser.getProcessedConfig(); + return processedConfig.baseUrl = serverUrl; +}; diff --git a/modules/benchmarks/src/tree/BUILD.bazel b/modules/benchmarks/src/tree/BUILD.bazel index 77f2cb24bd..b8f85c5bd7 100644 --- a/modules/benchmarks/src/tree/BUILD.bazel +++ b/modules/benchmarks/src/tree/BUILD.bazel @@ -13,3 +13,15 @@ ts_library( "//packages/core", ], ) + +ts_library( + name = "perf_lib", + testonly = 1, + srcs = [ + "tree_perf.spec.ts", + ], + deps = [ + "//modules/e2e_util:lib", + "//packages:types", + ], +) diff --git a/modules/benchmarks/src/tree/render3/BUILD.bazel b/modules/benchmarks/src/tree/render3/BUILD.bazel index d2b2136846..c3a4678ec3 100644 --- a/modules/benchmarks/src/tree/render3/BUILD.bazel +++ b/modules/benchmarks/src/tree/render3/BUILD.bazel @@ -1,18 +1,63 @@ package(default_visibility = ["//visibility:public"]) -load("//tools:defaults.bzl", "ng_module") +load("//tools:defaults.bzl", "ng_module", "ng_rollup_bundle") +load("//packages/bazel:index.bzl", "protractor_web_test") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") ng_module( - name = "render3_lib", + name = "tree_lib", srcs = glob( [ "**/*.ts", ], ), + tags = ["ivy-only"], deps = [ "//modules/benchmarks/src/tree:util_lib", "//packages:types", + "//packages/common", "//packages/core", - "@rxjs", + ], +) + +ng_rollup_bundle( + name = "bundle", + entry_point = "modules/benchmarks/src/tree/render3/index.js", + tags = ["ivy-only"], + deps = [ + ":tree_lib", + ], +) + +genrule( + name = "favicon", + srcs = ["//modules/benchmarks:favicon"], + outs = ["favicon.ico"], + cmd = "cp $< $@", +) + +ts_devserver( + name = "devserver", + static_files = [ + ":bundle.min_debug.js", + ":bundle.min.js", + "index.html", + ":favicon", + ], + tags = ["ivy-only"], +) + +protractor_web_test( + name = "perf", + configuration = "//:protractor-perf.conf.js", + data = [ + "//packages/bazel/src/protractor/utils", + "//packages/benchpress", + ], + on_prepare = ":protractor.on_prepare.js", + server = ":devserver", + tags = ["ivy-only"], + deps = [ + "//modules/benchmarks/src/tree:perf_lib", ], ) diff --git a/modules/benchmarks/src/tree/render3/index.html b/modules/benchmarks/src/tree/render3/index.html index a9200438b5..b5b1ea3614 100644 --- a/modules/benchmarks/src/tree/render3/index.html +++ b/modules/benchmarks/src/tree/render3/index.html @@ -30,9 +30,8 @@ diff --git a/modules/benchmarks/src/tree/render3/index.ts b/modules/benchmarks/src/tree/render3/index.ts index 9c28ec9399..6c84b1df34 100644 --- a/modules/benchmarks/src/tree/render3/index.ts +++ b/modules/benchmarks/src/tree/render3/index.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import 'reflect-metadata'; import {ɵrenderComponent as renderComponent} from '@angular/core'; import {bindAction, profile} from '../../util'; import {TreeComponent, createDom, destroyDom, detectChanges} from './tree'; @@ -27,3 +28,5 @@ export function main() { profile(() => createDom(component), () => destroyDom(component), 'create')); } } + +main(); diff --git a/modules/benchmarks/src/tree/render3/protractor.on_prepare.js b/modules/benchmarks/src/tree/render3/protractor.on_prepare.js new file mode 100644 index 0000000000..509208c84e --- /dev/null +++ b/modules/benchmarks/src/tree/render3/protractor.on_prepare.js @@ -0,0 +1,22 @@ +/** + * @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 + */ + +const protractorUtils = require('@angular/bazel/protractor-utils'); +const protractor = require('protractor'); + +module.exports = async function(config) { + const serverSpec = await protractorUtils.runServer(config.workspace, config.server, '-port', []); + + const serverUrl = `http://localhost:${serverSpec.port}`; + // Since the browser restarts in this benchmark we need to set both the browser.baseUrl + // for the first test and the protractor config.baseUrl for the subsequent tests + protractor.browser.baseUrl = serverUrl; + + const processedConfig = await protractor.browser.getProcessedConfig(); + return processedConfig.baseUrl = serverUrl; +}; diff --git a/modules/benchmarks/src/tree/render3/tree.ts b/modules/benchmarks/src/tree/render3/tree.ts index 25aae817a7..e6622edebd 100644 --- a/modules/benchmarks/src/tree/render3/tree.ts +++ b/modules/benchmarks/src/tree/render3/tree.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ɵRenderFlags, ɵbind, ɵcontainer, ɵcontainerRefreshEnd, ɵcontainerRefreshStart, ɵdefineComponent, ɵdetectChanges, ɵelementEnd, ɵelementProperty, ɵelementStart, ɵelementStyleProp, ɵelementStyling as s, ɵembeddedViewEnd, ɵembeddedViewStart, ɵinterpolation1, ɵtext, ɵtextBinding as ɵtextBinding} from '@angular/core'; +import {CommonModule} from '@angular/common'; +import {Component, NgModule, ɵdetectChanges} from '@angular/core'; import {TreeNode, buildTree, emptyTree} from '../util'; @@ -30,122 +31,17 @@ export function detectChanges(component: TreeComponent) { numberOfChecksEl.textContent = `${detectChangesRuns}`; } -const c0 = ['background-color']; +@Component({ + selector: 'tree', + inputs: ['data'], + template: + ` {{data.value}} ` +}) export class TreeComponent { - data: TreeNode = emptyTree; - - /** @nocollapse */ - static ngComponentDef = ɵdefineComponent({ - type: TreeComponent, - selectors: [['tree']], - consts: 4, - vars: 1, - template: function(rf: ɵRenderFlags, ctx: TreeComponent) { - if (rf & ɵRenderFlags.Create) { - ɵelementStart(0, 'span'); - s(null, c0); - { ɵtext(1); } - ɵelementEnd(); - ɵcontainer(2); - ɵcontainer(3); - } - if (rf & ɵRenderFlags.Update) { - ɵelementStyleProp(0, 0, ctx.data.depth % 2 ? '' : 'grey'); - ɵtextBinding(1, ɵinterpolation1(' ', ctx.data.value, ' ')); - ɵcontainerRefreshStart(2); - { - if (ctx.data.left != null) { - let rf0 = ɵembeddedViewStart(0, 1, 1); - { - if (rf0 & ɵRenderFlags.Create) { - ɵelementStart(0, 'tree'); - ɵelementEnd(); - } - if (rf0 & ɵRenderFlags.Update) { - ɵelementProperty(0, 'data', ɵbind(ctx.data.left)); - } - } - ɵembeddedViewEnd(); - } - } - ɵcontainerRefreshEnd(); - ɵcontainerRefreshStart(3); - { - if (ctx.data.right != null) { - let rf0 = ɵembeddedViewStart(0, 1, 1); - { - if (rf0 & ɵRenderFlags.Create) { - ɵelementStart(0, 'tree'); - ɵelementEnd(); - } - if (rf0 & ɵRenderFlags.Update) { - ɵelementProperty(0, 'data', ɵbind(ctx.data.right)); - } - } - ɵembeddedViewEnd(); - } - } - ɵcontainerRefreshEnd(); - } - }, - factory: () => new TreeComponent, - inputs: {data: 'data'}, - directives: () => [TreeComponent] - }); + data: any = emptyTree; + get bgColor() { return this.data.depth % 2 ? '' : 'grey'; } } -export class TreeFunction { - data: TreeNode = emptyTree; - - /** @nocollapse */ - static ngComponentDef = ɵdefineComponent({ - type: TreeFunction, - selectors: [['tree']], - consts: 5, - vars: 1, - template: function(rf: ɵRenderFlags, ctx: TreeFunction) { - // bit of a hack - TreeTpl(rf, ctx.data); - }, - factory: () => new TreeFunction, - inputs: {data: 'data'} - }); -} - -const c1 = ['background-color']; -export function TreeTpl(rf: ɵRenderFlags, ctx: TreeNode) { - if (rf & ɵRenderFlags.Create) { - ɵelementStart(0, 'tree'); - { - ɵelementStart(1, 'span'); - s(null, c1); - { ɵtext(2); } - ɵelementEnd(); - ɵcontainer(3); - ɵcontainer(4); - } - ɵelementEnd(); - } - if (rf & ɵRenderFlags.Update) { - ɵelementStyleProp(1, 0, ctx.depth % 2 ? '' : 'grey'); - ɵtextBinding(2, ɵinterpolation1(' ', ctx.value, ' ')); - ɵcontainerRefreshStart(3); - { - if (ctx.left != null) { - let rf0 = ɵembeddedViewStart(0, 5, 1); - { TreeTpl(rf0, ctx.left); } - ɵembeddedViewEnd(); - } - } - ɵcontainerRefreshEnd(); - ɵcontainerRefreshStart(4); - { - if (ctx.right != null) { - let rf0 = ɵembeddedViewStart(0, 5, 1); - { TreeTpl(rf0, ctx.right); } - ɵembeddedViewEnd(); - } - } - ɵcontainerRefreshEnd(); - } +@NgModule({declarations: [TreeComponent], imports: [CommonModule]}) +export class TreeModule { } diff --git a/modules/benchmarks/src/tree/render3_function/BUILD.bazel b/modules/benchmarks/src/tree/render3_function/BUILD.bazel index 91236e044d..1e8adc00de 100644 --- a/modules/benchmarks/src/tree/render3_function/BUILD.bazel +++ b/modules/benchmarks/src/tree/render3_function/BUILD.bazel @@ -11,7 +11,7 @@ ng_module( ), deps = [ "//modules/benchmarks/src/tree:util_lib", - "//modules/benchmarks/src/tree/render3:render3_lib", + "//modules/benchmarks/src/tree/render3:tree_lib", "//packages:types", "//packages/core", "@rxjs", diff --git a/modules/benchmarks/src/tree/render3_function/index.ts b/modules/benchmarks/src/tree/render3_function/index.ts index 3c4b0dc978..afb084ac76 100644 --- a/modules/benchmarks/src/tree/render3_function/index.ts +++ b/modules/benchmarks/src/tree/render3_function/index.ts @@ -6,9 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ -import {ɵrenderComponent as renderComponent} from '@angular/core'; +import {ɵRenderFlags, ɵcontainer, ɵcontainerRefreshEnd, ɵcontainerRefreshStart, ɵdefineComponent, ɵelementEnd, ɵelementStart, ɵelementStyleProp, ɵelementStyling, ɵembeddedViewEnd, ɵembeddedViewStart, ɵinterpolation1, ɵrenderComponent as renderComponent, ɵtext, ɵtextBinding} from '@angular/core'; + import {bindAction, profile} from '../../util'; -import {TreeFunction, createDom, destroyDom, detectChanges} from '../render3/tree'; +import {createDom, destroyDom, detectChanges} from '../render3/tree'; +import {TreeNode, emptyTree} from '../util'; function noop() {} @@ -16,14 +18,71 @@ export function main() { let component: TreeFunction; if (typeof window !== 'undefined') { component = renderComponent(TreeFunction); - bindAction('#createDom', () => createDom(component)); - bindAction('#destroyDom', () => destroyDom(component)); - bindAction('#detectChanges', () => detectChanges(component)); + bindAction('#createDom', () => createDom(component as any)); + bindAction('#destroyDom', () => destroyDom(component as any)); + bindAction('#detectChanges', () => detectChanges(component as any)); bindAction( - '#detectChangesProfile', profile(() => detectChanges(component), noop, 'detectChanges')); - bindAction('#updateDomProfile', profile(() => createDom(component), noop, 'update')); + '#detectChangesProfile', + profile(() => detectChanges(component as any), noop, 'detectChanges')); + bindAction('#updateDomProfile', profile(() => createDom(component as any), noop, 'update')); bindAction( '#createDomProfile', - profile(() => createDom(component), () => destroyDom(component), 'create')); + profile(() => createDom(component as any), () => destroyDom(component as any), 'create')); + } +} + +export class TreeFunction { + data: TreeNode = emptyTree; + + /** @nocollapse */ + static ngComponentDef = ɵdefineComponent({ + type: TreeFunction, + selectors: [['tree']], + consts: 5, + vars: 1, + template: function(rf: ɵRenderFlags, ctx: TreeFunction) { + // bit of a hack + TreeTpl(rf, ctx.data); + }, + factory: () => new TreeFunction, + inputs: {data: 'data'} + }); +} + +const c1 = ['background-color']; +export function TreeTpl(rf: ɵRenderFlags, ctx: TreeNode) { + if (rf & ɵRenderFlags.Create) { + ɵelementStart(0, 'tree'); + { + ɵelementStart(1, 'span'); + ɵelementStyling(null, c1); + { ɵtext(2); } + ɵelementEnd(); + ɵcontainer(3); + ɵcontainer(4); + } + ɵelementEnd(); + } + if (rf & ɵRenderFlags.Update) { + ɵelementStyleProp(1, 0, ctx.depth % 2 ? '' : 'grey'); + ɵtextBinding(2, ɵinterpolation1(' ', ctx.value, ' ')); + ɵcontainerRefreshStart(3); + { + if (ctx.left != null) { + let rf0 = ɵembeddedViewStart(0, 5, 1); + { TreeTpl(rf0, ctx.left); } + ɵembeddedViewEnd(); + } + } + ɵcontainerRefreshEnd(); + ɵcontainerRefreshStart(4); + { + if (ctx.right != null) { + let rf0 = ɵembeddedViewStart(0, 5, 1); + { TreeTpl(rf0, ctx.right); } + ɵembeddedViewEnd(); + } + } + ɵcontainerRefreshEnd(); } } diff --git a/modules/benchmarks/src/tree/tree_perf.spec.ts b/modules/benchmarks/src/tree/tree_perf.spec.ts new file mode 100644 index 0000000000..25df3f8632 --- /dev/null +++ b/modules/benchmarks/src/tree/tree_perf.spec.ts @@ -0,0 +1,101 @@ +/** + * @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 {$, browser} from 'protractor'; + +import {openBrowser} from '../../../e2e_util/e2e_util'; +import {runBenchmark} from '../../../e2e_util/perf_util'; + +describe('benchmark render', () => { + it('should work for createDestroy', () => { + openTreeBenchmark(); + $('#createDom').click(); + expect($('#root').getText()).toContain('0'); + $('#destroyDom').click(); + expect($('#root').getText() as any).toEqual(''); + }); + + it('should work for update', () => { + openTreeBenchmark(); + $('#createDom').click(); + $('#createDom').click(); + expect($('#root').getText()).toContain('A'); + }); + + it('should work for detectChanges', () => { + openTreeBenchmark(); + $('#detectChanges').click(); + expect($('#numberOfChecks').getText()).toContain('10'); + }); + +}); + +describe('benchmarks', () => { + + it('should work for createOnly', done => { + runTreeBenchmark({ + id: 'createOnly', + prepare: () => $('#destroyDom').click(), + work: () => $('#createDom').click() + }).then(done, done.fail); + }); + + it('should work for destroy', done => { + runTreeBenchmark({ + id: 'createOnly', + prepare: () => $('#createDom').click(), + work: () => $('#destroyDom').click() + }).then(done, done.fail); + }); + + it('should work for createDestroy', done => { + runTreeBenchmark({ + id: 'createDestroy', + work: () => { + $('#destroyDom').click(); + $('#createDom').click(); + } + }).then(done, done.fail); + }); + + it('should work for update', done => { + runTreeBenchmark({id: 'update', work: () => $('#createDom').click()}).then(done, done.fail); + }); + + it('should work for detectChanges', done => { + runTreeBenchmark({ + id: 'detectChanges', + work: () => $('#detectChanges').click(), + setup: () => $('#destroyDom').click() + }).then(done, done.fail); + }); + +}); + +function runTreeBenchmark({id, prepare, setup, work}: + {id: string; prepare ? () : void; setup ? () : void; work(): void;}) { + browser.rootEl = '#root'; + return runBenchmark({ + id: id, + url: '', + ignoreBrowserSynchronization: true, + params: [{name: 'depth', value: 11}], + work: work, + prepare: prepare, + setup: setup + }); +} + +function openTreeBenchmark() { + browser.rootEl = '#root'; + openBrowser({ + url: '', + ignoreBrowserSynchronization: true, + params: [{name: 'depth', value: 4}], + }); +}