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:
@ -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) {
|
@ -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);
|
||||
}
|
||||
}]);
|
||||
|
@ -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">
|
||||
<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>
|
||||
</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';
|
13
modules/benchmarks_external/src/index.html
Normal file
13
modules/benchmarks_external/src/index.html
Normal file
@ -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;
|
||||
|
||||
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(
|
102
modules/benchmarks_external/src/tree/tree_benchmark.es6
Normal file
102
modules/benchmarks_external/src/tree/tree_benchmark.es6
Normal file
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
17
modules/benchmarks_external/src/tree/tree_benchmark.html
Normal file
17
modules/benchmarks_external/src/tree/tree_benchmark.html
Normal file
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user