feat(compiler): add benchmarks

- compileEmptyTemplate
- compile25ElementsNoBindings
- compile25ElementsWithBindings

For the results see the PR #197.

Closes #197
This commit is contained in:
Tobias Bosch 2014-11-14 14:03:03 -08:00
parent aa9eeb80e7
commit b07ea6b90e
6 changed files with 235 additions and 15 deletions

View File

@ -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())
}));
}

View File

@ -1,17 +1,35 @@
System.import('benchmarks/compiler/selector_benchmark').then(function (bm) { System.import('benchmarks/compiler/selector_benchmark').then(function (bm) {
bm.setup(); 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)); }, console.log.bind(console));
System.import('benchmarks/compiler/selector_benchmark').then(function (bm) { System.import('benchmarks/compiler/selector_benchmark').then(function (bm) {
bm.setup(); 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)); }, console.log.bind(console));
System.import('benchmarks/compiler/selector_benchmark').then(function (bm) { System.import('benchmarks/compiler/selector_benchmark').then(function (bm) {
bm.setup(); 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)); }, console.log.bind(console));

View File

@ -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('<div></div>');
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:
// <div class="class0 class1 class2 class3 class4 " dir0="" attr0="value0" dir1="" attr1="value1" dir2="" attr2="value2" dir3="" attr3="value3" dir4="" attr4="value4">
// </div>
function buildTemplateWith25ElementsNoBindings() {
var result = '';
for (var i=0; i<5; i++) {
for (var j=0; j<5; j++) {
result += '<div class="';
for (var k=0; k<5; k++) {
result += `class${k} `;
}
result += '"';
for (var k=0; k<5; k++) {
result += ` dir${k}`;
result += ` attr${k}=value${k}`;
}
for (var k=0; k<5; k++) {
result += ` dir${k}`;
result += ` attr${k}=value${k}`;
}
result += '>';
}
for (var j=0; j<5; j++) {
result += '</div>';
}
}
return createTemplate(result);
}
// creates 25 nested divs , each looking like this:
// <div class="class0 class1 class2 class3 class4 " dir0="" [attr0]="value0" dir1="" [attr1]="value1" dir2="" [attr2]="value2" dir3="" [attr3]="value3" dir4="" [attr4]="value4">
// {{inter0}}{{inter1}}{{inter2}}{{inter3}}{{inter4}}
// </div>
function buildTemplateWith25ElementsAndBindings() {
var result = '';
for (var i=0; i<5; i++) {
for (var j=0; j<5; j++) {
result += '<div class="';
for (var k=0; k<5; k++) {
result += `class${k} `;
}
result += '"';
for (var k=0; k<5; k++) {
result += ` dir${k}`;
result += ` [attr${k}]=value${k}`;
}
for (var k=0; k<5; k++) {
result += ` dir${k}`;
result += ` [attr${k}]=value${k}`;
}
result += '>';
for (var k=0; k<5; k++) {
result += `{{inter${k}}}`;
}
}
for (var j=0; j<5; j++) {
result += '</div>';
}
}
return createTemplate(result);
}
function createTemplate(html) {
return DOM.createTemplate(html);
}

View File

@ -31,13 +31,11 @@ export function runParse() {
} }
export function runAdd() { export function runAdd() {
// The sum is used to prevent Chrome from optimizing the loop away...
var matcher = new SelectorMatcher(); var matcher = new SelectorMatcher();
var count = 0;
for (var i=0; i<COUNT; i++) { for (var i=0; i<COUNT; i++) {
count += matcher.addSelectable(fixedSelectors[i], i); matcher.addSelectable(fixedSelectors[i], i);
} }
return count; return matcher;
} }
export function runMatch() { export function runMatch() {
@ -72,7 +70,7 @@ function randomStr(len){
function randomChar(){ function randomChar(){
var n = randomNum(62); var n = randomNum(62);
if(n<10) return n; //1-10 if(n<10) return n.toString(); //1-10
if(n<36) return StringWrapper.fromCharCode(n+55); //A-Z if(n<36) return StringWrapper.fromCharCode(n+55); //A-Z
return StringWrapper.fromCharCode(n+61); //a-z return StringWrapper.fromCharCode(n+61); //a-z
} }

View File

@ -39,14 +39,13 @@ export class Compiler {
compile(component:Type, templateRoot:Element = null):Promise<ProtoView> { compile(component:Type, templateRoot:Element = null):Promise<ProtoView> {
// TODO load all components transitively from the cache first // TODO load all components transitively from the cache first
var cache = null; var cache = null;
return PromiseWrapper.resolve(this._compileAllCached( return PromiseWrapper.resolve(this.compileWithCache(
this._reflector.annotatedType(component), cache, this._reflector.annotatedType(component), templateRoot)
cache,
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)) { if (isBlank(templateRoot)) {
// TODO: read out the cache if templateRoot = null. Could contain: // TODO: read out the cache if templateRoot = null. Could contain:
// - templateRoot string // - templateRoot string
@ -62,7 +61,7 @@ export class Compiler {
for (var i=0; i<compileElements.length; i++) { for (var i=0; i<compileElements.length; i++) {
var ce = compileElements[i]; var ce = compileElements[i];
if (isPresent(ce.componentDirective)) { if (isPresent(ce.componentDirective)) {
ce.inheritedElementBinder.nestedProtoView = this._compileAllCached(ce.componentDirective, cache, null); ce.inheritedElementBinder.nestedProtoView = this.compileWithCache(cache, ce.componentDirective, null);
} }
} }

View File

@ -1,4 +1,4 @@
library facade.di.reflector; library facade.compiler.reflector;
import 'dart:mirrors'; import 'dart:mirrors';
import '../annotations/directive.dart'; import '../annotations/directive.dart';