Skip to content

Commit df6d6e0

Browse files
pkozlowski-opensourcemhevery
authored andcommitted
perf: add js-web-frameworks benchmark (angular#34034)
PR Close angular#34034
1 parent ea37e82 commit df6d6e0

File tree

7 files changed

+336
-0
lines changed

7 files changed

+336
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
load("//tools:defaults.bzl", "ts_library")
2+
3+
package(default_visibility = ["//visibility:public"])
4+
5+
ts_library(
6+
name = "perf_lib",
7+
testonly = True,
8+
srcs = ["perf.spec.ts"],
9+
deps = [
10+
"//modules/e2e_util",
11+
"@npm//protractor",
12+
],
13+
)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
load("//tools:defaults.bzl", "ng_module", "ng_rollup_bundle", "ts_devserver")
2+
load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test")
3+
4+
package(default_visibility = ["//modules/benchmarks:__subpackages__"])
5+
6+
ng_module(
7+
name = "ng2",
8+
srcs = glob(["*.ts"]),
9+
generate_ve_shims = True,
10+
tsconfig = "//modules/benchmarks:tsconfig-build.json",
11+
deps = [
12+
"//modules/benchmarks/src:util_lib",
13+
"//packages/core",
14+
"//packages/platform-browser",
15+
],
16+
)
17+
18+
ng_rollup_bundle(
19+
name = "bundle",
20+
entry_point = ":index.ts",
21+
deps = [
22+
":ng2",
23+
"@npm//rxjs",
24+
],
25+
)
26+
27+
ts_devserver(
28+
name = "prodserver",
29+
bootstrap = ["//packages/zone.js/dist:zone.js"],
30+
port = 4200,
31+
static_files = ["index.html"],
32+
deps = [":bundle.min_debug.es2015.js"],
33+
)
34+
35+
benchmark_test(
36+
name = "perf",
37+
server = ":prodserver",
38+
deps = ["//modules/benchmarks/src/js-web-frameworks:perf_lib"],
39+
)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!doctype html>
2+
<html>
3+
4+
<head>
5+
<!-- Prevent the browser from requesting any favicon. -->
6+
<link rel="icon" href="data:,">
7+
</head>
8+
9+
<body>
10+
11+
<h2>Angular <a href="https://www.stefankrause.net/wp/?p=504" target="_blank">JS Web Frameworks benchmark</a></h2>
12+
<p>
13+
<button id="create1KRows">create 1K rows</button>
14+
<button id="create10KRows">create 10K rows</button>
15+
<button id="deleteAll">delete all rows</button>
16+
<button id="update">update every 10th row</button>
17+
<button id="swap">swap 2 rows</button>
18+
</p>
19+
20+
<div>
21+
<js-web-frameworks id="root">Loading...</js-web-frameworks>
22+
</div>
23+
24+
<!--load location for ts_devserver-->
25+
<script src="/app_bundle.js"></script>
26+
</body>
27+
28+
</html>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {enableProdMode} from '@angular/core';
10+
import {platformBrowser} from '@angular/platform-browser';
11+
12+
import {init} from './init';
13+
import {JsWebFrameworksModuleNgFactory} from './rows.ngfactory';
14+
15+
enableProdMode();
16+
platformBrowser().bootstrapModuleFactory(JsWebFrameworksModuleNgFactory).then(init);
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {ApplicationRef, NgModuleRef} from '@angular/core';
10+
11+
import {bindAction} from '../../util';
12+
13+
import {JsWebFrameworksComponent, JsWebFrameworksModule, RowData} from './rows';
14+
15+
16+
function _random(max: number) {
17+
return Math.round(Math.random() * 1000) % max;
18+
}
19+
20+
function buildData(count: number): Array<RowData> {
21+
const data: Array<RowData> = [];
22+
for (let i = 0; i < count; i++) {
23+
data.push({
24+
id: i,
25+
label: ADJECTIVES[_random(ADJECTIVES.length)] + ' ' + COLOURS[_random(COLOURS.length)] + ' ' +
26+
NOUNS[_random(NOUNS.length)]
27+
});
28+
}
29+
return data;
30+
}
31+
32+
const ADJECTIVES = [
33+
'pretty', 'large', 'big', 'small', 'tall', 'short', 'long',
34+
'handsome', 'plain', 'quaint', 'clean', 'elegant', 'easy', 'angry',
35+
'crazy', 'helpful', 'mushy', 'odd', 'unsightly', 'adorable', 'important',
36+
'inexpensive', 'cheap', 'expensive', 'fancy'
37+
];
38+
const COLOURS = [
39+
'red', 'yellow', 'blue', 'green', 'pink', 'brown', 'purple', 'brown', 'white', 'black', 'orange'
40+
];
41+
const NOUNS = [
42+
'table', 'chair', 'house', 'bbq', 'desk', 'car', 'pony', 'cookie', 'sandwich', 'burger', 'pizza',
43+
'mouse', 'keyboard'
44+
];
45+
46+
export function init(moduleRef: NgModuleRef<JsWebFrameworksModule>) {
47+
let component: JsWebFrameworksComponent;
48+
let appRef: ApplicationRef;
49+
50+
function create1K() {
51+
component.data = buildData(1 * 1000);
52+
appRef.tick();
53+
}
54+
55+
function create10K() {
56+
component.data = buildData(10 * 1000);
57+
appRef.tick();
58+
}
59+
60+
function deleteAll() {
61+
component.data = [];
62+
appRef.tick();
63+
}
64+
65+
function update() {
66+
for (let i = 0; i < component.data.length; i += 10) {
67+
component.data[i].label += ' !!!';
68+
}
69+
appRef.tick();
70+
}
71+
72+
function swapRows() {
73+
const data = component.data;
74+
if (data.length > 998) {
75+
const a = data[1];
76+
data[1] = data[998];
77+
data[998] = a;
78+
}
79+
appRef.tick();
80+
}
81+
82+
const injector = moduleRef.injector;
83+
appRef = injector.get(ApplicationRef);
84+
85+
component = appRef.components[0].instance;
86+
87+
bindAction('#create1KRows', create1K);
88+
bindAction('#create10KRows', create10K);
89+
bindAction('#deleteAll', deleteAll);
90+
bindAction('#update', update);
91+
bindAction('#swap', swapRows);
92+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {ApplicationRef, Component, NgModule} from '@angular/core';
10+
import {BrowserModule} from '@angular/platform-browser';
11+
12+
export interface RowData {
13+
id: number;
14+
label: string;
15+
}
16+
17+
18+
@Component({
19+
selector: 'js-web-frameworks',
20+
template: `
21+
<table class="table table-hover table-striped test-data">
22+
<tbody>
23+
<tr [class.danger]="item.id === selected" *ngFor="let item of data; trackBy: itemById">
24+
<td class="col-md-1">{{item.id}}</td>
25+
<td class="col-md-4">
26+
<a href="#" (click)="select(item.id); $event.preventDefault()">{{item.label}}</a>
27+
</td>
28+
<td class="col-md-1">
29+
<a href="#" (click)="delete(item.id); $event.preventDefault()">
30+
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
31+
</a>
32+
</td>
33+
<td class="col-md-6"></td>
34+
</tr>
35+
</tbody>
36+
</table>
37+
`
38+
})
39+
export class JsWebFrameworksComponent {
40+
data: Array<RowData> = [];
41+
selected: number|null;
42+
43+
constructor(private _appRef: ApplicationRef) {}
44+
45+
itemById(index: number, item: RowData) { return item.id; }
46+
47+
select(itemId: number) {
48+
this.selected = itemId;
49+
this._appRef.tick();
50+
}
51+
52+
delete (itemId: number) {
53+
const data = this.data;
54+
for (let i = 0, l = data.length; i < l; i++) {
55+
if (data[i].id === itemId) {
56+
data.splice(i, 1);
57+
break;
58+
}
59+
}
60+
this._appRef.tick();
61+
}
62+
}
63+
64+
@NgModule({
65+
imports: [BrowserModule],
66+
declarations: [JsWebFrameworksComponent],
67+
bootstrap: [JsWebFrameworksComponent],
68+
})
69+
export class JsWebFrameworksModule {
70+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {$} from 'protractor';
10+
import {runBenchmark, verifyNoBrowserErrors} from '../../../e2e_util/perf_util';
11+
12+
interface Worker {
13+
id: string;
14+
prepare?(): void;
15+
work(): void;
16+
}
17+
18+
const Create1KWorker: Worker = {
19+
id: 'create1K',
20+
prepare: () => $('#deleteAll').click(),
21+
work: () => $('#create1KRows').click()
22+
};
23+
24+
const Delete1KWorker: Worker = {
25+
id: 'delete1K',
26+
prepare: () => $('#create1KRows').click(),
27+
work: () => { $('#deleteAll').click(); }
28+
};
29+
30+
const UpdateWorker: Worker = {
31+
id: 'update',
32+
prepare: () => $('#create1KRows').click(),
33+
work: () => { $('#update').click(); }
34+
};
35+
36+
const SwapWorker: Worker = {
37+
id: 'swap',
38+
prepare: () => $('#create1KRows').click(),
39+
work: () => { $('#swap').click(); }
40+
};
41+
42+
// In order to make sure that we don't change the ids of the benchmarks, we need to
43+
// determine the current test package name from the Bazel target. This is necessary
44+
// because previous to the Bazel conversion, the benchmark test ids contained the test
45+
// name. e.g. "largeTable.ng2_switch.createDestroy". We determine the name of the
46+
// Bazel package where this test runs from the current test target. The Bazel target
47+
// looks like: "//modules/benchmarks/src/largetable/{pkg_name}:{target_name}".
48+
const testPackageName = process.env['BAZEL_TARGET'] !.split(':')[0].split('/').pop();
49+
50+
describe('js-web-frameworks benchmark perf', () => {
51+
52+
afterEach(verifyNoBrowserErrors);
53+
54+
[Create1KWorker, Delete1KWorker, UpdateWorker, SwapWorker].forEach((worker) => {
55+
describe(worker.id, () => {
56+
it(`should run benchmark for ${testPackageName}`, done => {
57+
runTableBenchmark({
58+
id: `js-web-frameworks.${testPackageName}.${worker.id}`,
59+
url: '/',
60+
ignoreBrowserSynchronization: true,
61+
worker: worker
62+
}).then(done, done.fail);
63+
});
64+
});
65+
});
66+
});
67+
68+
function runTableBenchmark(
69+
config: {id: string, url: string, ignoreBrowserSynchronization?: boolean, worker: Worker}) {
70+
return runBenchmark({
71+
id: config.id,
72+
url: config.url,
73+
ignoreBrowserSynchronization: config.ignoreBrowserSynchronization,
74+
params: [],
75+
prepare: config.worker.prepare,
76+
work: config.worker.work
77+
});
78+
}

0 commit comments

Comments
 (0)