From df1822fc2ac7cee4844b8cba887206da6650e37e Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Fri, 30 Sep 2016 09:09:31 -0700 Subject: [PATCH] benchmarks: add ng2_ftl and ng2_switch_ftl benchmarks (#11963) These benchmarks take the output of AoT and manually tweaks it to explore possible future changes to the compiler to produce this output directly. --- modules/benchmarks/e2e_test/tree_perf.ts | 58 +++- modules/benchmarks/e2e_test/tree_spec.ts | 30 +- modules/benchmarks/src/tree/ng2_ftl/README.md | 168 +++++++++ .../src/tree/ng2_ftl/app.ngfactory.ts | 319 ++++++++++++++++++ .../benchmarks/src/tree/ng2_ftl/ftl_util.ts | 199 +++++++++++ .../benchmarks/src/tree/ng2_ftl/index.html | 26 ++ modules/benchmarks/src/tree/ng2_ftl/index.ts | 41 +++ .../src/tree/ng2_ftl/ng_if.ngfactory.ts | 20 ++ .../src/tree/ng2_ftl/tree.ngfactory.ts | 127 +++++++ modules/benchmarks/src/tree/ng2_ftl/tree.ts | 5 + .../src/tree/ng2_ftl/tree_host.ngfactory.ts | 65 ++++ .../src/tree/ng2_static_ftl/README.md | 79 +++++ .../src/tree/ng2_static_ftl/app.ngfactory.ts | 319 ++++++++++++++++++ .../benchmarks/src/tree/ng2_static_ftl/app.ts | 1 + .../src/tree/ng2_static_ftl/ftl_util.ts | 17 + .../src/tree/ng2_static_ftl/index.html | 26 ++ .../src/tree/ng2_static_ftl/index.ts | 41 +++ .../src/tree/ng2_static_ftl/tree.ts | 7 + .../ng2_static_ftl/tree_branch.ngfactory.ts | 76 +++++ .../ng2_static_ftl/tree_leaf.ngfactory.ts | 56 +++ .../ng2_static_ftl/tree_root.ngfactory.ts | 150 ++++++++ modules/e2e_util/e2e_util.ts | 4 +- 22 files changed, 1824 insertions(+), 10 deletions(-) create mode 100644 modules/benchmarks/src/tree/ng2_ftl/README.md create mode 100644 modules/benchmarks/src/tree/ng2_ftl/app.ngfactory.ts create mode 100644 modules/benchmarks/src/tree/ng2_ftl/ftl_util.ts create mode 100644 modules/benchmarks/src/tree/ng2_ftl/index.html create mode 100644 modules/benchmarks/src/tree/ng2_ftl/index.ts create mode 100644 modules/benchmarks/src/tree/ng2_ftl/ng_if.ngfactory.ts create mode 100644 modules/benchmarks/src/tree/ng2_ftl/tree.ngfactory.ts create mode 100644 modules/benchmarks/src/tree/ng2_ftl/tree.ts create mode 100644 modules/benchmarks/src/tree/ng2_ftl/tree_host.ngfactory.ts create mode 100644 modules/benchmarks/src/tree/ng2_static_ftl/README.md create mode 100644 modules/benchmarks/src/tree/ng2_static_ftl/app.ngfactory.ts create mode 100644 modules/benchmarks/src/tree/ng2_static_ftl/app.ts create mode 100644 modules/benchmarks/src/tree/ng2_static_ftl/ftl_util.ts create mode 100644 modules/benchmarks/src/tree/ng2_static_ftl/index.html create mode 100644 modules/benchmarks/src/tree/ng2_static_ftl/index.ts create mode 100644 modules/benchmarks/src/tree/ng2_static_ftl/tree.ts create mode 100644 modules/benchmarks/src/tree/ng2_static_ftl/tree_branch.ngfactory.ts create mode 100644 modules/benchmarks/src/tree/ng2_static_ftl/tree_leaf.ngfactory.ts create mode 100644 modules/benchmarks/src/tree/ng2_static_ftl/tree_root.ngfactory.ts diff --git a/modules/benchmarks/e2e_test/tree_perf.ts b/modules/benchmarks/e2e_test/tree_perf.ts index 95d9659ed0..c9311db41d 100644 --- a/modules/benchmarks/e2e_test/tree_perf.ts +++ b/modules/benchmarks/e2e_test/tree_perf.ts @@ -44,6 +44,20 @@ describe('tree benchmark perf', () => { runTreeBenchmark({ id: `deepTree.ng2.${worker.id}`, url: 'all/benchmarks/src/tree/ng2/index.html', + work: worker.work, + prepare: worker.prepare, + }).then(done, done.fail); + }); + + it('should run for ng2 ftl', (done) => { + runTreeBenchmark({ + id: `deepTree.ng2.ftl.${worker.id}`, + url: 'all/benchmarks/src/tree/ng2_ftl/index.html', + work: worker.work, + prepare: worker.prepare, + // Can't use bundles as we use AoT generated code + // which relies on deep imports + extraParams: [{name: 'bundles', value: false}] }).then(done, done.fail); }); @@ -51,6 +65,20 @@ describe('tree benchmark perf', () => { runTreeBenchmark({ id: `deepTree.ng2.static.${worker.id}`, url: 'all/benchmarks/src/tree/ng2_static/index.html', + work: worker.work, + prepare: worker.prepare, + }).then(done, done.fail); + }); + + it('should run for ng2 static ftl', (done) => { + runTreeBenchmark({ + id: `deepTree.ng2.ftl.${worker.id}`, + url: 'all/benchmarks/src/tree/ng2_static_ftl/index.html', + work: worker.work, + prepare: worker.prepare, + // Can't use bundles as we use AoT generated code + // which relies on deep imports + extraParams: [{name: 'bundles', value: false}] }).then(done, done.fail); }); @@ -58,6 +86,8 @@ describe('tree benchmark perf', () => { runTreeBenchmark({ id: `deepTree.ng2_switch.${worker.id}`, url: 'all/benchmarks/src/tree/ng2_switch/index.html', + work: worker.work, + prepare: worker.prepare, }).then(done, done.fail); }); @@ -66,6 +96,8 @@ describe('tree benchmark perf', () => { id: `deepTree.baseline.${worker.id}`, url: 'all/benchmarks/src/tree/baseline/index.html', ignoreBrowserSynchronization: true, + work: worker.work, + prepare: worker.prepare, }).then(done, done.fail); }); @@ -74,6 +106,8 @@ describe('tree benchmark perf', () => { id: `deepTree.incremental_dom.${worker.id}`, url: 'all/benchmarks/src/tree/incremental_dom/index.html', ignoreBrowserSynchronization: true, + work: worker.work, + prepare: worker.prepare, }).then(done, done.fail); }); @@ -82,6 +116,8 @@ describe('tree benchmark perf', () => { id: `deepTree.polymer.${worker.id}`, url: 'all/benchmarks/src/tree/polymer/index.html', ignoreBrowserSynchronization: true, + work: worker.work, + prepare: worker.prepare, }).then(done, done.fail); }); @@ -90,22 +126,30 @@ describe('tree benchmark perf', () => { id: `deepTree.polymer_leaves.${worker.id}`, url: 'all/benchmarks/src/tree/polymer_leaves/index.html', ignoreBrowserSynchronization: true, + work: worker.work, + prepare: worker.prepare, }).then(done, done.fail); }); }); }); - function runTreeBenchmark( - config: {id: string, url: string, ignoreBrowserSynchronization?: boolean}) { + function runTreeBenchmark(config: { + id: string, + url: string, ignoreBrowserSynchronization?: boolean, + work: () => any, + prepare: () => any, extraParams?: {name: string, value: any}[] + }) { + let params = [{name: 'depth', value: 11}]; + if (config.extraParams) { + params = params.concat(config.extraParams); + } return runBenchmark({ id: config.id, url: config.url, ignoreBrowserSynchronization: config.ignoreBrowserSynchronization, - params: [{name: 'depth', value: 9}], - work: () => { - $('#createDom').click(); - $('#destroyDom').click(); - } + params: params, + work: config.work, + prepare: config.prepare }); } }); diff --git a/modules/benchmarks/e2e_test/tree_spec.ts b/modules/benchmarks/e2e_test/tree_spec.ts index 13bb9bac57..168517df94 100644 --- a/modules/benchmarks/e2e_test/tree_spec.ts +++ b/modules/benchmarks/e2e_test/tree_spec.ts @@ -18,12 +18,30 @@ describe('tree benchmark spec', () => { }); }); + it('should work for ng2 ftl', () => { + testTreeBenchmark({ + url: 'all/benchmarks/src/tree/ng2_ftl/index.html', + // Can't use bundles as we use AoT generated code + // which relies on deep imports + extraParams: [{name: 'bundles', value: false}] + }); + }); + it('should work for ng2 static', () => { testTreeBenchmark({ url: 'all/benchmarks/src/tree/ng2_static/index.html', }); }); + it('should work for ng2 static ftl', () => { + testTreeBenchmark({ + url: 'all/benchmarks/src/tree/ng2_static_ftl/index.html', + // Can't use bundles as we use AoT generated code + // which relies on deep imports + extraParams: [{name: 'bundles', value: false}] + }); + }); + it('should work for ng2 switch', () => { testTreeBenchmark({ url: 'all/benchmarks/src/tree/ng2_switch/index.html', @@ -58,11 +76,19 @@ describe('tree benchmark spec', () => { }); }); - function testTreeBenchmark(openConfig: {url: string, ignoreBrowserSynchronization?: boolean}) { + function testTreeBenchmark(openConfig: { + url: string, + ignoreBrowserSynchronization?: boolean, + extraParams?: {name: string, value: any}[] + }) { + let params = [{name: 'depth', value: 4}]; + if (openConfig.extraParams) { + params = params.concat(openConfig.extraParams); + } openBrowser({ url: openConfig.url, ignoreBrowserSynchronization: openConfig.ignoreBrowserSynchronization, - params: [{name: 'depth', value: 4}], + params: params, }); $('#createDom').click(); expect($('#root').getText()).toContain('0'); diff --git a/modules/benchmarks/src/tree/ng2_ftl/README.md b/modules/benchmarks/src/tree/ng2_ftl/README.md new file mode 100644 index 0000000000..14b8cb0042 --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_ftl/README.md @@ -0,0 +1,168 @@ +# Ng2 Faster Than BaseLine (FTL) Benchmark + +This benchmark was produced in a similar way as `ng2_static_ftl`, +but starting from the `ng2` benchmark, i.e. the benchmark +that only uses 1 component that contains itself via 2 `NgIf`s. + +1. Run AoT over the `TreeComponent` and `AppModule` +2. Move the `ComponentFactory` and the corresponding host view class + from `tree.ngfactory.ts` into `tree_host.ngfactory.ts` +3. Move the `NgModuleFactory` into the `app.ngfactory.ts` +4. Optimize the `tree.ngfactory.ts` (see below) + +The goal of this benchmark is to explore what kind of +code the Ng2 compiler should generate in order to get faster. +I.e. right now, the Ng2 compiler _does not_ produce this kind of code, +but hopefully will in the future. + + +## Optimizations and cleanups + +See `tree.ngfactory.ts` and `tree_leaf.ngfactory.ts`. + +Performance: + +- remove view factory functions, call the constructor of the view class directly +- remove `createInternal` and move the logic into the constructor +- generate direct calls to `detectChangesInternal` / `destroyInternal` of nested components + _and_ view containers, don't use `viewChildren` / `contentChildren` +- remove `Renderer` and `SanitizationService` to update + the dom directly via `document.createElement` / `element.appendChild` / setting + `Text.nodeValue` / `Element.style....` +- remove `AppElement` on component host elements +- custom implementation of `ViewContainerRef` that uses + the views as linked list, instead of an array (see `ftl_util`). +- custom implementation of TemplateRef which not use a closure, only a view and an index, + and the view has a factory method that switches over the index + (see `ftl_util`). +- Don't wrap Views into ViewRefs before passing to the user. +- View does not use an array to store root nodes, + but rather has a generated method `visitRootNodes` (see below) +- ViewContainer, TemplateRef and views have minimal amount of fields +- use `insertBefore` as primitive. + +Code size: +- inputs for `NgIf`, `TreeComponent` are wrapped into view class / directive wrapper method + (see `ng_if.ngfactory.ts` and `tree.ngfactory.ts`). +- helper methods `createElementAndAppend` / `createTextAndAppend` / `createAnchorAndAppend` +- remove `injectorGetInternal` assuming we can detect that nobody is injecting an `Injector` + +## Properties +- no allocation of arrays nor closures + +## Background: why `visitRootNodes`? + +* An embedded view has root nodes that need to be attached / detached + to the DOM when the view is inserted. +* An embedded view can have view containers as root nodes. I.e. the root nodes + of a view need to include the root nodes of all views in root view containers +* An embedded view can have `` as root nodes. I.e. the root + nodes of a view need to include the projects nodes, which can + include a view container, in which case they need to include the root nodes + of all included views as well. + +Previous implementation: +The generated view classes would store a (possible nested) array of root nodes +that can contain regular DOM nodes as well as ViewContainers. +The helper method `flattenNestedViewRootNodes` is used to convert this array +into a flat array of node. +However, this generates a new array and is probably hard to optimize for +a vm. + +### Solution +Generate loop functions / methods. +I.e. a method like: +``` +loopRootNodes(cb: (obj: any, ctx: any), ctx: any) { + cb(this.node0, ctx); + ... +} +``` +These methods can easily be nested, i.e. a view container +can just loop over its views and call this method, +forwarding the callback! + +Same is true for projection! +==> Tried it, no impact on the benchmark! + +### Discarded Solution 1) +Generate `attach` / `detach` method on EmbeddedView, +which will `insertBefore` the root nodes. Also +generate `project` and `unproject` methods in the caller +of a component to add / remove nodes. + +Problems: +- generates a lot of code! +- projected nodes can only be inserted into the DOM via + `insertBefore`, but never via `appendChild` as + the generated method `project` does it, + and it can do only one of these two, but not both. + +### Discarded Solution 2) +Generate a method `rootNodes` on every view that will +do produce a flattened array of nodes by generating the +right `concat` statements. + +Problems: +- allocates arrays and `concat` calls that slows things down + (an experiment showed about about 2-5%). + +## Experiments tried +- just the fact of having another base class in the prototype chain + is not a problem! +- Using a linked list over the views vs an array in ViewContainerRef + has no impact on performance, given that we use `Array.prototype.push` + for adding if possible (only tried with ngIf though...) + * Using `Array.prototype.splice` to add made benchmark 2% slower though! +- creating an array with root nodes does not make the benchmark much slower. + * Using `flattenNestedViewRootNodes` made it 5-10% slower! + * Note that this benchmark only includes `NgIf`, i.e. it only + inserts 1 entry into the array. +- creating an additional comment node for the view container, + so it is safe to do `insertBefore` + * this slows the benchmark down by 14% (added 2 comment nodes)! + ==> the number of comment nodes is important! + +## Open experiments: +- using ViewRef as a separate wrapper, compared to + using the view itself as ref. +- using AppElement with an injector, native node, ..., + compared to not having all of these fields +- using `insertAfter` instead of `insertBefore`? + +## Initial resuls: size + +File size for view class of the component + the 2 embedded view classes (without imports nor host view factory): +* before: 140 LOC +* after: 104 LOC + +## Initial results: Deep Tree Benchmark + +BENCHMARK deepTree.... +Description: +- bundles: false +- depth: 11 +- forceGc: false +- regressionSlopeMetric: scriptTime +- runId: f9ae32f0-8580-11e6-914d-9f4f8dbfb5e8 +- sampleSize: 20 +- userAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 + +...createOnly | gcAmount | gcTime | majorGcTime | pureScriptTime | renderTime | scriptTime +--------------- | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ +ng2 | 5926.64+-11% | 17.46+-5% | 0.02+-44% | 96.74+-9% | 49.72+-5% | 114.19+-8% +ng2.ftl | 584.50+-435% | 0.43+-435% | 0.00+-435% | 33.98+-7% | 50.27+-5% | 33.98+-7% +baseline | 0.00 | 0.00 | 0.00 | 15.83+-7% | 45.75+-4% | 15.83+-7% +incremental_dom | 100.82+-302% | 1.64+-321% | 0.00+-304% | 53.43+-9% | 43.96+-4% | 55.07+-13% + +...update gcAmount | gcTime | majorGcTime | pureScriptTime | renderTime | scriptTime +--------------- | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ +ng2 | 0.00 | 0.00+-435% | 0.00+-435% | 22.82+-9% | 29.52+-6% | 22.82+-9% +ng2.ftl | 219.72+-301% | 0.97+-300% | 0.00+-302% | 17.37+-10% | 29.27+-5% | 17.37+-10% +baseline | 530.73+-178% | 0.55+-281% | 0.35+-434% | 25.82+-8% | 31.67+-11% | 25.82+-8% +incremental_dom | 1057.56+-200% | 0.28+-201% | 0.00+-204% | 22.50+-9% | 28.03+-4% | 22.50+-9% + +Ratios (create, pureScriptTime): +- 2.8x faster than current implementation +- 1.5x faster than incremental DOM +- 2.1x slower than baseline diff --git a/modules/benchmarks/src/tree/ng2_ftl/app.ngfactory.ts b/modules/benchmarks/src/tree/ng2_ftl/app.ngfactory.ts new file mode 100644 index 0000000000..3e6af90477 --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_ftl/app.ngfactory.ts @@ -0,0 +1,319 @@ +/** + * This file is generated by the Angular 2 template compiler. + * Do not edit. + */ +/* tslint:disable */ + +import * as import2 from '@angular/common/src/common_module'; +import * as import5 from '@angular/common/src/localization'; +import * as import6 from '@angular/core/src/application_init'; +import * as import3 from '@angular/core/src/application_module'; +import * as import8 from '@angular/core/src/application_ref'; +import * as import19 from '@angular/core/src/application_tokens'; +import * as import31 from '@angular/core/src/change_detection/differs/iterable_differs'; +import * as import32 from '@angular/core/src/change_detection/differs/keyvalue_differs'; +import * as import24 from '@angular/core/src/console'; +import * as import17 from '@angular/core/src/di/injector'; +import * as import26 from '@angular/core/src/error_handler'; +import * as import33 from '@angular/core/src/i18n/tokens'; +import * as import25 from '@angular/core/src/i18n/tokens'; +import * as import9 from '@angular/core/src/linker/compiler'; +import * as import0 from '@angular/core/src/linker/ng_module_factory'; +import * as import15 from '@angular/core/src/linker/view_utils'; +import * as import29 from '@angular/core/src/render/api'; +import * as import30 from '@angular/core/src/security'; +import * as import7 from '@angular/core/src/testability/testability'; +import * as import22 from '@angular/core/src/zone/ng_zone'; +import * as import4 from '@angular/platform-browser/src/browser'; +import * as import16 from '@angular/platform-browser/src/browser/title'; +import * as import28 from '@angular/platform-browser/src/dom/animation_driver'; +import * as import23 from '@angular/platform-browser/src/dom/debug/ng_probe'; +import * as import13 from '@angular/platform-browser/src/dom/dom_renderer'; +import * as import27 from '@angular/platform-browser/src/dom/dom_tokens'; +import * as import20 from '@angular/platform-browser/src/dom/events/dom_events'; +import * as import11 from '@angular/platform-browser/src/dom/events/event_manager'; +import * as import10 from '@angular/platform-browser/src/dom/events/hammer_gestures'; +import * as import21 from '@angular/platform-browser/src/dom/events/key_events'; +import * as import12 from '@angular/platform-browser/src/dom/shared_styles_host'; +import * as import14 from '@angular/platform-browser/src/security/dom_sanitization_service'; + +import * as import1 from './tree'; +import * as import18 from './tree_host.ngfactory'; + +class AppModuleInjector extends import0.NgModuleInjector { + _CommonModule_0: import2.CommonModule; + _ApplicationModule_1: import3.ApplicationModule; + _BrowserModule_2: import4.BrowserModule; + _AppModule_3: import1.AppModule; + __LOCALE_ID_4: any; + __NgLocalization_5: import5.NgLocaleLocalization; + _ErrorHandler_6: any; + _ApplicationInitStatus_7: import6.ApplicationInitStatus; + _Testability_8: import7.Testability; + _ApplicationRef__9: import8.ApplicationRef_; + __ApplicationRef_10: any; + __Compiler_11: import9.Compiler; + __APP_ID_12: any; + __DOCUMENT_13: any; + __HAMMER_GESTURE_CONFIG_14: import10.HammerGestureConfig; + __EVENT_MANAGER_PLUGINS_15: any[]; + __EventManager_16: import11.EventManager; + __DomSharedStylesHost_17: import12.DomSharedStylesHost; + __AnimationDriver_18: any; + __DomRootRenderer_19: import13.DomRootRenderer_; + __RootRenderer_20: any; + __DomSanitizer_21: import14.DomSanitizerImpl; + __Sanitizer_22: any; + __ViewUtils_23: import15.ViewUtils; + __IterableDiffers_24: any; + __KeyValueDiffers_25: any; + __SharedStylesHost_26: any; + __Title_27: import16.Title; + __TRANSLATIONS_FORMAT_28: any; + constructor(parent: import17.Injector) { + super(parent, [import18.TreeComponentNgFactory], [import18.TreeComponentNgFactory]); + } + get _LOCALE_ID_4(): any { + if ((this.__LOCALE_ID_4 == (null as any))) { + (this.__LOCALE_ID_4 = (null as any)); + } + return this.__LOCALE_ID_4; + } + get _NgLocalization_5(): import5.NgLocaleLocalization { + if ((this.__NgLocalization_5 == (null as any))) { + (this.__NgLocalization_5 = new import5.NgLocaleLocalization(this._LOCALE_ID_4)); + } + return this.__NgLocalization_5; + } + get _ApplicationRef_10(): any { + if ((this.__ApplicationRef_10 == (null as any))) { + (this.__ApplicationRef_10 = this._ApplicationRef__9); + } + return this.__ApplicationRef_10; + } + get _Compiler_11(): import9.Compiler { + if ((this.__Compiler_11 == (null as any))) { + (this.__Compiler_11 = new import9.Compiler()); + } + return this.__Compiler_11; + } + get _APP_ID_12(): any { + if ((this.__APP_ID_12 == (null as any))) { + (this.__APP_ID_12 = import19._appIdRandomProviderFactory()); + } + return this.__APP_ID_12; + } + get _DOCUMENT_13(): any { + if ((this.__DOCUMENT_13 == (null as any))) { + (this.__DOCUMENT_13 = import4._document()); + } + return this.__DOCUMENT_13; + } + get _HAMMER_GESTURE_CONFIG_14(): import10.HammerGestureConfig { + if ((this.__HAMMER_GESTURE_CONFIG_14 == (null as any))) { + (this.__HAMMER_GESTURE_CONFIG_14 = new import10.HammerGestureConfig()); + } + return this.__HAMMER_GESTURE_CONFIG_14; + } + get _EVENT_MANAGER_PLUGINS_15(): any[] { + if ((this.__EVENT_MANAGER_PLUGINS_15 == (null as any))) { + (this.__EVENT_MANAGER_PLUGINS_15 = [ + new import20.DomEventsPlugin(), new import21.KeyEventsPlugin(), + new import10.HammerGesturesPlugin(this._HAMMER_GESTURE_CONFIG_14) + ]); + } + return this.__EVENT_MANAGER_PLUGINS_15; + } + get _EventManager_16(): import11.EventManager { + if ((this.__EventManager_16 == (null as any))) { + (this.__EventManager_16 = new import11.EventManager( + this._EVENT_MANAGER_PLUGINS_15, this.parent.get(import22.NgZone))); + } + return this.__EventManager_16; + } + get _DomSharedStylesHost_17(): import12.DomSharedStylesHost { + if ((this.__DomSharedStylesHost_17 == (null as any))) { + (this.__DomSharedStylesHost_17 = new import12.DomSharedStylesHost(this._DOCUMENT_13)); + } + return this.__DomSharedStylesHost_17; + } + get _AnimationDriver_18(): any { + if ((this.__AnimationDriver_18 == (null as any))) { + (this.__AnimationDriver_18 = import4._resolveDefaultAnimationDriver()); + } + return this.__AnimationDriver_18; + } + get _DomRootRenderer_19(): import13.DomRootRenderer_ { + if ((this.__DomRootRenderer_19 == (null as any))) { + (this.__DomRootRenderer_19 = new import13.DomRootRenderer_( + this._DOCUMENT_13, this._EventManager_16, this._DomSharedStylesHost_17, + this._AnimationDriver_18)); + } + return this.__DomRootRenderer_19; + } + get _RootRenderer_20(): any { + if ((this.__RootRenderer_20 == (null as any))) { + (this.__RootRenderer_20 = import23._createConditionalRootRenderer( + this._DomRootRenderer_19, this.parent.get(import23.NgProbeToken, (null as any)))); + } + return this.__RootRenderer_20; + } + get _DomSanitizer_21(): import14.DomSanitizerImpl { + if ((this.__DomSanitizer_21 == (null as any))) { + (this.__DomSanitizer_21 = new import14.DomSanitizerImpl()); + } + return this.__DomSanitizer_21; + } + get _Sanitizer_22(): any { + if ((this.__Sanitizer_22 == (null as any))) { + (this.__Sanitizer_22 = this._DomSanitizer_21); + } + return this.__Sanitizer_22; + } + get _ViewUtils_23(): import15.ViewUtils { + if ((this.__ViewUtils_23 == (null as any))) { + (this.__ViewUtils_23 = + new import15.ViewUtils(this._RootRenderer_20, this._APP_ID_12, this._Sanitizer_22)); + } + return this.__ViewUtils_23; + } + get _IterableDiffers_24(): any { + if ((this.__IterableDiffers_24 == (null as any))) { + (this.__IterableDiffers_24 = import3._iterableDiffersFactory()); + } + return this.__IterableDiffers_24; + } + get _KeyValueDiffers_25(): any { + if ((this.__KeyValueDiffers_25 == (null as any))) { + (this.__KeyValueDiffers_25 = import3._keyValueDiffersFactory()); + } + return this.__KeyValueDiffers_25; + } + get _SharedStylesHost_26(): any { + if ((this.__SharedStylesHost_26 == (null as any))) { + (this.__SharedStylesHost_26 = this._DomSharedStylesHost_17); + } + return this.__SharedStylesHost_26; + } + get _Title_27(): import16.Title { + if ((this.__Title_27 == (null as any))) { + (this.__Title_27 = new import16.Title()); + } + return this.__Title_27; + } + get _TRANSLATIONS_FORMAT_28(): any { + if ((this.__TRANSLATIONS_FORMAT_28 == (null as any))) { + (this.__TRANSLATIONS_FORMAT_28 = (null as any)); + } + return this.__TRANSLATIONS_FORMAT_28; + } + createInternal(): import1.AppModule { + this._CommonModule_0 = new import2.CommonModule(); + this._ApplicationModule_1 = new import3.ApplicationModule(); + this._BrowserModule_2 = + new import4.BrowserModule(this.parent.get(import4.BrowserModule, (null as any))); + this._AppModule_3 = new import1.AppModule(); + this._ErrorHandler_6 = import4.errorHandler(); + this._ApplicationInitStatus_7 = + new import6.ApplicationInitStatus(this.parent.get(import6.APP_INITIALIZER, (null as any))); + this._Testability_8 = new import7.Testability(this.parent.get(import22.NgZone)); + this._ApplicationRef__9 = new import8.ApplicationRef_( + this.parent.get(import22.NgZone), this.parent.get(import24.Console), this, + this._ErrorHandler_6, this, this._ApplicationInitStatus_7, + this.parent.get(import7.TestabilityRegistry, (null as any)), this._Testability_8); + return this._AppModule_3; + } + getInternal(token: any, notFoundResult: any): any { + if ((token === import2.CommonModule)) { + return this._CommonModule_0; + } + if ((token === import3.ApplicationModule)) { + return this._ApplicationModule_1; + } + if ((token === import4.BrowserModule)) { + return this._BrowserModule_2; + } + if ((token === import1.AppModule)) { + return this._AppModule_3; + } + if ((token === import25.LOCALE_ID)) { + return this._LOCALE_ID_4; + } + if ((token === import5.NgLocalization)) { + return this._NgLocalization_5; + } + if ((token === import26.ErrorHandler)) { + return this._ErrorHandler_6; + } + if ((token === import6.ApplicationInitStatus)) { + return this._ApplicationInitStatus_7; + } + if ((token === import7.Testability)) { + return this._Testability_8; + } + if ((token === import8.ApplicationRef_)) { + return this._ApplicationRef__9; + } + if ((token === import8.ApplicationRef)) { + return this._ApplicationRef_10; + } + if ((token === import9.Compiler)) { + return this._Compiler_11; + } + if ((token === import19.APP_ID)) { + return this._APP_ID_12; + } + if ((token === import27.DOCUMENT)) { + return this._DOCUMENT_13; + } + if ((token === import10.HAMMER_GESTURE_CONFIG)) { + return this._HAMMER_GESTURE_CONFIG_14; + } + if ((token === import11.EVENT_MANAGER_PLUGINS)) { + return this._EVENT_MANAGER_PLUGINS_15; + } + if ((token === import11.EventManager)) { + return this._EventManager_16; + } + if ((token === import12.DomSharedStylesHost)) { + return this._DomSharedStylesHost_17; + } + if ((token === import28.AnimationDriver)) { + return this._AnimationDriver_18; + } + if ((token === import13.DomRootRenderer)) { + return this._DomRootRenderer_19; + } + if ((token === import29.RootRenderer)) { + return this._RootRenderer_20; + } + if ((token === import14.DomSanitizer)) { + return this._DomSanitizer_21; + } + if ((token === import30.Sanitizer)) { + return this._Sanitizer_22; + } + if ((token === import15.ViewUtils)) { + return this._ViewUtils_23; + } + if ((token === import31.IterableDiffers)) { + return this._IterableDiffers_24; + } + if ((token === import32.KeyValueDiffers)) { + return this._KeyValueDiffers_25; + } + if ((token === import12.SharedStylesHost)) { + return this._SharedStylesHost_26; + } + if ((token === import16.Title)) { + return this._Title_27; + } + if ((token === import33.TRANSLATIONS_FORMAT)) { + return this._TRANSLATIONS_FORMAT_28; + } + return notFoundResult; + } + destroyInternal(): void { this._ApplicationRef__9.ngOnDestroy(); } +} +export const AppModuleNgFactory: import0.NgModuleFactory = + new import0.NgModuleFactory(AppModuleInjector, import1.AppModule); \ No newline at end of file diff --git a/modules/benchmarks/src/tree/ng2_ftl/ftl_util.ts b/modules/benchmarks/src/tree/ng2_ftl/ftl_util.ts new file mode 100644 index 0000000000..0b8c69b2fa --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_ftl/ftl_util.ts @@ -0,0 +1,199 @@ +import {ComponentFactory, ComponentRef, ElementRef, Injector, TemplateRef, ViewContainerRef, ViewRef} from '@angular/core'; + +export function unimplemented(): any { + throw new Error('unimplemented'); +} + +export interface FtlView { + context: C; + detectChangesInternal(throwOnChange: boolean): void; + createEmbeddedView?(context: NC, nodeIndex: number): FtlEmbeddedView; + destroyInternal(): void; +} + +export interface FtlEmbeddedView extends FtlView { + // Note: if the view has a view container as first node, + // create a comment node before it. This makes + // inserting a view before this view simpler! + _node0: any; + prev: FtlEmbeddedView; + next: FtlEmbeddedView; + // Purpose of the `ctx` argument: + // Allows to use top level functions, i.e. no need to create closures! + visitRootNodes(callback: (node: any, ctx: CTX) => void, ctx: CTX): void; +} + +// TODO(tbosch): FTL EmbeddedViewRefs should have no +// methods / properties at all. Because of this we can just use the FtlView for it as well! +// TODO(tbosch): We can't cast to EmbededViewRef as that also has the `rootNodes` filled +// -> would need to generate code for that as well. +// Rather: change API for FTL to allow to call View.attachBefore / View.detach +// -> faster and we don't need to flatten the root nodes! +export type FtlEmbeddedViewRef = FtlView; + +export class FtlTemplateRef implements TemplateRef { + constructor(private _index: number, private _view: FtlView) {} + get elementRef(): ElementRef { return unimplemented(); } + createEmbeddedView(context: C): any { + return this._view.createEmbeddedView(context, this._index); + } +} + +export class FtlViewContainerRef implements ViewContainerRef { + private _firstView: FtlEmbeddedView = null; + private _lastView: FtlEmbeddedView = null; + private _length = 0; + + constructor(private _anchor: any) {} + + detectChangesInternal(throwOnChange: boolean) { + let view = this._firstView; + while (view) { + view.detectChangesInternal(throwOnChange); + view = view.next; + } + } + + // TODO(tbosch): don't allow this API in FTL mode! + get element(): ElementRef { return unimplemented(); } + + // TODO(tbosch): don't allow this API in FTL mode! + get injector(): Injector { return unimplemented(); } + + // TODO(tbosch): don't allow this API in FTL mode! + get parentInjector(): Injector { return unimplemented(); } + + destroyInternal() { + let view = this._firstView; + while (view) { + view.destroyInternal(); + view = view.next; + } + } + + clear(): void { + let view = this._firstView; + while (view) { + detachView(view); + view.destroyInternal(); + view = view.next; + } + this._firstView = null; + this._lastView = null; + this._length = 0; + } + + get(index: number): any { + var result = this._firstView; + while (index > 0 && result) { + result = result.next; + index--; + } + return result; + } + + get length(): number { return this._length; }; + + createEmbeddedView(templateRef: TemplateRef, context?: C, index?: number): any { + const view = templateRef.createEmbeddedView(context); + return this.insert(view, index); + } + + createComponent( + componentFactory: ComponentFactory, index?: number, injector?: Injector, + projectableNodes?: any[][]): ComponentRef { + // TODO(tbosch): implement this! + return unimplemented(); + } + + insert(viewRef: ViewRef, index?: number): any { + const view: FtlEmbeddedView = viewRef; + let insertBeforeNode: any; + if (this._length === 0) { + this._firstView = this._lastView = view; + insertBeforeNode = this._anchor; + view.prev = null; + view.next = null; + } else if (index >= this._length) { + view.prev = this._lastView; + view.next = null; + this._lastView.next = view; + this._lastView = view; + insertBeforeNode = this._anchor; + } else { + // TODO(tbosch): implement this! + unimplemented(); + } + attachViewBefore(view, insertBeforeNode); + this._length++; + } + + detach(index?: number): any { + let view: FtlEmbeddedView; + if (this._length === 1) { + view = this._firstView; + this._firstView = this._lastView = null; + } else if (index >= this._length) { + view = this._lastView; + this._lastView = view.prev; + view.prev = null; + this._lastView.next = null; + } else { + // TODO(tbosch): implement this! + unimplemented(); + } + this._length--; + detachView(view); + return view; + } + + move(viewRef: ViewRef, currentIndex: number): ViewRef { + // TODO(tbosch): implement this! + return unimplemented(); + } + + indexOf(viewRef: ViewRef): number { + // TODO(tbosch): implement this! + return unimplemented(); + } + + remove(index?: number): void { + var view: FtlView = this.detach(index); + view.destroyInternal(); + } +} + +function attachViewBefore(view: FtlEmbeddedView, node: any) { + const parent = node.parentNode; + view.visitRootNodes(insertBefore, {parent: parent, refNode: node}); +} + +function insertBefore(node: any, ctx: {parent: any, refNode: any}) { + ctx.parent.insertBefore(node, ctx.refNode); +} + +function detachView(view: FtlEmbeddedView) { + view.visitRootNodes(remove, null); +} + +function remove(node: any, ctx: any) { + node.remove(); +} + +export function createElementAndAppend(parent: any, name: string) { + const el = document.createElement(name); + parent.appendChild(el); + return el; +} + +export function createTextAndAppend(parent: any) { + const txt = document.createTextNode(''); + parent.appendChild(txt); + return txt; +} + +export function createAnchorAndAppend(parent: any) { + const txt = document.createComment(''); + parent.appendChild(txt); + return txt; +} \ No newline at end of file diff --git a/modules/benchmarks/src/tree/ng2_ftl/index.html b/modules/benchmarks/src/tree/ng2_ftl/index.html new file mode 100644 index 0000000000..0406a00d67 --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_ftl/index.html @@ -0,0 +1,26 @@ + + + +

Params

+
+ Depth: + +
+ +
+ +

Ng2 FTL Tree Benchmark

+

+ + + + +

+ +
+ +
+ + + + \ No newline at end of file diff --git a/modules/benchmarks/src/tree/ng2_ftl/index.ts b/modules/benchmarks/src/tree/ng2_ftl/index.ts new file mode 100644 index 0000000000..6790e9057f --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_ftl/index.ts @@ -0,0 +1,41 @@ +import {ApplicationRef, NgModule, enableProdMode} from '@angular/core'; +import {platformBrowser} from '@angular/platform-browser'; + +import {bindAction, profile} from '../../util'; +import {TreeNode, buildTree, emptyTree} from '../util'; + +import {AppModuleNgFactory} from './app.ngfactory'; +import {TreeComponent} from './tree'; + +export function main() { + let tree: TreeComponent; + let appRef: ApplicationRef; + + function destroyDom() { + tree.data = emptyTree; + appRef.tick(); + } + + function createDom() { + tree.data = buildTree(); + appRef.tick(); + } + + function noop() {} + + function init() { + enableProdMode(); + platformBrowser().bootstrapModuleFactory(AppModuleNgFactory).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(); +} diff --git a/modules/benchmarks/src/tree/ng2_ftl/ng_if.ngfactory.ts b/modules/benchmarks/src/tree/ng2_ftl/ng_if.ngfactory.ts new file mode 100644 index 0000000000..b3ff2b141f --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_ftl/ng_if.ngfactory.ts @@ -0,0 +1,20 @@ +import {NgIf} from '@angular/common'; +import {TemplateRef, ViewContainerRef} from '@angular/core'; +import * as import7 from '@angular/core/src/change_detection/change_detection'; +import * as import4 from '@angular/core/src/linker/view_utils'; + +export class NgIfWrapper { + directive: NgIf; + _expr_0: any; + constructor(viewContainerRef: ViewContainerRef, templateRef: TemplateRef) { + this.directive = new NgIf(viewContainerRef, templateRef); + this._expr_0 = import7.UNINITIALIZED; + } + + updateNgIf(throwOnChange: boolean, currVal: any) { + if (import4.checkBinding(throwOnChange, this._expr_0, currVal)) { + this.directive.ngIf = currVal; + this._expr_0 = currVal; + } + } +} diff --git a/modules/benchmarks/src/tree/ng2_ftl/tree.ngfactory.ts b/modules/benchmarks/src/tree/ng2_ftl/tree.ngfactory.ts new file mode 100644 index 0000000000..9fcf948ec4 --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_ftl/tree.ngfactory.ts @@ -0,0 +1,127 @@ +/** + * This file is hand tweeked based on + * the out put of the Angular 2 template compiler + * and then hand tweeked to show possible future output. + */ +/* tslint:disable */ + +import * as import10 from '@angular/common/src/directives/ng_if'; +import * as import7 from '@angular/core/src/change_detection/change_detection'; +import * as import5 from '@angular/core/src/di/injector'; +import * as import9 from '@angular/core/src/linker/component_factory'; +import * as import2 from '@angular/core/src/linker/element'; +import * as import11 from '@angular/core/src/linker/template_ref'; +import * as import1 from '@angular/core/src/linker/view'; +import * as import6 from '@angular/core/src/linker/view_type'; +import * as import4 from '@angular/core/src/linker/view_utils'; +import * as import8 from '@angular/core/src/metadata/view'; +import * as import0 from '@angular/core/src/render/api'; +import * as import12 from '@angular/core/src/security'; + +import {FtlEmbeddedView, FtlTemplateRef, FtlView, FtlViewContainerRef, createAnchorAndAppend, createElementAndAppend, createTextAndAppend} from './ftl_util'; +import {NgIfWrapper} from './ng_if.ngfactory'; +import * as import3 from './tree'; + + +export class _View_TreeComponent0 implements FtlView { + context: import3.TreeComponent; + _el_0: any; + _text_1: any; + _anchor_2: any; + _vc_2: FtlViewContainerRef; + _TemplateRef_2_5: any; + _NgIf_2_6: NgIfWrapper; + _anchor_3: any; + _vc_3: FtlViewContainerRef; + _TemplateRef_3_5: any; + _NgIf_3_6: NgIfWrapper; + _expr_0: any; + _expr_1: any; + _expr_2: any; + constructor(parentRenderNode: any) { + this.context = new import3.TreeComponent(); + this._el_0 = createElementAndAppend(parentRenderNode, 'span'); + this._text_1 = createTextAndAppend(this._el_0); + this._anchor_2 = createAnchorAndAppend(parentRenderNode); + this._TemplateRef_2_5 = new FtlTemplateRef(2, this); + this._vc_2 = new FtlViewContainerRef(this._anchor_2); + this._NgIf_2_6 = new NgIfWrapper(this._vc_2, this._TemplateRef_2_5); + this._anchor_3 = createAnchorAndAppend(parentRenderNode); + this._TemplateRef_3_5 = new FtlTemplateRef(3, this); + this._vc_3 = new FtlViewContainerRef(this._anchor_3); + this._NgIf_3_6 = new NgIfWrapper(this._vc_3, this._TemplateRef_3_5); + this._expr_0 = import7.UNINITIALIZED; + this._expr_1 = import7.UNINITIALIZED; + this._expr_2 = import7.UNINITIALIZED; + } + detectChangesInternal(throwOnChange: boolean): void { + this._NgIf_2_6.updateNgIf(throwOnChange, (this.context.data.right != (null as any))); + this._NgIf_3_6.updateNgIf(throwOnChange, (this.context.data.left != (null as any))); + this._vc_2.detectChangesInternal(throwOnChange); + this._vc_3.detectChangesInternal(throwOnChange); + const currVal_0: any = ((this.context.data.depth % 2) ? '' : 'grey'); + if (import4.checkBinding(throwOnChange, this._expr_0, currVal_0)) { + this._el_0.style.backgroundColor = currVal_0; + this._expr_0 = currVal_0; + } + const currVal_1: any = import4.interpolate(1, ' ', this.context.data.value, ' '); + if (import4.checkBinding(throwOnChange, this._expr_1, currVal_1)) { + this._text_1.nodeValue = currVal_1; + this._expr_1 = currVal_1; + } + } + destroyInternal() { + this._vc_2.destroyInternal(); + this._vc_3.destroyInternal(); + } + updateData(throwOnChange: boolean, currVal: any) { + if (import4.checkBinding(throwOnChange, this._expr_2, currVal)) { + this.context.data = currVal; + this._expr_2 = currVal; + } + } + createEmbeddedView(context: any, nodeIndex: number): any { + switch (nodeIndex) { + case 2: + return new _View_TreeComponent1(this, context); + case 3: + return new _View_TreeComponent2(this, context); + default: + return null; + } + } +} + +class _View_TreeComponent1 implements FtlEmbeddedView { + _node0: any; + _TreeComponent_0_4: _View_TreeComponent0; + prev: FtlEmbeddedView; + next: FtlEmbeddedView; + constructor(private parent: _View_TreeComponent0, public context: any) { + this._node0 = document.createElement('tree'); + this._TreeComponent_0_4 = new _View_TreeComponent0(this._node0); + } + detectChangesInternal(throwOnChange: boolean): void { + this._TreeComponent_0_4.updateData(throwOnChange, this.parent.context.data.right); + this._TreeComponent_0_4.detectChangesInternal(throwOnChange); + } + visitRootNodes(cb: (...args: any[]) => void, ctx: any) { cb(this._node0, ctx); } + destroyInternal() { this._TreeComponent_0_4.destroyInternal(); } +} + +class _View_TreeComponent2 implements FtlEmbeddedView { + _node0: any; + _TreeComponent_0_4: _View_TreeComponent0; + prev: FtlEmbeddedView; + next: FtlEmbeddedView; + constructor(private parent: _View_TreeComponent0, public context: any) { + this._node0 = document.createElement('tree'); + this._TreeComponent_0_4 = new _View_TreeComponent0(this._node0); + } + detectChangesInternal(throwOnChange: boolean): void { + this._TreeComponent_0_4.updateData(throwOnChange, this.parent.context.data.left); + this._TreeComponent_0_4.detectChangesInternal(throwOnChange); + } + visitRootNodes(cb: (...args: any[]) => void, ctx: any) { cb(this._node0, ctx); } + destroyInternal() { this._TreeComponent_0_4.destroyInternal(); } +} diff --git a/modules/benchmarks/src/tree/ng2_ftl/tree.ts b/modules/benchmarks/src/tree/ng2_ftl/tree.ts new file mode 100644 index 0000000000..aef20567f4 --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_ftl/tree.ts @@ -0,0 +1,5 @@ +import {TreeNode, emptyTree} from '../util'; + +export class TreeComponent { data: TreeNode = emptyTree; } + +export class AppModule {} diff --git a/modules/benchmarks/src/tree/ng2_ftl/tree_host.ngfactory.ts b/modules/benchmarks/src/tree/ng2_ftl/tree_host.ngfactory.ts new file mode 100644 index 0000000000..93545376f8 --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_ftl/tree_host.ngfactory.ts @@ -0,0 +1,65 @@ +/** + * This file is generated by the Angular 2 template compiler. + * Do not edit. + */ +/* tslint:disable */ + +import * as import10 from '@angular/common/src/directives/ng_if'; +import * as import7 from '@angular/core/src/change_detection/change_detection'; +import * as import5 from '@angular/core/src/di/injector'; +import * as import9 from '@angular/core/src/linker/component_factory'; +import * as import2 from '@angular/core/src/linker/element'; +import * as import11 from '@angular/core/src/linker/template_ref'; +import * as import1 from '@angular/core/src/linker/view'; +import * as import6 from '@angular/core/src/linker/view_type'; +import * as import4 from '@angular/core/src/linker/view_utils'; +import * as import8 from '@angular/core/src/metadata/view'; +import * as import0 from '@angular/core/src/render/api'; +import * as import12 from '@angular/core/src/security'; + +import * as import3 from './tree'; +import {_View_TreeComponent0} from './tree.ngfactory'; + +var renderType_TreeComponent_Host: import0.RenderComponentType = (null as any); +class _View_TreeComponent_Host0 extends import1.AppView { + _el_0: any; + _vc_0: import2.AppElement; + _TreeComponent_0_4: _View_TreeComponent0; + constructor( + viewUtils: import4.ViewUtils, parentInjector: import5.Injector, + declarationEl: import2.AppElement) { + super( + _View_TreeComponent_Host0, renderType_TreeComponent_Host, import6.ViewType.HOST, viewUtils, + parentInjector, declarationEl, import7.ChangeDetectorStatus.CheckAlways); + } + createInternal(rootSelector: string): import2.AppElement { + this._el_0 = this.selectOrCreateHostElement('tree', rootSelector, (null as any)); + this._vc_0 = new import2.AppElement(0, (null as any), this, this._el_0); + this._TreeComponent_0_4 = new _View_TreeComponent0(this._el_0); + this._vc_0.initComponent(this._TreeComponent_0_4.context, [], this._TreeComponent_0_4); + this.init([].concat([this._el_0]), [this._el_0], [], []); + return this._vc_0; + } + detectChangesInternal(throwOnChange: boolean): void { + this._TreeComponent_0_4.detectChangesInternal(throwOnChange); + } + destroyInternal(): void { this._TreeComponent_0_4.destroyInternal(); } + injectorGetInternal(token: any, requestNodeIndex: number, notFoundResult: any): any { + if (((token === import3.TreeComponent) && (0 === requestNodeIndex))) { + return this._TreeComponent_0_4; + } + return notFoundResult; + } +} +function viewFactory_TreeComponent_Host0( + viewUtils: import4.ViewUtils, parentInjector: import5.Injector, + declarationEl: import2.AppElement): import1.AppView { + if ((renderType_TreeComponent_Host === (null as any))) { + (renderType_TreeComponent_Host = + viewUtils.createRenderComponentType('', 0, import8.ViewEncapsulation.None, [], {})); + } + return new _View_TreeComponent_Host0(viewUtils, parentInjector, declarationEl); +} +export const TreeComponentNgFactory: import9.ComponentFactory = + new import9.ComponentFactory( + 'tree', viewFactory_TreeComponent_Host0, import3.TreeComponent); diff --git a/modules/benchmarks/src/tree/ng2_static_ftl/README.md b/modules/benchmarks/src/tree/ng2_static_ftl/README.md new file mode 100644 index 0000000000..dc79ac2a19 --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_static_ftl/README.md @@ -0,0 +1,79 @@ +# Ng2 Static Faster Than BaseLine (FTL) Benchmark + +This benchmark was produced in the following way: + +1. Run AoT over the root component, one branch component + and the leaf component of the ng2_static benchmark +2. Move all 3 component classes to `tree.ts` +3. Add a `depth` property to the view factory constructor of + the `TreeBranchComponent` and pass it down to nested view factory calls + to be able to use the same view factory for all + nesting levels. This is just to make the experiment simpler to not + need to change so much code. +4. Optimize the `tree_branch.ngfactory.ts` and `tree_leaf.ngfactory.ts` + (see below) + +The goal of this benchmark is to explore what kind of +code the Ng2 compiler should generate in order to get faster. +I.e. right now, the Ng2 compiler _does not_ produce this kind of code, +but hopefully will in the future. + +## Optimizations and cleanups + +See `tree_branch.ngfactory.ts` and `tree_leaf.ngfactory.ts`. + +Performance: + +- remove view factory functions, call the constructor of the view class directly +- remove `createInternal` and move the logic into the constructor +- remove `AppView` parent class +- generate direct calls to `detectChangesInternal` / `destroyInternal` of nested components +- remove `Renderer` and `SanitizationService` to update + the dom directly via `document.createElement` / `element.appendChild` / setting + `Text.nodeValue` / `Element.style....` +- remove `AppElement` +- create component instance in view constructor + +Code size: +- helper methods `createElementAndAppend` / `createTextAndAppend` / `createAnchorAndAppend` +- wrap dirty check for `TreeComponent.data` into the method `updateData` + in the view class +- remove `injectorGetInternal` assuming we can detect that nobody is injecting an `Injector` + + +## Initial results: File size + +File size for view class of the component (without imports nor host view factory): +* before: 81 LOC +* after: 53 LOC + +## Initial results: Deep Tree Benchmark + +BENCHMARK deepTree.... +Description: +- bundles: false +- depth: 11 +- forceGc: false +- regressionSlopeMetric: scriptTime +- runId: f9ae32f0-8580-11e6-914d-9f4f8dbfb5e8 +- sampleSize: 20 +- userAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 + +...createOnly | gcAmount | gcTime | majorGcTime | pureScriptTime | renderTime | scriptTime +--------------- | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ +ng2.static | 10068.17+-33% | 9.50+-43% | 0.01+-84% | 83.01+-18% | 57.81+-19% | 92.33+-16% +ng2.ftl | 493.36+-435% | 0.65+-435% | 0.00+-435% | 28.48+-16% | 53.97+-7% | 28.48+-16% +baseline | 53.81+-435% | 0.10+-435% | 0.00+-435% | 19.79+-20% | 52.08+-19% | 19.89+-20% +incremental_dom | 311.14+-254% | 2.43+-248% | 0.00+-207% | 68.30+-20% | 59.31+-19% | 70.73+-19% + +.....update | gcAmount | gcTime | majorGcTime | pureScriptTime | renderTime | scriptTime +--------------- | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ +ng2.static | 0.00 | 0.00 | 0.00 | 24.65+-12% | 31.43+-22% | 24.65+-12% +ng2.ftl | 0.00 | 0.00+-435% | 0.00+-435% | 16.02+-13% | 29.15+-9% | 16.02+-13% +baseline | 509.97+-176% | 0.65+-269% | 0.40+-434% | 28.32+-16% | 35.80+-33% | 28.32+-16% +incremental_dom | 961.48+-246% | 0.52+-311% | 0.31+-435% | 28.94+-19% | 36.13+-21% | 28.94+-19% + +Ratios (create, pureScriptTime) +- 2.9x faster than current implementation +- 2.3x faster than incremental dom +- 1.4x slower than baseline diff --git a/modules/benchmarks/src/tree/ng2_static_ftl/app.ngfactory.ts b/modules/benchmarks/src/tree/ng2_static_ftl/app.ngfactory.ts new file mode 100644 index 0000000000..c4214df11c --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_static_ftl/app.ngfactory.ts @@ -0,0 +1,319 @@ +/** + * This file is generated by the Angular 2 template compiler. + * Do not edit. + */ +/* tslint:disable */ + +import * as import2 from '@angular/common/src/common_module'; +import * as import5 from '@angular/common/src/localization'; +import * as import6 from '@angular/core/src/application_init'; +import * as import3 from '@angular/core/src/application_module'; +import * as import8 from '@angular/core/src/application_ref'; +import * as import19 from '@angular/core/src/application_tokens'; +import * as import31 from '@angular/core/src/change_detection/differs/iterable_differs'; +import * as import32 from '@angular/core/src/change_detection/differs/keyvalue_differs'; +import * as import24 from '@angular/core/src/console'; +import * as import17 from '@angular/core/src/di/injector'; +import * as import26 from '@angular/core/src/error_handler'; +import * as import33 from '@angular/core/src/i18n/tokens'; +import * as import25 from '@angular/core/src/i18n/tokens'; +import * as import9 from '@angular/core/src/linker/compiler'; +import * as import0 from '@angular/core/src/linker/ng_module_factory'; +import * as import15 from '@angular/core/src/linker/view_utils'; +import * as import29 from '@angular/core/src/render/api'; +import * as import30 from '@angular/core/src/security'; +import * as import7 from '@angular/core/src/testability/testability'; +import * as import22 from '@angular/core/src/zone/ng_zone'; +import * as import4 from '@angular/platform-browser/src/browser'; +import * as import16 from '@angular/platform-browser/src/browser/title'; +import * as import28 from '@angular/platform-browser/src/dom/animation_driver'; +import * as import23 from '@angular/platform-browser/src/dom/debug/ng_probe'; +import * as import13 from '@angular/platform-browser/src/dom/dom_renderer'; +import * as import27 from '@angular/platform-browser/src/dom/dom_tokens'; +import * as import20 from '@angular/platform-browser/src/dom/events/dom_events'; +import * as import11 from '@angular/platform-browser/src/dom/events/event_manager'; +import * as import10 from '@angular/platform-browser/src/dom/events/hammer_gestures'; +import * as import21 from '@angular/platform-browser/src/dom/events/key_events'; +import * as import12 from '@angular/platform-browser/src/dom/shared_styles_host'; +import * as import14 from '@angular/platform-browser/src/security/dom_sanitization_service'; + +import * as import1 from './app'; +import * as import18 from './tree_root.ngfactory'; + +class AppModuleInjector extends import0.NgModuleInjector { + _CommonModule_0: import2.CommonModule; + _ApplicationModule_1: import3.ApplicationModule; + _BrowserModule_2: import4.BrowserModule; + _AppModule_3: import1.AppModule; + __LOCALE_ID_4: any; + __NgLocalization_5: import5.NgLocaleLocalization; + _ErrorHandler_6: any; + _ApplicationInitStatus_7: import6.ApplicationInitStatus; + _Testability_8: import7.Testability; + _ApplicationRef__9: import8.ApplicationRef_; + __ApplicationRef_10: any; + __Compiler_11: import9.Compiler; + __APP_ID_12: any; + __DOCUMENT_13: any; + __HAMMER_GESTURE_CONFIG_14: import10.HammerGestureConfig; + __EVENT_MANAGER_PLUGINS_15: any[]; + __EventManager_16: import11.EventManager; + __DomSharedStylesHost_17: import12.DomSharedStylesHost; + __AnimationDriver_18: any; + __DomRootRenderer_19: import13.DomRootRenderer_; + __RootRenderer_20: any; + __DomSanitizer_21: import14.DomSanitizerImpl; + __Sanitizer_22: any; + __ViewUtils_23: import15.ViewUtils; + __IterableDiffers_24: any; + __KeyValueDiffers_25: any; + __SharedStylesHost_26: any; + __Title_27: import16.Title; + __TRANSLATIONS_FORMAT_28: any; + constructor(parent: import17.Injector) { + super(parent, [import18.TreeRootComponentNgFactory], [import18.TreeRootComponentNgFactory]); + } + get _LOCALE_ID_4(): any { + if ((this.__LOCALE_ID_4 == (null as any))) { + (this.__LOCALE_ID_4 = (null as any)); + } + return this.__LOCALE_ID_4; + } + get _NgLocalization_5(): import5.NgLocaleLocalization { + if ((this.__NgLocalization_5 == (null as any))) { + (this.__NgLocalization_5 = new import5.NgLocaleLocalization(this._LOCALE_ID_4)); + } + return this.__NgLocalization_5; + } + get _ApplicationRef_10(): any { + if ((this.__ApplicationRef_10 == (null as any))) { + (this.__ApplicationRef_10 = this._ApplicationRef__9); + } + return this.__ApplicationRef_10; + } + get _Compiler_11(): import9.Compiler { + if ((this.__Compiler_11 == (null as any))) { + (this.__Compiler_11 = new import9.Compiler()); + } + return this.__Compiler_11; + } + get _APP_ID_12(): any { + if ((this.__APP_ID_12 == (null as any))) { + (this.__APP_ID_12 = import19._appIdRandomProviderFactory()); + } + return this.__APP_ID_12; + } + get _DOCUMENT_13(): any { + if ((this.__DOCUMENT_13 == (null as any))) { + (this.__DOCUMENT_13 = import4._document()); + } + return this.__DOCUMENT_13; + } + get _HAMMER_GESTURE_CONFIG_14(): import10.HammerGestureConfig { + if ((this.__HAMMER_GESTURE_CONFIG_14 == (null as any))) { + (this.__HAMMER_GESTURE_CONFIG_14 = new import10.HammerGestureConfig()); + } + return this.__HAMMER_GESTURE_CONFIG_14; + } + get _EVENT_MANAGER_PLUGINS_15(): any[] { + if ((this.__EVENT_MANAGER_PLUGINS_15 == (null as any))) { + (this.__EVENT_MANAGER_PLUGINS_15 = [ + new import20.DomEventsPlugin(), new import21.KeyEventsPlugin(), + new import10.HammerGesturesPlugin(this._HAMMER_GESTURE_CONFIG_14) + ]); + } + return this.__EVENT_MANAGER_PLUGINS_15; + } + get _EventManager_16(): import11.EventManager { + if ((this.__EventManager_16 == (null as any))) { + (this.__EventManager_16 = new import11.EventManager( + this._EVENT_MANAGER_PLUGINS_15, this.parent.get(import22.NgZone))); + } + return this.__EventManager_16; + } + get _DomSharedStylesHost_17(): import12.DomSharedStylesHost { + if ((this.__DomSharedStylesHost_17 == (null as any))) { + (this.__DomSharedStylesHost_17 = new import12.DomSharedStylesHost(this._DOCUMENT_13)); + } + return this.__DomSharedStylesHost_17; + } + get _AnimationDriver_18(): any { + if ((this.__AnimationDriver_18 == (null as any))) { + (this.__AnimationDriver_18 = import4._resolveDefaultAnimationDriver()); + } + return this.__AnimationDriver_18; + } + get _DomRootRenderer_19(): import13.DomRootRenderer_ { + if ((this.__DomRootRenderer_19 == (null as any))) { + (this.__DomRootRenderer_19 = new import13.DomRootRenderer_( + this._DOCUMENT_13, this._EventManager_16, this._DomSharedStylesHost_17, + this._AnimationDriver_18)); + } + return this.__DomRootRenderer_19; + } + get _RootRenderer_20(): any { + if ((this.__RootRenderer_20 == (null as any))) { + (this.__RootRenderer_20 = import23._createConditionalRootRenderer( + this._DomRootRenderer_19, this.parent.get(import23.NgProbeToken, (null as any)))); + } + return this.__RootRenderer_20; + } + get _DomSanitizer_21(): import14.DomSanitizerImpl { + if ((this.__DomSanitizer_21 == (null as any))) { + (this.__DomSanitizer_21 = new import14.DomSanitizerImpl()); + } + return this.__DomSanitizer_21; + } + get _Sanitizer_22(): any { + if ((this.__Sanitizer_22 == (null as any))) { + (this.__Sanitizer_22 = this._DomSanitizer_21); + } + return this.__Sanitizer_22; + } + get _ViewUtils_23(): import15.ViewUtils { + if ((this.__ViewUtils_23 == (null as any))) { + (this.__ViewUtils_23 = + new import15.ViewUtils(this._RootRenderer_20, this._APP_ID_12, this._Sanitizer_22)); + } + return this.__ViewUtils_23; + } + get _IterableDiffers_24(): any { + if ((this.__IterableDiffers_24 == (null as any))) { + (this.__IterableDiffers_24 = import3._iterableDiffersFactory()); + } + return this.__IterableDiffers_24; + } + get _KeyValueDiffers_25(): any { + if ((this.__KeyValueDiffers_25 == (null as any))) { + (this.__KeyValueDiffers_25 = import3._keyValueDiffersFactory()); + } + return this.__KeyValueDiffers_25; + } + get _SharedStylesHost_26(): any { + if ((this.__SharedStylesHost_26 == (null as any))) { + (this.__SharedStylesHost_26 = this._DomSharedStylesHost_17); + } + return this.__SharedStylesHost_26; + } + get _Title_27(): import16.Title { + if ((this.__Title_27 == (null as any))) { + (this.__Title_27 = new import16.Title()); + } + return this.__Title_27; + } + get _TRANSLATIONS_FORMAT_28(): any { + if ((this.__TRANSLATIONS_FORMAT_28 == (null as any))) { + (this.__TRANSLATIONS_FORMAT_28 = (null as any)); + } + return this.__TRANSLATIONS_FORMAT_28; + } + createInternal(): import1.AppModule { + this._CommonModule_0 = new import2.CommonModule(); + this._ApplicationModule_1 = new import3.ApplicationModule(); + this._BrowserModule_2 = + new import4.BrowserModule(this.parent.get(import4.BrowserModule, (null as any))); + this._AppModule_3 = new import1.AppModule(); + this._ErrorHandler_6 = import4.errorHandler(); + this._ApplicationInitStatus_7 = + new import6.ApplicationInitStatus(this.parent.get(import6.APP_INITIALIZER, (null as any))); + this._Testability_8 = new import7.Testability(this.parent.get(import22.NgZone)); + this._ApplicationRef__9 = new import8.ApplicationRef_( + this.parent.get(import22.NgZone), this.parent.get(import24.Console), this, + this._ErrorHandler_6, this, this._ApplicationInitStatus_7, + this.parent.get(import7.TestabilityRegistry, (null as any)), this._Testability_8); + return this._AppModule_3; + } + getInternal(token: any, notFoundResult: any): any { + if ((token === import2.CommonModule)) { + return this._CommonModule_0; + } + if ((token === import3.ApplicationModule)) { + return this._ApplicationModule_1; + } + if ((token === import4.BrowserModule)) { + return this._BrowserModule_2; + } + if ((token === import1.AppModule)) { + return this._AppModule_3; + } + if ((token === import25.LOCALE_ID)) { + return this._LOCALE_ID_4; + } + if ((token === import5.NgLocalization)) { + return this._NgLocalization_5; + } + if ((token === import26.ErrorHandler)) { + return this._ErrorHandler_6; + } + if ((token === import6.ApplicationInitStatus)) { + return this._ApplicationInitStatus_7; + } + if ((token === import7.Testability)) { + return this._Testability_8; + } + if ((token === import8.ApplicationRef_)) { + return this._ApplicationRef__9; + } + if ((token === import8.ApplicationRef)) { + return this._ApplicationRef_10; + } + if ((token === import9.Compiler)) { + return this._Compiler_11; + } + if ((token === import19.APP_ID)) { + return this._APP_ID_12; + } + if ((token === import27.DOCUMENT)) { + return this._DOCUMENT_13; + } + if ((token === import10.HAMMER_GESTURE_CONFIG)) { + return this._HAMMER_GESTURE_CONFIG_14; + } + if ((token === import11.EVENT_MANAGER_PLUGINS)) { + return this._EVENT_MANAGER_PLUGINS_15; + } + if ((token === import11.EventManager)) { + return this._EventManager_16; + } + if ((token === import12.DomSharedStylesHost)) { + return this._DomSharedStylesHost_17; + } + if ((token === import28.AnimationDriver)) { + return this._AnimationDriver_18; + } + if ((token === import13.DomRootRenderer)) { + return this._DomRootRenderer_19; + } + if ((token === import29.RootRenderer)) { + return this._RootRenderer_20; + } + if ((token === import14.DomSanitizer)) { + return this._DomSanitizer_21; + } + if ((token === import30.Sanitizer)) { + return this._Sanitizer_22; + } + if ((token === import15.ViewUtils)) { + return this._ViewUtils_23; + } + if ((token === import31.IterableDiffers)) { + return this._IterableDiffers_24; + } + if ((token === import32.KeyValueDiffers)) { + return this._KeyValueDiffers_25; + } + if ((token === import12.SharedStylesHost)) { + return this._SharedStylesHost_26; + } + if ((token === import16.Title)) { + return this._Title_27; + } + if ((token === import33.TRANSLATIONS_FORMAT)) { + return this._TRANSLATIONS_FORMAT_28; + } + return notFoundResult; + } + destroyInternal(): void { this._ApplicationRef__9.ngOnDestroy(); } +} +export const AppModuleNgFactory: import0.NgModuleFactory = + new import0.NgModuleFactory(AppModuleInjector, import1.AppModule); \ No newline at end of file diff --git a/modules/benchmarks/src/tree/ng2_static_ftl/app.ts b/modules/benchmarks/src/tree/ng2_static_ftl/app.ts new file mode 100644 index 0000000000..218010265c --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_static_ftl/app.ts @@ -0,0 +1 @@ +export class AppModule {} diff --git a/modules/benchmarks/src/tree/ng2_static_ftl/ftl_util.ts b/modules/benchmarks/src/tree/ng2_static_ftl/ftl_util.ts new file mode 100644 index 0000000000..9434a049fa --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_static_ftl/ftl_util.ts @@ -0,0 +1,17 @@ +export function createElementAndAppend(parent: any, name: string) { + const el = document.createElement(name); + parent.appendChild(el); + return el; +} + +export function createTextAndAppend(parent: any) { + const txt = document.createTextNode(''); + parent.appendChild(txt); + return txt; +} + +export function createAnchorAndAppend(parent: any) { + const txt = document.createComment(''); + parent.appendChild(txt); + return txt; +} \ No newline at end of file diff --git a/modules/benchmarks/src/tree/ng2_static_ftl/index.html b/modules/benchmarks/src/tree/ng2_static_ftl/index.html new file mode 100644 index 0000000000..7edd41a68c --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_static_ftl/index.html @@ -0,0 +1,26 @@ + + + +

Params

+
+ Depth: + +
+ +
+ +

Ng2 Static FTL Tree Benchmark

+

+ + + + +

+ +
+ +
+ + + + \ No newline at end of file diff --git a/modules/benchmarks/src/tree/ng2_static_ftl/index.ts b/modules/benchmarks/src/tree/ng2_static_ftl/index.ts new file mode 100644 index 0000000000..f07c63c493 --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_static_ftl/index.ts @@ -0,0 +1,41 @@ +import {ApplicationRef, NgModule, enableProdMode} from '@angular/core'; +import {platformBrowser} from '@angular/platform-browser'; + +import {bindAction, profile} from '../../util'; +import {TreeNode, buildTree, emptyTree} from '../util'; + +import {AppModuleNgFactory} from './app.ngfactory'; +import {TreeRootComponent} from './tree'; + +export function main() { + let tree: TreeRootComponent; + let appRef: ApplicationRef; + + function destroyDom() { + tree.data = emptyTree; + appRef.tick(); + } + + function createDom() { + tree.data = buildTree(); + appRef.tick(); + } + + function noop() {} + + function init() { + enableProdMode(); + platformBrowser().bootstrapModuleFactory(AppModuleNgFactory).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(); +} diff --git a/modules/benchmarks/src/tree/ng2_static_ftl/tree.ts b/modules/benchmarks/src/tree/ng2_static_ftl/tree.ts new file mode 100644 index 0000000000..431f1331c8 --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_static_ftl/tree.ts @@ -0,0 +1,7 @@ +import {TreeNode, emptyTree} from '../util'; + +export class TreeRootComponent { data: TreeNode = emptyTree; } + +export class TreeBranchComponent { data: TreeNode; } + +export class TreeLeafComponent { data: TreeNode; } diff --git a/modules/benchmarks/src/tree/ng2_static_ftl/tree_branch.ngfactory.ts b/modules/benchmarks/src/tree/ng2_static_ftl/tree_branch.ngfactory.ts new file mode 100644 index 0000000000..4af60aa484 --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_static_ftl/tree_branch.ngfactory.ts @@ -0,0 +1,76 @@ +/** + * This file is hand tweeked based on + * the out put of the Angular 2 template compiler + * and then hand tweeked to show possible future output. + */ +/* tslint:disable */ + +import * as import7 from '@angular/core/src/change_detection/change_detection'; +import * as import5 from '@angular/core/src/di/injector'; +import * as import9 from '@angular/core/src/linker/component_factory'; +import * as import2 from '@angular/core/src/linker/element'; +import * as import1 from '@angular/core/src/linker/view'; +import * as import6 from '@angular/core/src/linker/view_type'; +import * as import4 from '@angular/core/src/linker/view_utils'; +import * as import8 from '@angular/core/src/metadata/view'; +import * as import0 from '@angular/core/src/render/api'; +import * as import12 from '@angular/core/src/security'; + +import {createAnchorAndAppend, createElementAndAppend, createTextAndAppend} from './ftl_util'; +import * as import3 from './tree'; +import * as import11 from './tree_leaf.ngfactory'; + +export class View_TreeTreeComponent { + context: import3.TreeBranchComponent; + ref: any; + _el_0: any; + _text_1: any; + _el_2: any; + _TreeComponent20_2_4View: any; + _el_3: any; + _TreeComponent20_3_4View: any; + /*private*/ _expr_0: any; + /*private*/ _expr_1: any; + /*private*/ _expr_2: any; + constructor(depth: number, parentRenderNode: any) { + this.context = new import3.TreeBranchComponent(); + this._el_0 = createElementAndAppend(parentRenderNode, 'span'); + this._text_1 = createTextAndAppend(this._el_0); + this._el_2 = createElementAndAppend(parentRenderNode, 'tree'); + this._TreeComponent20_2_4View = depth > 0 ? new View_TreeTreeComponent(depth - 1, this._el_2) : + new import11.View_TreeLeafComponent(this._el_2); + this._el_3 = createElementAndAppend(parentRenderNode, 'tree'); + this._TreeComponent20_3_4View = depth > 0 ? new View_TreeTreeComponent(depth - 1, this._el_3) : + new import11.View_TreeLeafComponent(this._el_3); + this._expr_0 = import7.UNINITIALIZED; + this._expr_1 = import7.UNINITIALIZED; + this._expr_2 = import7.UNINITIALIZED; + } + destroyInternal() { + this._TreeComponent20_2_4View.destroyInternal(); + this._TreeComponent20_3_4View.destroyInternal(); + } + updateData(currVal_2: any) { + if (import4.checkBinding(false, this._expr_2, currVal_2)) { + this.context.data = currVal_2; + this._expr_2 = currVal_2; + } + } + detectChangesInternal(throwOnChange: boolean): void { + this._TreeComponent20_2_4View.updateData(this.context.data.right); + this._TreeComponent20_3_4View.updateData(this.context.data.left); + + const currVal_0: any = ((this.context.data.depth % 2) ? '' : 'grey'); + if (import4.checkBinding(throwOnChange, this._expr_0, currVal_0)) { + this._el_0.style.backgroundColor = currVal_0; + this._expr_0 = currVal_0; + } + const currVal_1: any = import4.interpolate(1, ' ', this.context.data.value, ' '); + if (import4.checkBinding(throwOnChange, this._expr_1, currVal_1)) { + this._text_1.nodeValue = currVal_1; + this._expr_1 = currVal_1; + } + this._TreeComponent20_2_4View.detectChangesInternal(throwOnChange); + this._TreeComponent20_3_4View.detectChangesInternal(throwOnChange); + } +} diff --git a/modules/benchmarks/src/tree/ng2_static_ftl/tree_leaf.ngfactory.ts b/modules/benchmarks/src/tree/ng2_static_ftl/tree_leaf.ngfactory.ts new file mode 100644 index 0000000000..f272eb29f5 --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_static_ftl/tree_leaf.ngfactory.ts @@ -0,0 +1,56 @@ +/** + * This file is hand tweeked based on + * the out put of the Angular 2 template compiler + * and then hand tweeked to show possible future output. + */ +/* tslint:disable */ + +import * as import7 from '@angular/core/src/change_detection/change_detection'; +import * as import5 from '@angular/core/src/di/injector'; +import * as import9 from '@angular/core/src/linker/component_factory'; +import * as import2 from '@angular/core/src/linker/element'; +import * as import1 from '@angular/core/src/linker/view'; +import * as import6 from '@angular/core/src/linker/view_type'; +import * as import4 from '@angular/core/src/linker/view_utils'; +import * as import8 from '@angular/core/src/metadata/view'; +import * as import0 from '@angular/core/src/render/api'; +import * as import10 from '@angular/core/src/security'; + +import * as import3 from './tree'; + +export class View_TreeLeafComponent { + context: import3.TreeLeafComponent; + _el_0: any; + _text_1: any; + /*private*/ _expr_0: any; + /*private*/ _expr_1: any; + /*private*/ _expr_2: any; + constructor(parentRenderNode: any) { + this.context = new import3.TreeLeafComponent(); + this._el_0 = document.createElement('span'); + parentRenderNode.appendChild(this._el_0); + this._text_1 = document.createTextNode(''); + this._el_0.appendChild(this._text_1); + this._expr_0 = import7.UNINITIALIZED; + this._expr_1 = import7.UNINITIALIZED; + } + updateData(currVal_2: any) { + if (import4.checkBinding(false, this._expr_2, currVal_2)) { + this.context.data = currVal_2; + this._expr_2 = currVal_2; + } + } + destroyInternal() {} + detectChangesInternal(throwOnChange: boolean): void { + const currVal_0: any = ((this.context.data.depth % 2) ? '' : 'grey'); + if (import4.checkBinding(throwOnChange, this._expr_0, currVal_0)) { + this._el_0.style.backgroundColor = currVal_0; + this._expr_0 = currVal_0; + } + const currVal_1: any = import4.interpolate(1, ' ', this.context.data.value, ' '); + if (import4.checkBinding(throwOnChange, this._expr_1, currVal_1)) { + this._text_1.nodeValue = currVal_1; + this._expr_1 = currVal_1; + } + } +} diff --git a/modules/benchmarks/src/tree/ng2_static_ftl/tree_root.ngfactory.ts b/modules/benchmarks/src/tree/ng2_static_ftl/tree_root.ngfactory.ts new file mode 100644 index 0000000000..18d11c830c --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_static_ftl/tree_root.ngfactory.ts @@ -0,0 +1,150 @@ +/** + * This file is generated by the Angular 2 template compiler. + * Do not edit. + */ +/* tslint:disable */ + +import * as import10 from '@angular/common/src/directives/ng_if'; +import * as import7 from '@angular/core/src/change_detection/change_detection'; +import * as import5 from '@angular/core/src/di/injector'; +import * as import9 from '@angular/core/src/linker/component_factory'; +import * as import2 from '@angular/core/src/linker/element'; +import * as import11 from '@angular/core/src/linker/template_ref'; +import * as import1 from '@angular/core/src/linker/view'; +import * as import6 from '@angular/core/src/linker/view_type'; +import * as import4 from '@angular/core/src/linker/view_utils'; +import * as import8 from '@angular/core/src/metadata/view'; +import * as import0 from '@angular/core/src/render/api'; + +import {maxDepth} from '../util'; + +import * as import3 from './tree'; +import * as import12 from './tree'; +import * as import13 from './tree_branch.ngfactory'; + +var renderType_TreeRootComponent_Host: import0.RenderComponentType = (null as any); +class _View_TreeRootComponent_Host0 extends import1.AppView { + _el_0: any; + /*private*/ _appEl_0: import2.AppElement; + _TreeRootComponent_0_4: import3.TreeRootComponent; + constructor( + viewUtils: import4.ViewUtils, parentInjector: import5.Injector, + declarationEl: import2.AppElement) { + super( + _View_TreeRootComponent_Host0, renderType_TreeRootComponent_Host, import6.ViewType.HOST, + viewUtils, parentInjector, declarationEl, import7.ChangeDetectorStatus.CheckAlways); + } + createInternal(rootSelector: string): import2.AppElement { + this._el_0 = this.selectOrCreateHostElement('tree', rootSelector, (null as any)); + this._appEl_0 = new import2.AppElement(0, (null as any), this, this._el_0); + var compView_0: any = + viewFactory_TreeRootComponent0(this.viewUtils, this.injector(0), this._appEl_0); + this._TreeRootComponent_0_4 = new import3.TreeRootComponent(); + this._appEl_0.initComponent(this._TreeRootComponent_0_4, [], compView_0); + compView_0.create(this._TreeRootComponent_0_4, this.projectableNodes, (null as any)); + this.init([].concat([this._el_0]), [this._el_0], [], []); + return this._appEl_0; + } + injectorGetInternal(token: any, requestNodeIndex: number, notFoundResult: any): any { + if (((token === import3.TreeRootComponent) && (0 === requestNodeIndex))) { + return this._TreeRootComponent_0_4; + } + return notFoundResult; + } +} +function viewFactory_TreeRootComponent_Host0( + viewUtils: import4.ViewUtils, parentInjector: import5.Injector, + declarationEl: import2.AppElement): import1.AppView { + if ((renderType_TreeRootComponent_Host === (null as any))) { + (renderType_TreeRootComponent_Host = + viewUtils.createRenderComponentType('', 0, import8.ViewEncapsulation.None, [], {})); + } + return new _View_TreeRootComponent_Host0(viewUtils, parentInjector, declarationEl); +} +export const TreeRootComponentNgFactory: import9.ComponentFactory = + new import9.ComponentFactory( + 'tree', viewFactory_TreeRootComponent_Host0, import3.TreeRootComponent); +const styles_TreeRootComponent: any[] = []; +var renderType_TreeRootComponent: import0.RenderComponentType = (null as any); +class _View_TreeRootComponent0 extends import1.AppView { + _anchor_0: any; + /*private*/ _appEl_0: import2.AppElement; + _TemplateRef_0_5: any; + _NgIf_0_6: import10.NgIf; + /*private*/ _expr_0: any; + constructor( + viewUtils: import4.ViewUtils, parentInjector: import5.Injector, + declarationEl: import2.AppElement) { + super( + _View_TreeRootComponent0, renderType_TreeRootComponent, import6.ViewType.COMPONENT, + viewUtils, parentInjector, declarationEl, import7.ChangeDetectorStatus.CheckAlways); + } + createInternal(rootSelector: string): import2.AppElement { + const parentRenderNode: any = + this.renderer.createViewRoot(this.declarationAppElement.nativeElement); + this._anchor_0 = this.renderer.createTemplateAnchor(parentRenderNode, (null as any)); + this._appEl_0 = new import2.AppElement(0, (null as any), this, this._anchor_0); + this._TemplateRef_0_5 = + new import11.TemplateRef_(this._appEl_0, viewFactory_TreeRootComponent1); + this._NgIf_0_6 = new import10.NgIf(this._appEl_0.vcRef, this._TemplateRef_0_5); + this._expr_0 = import7.UNINITIALIZED; + this.init([], [this._anchor_0], [], []); + return (null as any); + } + injectorGetInternal(token: any, requestNodeIndex: number, notFoundResult: any): any { + if (((token === import11.TemplateRef) && (0 === requestNodeIndex))) { + return this._TemplateRef_0_5; + } + if (((token === import10.NgIf) && (0 === requestNodeIndex))) { + return this._NgIf_0_6; + } + return notFoundResult; + } + detectChangesInternal(throwOnChange: boolean): void { + const currVal_0: any = (this.context.data.left != (null as any)); + if (import4.checkBinding(throwOnChange, this._expr_0, currVal_0)) { + this._NgIf_0_6.ngIf = currVal_0; + this._expr_0 = currVal_0; + } + this.detectContentChildrenChanges(throwOnChange); + this.detectViewChildrenChanges(throwOnChange); + } +} +export function viewFactory_TreeRootComponent0( + viewUtils: import4.ViewUtils, parentInjector: import5.Injector, + declarationEl: import2.AppElement): import1.AppView { + if ((renderType_TreeRootComponent === (null as any))) { + (renderType_TreeRootComponent = viewUtils.createRenderComponentType( + '/Users/tbosch/projects/conf-demos/ngc-demo/src/ng2_static/root_tree.ts class TreeRootComponent - inline template', + 0, import8.ViewEncapsulation.None, styles_TreeRootComponent, {})); + } + return new _View_TreeRootComponent0(viewUtils, parentInjector, declarationEl); +} +class _View_TreeRootComponent1 extends import1.AppView { + _el_0: any; + _TreeComponent0_0_4View: any; + constructor( + viewUtils: import4.ViewUtils, parentInjector: import5.Injector, + declarationEl: import2.AppElement) { + super( + _View_TreeRootComponent1, renderType_TreeRootComponent, import6.ViewType.EMBEDDED, + viewUtils, parentInjector, declarationEl, import7.ChangeDetectorStatus.CheckAlways); + } + createInternal(rootSelector: string): import2.AppElement { + this._el_0 = this.renderer.createElement((null as any), 'tree0', (null as any)); + this._TreeComponent0_0_4View = new import13.View_TreeTreeComponent(maxDepth - 1, this._el_0); + this.init([].concat([this._el_0]), [this._el_0], [], []); + return (null as any); + } + destroyInternal() { this._TreeComponent0_0_4View.destroyInternal(); } + detectChangesInternal(throwOnChange: boolean): void { + this._TreeComponent0_0_4View.updateData(this.parent.context.data); + this.detectContentChildrenChanges(throwOnChange); + this._TreeComponent0_0_4View.detectChangesInternal(throwOnChange); + } +} +function viewFactory_TreeRootComponent1( + viewUtils: import4.ViewUtils, parentInjector: import5.Injector, + declarationEl: import2.AppElement): import1.AppView { + return new _View_TreeRootComponent1(viewUtils, parentInjector, declarationEl); +} \ No newline at end of file diff --git a/modules/e2e_util/e2e_util.ts b/modules/e2e_util/e2e_util.ts index 5218716d64..394b21eabb 100644 --- a/modules/e2e_util/e2e_util.ts +++ b/modules/e2e_util/e2e_util.ts @@ -34,7 +34,9 @@ export function openBrowser(config: { browser.ignoreSynchronization = true; } var params = config.params || []; - params = params.concat([{name: 'bundles', value: cmdArgs.bundles}]); + if (!params.some((param) => param.name === 'bundles')) { + params = params.concat([{name: 'bundles', value: cmdArgs.bundles}]); + } var urlParams: string[] = []; params.forEach((param) => { urlParams.push(param.name + '=' + param.value); });