refactor(perf): use webdriver to execute benchmarks
- use performance log of chromedriver / appium to get timeline data for calculating metrics for benchmarks - change all benchmarks to be made of a standalone application and a protractor test that collectes timeline data - fix and simplify benchmarks - add dart2js to build - remove benchpress Closes #330
This commit is contained in:
parent
d642c6afb5
commit
df4ac0dd33
|
@ -1,4 +1,5 @@
|
||||||
language: node_js
|
language: node_js
|
||||||
|
sudo: false
|
||||||
node_js:
|
node_js:
|
||||||
- '0.10'
|
- '0.10'
|
||||||
env:
|
env:
|
||||||
|
|
85
gulpfile.js
85
gulpfile.js
|
@ -8,11 +8,12 @@ var clean = require('./tools/build/clean');
|
||||||
var deps = require('./tools/build/deps');
|
var deps = require('./tools/build/deps');
|
||||||
var transpile = require('./tools/build/transpile');
|
var transpile = require('./tools/build/transpile');
|
||||||
var html = require('./tools/build/html');
|
var html = require('./tools/build/html');
|
||||||
var benchpress = require('./tools/build/benchpress');
|
|
||||||
var pubspec = require('./tools/build/pubspec');
|
var pubspec = require('./tools/build/pubspec');
|
||||||
|
var pubbuild = require('./tools/build/pubbuild');
|
||||||
var dartanalyzer = require('./tools/build/dartanalyzer');
|
var dartanalyzer = require('./tools/build/dartanalyzer');
|
||||||
var jsserve = require('./tools/build/jsserve');
|
var jsserve = require('./tools/build/jsserve');
|
||||||
var pubserve = require('./tools/build/pubserve');
|
var pubserve = require('./tools/build/pubserve');
|
||||||
|
|
||||||
var DART_SDK = require('./tools/build/dartdetect')(gulp);
|
var DART_SDK = require('./tools/build/dartdetect')(gulp);
|
||||||
// -----------------------
|
// -----------------------
|
||||||
// configuration
|
// configuration
|
||||||
|
@ -43,23 +44,18 @@ var _HTLM_DEFAULT_SCRIPTS_JS = [
|
||||||
|
|
||||||
|
|
||||||
var CONFIG = {
|
var CONFIG = {
|
||||||
commands: {
|
|
||||||
pub: process.platform === 'win32' ? 'pub.bat' : 'pub',
|
|
||||||
dartanalyzer: process.platform === "win32" ? "dartanalyzer.bat" : "dartanalyzer"
|
|
||||||
},
|
|
||||||
dest: {
|
dest: {
|
||||||
js: {
|
js: {
|
||||||
all: 'dist/js',
|
all: 'dist/js',
|
||||||
dev: 'dist/js/dev',
|
dev: 'dist/js/dev',
|
||||||
prod: 'dist/js/prod'
|
prod: 'dist/js/prod',
|
||||||
|
dart2js: 'dist/js/dart2js'
|
||||||
},
|
},
|
||||||
dart: 'dist/dart'
|
dart: 'dist/dart'
|
||||||
},
|
},
|
||||||
srcFolderMapping: {
|
srcFolderMapping: {
|
||||||
'default': 'lib',
|
'default': 'lib',
|
||||||
// need a tmp folder as benchpress does not support
|
'**/benchmark*/**': 'web',
|
||||||
// inplace generation of the benchmarks...
|
|
||||||
'**/benchmark*/**': 'perf_tmp',
|
|
||||||
'**/example*/**': 'web'
|
'**/example*/**': 'web'
|
||||||
},
|
},
|
||||||
deps: {
|
deps: {
|
||||||
|
@ -76,12 +72,12 @@ var CONFIG = {
|
||||||
},
|
},
|
||||||
transpile: {
|
transpile: {
|
||||||
src: {
|
src: {
|
||||||
js: ['modules/**/*.js', 'modules/**/*.es6'],
|
js: ['modules/**/*.js', 'modules/**/*.es6', '!modules/**/perf/**/*'],
|
||||||
dart: ['modules/**/*.js']
|
dart: ['modules/**/*.js', '!modules/**/perf/**/*']
|
||||||
},
|
},
|
||||||
copy: {
|
copy: {
|
||||||
js: ['modules/**/*.es5'],
|
js: ['modules/**/*.es5', '!modules/**/perf/**/*'],
|
||||||
dart: ['modules/**/*.dart']
|
dart: ['modules/**/*.dart', '!modules/**/perf/**/*']
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
js: {
|
js: {
|
||||||
|
@ -122,14 +118,6 @@ var CONFIG = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
benchpress: {
|
|
||||||
configFile: {
|
|
||||||
content: 'module.exports=function(){};\n',
|
|
||||||
name: 'bp.conf.js'
|
|
||||||
},
|
|
||||||
mainHtmls: '*/perf_tmp/**/main.html',
|
|
||||||
outputFolderName: 'web'
|
|
||||||
},
|
|
||||||
pubspec: {
|
pubspec: {
|
||||||
src: 'modules/*/pubspec.yaml'
|
src: 'modules/*/pubspec.yaml'
|
||||||
}
|
}
|
||||||
|
@ -213,31 +201,6 @@ gulp.task('build/html.dart', html(gulp, gulpPlugins, {
|
||||||
scriptsPerFolder: CONFIG.html.scriptsPerFolder.dart
|
scriptsPerFolder: CONFIG.html.scriptsPerFolder.dart
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// ------------
|
|
||||||
// benchpress
|
|
||||||
|
|
||||||
gulp.task('build/benchpress.js.dev', benchpress(gulp, gulpPlugins, {
|
|
||||||
mainHtmls: CONFIG.benchpress.mainHtmls,
|
|
||||||
configFile: CONFIG.benchpress.configFile,
|
|
||||||
buildDir: CONFIG.dest.js.dev,
|
|
||||||
outputFolderName: CONFIG.benchpress.outputFolderName
|
|
||||||
}));
|
|
||||||
|
|
||||||
gulp.task('build/benchpress.js.prod', benchpress(gulp, gulpPlugins, {
|
|
||||||
mainHtmls: CONFIG.benchpress.mainHtmls,
|
|
||||||
configFile: CONFIG.benchpress.configFile,
|
|
||||||
buildDir: CONFIG.dest.js.prod,
|
|
||||||
outputFolderName: CONFIG.benchpress.outputFolderName
|
|
||||||
}));
|
|
||||||
|
|
||||||
gulp.task('build/benchpress.dart', benchpress(gulp, gulpPlugins, {
|
|
||||||
mainHtmls: CONFIG.benchpress.mainHtmls,
|
|
||||||
configFile: CONFIG.benchpress.configFile,
|
|
||||||
buildDir: CONFIG.dest.dart,
|
|
||||||
outputFolderName: CONFIG.benchpress.outputFolderName
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
// ------------
|
// ------------
|
||||||
// pubspec
|
// pubspec
|
||||||
|
|
||||||
|
@ -248,7 +211,7 @@ gulp.task('build/pubspec.dart', pubspec(gulp, gulpPlugins, {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// ------------
|
// ------------
|
||||||
// pubspec
|
// dartanalyzer
|
||||||
|
|
||||||
gulp.task('build/analyze.dart', dartanalyzer(gulp, gulpPlugins, {
|
gulp.task('build/analyze.dart', dartanalyzer(gulp, gulpPlugins, {
|
||||||
dest: CONFIG.dest.dart,
|
dest: CONFIG.dest.dart,
|
||||||
|
@ -256,14 +219,30 @@ gulp.task('build/analyze.dart', dartanalyzer(gulp, gulpPlugins, {
|
||||||
srcFolderMapping: CONFIG.srcFolderMapping
|
srcFolderMapping: CONFIG.srcFolderMapping
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// ------------
|
||||||
|
// pubbuild
|
||||||
|
|
||||||
|
gulp.task('build/pubbuild.dart', pubbuild(gulp, gulpPlugins, {
|
||||||
|
src: CONFIG.dest.dart,
|
||||||
|
dest: CONFIG.dest.js.dart2js,
|
||||||
|
command: DART_SDK.PUB
|
||||||
|
}));
|
||||||
|
|
||||||
// ------------------
|
// ------------------
|
||||||
// web servers
|
// web servers
|
||||||
gulp.task('serve.js.dev', jsserve(gulp, gulpPlugins, {
|
gulp.task('serve.js.dev', jsserve(gulp, gulpPlugins, {
|
||||||
path: CONFIG.dest.js.dev
|
path: CONFIG.dest.js.dev,
|
||||||
|
port: 8000
|
||||||
}));
|
}));
|
||||||
|
|
||||||
gulp.task('serve.js.prod', jsserve(gulp, gulpPlugins, {
|
gulp.task('serve.js.prod', jsserve(gulp, gulpPlugins, {
|
||||||
path: CONFIG.dest.js.prod
|
path: CONFIG.dest.js.prod,
|
||||||
|
port: 8001
|
||||||
|
}));
|
||||||
|
|
||||||
|
gulp.task('serve.js.dart2js', jsserve(gulp, gulpPlugins, {
|
||||||
|
path: CONFIG.dest.js.dart2js,
|
||||||
|
port: 8002
|
||||||
}));
|
}));
|
||||||
|
|
||||||
gulp.task('serve/examples.dart', pubserve(gulp, gulpPlugins, {
|
gulp.task('serve/examples.dart', pubserve(gulp, gulpPlugins, {
|
||||||
|
@ -343,22 +322,20 @@ gulp.task('build.dart', function() {
|
||||||
return runSequence(
|
return runSequence(
|
||||||
['build/transpile.dart', 'build/html.dart'],
|
['build/transpile.dart', 'build/html.dart'],
|
||||||
'build/pubspec.dart',
|
'build/pubspec.dart',
|
||||||
'build/benchpress.dart',
|
'build/pubbuild.dart',
|
||||||
'build/analyze.dart'
|
'build/analyze.dart'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('build.js.dev', function() {
|
gulp.task('build.js.dev', function() {
|
||||||
return runSequence(
|
return runSequence(
|
||||||
['build/deps.js.dev', 'build/transpile.js.dev', 'build/html.js.dev'],
|
['build/deps.js.dev', 'build/transpile.js.dev', 'build/html.js.dev']
|
||||||
'build/benchpress.js.dev'
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('build.js.prod', function() {
|
gulp.task('build.js.prod', function() {
|
||||||
return runSequence(
|
return runSequence(
|
||||||
['build/deps.js.prod', 'build/transpile.js.prod', 'build/html.js.prod'],
|
['build/deps.js.prod', 'build/transpile.js.prod', 'build/html.js.prod']
|
||||||
'build/benchpress.js.prod'
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,4 @@ dependencies:
|
||||||
path: ../core
|
path: ../core
|
||||||
change_detection:
|
change_detection:
|
||||||
path: ../change_detection
|
path: ../change_detection
|
||||||
benchpress:
|
|
||||||
path: ../benchpress
|
|
||||||
browser: '>=0.10.0 <0.11.0'
|
browser: '>=0.10.0 <0.11.0'
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<button id="ng2DetectChanges">Ng2 detect changes</button>
|
||||||
|
<button id="baselineDetectChanges">baseline detect changes</button>
|
||||||
|
|
||||||
|
$SCRIPTS$
|
||||||
|
|
||||||
|
</body>
|
|
@ -3,7 +3,7 @@ import {Parser} from 'change_detection/parser/parser';
|
||||||
import {Lexer} from 'change_detection/parser/lexer';
|
import {Lexer} from 'change_detection/parser/lexer';
|
||||||
import {reflector} from 'reflection/reflection';
|
import {reflector} from 'reflection/reflection';
|
||||||
import {isPresent} from 'facade/lang';
|
import {isPresent} from 'facade/lang';
|
||||||
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
|
import {document, DOM} from 'facade/dom';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ChangeDetector,
|
ChangeDetector,
|
||||||
|
@ -12,7 +12,7 @@ import {
|
||||||
} from 'change_detection/change_detector';
|
} from 'change_detection/change_detector';
|
||||||
|
|
||||||
|
|
||||||
var ITERATIONS = 200000;
|
var ITERATIONS = 500000;
|
||||||
|
|
||||||
class Obj {
|
class Obj {
|
||||||
field0;
|
field0;
|
||||||
|
@ -155,28 +155,25 @@ function setUpChangeDetection() {
|
||||||
|
|
||||||
export function main () {
|
export function main () {
|
||||||
setUpReflector();
|
setUpReflector();
|
||||||
|
var baselineHead = setUpBaseline();
|
||||||
|
var ng2ChangeDetector = setUpChangeDetection();
|
||||||
|
|
||||||
benchmark(`Baseline`, function () {
|
function baselineDetectChanges(_) {
|
||||||
var head = setUpBaseline();
|
var current = baselineHead;
|
||||||
|
|
||||||
benchmarkStep('run', function () {
|
|
||||||
var current = head;
|
|
||||||
while (isPresent(current)) {
|
while (isPresent(current)) {
|
||||||
if (current.getter(current.obj) !== current.previousValue) {
|
if (current.getter(current.obj) !== current.previousValue) {
|
||||||
throw "should not happen";
|
throw "should not happen";
|
||||||
}
|
}
|
||||||
current = current.next;
|
current = current.next;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
|
||||||
benchmark(`Change Detection`, function() {
|
function ng2DetectChanges(_) {
|
||||||
var cd = setUpChangeDetection();
|
ng2ChangeDetector.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
benchmarkStep('run', function() {
|
DOM.on(DOM.querySelector(document, '#ng2DetectChanges'), 'click', ng2DetectChanges);
|
||||||
cd.detectChanges();
|
DOM.on(DOM.querySelector(document, '#baselineDetectChanges'), 'click', baselineDetectChanges);
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
$SCRIPTS$
|
|
|
@ -1,5 +0,0 @@
|
||||||
import * as change_detection_benchmark from './change_detection_benchmark';
|
|
||||||
|
|
||||||
export function main() {
|
|
||||||
change_detection_benchmark.main();
|
|
||||||
}
|
|
|
@ -1,4 +1,9 @@
|
||||||
$SCRIPTS$
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<button id="compileWithBindings">Compile template with bindings</button>
|
||||||
|
<button id="compileNoBindings">Compile template without bindings</button>
|
||||||
|
|
||||||
<template id="templateNoBindings">
|
<template id="templateNoBindings">
|
||||||
<div class="class0 class1 class2 class3 class4 " nodir0="" attr0="value0" nodir1="" attr1="value1" nodir2="" attr2="value2" nodir3="" attr3="value3" nodir4="" attr4="value4">
|
<div class="class0 class1 class2 class3 class4 " nodir0="" attr0="value0" nodir1="" attr1="value1" nodir2="" attr2="value2" nodir3="" attr3="value3" nodir4="" attr4="value4">
|
||||||
|
@ -30,3 +35,8 @@ $SCRIPTS$
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
$SCRIPTS$
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,5 +1,3 @@
|
||||||
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
|
|
||||||
|
|
||||||
import {DOM, document} from 'facade/dom';
|
import {DOM, document} from 'facade/dom';
|
||||||
import {isBlank, Type} from 'facade/lang';
|
import {isBlank, Type} from 'facade/lang';
|
||||||
import {MapWrapper} from 'facade/collection';
|
import {MapWrapper} from 'facade/collection';
|
||||||
|
@ -20,10 +18,7 @@ import {reflector} from 'reflection/reflection';
|
||||||
|
|
||||||
var COUNT = 30;
|
var COUNT = 30;
|
||||||
|
|
||||||
var compiler;
|
function setupReflector() {
|
||||||
var annotatedComponent;
|
|
||||||
|
|
||||||
function setup() {
|
|
||||||
reflector.registerType(BenchmarkComponent, {
|
reflector.registerType(BenchmarkComponent, {
|
||||||
"factory": () => new BenchmarkComponent(),
|
"factory": () => new BenchmarkComponent(),
|
||||||
"parameters": [],
|
"parameters": [],
|
||||||
|
@ -79,47 +74,34 @@ function setup() {
|
||||||
|
|
||||||
"prop": (a,v) => a.prop = v
|
"prop": (a,v) => a.prop = v
|
||||||
});
|
});
|
||||||
|
|
||||||
var reader = new CachingDirectiveMetadataReader();
|
|
||||||
compiler = new Compiler(null, reader, new Parser(new Lexer()), new CompilerCache());
|
|
||||||
annotatedComponent = reader.annotatedType(BenchmarkComponent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
setup();
|
setupReflector();
|
||||||
|
var reader = new DirectiveMetadataReader();
|
||||||
|
var cache = new CompilerCache();
|
||||||
|
var compiler = new Compiler(null, reader, new Parser(new Lexer()), cache);
|
||||||
|
var annotatedComponent = reader.annotatedType(BenchmarkComponent);
|
||||||
|
|
||||||
benchmark(`Compiler.compile 5*${COUNT} element no bindings`, function() {
|
var templateNoBindings = loadTemplate('templateNoBindings', COUNT);
|
||||||
var template = loadTemplate('templateNoBindings', COUNT);
|
var templateWithBindings = loadTemplate('templateWithBindings', COUNT);
|
||||||
|
|
||||||
benchmarkStep('run', function() {
|
function compileNoBindings(_) {
|
||||||
// Need to clone every time as the compiler might modify the template!
|
// Need to clone every time as the compiler might modify the template!
|
||||||
var cloned = DOM.clone(template);
|
var cloned = DOM.clone(templateNoBindings);
|
||||||
|
cache.clear();
|
||||||
compiler.compileAllLoaded(null, annotatedComponent, cloned);
|
compiler.compileAllLoaded(null, annotatedComponent, cloned);
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
|
||||||
benchmark(`Compiler.compile 5*${COUNT} element with bindings`, function() {
|
function compileWithBindings(_) {
|
||||||
var template = loadTemplate('templateWithBindings', COUNT);
|
|
||||||
|
|
||||||
benchmarkStep('run', function() {
|
|
||||||
// Need to clone every time as the compiler might modify the template!
|
// Need to clone every time as the compiler might modify the template!
|
||||||
var cloned = DOM.clone(template);
|
var cloned = DOM.clone(templateWithBindings);
|
||||||
|
cache.clear();
|
||||||
compiler.compileAllLoaded(null, annotatedComponent, cloned);
|
compiler.compileAllLoaded(null, annotatedComponent, cloned);
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
|
||||||
benchmark(`instantiate 5*${COUNT} element with bindings`, function() {
|
DOM.on(DOM.querySelector(document, '#compileNoBindings'), 'click', compileNoBindings);
|
||||||
var template = loadTemplate('templateWithBindings', COUNT);
|
DOM.on(DOM.querySelector(document, '#compileWithBindings'), 'click', compileWithBindings);
|
||||||
var protoView = compiler.compileWithCache(null, annotatedComponent, template);
|
|
||||||
var rootRecordRange = new ProtoRecordRange().instantiate(null, null);
|
|
||||||
|
|
||||||
benchmarkStep('run', function() {
|
|
||||||
var view = protoView.instantiate(null, null, null);
|
|
||||||
// also include adding / removing the RecordRange from the parent in the benchmark.
|
|
||||||
rootRecordRange.addRange(view.recordRange);
|
|
||||||
view.recordRange.remove();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadTemplate(templateId, repeatCount) {
|
function loadTemplate(templateId, repeatCount) {
|
||||||
|
@ -132,22 +114,6 @@ function loadTemplate(templateId, repeatCount) {
|
||||||
return DOM.createTemplate(result);
|
return DOM.createTemplate(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Caching reflector as reflection in Dart using Mirrors
|
|
||||||
class CachingDirectiveMetadataReader extends DirectiveMetadataReader {
|
|
||||||
_cache: Map;
|
|
||||||
constructor() {
|
|
||||||
this._cache = MapWrapper.create();
|
|
||||||
}
|
|
||||||
annotatedType(type:Type):AnnotatedType {
|
|
||||||
var result = MapWrapper.get(this._cache, type);
|
|
||||||
if (isBlank(result)) {
|
|
||||||
result = super.annotatedType(type);
|
|
||||||
MapWrapper.set(this._cache, type, result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Decorator({
|
@Decorator({
|
||||||
selector: '[dir0]',
|
selector: '[dir0]',
|
||||||
bind: {
|
bind: {
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
import * as sbm from './selector_benchmark';
|
|
||||||
import * as cbm from './compiler_benchmark';
|
|
||||||
|
|
||||||
export function main() {
|
|
||||||
sbm.main();
|
|
||||||
cbm.main();
|
|
||||||
}
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<button id="parse">Selector.parse</button>
|
||||||
|
<button id="addSelectable">Selector.addSelectable</button>
|
||||||
|
<button id="match">Selector.match</button>
|
||||||
|
|
||||||
|
$SCRIPTS$
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,41 +1,44 @@
|
||||||
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
|
import {document, DOM} from 'facade/dom';
|
||||||
|
|
||||||
import {SelectorMatcher} from "core/compiler/selector";
|
import {SelectorMatcher} from "core/compiler/selector";
|
||||||
import {CssSelector} from "core/compiler/selector";
|
import {CssSelector} from "core/compiler/selector";
|
||||||
import {StringWrapper, Math} from 'facade/lang';
|
import {StringWrapper, Math} from 'facade/lang';
|
||||||
import {ListWrapper} from 'facade/collection';
|
import {ListWrapper} from 'facade/collection';
|
||||||
|
|
||||||
var fixedMatcher;
|
|
||||||
var fixedSelectorStrings = [];
|
|
||||||
var fixedSelectors = [];
|
|
||||||
|
|
||||||
var COUNT = 1000;
|
var COUNT = 1000;
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
setup(COUNT);
|
var fixedMatcher;
|
||||||
|
var fixedSelectorStrings = [];
|
||||||
|
var fixedSelectors = [];
|
||||||
|
for (var i=0; i<COUNT; i++) {
|
||||||
|
ListWrapper.push(fixedSelectorStrings, randomSelector());
|
||||||
|
}
|
||||||
|
for (var i=0; i<COUNT; i++) {
|
||||||
|
ListWrapper.push(fixedSelectors, CssSelector.parse(fixedSelectorStrings[i]));
|
||||||
|
}
|
||||||
|
fixedMatcher = new SelectorMatcher();
|
||||||
|
for (var i=0; i<COUNT; i++) {
|
||||||
|
fixedMatcher.addSelectable(fixedSelectors[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
benchmark(`cssSelector.parse * ${COUNT}`, function() {
|
function parse(_) {
|
||||||
benchmarkStep(`run`, function() {
|
|
||||||
var result = [];
|
var result = [];
|
||||||
for (var i=0; i<COUNT; i++) {
|
for (var i=0; i<COUNT; i++) {
|
||||||
ListWrapper.push(result, CssSelector.parse(fixedSelectorStrings[i]));
|
ListWrapper.push(result, CssSelector.parse(fixedSelectorStrings[i]));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
|
||||||
benchmark(`cssSelector.addSelectable * ${COUNT}`, function() {
|
function addSelectable(_) {
|
||||||
benchmarkStep(`run`, function() {
|
|
||||||
var matcher = new SelectorMatcher();
|
var matcher = new SelectorMatcher();
|
||||||
for (var i=0; i<COUNT; i++) {
|
for (var i=0; i<COUNT; i++) {
|
||||||
matcher.addSelectable(fixedSelectors[i], i);
|
matcher.addSelectable(fixedSelectors[i], i);
|
||||||
}
|
}
|
||||||
return matcher;
|
return matcher;
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
|
||||||
benchmark(`cssSelector.match * ${COUNT}`, function() {
|
function match(_) {
|
||||||
benchmarkStep(`run`, function() {
|
|
||||||
var matchCount = 0;
|
var matchCount = 0;
|
||||||
for (var i=0; i<COUNT; i++) {
|
for (var i=0; i<COUNT; i++) {
|
||||||
fixedMatcher.match(fixedSelectors[i], (selected) => {
|
fixedMatcher.match(fixedSelectors[i], (selected) => {
|
||||||
|
@ -43,21 +46,11 @@ export function main() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return matchCount;
|
return matchCount;
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup(count) {
|
DOM.on(DOM.querySelector(document, '#parse'), 'click', parse);
|
||||||
for (var i=0; i<count; i++) {
|
DOM.on(DOM.querySelector(document, '#addSelectable'), 'click', addSelectable);
|
||||||
ListWrapper.push(fixedSelectorStrings, randomSelector());
|
DOM.on(DOM.querySelector(document, '#match'), 'click', match);
|
||||||
}
|
|
||||||
for (var i=0; i<count; i++) {
|
|
||||||
ListWrapper.push(fixedSelectors, CssSelector.parse(fixedSelectorStrings[i]));
|
|
||||||
}
|
|
||||||
fixedMatcher = new SelectorMatcher();
|
|
||||||
for (var i=0; i<count; i++) {
|
|
||||||
fixedMatcher.addSelectable(fixedSelectors[i], i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function randomSelector() {
|
function randomSelector() {
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<button id="getByToken">Injector.get (token)</button>
|
||||||
|
<button id="getByKey">Injector.get (key)</button>
|
||||||
|
<button id="getChild">Injector.get (grand x 5 child)</button>
|
||||||
|
<button id="instantiate">Injector.instantiate</button>
|
||||||
|
|
||||||
|
$SCRIPTS$
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,113 @@
|
||||||
|
import {Injector, Key} from "di/di";
|
||||||
|
import {reflector} from 'reflection/reflection';
|
||||||
|
import {document, DOM} from 'facade/dom';
|
||||||
|
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
function setupReflector() {
|
||||||
|
reflector.registerType(A, {
|
||||||
|
'factory': () => new A(),
|
||||||
|
'parameters': [],
|
||||||
|
'annotations' : []
|
||||||
|
});
|
||||||
|
reflector.registerType(B, {
|
||||||
|
'factory': (a) => new B(a),
|
||||||
|
'parameters': [[A]],
|
||||||
|
'annotations' : []
|
||||||
|
});
|
||||||
|
reflector.registerType(C, {
|
||||||
|
'factory': (b) => new C(b),
|
||||||
|
'parameters': [[B]],
|
||||||
|
'annotations' : []
|
||||||
|
});
|
||||||
|
reflector.registerType(D, {
|
||||||
|
'factory': (c,b) => new D(c,b),
|
||||||
|
'parameters': [[C],[B]],
|
||||||
|
'annotations' : []
|
||||||
|
});
|
||||||
|
reflector.registerType(E, {
|
||||||
|
'factory': (d,c) => new E(d,c),
|
||||||
|
'parameters': [[D],[C]],
|
||||||
|
'annotations' : []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
setupReflector();
|
||||||
|
var bindings = [A, B, C, D, E];
|
||||||
|
var injector = new Injector(bindings);
|
||||||
|
|
||||||
|
var D_KEY = Key.get(D);
|
||||||
|
var E_KEY = Key.get(E);
|
||||||
|
var childInjector = injector.
|
||||||
|
createChild([]).
|
||||||
|
createChild([]).
|
||||||
|
createChild([]).
|
||||||
|
createChild([]).
|
||||||
|
createChild([]);
|
||||||
|
|
||||||
|
function getByToken (_) {
|
||||||
|
for (var i = 0; i < 20000; ++i) {
|
||||||
|
injector.get(D);
|
||||||
|
injector.get(E);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getByKey(_) {
|
||||||
|
for (var i = 0; i < 20000; ++i) {
|
||||||
|
injector.get(D_KEY);
|
||||||
|
injector.get(E_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getChild (_) {
|
||||||
|
for (var i = 0; i < 20000; ++i) {
|
||||||
|
childInjector.get(D);
|
||||||
|
childInjector.get(E);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function instantiate (_) {
|
||||||
|
for (var i = 0; i < 5000; ++i) {
|
||||||
|
var child = injector.createChild([E]);
|
||||||
|
child.get(E);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DOM.on(DOM.querySelector(document, '#getByToken'), 'click', getByToken);
|
||||||
|
DOM.on(DOM.querySelector(document, '#getByKey'), 'click', getByKey);
|
||||||
|
DOM.on(DOM.querySelector(document, '#getChild'), 'click', getChild);
|
||||||
|
DOM.on(DOM.querySelector(document, '#instantiate'), 'click', instantiate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class A {
|
||||||
|
constructor() {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
constructor(a:A) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
constructor(b:B) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class D {
|
||||||
|
constructor(c:C, b:B) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class E {
|
||||||
|
constructor(d:D, c:C) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,43 +0,0 @@
|
||||||
import {Injector} from "di/di";
|
|
||||||
|
|
||||||
var count = 0;
|
|
||||||
|
|
||||||
export function run () {
|
|
||||||
var bindings = [A, B, C, D, E];
|
|
||||||
var injector = new Injector(bindings);
|
|
||||||
|
|
||||||
for (var i = 0; i < 20000; ++i) {
|
|
||||||
injector.get(D);
|
|
||||||
injector.get(E);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class A {
|
|
||||||
constructor() {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class B {
|
|
||||||
constructor(a:A) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class C {
|
|
||||||
constructor(b:B) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class D {
|
|
||||||
constructor(c:C, b:B) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class E {
|
|
||||||
constructor(d:D, c:C) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
import {Injector, Key} from "di/di";
|
|
||||||
|
|
||||||
var count = 0;
|
|
||||||
|
|
||||||
export function run () {
|
|
||||||
var bindings = [A, B, C, D, E];
|
|
||||||
var injector = new Injector(bindings);
|
|
||||||
|
|
||||||
var D_KEY = Key.get(D);
|
|
||||||
var E_KEY = Key.get(E);
|
|
||||||
|
|
||||||
for (var i = 0; i < 20000; ++i) {
|
|
||||||
injector.get(D_KEY);
|
|
||||||
injector.get(E_KEY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class A {
|
|
||||||
constructor() {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class B {
|
|
||||||
constructor(a:A) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class C {
|
|
||||||
constructor(b:B) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class D {
|
|
||||||
constructor(c:C, b:B) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class E {
|
|
||||||
constructor(d:D, c:C) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
import {Injector, Key} from "di/di";
|
|
||||||
|
|
||||||
var count = 0;
|
|
||||||
|
|
||||||
export function run () {
|
|
||||||
var bindings = [A, B, C, D, E];
|
|
||||||
var injector = new Injector(bindings);
|
|
||||||
var childInjector = injector.
|
|
||||||
createChild([]).
|
|
||||||
createChild([]).
|
|
||||||
createChild([]).
|
|
||||||
createChild([]).
|
|
||||||
createChild([]);
|
|
||||||
|
|
||||||
for (var i = 0; i < 20000; ++i) {
|
|
||||||
childInjector.get(D);
|
|
||||||
childInjector.get(E);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class A {
|
|
||||||
constructor() {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class B {
|
|
||||||
constructor(a:A) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class C {
|
|
||||||
constructor(b:B) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class D {
|
|
||||||
constructor(c:C, b:B) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class E {
|
|
||||||
constructor(d:D, c:C) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
import {Injector, Key} from "di/di";
|
|
||||||
|
|
||||||
var count = 0;
|
|
||||||
|
|
||||||
export function run () {
|
|
||||||
var bindings = [A, B, C, D];
|
|
||||||
var injector = new Injector(bindings);
|
|
||||||
|
|
||||||
for (var i = 0; i < 1000; ++i) {
|
|
||||||
var child = injector.createChild([E]);
|
|
||||||
child.get(E);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class A {
|
|
||||||
constructor() {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class B {
|
|
||||||
constructor(a:A) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class C {
|
|
||||||
constructor(b:B) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class D {
|
|
||||||
constructor(c:C, b:B) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class E {
|
|
||||||
constructor(d:D, c:C) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
$SCRIPTS$
|
|
|
@ -1,24 +0,0 @@
|
||||||
import * as injector_get_benchmark from './injector_get_benchmark';
|
|
||||||
import * as injector_get_by_key_benchmark from './injector_get_by_key_benchmark';
|
|
||||||
import * as injector_get_child_benchmark from './injector_get_child_benchmark';
|
|
||||||
import * as injector_instantiate_benchmark from './injector_instantiate_benchmark';
|
|
||||||
|
|
||||||
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
|
|
||||||
|
|
||||||
export function main() {
|
|
||||||
benchmark(`Injector.get (token)`, function() {
|
|
||||||
benchmarkStep('run', injector_get_benchmark.run);
|
|
||||||
});
|
|
||||||
|
|
||||||
benchmark(`Injector.get (key)`, function() {
|
|
||||||
benchmarkStep('run', injector_get_by_key_benchmark.run);
|
|
||||||
});
|
|
||||||
|
|
||||||
benchmark(`Injector.get (grand x 5 child)`, function() {
|
|
||||||
benchmarkStep('run', injector_get_child_benchmark.run);
|
|
||||||
});
|
|
||||||
|
|
||||||
benchmark(`Injector.instantiate`, function() {
|
|
||||||
benchmarkStep('run', injector_instantiate_benchmark.run);
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<button id="instantiate">ElementInjector.instantiate</button>
|
||||||
|
<button id="instantiateDirectives">ElementInjector.instantiateDirectives</button>
|
||||||
|
|
||||||
|
$SCRIPTS$
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,69 @@
|
||||||
|
import {reflector} from 'reflection/reflection';
|
||||||
|
import {Injector} from 'di/di';
|
||||||
|
import {ProtoElementInjector} from 'core/compiler/element_injector';
|
||||||
|
import {document, DOM} from 'facade/dom';
|
||||||
|
|
||||||
|
var count = 0;
|
||||||
|
var ITERATIONS = 20000;
|
||||||
|
|
||||||
|
function setupReflector() {
|
||||||
|
reflector.registerType(A, {
|
||||||
|
'factory': () => new A(),
|
||||||
|
'parameters': [],
|
||||||
|
'annotations' : []
|
||||||
|
});
|
||||||
|
reflector.registerType(B, {
|
||||||
|
'factory': () => new B(),
|
||||||
|
'parameters': [],
|
||||||
|
'annotations' : []
|
||||||
|
});
|
||||||
|
reflector.registerType(C, {
|
||||||
|
'factory': (a,b) => new C(a,b),
|
||||||
|
'parameters': [[A],[B]],
|
||||||
|
'annotations' : []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
setupReflector();
|
||||||
|
var appInjector = new Injector([]);
|
||||||
|
|
||||||
|
var bindings = [A, B, C];
|
||||||
|
var proto = new ProtoElementInjector(null, 0, bindings);
|
||||||
|
var elementInjector = proto.instantiate(null,null);
|
||||||
|
|
||||||
|
function instantiate (_) {
|
||||||
|
for (var i = 0; i < ITERATIONS; ++i) {
|
||||||
|
var ei = proto.instantiate(null, null);
|
||||||
|
ei.instantiateDirectives(appInjector, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function instantiateDirectives (_) {
|
||||||
|
for (var i = 0; i < ITERATIONS; ++i) {
|
||||||
|
elementInjector.clearDirectives();
|
||||||
|
elementInjector.instantiateDirectives(appInjector, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DOM.on(DOM.querySelector(document, '#instantiate'), 'click', instantiate);
|
||||||
|
DOM.on(DOM.querySelector(document, '#instantiateDirectives'), 'click', instantiateDirectives);
|
||||||
|
}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
constructor() {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
constructor() {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
constructor(a:A, b:B) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
import {Injector} from 'di/di';
|
|
||||||
import {ProtoElementInjector} from 'core/compiler/element_injector';
|
|
||||||
|
|
||||||
var ITERATIONS = 20000;
|
|
||||||
var count = 0;
|
|
||||||
|
|
||||||
export function run () {
|
|
||||||
var appInjector = new Injector([]);
|
|
||||||
|
|
||||||
var bindings = [A, B, C];
|
|
||||||
var proto = new ProtoElementInjector(null, 0, bindings);
|
|
||||||
for (var i = 0; i < ITERATIONS; ++i) {
|
|
||||||
var ei = proto.instantiate(null, null);
|
|
||||||
ei.instantiateDirectives(appInjector, null, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class A {
|
|
||||||
constructor() {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class B {
|
|
||||||
constructor() {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class C {
|
|
||||||
constructor(a:A, b:B) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
import {Binding, Dependency, Key, Injector} from 'di/di';
|
|
||||||
import {ProtoElementInjector} from 'core/compiler/element_injector';
|
|
||||||
|
|
||||||
var ITERATIONS = 20000;
|
|
||||||
var count = 0;
|
|
||||||
|
|
||||||
export function run () {
|
|
||||||
var appInjector = new Injector([]);
|
|
||||||
|
|
||||||
var bindings = [
|
|
||||||
new Binding(Key.get(A), () => new A(), [], false),
|
|
||||||
new Binding(Key.get(B), () => new B(), [], false),
|
|
||||||
new Binding(Key.get(C), (a,b) => new C(a,b), [
|
|
||||||
new Dependency(Key.get(A), false, false, []),
|
|
||||||
new Dependency(Key.get(B), false, false, [])
|
|
||||||
], false)];
|
|
||||||
|
|
||||||
|
|
||||||
var proto = new ProtoElementInjector(null, 0, bindings);
|
|
||||||
for (var i = 0; i < ITERATIONS; ++i) {
|
|
||||||
var ei = proto.instantiate(null,null);
|
|
||||||
ei.instantiateDirectives(appInjector, null, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class A {
|
|
||||||
constructor() {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class B {
|
|
||||||
constructor() {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class C {
|
|
||||||
constructor(a:A, b:B) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
import {Injector} from 'di/di';
|
|
||||||
import {ProtoElementInjector} from 'core/compiler/element_injector';
|
|
||||||
|
|
||||||
var ITERATIONS = 20000;
|
|
||||||
var count = 0;
|
|
||||||
|
|
||||||
export function run () {
|
|
||||||
var appInjector = new Injector([]);
|
|
||||||
|
|
||||||
var bindings = [A, B, C];
|
|
||||||
var proto = new ProtoElementInjector(null, 0, bindings);
|
|
||||||
var ei = proto.instantiate(null,null);
|
|
||||||
|
|
||||||
for (var i = 0; i < ITERATIONS; ++i) {
|
|
||||||
ei.clearDirectives();
|
|
||||||
ei.instantiateDirectives(appInjector, null, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class A {
|
|
||||||
constructor() {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class B {
|
|
||||||
constructor() {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class C {
|
|
||||||
constructor(a:A, b:B) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
$SCRIPTS$
|
|
|
@ -1,19 +0,0 @@
|
||||||
import * as instantiate_benchmark from './instantiate_benchmark';
|
|
||||||
import * as instantiate_directive_benchmark from './instantiate_directive_benchmark';
|
|
||||||
import * as instantiate_benchmark_codegen from './instantiate_benchmark_codegen';
|
|
||||||
|
|
||||||
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
|
|
||||||
|
|
||||||
export function main() {
|
|
||||||
benchmark(`ElementInjector.instantiate + instantiateDirectives`, function() {
|
|
||||||
benchmarkStep('run', instantiate_benchmark.run);
|
|
||||||
});
|
|
||||||
|
|
||||||
benchmark(`ElementInjector.instantiateDirectives`, function() {
|
|
||||||
benchmarkStep('run', instantiate_directive_benchmark.run);
|
|
||||||
});
|
|
||||||
|
|
||||||
benchmark(`ElementInjector.instantiate + instantiateDirectives (codegen)`, function() {
|
|
||||||
benchmarkStep('run', instantiate_benchmark_codegen.run);
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="di/di_benchmark.html">DI benchmark</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="change_detection/change_detection_benchmark.html">Change detection benchmark</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="compiler/selector_benchmark.html">Selector benchmark</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="compiler/compiler_benchmark.html">Compiler benchmark</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="element_injector/element_injector_benchmark.html">Element injector benchmark</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="tree/tree_benchmark.html">Tree benchmark</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,5 +0,0 @@
|
||||||
$SCRIPTS$
|
|
||||||
|
|
||||||
<app></app>
|
|
||||||
|
|
||||||
<baseline></baseline>
|
|
|
@ -1,5 +0,0 @@
|
||||||
import * as tree_benchmark from './tree_benchmark';
|
|
||||||
|
|
||||||
export function main() {
|
|
||||||
tree_benchmark.main();
|
|
||||||
}
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h2>Angular2 tree benchmark</h2>
|
||||||
|
<p>
|
||||||
|
<button id="ng2DestroyDom">destroyDom</button>
|
||||||
|
<button id="ng2CreateDom">createDom</button>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Baseline tree benchmark</h2>
|
||||||
|
<p>
|
||||||
|
<button id="baselineDestroyDom">destroyDom</button>
|
||||||
|
<button id="baselineCreateDom">createDom</button>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<app></app>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<baseline></baseline>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
$SCRIPTS$
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,5 +1,3 @@
|
||||||
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
|
|
||||||
|
|
||||||
import {ChangeDetector} from 'change_detection/change_detector';
|
import {ChangeDetector} from 'change_detection/change_detector';
|
||||||
import {Parser} from 'change_detection/parser/parser';
|
import {Parser} from 'change_detection/parser/parser';
|
||||||
import {Lexer} from 'change_detection/parser/lexer';
|
import {Lexer} from 'change_detection/parser/lexer';
|
||||||
|
@ -9,6 +7,7 @@ import {bootstrap, Component, Template, TemplateConfig, ViewPort, Compiler} from
|
||||||
import {CompilerCache} from 'core/compiler/compiler';
|
import {CompilerCache} from 'core/compiler/compiler';
|
||||||
import {DirectiveMetadataReader} from 'core/compiler/directive_metadata_reader';
|
import {DirectiveMetadataReader} from 'core/compiler/directive_metadata_reader';
|
||||||
import {TemplateLoader} from 'core/compiler/template_loader';
|
import {TemplateLoader} from 'core/compiler/template_loader';
|
||||||
|
import {LifeCycle} from 'core/life_cycle/life_cycle';
|
||||||
|
|
||||||
import {reflector} from 'reflection/reflection';
|
import {reflector} from 'reflection/reflection';
|
||||||
import {DOM, document, Element} from 'facade/dom';
|
import {DOM, document, Element} from 'facade/dom';
|
||||||
|
@ -16,7 +15,7 @@ import {isPresent} from 'facade/lang';
|
||||||
|
|
||||||
var MAX_DEPTH = 9;
|
var MAX_DEPTH = 9;
|
||||||
|
|
||||||
function setup() {
|
function setupReflector() {
|
||||||
// TODO: Put the general calls to reflector.register... in a shared file
|
// TODO: Put the general calls to reflector.register... in a shared file
|
||||||
// as they are needed in all benchmarks...
|
// as they are needed in all benchmarks...
|
||||||
|
|
||||||
|
@ -98,6 +97,12 @@ function setup() {
|
||||||
'annotations': []
|
'annotations': []
|
||||||
});
|
});
|
||||||
|
|
||||||
|
reflector.registerType(LifeCycle, {
|
||||||
|
"factory": (cd) => new LifeCycle(cd),
|
||||||
|
"parameters": [[ChangeDetector]],
|
||||||
|
"annotations": []
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
reflector.registerGetters({
|
reflector.registerGetters({
|
||||||
'value': (a) => a.value,
|
'value': (a) => a.value,
|
||||||
|
@ -115,61 +120,62 @@ function setup() {
|
||||||
'data': (a,v) => a.data = v,
|
'data': (a,v) => a.data = v,
|
||||||
'ngIf': (a,v) => a.ngIf = v
|
'ngIf': (a,v) => a.ngIf = v
|
||||||
});
|
});
|
||||||
|
|
||||||
return bootstrap(AppComponent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
|
setupReflector();
|
||||||
|
|
||||||
var app;
|
var app;
|
||||||
var changeDetector;
|
var changeDetector;
|
||||||
setup().then((injector) => {
|
var baselineRootTreeComponent;
|
||||||
changeDetector = injector.get(ChangeDetector);
|
|
||||||
app = injector.get(AppComponent);
|
|
||||||
});
|
|
||||||
|
|
||||||
benchmark(`tree benchmark`, function() {
|
|
||||||
var count = 0;
|
var count = 0;
|
||||||
|
|
||||||
benchmarkStep(`destroyDom binary tree of depth ${MAX_DEPTH}`, function() {
|
function ng2DestroyDom(_) {
|
||||||
// TODO: We need an initial value as otherwise the getter for data.value will fail
|
// TODO: We need an initial value as otherwise the getter for data.value will fail
|
||||||
// --> this should be already caught in change detection!
|
// --> this should be already caught in change detection!
|
||||||
app.initData = new TreeNode('', null, null);
|
app.initData = new TreeNode('', null, null);
|
||||||
changeDetector.detectChanges();
|
changeDetector.detectChanges();
|
||||||
});
|
}
|
||||||
|
|
||||||
benchmarkStep(`createDom binary tree of depth ${MAX_DEPTH}`, function() {
|
function ng2CreateDom(_) {
|
||||||
var maxDepth = 9;
|
|
||||||
var values = count++ % 2 == 0 ?
|
var values = count++ % 2 == 0 ?
|
||||||
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] :
|
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] :
|
||||||
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-'];
|
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-'];
|
||||||
|
|
||||||
app.initData = buildTree(maxDepth, values, 0);
|
app.initData = buildTree(MAX_DEPTH, values, 0);
|
||||||
changeDetector.detectChanges();
|
changeDetector.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
function initNg2() {
|
||||||
|
bootstrap(AppComponent).then((injector) => {
|
||||||
|
changeDetector = injector.get(ChangeDetector);
|
||||||
|
app = injector.get(AppComponent);
|
||||||
|
DOM.on(DOM.querySelector(document, '#ng2DestroyDom'), 'click', ng2DestroyDom);
|
||||||
|
DOM.on(DOM.querySelector(document, '#ng2CreateDom'), 'click', ng2CreateDom);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
});
|
function baselineDestroyDom(_) {
|
||||||
|
baselineRootTreeComponent.update(new TreeNode('', null, null));
|
||||||
|
}
|
||||||
|
|
||||||
benchmark(`baseline tree benchmark`, function() {
|
function baselineCreateDom(_) {
|
||||||
var baselineAppElement = DOM.querySelectorAll(document, 'baseline')[0];
|
|
||||||
var rootTreeComponent = new BaseLineTreeComponent();
|
|
||||||
DOM.appendChild(baselineAppElement, rootTreeComponent.element);
|
|
||||||
|
|
||||||
var count = 0;
|
|
||||||
|
|
||||||
benchmarkStep(`destroyDom binary tree of depth ${MAX_DEPTH}`, function() {
|
|
||||||
rootTreeComponent.update(new TreeNode('', null, null));
|
|
||||||
});
|
|
||||||
|
|
||||||
benchmarkStep(`createDom binary tree of depth ${MAX_DEPTH}`, function() {
|
|
||||||
var maxDepth = 9;
|
|
||||||
var values = count++ % 2 == 0 ?
|
var values = count++ % 2 == 0 ?
|
||||||
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] :
|
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] :
|
||||||
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-'];
|
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-'];
|
||||||
|
|
||||||
rootTreeComponent.update(buildTree(maxDepth, values, 0));
|
baselineRootTreeComponent.update(buildTree(MAX_DEPTH, values, 0));
|
||||||
});
|
}
|
||||||
|
|
||||||
});
|
function initBaseline() {
|
||||||
|
baselineRootTreeComponent = new BaseLineTreeComponent();
|
||||||
|
DOM.appendChild(DOM.querySelector(document, 'baseline'), baselineRootTreeComponent.element);
|
||||||
|
DOM.on(DOM.querySelector(document, '#baselineDestroyDom'), 'click', baselineDestroyDom);
|
||||||
|
DOM.on(DOM.querySelector(document, '#baselineCreateDom'), 'click', baselineCreateDom);
|
||||||
|
}
|
||||||
|
|
||||||
|
initNg2();
|
||||||
|
initBaseline();
|
||||||
}
|
}
|
||||||
|
|
||||||
class TreeNode {
|
class TreeNode {
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
"use strict";
|
||||||
|
var util = require('../../../../tools/perf/util.js');
|
||||||
|
|
||||||
|
describe('ng2 change detection benchmark', function () {
|
||||||
|
|
||||||
|
var URL = 'benchmarks/web/change_detection/change_detection_benchmark.html';
|
||||||
|
|
||||||
|
afterEach(util.verifyNoErrors);
|
||||||
|
|
||||||
|
it('should log ng stats', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#ng2DetectChanges'],
|
||||||
|
name: browser.params.lang+'.ng2.changeDetection'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log baseline stats', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#baselineDetectChanges'],
|
||||||
|
name: browser.params.lang+'.baseline.changeDetection'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,26 @@
|
||||||
|
"use strict";
|
||||||
|
var util = require('../../../../tools/perf/util.js');
|
||||||
|
|
||||||
|
describe('ng2 compiler benchmark', function () {
|
||||||
|
|
||||||
|
var URL = 'benchmarks/web/compiler/compiler_benchmark.html';
|
||||||
|
|
||||||
|
afterEach(util.verifyNoErrors);
|
||||||
|
|
||||||
|
it('should log withBindings stats', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#compileWithBindings'],
|
||||||
|
name: browser.params.lang+'.ng2.compile.withBindings'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log noBindings stats', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#compileNoBindings'],
|
||||||
|
name: browser.params.lang+'.ng2.compile.noBindings'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,42 @@
|
||||||
|
"use strict";
|
||||||
|
var util = require('../../../../tools/perf/util.js');
|
||||||
|
|
||||||
|
describe('ng2 di benchmark', function () {
|
||||||
|
|
||||||
|
var URL = 'benchmarks/web/di/di_benchmark.html';
|
||||||
|
|
||||||
|
afterEach(util.verifyNoErrors);
|
||||||
|
|
||||||
|
it('should log the stats for getByToken', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#getByToken'],
|
||||||
|
name: browser.params.lang+'.ng2.di.getByToken'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log the stats for getByKey', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#getByKey'],
|
||||||
|
name: browser.params.lang+'.ng2.di.getByKey'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log the stats for getChild', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#getChild'],
|
||||||
|
name: browser.params.lang+'.ng2.di.getChild'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log the stats for instantiate', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#instantiate'],
|
||||||
|
name: browser.params.lang+'.ng2.di.instantiate'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,26 @@
|
||||||
|
"use strict";
|
||||||
|
var util = require('../../../../tools/perf/util.js');
|
||||||
|
|
||||||
|
describe('ng2 element injector benchmark', function () {
|
||||||
|
|
||||||
|
var URL = 'benchmarks/web/element_injector/element_injector_benchmark.html';
|
||||||
|
|
||||||
|
afterEach(util.verifyNoErrors);
|
||||||
|
|
||||||
|
it('should log the stats for instantiate', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#instantiate'],
|
||||||
|
name: browser.params.lang+'.ng2.elementInjector.instantiate'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log the stats for instantiateDirectives', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#instantiateDirectives'],
|
||||||
|
name: browser.params.lang+'.ng2.elementInjector.instantiateDirectives'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,26 @@
|
||||||
|
"use strict";
|
||||||
|
var util = require('../../../../tools/perf/util.js');
|
||||||
|
|
||||||
|
describe('ng2 tree benchmark', function () {
|
||||||
|
|
||||||
|
var URL = 'benchmarks/web/tree/tree_benchmark.html';
|
||||||
|
|
||||||
|
afterEach(util.verifyNoErrors);
|
||||||
|
|
||||||
|
it('should log the ng stats', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#ng2DestroyDom', '#ng2CreateDom'],
|
||||||
|
name: browser.params.lang+'.ng2.tree'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log the baseline stats', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#baselineDestroyDom', '#baselineCreateDom'],
|
||||||
|
name: browser.params.lang+'.baseline.tree'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -3,7 +3,6 @@ environment:
|
||||||
sdk: '>=1.4.0'
|
sdk: '>=1.4.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
angular: ">=1.0.0 <2.0.0"
|
angular: ">=1.0.0 <2.0.0"
|
||||||
benchpress:
|
browser: '>=0.10.0 <0.11.0'
|
||||||
path: ../benchpress
|
|
||||||
transformers:
|
transformers:
|
||||||
- angular
|
- angular
|
|
@ -1,8 +1,8 @@
|
||||||
|
// compiler benchmark in AngularDart 1.x
|
||||||
library compiler_benchmark_ng10;
|
library compiler_benchmark_ng10;
|
||||||
|
|
||||||
import 'package:angular/angular.dart';
|
import 'package:angular/angular.dart';
|
||||||
import 'package:angular/application_factory.dart';
|
import 'package:angular/application_factory.dart';
|
||||||
import 'package:benchpress/benchpress.dart';
|
|
||||||
import 'dart:html';
|
import 'dart:html';
|
||||||
|
|
||||||
var COUNT = 30;
|
var COUNT = 30;
|
||||||
|
@ -16,42 +16,26 @@ main() {
|
||||||
..bind(Dir3)
|
..bind(Dir3)
|
||||||
..bind(Dir4);
|
..bind(Dir4);
|
||||||
|
|
||||||
benchmark("AngularDart 1.0 Compiler.compile 5*${COUNT} element with bindings", () {
|
var templateWithBindings = loadTemplate('templateWithBindings', COUNT);
|
||||||
var template = loadTemplate('templateWithBindings', COUNT);
|
var templateNoBindings = loadTemplate('templateWithBindings', COUNT);
|
||||||
|
|
||||||
final injector = applicationFactory().addModule(m).run();
|
final injector = applicationFactory().addModule(m).run();
|
||||||
|
|
||||||
final compiler = injector.get(Compiler);
|
final compiler = injector.get(Compiler);
|
||||||
final directiveMap = injector.get(DirectiveMap);
|
final directiveMap = injector.get(DirectiveMap);
|
||||||
final di = injector.get(DirectiveInjector);
|
|
||||||
final rootScope = injector.get(Scope);
|
|
||||||
|
|
||||||
benchmarkStep('run', () {
|
compileWithBindings(_) {
|
||||||
final cloned = template.clone(true);
|
final cloned = templateWithBindings.clone(true);
|
||||||
final scope = rootScope.createChild({});
|
compiler([cloned], directiveMap);
|
||||||
final viewFactory = compiler([cloned], directiveMap);
|
}
|
||||||
viewFactory(scope, di);
|
|
||||||
scope.destroy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
benchmark("AngularDart 1.0 instantiate 5*${COUNT} element with bindings", () {
|
compileNoBindings(_) {
|
||||||
var template = loadTemplate('templateWithBindings', COUNT);
|
final cloned = templateNoBindings.clone(true);
|
||||||
|
compiler([cloned], directiveMap);
|
||||||
|
}
|
||||||
|
|
||||||
final injector = applicationFactory().addModule(m).run();
|
document.querySelector('#compileWithBindings').addEventListener('click', compileWithBindings);
|
||||||
|
document.querySelector('#compileNoBindings').addEventListener('click', compileNoBindings);
|
||||||
|
|
||||||
final compiler = injector.get(Compiler);
|
|
||||||
final directiveMap = injector.get(DirectiveMap);
|
|
||||||
final di = injector.get(DirectiveInjector);
|
|
||||||
final rootScope = injector.get(Scope);
|
|
||||||
final viewFactory = compiler([template], directiveMap);
|
|
||||||
|
|
||||||
benchmarkStep('run', () {
|
|
||||||
var scope = rootScope.createChild({});
|
|
||||||
viewFactory(scope, di);
|
|
||||||
scope.destroy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadTemplate(templateId, repeatCount) {
|
loadTemplate(templateId, repeatCount) {
|
|
@ -1,46 +1,7 @@
|
||||||
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
|
// compiler benchmark in AngularJS 1.x
|
||||||
|
|
||||||
var COUNT = 30;
|
var COUNT = 30;
|
||||||
var $compile;
|
|
||||||
var $rootScope;
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
|
|
||||||
benchmark(`Ng 1.3 Compiler.compile 5*${COUNT} element no bindings`, function() {
|
|
||||||
var template = loadTemplate('templateNoBindings', COUNT);
|
|
||||||
|
|
||||||
benchmarkStep('run', function() {
|
|
||||||
// Need to clone every time as the compiler might modify the template!
|
|
||||||
var cloned = template.cloneNode(true);
|
|
||||||
$compile(cloned);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
benchmark(`Ng 1.3 Compiler.compile 5*${COUNT} element with bindings`, function() {
|
|
||||||
var template = loadTemplate('templateWithBindings', COUNT);
|
|
||||||
|
|
||||||
benchmarkStep('run', function() {
|
|
||||||
// Need to clone every time as the compiler might modify the template!
|
|
||||||
var cloned = template.cloneNode(true);
|
|
||||||
$compile(cloned);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
benchmark(`Ng 1.3 instantiate 5*${COUNT} element with bindings`, function() {
|
|
||||||
var linkFn;
|
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
var template = loadTemplate('templateWithBindings', COUNT);
|
|
||||||
linkFn = $compile(template);
|
|
||||||
});
|
|
||||||
|
|
||||||
benchmarkStep('run', function() {
|
|
||||||
var scope = $rootScope.$new();
|
|
||||||
linkFn(scope);
|
|
||||||
scope.$destroy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var ngEl = document.createElement('div');
|
var ngEl = document.createElement('div');
|
||||||
angular.bootstrap(ngEl, ['app']);
|
angular.bootstrap(ngEl, ['app']);
|
||||||
}
|
}
|
||||||
|
@ -62,7 +23,7 @@ function loadTemplate(templateId, repeatCount) {
|
||||||
}
|
}
|
||||||
|
|
||||||
angular.module('app', [])
|
angular.module('app', [])
|
||||||
.directive('dir0', function($parse) {
|
.directive('dir0', ['$parse', function($parse) {
|
||||||
return {
|
return {
|
||||||
compile: function($element, $attrs) {
|
compile: function($element, $attrs) {
|
||||||
var expr = $parse($attrs.attr0);
|
var expr = $parse($attrs.attr0);
|
||||||
|
@ -71,8 +32,8 @@ angular.module('app', [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
}])
|
||||||
.directive('dir1', function($parse) {
|
.directive('dir1', ['$parse', function($parse) {
|
||||||
return {
|
return {
|
||||||
compile: function($element, $attrs) {
|
compile: function($element, $attrs) {
|
||||||
var expr = $parse($attrs.attr1);
|
var expr = $parse($attrs.attr1);
|
||||||
|
@ -81,8 +42,8 @@ angular.module('app', [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
}])
|
||||||
.directive('dir2', function($parse) {
|
.directive('dir2', ['$parse', function($parse) {
|
||||||
return {
|
return {
|
||||||
compile: function($element, $attrs) {
|
compile: function($element, $attrs) {
|
||||||
var expr = $parse($attrs.attr2);
|
var expr = $parse($attrs.attr2);
|
||||||
|
@ -91,8 +52,8 @@ angular.module('app', [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
}])
|
||||||
.directive('dir3', function($parse) {
|
.directive('dir3', ['$parse', function($parse) {
|
||||||
return {
|
return {
|
||||||
compile: function($element, $attrs) {
|
compile: function($element, $attrs) {
|
||||||
var expr = $parse($attrs.attr3);
|
var expr = $parse($attrs.attr3);
|
||||||
|
@ -101,8 +62,8 @@ angular.module('app', [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
}])
|
||||||
.directive('dir4', function($parse) {
|
.directive('dir4', ['$parse', function($parse) {
|
||||||
return {
|
return {
|
||||||
compile: function($element, $attrs) {
|
compile: function($element, $attrs) {
|
||||||
var expr = $parse($attrs.attr4);
|
var expr = $parse($attrs.attr4);
|
||||||
|
@ -111,9 +72,24 @@ angular.module('app', [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
}])
|
||||||
.run(function(_$compile_, _$rootScope_) {
|
.run(['$compile', function($compile) {
|
||||||
$compile = _$compile_;
|
var templateNoBindings = loadTemplate('templateNoBindings', COUNT);
|
||||||
$rootScope = _$rootScope_;
|
var templateWithBindings = loadTemplate('templateWithBindings', COUNT);
|
||||||
});
|
|
||||||
|
document.querySelector('#compileWithBindings').addEventListener('click', compileWithBindings, false);
|
||||||
|
document.querySelector('#compileNoBindings').addEventListener('click', compileNoBindings, false);
|
||||||
|
|
||||||
|
function compileNoBindings(_) {
|
||||||
|
// Need to clone every time as the compiler might modify the template!
|
||||||
|
var cloned = templateNoBindings.cloneNode(true);
|
||||||
|
$compile(cloned);
|
||||||
|
}
|
||||||
|
|
||||||
|
function compileWithBindings(_) {
|
||||||
|
// Need to clone every time as the compiler might modify the template!
|
||||||
|
var cloned = templateWithBindings.cloneNode(true);
|
||||||
|
$compile(cloned);
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
$SCRIPTS$
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<button id="compileWithBindings">Compile template with bindings</button>
|
||||||
|
<button id="compileNoBindings">Compile template without bindings</button>
|
||||||
|
|
||||||
<template id="templateNoBindings">
|
<template id="templateNoBindings">
|
||||||
<div class="class0 class1 class2 class3 class4 " nodir0="" attr0="value0" nodir1="" attr1="value1" nodir2="" attr2="value2" nodir3="" attr3="value3" nodir4="" attr4="value4">
|
<div class="class0 class1 class2 class3 class4 " nodir0="" attr0="value0" nodir1="" attr1="value1" nodir2="" attr2="value2" nodir3="" attr3="value3" nodir4="" attr4="value4">
|
||||||
|
@ -30,3 +35,8 @@ $SCRIPTS$
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
$SCRIPTS$
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,7 +0,0 @@
|
||||||
library compiler_benchmark;
|
|
||||||
|
|
||||||
import './compiler_benchmark_ng10.dart' as cbm;
|
|
||||||
|
|
||||||
main () {
|
|
||||||
cbm.main();
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export {main} from './compiler_benchmark_ng13';
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="compiler/compiler_benchmark.html">Compiler benchmark</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="tree/tree_benchmark.html">Tree benchmark</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,7 +0,0 @@
|
||||||
library tree_benchmark;
|
|
||||||
|
|
||||||
import './tree_benchmark_ng10.dart' as bm;
|
|
||||||
|
|
||||||
main () {
|
|
||||||
bm.main();
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export {main} from './tree_benchmark_ng13';
|
|
|
@ -1,3 +0,0 @@
|
||||||
$SCRIPTS$
|
|
||||||
|
|
||||||
<tree data="initData"></tree>
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
// tree benchmark in AngularDart 1.x
|
||||||
library tree_benchmark_ng10;
|
library tree_benchmark_ng10;
|
||||||
|
|
||||||
import 'package:angular/angular.dart';
|
import 'package:angular/angular.dart';
|
||||||
import 'package:angular/application_factory.dart';
|
import 'package:angular/application_factory.dart';
|
||||||
import 'package:benchpress/benchpress.dart';
|
|
||||||
import 'dart:html';
|
import 'dart:html';
|
||||||
|
|
||||||
var MAX_DEPTH = 9;
|
var MAX_DEPTH = 9;
|
||||||
|
@ -23,28 +23,26 @@ main() {
|
||||||
final injector = setup();
|
final injector = setup();
|
||||||
final zone = injector.get(VmTurnZone);
|
final zone = injector.get(VmTurnZone);
|
||||||
final rootScope = injector.get(Scope);
|
final rootScope = injector.get(Scope);
|
||||||
|
|
||||||
benchmark("tree benchmark", () {
|
|
||||||
var count = 0;
|
var count = 0;
|
||||||
|
|
||||||
benchmarkStep("AngularDart destroyDom binary tree of depth ${MAX_DEPTH}", () {
|
destroyDom(_) {
|
||||||
zone.run(() {
|
zone.run(() {
|
||||||
rootScope.context['initData'] = new TreeNode('');
|
rootScope.context['initData'] = new TreeNode('');
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
benchmarkStep("AngularDart createDom binary tree of depth ${MAX_DEPTH}", () {
|
createDom(_) {
|
||||||
zone.run(() {
|
zone.run(() {
|
||||||
var maxDepth = 9;
|
|
||||||
var values = count++ % 2 == 0 ?
|
var values = count++ % 2 == 0 ?
|
||||||
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] :
|
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] :
|
||||||
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-'];
|
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-'];
|
||||||
|
|
||||||
rootScope.context['initData'] = buildTree(maxDepth, values, 0);
|
rootScope.context['initData'] = buildTree(MAX_DEPTH, values, 0);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
});
|
document.querySelector('#destroyDom').addEventListener('click', destroyDom);
|
||||||
|
document.querySelector('#createDom').addEventListener('click', createDom);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component(
|
@Component(
|
|
@ -0,0 +1,102 @@
|
||||||
|
// tree benchmark in AngularJS 1.x
|
||||||
|
var MAX_DEPTH = 9;
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
angular.bootstrap(document.body, ['app']);
|
||||||
|
}
|
||||||
|
|
||||||
|
angular.module('app', [])
|
||||||
|
.directive('tree', function() {
|
||||||
|
return {
|
||||||
|
scope: {
|
||||||
|
data: '='
|
||||||
|
},
|
||||||
|
template:
|
||||||
|
'<span> {{data.value}}'+
|
||||||
|
' <span tree-if="data.left"></span>'+
|
||||||
|
' <span tree-if="data.right"></span>'+
|
||||||
|
'</span>'
|
||||||
|
};
|
||||||
|
})
|
||||||
|
// special directive for "if" as angular 1.3 does not support
|
||||||
|
// recursive components.
|
||||||
|
.directive('treeIf', ['$compile', '$parse', function($compile, $parse) {
|
||||||
|
var transcludeFn;
|
||||||
|
return {
|
||||||
|
compile: function(element, attrs) {
|
||||||
|
var expr = $parse(attrs.treeIf);
|
||||||
|
var template = '<tree data="'+attrs.treeIf+'"></tree>';
|
||||||
|
var transclude;
|
||||||
|
return function($scope, $element, $attrs) {
|
||||||
|
if (!transclude) {
|
||||||
|
transclude = $compile(template);
|
||||||
|
}
|
||||||
|
var childScope;
|
||||||
|
var childElement;
|
||||||
|
$scope.$watch(expr, function(newValue) {
|
||||||
|
if (childScope) {
|
||||||
|
childScope.$destroy();
|
||||||
|
childElement.remove();
|
||||||
|
childScope = null;
|
||||||
|
childElement = null;
|
||||||
|
}
|
||||||
|
if (newValue) {
|
||||||
|
childScope = $scope.$new();
|
||||||
|
childElement = transclude(childScope, function(clone) {
|
||||||
|
$element.append(clone);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
.config(['$compileProvider', function($compileProvider) {
|
||||||
|
$compileProvider.debugInfoEnabled(false);
|
||||||
|
}])
|
||||||
|
.run(['$rootScope', function($rootScope) {
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
document.querySelector('#destroyDom').addEventListener('click', destroyDom, false);
|
||||||
|
document.querySelector('#createDom').addEventListener('click', createDom, false);
|
||||||
|
|
||||||
|
function destroyDom(_) {
|
||||||
|
$rootScope.$apply(function() {
|
||||||
|
$rootScope.initData = new TreeNode('', null, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDom(_) {
|
||||||
|
var maxDepth = MAX_DEPTH;
|
||||||
|
var values = count++ % 2 == 0 ?
|
||||||
|
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] :
|
||||||
|
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-'];
|
||||||
|
|
||||||
|
$rootScope.$apply(function() {
|
||||||
|
$rootScope.initData = buildTree(MAX_DEPTH, values, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
class TreeNode {
|
||||||
|
value:string;
|
||||||
|
left:TreeNode;
|
||||||
|
right:TreeNode;
|
||||||
|
constructor(value, left, right) {
|
||||||
|
this.value = value;
|
||||||
|
this.left = left;
|
||||||
|
this.right = right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTree(maxDepth, values, curDepth) {
|
||||||
|
if (maxDepth === curDepth) return new TreeNode('', null, null);
|
||||||
|
return new TreeNode(
|
||||||
|
values[curDepth],
|
||||||
|
buildTree(maxDepth, values, curDepth+1),
|
||||||
|
buildTree(maxDepth, values, curDepth+1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h2>AngularJS/Dart 1.x tree benchmark</h2>
|
||||||
|
<p>
|
||||||
|
<button id="destroyDom">destroyDom</button>
|
||||||
|
<button id="createDom">createDom</button>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<tree data="initData"></tree>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
$SCRIPTS$
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,112 +0,0 @@
|
||||||
import {benchmark, benchmarkStep} from 'benchpress/benchpress';
|
|
||||||
|
|
||||||
var MAX_DEPTH = 9;
|
|
||||||
|
|
||||||
function setup() {
|
|
||||||
var $rootScope;
|
|
||||||
|
|
||||||
angular.module('app', [])
|
|
||||||
.directive('tree', function() {
|
|
||||||
return {
|
|
||||||
scope: {
|
|
||||||
data: '='
|
|
||||||
},
|
|
||||||
template:
|
|
||||||
'<span> {{data.value}}'+
|
|
||||||
' <span tree-if="data.left"></span>'+
|
|
||||||
' <span tree-if="data.right"></span>'+
|
|
||||||
'</span>'
|
|
||||||
};
|
|
||||||
})
|
|
||||||
// special directive for "if" as angular 1.3 does not support
|
|
||||||
// recursive components.
|
|
||||||
.directive('treeIf', ['$compile', '$parse', function($compile, $parse) {
|
|
||||||
var transcludeFn;
|
|
||||||
return {
|
|
||||||
compile: function(element, attrs) {
|
|
||||||
var expr = $parse(attrs.treeIf);
|
|
||||||
var template = '<tree data="'+attrs.treeIf+'"></tree>';
|
|
||||||
var transclude;
|
|
||||||
return function($scope, $element, $attrs) {
|
|
||||||
if (!transclude) {
|
|
||||||
transclude = $compile(template);
|
|
||||||
}
|
|
||||||
var childScope;
|
|
||||||
var childElement;
|
|
||||||
$scope.$watch(expr, function(newValue) {
|
|
||||||
if (childScope) {
|
|
||||||
childScope.$destroy();
|
|
||||||
childElement.remove();
|
|
||||||
childScope = null;
|
|
||||||
childElement = null;
|
|
||||||
}
|
|
||||||
if (newValue) {
|
|
||||||
childScope = $scope.$new();
|
|
||||||
childElement = transclude(childScope, function(clone) {
|
|
||||||
$element.append(clone);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}])
|
|
||||||
.config(['$compileProvider', function($compileProvider) {
|
|
||||||
$compileProvider.debugInfoEnabled(false);
|
|
||||||
}])
|
|
||||||
.run(['$rootScope', function(_$rootScope_) {
|
|
||||||
$rootScope = _$rootScope_;
|
|
||||||
}])
|
|
||||||
angular.bootstrap(document.body, ['app']);
|
|
||||||
return $rootScope;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function main() {
|
|
||||||
var $rootScope = setup();
|
|
||||||
|
|
||||||
benchmark(`tree benchmark`, function() {
|
|
||||||
var count = 0;
|
|
||||||
|
|
||||||
benchmarkStep(`AngularJS destroyDom binary tree of depth ${MAX_DEPTH}`, function() {
|
|
||||||
$rootScope.$apply(function() {
|
|
||||||
$rootScope.initData = new TreeNode('', null, null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
benchmarkStep(`AngularJS createDom binary tree of depth ${MAX_DEPTH}`, function() {
|
|
||||||
var maxDepth = 9;
|
|
||||||
var values = count++ % 2 == 0 ?
|
|
||||||
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] :
|
|
||||||
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-'];
|
|
||||||
|
|
||||||
$rootScope.$apply(function() {
|
|
||||||
$rootScope.initData = buildTree(maxDepth, values, 0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class TreeNode {
|
|
||||||
value:string;
|
|
||||||
left:TreeNode;
|
|
||||||
right:TreeNode;
|
|
||||||
constructor(value, left, right) {
|
|
||||||
this.value = value;
|
|
||||||
this.left = left;
|
|
||||||
this.right = right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildTree(maxDepth, values, curDepth) {
|
|
||||||
if (maxDepth === curDepth) return new TreeNode('', null, null);
|
|
||||||
return new TreeNode(
|
|
||||||
values[curDepth],
|
|
||||||
buildTree(maxDepth, values, curDepth+1),
|
|
||||||
buildTree(maxDepth, values, curDepth+1));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
"use strict";
|
||||||
|
var util = require('../../../../tools/perf/util.js');
|
||||||
|
|
||||||
|
describe('ng1.x compiler benchmark', function () {
|
||||||
|
|
||||||
|
var URL = 'benchmarks_external/web/compiler/compiler_benchmark.html';
|
||||||
|
|
||||||
|
afterEach(util.verifyNoErrors);
|
||||||
|
|
||||||
|
it('should log withBinding stats', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#compileWithBindings'],
|
||||||
|
name: browser.params.lang+'.ng1.compile.withBindings'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log noBindings stats', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#compileNoBindings'],
|
||||||
|
name: browser.params.lang+'.ng1.compile.noBindings'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,18 @@
|
||||||
|
"use strict";
|
||||||
|
var util = require('../../../../tools/perf/util.js');
|
||||||
|
|
||||||
|
describe('ng1.x tree benchmark', function () {
|
||||||
|
|
||||||
|
var URL = 'benchmarks_external/web/tree/tree_benchmark.html';
|
||||||
|
|
||||||
|
afterEach(util.verifyNoErrors);
|
||||||
|
|
||||||
|
it('should log the stats', function() {
|
||||||
|
util.runSimpleBenchmark({
|
||||||
|
url: URL,
|
||||||
|
buttons: ['#destroyDom', '#createDom'],
|
||||||
|
name: browser.params.lang+'.ng1.tree'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -1,4 +0,0 @@
|
||||||
name: benchpress
|
|
||||||
environment:
|
|
||||||
sdk: '>=1.4.0'
|
|
||||||
dependencies:
|
|
|
@ -1,63 +0,0 @@
|
||||||
library benchmarks.benchpress;
|
|
||||||
|
|
||||||
import 'dart:js' as js;
|
|
||||||
import 'dart:html';
|
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
// TODO: move the functionality of this module into benchpress and replace this
|
|
||||||
// file with a Dart wrapper!
|
|
||||||
|
|
||||||
var _benchmarkNames = [];
|
|
||||||
|
|
||||||
_benchmarkId(index) {
|
|
||||||
return "benchmark${index}";
|
|
||||||
}
|
|
||||||
|
|
||||||
_useBenchmark(index) {
|
|
||||||
var search = window.location.search;
|
|
||||||
if (search.length > 0) {
|
|
||||||
search = search.substring(1);
|
|
||||||
}
|
|
||||||
if (search.length > 0) {
|
|
||||||
return search == _benchmarkId(index);
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_onLoad(callback) {
|
|
||||||
var isReady = document.readyState == 'complete';
|
|
||||||
if (isReady) {
|
|
||||||
Timer.run(callback);
|
|
||||||
} else {
|
|
||||||
window.addEventListener('load', (event) => callback(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_createBenchmarkMenu() {
|
|
||||||
var div = document.createElement('div');
|
|
||||||
div.innerHtml += '<h1>Benchmarks:</h1><a class="btn btn-default" href="?">All</a>';
|
|
||||||
for (var i=0; i<_benchmarkNames.length; i++) {
|
|
||||||
var activeClass = _useBenchmark(i) ? 'active' : '';
|
|
||||||
div.innerHtml += '<a class="btn btn-default ${activeClass}" href="?${_benchmarkId(i)}">${_benchmarkNames[i]}</a>';
|
|
||||||
}
|
|
||||||
document.body.insertBefore(div, document.body.childNodes[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
benchmark(name, stepsCreationCallback) {
|
|
||||||
_benchmarkNames.add(name);
|
|
||||||
if (_benchmarkNames.length == 2) {
|
|
||||||
_onLoad(_createBenchmarkMenu);
|
|
||||||
}
|
|
||||||
if (_useBenchmark(_benchmarkNames.length-1)) {
|
|
||||||
stepsCreationCallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
benchmarkStep(name, callback) {
|
|
||||||
var benchmarkName = _benchmarkNames[_benchmarkNames.length-1];
|
|
||||||
js.context['benchmarkSteps'].add(new js.JsObject.jsify({
|
|
||||||
"name": benchmarkName + '#' + name,
|
|
||||||
"fn": new js.JsFunction.withThis((_) => callback())
|
|
||||||
}));
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
// TODO: move the functionality of this module into benchpress itself!
|
|
||||||
|
|
||||||
var benchmarkNames = [];
|
|
||||||
|
|
||||||
function benchmarkId(index) {
|
|
||||||
return 'benchmark' + index;
|
|
||||||
}
|
|
||||||
|
|
||||||
function useBenchmark(index) {
|
|
||||||
var search = window.location.search;
|
|
||||||
if (search.length > 0) {
|
|
||||||
search = search.substring(1);
|
|
||||||
}
|
|
||||||
if (search.length > 0) {
|
|
||||||
return search == benchmarkId(index);
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onLoad(callback) {
|
|
||||||
var isReady = document.readyState === 'complete';
|
|
||||||
if (isReady) {
|
|
||||||
window.setTimeout(callback);
|
|
||||||
} else {
|
|
||||||
window.addEventListener('load', callback, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createBenchmarkMenu() {
|
|
||||||
var div = document.createElement('div');
|
|
||||||
div.innerHTML += '<h1>Benchmarks:</h1><a class="btn btn-default" href="?">All</a>';
|
|
||||||
for (var i=0; i<benchmarkNames.length; i++) {
|
|
||||||
var activeClass = useBenchmark(i) ? 'active' : '';
|
|
||||||
div.innerHTML += ('<a class="btn btn-default '+activeClass+'" href="?'+benchmarkId(i)+'">'+benchmarkNames[i]+'</a>');
|
|
||||||
}
|
|
||||||
document.body.insertBefore(div, document.body.childNodes[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function benchmark(name, stepsCreationCallback) {
|
|
||||||
benchmarkNames.push(name);
|
|
||||||
if (benchmarkNames.length === 2) {
|
|
||||||
onLoad(createBenchmarkMenu);
|
|
||||||
}
|
|
||||||
if (useBenchmark(benchmarkNames.length-1)) {
|
|
||||||
stepsCreationCallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function benchmarkStep(name, callback) {
|
|
||||||
var benchmarkName = benchmarkNames[benchmarkNames.length-1];
|
|
||||||
window.benchmarkSteps.push({
|
|
||||||
name: benchmarkName + '#' + name, fn: callback
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -36,6 +36,10 @@ export class CompilerCache {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this._cache = MapWrapper.create();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
"author": "Tobias Bosch <tbosch@google.com>",
|
"author": "Tobias Bosch <tbosch@google.com>",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"angular-benchpress": "^0.1.3",
|
"protractor": "1.5.x",
|
||||||
"del": "~1",
|
"del": "~1",
|
||||||
"es6-module-loader": "^0.9.2",
|
"es6-module-loader": "^0.9.2",
|
||||||
"event-stream": "^3.1.5",
|
"event-stream": "^3.1.5",
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
var config = exports.config = require('./protractor-perf-shared.js').config;
|
||||||
|
config.params.lang = 'dart';
|
||||||
|
config.baseUrl = 'http://localhost:8002/';
|
|
@ -0,0 +1,4 @@
|
||||||
|
var config = exports.config = require('./protractor-perf-shared.js').config;
|
||||||
|
config.params.lang = 'js';
|
||||||
|
config.baseUrl = 'http://localhost:8001/';
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
var config = exports.config = {
|
||||||
|
|
||||||
|
specs: ['modules/*/test/**/*_perf.js'],
|
||||||
|
|
||||||
|
params: {
|
||||||
|
// number test iterations to warm up the browser
|
||||||
|
warmupCount: 10,
|
||||||
|
// number test iterations to measure
|
||||||
|
measureCount: 10,
|
||||||
|
// TODO(tbosch): remove this and provide a proper protractor integration
|
||||||
|
sleepInterval: process.env.TRAVIS ? 5000 : 1000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Disable waiting for Angular as we don't have an integration layer yet...
|
||||||
|
// TODO(tbosch): Implement a proper debugging API for Ng2.0, remove this here
|
||||||
|
// and the sleeps in all tests.
|
||||||
|
onPrepare: function() {
|
||||||
|
browser.ignoreSynchronization = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
jasmineNodeOpts: {
|
||||||
|
showColors: true,
|
||||||
|
defaultTimeoutInterval: 30000
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: add real mobile devices via a cloud provider that supports appium
|
||||||
|
if (process.env.TRAVIS) {
|
||||||
|
config.capabilities = {
|
||||||
|
name: 'Dartium',
|
||||||
|
browserName: 'chrome',
|
||||||
|
chromeOptions: {
|
||||||
|
'binary': process.env.DARTIUM,
|
||||||
|
'args': ['--js-flags=--expose-gc']
|
||||||
|
},
|
||||||
|
loggingPrefs: {
|
||||||
|
performance: 'ALL'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
config.capabilities = {
|
||||||
|
browserName: 'chrome',
|
||||||
|
chromeOptions: {
|
||||||
|
'args': ['--js-flags=--expose-gc']
|
||||||
|
},
|
||||||
|
loggingPrefs: {
|
||||||
|
performance: 'ALL'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo =============================================================================
|
echo =============================================================================
|
||||||
|
@ -18,3 +17,17 @@ pub install
|
||||||
./node_modules/karma/bin/karma start karma-dart.conf \
|
./node_modules/karma/bin/karma start karma-dart.conf \
|
||||||
--reporters=dots \
|
--reporters=dots \
|
||||||
--browsers=$BROWSERS --single-run
|
--browsers=$BROWSERS --single-run
|
||||||
|
|
||||||
|
./node_modules/.bin/webdriver-manager update
|
||||||
|
|
||||||
|
function killServer () {
|
||||||
|
kill $serverPid
|
||||||
|
}
|
||||||
|
|
||||||
|
./node_modules/.bin/gulp serve.js.prod serve.js.dart2js&
|
||||||
|
serverPid=$!
|
||||||
|
|
||||||
|
trap killServer EXIT
|
||||||
|
|
||||||
|
./node_modules/.bin/protractor protractor-perf-js.conf.js
|
||||||
|
./node_modules/.bin/protractor protractor-perf-dart2js.conf.js
|
|
@ -1,39 +0,0 @@
|
||||||
var util = require('./util');
|
|
||||||
var path = require('path');
|
|
||||||
var benchpress = require('angular-benchpress/lib/cli');
|
|
||||||
var through2 = require('through2');
|
|
||||||
var Q = require('q');
|
|
||||||
var path = require('path');
|
|
||||||
|
|
||||||
module.exports = function(gulp, plugins, config) {
|
|
||||||
return function() {
|
|
||||||
var benchmarkParentFolders = {};
|
|
||||||
var createBpConfStream = util.streamToPromise(
|
|
||||||
gulp.src(path.join(config.buildDir, config.mainHtmls))
|
|
||||||
.pipe(through2.obj(function(file, enc, done) {
|
|
||||||
file.path = path.join(path.dirname(file.path), config.configFile.name);
|
|
||||||
file.contents = new Buffer(config.configFile.content);
|
|
||||||
this.push(file);
|
|
||||||
benchmarkParentFolders[getParentFolder(file.path)] = true;
|
|
||||||
done();
|
|
||||||
}))
|
|
||||||
.pipe(gulp.dest(config.buildDir)));
|
|
||||||
|
|
||||||
return createBpConfStream.then(function() {
|
|
||||||
return Promise.all(Object.keys(benchmarkParentFolders).map(function(benchmarkParentPath) {
|
|
||||||
var defer = Q.defer();
|
|
||||||
benchpress.build({
|
|
||||||
benchmarksPath: benchmarkParentPath,
|
|
||||||
buildPath: path.join(benchmarkParentPath, path.join('../', config.outputFolderName))
|
|
||||||
}, defer.makeNodeResolver());
|
|
||||||
return defer.promise;
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function getParentFolder(file) {
|
|
||||||
var parts = path.dirname(file).split(path.sep);
|
|
||||||
parts.pop();
|
|
||||||
return parts.join(path.sep);
|
|
||||||
}
|
|
|
@ -2,7 +2,7 @@ module.exports = function(gulp, plugins, config) {
|
||||||
return function() {
|
return function() {
|
||||||
plugins.connect.server({
|
plugins.connect.server({
|
||||||
root: [__dirname+'/../../'+config.path],
|
root: [__dirname+'/../../'+config.path],
|
||||||
port: 8000,
|
port: config.port,
|
||||||
livereload: false,
|
livereload: false,
|
||||||
open: false
|
open: false
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
var util = require('./util');
|
||||||
|
var Q = require('q');
|
||||||
|
var spawn = require('child_process').spawn;
|
||||||
|
var through2 = require('through2');
|
||||||
|
var path = require('path');
|
||||||
|
var glob = require('glob');
|
||||||
|
|
||||||
|
module.exports = function(gulp, plugins, config) {
|
||||||
|
return function() {
|
||||||
|
var webFolders = [].slice.call(glob.sync(path.join(config.src, '*/web')));
|
||||||
|
return nextFolder();
|
||||||
|
|
||||||
|
function nextFolder() {
|
||||||
|
if (!webFolders.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var folder = getParentFolder(webFolders.shift());
|
||||||
|
var destFolder = path.resolve(path.join(config.dest, path.basename(folder)));
|
||||||
|
return util.processToPromise(spawn(config.command, ['build', '-o', destFolder], {
|
||||||
|
stdio: 'inherit',
|
||||||
|
cwd: folder
|
||||||
|
})).then(function() {
|
||||||
|
return replaceDartWithJsScripts(gulp, destFolder);
|
||||||
|
}).then(nextFolder);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function getParentFolder(folder) {
|
||||||
|
var parts = folder.split(path.sep);
|
||||||
|
parts.pop();
|
||||||
|
return parts.join(path.sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceDartWithJsScripts(gulp, folder) {
|
||||||
|
return util.streamToPromise(gulp.src(path.join(folder, '**/*.html'))
|
||||||
|
.pipe(through2.obj(function(file, enc, done) {
|
||||||
|
var content = file.contents.toString();
|
||||||
|
content = content.replace(/\.dart/, '.dart.js');
|
||||||
|
content = content.replace(/application\/dart/, 'text/javascript');
|
||||||
|
file.contents = new Buffer(content);
|
||||||
|
this.push(file);
|
||||||
|
done();
|
||||||
|
}))
|
||||||
|
.pipe(gulp.dest(folder)));
|
||||||
|
}
|
|
@ -0,0 +1,179 @@
|
||||||
|
var webdriver = require('protractor/node_modules/selenium-webdriver');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
perfLogs: perfLogs,
|
||||||
|
sumTimelineStats: sumTimelineStats,
|
||||||
|
runSimpleBenchmark: runSimpleBenchmark,
|
||||||
|
verifyNoErrors: verifyNoErrors,
|
||||||
|
printObjectAsMarkdown: printObjectAsMarkdown
|
||||||
|
};
|
||||||
|
|
||||||
|
function perfLogs() {
|
||||||
|
return plainLogs('performance').then(function(entries) {
|
||||||
|
var entriesByMethod = {};
|
||||||
|
entries.forEach(function(entry) {
|
||||||
|
var message = JSON.parse(entry.message).message;
|
||||||
|
var entries = entriesByMethod[message.method];
|
||||||
|
if (!entries) {
|
||||||
|
entries = entriesByMethod[message.method] = [];
|
||||||
|
}
|
||||||
|
entries.push(message.params);
|
||||||
|
});
|
||||||
|
return entriesByMethod;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Needed as selenium-webdriver does not forward
|
||||||
|
// performance logs in the correct way
|
||||||
|
function plainLogs(type) {
|
||||||
|
var webdriver = require('protractor/node_modules/selenium-webdriver');
|
||||||
|
return browser.driver.schedule(
|
||||||
|
new webdriver.Command(webdriver.CommandName.GET_LOG).
|
||||||
|
setParameter('type', type),
|
||||||
|
'WebDriver.manage().logs().get(' + type + ')');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function sumTimelineStats(messages) {
|
||||||
|
var recordStats = {
|
||||||
|
script: 0,
|
||||||
|
gc: {
|
||||||
|
time: 0,
|
||||||
|
amount: 0
|
||||||
|
},
|
||||||
|
render: 0
|
||||||
|
};
|
||||||
|
messages.forEach(function(message) {
|
||||||
|
sumTimelineRecordStats(message.record, recordStats);
|
||||||
|
});
|
||||||
|
return recordStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sumTimelineRecordStats(record, result) {
|
||||||
|
var summedChildrenDuration = 0;
|
||||||
|
if (record.children) {
|
||||||
|
record.children.forEach(function(child) {
|
||||||
|
summedChildrenDuration += sumTimelineRecordStats(child, result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// in case a script forced a gc or a reflow
|
||||||
|
// we need to substract the gc time / reflow time
|
||||||
|
// from the script time!
|
||||||
|
var recordDuration = (record.endTime ? record.endTime - record.startTime : 0)
|
||||||
|
- summedChildrenDuration;
|
||||||
|
|
||||||
|
var recordSummed = true;
|
||||||
|
if (record.type === 'FunctionCall') {
|
||||||
|
result.script += recordDuration;
|
||||||
|
} else if (record.type === 'GCEvent') {
|
||||||
|
result.gc.time += recordDuration;
|
||||||
|
result.gc.amount += record.data.usedHeapSizeDelta;
|
||||||
|
} else if (record.type === 'RecalculateStyles' ||
|
||||||
|
record.type === 'Layout' ||
|
||||||
|
record.type === 'UpdateLayerTree' ||
|
||||||
|
record.type === 'Paint' ||
|
||||||
|
record.type === 'Rasterize' ||
|
||||||
|
record.type === 'CompositeLayers') {
|
||||||
|
result.render += recordDuration;
|
||||||
|
} else {
|
||||||
|
recordSummed = false;
|
||||||
|
}
|
||||||
|
if (recordSummed) {
|
||||||
|
return recordDuration;
|
||||||
|
} else {
|
||||||
|
return summedChildrenDuration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function runSimpleBenchmark(config) {
|
||||||
|
var url = config.url;
|
||||||
|
var buttonSelectors = config.buttons;
|
||||||
|
// TODO: Don't use a fixed number of warmup / measure iterations,
|
||||||
|
// but make this dependent on the variance of the test results!
|
||||||
|
var warmupCount = browser.params.warmupCount;
|
||||||
|
var measureCount = browser.params.measureCount;
|
||||||
|
var name = config.name;
|
||||||
|
|
||||||
|
browser.get(url);
|
||||||
|
// TODO(tbosch): replace this with a proper protractor/ng2.0 integration
|
||||||
|
// and remove this function as well as all method calls.
|
||||||
|
browser.sleep(browser.params.sleepInterval)
|
||||||
|
|
||||||
|
var btns = buttonSelectors.map(function(selector) {
|
||||||
|
return $(selector);
|
||||||
|
});
|
||||||
|
|
||||||
|
multiClick(btns, warmupCount);
|
||||||
|
gc();
|
||||||
|
// empty perflogs queue
|
||||||
|
perfLogs();
|
||||||
|
|
||||||
|
multiClick(btns, measureCount);
|
||||||
|
gc();
|
||||||
|
return perfLogs().then(function(logs) {
|
||||||
|
var stats = sumTimelineStats(logs['Timeline.eventRecorded']);
|
||||||
|
printObjectAsMarkdown(name, stats);
|
||||||
|
return stats;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function gc() {
|
||||||
|
// TODO(tbosch): this only works on chrome.
|
||||||
|
// For iOS Safari we need an extension to appium...
|
||||||
|
browser.executeScript('window.gc()');
|
||||||
|
}
|
||||||
|
|
||||||
|
function multiClick(buttons, count) {
|
||||||
|
var actions = browser.actions();
|
||||||
|
for (var i=0; i<count; i++) {
|
||||||
|
buttons.forEach(function(button) {
|
||||||
|
actions.click(button);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
actions.perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
function verifyNoErrors() {
|
||||||
|
browser.manage().logs().get('browser').then(function(browserLog) {
|
||||||
|
var filteredLog = browserLog.filter(function(logEntry) {
|
||||||
|
return logEntry.level.value > webdriver.logging.Level.WARNING.value;
|
||||||
|
});
|
||||||
|
expect(filteredLog.length).toEqual(0);
|
||||||
|
if (filteredLog.length) {
|
||||||
|
console.log('browser console errors: ' + require('util').inspect(filteredLog));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function printObjectAsMarkdown(name, obj) {
|
||||||
|
var props = [['name']];
|
||||||
|
var vals = [name];
|
||||||
|
flattenObj(obj, [], props, vals);
|
||||||
|
// log header
|
||||||
|
var separators = [];
|
||||||
|
var header = props.map(function(propPath) {
|
||||||
|
separators.push('----');
|
||||||
|
return propPath.join('.');
|
||||||
|
}).join(' | ');
|
||||||
|
console.log('\n'+header);
|
||||||
|
console.log(separators.join(' | '));
|
||||||
|
console.log(vals.join(' | '));
|
||||||
|
console.log('\n');
|
||||||
|
|
||||||
|
function flattenObj(obj, propPathPrefix, targetProps, targetVals) {
|
||||||
|
for (var prop in obj) {
|
||||||
|
var val = obj[prop];
|
||||||
|
var currPropPath = propPathPrefix.concat([prop]);
|
||||||
|
if (val && typeof val === 'object') {
|
||||||
|
flattenObj(val, currPropPath, targetProps, targetVals);
|
||||||
|
} else {
|
||||||
|
targetProps.push(currPropPath);
|
||||||
|
var valStr = val;
|
||||||
|
if (typeof val === 'number') {
|
||||||
|
valStr = val.toFixed(2);
|
||||||
|
}
|
||||||
|
targetVals.push(valStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue