diff --git a/modules/benchmarks/src/compiler/benchmark.dart b/modules/benchmarks/src/compiler/benchmark.dart new file mode 100644 index 0000000000..d78e810612 --- /dev/null +++ b/modules/benchmarks/src/compiler/benchmark.dart @@ -0,0 +1,36 @@ +library compiler_benchmark; + +import './selector_benchmark.dart' as sbm; +import './compiler_benchmark.dart' as cbm; +import 'dart:js' as js; + +main () { + sbm.setup(); + cbm.setup(); + + js.context['benchmarkSteps'].add(new js.JsObject.jsify({ + "name": "CssSelector.parse * 1000", + "fn": new js.JsFunction.withThis((_) => sbm.runParse()) + })); + js.context['benchmarkSteps'].add(new js.JsObject.jsify({ + "name": "SelectorMatcher.addSelectable * 1000", + "fn": new js.JsFunction.withThis((_) => sbm.runAdd()) + })); + js.context['benchmarkSteps'].add(new js.JsObject.jsify({ + "name": "SelectorMatcher.match * 1000", + "fn": new js.JsFunction.withThis((_) => sbm.runMatch()) + })); + + js.context['benchmarkSteps'].add(new js.JsObject.jsify({ + "name": "Compiler.compile empty template", + "fn": new js.JsFunction.withThis((_) => cbm.compileEmptyTemplate()) + })); + js.context['benchmarkSteps'].add(new js.JsObject.jsify({ + "name": "Compiler.compile 25 element no bindings", + "fn": new js.JsFunction.withThis((_) => cbm.compile25ElementsNoBindings()) + })); + js.context['benchmarkSteps'].add(new js.JsObject.jsify({ + "name": "Compiler.compile 25 element with bindings", + "fn": new js.JsFunction.withThis((_) => cbm.compile25ElementsWithBindings()) + })); +} \ No newline at end of file diff --git a/modules/benchmarks/src/compiler/benchmark.es5 b/modules/benchmarks/src/compiler/benchmark.es5 index 9e007b302c..4be167af17 100644 --- a/modules/benchmarks/src/compiler/benchmark.es5 +++ b/modules/benchmarks/src/compiler/benchmark.es5 @@ -1,17 +1,35 @@ System.import('benchmarks/compiler/selector_benchmark').then(function (bm) { bm.setup(); - window.benchmarkSteps.push({name: 'CssSelector.parse', fn: bm.runParse}); + window.benchmarkSteps.push({name: 'CssSelector.parse * 1000', fn: bm.runParse}); }, console.log.bind(console)); System.import('benchmarks/compiler/selector_benchmark').then(function (bm) { bm.setup(); - window.benchmarkSteps.push({name: 'SelectorMatcher.addSelectable', fn: bm.runAdd}); + window.benchmarkSteps.push({name: 'SelectorMatcher.addSelectable * 1000', fn: bm.runAdd}); }, console.log.bind(console)); System.import('benchmarks/compiler/selector_benchmark').then(function (bm) { bm.setup(); - window.benchmarkSteps.push({name: 'SelectorMatcher.match', fn: bm.runMatch}); + window.benchmarkSteps.push({name: 'SelectorMatcher.match * 1000', fn: bm.runMatch}); +}, console.log.bind(console)); + +System.import('benchmarks/compiler/compiler_benchmark').then(function (bm) { + bm.setup(); + + window.benchmarkSteps.push({name: 'Compiler.compile empty template', fn: bm.compileEmptyTemplate}); +}, console.log.bind(console)); + +System.import('benchmarks/compiler/compiler_benchmark').then(function (bm) { + bm.setup(); + + window.benchmarkSteps.push({name: 'Compiler.compile 25 element no bindings', fn: bm.compile25ElementsNoBindings}); +}, console.log.bind(console)); + +System.import('benchmarks/compiler/compiler_benchmark').then(function (bm) { + bm.setup(); + + window.benchmarkSteps.push({name: 'Compiler.compile 25 element with bindings', fn: bm.compile25ElementsWithBindings}); }, console.log.bind(console)); diff --git a/modules/benchmarks/src/compiler/compiler_benchmark.js b/modules/benchmarks/src/compiler/compiler_benchmark.js new file mode 100644 index 0000000000..5b9ed81864 --- /dev/null +++ b/modules/benchmarks/src/compiler/compiler_benchmark.js @@ -0,0 +1,169 @@ +import {DOM} from 'facade/dom'; + +import {Parser} from 'change_detection/parser/parser'; +import {ClosureMap} from 'change_detection/parser/closure_map'; +import {Lexer} from 'change_detection/parser/lexer'; + +import {Compiler} from 'core/compiler/compiler'; +import {Reflector} from 'core/compiler/reflector'; + +import {Component} from 'core/annotations/component'; +import {Decorator} from 'core/annotations/decorator'; +import {TemplateConfig} from 'core/annotations/template_config'; + +var compiler; +var annotatedComponent; +var annotatedComponentNoDirectives; + +var emptyTemplate; +var templateWith25ElementsNoBindings; +var templateWith25ElementsAndBindings; + +export function setup() { + var closureMap = new ClosureMap(); + var reflector = new Reflector(); + compiler = new Compiler(null, reflector, new Parser(new Lexer(), closureMap), closureMap); + annotatedComponent = reflector.annotatedType(SomeComponent); + annotatedComponentNoDirectives = reflector.annotatedType(ComponentWithNoDirectives); + + emptyTemplate = createTemplate('
'); + templateWith25ElementsNoBindings = buildTemplateWith25ElementsNoBindings(); + templateWith25ElementsAndBindings = buildTemplateWith25ElementsAndBindings(); +} + +export function compileEmptyTemplate() { + var template = emptyTemplate; + return compiler.compileWithCache(null, annotatedComponent, template); +} + +export function compile25ElementsWithBindings() { + var template = templateWith25ElementsAndBindings; + return compiler.compileWithCache(null, annotatedComponent, template); +} + +export function compile25ElementsNoBindings() { + var template = templateWith25ElementsNoBindings; + return compiler.compileWithCache(null, annotatedComponentNoDirectives, template); +} + +@Decorator({ + selector: '[dir0]', + bind: { + 'attr0': 'prop' + } +}) +class Dir0 {} + +@Decorator({ + selector: '[dir1]', + bind: { + 'attr1': 'prop' + } +}) +class Dir1 {} + +@Decorator({ + selector: '[dir2]', + bind: { + 'attr2': 'prop' + } +}) +class Dir2 {} + +@Decorator({ + selector: '[dir3]', + bind: { + 'attr3': 'prop' + } +}) +class Dir3 {} + +@Decorator({ + selector: '[dir4]', + bind: { + 'attr4': 'prop' + } +}) +class Dir4 {} + +@Component({ + template: new TemplateConfig({ + directives: [Dir0, Dir1, Dir2, Dir3, Dir4] + }) +}) +class SomeComponent {} + +@Component({ + template: new TemplateConfig({ + directives: [] + }) +}) +class ComponentWithNoDirectives {} + +// creates 25 nested divs without bindings, each looking like this: +//
+//
+function buildTemplateWith25ElementsNoBindings() { + var result = ''; + for (var i=0; i<5; i++) { + for (var j=0; j<5; j++) { + result += '
+// {{inter0}}{{inter1}}{{inter2}}{{inter3}}{{inter4}} +//
+function buildTemplateWith25ElementsAndBindings() { + var result = ''; + for (var i=0; i<5; i++) { + for (var j=0; j<5; j++) { + result += '
{ // TODO load all components transitively from the cache first var cache = null; - return PromiseWrapper.resolve(this._compileAllCached( - this._reflector.annotatedType(component), - cache, - templateRoot) + return PromiseWrapper.resolve(this.compileWithCache( + cache, this._reflector.annotatedType(component), templateRoot) ); } - _compileAllCached(component:AnnotatedType, cache, templateRoot:Element = null):ProtoView { + // public so that we can compile in sync in performance tests. + compileWithCache(cache, component:AnnotatedType, templateRoot:Element = null):ProtoView { if (isBlank(templateRoot)) { // TODO: read out the cache if templateRoot = null. Could contain: // - templateRoot string @@ -62,7 +61,7 @@ export class Compiler { for (var i=0; i