diff --git a/modules/benchmarks/src/js-web-frameworks/BUILD.bazel b/modules/benchmarks/src/js-web-frameworks/BUILD.bazel new file mode 100644 index 0000000000..d319d9b297 --- /dev/null +++ b/modules/benchmarks/src/js-web-frameworks/BUILD.bazel @@ -0,0 +1,13 @@ +load("//tools:defaults.bzl", "ts_library") + +package(default_visibility = ["//visibility:public"]) + +ts_library( + name = "perf_lib", + testonly = True, + srcs = ["perf.spec.ts"], + deps = [ + "//modules/e2e_util", + "@npm//protractor", + ], +) diff --git a/modules/benchmarks/src/js-web-frameworks/ng2/BUILD.bazel b/modules/benchmarks/src/js-web-frameworks/ng2/BUILD.bazel new file mode 100644 index 0000000000..ea6927b6f7 --- /dev/null +++ b/modules/benchmarks/src/js-web-frameworks/ng2/BUILD.bazel @@ -0,0 +1,39 @@ +load("//tools:defaults.bzl", "ng_module", "ng_rollup_bundle", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +ng_module( + name = "ng2", + srcs = glob(["*.ts"]), + generate_ve_shims = True, + tsconfig = "//modules/benchmarks:tsconfig-build.json", + deps = [ + "//modules/benchmarks/src:util_lib", + "//packages/core", + "//packages/platform-browser", + ], +) + +ng_rollup_bundle( + name = "bundle", + entry_point = ":index.ts", + deps = [ + ":ng2", + "@npm//rxjs", + ], +) + +ts_devserver( + name = "prodserver", + bootstrap = ["//packages/zone.js/dist:zone.js"], + port = 4200, + static_files = ["index.html"], + deps = [":bundle.min_debug.es2015.js"], +) + +benchmark_test( + name = "perf", + server = ":prodserver", + deps = ["//modules/benchmarks/src/js-web-frameworks:perf_lib"], +) diff --git a/modules/benchmarks/src/js-web-frameworks/ng2/index.html b/modules/benchmarks/src/js-web-frameworks/ng2/index.html new file mode 100644 index 0000000000..0375e88279 --- /dev/null +++ b/modules/benchmarks/src/js-web-frameworks/ng2/index.html @@ -0,0 +1,28 @@ + + + + + + + + + + +

Angular JS Web Frameworks benchmark

+

+ + + + + +

+ +
+ Loading... +
+ + + + + + \ No newline at end of file diff --git a/modules/benchmarks/src/js-web-frameworks/ng2/index.ts b/modules/benchmarks/src/js-web-frameworks/ng2/index.ts new file mode 100644 index 0000000000..c658092360 --- /dev/null +++ b/modules/benchmarks/src/js-web-frameworks/ng2/index.ts @@ -0,0 +1,16 @@ +/** + * @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 {enableProdMode} from '@angular/core'; +import {platformBrowser} from '@angular/platform-browser'; + +import {init} from './init'; +import {JsWebFrameworksModuleNgFactory} from './rows.ngfactory'; + +enableProdMode(); +platformBrowser().bootstrapModuleFactory(JsWebFrameworksModuleNgFactory).then(init); diff --git a/modules/benchmarks/src/js-web-frameworks/ng2/init.ts b/modules/benchmarks/src/js-web-frameworks/ng2/init.ts new file mode 100644 index 0000000000..b1d4861075 --- /dev/null +++ b/modules/benchmarks/src/js-web-frameworks/ng2/init.ts @@ -0,0 +1,92 @@ +/** + * @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 {ApplicationRef, NgModuleRef} from '@angular/core'; + +import {bindAction} from '../../util'; + +import {JsWebFrameworksComponent, JsWebFrameworksModule, RowData} from './rows'; + + +function _random(max: number) { + return Math.round(Math.random() * 1000) % max; +} + +function buildData(count: number): Array { + const data: Array = []; + for (let i = 0; i < count; i++) { + data.push({ + id: i, + label: ADJECTIVES[_random(ADJECTIVES.length)] + ' ' + COLOURS[_random(COLOURS.length)] + ' ' + + NOUNS[_random(NOUNS.length)] + }); + } + return data; +} + +const ADJECTIVES = [ + 'pretty', 'large', 'big', 'small', 'tall', 'short', 'long', + 'handsome', 'plain', 'quaint', 'clean', 'elegant', 'easy', 'angry', + 'crazy', 'helpful', 'mushy', 'odd', 'unsightly', 'adorable', 'important', + 'inexpensive', 'cheap', 'expensive', 'fancy' +]; +const COLOURS = [ + 'red', 'yellow', 'blue', 'green', 'pink', 'brown', 'purple', 'brown', 'white', 'black', 'orange' +]; +const NOUNS = [ + 'table', 'chair', 'house', 'bbq', 'desk', 'car', 'pony', 'cookie', 'sandwich', 'burger', 'pizza', + 'mouse', 'keyboard' +]; + +export function init(moduleRef: NgModuleRef) { + let component: JsWebFrameworksComponent; + let appRef: ApplicationRef; + + function create1K() { + component.data = buildData(1 * 1000); + appRef.tick(); + } + + function create10K() { + component.data = buildData(10 * 1000); + appRef.tick(); + } + + function deleteAll() { + component.data = []; + appRef.tick(); + } + + function update() { + for (let i = 0; i < component.data.length; i += 10) { + component.data[i].label += ' !!!'; + } + appRef.tick(); + } + + function swapRows() { + const data = component.data; + if (data.length > 998) { + const a = data[1]; + data[1] = data[998]; + data[998] = a; + } + appRef.tick(); + } + + const injector = moduleRef.injector; + appRef = injector.get(ApplicationRef); + + component = appRef.components[0].instance; + + bindAction('#create1KRows', create1K); + bindAction('#create10KRows', create10K); + bindAction('#deleteAll', deleteAll); + bindAction('#update', update); + bindAction('#swap', swapRows); +} diff --git a/modules/benchmarks/src/js-web-frameworks/ng2/rows.ts b/modules/benchmarks/src/js-web-frameworks/ng2/rows.ts new file mode 100644 index 0000000000..655c2385cd --- /dev/null +++ b/modules/benchmarks/src/js-web-frameworks/ng2/rows.ts @@ -0,0 +1,70 @@ +/** + * @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 {ApplicationRef, Component, NgModule} from '@angular/core'; +import {BrowserModule} from '@angular/platform-browser'; + +export interface RowData { + id: number; + label: string; +} + + +@Component({ + selector: 'js-web-frameworks', + template: ` + + + + + + + + + +
{{item.id}} + {{item.label}} + + + + +
+ ` +}) +export class JsWebFrameworksComponent { + data: Array = []; + selected: number|null; + + constructor(private _appRef: ApplicationRef) {} + + itemById(index: number, item: RowData) { return item.id; } + + select(itemId: number) { + this.selected = itemId; + this._appRef.tick(); + } + + delete (itemId: number) { + const data = this.data; + for (let i = 0, l = data.length; i < l; i++) { + if (data[i].id === itemId) { + data.splice(i, 1); + break; + } + } + this._appRef.tick(); + } +} + +@NgModule({ + imports: [BrowserModule], + declarations: [JsWebFrameworksComponent], + bootstrap: [JsWebFrameworksComponent], +}) +export class JsWebFrameworksModule { +} \ No newline at end of file diff --git a/modules/benchmarks/src/js-web-frameworks/perf.spec.ts b/modules/benchmarks/src/js-web-frameworks/perf.spec.ts new file mode 100644 index 0000000000..dfa3ab797f --- /dev/null +++ b/modules/benchmarks/src/js-web-frameworks/perf.spec.ts @@ -0,0 +1,78 @@ +/** + * @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 {$} from 'protractor'; +import {runBenchmark, verifyNoBrowserErrors} from '../../../e2e_util/perf_util'; + +interface Worker { + id: string; + prepare?(): void; + work(): void; +} + +const Create1KWorker: Worker = { + id: 'create1K', + prepare: () => $('#deleteAll').click(), + work: () => $('#create1KRows').click() +}; + +const Delete1KWorker: Worker = { + id: 'delete1K', + prepare: () => $('#create1KRows').click(), + work: () => { $('#deleteAll').click(); } +}; + +const UpdateWorker: Worker = { + id: 'update', + prepare: () => $('#create1KRows').click(), + work: () => { $('#update').click(); } +}; + +const SwapWorker: Worker = { + id: 'swap', + prepare: () => $('#create1KRows').click(), + work: () => { $('#swap').click(); } +}; + +// In order to make sure that we don't change the ids of the benchmarks, we need to +// determine the current test package name from the Bazel target. This is necessary +// because previous to the Bazel conversion, the benchmark test ids contained the test +// name. e.g. "largeTable.ng2_switch.createDestroy". We determine the name of the +// Bazel package where this test runs from the current test target. The Bazel target +// looks like: "//modules/benchmarks/src/largetable/{pkg_name}:{target_name}". +const testPackageName = process.env['BAZEL_TARGET'] !.split(':')[0].split('/').pop(); + +describe('js-web-frameworks benchmark perf', () => { + + afterEach(verifyNoBrowserErrors); + + [Create1KWorker, Delete1KWorker, UpdateWorker, SwapWorker].forEach((worker) => { + describe(worker.id, () => { + it(`should run benchmark for ${testPackageName}`, done => { + runTableBenchmark({ + id: `js-web-frameworks.${testPackageName}.${worker.id}`, + url: '/', + ignoreBrowserSynchronization: true, + worker: worker + }).then(done, done.fail); + }); + }); + }); +}); + +function runTableBenchmark( + config: {id: string, url: string, ignoreBrowserSynchronization?: boolean, worker: Worker}) { + return runBenchmark({ + id: config.id, + url: config.url, + ignoreBrowserSynchronization: config.ignoreBrowserSynchronization, + params: [], + prepare: config.worker.prepare, + work: config.worker.work + }); +}