diff --git a/.travis.yml b/.travis.yml index b7e170454f..bb739297b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: node_js +sudo: false node_js: - '0.10' env: diff --git a/gulpfile.js b/gulpfile.js index fa29b2a741..9d7225a095 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -8,11 +8,12 @@ var clean = require('./tools/build/clean'); var deps = require('./tools/build/deps'); var transpile = require('./tools/build/transpile'); var html = require('./tools/build/html'); -var benchpress = require('./tools/build/benchpress'); var pubspec = require('./tools/build/pubspec'); +var pubbuild = require('./tools/build/pubbuild'); var dartanalyzer = require('./tools/build/dartanalyzer'); var jsserve = require('./tools/build/jsserve'); var pubserve = require('./tools/build/pubserve'); + var DART_SDK = require('./tools/build/dartdetect')(gulp); // ----------------------- // configuration @@ -43,23 +44,18 @@ var _HTLM_DEFAULT_SCRIPTS_JS = [ var CONFIG = { - commands: { - pub: process.platform === 'win32' ? 'pub.bat' : 'pub', - dartanalyzer: process.platform === "win32" ? "dartanalyzer.bat" : "dartanalyzer" - }, dest: { js: { all: 'dist/js', dev: 'dist/js/dev', - prod: 'dist/js/prod' + prod: 'dist/js/prod', + dart2js: 'dist/js/dart2js' }, dart: 'dist/dart' }, srcFolderMapping: { 'default': 'lib', - // need a tmp folder as benchpress does not support - // inplace generation of the benchmarks... - '**/benchmark*/**': 'perf_tmp', + '**/benchmark*/**': 'web', '**/example*/**': 'web' }, deps: { @@ -76,12 +72,12 @@ var CONFIG = { }, transpile: { src: { - js: ['modules/**/*.js', 'modules/**/*.es6'], - dart: ['modules/**/*.js'] + js: ['modules/**/*.js', 'modules/**/*.es6', '!modules/**/perf/**/*'], + dart: ['modules/**/*.js', '!modules/**/perf/**/*'] }, copy: { - js: ['modules/**/*.es5'], - dart: ['modules/**/*.dart'] + js: ['modules/**/*.es5', '!modules/**/perf/**/*'], + dart: ['modules/**/*.dart', '!modules/**/perf/**/*'] }, options: { 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: { src: 'modules/*/pubspec.yaml' } @@ -213,31 +201,6 @@ gulp.task('build/html.dart', html(gulp, gulpPlugins, { 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 @@ -248,7 +211,7 @@ gulp.task('build/pubspec.dart', pubspec(gulp, gulpPlugins, { })); // ------------ -// pubspec +// dartanalyzer gulp.task('build/analyze.dart', dartanalyzer(gulp, gulpPlugins, { dest: CONFIG.dest.dart, @@ -256,14 +219,30 @@ gulp.task('build/analyze.dart', dartanalyzer(gulp, gulpPlugins, { 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 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, { - 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, { @@ -343,22 +322,20 @@ gulp.task('build.dart', function() { return runSequence( ['build/transpile.dart', 'build/html.dart'], 'build/pubspec.dart', - 'build/benchpress.dart', + 'build/pubbuild.dart', 'build/analyze.dart' ); }); gulp.task('build.js.dev', function() { return runSequence( - ['build/deps.js.dev', 'build/transpile.js.dev', 'build/html.js.dev'], - 'build/benchpress.js.dev' + ['build/deps.js.dev', 'build/transpile.js.dev', 'build/html.js.dev'] ); }); gulp.task('build.js.prod', function() { return runSequence( - ['build/deps.js.prod', 'build/transpile.js.prod', 'build/html.js.prod'], - 'build/benchpress.js.prod' + ['build/deps.js.prod', 'build/transpile.js.prod', 'build/html.js.prod'] ); }); diff --git a/modules/benchmarks/pubspec.yaml b/modules/benchmarks/pubspec.yaml index 67371437d7..ef8e17b45f 100644 --- a/modules/benchmarks/pubspec.yaml +++ b/modules/benchmarks/pubspec.yaml @@ -12,6 +12,4 @@ dependencies: path: ../core change_detection: path: ../change_detection - benchpress: - path: ../benchpress browser: '>=0.10.0 <0.11.0' diff --git a/modules/benchmarks/src/change_detection/change_detection_benchmark.html b/modules/benchmarks/src/change_detection/change_detection_benchmark.html new file mode 100644 index 0000000000..8f1707ae77 --- /dev/null +++ b/modules/benchmarks/src/change_detection/change_detection_benchmark.html @@ -0,0 +1,10 @@ + + + + + + + +$SCRIPTS$ + + \ No newline at end of file diff --git a/modules/benchmarks/src/change_detection/change_detection_benchmark.js b/modules/benchmarks/src/change_detection/change_detection_benchmark.js index c49d1f1550..698b92ac71 100644 --- a/modules/benchmarks/src/change_detection/change_detection_benchmark.js +++ b/modules/benchmarks/src/change_detection/change_detection_benchmark.js @@ -3,7 +3,7 @@ import {Parser} from 'change_detection/parser/parser'; import {Lexer} from 'change_detection/parser/lexer'; import {reflector} from 'reflection/reflection'; import {isPresent} from 'facade/lang'; -import {benchmark, benchmarkStep} from 'benchpress/benchpress'; +import {document, DOM} from 'facade/dom'; import { ChangeDetector, @@ -12,7 +12,7 @@ import { } from 'change_detection/change_detector'; -var ITERATIONS = 200000; +var ITERATIONS = 500000; class Obj { field0; @@ -155,28 +155,25 @@ function setUpChangeDetection() { export function main () { setUpReflector(); + var baselineHead = setUpBaseline(); + var ng2ChangeDetector = setUpChangeDetection(); - benchmark(`Baseline`, function () { - var head = setUpBaseline(); - - benchmarkStep('run', function () { - var current = head; - while (isPresent(current)) { - if (current.getter(current.obj) !== current.previousValue) { - throw "should not happen"; - } - current = current.next; + function baselineDetectChanges(_) { + var current = baselineHead; + while (isPresent(current)) { + if (current.getter(current.obj) !== current.previousValue) { + throw "should not happen"; } - }); - }); + current = current.next; + } + } - benchmark(`Change Detection`, function() { - var cd = setUpChangeDetection(); + function ng2DetectChanges(_) { + ng2ChangeDetector.detectChanges(); + } - benchmarkStep('run', function() { - cd.detectChanges(); - }); - }); + DOM.on(DOM.querySelector(document, '#ng2DetectChanges'), 'click', ng2DetectChanges); + DOM.on(DOM.querySelector(document, '#baselineDetectChanges'), 'click', baselineDetectChanges); } diff --git a/modules/benchmarks/src/change_detection/main.html b/modules/benchmarks/src/change_detection/main.html deleted file mode 100644 index 3995f8ae30..0000000000 --- a/modules/benchmarks/src/change_detection/main.html +++ /dev/null @@ -1 +0,0 @@ -$SCRIPTS$ \ No newline at end of file diff --git a/modules/benchmarks/src/change_detection/main.js b/modules/benchmarks/src/change_detection/main.js deleted file mode 100644 index 5b55ee8923..0000000000 --- a/modules/benchmarks/src/change_detection/main.js +++ /dev/null @@ -1,5 +0,0 @@ -import * as change_detection_benchmark from './change_detection_benchmark'; - -export function main() { - change_detection_benchmark.main(); -} diff --git a/modules/benchmarks/src/compiler/main.html b/modules/benchmarks/src/compiler/compiler_benchmark.html similarity index 92% rename from modules/benchmarks/src/compiler/main.html rename to modules/benchmarks/src/compiler/compiler_benchmark.html index 178588bd7d..460bb9bf54 100644 --- a/modules/benchmarks/src/compiler/main.html +++ b/modules/benchmarks/src/compiler/compiler_benchmark.html @@ -1,4 +1,9 @@ -$SCRIPTS$ + + + + + + + +$SCRIPTS$ + + + \ No newline at end of file diff --git a/modules/benchmarks/src/compiler/compiler_benchmark.js b/modules/benchmarks/src/compiler/compiler_benchmark.js index 67325a015a..6eca478c1e 100644 --- a/modules/benchmarks/src/compiler/compiler_benchmark.js +++ b/modules/benchmarks/src/compiler/compiler_benchmark.js @@ -1,5 +1,3 @@ -import {benchmark, benchmarkStep} from 'benchpress/benchpress'; - import {DOM, document} from 'facade/dom'; import {isBlank, Type} from 'facade/lang'; import {MapWrapper} from 'facade/collection'; @@ -20,10 +18,7 @@ import {reflector} from 'reflection/reflection'; var COUNT = 30; -var compiler; -var annotatedComponent; - -function setup() { +function setupReflector() { reflector.registerType(BenchmarkComponent, { "factory": () => new BenchmarkComponent(), "parameters": [], @@ -79,47 +74,34 @@ function setup() { "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() { - 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 template = loadTemplate('templateNoBindings', COUNT); + var templateNoBindings = loadTemplate('templateNoBindings', COUNT); + var templateWithBindings = loadTemplate('templateWithBindings', COUNT); - benchmarkStep('run', function() { - // Need to clone every time as the compiler might modify the template! - var cloned = DOM.clone(template); - compiler.compileAllLoaded(null, annotatedComponent, cloned); - }); - }); + function compileNoBindings(_) { + // Need to clone every time as the compiler might modify the template! + var cloned = DOM.clone(templateNoBindings); + cache.clear(); + compiler.compileAllLoaded(null, annotatedComponent, cloned); + } - benchmark(`Compiler.compile 5*${COUNT} element with bindings`, function() { - var template = loadTemplate('templateWithBindings', COUNT); + function compileWithBindings(_) { + // Need to clone every time as the compiler might modify the template! + var cloned = DOM.clone(templateWithBindings); + cache.clear(); + compiler.compileAllLoaded(null, annotatedComponent, cloned); + } - benchmarkStep('run', function() { - // Need to clone every time as the compiler might modify the template! - var cloned = DOM.clone(template); - compiler.compileAllLoaded(null, annotatedComponent, cloned); - }); - }); - - benchmark(`instantiate 5*${COUNT} element with bindings`, function() { - var template = loadTemplate('templateWithBindings', COUNT); - 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(); - }); - }); + DOM.on(DOM.querySelector(document, '#compileNoBindings'), 'click', compileNoBindings); + DOM.on(DOM.querySelector(document, '#compileWithBindings'), 'click', compileWithBindings); } function loadTemplate(templateId, repeatCount) { @@ -132,22 +114,6 @@ function loadTemplate(templateId, repeatCount) { 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({ selector: '[dir0]', bind: { diff --git a/modules/benchmarks/src/compiler/main.js b/modules/benchmarks/src/compiler/main.js deleted file mode 100644 index 3a3a19252c..0000000000 --- a/modules/benchmarks/src/compiler/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import * as sbm from './selector_benchmark'; -import * as cbm from './compiler_benchmark'; - -export function main() { - sbm.main(); - cbm.main(); -} diff --git a/modules/benchmarks/src/compiler/selector_benchmark.html b/modules/benchmarks/src/compiler/selector_benchmark.html new file mode 100644 index 0000000000..3c2d8dd0e1 --- /dev/null +++ b/modules/benchmarks/src/compiler/selector_benchmark.html @@ -0,0 +1,12 @@ + + + + + + + + +$SCRIPTS$ + + + \ No newline at end of file diff --git a/modules/benchmarks/src/compiler/selector_benchmark.js b/modules/benchmarks/src/compiler/selector_benchmark.js index 509d710902..e0e6cab4de 100644 --- a/modules/benchmarks/src/compiler/selector_benchmark.js +++ b/modules/benchmarks/src/compiler/selector_benchmark.js @@ -1,63 +1,56 @@ -import {benchmark, benchmarkStep} from 'benchpress/benchpress'; +import {document, DOM} from 'facade/dom'; import {SelectorMatcher} from "core/compiler/selector"; import {CssSelector} from "core/compiler/selector"; import {StringWrapper, Math} from 'facade/lang'; import {ListWrapper} from 'facade/collection'; -var fixedMatcher; -var fixedSelectorStrings = []; -var fixedSelectors = []; - var COUNT = 1000; export function main() { - setup(COUNT); - - benchmark(`cssSelector.parse * ${COUNT}`, function() { - benchmarkStep(`run`, function() { - var result = []; - for (var i=0; i { - matchCount += selected; - }); - } - return matchCount; - }); - }); -} - -function setup(count) { - for (var i=0; i { + matchCount += selected; + }); + } + return matchCount; + } + + DOM.on(DOM.querySelector(document, '#parse'), 'click', parse); + DOM.on(DOM.querySelector(document, '#addSelectable'), 'click', addSelectable); + DOM.on(DOM.querySelector(document, '#match'), 'click', match); } function randomSelector() { diff --git a/modules/benchmarks/src/di/di_benchmark.html b/modules/benchmarks/src/di/di_benchmark.html new file mode 100644 index 0000000000..b779dca771 --- /dev/null +++ b/modules/benchmarks/src/di/di_benchmark.html @@ -0,0 +1,12 @@ + + + + + + + + + +$SCRIPTS$ + + diff --git a/modules/benchmarks/src/di/di_benchmark.js b/modules/benchmarks/src/di/di_benchmark.js new file mode 100644 index 0000000000..fffcf3ee70 --- /dev/null +++ b/modules/benchmarks/src/di/di_benchmark.js @@ -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++; + } +} diff --git a/modules/benchmarks/src/di/injector_get_benchmark.js b/modules/benchmarks/src/di/injector_get_benchmark.js deleted file mode 100644 index c3cc8c95fd..0000000000 --- a/modules/benchmarks/src/di/injector_get_benchmark.js +++ /dev/null @@ -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++; - } -} diff --git a/modules/benchmarks/src/di/injector_get_by_key_benchmark.js b/modules/benchmarks/src/di/injector_get_by_key_benchmark.js deleted file mode 100644 index 6fd8669651..0000000000 --- a/modules/benchmarks/src/di/injector_get_by_key_benchmark.js +++ /dev/null @@ -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++; - } -} diff --git a/modules/benchmarks/src/di/injector_get_child_benchmark.js b/modules/benchmarks/src/di/injector_get_child_benchmark.js deleted file mode 100644 index 1aa1195695..0000000000 --- a/modules/benchmarks/src/di/injector_get_child_benchmark.js +++ /dev/null @@ -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++; - } -} diff --git a/modules/benchmarks/src/di/injector_instantiate_benchmark.js b/modules/benchmarks/src/di/injector_instantiate_benchmark.js deleted file mode 100644 index 9a8d44875f..0000000000 --- a/modules/benchmarks/src/di/injector_instantiate_benchmark.js +++ /dev/null @@ -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++; - } -} diff --git a/modules/benchmarks/src/di/main.html b/modules/benchmarks/src/di/main.html deleted file mode 100644 index 3995f8ae30..0000000000 --- a/modules/benchmarks/src/di/main.html +++ /dev/null @@ -1 +0,0 @@ -$SCRIPTS$ \ No newline at end of file diff --git a/modules/benchmarks/src/di/main.js b/modules/benchmarks/src/di/main.js deleted file mode 100644 index dac1fc9a9f..0000000000 --- a/modules/benchmarks/src/di/main.js +++ /dev/null @@ -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); - }); -} diff --git a/modules/benchmarks/src/element_injector/element_injector_benchmark.html b/modules/benchmarks/src/element_injector/element_injector_benchmark.html new file mode 100644 index 0000000000..fb6fdb6ade --- /dev/null +++ b/modules/benchmarks/src/element_injector/element_injector_benchmark.html @@ -0,0 +1,10 @@ + + + + + + + +$SCRIPTS$ + + diff --git a/modules/benchmarks/src/element_injector/element_injector_benchmark.js b/modules/benchmarks/src/element_injector/element_injector_benchmark.js new file mode 100644 index 0000000000..f35218db38 --- /dev/null +++ b/modules/benchmarks/src/element_injector/element_injector_benchmark.js @@ -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++; + } +} diff --git a/modules/benchmarks/src/element_injector/instantiate_benchmark.js b/modules/benchmarks/src/element_injector/instantiate_benchmark.js deleted file mode 100644 index c034986e9c..0000000000 --- a/modules/benchmarks/src/element_injector/instantiate_benchmark.js +++ /dev/null @@ -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++; - } -} diff --git a/modules/benchmarks/src/element_injector/instantiate_benchmark_codegen.js b/modules/benchmarks/src/element_injector/instantiate_benchmark_codegen.js deleted file mode 100644 index c92fbc092f..0000000000 --- a/modules/benchmarks/src/element_injector/instantiate_benchmark_codegen.js +++ /dev/null @@ -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++; - } -} diff --git a/modules/benchmarks/src/element_injector/instantiate_directive_benchmark.js b/modules/benchmarks/src/element_injector/instantiate_directive_benchmark.js deleted file mode 100644 index e9d3b06b99..0000000000 --- a/modules/benchmarks/src/element_injector/instantiate_directive_benchmark.js +++ /dev/null @@ -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++; - } -} diff --git a/modules/benchmarks/src/element_injector/main.html b/modules/benchmarks/src/element_injector/main.html deleted file mode 100644 index 3995f8ae30..0000000000 --- a/modules/benchmarks/src/element_injector/main.html +++ /dev/null @@ -1 +0,0 @@ -$SCRIPTS$ \ No newline at end of file diff --git a/modules/benchmarks/src/element_injector/main.js b/modules/benchmarks/src/element_injector/main.js deleted file mode 100644 index ebfe18b11d..0000000000 --- a/modules/benchmarks/src/element_injector/main.js +++ /dev/null @@ -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); - }); -} diff --git a/modules/benchmarks/src/index.html b/modules/benchmarks/src/index.html new file mode 100644 index 0000000000..9af6c61036 --- /dev/null +++ b/modules/benchmarks/src/index.html @@ -0,0 +1,25 @@ + + + + + + diff --git a/modules/benchmarks/src/tree/main.html b/modules/benchmarks/src/tree/main.html deleted file mode 100644 index dd294aa7ef..0000000000 --- a/modules/benchmarks/src/tree/main.html +++ /dev/null @@ -1,5 +0,0 @@ -$SCRIPTS$ - - - - \ No newline at end of file diff --git a/modules/benchmarks/src/tree/main.js b/modules/benchmarks/src/tree/main.js deleted file mode 100644 index f98bafc9a3..0000000000 --- a/modules/benchmarks/src/tree/main.js +++ /dev/null @@ -1,5 +0,0 @@ -import * as tree_benchmark from './tree_benchmark'; - -export function main() { - tree_benchmark.main(); -} diff --git a/modules/benchmarks/src/tree/tree_benchmark.html b/modules/benchmarks/src/tree/tree_benchmark.html new file mode 100644 index 0000000000..a0634dd2e3 --- /dev/null +++ b/modules/benchmarks/src/tree/tree_benchmark.html @@ -0,0 +1,27 @@ + + + + +

Angular2 tree benchmark

+

+ + +

+ +

Baseline tree benchmark

+

+ + +

+ +
+ +
+ +
+ +
+ +$SCRIPTS$ + + \ No newline at end of file diff --git a/modules/benchmarks/src/tree/tree_benchmark.js b/modules/benchmarks/src/tree/tree_benchmark.js index 7d54ab3131..526489793d 100644 --- a/modules/benchmarks/src/tree/tree_benchmark.js +++ b/modules/benchmarks/src/tree/tree_benchmark.js @@ -1,5 +1,3 @@ -import {benchmark, benchmarkStep} from 'benchpress/benchpress'; - import {ChangeDetector} from 'change_detection/change_detector'; import {Parser} from 'change_detection/parser/parser'; 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 {DirectiveMetadataReader} from 'core/compiler/directive_metadata_reader'; import {TemplateLoader} from 'core/compiler/template_loader'; +import {LifeCycle} from 'core/life_cycle/life_cycle'; import {reflector} from 'reflection/reflection'; import {DOM, document, Element} from 'facade/dom'; @@ -16,7 +15,7 @@ import {isPresent} from 'facade/lang'; var MAX_DEPTH = 9; -function setup() { +function setupReflector() { // TODO: Put the general calls to reflector.register... in a shared file // as they are needed in all benchmarks... @@ -98,6 +97,12 @@ function setup() { 'annotations': [] }); + reflector.registerType(LifeCycle, { + "factory": (cd) => new LifeCycle(cd), + "parameters": [[ChangeDetector]], + "annotations": [] + }); + reflector.registerGetters({ 'value': (a) => a.value, @@ -115,61 +120,62 @@ function setup() { 'data': (a,v) => a.data = v, 'ngIf': (a,v) => a.ngIf = v }); - - return bootstrap(AppComponent); } export function main() { + setupReflector(); + var app; var changeDetector; - setup().then((injector) => { - changeDetector = injector.get(ChangeDetector); - app = injector.get(AppComponent); - }); + var baselineRootTreeComponent; + var count = 0; - benchmark(`tree benchmark`, function() { - var count = 0; + function ng2DestroyDom(_) { + // TODO: We need an initial value as otherwise the getter for data.value will fail + // --> this should be already caught in change detection! + app.initData = new TreeNode('', null, null); + changeDetector.detectChanges(); + } - benchmarkStep(`destroyDom binary tree of depth ${MAX_DEPTH}`, function() { - // TODO: We need an initial value as otherwise the getter for data.value will fail - // --> this should be already caught in change detection! - app.initData = new TreeNode('', null, null); - changeDetector.detectChanges(); + function ng2CreateDom(_) { + 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', '-']; + + app.initData = buildTree(MAX_DEPTH, values, 0); + 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); }); + } - benchmarkStep(`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', '-']; + function baselineDestroyDom(_) { + baselineRootTreeComponent.update(new TreeNode('', null, null)); + } - app.initData = buildTree(maxDepth, values, 0); - changeDetector.detectChanges(); - }); + function baselineCreateDom(_) { + 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', '-']; - }); + baselineRootTreeComponent.update(buildTree(MAX_DEPTH, values, 0)); + } - benchmark(`baseline tree benchmark`, function() { - var baselineAppElement = DOM.querySelectorAll(document, 'baseline')[0]; - var rootTreeComponent = new BaseLineTreeComponent(); - DOM.appendChild(baselineAppElement, rootTreeComponent.element); + 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); + } - 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 ? - ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] : - ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-']; - - rootTreeComponent.update(buildTree(maxDepth, values, 0)); - }); - - }); + initNg2(); + initBaseline(); } class TreeNode { diff --git a/modules/benchmarks/test/perf/change_detection_perf.js b/modules/benchmarks/test/perf/change_detection_perf.js new file mode 100644 index 0000000000..9dfd487a70 --- /dev/null +++ b/modules/benchmarks/test/perf/change_detection_perf.js @@ -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' + }); + }); + +}); diff --git a/modules/benchmarks/test/perf/compiler_perf.js b/modules/benchmarks/test/perf/compiler_perf.js new file mode 100644 index 0000000000..f525b0e815 --- /dev/null +++ b/modules/benchmarks/test/perf/compiler_perf.js @@ -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' + }); + }); + +}); diff --git a/modules/benchmarks/test/perf/di_perf.js b/modules/benchmarks/test/perf/di_perf.js new file mode 100644 index 0000000000..9d84f44304 --- /dev/null +++ b/modules/benchmarks/test/perf/di_perf.js @@ -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' + }); + }); + +}); diff --git a/modules/benchmarks/test/perf/element_injector_perf.js b/modules/benchmarks/test/perf/element_injector_perf.js new file mode 100644 index 0000000000..1702196ae8 --- /dev/null +++ b/modules/benchmarks/test/perf/element_injector_perf.js @@ -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' + }); + }); + +}); diff --git a/modules/benchmarks/test/perf/tree_perf.js b/modules/benchmarks/test/perf/tree_perf.js new file mode 100644 index 0000000000..41be46c751 --- /dev/null +++ b/modules/benchmarks/test/perf/tree_perf.js @@ -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' + }); + }); + +}); diff --git a/modules/benchmarks_external/pubspec.yaml b/modules/benchmarks_external/pubspec.yaml index 41e80a792a..132b08601b 100644 --- a/modules/benchmarks_external/pubspec.yaml +++ b/modules/benchmarks_external/pubspec.yaml @@ -3,7 +3,6 @@ environment: sdk: '>=1.4.0' dependencies: angular: ">=1.0.0 <2.0.0" - benchpress: - path: ../benchpress + browser: '>=0.10.0 <0.11.0' transformers: - angular \ No newline at end of file diff --git a/modules/benchmarks_external/src/compiler/compiler_benchmark_ng10.dart b/modules/benchmarks_external/src/compiler/compiler_benchmark.dart similarity index 54% rename from modules/benchmarks_external/src/compiler/compiler_benchmark_ng10.dart rename to modules/benchmarks_external/src/compiler/compiler_benchmark.dart index 834855c792..db03be93c9 100644 --- a/modules/benchmarks_external/src/compiler/compiler_benchmark_ng10.dart +++ b/modules/benchmarks_external/src/compiler/compiler_benchmark.dart @@ -1,8 +1,8 @@ +// compiler benchmark in AngularDart 1.x library compiler_benchmark_ng10; import 'package:angular/angular.dart'; import 'package:angular/application_factory.dart'; -import 'package:benchpress/benchpress.dart'; import 'dart:html'; var COUNT = 30; @@ -16,42 +16,26 @@ main() { ..bind(Dir3) ..bind(Dir4); - benchmark("AngularDart 1.0 Compiler.compile 5*${COUNT} element with bindings", () { - var template = loadTemplate('templateWithBindings', COUNT); + var templateWithBindings = 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 directiveMap = injector.get(DirectiveMap); - final compiler = injector.get(Compiler); - final directiveMap = injector.get(DirectiveMap); - final di = injector.get(DirectiveInjector); - final rootScope = injector.get(Scope); + compileWithBindings(_) { + final cloned = templateWithBindings.clone(true); + compiler([cloned], directiveMap); + } - benchmarkStep('run', () { - final cloned = template.clone(true); - final scope = rootScope.createChild({}); - final viewFactory = compiler([cloned], directiveMap); - viewFactory(scope, di); - scope.destroy(); - }); - }); + compileNoBindings(_) { + final cloned = templateNoBindings.clone(true); + compiler([cloned], directiveMap); + } - benchmark("AngularDart 1.0 instantiate 5*${COUNT} element with bindings", () { - var template = loadTemplate('templateWithBindings', COUNT); + document.querySelector('#compileWithBindings').addEventListener('click', compileWithBindings); + document.querySelector('#compileNoBindings').addEventListener('click', compileNoBindings); - final injector = applicationFactory().addModule(m).run(); - - 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) { diff --git a/modules/benchmarks_external/src/compiler/compiler_benchmark_ng13.es6 b/modules/benchmarks_external/src/compiler/compiler_benchmark.es6 similarity index 51% rename from modules/benchmarks_external/src/compiler/compiler_benchmark_ng13.es6 rename to modules/benchmarks_external/src/compiler/compiler_benchmark.es6 index 895d0b5399..15ce5ee3f0 100644 --- a/modules/benchmarks_external/src/compiler/compiler_benchmark_ng13.es6 +++ b/modules/benchmarks_external/src/compiler/compiler_benchmark.es6 @@ -1,46 +1,7 @@ -import {benchmark, benchmarkStep} from 'benchpress/benchpress'; - +// compiler benchmark in AngularJS 1.x var COUNT = 30; -var $compile; -var $rootScope; 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'); angular.bootstrap(ngEl, ['app']); } @@ -62,7 +23,7 @@ function loadTemplate(templateId, repeatCount) { } angular.module('app', []) -.directive('dir0', function($parse) { +.directive('dir0', ['$parse', function($parse) { return { compile: function($element, $attrs) { var expr = $parse($attrs.attr0); @@ -71,8 +32,8 @@ angular.module('app', []) } } }; -}) -.directive('dir1', function($parse) { +}]) +.directive('dir1', ['$parse', function($parse) { return { compile: function($element, $attrs) { var expr = $parse($attrs.attr1); @@ -81,8 +42,8 @@ angular.module('app', []) } } }; -}) -.directive('dir2', function($parse) { +}]) +.directive('dir2', ['$parse', function($parse) { return { compile: function($element, $attrs) { var expr = $parse($attrs.attr2); @@ -91,8 +52,8 @@ angular.module('app', []) } } }; -}) -.directive('dir3', function($parse) { +}]) +.directive('dir3', ['$parse', function($parse) { return { compile: function($element, $attrs) { var expr = $parse($attrs.attr3); @@ -101,8 +62,8 @@ angular.module('app', []) } } }; -}) -.directive('dir4', function($parse) { +}]) +.directive('dir4', ['$parse', function($parse) { return { compile: function($element, $attrs) { var expr = $parse($attrs.attr4); @@ -111,9 +72,24 @@ angular.module('app', []) } } }; -}) -.run(function(_$compile_, _$rootScope_) { - $compile = _$compile_; - $rootScope = _$rootScope_; -}); +}]) +.run(['$compile', function($compile) { + var templateNoBindings = loadTemplate('templateNoBindings', COUNT); + 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); + } +}]); diff --git a/modules/benchmarks_external/src/compiler/main.html b/modules/benchmarks_external/src/compiler/compiler_benchmark.html similarity index 92% rename from modules/benchmarks_external/src/compiler/main.html rename to modules/benchmarks_external/src/compiler/compiler_benchmark.html index 178588bd7d..460bb9bf54 100644 --- a/modules/benchmarks_external/src/compiler/main.html +++ b/modules/benchmarks_external/src/compiler/compiler_benchmark.html @@ -1,4 +1,9 @@ -$SCRIPTS$ + + + + + + + +$SCRIPTS$ + + + \ No newline at end of file diff --git a/modules/benchmarks_external/src/compiler/main.dart b/modules/benchmarks_external/src/compiler/main.dart deleted file mode 100644 index 8c6ceb28a2..0000000000 --- a/modules/benchmarks_external/src/compiler/main.dart +++ /dev/null @@ -1,7 +0,0 @@ -library compiler_benchmark; - -import './compiler_benchmark_ng10.dart' as cbm; - -main () { - cbm.main(); -} \ No newline at end of file diff --git a/modules/benchmarks_external/src/compiler/main.es6 b/modules/benchmarks_external/src/compiler/main.es6 deleted file mode 100644 index a127b6e36b..0000000000 --- a/modules/benchmarks_external/src/compiler/main.es6 +++ /dev/null @@ -1 +0,0 @@ -export {main} from './compiler_benchmark_ng13'; diff --git a/modules/benchmarks_external/src/index.html b/modules/benchmarks_external/src/index.html new file mode 100644 index 0000000000..51a492c9da --- /dev/null +++ b/modules/benchmarks_external/src/index.html @@ -0,0 +1,13 @@ + + + + + + diff --git a/modules/benchmarks_external/src/tree/main.dart b/modules/benchmarks_external/src/tree/main.dart deleted file mode 100644 index 59d88c0aee..0000000000 --- a/modules/benchmarks_external/src/tree/main.dart +++ /dev/null @@ -1,7 +0,0 @@ -library tree_benchmark; - -import './tree_benchmark_ng10.dart' as bm; - -main () { - bm.main(); -} \ No newline at end of file diff --git a/modules/benchmarks_external/src/tree/main.es6 b/modules/benchmarks_external/src/tree/main.es6 deleted file mode 100644 index c064dd1dbb..0000000000 --- a/modules/benchmarks_external/src/tree/main.es6 +++ /dev/null @@ -1 +0,0 @@ -export {main} from './tree_benchmark_ng13'; diff --git a/modules/benchmarks_external/src/tree/main.html b/modules/benchmarks_external/src/tree/main.html deleted file mode 100644 index a260a6be0f..0000000000 --- a/modules/benchmarks_external/src/tree/main.html +++ /dev/null @@ -1,3 +0,0 @@ -$SCRIPTS$ - - \ No newline at end of file diff --git a/modules/benchmarks_external/src/tree/tree_benchmark_ng10.dart b/modules/benchmarks_external/src/tree/tree_benchmark.dart similarity index 65% rename from modules/benchmarks_external/src/tree/tree_benchmark_ng10.dart rename to modules/benchmarks_external/src/tree/tree_benchmark.dart index 44a651e4dd..e81408b0d1 100644 --- a/modules/benchmarks_external/src/tree/tree_benchmark_ng10.dart +++ b/modules/benchmarks_external/src/tree/tree_benchmark.dart @@ -1,8 +1,8 @@ +// tree benchmark in AngularDart 1.x library tree_benchmark_ng10; import 'package:angular/angular.dart'; import 'package:angular/application_factory.dart'; -import 'package:benchpress/benchpress.dart'; import 'dart:html'; var MAX_DEPTH = 9; @@ -23,28 +23,26 @@ main() { final injector = setup(); final zone = injector.get(VmTurnZone); final rootScope = injector.get(Scope); + var count = 0; - benchmark("tree benchmark", () { - var count = 0; - - benchmarkStep("AngularDart destroyDom binary tree of depth ${MAX_DEPTH}", () { - zone.run(() { - rootScope.context['initData'] = new TreeNode(''); - }); + destroyDom(_) { + zone.run(() { + rootScope.context['initData'] = new TreeNode(''); }); + } - benchmarkStep("AngularDart createDom binary tree of depth ${MAX_DEPTH}", () { - zone.run(() { - 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', '-']; + createDom(_) { + zone.run(() { + 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.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( diff --git a/modules/benchmarks_external/src/tree/tree_benchmark.es6 b/modules/benchmarks_external/src/tree/tree_benchmark.es6 new file mode 100644 index 0000000000..8d8177a38e --- /dev/null +++ b/modules/benchmarks_external/src/tree/tree_benchmark.es6 @@ -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: +' {{data.value}}'+ +' '+ +' '+ +'' + }; +}) +// 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 = ''; + 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)); +} + + + diff --git a/modules/benchmarks_external/src/tree/tree_benchmark.html b/modules/benchmarks_external/src/tree/tree_benchmark.html new file mode 100644 index 0000000000..5d381f83ae --- /dev/null +++ b/modules/benchmarks_external/src/tree/tree_benchmark.html @@ -0,0 +1,17 @@ + + + + +

AngularJS/Dart 1.x tree benchmark

+

+ + +

+ +
+ +
+ +$SCRIPTS$ + + \ No newline at end of file diff --git a/modules/benchmarks_external/src/tree/tree_benchmark_ng13.es6 b/modules/benchmarks_external/src/tree/tree_benchmark_ng13.es6 deleted file mode 100644 index 9dd2c8af11..0000000000 --- a/modules/benchmarks_external/src/tree/tree_benchmark_ng13.es6 +++ /dev/null @@ -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: -' {{data.value}}'+ -' '+ -' '+ -'' - }; - }) - // 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 = ''; - 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)); -} - - - diff --git a/modules/benchmarks_external/test/perf/compiler_perf.js b/modules/benchmarks_external/test/perf/compiler_perf.js new file mode 100644 index 0000000000..f2be62cca0 --- /dev/null +++ b/modules/benchmarks_external/test/perf/compiler_perf.js @@ -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' + }); + }); + +}); diff --git a/modules/benchmarks_external/test/perf/tree_perf.js b/modules/benchmarks_external/test/perf/tree_perf.js new file mode 100644 index 0000000000..915cf53cfe --- /dev/null +++ b/modules/benchmarks_external/test/perf/tree_perf.js @@ -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' + }); + }); + +}); diff --git a/modules/benchpress/pubspec.yaml b/modules/benchpress/pubspec.yaml deleted file mode 100644 index b83af2da19..0000000000 --- a/modules/benchpress/pubspec.yaml +++ /dev/null @@ -1,4 +0,0 @@ -name: benchpress -environment: - sdk: '>=1.4.0' -dependencies: diff --git a/modules/benchpress/src/benchpress.dart b/modules/benchpress/src/benchpress.dart deleted file mode 100644 index 81542709bd..0000000000 --- a/modules/benchpress/src/benchpress.dart +++ /dev/null @@ -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 += '

Benchmarks:

All'; - for (var i=0; i<_benchmarkNames.length; i++) { - var activeClass = _useBenchmark(i) ? 'active' : ''; - div.innerHtml += '${_benchmarkNames[i]}'; - } - 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()) - })); -} diff --git a/modules/benchpress/src/benchpress.es6 b/modules/benchpress/src/benchpress.es6 deleted file mode 100644 index d5e5d5e0df..0000000000 --- a/modules/benchpress/src/benchpress.es6 +++ /dev/null @@ -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 += '

Benchmarks:

All'; - for (var i=0; i'+benchmarkNames[i]+''); - } - 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 - }); -} diff --git a/modules/core/src/compiler/compiler.js b/modules/core/src/compiler/compiler.js index 9ab2f6545d..50e82378fa 100644 --- a/modules/core/src/compiler/compiler.js +++ b/modules/core/src/compiler/compiler.js @@ -36,6 +36,10 @@ export class CompilerCache { } return result; } + + clear() { + this._cache = MapWrapper.create(); + } } /** diff --git a/package.json b/package.json index 67757d8dba..3ba814508d 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "author": "Tobias Bosch ", "license": "Apache-2.0", "dependencies": { - "angular-benchpress": "^0.1.3", + "protractor": "1.5.x", "del": "~1", "es6-module-loader": "^0.9.2", "event-stream": "^3.1.5", diff --git a/protractor-perf-dart2js.conf.js b/protractor-perf-dart2js.conf.js new file mode 100644 index 0000000000..89176bbbdb --- /dev/null +++ b/protractor-perf-dart2js.conf.js @@ -0,0 +1,3 @@ +var config = exports.config = require('./protractor-perf-shared.js').config; +config.params.lang = 'dart'; +config.baseUrl = 'http://localhost:8002/'; diff --git a/protractor-perf-js.conf.js b/protractor-perf-js.conf.js new file mode 100644 index 0000000000..172de8c4d5 --- /dev/null +++ b/protractor-perf-js.conf.js @@ -0,0 +1,4 @@ +var config = exports.config = require('./protractor-perf-shared.js').config; +config.params.lang = 'js'; +config.baseUrl = 'http://localhost:8001/'; + diff --git a/protractor-perf-shared.js b/protractor-perf-shared.js new file mode 100644 index 0000000000..6eb78ebc80 --- /dev/null +++ b/protractor-perf-shared.js @@ -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' + } + }; +} \ No newline at end of file diff --git a/scripts/travis/build.sh b/scripts/travis/build.sh index 95e817aed3..707c0c6fd0 100755 --- a/scripts/travis/build.sh +++ b/scripts/travis/build.sh @@ -1,5 +1,4 @@ #!/bin/bash - set -e echo ============================================================================= @@ -17,4 +16,18 @@ pub install --browsers=$BROWSERS --single-run ./node_modules/karma/bin/karma start karma-dart.conf \ --reporters=dots \ - --browsers=$BROWSERS --single-run \ No newline at end of file + --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 \ No newline at end of file diff --git a/tools/build/benchpress.js b/tools/build/benchpress.js deleted file mode 100644 index e0d7a9c84c..0000000000 --- a/tools/build/benchpress.js +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/tools/build/jsserve.js b/tools/build/jsserve.js index ab263b9a6a..0a60f5bb8f 100644 --- a/tools/build/jsserve.js +++ b/tools/build/jsserve.js @@ -2,7 +2,7 @@ module.exports = function(gulp, plugins, config) { return function() { plugins.connect.server({ root: [__dirname+'/../../'+config.path], - port: 8000, + port: config.port, livereload: false, open: false })(); diff --git a/tools/build/pubbuild.js b/tools/build/pubbuild.js new file mode 100644 index 0000000000..ac51f1e658 --- /dev/null +++ b/tools/build/pubbuild.js @@ -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))); +} \ No newline at end of file diff --git a/tools/perf/util.js b/tools/perf/util.js new file mode 100644 index 0000000000..c5c2e01368 --- /dev/null +++ b/tools/perf/util.js @@ -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 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); + } + } + } +} \ No newline at end of file