fix(benchpress): make code compile and unit tests green again

This commit is contained in:
Tobias Bosch 2016-08-26 16:34:08 -07:00
parent db280fc67e
commit 1ef122988e
71 changed files with 704 additions and 998 deletions

View File

@ -41,6 +41,7 @@ module.exports = function(config) {
'dist/all/@angular/**/e2e_test/**',
'dist/all/@angular/router/**',
'dist/all/@angular/compiler-cli/**',
'dist/all/@angular/benchpress/**',
'dist/all/angular1_router.js',
'dist/all/@angular/platform-browser/testing/e2e_util.js'
],

View File

@ -1,6 +0,0 @@
Benchpress - a framework for e2e performance tests
=========
The sources for this package are in the main [Angular2](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo.
License: Apache MIT 2.0

View File

@ -1,8 +0,0 @@
Benchpress - a framework for e2e performance tests
=========
The sources for this package are in the main [Angular2](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo.
See [this project](https://github.com/angular/benchpress-tree) for an example.
License: Apache MIT 2.0

View File

@ -3,6 +3,10 @@
Benchpress is a framework for e2e performance tests.
See [here for an example project](https://github.com/angular/benchpress-tree).
The sources for this package are in the main [Angular2](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo.
License: Apache MIT 2.0
# Why?
There are so called "micro benchmarks" that essentially use a stop watch in the browser to measure time
@ -158,7 +162,7 @@ runner.sample({
````
When looking into the DevTools Timeline, we see a marker as well:
![Marked Timeline](marked_timeline.png)
![Marked Timeline](docs/marked_timeline.png)
### Custom Metrics Without Using `console.time`
@ -185,8 +189,8 @@ describe('home page load', function() {
userMetrics: {
timeToBootstrap: 'The time in milliseconds to bootstrap'
},
bindings: [
bind(RegressionSlopeValidator.METRIC).toValue('timeToBootstrap')
providers: [
{provide: RegressionSlopeValidator.METRIC, useValue: 'timeToBootstrap'}
]
}).then(done);
});
@ -208,9 +212,9 @@ Benchpress can also measure the "smoothness" of scrolling and animations. In ord
To collect these metrics, you need to execute `console.time('frameCapture')` and `console.timeEnd('frameCapture')` either in your benchmark application or in you benchmark driver via webdriver. The metrics mentioned above will only be collected between those two calls and it is recommended to wrap the time/timeEnd calls as closely as possible around the action you want to evaluate to get accurate measurements.
In addition to that, one extra binding needs to be passed to benchpress in tests that want to collect these metrics:
In addition to that, one extra provider needs to be passed to benchpress in tests that want to collect these metrics:
benchpress.sample(providers: [bp.bind(bp.Options.CAPTURE_FRAMES).toValue(true)], ... )
benchpress.sample(providers: [{provide: bp.Options.CAPTURE_FRAMES, useValue: true}], ... )
# Requests Metrics
@ -222,8 +226,8 @@ Benchpress can also record the number of requests sent and count the received "e
To collect these metrics, you need the following corresponding extra providers:
benchpress.sample(providers: [
bp.bind(bp.Options.RECEIVED_DATA).toValue(true),
bp.bind(bp.Options.REQUEST_COUNT).toValue(true)
{provide: bp.Options.RECEIVED_DATA, useValue: true},
{provide: bp.Options.REQUEST_COUNT, useValue: true}
], ... )
# Best practices
@ -256,7 +260,7 @@ To collect these metrics, you need the following corresponding extra providers:
# Detailed overview
![Overview](overview.png)
![Overview](docs/overview.png)
Definitions:

View File

@ -1,3 +0,0 @@
export './common.dart';
export './src/webdriver/async_webdriver_adapter.dart'
show AsyncWebDriverAdapter;

View File

@ -1,33 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Options} from './common';
export * from './common';
export {SeleniumWebDriverAdapter} from './src/webdriver/selenium_webdriver_adapter';
var fs = require('fs');
// TODO(tbosch): right now we bind the `writeFile` method
// in benchpres/benchpress.es6. This does not work for Dart,
// find another way...
// Note: Can't do the `require` call in a facade as it can't be loaded into the browser
// for our unit tests via karma.
Options.DEFAULT_PROVIDERS.push({provide: Options.WRITE_FILE, useValue: writeFile});
function writeFile(filename, content): Promise<any> {
return new Promise(function(resolve, reject) {
fs.writeFile(filename, content, (error) => {
if (error) {
reject(error);
} else {
resolve();
}
});
});
}

View File

@ -1,30 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export {Injector, OpaqueToken, ReflectiveInjector} from '@angular/core/src/di';
export {Options} from './src/common_options';
export {MeasureValues} from './src/measure_values';
export {Metric} from './src/metric';
export {MultiMetric} from './src/metric/multi_metric';
export {PerflogMetric} from './src/metric/perflog_metric';
export {UserMetric} from './src/metric/user_metric';
export {Reporter} from './src/reporter';
export {ConsoleReporter} from './src/reporter/console_reporter';
export {JsonFileReporter} from './src/reporter/json_file_reporter';
export {MultiReporter} from './src/reporter/multi_reporter';
export {Runner} from './src/runner';
export {SampleDescription} from './src/sample_description';
export {SampleState, Sampler} from './src/sampler';
export {Validator} from './src/validator';
export {RegressionSlopeValidator} from './src/validator/regression_slope_validator';
export {SizeValidator} from './src/validator/size_validator';
export {WebDriverAdapter} from './src/web_driver_adapter';
export {PerfLogFeatures, WebDriverExtension} from './src/web_driver_extension';
export {ChromeDriverExtension} from './src/webdriver/chrome_driver_extension';
export {FirefoxDriverExtension} from './src/webdriver/firefox_driver_extension';
export {IOsDriverExtension} from './src/webdriver/ios_driver_extension';

View File

@ -1,3 +0,0 @@
library benchpress.index;
//no dart implementation

View File

@ -6,9 +6,29 @@
* found in the LICENSE file at https://angular.io/license
*/
require('reflect-metadata');
require('core-js');
module.exports = require('./benchpress.js');
// when bundling benchpress to one file, this is used
// for getting exports out of browserify's scope.
(<any>global).__benchpressExports = module.exports;
// Must be imported first, because angular2 decorators throws on load.
import 'reflect-metadata';
export {Injector, OpaqueToken, Provider, ReflectiveInjector} from '@angular/core';
export {Options} from './src/common_options';
export {MeasureValues} from './src/measure_values';
export {Metric} from './src/metric';
export {MultiMetric} from './src/metric/multi_metric';
export {PerflogMetric} from './src/metric/perflog_metric';
export {UserMetric} from './src/metric/user_metric';
export {Reporter} from './src/reporter';
export {ConsoleReporter} from './src/reporter/console_reporter';
export {JsonFileReporter} from './src/reporter/json_file_reporter';
export {MultiReporter} from './src/reporter/multi_reporter';
export {Runner} from './src/runner';
export {SampleDescription} from './src/sample_description';
export {SampleState, Sampler} from './src/sampler';
export {Validator} from './src/validator';
export {RegressionSlopeValidator} from './src/validator/regression_slope_validator';
export {SizeValidator} from './src/validator/size_validator';
export {WebDriverAdapter} from './src/web_driver_adapter';
export {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from './src/web_driver_extension';
export {ChromeDriverExtension} from './src/webdriver/chrome_driver_extension';
export {FirefoxDriverExtension} from './src/webdriver/firefox_driver_extension';
export {IOsDriverExtension} from './src/webdriver/ios_driver_extension';
export {SeleniumWebDriverAdapter} from './src/webdriver/selenium_webdriver_adapter';

View File

@ -1,23 +1,33 @@
{
"name": "benchpress",
"version": "<%= packageJson.version %>",
"name": "@angular/benchpress",
"version": "0.0.0-PLACEHOLDER",
"description": "Benchpress - a framework for e2e performance tests",
"homepage": "<%= packageJson.homepage %>",
"bugs": "<%= packageJson.bugs %>",
"main" : "./index.js",
"contributors": <%= JSON.stringify(packageJson.contributors) %>,
"license": "<%= packageJson.license %>",
"repository": <%= JSON.stringify(packageJson.repository) %>,
"main": "index.js",
"typings": "index.d.ts",
"dependencies": {
"angular2": "<%= packageJson.version %>",
"core-js": "<%= packageJson.dependencies['core-js'] %>",
"reflect-metadata": "<%= packageJson.dependencies['reflect-metadata'] %>",
"rxjs": "<%= packageJson.dependencies['rxjs'] %>",
"selenium-webdriver": "<%= packageJson.dependencies['selenium-webdriver'] %>",
"zone.js": "<%= packageJson.dependencies['zone.js'] %>"
"@angular/core": "0.0.0-PLACEHOLDER",
"reflect-metadata": "^0.1.2",
"rxjs": "5.0.0-beta.11"
},
"optionalDependencies": {
"jpm": "<%= packageJson.devDependencies.jpm %>",
"firefox-profile": "<%= packageJson.devDependencies['firefox-profile'] %>"
}
"jpm": "1.1.4",
"firefox-profile": "0.4.0",
"selenium-webdriver": "3.0.0-beta-2"
},
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.git"
},
"keywords": [
"angular",
"benchmarks"
],
"contributors": [
"Tobias Bosch <tbosch@google.com> (https://angular.io/)"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/angular/angular/issues"
},
"homepage": "https://github.com/angular/angular/tree/master/modules/@angular/compiler-cli"
}

View File

@ -1,22 +0,0 @@
name: benchpress
version: <%= packageJson.version %>
authors:
<%= Object.keys(packageJson.contributors).map(function(name) {
return '- '+name+' <'+packageJson.contributors[name]+'>';
}).join('\n') %>
description: Benchpress - a framework for e2e performance tests
homepage: <%= packageJson.homepage %>
environment:
sdk: '>=1.10.0 <2.0.0'
dependencies:
angular2: '^<%= packageJson.version %>'
stack_trace: '^1.1.1'
webdriver: '^0.9.0'
dev_dependencies:
guinness2: '0.0.4'
quiver: '^0.21.4'
test: '^0.12.10'
dependency_overrides:
angular2:
path: ../angular2
matcher: '0.12.0+1'

View File

@ -6,63 +6,50 @@
* found in the LICENSE file at https://angular.io/license
*/
import {OpaqueToken} from '@angular/core/src/di';
import {DateWrapper} from '@angular/facade/src/lang';
import {OpaqueToken} from '@angular/core';
import * as fs from 'fs';
import {DateWrapper} from './facade/lang';
export class Options {
static get DEFAULT_PROVIDERS(): any[] { return _DEFAULT_PROVIDERS; }
// TODO(tbosch): use static initializer when our transpiler supports it
static get SAMPLE_ID() { return _SAMPLE_ID; }
// TODO(tbosch): use static initializer when our transpiler supports it
static get DEFAULT_DESCRIPTION() { return _DEFAULT_DESCRIPTION; }
// TODO(tbosch): use static initializer when our transpiler supports it
static get SAMPLE_DESCRIPTION() { return _SAMPLE_DESCRIPTION; }
// TODO(tbosch): use static initializer when our transpiler supports it
static get FORCE_GC() { return _FORCE_GC; }
// TODO(tbosch): use static initializer when our transpiler supports it
static get PREPARE() { return _PREPARE; }
// TODO(tbosch): use static initializer when our transpiler supports it
static get EXECUTE() { return _EXECUTE; }
// TODO(tbosch): use static initializer when our transpiler supports it
static get CAPABILITIES() { return _CAPABILITIES; }
// TODO(tbosch): use static initializer when our transpiler supports it
static get USER_AGENT() { return _USER_AGENT; }
// TODO(tbosch): use static initializer when our transpiler supports it
static get NOW() { return _NOW; }
// TODO(tbosch): use static values when our transpiler supports them
static get WRITE_FILE() { return _WRITE_FILE; }
// TODO(tbosch): use static values when our transpiler supports them
static get MICRO_METRICS() { return _MICRO_METRICS; }
// TODO(tbosch): use static values when our transpiler supports them
static get USER_METRICS() { return _USER_METRICS; }
// TODO(tbosch): use static values when our transpiler supports them
static get RECEIVED_DATA() { return _RECEIVED_DATA; }
// TODO(tbosch): use static values when our transpiler supports them
static get REQUEST_COUNT() { return _REQUEST_COUNT; }
// TODO(tbosch): use static values when our transpiler supports them
static get CAPTURE_FRAMES() { return _CAPTURE_FRAMES; }
static SAMPLE_ID = new OpaqueToken('Options.sampleId');
static DEFAULT_DESCRIPTION = new OpaqueToken('Options.defaultDescription');
static SAMPLE_DESCRIPTION = new OpaqueToken('Options.sampleDescription');
static FORCE_GC = new OpaqueToken('Options.forceGc');
static NO_PREPARE = () => true;
static PREPARE = new OpaqueToken('Options.prepare');
static EXECUTE = new OpaqueToken('Options.execute');
static CAPABILITIES = new OpaqueToken('Options.capabilities');
static USER_AGENT = new OpaqueToken('Options.userAgent');
static MICRO_METRICS = new OpaqueToken('Options.microMetrics');
static USER_METRICS = new OpaqueToken('Options.userMetrics');
static NOW = new OpaqueToken('Options.now');
static WRITE_FILE = new OpaqueToken('Options.writeFile');
static RECEIVED_DATA = new OpaqueToken('Options.receivedData');
static REQUEST_COUNT = new OpaqueToken('Options.requestCount');
static CAPTURE_FRAMES = new OpaqueToken('Options.frameCapture');
static DEFAULT_PROVIDERS = [
{provide: Options.DEFAULT_DESCRIPTION, useValue: {}},
{provide: Options.SAMPLE_DESCRIPTION, useValue: {}},
{provide: Options.FORCE_GC, useValue: false},
{provide: Options.PREPARE, useValue: Options.NO_PREPARE},
{provide: Options.MICRO_METRICS, useValue: {}}, {provide: Options.USER_METRICS, useValue: {}},
{provide: Options.NOW, useValue: () => DateWrapper.now()},
{provide: Options.RECEIVED_DATA, useValue: false},
{provide: Options.REQUEST_COUNT, useValue: false},
{provide: Options.CAPTURE_FRAMES, useValue: false},
{provide: Options.WRITE_FILE, useValue: writeFile}
];
}
var _SAMPLE_ID = new OpaqueToken('Options.sampleId');
var _DEFAULT_DESCRIPTION = new OpaqueToken('Options.defaultDescription');
var _SAMPLE_DESCRIPTION = new OpaqueToken('Options.sampleDescription');
var _FORCE_GC = new OpaqueToken('Options.forceGc');
var _PREPARE = new OpaqueToken('Options.prepare');
var _EXECUTE = new OpaqueToken('Options.execute');
var _CAPABILITIES = new OpaqueToken('Options.capabilities');
var _USER_AGENT = new OpaqueToken('Options.userAgent');
var _MICRO_METRICS = new OpaqueToken('Options.microMetrics');
var _USER_METRICS = new OpaqueToken('Options.userMetrics');
var _NOW = new OpaqueToken('Options.now');
var _WRITE_FILE = new OpaqueToken('Options.writeFile');
var _RECEIVED_DATA = new OpaqueToken('Options.receivedData');
var _REQUEST_COUNT = new OpaqueToken('Options.requestCount');
var _CAPTURE_FRAMES = new OpaqueToken('Options.frameCapture');
var _DEFAULT_PROVIDERS = [
{provide: _DEFAULT_DESCRIPTION, useValue: {}}, {provide: _SAMPLE_DESCRIPTION, useValue: {}},
{provide: _FORCE_GC, useValue: false}, {provide: _PREPARE, useValue: false},
{provide: _MICRO_METRICS, useValue: {}}, {provide: _USER_METRICS, useValue: {}},
{provide: _NOW, useValue: () => DateWrapper.now()}, {provide: _RECEIVED_DATA, useValue: false},
{provide: _REQUEST_COUNT, useValue: false}, {provide: _CAPTURE_FRAMES, useValue: false}
];
function writeFile(filename: string, content: string): Promise<any> {
return new Promise(function(resolve, reject) {
fs.writeFile(filename, content, (error) => {
if (error) {
reject(error);
} else {
resolve();
}
});
});
}

View File

@ -0,0 +1 @@
../../facade/src

View File

@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
declare var exportFunction;
declare var unsafeWindow;
declare var exportFunction: any;
declare var unsafeWindow: any;
exportFunction(function() {
var curTime = unsafeWindow.performance.now();
@ -18,7 +18,7 @@ exportFunction(function() {
(<any>self).port.emit('stopProfiler');
}, unsafeWindow, {defineAs: 'stopProfiler'});
exportFunction(function(cb) {
exportFunction(function(cb: Function) {
(<any>self).port.once('perfProfile', cb);
(<any>self).port.emit('getProfile');
}, unsafeWindow, {defineAs: 'getProfile'});
@ -27,12 +27,12 @@ exportFunction(function() {
(<any>self).port.emit('forceGC');
}, unsafeWindow, {defineAs: 'forceGC'});
exportFunction(function(name) {
exportFunction(function(name: string) {
var curTime = unsafeWindow.performance.now();
(<any>self).port.emit('markStart', name, curTime);
}, unsafeWindow, {defineAs: 'markStart'});
exportFunction(function(name) {
exportFunction(function(name: string) {
var curTime = unsafeWindow.performance.now();
(<any>self).port.emit('markEnd', name, curTime);
}, unsafeWindow, {defineAs: 'markEnd'});

View File

@ -1,3 +0,0 @@
library benchpress.src.firefox_extension.lib.main;
//no dart implementation

View File

@ -11,13 +11,13 @@ var os = Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService)
var ParserUtil = require('./parser_util');
class Profiler {
private _profiler;
private _profiler: any;
private _markerEvents: any[];
private _profilerStartTime: number;
constructor() { this._profiler = Cc['@mozilla.org/tools/profiler;1'].getService(Ci.nsIProfiler); }
start(entries, interval, features, timeStarted) {
start(entries: any, interval: any, features: any, timeStarted: any) {
this._profiler.StartProfiler(entries, interval, features, features.length);
this._profilerStartTime = timeStarted;
this._markerEvents = [];
@ -29,7 +29,9 @@ class Profiler {
var profileData = this._profiler.getProfileData();
var perfEvents = ParserUtil.convertPerfProfileToEvents(profileData);
perfEvents = this._mergeMarkerEvents(perfEvents);
perfEvents.sort(function(event1, event2) { return event1.ts - event2.ts; }); // Sort by ts
perfEvents.sort(function(event1: any, event2: any) {
return event1.ts - event2.ts;
}); // Sort by ts
return perfEvents;
}
@ -59,16 +61,18 @@ var profiler = new Profiler();
mod.PageMod({
include: ['*'],
contentScriptFile: data.url('installed_script.js'),
onAttach: worker => {
onAttach: (worker: any) => {
worker.port.on(
'startProfiler',
(timeStarted) => profiler.start(
(timeStarted: any) => profiler.start(
/* = profiler memory */ 3000000, 0.1, ['leaf', 'js', 'stackwalk', 'gc'], timeStarted));
worker.port.on('stopProfiler', () => profiler.stop());
worker.port.on(
'getProfile', () => worker.port.emit('perfProfile', profiler.getProfilePerfEvents()));
worker.port.on('forceGC', forceGC);
worker.port.on('markStart', (name, timeStarted) => profiler.addStartEvent(name, timeStarted));
worker.port.on('markEnd', (name, timeEnded) => profiler.addEndEvent(name, timeEnded));
worker.port.on(
'markStart', (name: string, timeStarted: any) => profiler.addStartEvent(name, timeStarted));
worker.port.on(
'markEnd', (name: string, timeEnded: any) => profiler.addEndEvent(name, timeEnded));
}
});

View File

@ -1,3 +0,0 @@
library benchpress.src.firefox_extension.lib.parser_util;
//no dart implementation

View File

@ -12,11 +12,11 @@
* within the perf profile.
*/
export function convertPerfProfileToEvents(perfProfile: any): any[] {
var inProgressEvents = new Map(); // map from event name to start time
var finishedEvents = []; // Event[] finished events
var addFinishedEvent = function(eventName, startTime, endTime) {
var inProgressEvents = new Map(); // map from event name to start time
var finishedEvents: {[key: string]: any}[] = []; // Event[] finished events
var addFinishedEvent = function(eventName: string, startTime: number, endTime: number) {
var categorizedEventName = categorizeEvent(eventName);
var args = undefined;
var args: {[key: string]: any} = undefined;
if (categorizedEventName == 'gc') {
// TODO: We cannot measure heap size at the moment
args = {usedHeapSize: 0};
@ -42,7 +42,9 @@ export function convertPerfProfileToEvents(perfProfile: any): any[] {
// Add all the frames into a set so it's easier/faster to find the set
// differences
var sampleFrames = new Set();
sample.frames.forEach(function(frame) { sampleFrames.add(frame.location); });
sample.frames.forEach(function(frame: {[key: string]: any}) {
sampleFrames.add(frame['location']);
});
// If an event is in the inProgressEvents map, but not in the current sample,
// then it must have just finished. We add this event to the finishedEvents
@ -73,7 +75,7 @@ export function convertPerfProfileToEvents(perfProfile: any): any[] {
});
// Remove all the unknown categories.
return finishedEvents.filter(function(event) { return event.name != 'unknown'; });
return finishedEvents.filter(function(event) { return event['name'] != 'unknown'; });
}
// TODO: this is most likely not exhaustive.

View File

@ -1,3 +0,0 @@
library benchpress.src.firefox_extension.lib.test_helper;
//no dart implementation

View File

@ -13,7 +13,7 @@ var pathUtil = require('path');
var PERF_ADDON_PACKAGE_JSON_DIR = '..';
exports.getAbsolutePath = function(path) {
exports.getAbsolutePath = function(path: string) {
var normalizedPath = pathUtil.normalize(path);
if (pathUtil.resolve(normalizedPath) == normalizedPath) {
// Already absolute path
@ -23,12 +23,12 @@ exports.getAbsolutePath = function(path) {
}
};
exports.getFirefoxProfile = function(extensionPath) {
exports.getFirefoxProfile = function(extensionPath: string) {
var deferred = q.defer();
var firefoxProfile = new FirefoxProfile();
firefoxProfile.addExtensions([extensionPath], () => {
firefoxProfile.encoded(encodedProfile => {
firefoxProfile.encoded((encodedProfile: any) => {
var multiCapabilities = [{browserName: 'firefox', firefox_profile: encodedProfile}];
deferred.resolve(multiCapabilities);
});
@ -44,7 +44,7 @@ exports.getFirefoxProfileWithExtension = function() {
var savedCwd = process.cwd();
process.chdir(absPackageJsonDir);
return jpm(packageJson).then(xpiPath => {
return jpm(packageJson).then((xpiPath: string) => {
process.chdir(savedCwd);
return exports.getFirefoxProfile(xpiPath);
});

View File

@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Map} from '@angular/facade/src/collection';
import {Date, DateWrapper} from '@angular/facade/src/lang';
import {Map} from './facade/collection';
import {Date, DateWrapper} from './facade/lang';
export class MeasureValues {
constructor(

View File

@ -11,10 +11,6 @@
* A metric is measures values
*/
export abstract class Metric {
static bindTo(delegateToken): any[] {
return [{provide: Metric, useFactory: (delegate) => delegate, deps: [delegateToken]}];
}
/**
* Starts measuring
*/
@ -31,5 +27,5 @@ export abstract class Metric {
* Describes the metrics provided by this metric implementation.
* (e.g. units, ...)
*/
describe(): {[key: string]: any} { throw new Error('NYI'); }
describe(): {[key: string]: string} { throw new Error('NYI'); }
}

View File

@ -6,20 +6,24 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injector, OpaqueToken} from '@angular/core/src/di';
import {StringMapWrapper} from '@angular/facade/src/collection';
import {Injector, OpaqueToken} from '@angular/core';
import {StringMapWrapper} from '../facade/collection';
import {Metric} from '../metric';
export class MultiMetric extends Metric {
static createBindings(childTokens: any[]): any[] {
static provideWith(childTokens: any[]): any[] {
return [
{
provide: _CHILDREN,
useFactory: (injector: Injector) => childTokens.map(token => injector.get(token)),
deps: [Injector]
},
{provide: MultiMetric, useFactory: children => new MultiMetric(children), deps: [_CHILDREN]}
{
provide: MultiMetric,
useFactory: (children: Metric[]) => new MultiMetric(children),
deps: [_CHILDREN]
}
];
}
@ -52,7 +56,7 @@ export class MultiMetric extends Metric {
}
function mergeStringMaps(maps: {[key: string]: string}[]): {[key: string]: string} {
var result = {};
var result: {[key: string]: string} = {};
maps.forEach(
map => { StringMapWrapper.forEach(map, (value, prop) => { result[prop] = value; }); });
return result;

View File

@ -6,52 +6,45 @@
* found in the LICENSE file at https://angular.io/license
*/
import {OpaqueToken} from '@angular/core/src/di';
import {ListWrapper, StringMapWrapper} from '@angular/facade/src/collection';
import {Math, NumberWrapper, StringWrapper, isBlank, isPresent} from '@angular/facade/src/lang';
import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Options} from '../common_options';
import {ListWrapper, StringMapWrapper} from '../facade/collection';
import {Math, NumberWrapper, StringWrapper, isBlank, isPresent} from '../facade/lang';
import {Metric} from '../metric';
import {PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
/**
* A metric that reads out the performance log
*/
@Injectable()
export class PerflogMetric extends Metric {
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): any[] { return _PROVIDERS; }
// TODO(tbosch): use static values when our transpiler supports them
static get SET_TIMEOUT(): OpaqueToken { return _SET_TIMEOUT; }
static SET_TIMEOUT = new OpaqueToken('PerflogMetric.setTimeout');
static PROVIDERS = [
PerflogMetric, {
provide: PerflogMetric.SET_TIMEOUT,
useValue: (fn: Function, millis: number) => <any>setTimeout(fn, millis)
}
];
/** @internal */
private _remainingEvents: Array<{[key: string]: any}>;
/** @internal */
private _remainingEvents: PerfLogEvent[];
private _measureCount: number;
/** @internal */
private _perfLogFeatures: PerfLogFeatures;
/**
* @param driverExtension
* @param setTimeout
* @param microMetrics Name and description of metrics provided via console.time / console.timeEnd
**/
constructor(
/** @internal */
private _driverExtension: WebDriverExtension,
/** @internal */
private _setTimeout: Function,
/** @internal */
private _microMetrics: {[key: string]: any},
/** @internal */
private _forceGc: boolean,
/** @internal */
private _captureFrames: boolean,
/** @internal */
private _receivedData: boolean,
/** @internal */
private _requestCount: boolean) {
@Inject(PerflogMetric.SET_TIMEOUT) private _setTimeout: Function,
@Inject(Options.MICRO_METRICS) private _microMetrics: {[key: string]: string},
@Inject(Options.FORCE_GC) private _forceGc: boolean,
@Inject(Options.CAPTURE_FRAMES) private _captureFrames: boolean,
@Inject(Options.RECEIVED_DATA) private _receivedData: boolean,
@Inject(Options.REQUEST_COUNT) private _requestCount: boolean) {
super();
this._remainingEvents = [];
@ -64,8 +57,8 @@ export class PerflogMetric extends Metric {
}
}
describe(): {[key: string]: any} {
var res = {
describe(): {[key: string]: string} {
var res: {[key: string]: any} = {
'scriptTime': 'script execution time in ms, including gc and render',
'pureScriptTime': 'script execution time in ms, without gc nor render'
};
@ -115,7 +108,7 @@ export class PerflogMetric extends Metric {
return resultPromise.then((_) => this._beginMeasure());
}
endMeasure(restart: boolean): Promise<{[key: string]: any}> {
endMeasure(restart: boolean): Promise<{[key: string]: number}> {
if (this._forceGc) {
return this._endPlainMeasureAndMeasureForceGc(restart);
} else {
@ -140,21 +133,19 @@ export class PerflogMetric extends Metric {
});
}
/** @internal */
private _beginMeasure(): Promise<any> {
return this._driverExtension.timeBegin(this._markName(this._measureCount++));
}
/** @internal */
private _endMeasure(restart: boolean): Promise<{[key: string]: any}> {
private _endMeasure(restart: boolean): Promise<{[key: string]: number}> {
var markName = this._markName(this._measureCount - 1);
var nextMarkName = restart ? this._markName(this._measureCount++) : null;
return this._driverExtension.timeEnd(markName, nextMarkName)
.then((_) => this._readUntilEndMark(markName));
}
/** @internal */
private _readUntilEndMark(markName: string, loopCount: number = 0, startEvent = null) {
private _readUntilEndMark(
markName: string, loopCount: number = 0, startEvent: PerfLogEvent = null) {
if (loopCount > _MAX_RETRY_COUNT) {
throw new Error(`Tried too often to get the ending mark: ${loopCount}`);
}
@ -172,17 +163,16 @@ export class PerflogMetric extends Metric {
});
}
/** @internal */
private _addEvents(events: {[key: string]: string}[]) {
private _addEvents(events: PerfLogEvent[]) {
var needSort = false;
events.forEach(event => {
if (StringWrapper.equals(event['ph'], 'X')) {
needSort = true;
var startEvent = {};
var endEvent = {};
var startEvent: PerfLogEvent = {};
var endEvent: PerfLogEvent = {};
StringMapWrapper.forEach(event, (value, prop) => {
startEvent[prop] = value;
endEvent[prop] = value;
(<any>startEvent)[prop] = value;
(<any>endEvent)[prop] = value;
});
startEvent['ph'] = 'B';
endEvent['ph'] = 'E';
@ -202,9 +192,8 @@ export class PerflogMetric extends Metric {
}
}
/** @internal */
private _aggregateEvents(events: Array<{[key: string]: any}>, markName): {[key: string]: any} {
var result = {'scriptTime': 0, 'pureScriptTime': 0};
private _aggregateEvents(events: PerfLogEvent[], markName: string): {[key: string]: number} {
var result: {[key: string]: number} = {'scriptTime': 0, 'pureScriptTime': 0};
if (this._perfLogFeatures.gc) {
result['gcTime'] = 0;
result['majorGcTime'] = 0;
@ -227,17 +216,17 @@ export class PerflogMetric extends Metric {
result['requestCount'] = 0;
}
var markStartEvent = null;
var markEndEvent = null;
var markStartEvent: PerfLogEvent = null;
var markEndEvent: PerfLogEvent = null;
var gcTimeInScript = 0;
var renderTimeInScript = 0;
var frameTimestamps = [];
var frameTimes = [];
var frameCaptureStartEvent = null;
var frameCaptureEndEvent = null;
var frameTimestamps: number[] = [];
var frameTimes: number[] = [];
var frameCaptureStartEvent: PerfLogEvent = null;
var frameCaptureEndEvent: PerfLogEvent = null;
var intervalStarts: {[key: string]: any} = {};
var intervalStarts: {[key: string]: PerfLogEvent} = {};
var intervalStartCount: {[key: string]: number} = {};
events.forEach((event) => {
var ph = event['ph'];
@ -337,7 +326,7 @@ export class PerflogMetric extends Metric {
} else if (StringWrapper.equals(name, 'script')) {
result['scriptTime'] += duration;
} else if (isPresent(this._microMetrics[name])) {
result[name] += duration / microIterations;
(<any>result)[name] += duration / microIterations;
}
}
}
@ -362,8 +351,7 @@ export class PerflogMetric extends Metric {
return result;
}
/** @internal */
private _addFrameMetrics(result: {[key: string]: any}, frameTimes: any[]) {
private _addFrameMetrics(result: {[key: string]: number}, frameTimes: any[]) {
result['frameTime.mean'] = frameTimes.reduce((a, b) => a + b, 0) / frameTimes.length;
var firstFrame = frameTimes[0];
result['frameTime.worst'] = frameTimes.reduce((a, b) => a > b ? a : b, firstFrame);
@ -372,32 +360,14 @@ export class PerflogMetric extends Metric {
frameTimes.filter(t => t < _FRAME_TIME_SMOOTH_THRESHOLD).length / frameTimes.length;
}
/** @internal */
private _markName(index) { return `${_MARK_NAME_PREFIX}${index}`; }
private _markName(index: number) { return `${_MARK_NAME_PREFIX}${index}`; }
}
var _MICRO_ITERATIONS_REGEX = /(.+)\*(\d+)$/;
var _MAX_RETRY_COUNT = 20;
var _MARK_NAME_PREFIX = 'benchpress';
var _SET_TIMEOUT = new OpaqueToken('PerflogMetric.setTimeout');
var _MARK_NAME_FRAME_CAPUTRE = 'frameCapture';
// using 17ms as a somewhat looser threshold, instead of 16.6666ms
var _FRAME_TIME_SMOOTH_THRESHOLD = 17;
var _PROVIDERS = [
{
provide: PerflogMetric,
useFactory: (driverExtension, setTimeout, microMetrics, forceGc, captureFrames, receivedData,
requestCount) =>
new PerflogMetric(
driverExtension, setTimeout, microMetrics, forceGc, captureFrames,
receivedData, requestCount),
deps: [
WebDriverExtension, _SET_TIMEOUT, Options.MICRO_METRICS, Options.FORCE_GC,
Options.CAPTURE_FRAMES, Options.RECEIVED_DATA, Options.REQUEST_COUNT
]
},
{provide: _SET_TIMEOUT, useValue: (fn, millis) => <any>setTimeout(fn, millis)}
];

View File

@ -6,19 +6,21 @@
* found in the LICENSE file at https://angular.io/license
*/
import {OpaqueToken, Provider} from '@angular/core';
import {StringMapWrapper} from '@angular/facade/src/collection';
import {isNumber} from '@angular/facade/src/lang';
import {Inject, Injectable, OpaqueToken, Provider} from '@angular/core';
import {Options} from '../common_options';
import {StringMapWrapper} from '../facade/collection';
import {isNumber} from '../facade/lang';
import {Metric} from '../metric';
import {WebDriverAdapter} from '../web_driver_adapter';
@Injectable()
export class UserMetric extends Metric {
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): Provider[] { return _PROVIDERS; }
static PROVIDERS = [UserMetric];
constructor(private _userMetrics: {[key: string]: string}, private _wdAdapter: WebDriverAdapter) {
constructor(
@Inject(Options.USER_METRICS) private _userMetrics: {[key: string]: string},
private _wdAdapter: WebDriverAdapter) {
super();
}
@ -67,9 +69,3 @@ export class UserMetric extends Metric {
*/
describe(): {[key: string]: any} { return this._userMetrics; }
}
var _PROVIDERS: Provider[] = [{
provide: UserMetric,
useFactory: (userMetrics, wdAdapter) => new UserMetric(userMetrics, wdAdapter),
deps: [Options.USER_METRICS, WebDriverAdapter]
}];

View File

@ -12,10 +12,6 @@ import {MeasureValues} from './measure_values';
* A reporter reports measure values and the valid sample.
*/
export abstract class Reporter {
static bindTo(delegateToken): any[] {
return [{provide: Reporter, useFactory: (delegate) => delegate, deps: [delegateToken]}];
}
reportMeasureValues(values: MeasureValues): Promise<any> { throw new Error('NYI'); }
reportSample(completeSample: MeasureValues[], validSample: MeasureValues[]): Promise<any> {

View File

@ -6,11 +6,11 @@
* found in the LICENSE file at https://angular.io/license
*/
import {OpaqueToken} from '@angular/core/src/di';
import {ListWrapper, StringMapWrapper} from '@angular/facade/src/collection';
import {NumberWrapper, isBlank, isPresent, print} from '@angular/facade/src/lang';
import {Math} from '@angular/facade/src/math';
import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {ListWrapper, StringMapWrapper} from '../facade/collection';
import {NumberWrapper, isBlank, isPresent, print} from '../facade/lang';
import {Math} from '../facade/math';
import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter';
import {SampleDescription} from '../sample_description';
@ -20,17 +20,16 @@ import {Statistic} from '../statistic';
/**
* A reporter for the console
*/
@Injectable()
export class ConsoleReporter extends Reporter {
// TODO(tbosch): use static values when our transpiler supports them
static get PRINT(): OpaqueToken { return _PRINT; }
// TODO(tbosch): use static values when our transpiler supports them
static get COLUMN_WIDTH(): OpaqueToken { return _COLUMN_WIDTH; }
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): any[] { return _PROVIDERS; }
static PRINT = new OpaqueToken('ConsoleReporter.print');
static COLUMN_WIDTH = new OpaqueToken('ConsoleReporter.columnWidth');
static PROVIDERS = [
ConsoleReporter, {provide: ConsoleReporter.COLUMN_WIDTH, useValue: 18},
{provide: ConsoleReporter.PRINT, useValue: print}
];
/** @internal */
private static _lpad(value, columnWidth, fill = ' ') {
private static _lpad(value: string, columnWidth: number, fill = ' ') {
var result = '';
for (var i = 0; i < columnWidth - value.length; i++) {
result += fill;
@ -38,28 +37,27 @@ export class ConsoleReporter extends Reporter {
return result + value;
}
/** @internal */
private static _formatNum(n) { return NumberWrapper.toFixed(n, 2); }
private static _formatNum(n: number) { return NumberWrapper.toFixed(n, 2); }
/** @internal */
private static _sortedProps(obj) {
var props = [];
private static _sortedProps(obj: {[key: string]: any}) {
var props: string[] = [];
StringMapWrapper.forEach(obj, (value, prop) => props.push(prop));
props.sort();
return props;
}
/** @internal */
private _metricNames: string[];
constructor(private _columnWidth: number, sampleDescription, private _print: Function) {
constructor(
@Inject(ConsoleReporter.COLUMN_WIDTH) private _columnWidth: number,
sampleDescription: SampleDescription,
@Inject(ConsoleReporter.PRINT) private _print: Function) {
super();
this._metricNames = ConsoleReporter._sortedProps(sampleDescription.metrics);
this._printDescription(sampleDescription);
}
/** @internal */
private _printDescription(sampleDescription) {
private _printDescription(sampleDescription: SampleDescription) {
this._print(`BENCHMARK ${sampleDescription.id}`);
this._print('Description:');
var props = ConsoleReporter._sortedProps(sampleDescription.description);
@ -96,21 +94,8 @@ export class ConsoleReporter extends Reporter {
return Promise.resolve(null);
}
/** @internal */
private _printStringRow(parts: any[], fill = ' ') {
this._print(
parts.map(part => ConsoleReporter._lpad(part, this._columnWidth, fill)).join(' | '));
}
}
var _PRINT = new OpaqueToken('ConsoleReporter.print');
var _COLUMN_WIDTH = new OpaqueToken('ConsoleReporter.columnWidth');
var _PROVIDERS = [
{
provide: ConsoleReporter,
useFactory: (columnWidth, sampleDescription, print) =>
new ConsoleReporter(columnWidth, sampleDescription, print),
deps: [_COLUMN_WIDTH, SampleDescription, _PRINT]
},
{provide: _COLUMN_WIDTH, useValue: 18}, {provide: _PRINT, useValue: print}
];

View File

@ -6,39 +6,29 @@
* found in the LICENSE file at https://angular.io/license
*/
import {OpaqueToken} from '@angular/core/src/di';
import {DateWrapper, Json, isBlank, isPresent} from '@angular/facade/src/lang';
import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Options} from '../common_options';
import {DateWrapper, Json, isBlank, isPresent} from '../facade/lang';
import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter';
import {SampleDescription} from '../sample_description';
/**
* A reporter that writes results into a json file.
*/
@Injectable()
export class JsonFileReporter extends Reporter {
// TODO(tbosch): use static values when our transpiler supports them
static get PATH(): OpaqueToken { return _PATH; }
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): any[] { return _PROVIDERS; }
static PATH = new OpaqueToken('JsonFileReporter.path');
static PROVIDERS = [JsonFileReporter, {provide: JsonFileReporter.PATH, useValue: '.'}];
/** @internal */
private _writeFile: Function;
/** @internal */
private _path: string;
/** @internal */
private _description: SampleDescription;
/** @internal */
private _now: Function;
constructor(sampleDescription, path, writeFile, now) {
constructor(
private _description: SampleDescription, @Inject(JsonFileReporter.PATH) private _path: string,
@Inject(Options.WRITE_FILE) private _writeFile: Function,
@Inject(Options.NOW) private _now: Function) {
super();
this._description = sampleDescription;
this._path = path;
this._writeFile = writeFile;
this._now = now;
}
reportMeasureValues(measureValues: MeasureValues): Promise<any> { return Promise.resolve(null); }
@ -54,14 +44,3 @@ export class JsonFileReporter extends Reporter {
return this._writeFile(filePath, content);
}
}
var _PATH = new OpaqueToken('JsonFileReporter.path');
var _PROVIDERS = [
{
provide: JsonFileReporter,
useFactory: (sampleDescription, path, writeFile, now) =>
new JsonFileReporter(sampleDescription, path, writeFile, now),
deps: [SampleDescription, _PATH, Options.WRITE_FILE, Options.NOW]
},
{provide: _PATH, useValue: '.'}
];

View File

@ -6,13 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injector, OpaqueToken} from '@angular/core/src/di';
import {Injector, OpaqueToken} from '@angular/core';
import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter';
export class MultiReporter extends Reporter {
static createBindings(childTokens: any[]): any[] {
static provideWith(childTokens: any[]): any[] {
return [
{
provide: _CHILDREN,
@ -21,19 +21,13 @@ export class MultiReporter extends Reporter {
},
{
provide: MultiReporter,
useFactory: children => new MultiReporter(children),
useFactory: (children: Reporter[]) => new MultiReporter(children),
deps: [_CHILDREN]
}
];
}
/** @internal */
private _reporters: Reporter[];
constructor(reporters) {
super();
this._reporters = reporters;
}
constructor(private _reporters: Reporter[]) { super(); }
reportMeasureValues(values: MeasureValues): Promise<any[]> {
return Promise.all(this._reporters.map(reporter => reporter.reportMeasureValues(values)));

View File

@ -7,9 +7,9 @@
*/
import {Provider, ReflectiveInjector} from '@angular/core';
import {isBlank, isPresent} from '@angular/facade/src/lang';
import {Options} from './common_options';
import {isBlank, isPresent} from './facade/lang';
import {Metric} from './metric';
import {MultiMetric} from './metric/multi_metric';
import {PerflogMetric} from './metric/perflog_metric';
@ -29,28 +29,23 @@ import {FirefoxDriverExtension} from './webdriver/firefox_driver_extension';
import {IOsDriverExtension} from './webdriver/ios_driver_extension';
/**
* The Runner is the main entry point for executing a sample run.
* It provides defaults, creates the injector and calls the sampler.
*/
export class Runner {
private _defaultProviders: Provider[];
constructor(defaultProviders: Provider[] = null) {
if (isBlank(defaultProviders)) {
defaultProviders = [];
}
this._defaultProviders = defaultProviders;
}
constructor(private _defaultProviders: Provider[] = []) {}
sample({id, execute, prepare, microMetrics, providers, userMetrics}: {
id: string,
execute?: any,
prepare?: any,
microMetrics?: any,
providers?: any,
userMetrics?: any
execute?: Function,
prepare?: Function,
microMetrics?: {[key: string]: string},
providers?: Provider[],
userMetrics?: {[key: string]: string}
}): Promise<SampleState> {
var sampleProviders = [
var sampleProviders: Provider[] = [
_DEFAULT_PROVIDERS, this._defaultProviders, {provide: Options.SAMPLE_ID, useValue: id},
{provide: Options.EXECUTE, useValue: execute}
];
@ -105,10 +100,11 @@ var _DEFAULT_PROVIDERS = [
PerflogMetric.PROVIDERS,
UserMetric.PROVIDERS,
SampleDescription.PROVIDERS,
MultiReporter.createBindings([ConsoleReporter]),
MultiMetric.createBindings([PerflogMetric, UserMetric]),
Reporter.bindTo(MultiReporter),
Validator.bindTo(RegressionSlopeValidator),
WebDriverExtension.bindTo([ChromeDriverExtension, FirefoxDriverExtension, IOsDriverExtension]),
Metric.bindTo(MultiMetric),
MultiReporter.provideWith([ConsoleReporter]),
MultiMetric.provideWith([PerflogMetric, UserMetric]),
{provide: Reporter, useExisting: MultiReporter},
{provide: Validator, useExisting: RegressionSlopeValidator},
WebDriverExtension.provideFirstSupported(
[ChromeDriverExtension, FirefoxDriverExtension, IOsDriverExtension]),
{provide: Metric, useExisting: MultiMetric},
];

View File

@ -6,9 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {StringMapWrapper} from '@angular/facade/src/collection';
import {OpaqueToken} from '@angular/core';
import {Options} from './common_options';
import {StringMapWrapper} from './facade/collection';
import {Metric} from './metric';
import {Validator} from './validator';
@ -17,8 +18,23 @@ import {Validator} from './validator';
* SampleDescription merges all available descriptions about a sample
*/
export class SampleDescription {
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): any[] { return _PROVIDERS; }
static PROVIDERS = [{
provide: SampleDescription,
useFactory:
(metric: Metric, id: string, forceGc: boolean, userAgent: string, validator: Validator,
defaultDesc: {[key: string]: string}, userDesc: {[key: string]: string}) =>
new SampleDescription(
id,
[
{'forceGc': forceGc, 'userAgent': userAgent}, validator.describe(), defaultDesc,
userDesc
],
metric.describe()),
deps: [
Metric, Options.SAMPLE_ID, Options.FORCE_GC, Options.USER_AGENT, Validator,
Options.DEFAULT_DESCRIPTION, Options.SAMPLE_DESCRIPTION
]
}];
description: {[key: string]: any};
constructor(
@ -32,19 +48,3 @@ export class SampleDescription {
toJson() { return {'id': this.id, 'description': this.description, 'metrics': this.metrics}; }
}
var _PROVIDERS = [{
provide: SampleDescription,
useFactory: (metric, id, forceGc, userAgent, validator, defaultDesc, userDesc) =>
new SampleDescription(
id,
[
{'forceGc': forceGc, 'userAgent': userAgent}, validator.describe(),
defaultDesc, userDesc
],
metric.describe()),
deps: [
Metric, Options.SAMPLE_ID, Options.FORCE_GC, Options.USER_AGENT, Validator,
Options.DEFAULT_DESCRIPTION, Options.SAMPLE_DESCRIPTION
]
}];

View File

@ -6,9 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Date, DateWrapper, isBlank, isPresent} from '@angular/facade/src/lang';
import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Options} from './common_options';
import {Date, DateWrapper, isBlank, isPresent} from './facade/lang';
import {MeasureValues} from './measure_values';
import {Metric} from './metric';
import {Reporter} from './reporter';
@ -24,46 +25,18 @@ import {WebDriverAdapter} from './web_driver_adapter';
* 4. reports the new data to the reporter
* 5. loop until there is a valid sample
*/
@Injectable()
export class Sampler {
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): any[] { return _PROVIDERS; }
static PROVIDERS = [Sampler];
/** @internal */
private _driver: WebDriverAdapter;
/** @internal */
private _metric: Metric;
/** @internal */
private _reporter: Reporter;
/** @internal */
private _validator: Validator;
/** @internal */
private _prepare: Function;
/** @internal */
private _execute: Function;
/** @internal */
private _now: Function;
constructor({driver, metric, reporter, validator, prepare, execute, now}: {
driver?: WebDriverAdapter,
metric?: Metric,
reporter?: Reporter,
validator?: Validator,
prepare?: Function,
execute?: Function,
now?: Function
} = {}) {
this._driver = driver;
this._metric = metric;
this._reporter = reporter;
this._validator = validator;
this._prepare = prepare;
this._execute = execute;
this._now = now;
}
constructor(
private _driver: WebDriverAdapter, private _metric: Metric, private _reporter: Reporter,
private _validator: Validator, @Inject(Options.PREPARE) private _prepare: Function,
@Inject(Options.EXECUTE) private _execute: Function,
@Inject(Options.NOW) private _now: Function) {}
sample(): Promise<SampleState> {
var loop;
loop = (lastState) => {
const loop = (lastState: SampleState): Promise<SampleState> => {
return this._iterate(lastState).then((newState) => {
if (isPresent(newState.validSample)) {
return newState;
@ -75,23 +48,21 @@ export class Sampler {
return loop(new SampleState([], null));
}
/** @internal */
private _iterate(lastState): Promise<SampleState> {
private _iterate(lastState: SampleState): Promise<SampleState> {
var resultPromise: Promise<any>;
if (isPresent(this._prepare)) {
if (this._prepare !== Options.NO_PREPARE) {
resultPromise = this._driver.waitFor(this._prepare);
} else {
resultPromise = Promise.resolve(null);
}
if (isPresent(this._prepare) || lastState.completeSample.length === 0) {
if (this._prepare !== Options.NO_PREPARE || lastState.completeSample.length === 0) {
resultPromise = resultPromise.then((_) => this._metric.beginMeasure());
}
return resultPromise.then((_) => this._driver.waitFor(this._execute))
.then((_) => this._metric.endMeasure(isBlank(this._prepare)))
.then((_) => this._metric.endMeasure(this._prepare === Options.NO_PREPARE))
.then((measureValues) => this._report(lastState, measureValues));
}
/** @internal */
private _report(state: SampleState, metricValues: {[key: string]: any}): Promise<SampleState> {
var measureValues = new MeasureValues(state.completeSample.length, this._now(), metricValues);
var completeSample = state.completeSample.concat([measureValues]);
@ -108,22 +79,3 @@ export class Sampler {
export class SampleState {
constructor(public completeSample: any[], public validSample: any[]) {}
}
var _PROVIDERS = [{
provide: Sampler,
useFactory: (driver, metric, reporter, validator, prepare, execute, now) => new Sampler({
driver: driver,
reporter: reporter,
validator: validator,
metric: metric,
// TODO(tbosch): DI right now does not support null/undefined objects
// Mostly because the cache would have to be initialized with a
// special null object, which is expensive.
prepare: prepare !== false ? prepare : null,
execute: execute,
now: now
}),
deps: [
WebDriverAdapter, Metric, Reporter, Validator, Options.PREPARE, Options.EXECUTE, Options.NOW
]
}];

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Math} from '@angular/facade/src/math';
import {Math} from './facade/math';
export class Statistic {
static calculateCoefficientOfVariation(sample, mean) {
static calculateCoefficientOfVariation(sample: number[], mean: number) {
return Statistic.calculateStandardDeviation(sample, mean) / mean * 100;
}
@ -20,7 +20,7 @@ export class Statistic {
return total / samples.length;
}
static calculateStandardDeviation(samples: number[], mean) {
static calculateStandardDeviation(samples: number[], mean: number) {
var deviation = 0;
// TODO: use reduce
samples.forEach(x => deviation += Math.pow(x - mean, 2));

View File

@ -14,10 +14,6 @@ import {MeasureValues} from './measure_values';
* in the correct way.
*/
export abstract class Validator {
static bindTo(delegateToken): any[] {
return [{provide: Validator, useFactory: (delegate) => delegate, deps: [delegateToken]}];
}
/**
* Calculates a valid sample out of the complete sample
*/

View File

@ -6,35 +6,32 @@
* found in the LICENSE file at https://angular.io/license
*/
import {OpaqueToken} from '@angular/core/src/di';
import {ListWrapper} from '@angular/facade/src/collection';
import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {ListWrapper} from '../facade/collection';
import {MeasureValues} from '../measure_values';
import {Statistic} from '../statistic';
import {Validator} from '../validator';
/**
* A validator that checks the regression slope of a specific metric.
* Waits for the regression slope to be >=0.
*/
@Injectable()
export class RegressionSlopeValidator extends Validator {
// TODO(tbosch): use static values when our transpiler supports them
static get SAMPLE_SIZE(): OpaqueToken { return _SAMPLE_SIZE; }
// TODO(tbosch): use static values when our transpiler supports them
static get METRIC(): OpaqueToken { return _METRIC; }
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): any[] { return _PROVIDERS; }
static SAMPLE_SIZE = new OpaqueToken('RegressionSlopeValidator.sampleSize');
static METRIC = new OpaqueToken('RegressionSlopeValidator.metric');
static PROVIDERS = [
RegressionSlopeValidator, {provide: RegressionSlopeValidator.SAMPLE_SIZE, useValue: 10},
{provide: RegressionSlopeValidator.METRIC, useValue: 'scriptTime'}
];
/** @internal */
private _sampleSize: number;
/** @internal */
private _metric: string;
constructor(sampleSize, metric) {
constructor(
@Inject(RegressionSlopeValidator.SAMPLE_SIZE) private _sampleSize: number,
@Inject(RegressionSlopeValidator.METRIC) private _metric: string) {
super();
this._sampleSize = sampleSize;
this._metric = metric;
}
describe(): {[key: string]: any} {
@ -45,8 +42,8 @@ export class RegressionSlopeValidator extends Validator {
if (completeSample.length >= this._sampleSize) {
var latestSample = ListWrapper.slice(
completeSample, completeSample.length - this._sampleSize, completeSample.length);
var xValues = [];
var yValues = [];
var xValues: number[] = [];
var yValues: number[] = [];
for (var i = 0; i < latestSample.length; i++) {
// For now, we only use the array index as x value.
// TODO(tbosch): think about whether we should use time here instead
@ -61,14 +58,3 @@ export class RegressionSlopeValidator extends Validator {
}
}
}
var _SAMPLE_SIZE = new OpaqueToken('RegressionSlopeValidator.sampleSize');
var _METRIC = new OpaqueToken('RegressionSlopeValidator.metric');
var _PROVIDERS = [
{
provide: RegressionSlopeValidator,
useFactory: (sampleSize, metric) => new RegressionSlopeValidator(sampleSize, metric),
deps: [_SAMPLE_SIZE, _METRIC]
},
{provide: _SAMPLE_SIZE, useValue: 10}, {provide: _METRIC, useValue: 'scriptTime'}
];

View File

@ -6,29 +6,23 @@
* found in the LICENSE file at https://angular.io/license
*/
import {OpaqueToken} from '@angular/core/src/di';
import {ListWrapper} from '@angular/facade/src/collection';
import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {ListWrapper} from '../facade/collection';
import {MeasureValues} from '../measure_values';
import {Validator} from '../validator';
/**
* A validator that waits for the sample to have a certain size.
*/
@Injectable()
export class SizeValidator extends Validator {
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): any[] { return _PROVIDERS; }
// TODO(tbosch): use static values when our transpiler supports them
static get SAMPLE_SIZE() { return _SAMPLE_SIZE; }
static SAMPLE_SIZE = new OpaqueToken('SizeValidator.sampleSize');
static PROVIDERS = [SizeValidator, {provide: SizeValidator.SAMPLE_SIZE, useValue: 10}];
/** @internal */
private _sampleSize: number;
constructor(size) {
super();
this._sampleSize = size;
}
constructor(@Inject(SizeValidator.SAMPLE_SIZE) private _sampleSize: number) { super(); }
describe(): {[key: string]: any} { return {'sampleSize': this._sampleSize}; }
@ -41,9 +35,3 @@ export class SizeValidator extends Validator {
}
}
}
var _SAMPLE_SIZE = new OpaqueToken('SizeValidator.sampleSize');
var _PROVIDERS = [
{provide: SizeValidator, useFactory: (size) => new SizeValidator(size), deps: [_SAMPLE_SIZE]},
{provide: _SAMPLE_SIZE, useValue: 10}
];

View File

@ -14,10 +14,6 @@
* Needs one implementation for every supported WebDriver client.
*/
export abstract class WebDriverAdapter {
static bindTo(delegateToken): any[] {
return [{provide: WebDriverAdapter, useFactory: (delegate) => delegate, deps: [delegateToken]}];
}
waitFor(callback: Function): Promise<any> { throw new Error('NYI'); }
executeScript(script: string): Promise<any> { throw new Error('NYI'); }
executeAsyncScript(script: string): Promise<any> { throw new Error('NYI'); }

View File

@ -6,11 +6,20 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injector, OpaqueToken} from '@angular/core/src/di';
import {isBlank, isPresent} from '@angular/facade/src/lang';
import {Injector, OpaqueToken} from '@angular/core';
import {Options} from './common_options';
import {isBlank, isPresent} from './facade/lang';
export type PerfLogEvent = {
cat?: string,
ph?: 'X' | 'B' | 'E' | 'b' | 'e',
ts?: number,
dur?: number,
name?: string,
pid?: string,
args?: {encodedDataLength?: number, usedHeapSize?: number, majorGc?: number}
};
/**
* A WebDriverExtension implements extended commands of the webdriver protocol
@ -18,7 +27,7 @@ import {Options} from './common_options';
* Needs one implementation for every supported Browser.
*/
export abstract class WebDriverExtension {
static bindTo(childTokens: any[]): any[] {
static provideFirstSupported(childTokens: any[]): any[] {
var res = [
{
provide: _CHILDREN,
@ -27,8 +36,8 @@ export abstract class WebDriverExtension {
},
{
provide: WebDriverExtension,
useFactory: (children: WebDriverExtension[], capabilities) => {
var delegate;
useFactory: (children: WebDriverExtension[], capabilities: any) => {
var delegate: WebDriverExtension;
children.forEach(extension => {
if (extension.supports(capabilities)) {
delegate = extension;
@ -64,7 +73,7 @@ export abstract class WebDriverExtension {
* Based on [Chrome Trace Event
*Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit)
**/
readPerfLog(): Promise<any[]> { throw new Error('NYI'); }
readPerfLog(): Promise<PerfLogEvent[]> { throw new Error('NYI'); }
perfLogFeatures(): PerfLogFeatures { throw new Error('NYI'); }

View File

@ -1,35 +0,0 @@
library benchpress.src.webdriver.async_webdriver_adapter_dart;
import 'dart:async';
import 'package:webdriver/webdriver.dart' show WebDriver, LogEntry;
import '../web_driver_adapter.dart' show WebDriverAdapter;
class AsyncWebDriverAdapter extends WebDriverAdapter {
WebDriver _driver;
AsyncWebDriverAdapter(this._driver);
Future waitFor(Function callback) {
return callback();
}
Future executeScript(String script) {
return _driver.execute(script, const []);
}
Future executeAsyncScript(String script) {
return _driver.executeAsync(script, const []);
}
Future<Map> capabilities() {
return new Future.value(_driver.capabilities);
}
Future<List<Map>> logs(String type) {
return _driver.logs
.get(type)
.map((LogEntry entry) => {'message': entry.message})
.fold(<Map>[], (log, Map entry) {
return log..add(entry);
});
}
}

View File

@ -6,12 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ListWrapper, StringMapWrapper} from '@angular/facade/src/collection';
import {Json, NumberWrapper, StringWrapper, isBlank, isPresent} from '@angular/facade/src/lang';
import {Inject, Injectable} from '@angular/core';
import {Options} from '../common_options';
import {ListWrapper, StringMapWrapper} from '../facade/collection';
import {NumberWrapper, StringWrapper, isBlank, isPresent} from '../facade/lang';
import {WebDriverAdapter} from '../web_driver_adapter';
import {PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
/**
@ -21,13 +23,13 @@ import {PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
* In order to collect the frame rate related metrics, add 'benchmark'
* to the list above.
*/
@Injectable()
export class ChromeDriverExtension extends WebDriverExtension {
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): any[] { return _PROVIDERS; }
static PROVIDERS = [ChromeDriverExtension];
private _majorChromeVersion: number;
constructor(private _driver: WebDriverAdapter, userAgent: string) {
constructor(private _driver: WebDriverAdapter, @Inject(Options.USER_AGENT) userAgent: string) {
super();
this._majorChromeVersion = this._parseChromeVersion(userAgent);
}
@ -63,15 +65,15 @@ export class ChromeDriverExtension extends WebDriverExtension {
// See [Chrome Trace Event
// Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit)
readPerfLog(): Promise<any> {
readPerfLog(): Promise<PerfLogEvent[]> {
// TODO(tbosch): Chromedriver bug https://code.google.com/p/chromedriver/issues/detail?id=1098
// Need to execute at least one command so that the browser logs can be read out!
return this._driver.executeScript('1+1')
.then((_) => this._driver.logs('performance'))
.then((entries) => {
var events = [];
var events: PerfLogEvent[] = [];
entries.forEach(entry => {
var message = Json.parse(entry['message'])['message'];
var message = JSON.parse(entry['message'])['message'];
if (StringWrapper.equals(message['method'], 'Tracing.dataCollected')) {
events.push(message['params']);
}
@ -84,8 +86,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
}
private _convertPerfRecordsToEvents(
chromeEvents: Array<{[key: string]: any}>,
normalizedEvents: Array<{[key: string]: any}> = null) {
chromeEvents: Array<{[key: string]: any}>, normalizedEvents: PerfLogEvent[] = null) {
if (isBlank(normalizedEvents)) {
normalizedEvents = [];
}
@ -128,7 +129,8 @@ export class ChromeDriverExtension extends WebDriverExtension {
return normalizedEvents;
}
private _processAsPreChrome45Event(event, categories, majorGCPids) {
private _processAsPreChrome45Event(
event: {[key: string]: any}, categories: string[], majorGCPids: {[key: string]: any}) {
var name = event['name'];
var args = event['args'];
var pid = event['pid'];
@ -148,7 +150,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
return normalizeEvent(event, {'name': 'render'});
} else if (this._isEvent(
categories, name, ['disabled-by-default-devtools.timeline'], 'GCEvent')) {
var normArgs = {
var normArgs: {[key: string]: any} = {
'usedHeapSize': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] :
args['usedHeapSizeBefore']
};
@ -164,7 +166,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
return null; // nothing useful in this event
}
private _processAsPostChrome44Event(event, categories) {
private _processAsPostChrome44Event(event: {[key: string]: any}, categories: string[]) {
var name = event['name'];
var args = event['args'];
if (this._isEvent(categories, name, ['devtools.timeline', 'v8'], 'MajorGC')) {
@ -230,14 +232,14 @@ export class ChromeDriverExtension extends WebDriverExtension {
}
function normalizeEvent(
chromeEvent: {[key: string]: any}, data: {[key: string]: any}): {[key: string]: any} {
chromeEvent: {[key: string]: any}, data: {[key: string]: any}): PerfLogEvent {
var ph = chromeEvent['ph'];
if (StringWrapper.equals(ph, 'S')) {
ph = 'b';
} else if (StringWrapper.equals(ph, 'F')) {
ph = 'e';
}
var result =
var result: {[key: string]: any} =
{'pid': chromeEvent['pid'], 'ph': ph, 'cat': 'timeline', 'ts': chromeEvent['ts'] / 1000};
if (chromeEvent['ph'] === 'X') {
var dur = chromeEvent['dur'];
@ -249,9 +251,3 @@ function normalizeEvent(
StringMapWrapper.forEach(data, (value, prop) => { result[prop] = value; });
return result;
}
var _PROVIDERS = [{
provide: ChromeDriverExtension,
useFactory: (driver, userAgent) => new ChromeDriverExtension(driver, userAgent),
deps: [WebDriverAdapter, Options.USER_AGENT]
}];

View File

@ -6,13 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
import {StringWrapper, isPresent} from '@angular/facade/src/lang';
import {Injectable} from '@angular/core';
import {StringWrapper, isPresent} from '../facade/lang';
import {WebDriverAdapter} from '../web_driver_adapter';
import {PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
@Injectable()
export class FirefoxDriverExtension extends WebDriverExtension {
static get PROVIDERS(): any[] { return _PROVIDERS; }
static PROVIDERS = [FirefoxDriverExtension];
private _profilerStarted: boolean;
@ -39,7 +41,7 @@ export class FirefoxDriverExtension extends WebDriverExtension {
return this._driver.executeScript(script);
}
readPerfLog(): Promise<any> {
readPerfLog(): Promise<PerfLogEvent> {
return this._driver.executeAsyncScript('var cb = arguments[0]; window.getProfile(cb);');
}
@ -49,9 +51,3 @@ export class FirefoxDriverExtension extends WebDriverExtension {
return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'firefox');
}
}
var _PROVIDERS = [{
provide: FirefoxDriverExtension,
useFactory: (driver) => new FirefoxDriverExtension(driver),
deps: [WebDriverAdapter]
}];

View File

@ -6,14 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Json, StringWrapper, isBlank, isPresent} from '@angular/facade/src/lang';
import {Injectable} from '@angular/core';
import {StringWrapper, isBlank, isPresent} from '../facade/lang';
import {WebDriverAdapter} from '../web_driver_adapter';
import {PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
@Injectable()
export class IOsDriverExtension extends WebDriverExtension {
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): any[] { return _PROVIDERS; }
static PROVIDERS = [IOsDriverExtension];
constructor(private _driver: WebDriverAdapter) { super(); }
@ -38,9 +39,9 @@ export class IOsDriverExtension extends WebDriverExtension {
return this._driver.executeScript('1+1')
.then((_) => this._driver.logs('performance'))
.then((entries) => {
var records = [];
var records: any[] = [];
entries.forEach(entry => {
var message = Json.parse(entry['message'])['message'];
var message = JSON.parse(entry['message'])['message'];
if (StringWrapper.equals(message['method'], 'Timeline.eventRecorded')) {
records.push(message['params']['record']);
}
@ -50,12 +51,12 @@ export class IOsDriverExtension extends WebDriverExtension {
}
/** @internal */
private _convertPerfRecordsToEvents(records: any[], events: any[] = null) {
private _convertPerfRecordsToEvents(records: any[], events: PerfLogEvent[] = null) {
if (isBlank(events)) {
events = [];
}
records.forEach((record) => {
var endEvent = null;
var endEvent: PerfLogEvent = null;
var type = record['type'];
var data = record['data'];
var startTime = record['startTime'];
@ -95,8 +96,9 @@ export class IOsDriverExtension extends WebDriverExtension {
}
}
function createEvent(ph, name, time, args = null) {
var result = {
function createEvent(
ph: 'X' | 'B' | 'E' | 'b' | 'e', name: string, time: number, args: any = null) {
var result: PerfLogEvent = {
'cat': 'timeline',
'name': name,
'ts': time,
@ -111,24 +113,18 @@ function createEvent(ph, name, time, args = null) {
return result;
}
function createStartEvent(name, time, args = null) {
function createStartEvent(name: string, time: number, args: any = null) {
return createEvent('B', name, time, args);
}
function createEndEvent(name, time, args = null) {
function createEndEvent(name: string, time: number, args: any = null) {
return createEvent('E', name, time, args);
}
function createMarkStartEvent(name, time) {
function createMarkStartEvent(name: string, time: number) {
return createEvent('b', name, time);
}
function createMarkEndEvent(name, time) {
function createMarkEndEvent(name: string, time: number) {
return createEvent('e', name, time);
}
var _PROVIDERS = [{
provide: IOsDriverExtension,
useFactory: (driver) => new IOsDriverExtension(driver),
deps: [WebDriverAdapter]
}];

View File

@ -1,3 +0,0 @@
library benchpress.src.webdriver.selenium_webdriver_adapter;
//no dart implementation

View File

@ -10,18 +10,19 @@ import * as webdriver from 'selenium-webdriver';
import {WebDriverAdapter} from '../web_driver_adapter';
/**
* Adapter for the selenium-webdriver.
*/
export class SeleniumWebDriverAdapter extends WebDriverAdapter {
static get PROTRACTOR_BINDINGS(): any[] { return _PROTRACTOR_BINDINGS; }
static PROTRACTOR_PROVIDERS = [{
provide: WebDriverAdapter,
useFactory: () => new SeleniumWebDriverAdapter((<any>global).browser)
}];
constructor(private _driver: any) { super(); }
/** @internal */
private _convertPromise(thenable) {
private _convertPromise(thenable: PromiseLike<any>) {
var resolve: (result: any) => void;
var reject: (error: any) => void;
var promise = new Promise((res, rej) => {
@ -31,12 +32,11 @@ export class SeleniumWebDriverAdapter extends WebDriverAdapter {
thenable.then(
// selenium-webdriver uses an own Node.js context,
// so we need to convert data into objects of this context.
// Previously needed for rtts_asserts.
(data) => resolve(convertToLocalProcess(data)), reject);
(data: any) => resolve(convertToLocalProcess(data)), reject);
return promise;
}
waitFor(callback): Promise<any> {
waitFor(callback: () => any): Promise<any> {
return this._convertPromise(this._driver.controlFlow().execute(callback));
}
@ -50,7 +50,7 @@ export class SeleniumWebDriverAdapter extends WebDriverAdapter {
capabilities(): Promise<any> {
return this._convertPromise(
this._driver.getCapabilities().then((capsObject) => capsObject.serialize()));
this._driver.getCapabilities().then((capsObject: any) => capsObject.serialize()));
}
logs(type: string): Promise<any> {
@ -62,16 +62,10 @@ export class SeleniumWebDriverAdapter extends WebDriverAdapter {
}
}
function convertToLocalProcess(data): Object {
function convertToLocalProcess(data: any): Object {
var serialized = JSON.stringify(data);
if ('' + serialized === 'undefined') {
return undefined;
}
return JSON.parse(serialized);
}
var _PROTRACTOR_BINDINGS = [{
provide: WebDriverAdapter,
useFactory: () => new SeleniumWebDriverAdapter((<any>global).browser),
deps: []
}];

View File

@ -1,3 +0,0 @@
library benchpress.test.firefox_extension.conf;
//empty as we don't have a version for dart

View File

@ -1,3 +0,0 @@
library benchpress.test.firefox_extension.parser_util_spec;
main() {}

View File

@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
import {convertPerfProfileToEvents} from 'benchpress/src/firefox_extension/lib/parser_util';
import {convertPerfProfileToEvents} from '../../src/firefox_extension/lib/parser_util';
function assertEventsEqual(actualEvents, expectedEvents) {
function assertEventsEqual(actualEvents: any[], expectedEvents: any[]) {
expect(actualEvents.length == expectedEvents.length);
for (var i = 0; i < actualEvents.length; ++i) {
var actualEvent = actualEvents[i];

View File

@ -1,3 +0,0 @@
library benchpress.test.firefox_extension.sample_benchmark;
main() {}

View File

@ -9,7 +9,7 @@
var benchpress = require('../../index.js');
var runner = new benchpress.Runner([
// use protractor as Webdriver client
benchpress.SeleniumWebDriverAdapter.PROTRACTOR_BINDINGS,
benchpress.SeleniumWebDriverAdapter.PROTRACTOR_PROVIDERS,
// use RegressionSlopeValidator to validate samples
benchpress.Validator.bindTo(benchpress.RegressionSlopeValidator),
// use 10 samples to calculate slope regression

View File

@ -1,3 +0,0 @@
library benchpress.test.firefox_extension.spec;
main() {}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
var assertEventsContainsName = function(events, eventName) {
var assertEventsContainsName = function(events: any[], eventName: string) {
var found = false;
for (var i = 0; i < events.length; ++i) {
if (events[i].name == eventName) {
@ -33,7 +33,7 @@ describe('firefox extension', function() {
browser.executeScript('window.forceGC()');
browser.executeAsyncScript('var cb = arguments[0]; window.getProfile(cb);')
.then(function(profile) {
.then(function(profile: any) {
assertEventsContainsName(profile, 'gc');
assertEventsContainsName(profile, 'script');
});

View File

@ -7,28 +7,29 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Metric, MultiMetric, ReflectiveInjector} from 'benchpress/common';
import {Metric, MultiMetric, ReflectiveInjector} from '../../index';
export function main() {
function createMetric(ids: any[]) {
var m = ReflectiveInjector
.resolveAndCreate([
ids.map(id => { return {provide: id, useValue: new MockMetric(id)}; }),
MultiMetric.createBindings(ids)
MultiMetric.provideWith(ids)
])
.get(MultiMetric);
return Promise.resolve(m);
}
describe('multi metric', () => {
it('should merge descriptions', inject([AsyncTestCompleter], (async) => {
it('should merge descriptions', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createMetric(['m1', 'm2']).then((m) => {
expect(m.describe()).toEqual({'m1': 'describe', 'm2': 'describe'});
async.done();
});
}));
it('should merge all beginMeasure calls', inject([AsyncTestCompleter], (async) => {
it('should merge all beginMeasure calls',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createMetric(['m1', 'm2']).then((m) => m.beginMeasure()).then((values) => {
expect(values).toEqual(['m1_beginMeasure', 'm2_beginMeasure']);
async.done();
@ -37,7 +38,7 @@ export function main() {
[false, true].forEach((restartFlag) => {
it(`should merge all endMeasure calls for restart=${restartFlag}`,
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createMetric(['m1', 'm2']).then((m) => m.endMeasure(restartFlag)).then((values) => {
expect(values).toEqual(
{'m1': {'restart': restartFlag}, 'm2': {'restart': restartFlag}});
@ -50,18 +51,12 @@ export function main() {
}
class MockMetric extends Metric {
/** @internal */
private _id: string;
constructor(id) {
super();
this._id = id;
}
constructor(private _id: string) { super(); }
beginMeasure(): Promise<string> { return Promise.resolve(`${this._id}_beginMeasure`); }
endMeasure(restart: boolean): Promise<{[key: string]: any}> {
var result = {};
var result: {[key: string]: any} = {};
result[this._id] = {'restart': restart};
return Promise.resolve(result);
}

View File

@ -8,10 +8,10 @@
import {Provider} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {StringMapWrapper} from '@angular/facade/src/collection';
import {isBlank, isPresent} from '@angular/facade/src/lang';
import {Metric, Options, PerfLogFeatures, PerflogMetric, ReflectiveInjector, WebDriverExtension} from 'benchpress/common';
import {Metric, Options, PerfLogEvent, PerfLogFeatures, PerflogMetric, ReflectiveInjector, WebDriverExtension} from '../../index';
import {StringMapWrapper} from '../../src/facade/collection';
import {isBlank, isPresent} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory';
export function main() {
@ -19,7 +19,7 @@ export function main() {
var eventFactory = new TraceEventFactory('timeline', 'pid0');
function createMetric(
perfLogs, perfLogFeatures,
perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
{microMetrics, forceGc, captureFrames, receivedData, requestCount}: {
microMetrics?: {[key: string]: string},
forceGc?: boolean,
@ -39,7 +39,7 @@ export function main() {
Options.DEFAULT_PROVIDERS, PerflogMetric.PROVIDERS,
{provide: Options.MICRO_METRICS, useValue: microMetrics}, {
provide: PerflogMetric.SET_TIMEOUT,
useValue: (fn, millis) => {
useValue: (fn: Function, millis: number) => {
commandLog.push(['setTimeout', millis]);
fn();
},
@ -66,8 +66,8 @@ export function main() {
describe('perflog metric', () => {
function sortedKeys(stringMap) {
var res = [];
function sortedKeys(stringMap: {[key: string]: any}) {
var res: string[] = [];
StringMapWrapper.forEach(stringMap, (_, key) => { res.push(key); });
res.sort();
return res;
@ -130,7 +130,8 @@ export function main() {
describe('beginMeasure', () => {
it('should not force gc and mark the timeline', inject([AsyncTestCompleter], (async) => {
it('should not force gc and mark the timeline',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var metric = createMetric([[]], null);
metric.beginMeasure().then((_) => {
expect(commandLog).toEqual([['timeBegin', 'benchpress0']]);
@ -139,7 +140,8 @@ export function main() {
});
}));
it('should force gc and mark the timeline', inject([AsyncTestCompleter], (async) => {
it('should force gc and mark the timeline',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var metric = createMetric([[]], null, {forceGc: true});
metric.beginMeasure().then((_) => {
expect(commandLog).toEqual([['gc'], ['timeBegin', 'benchpress0']]);
@ -153,7 +155,7 @@ export function main() {
describe('endMeasure', () => {
it('should mark and aggregate events in between the marks',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var events = [[
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4),
eventFactory.end('script', 6), eventFactory.markEnd('benchpress0', 10)
@ -169,7 +171,7 @@ export function main() {
});
}));
it('should restart timing', inject([AsyncTestCompleter], (async) => {
it('should restart timing', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var events = [
[
eventFactory.markStart('benchpress0', 0),
@ -193,7 +195,7 @@ export function main() {
}));
it('should loop and aggregate until the end mark is present',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var events = [
[eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 1)],
[eventFactory.end('script', 2)],
@ -215,7 +217,7 @@ export function main() {
}));
it('should store events after the end mark for the next call',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var events = [
[
eventFactory.markStart('benchpress0', 0), eventFactory.markEnd('benchpress0', 1),
@ -246,7 +248,7 @@ export function main() {
}));
describe('with forced gc', () => {
var events;
var events: PerfLogEvent[][];
beforeEach(() => {
events = [[
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4),
@ -258,7 +260,7 @@ export function main() {
]];
});
it('should measure forced gc', inject([AsyncTestCompleter], (async) => {
it('should measure forced gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var metric = createMetric(events, null, {forceGc: true});
metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => {
expect(commandLog).toEqual([
@ -272,7 +274,8 @@ export function main() {
});
}));
it('should restart after the forced gc if needed', inject([AsyncTestCompleter], (async) => {
it('should restart after the forced gc if needed',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var metric = createMetric(events, null, {forceGc: true});
metric.beginMeasure().then((_) => metric.endMeasure(true)).then((data) => {
expect(commandLog[5]).toEqual(['timeEnd', 'benchpress1', 'benchpress2']);
@ -305,7 +308,8 @@ export function main() {
}
describe('frame metrics', () => {
it('should calculate mean frame time', inject([AsyncTestCompleter], (async) => {
it('should calculate mean frame time',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1),
@ -319,7 +323,8 @@ export function main() {
});
}));
it('should throw if no start event', inject([AsyncTestCompleter], (async) => {
it('should throw if no start event',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[eventFactory.instant('frame', 4), eventFactory.markEnd('frameCapture', 5)],
@ -332,7 +337,8 @@ export function main() {
});
}));
it('should throw if no end event', inject([AsyncTestCompleter], (async) => {
it('should throw if no end event',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[eventFactory.markStart('frameCapture', 3), eventFactory.instant('frame', 4)],
@ -343,7 +349,8 @@ export function main() {
});
}));
it('should throw if trying to capture twice', inject([AsyncTestCompleter], (async) => {
it('should throw if trying to capture twice',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
@ -360,7 +367,7 @@ export function main() {
}));
it('should throw if trying to capture when frame capture is disabled',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([eventFactory.markStart('frameCapture', 3)]).catch((err) => {
expect(() => { throw err; })
.toThrowError(
@ -371,7 +378,7 @@ export function main() {
}));
it('should throw if frame capture is enabled, but nothing is captured',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([], {captureFrames: true}).catch((err): any => {
expect(() => { throw err; })
.toThrowError(
@ -380,7 +387,8 @@ export function main() {
});
}));
it('should calculate best and worst frame time', inject([AsyncTestCompleter], (async) => {
it('should calculate best and worst frame time',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1),
@ -397,7 +405,7 @@ export function main() {
}));
it('should calculate percentage of smoothness to be good',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1),
@ -412,7 +420,7 @@ export function main() {
}));
it('should calculate percentage of smoothness to be bad',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1),
@ -429,7 +437,8 @@ export function main() {
});
it('should report a single interval', inject([AsyncTestCompleter], (async) => {
it('should report a single interval',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('script', 0), eventFactory.end('script', 5)
]).then((data) => {
@ -438,7 +447,8 @@ export function main() {
});
}));
it('should sum up multiple intervals', inject([AsyncTestCompleter], (async) => {
it('should sum up multiple intervals',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('script', 0), eventFactory.end('script', 5),
eventFactory.start('script', 10), eventFactory.end('script', 17)
@ -448,21 +458,24 @@ export function main() {
});
}));
it('should ignore not started intervals', inject([AsyncTestCompleter], (async) => {
it('should ignore not started intervals',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([eventFactory.end('script', 10)]).then((data) => {
expect(data['scriptTime']).toBe(0);
async.done();
});
}));
it('should ignore not ended intervals', inject([AsyncTestCompleter], (async) => {
it('should ignore not ended intervals',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([eventFactory.start('script', 10)]).then((data) => {
expect(data['scriptTime']).toBe(0);
async.done();
});
}));
it('should ignore nested intervals', inject([AsyncTestCompleter], (async) => {
it('should ignore nested intervals',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('script', 0), eventFactory.start('script', 5),
eventFactory.end('script', 10), eventFactory.end('script', 17)
@ -473,7 +486,7 @@ export function main() {
}));
it('should ignore events from different processed as the start mark',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1');
var metric = createMetric(
[[
@ -490,7 +503,8 @@ export function main() {
});
}));
it('should support scriptTime metric', inject([AsyncTestCompleter], (async) => {
it('should support scriptTime metric',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('script', 0), eventFactory.end('script', 5)
]).then((data) => {
@ -499,7 +513,8 @@ export function main() {
});
}));
it('should support renderTime metric', inject([AsyncTestCompleter], (async) => {
it('should support renderTime metric',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('render', 0), eventFactory.end('render', 5)
]).then((data) => {
@ -508,7 +523,8 @@ export function main() {
});
}));
it('should support gcTime/gcAmount metric', inject([AsyncTestCompleter], (async) => {
it('should support gcTime/gcAmount metric',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('gc', 0, {'usedHeapSize': 2500}),
eventFactory.end('gc', 5, {'usedHeapSize': 1000})
@ -520,7 +536,8 @@ export function main() {
});
}));
it('should support majorGcTime metric', inject([AsyncTestCompleter], (async) => {
it('should support majorGcTime metric',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('gc', 0, {'usedHeapSize': 2500}),
eventFactory.end('gc', 5, {'usedHeapSize': 1000, 'majorGc': true})
@ -532,7 +549,7 @@ export function main() {
}));
it('should support pureScriptTime = scriptTime-gcTime-renderTime',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('script', 0), eventFactory.start('gc', 1, {'usedHeapSize': 1000}),
eventFactory.end('gc', 4, {'usedHeapSize': 0}), eventFactory.start('render', 4),
@ -546,7 +563,7 @@ export function main() {
describe('receivedData', () => {
it('should report received data since last navigationStart',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.instant('receivedData', 0, {'encodedDataLength': 1}),
@ -566,7 +583,7 @@ export function main() {
describe('requestCount', () => {
it('should report count of requests sent since last navigationStart',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.instant('sendRequest', 0),
@ -585,7 +602,8 @@ export function main() {
describe('microMetrics', () => {
it('should report micro metrics', inject([AsyncTestCompleter], (async) => {
it('should report micro metrics',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.markStart('mm1', 0),
@ -599,7 +617,7 @@ export function main() {
}));
it('should ignore micro metrics that were not specified',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.markStart('mm1', 0),
eventFactory.markEnd('mm1', 5),
@ -609,7 +627,8 @@ export function main() {
});
}));
it('should report micro metric averages', inject([AsyncTestCompleter], (async) => {
it('should report micro metric averages',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.markStart('mm1*20', 0),
@ -636,12 +655,12 @@ class MockDriverExtension extends WebDriverExtension {
super();
}
timeBegin(name): Promise<any> {
timeBegin(name: string): Promise<any> {
this._commandLog.push(['timeBegin', name]);
return Promise.resolve(null);
}
timeEnd(name, restartName): Promise<any> {
timeEnd(name: string, restartName: string): Promise<any> {
this._commandLog.push(['timeEnd', name, restartName]);
return Promise.resolve(null);
}

View File

@ -8,15 +8,16 @@
import {Provider, ReflectiveInjector} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {StringMapWrapper} from '@angular/facade/src/collection';
import {Json, isBlank, isPresent} from '@angular/facade/src/lang';
import {Injector, Metric, MultiMetric, Options, PerfLogFeatures, PerflogMetric, UserMetric, WebDriverAdapter, WebDriverExtension} from 'benchpress/common';
import {Injector, Metric, MultiMetric, Options, PerfLogEvent, PerfLogFeatures, PerflogMetric, UserMetric, WebDriverAdapter, WebDriverExtension} from '../../index';
import {StringMapWrapper} from '../../src/facade/collection';
import {Json, isBlank, isPresent} from '../../src/facade/lang';
export function main() {
var wdAdapter: MockDriverAdapter;
function createMetric(
perfLogs, perfLogFeatures,
perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
{userMetrics}: {userMetrics?: {[key: string]: string}} = {}): UserMetric {
if (isBlank(perfLogFeatures)) {
perfLogFeatures =
@ -26,12 +27,12 @@ export function main() {
userMetrics = StringMapWrapper.create();
}
wdAdapter = new MockDriverAdapter();
var bindings: Provider[] = [
var providers: Provider[] = [
Options.DEFAULT_PROVIDERS, UserMetric.PROVIDERS,
{provide: Options.USER_METRICS, useValue: userMetrics},
{provide: WebDriverAdapter, useValue: wdAdapter}
];
return ReflectiveInjector.resolveAndCreate(bindings).get(UserMetric);
return ReflectiveInjector.resolveAndCreate(providers).get(UserMetric);
}
describe('user metric', () => {
@ -45,7 +46,7 @@ export function main() {
describe('endMeasure', () => {
it('should stop measuring when all properties have numeric values',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let metric = createMetric(
[[]], new PerfLogFeatures(),
{userMetrics: {'loadTime': 'time to load', 'content': 'time to see content'}});

View File

@ -6,17 +6,24 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Provider} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Date, DateWrapper, isBlank, isPresent} from '@angular/facade/src/lang';
import {ConsoleReporter, MeasureValues, ReflectiveInjector, Reporter, SampleDescription, SampleState} from 'benchpress/common';
import {ConsoleReporter, MeasureValues, ReflectiveInjector, Reporter, SampleDescription, SampleState} from '../../index';
import {Date, DateWrapper, isBlank, isPresent} from '../../src/facade/lang';
export function main() {
describe('console reporter', () => {
var reporter;
var reporter: ConsoleReporter;
var log: string[];
function createReporter({columnWidth = null, sampleId = null, descriptions = null,
metrics = null}: {columnWidth?, sampleId?, descriptions?, metrics?}) {
function createReporter(
{columnWidth = null, sampleId = null, descriptions = null, metrics = null}: {
columnWidth?: number,
sampleId?: string,
descriptions?: {[key: string]: any}[],
metrics?: {[key: string]: any}
}) {
log = [];
if (isBlank(descriptions)) {
descriptions = [];
@ -24,17 +31,17 @@ export function main() {
if (isBlank(sampleId)) {
sampleId = 'null';
}
var bindings = [
var providers: Provider[] = [
ConsoleReporter.PROVIDERS, {
provide: SampleDescription,
useValue: new SampleDescription(sampleId, descriptions, metrics)
},
{provide: ConsoleReporter.PRINT, useValue: (line) => log.push(line)}
{provide: ConsoleReporter.PRINT, useValue: (line: string) => log.push(line)}
];
if (isPresent(columnWidth)) {
bindings.push({provide: ConsoleReporter.COLUMN_WIDTH, useValue: columnWidth});
providers.push({provide: ConsoleReporter.COLUMN_WIDTH, useValue: columnWidth});
}
reporter = ReflectiveInjector.resolveAndCreate(bindings).get(ConsoleReporter);
reporter = ReflectiveInjector.resolveAndCreate(providers).get(ConsoleReporter);
}
it('should print the sample id, description and table header', () => {
@ -82,6 +89,6 @@ export function main() {
});
}
function mv(runIndex, time, values) {
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
}

View File

@ -7,16 +7,21 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {DateWrapper, Json, isPresent} from '@angular/facade/src/lang';
import {MeasureValues, Options, ReflectiveInjector, SampleDescription} from 'benchpress/common';
import {JsonFileReporter} from 'benchpress/src/reporter/json_file_reporter';
import {JsonFileReporter, MeasureValues, Options, ReflectiveInjector, SampleDescription} from '../../index';
import {DateWrapper, Json, isPresent} from '../../src/facade/lang';
export function main() {
describe('file reporter', () => {
var loggedFile;
var loggedFile: any;
function createReporter({sampleId, descriptions, metrics, path}) {
var bindings = [
function createReporter({sampleId, descriptions, metrics, path}: {
sampleId: string,
descriptions: {[key: string]: any}[],
metrics: {[key: string]: string},
path: string
}) {
var providers = [
JsonFileReporter.PROVIDERS, {
provide: SampleDescription,
useValue: new SampleDescription(sampleId, descriptions, metrics)
@ -24,16 +29,17 @@ export function main() {
{provide: JsonFileReporter.PATH, useValue: path},
{provide: Options.NOW, useValue: () => DateWrapper.fromMillis(1234)}, {
provide: Options.WRITE_FILE,
useValue: (filename, content) => {
useValue: (filename: string, content: string) => {
loggedFile = {'filename': filename, 'content': content};
return Promise.resolve(null);
}
}
];
return ReflectiveInjector.resolveAndCreate(bindings).get(JsonFileReporter);
return ReflectiveInjector.resolveAndCreate(providers).get(JsonFileReporter);
}
it('should write all data into a file', inject([AsyncTestCompleter], (async) => {
it('should write all data into a file',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createReporter({
sampleId: 'someId',
descriptions: [{'a': 2}],
@ -66,6 +72,6 @@ export function main() {
});
}
function mv(runIndex, time, values) {
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
}

View File

@ -7,15 +7,16 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {DateWrapper} from '@angular/facade/src/lang';
import {MeasureValues, MultiReporter, ReflectiveInjector, Reporter} from 'benchpress/common';
import {MeasureValues, MultiReporter, ReflectiveInjector, Reporter} from '../../index';
import {DateWrapper} from '../../src/facade/lang';
export function main() {
function createReporters(ids: any[]) {
var r = ReflectiveInjector
.resolveAndCreate([
ids.map(id => { return {provide: id, useValue: new MockReporter(id)}; }),
MultiReporter.createBindings(ids)
MultiReporter.provideWith(ids)
])
.get(MultiReporter);
return Promise.resolve(r);
@ -23,7 +24,8 @@ export function main() {
describe('multi reporter', () => {
it('should reportMeasureValues to all', inject([AsyncTestCompleter], (async) => {
it('should reportMeasureValues to all',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var mv = new MeasureValues(0, DateWrapper.now(), {});
createReporters(['m1', 'm2']).then((r) => r.reportMeasureValues(mv)).then((values) => {
@ -32,7 +34,7 @@ export function main() {
});
}));
it('should reportSample to call', inject([AsyncTestCompleter], (async) => {
it('should reportSample to call', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var completeSample = [
new MeasureValues(0, DateWrapper.now(), {}), new MeasureValues(1, DateWrapper.now(), {})
];

View File

@ -7,22 +7,23 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {isBlank} from '@angular/facade/src/lang';
import {Injector, Metric, Options, ReflectiveInjector, Runner, SampleDescription, SampleState, Sampler, Validator, WebDriverAdapter} from 'benchpress/common';
import {Injector, Metric, Options, ReflectiveInjector, Runner, SampleDescription, SampleState, Sampler, Validator, WebDriverAdapter} from '../index';
import {isBlank} from '../src/facade/lang';
export function main() {
describe('runner', () => {
var injector: ReflectiveInjector;
var runner;
var runner: Runner;
function createRunner(defaultBindings = null): Runner {
if (isBlank(defaultBindings)) {
defaultBindings = [];
function createRunner(defaultProviders: any[] = null): Runner {
if (isBlank(defaultProviders)) {
defaultProviders = [];
}
runner = new Runner([
defaultBindings, {
defaultProviders, {
provide: Sampler,
useFactory: (_injector) => {
useFactory: (_injector: ReflectiveInjector) => {
injector = _injector;
return new MockSampler();
},
@ -35,7 +36,8 @@ export function main() {
return runner;
}
it('should set SampleDescription.id', inject([AsyncTestCompleter], (async) => {
it('should set SampleDescription.id',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner()
.sample({id: 'someId'})
.then((_) => injector.get(SampleDescription))
@ -45,7 +47,8 @@ export function main() {
});
}));
it('should merge SampleDescription.description', inject([AsyncTestCompleter], (async) => {
it('should merge SampleDescription.description',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner([{provide: Options.DEFAULT_DESCRIPTION, useValue: {'a': 1}}])
.sample({
id: 'someId',
@ -61,7 +64,7 @@ export function main() {
}));
it('should fill SampleDescription.metrics from the Metric',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner()
.sample({id: 'someId'})
.then((_) => injector.get(SampleDescription))
@ -72,7 +75,8 @@ export function main() {
});
}));
it('should bind Options.EXECUTE', inject([AsyncTestCompleter], (async) => {
it('should provide Options.EXECUTE',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var execute = () => {};
createRunner().sample({id: 'someId', execute: execute}).then((_) => {
expect(injector.get(Options.EXECUTE)).toEqual(execute);
@ -80,7 +84,8 @@ export function main() {
});
}));
it('should bind Options.PREPARE', inject([AsyncTestCompleter], (async) => {
it('should provide Options.PREPARE',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var prepare = () => {};
createRunner().sample({id: 'someId', prepare: prepare}).then((_) => {
expect(injector.get(Options.PREPARE)).toEqual(prepare);
@ -88,14 +93,16 @@ export function main() {
});
}));
it('should bind Options.MICRO_METRICS', inject([AsyncTestCompleter], (async) => {
it('should provide Options.MICRO_METRICS',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner().sample({id: 'someId', microMetrics: {'a': 'b'}}).then((_) => {
expect(injector.get(Options.MICRO_METRICS)).toEqual({'a': 'b'});
async.done();
});
}));
it('should overwrite bindings per sample call', inject([AsyncTestCompleter], (async) => {
it('should overwrite providers per sample call',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner([{provide: Options.DEFAULT_DESCRIPTION, useValue: {'a': 1}}])
.sample({
id: 'someId',
@ -114,8 +121,8 @@ export function main() {
}
class MockWebDriverAdapter extends WebDriverAdapter {
executeScript(script): Promise<string> { return Promise.resolve('someUserAgent'); }
capabilities() { return null; }
executeScript(script: string): Promise<string> { return Promise.resolve('someUserAgent'); }
capabilities(): Promise<Map<string, any>> { return null; }
}
class MockValidator extends Validator {
@ -129,6 +136,6 @@ class MockMetric extends Metric {
}
class MockSampler extends Sampler {
constructor() { super(); }
constructor() { super(null, null, null, null, null, null, null); }
sample(): Promise<SampleState> { return Promise.resolve(new SampleState([], [])); }
}

View File

@ -7,8 +7,9 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Date, DateWrapper, isBlank, isPresent, stringify} from '@angular/facade/src/lang';
import {MeasureValues, Metric, Options, ReflectiveInjector, Reporter, Sampler, Validator, WebDriverAdapter} from 'benchpress/common';
import {MeasureValues, Metric, Options, ReflectiveInjector, Reporter, Sampler, Validator, WebDriverAdapter} from '../index';
import {Date, DateWrapper, isBlank, isPresent, stringify} from '../src/facade/lang';
export function main() {
var EMPTY_EXECUTE = () => {};
@ -48,10 +49,10 @@ export function main() {
}
it('should call the prepare and execute callbacks using WebDriverAdapter.waitFor',
inject([AsyncTestCompleter], (async) => {
var log = [];
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var log: any[] = [];
var count = 0;
var driver = new MockDriverAdapter([], (callback) => {
var driver = new MockDriverAdapter([], (callback: Function) => {
var result = callback();
log.push(result);
return Promise.resolve(result);
@ -71,9 +72,9 @@ export function main() {
}));
it('should call prepare, beginMeasure, execute, endMeasure for every iteration',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var workCount = 0;
var log = [];
var log: any[] = [];
createSampler({
metric: createCountingMetric(log),
validator: createCountingValidator(2),
@ -96,8 +97,8 @@ export function main() {
}));
it('should call execute, endMeasure for every iteration if there is no prepare callback',
inject([AsyncTestCompleter], (async) => {
var log = [];
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var log: any[] = [];
var workCount = 0;
createSampler({
metric: createCountingMetric(log),
@ -118,7 +119,7 @@ export function main() {
}));
it('should only collect metrics for execute and ignore metrics from prepare',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var scriptTime = 0;
var iterationCount = 1;
createSampler({
@ -145,9 +146,9 @@ export function main() {
}));
it('should call the validator for every execution and store the valid sample',
inject([AsyncTestCompleter], (async) => {
var log = [];
var validSample = [{}];
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var log: any[] = [];
var validSample = [mv(null, null, {})];
createSampler({
metric: createCountingMetric(),
@ -171,9 +172,10 @@ export function main() {
});
}));
it('should report the metric values', inject([AsyncTestCompleter], (async) => {
var log = [];
var validSample = [{}];
it('should report the metric values',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var log: any[] = [];
var validSample = [mv(null, null, {})];
createSampler({
validator: createCountingValidator(2, validSample),
metric: createCountingMetric(),
@ -201,12 +203,13 @@ export function main() {
});
}
function mv(runIndex, time, values) {
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
}
function createCountingValidator(count, validSample = null, log = null) {
return new MockValidator(log, (completeSample) => {
function createCountingValidator(
count: number, validSample: MeasureValues[] = null, log: any[] = []) {
return new MockValidator(log, (completeSample: MeasureValues[]) => {
count--;
if (count === 0) {
return isPresent(validSample) ? validSample : completeSample;
@ -216,23 +219,13 @@ function createCountingValidator(count, validSample = null, log = null) {
});
}
function createCountingMetric(log = null) {
function createCountingMetric(log: any[] = []) {
var scriptTime = 0;
return new MockMetric(log, () => { return {'script': scriptTime++}; });
}
class MockDriverAdapter extends WebDriverAdapter {
/** @internal */
private _log: any[];
private _waitFor: Function;
constructor(log = null, waitFor = null) {
super();
if (isBlank(log)) {
log = [];
}
this._log = log;
this._waitFor = waitFor;
}
constructor(private _log: any[] = [], private _waitFor: Function = null) { super(); }
waitFor(callback: Function): Promise<any> {
if (isPresent(this._waitFor)) {
return this._waitFor(callback);
@ -244,15 +237,7 @@ class MockDriverAdapter extends WebDriverAdapter {
class MockValidator extends Validator {
/** @internal */
private _log: any[];
constructor(log = null, private _validate: Function = null) {
super();
if (isBlank(log)) {
log = [];
}
this._log = log;
}
constructor(private _log: any[] = [], private _validate: Function = null) { super(); }
validate(completeSample: MeasureValues[]): MeasureValues[] {
var stableSample = isPresent(this._validate) ? this._validate(completeSample) : completeSample;
this._log.push(['validate', completeSample, stableSample]);
@ -261,20 +246,12 @@ class MockValidator extends Validator {
}
class MockMetric extends Metric {
/** @internal */
private _log: any[];
constructor(log = null, private _endMeasure: Function = null) {
super();
if (isBlank(log)) {
log = [];
}
this._log = log;
}
constructor(private _log: any[] = [], private _endMeasure: Function = null) { super(); }
beginMeasure() {
this._log.push(['beginMeasure']);
return Promise.resolve(null);
}
endMeasure(restart) {
endMeasure(restart: boolean) {
var measureValues = isPresent(this._endMeasure) ? this._endMeasure() : {};
this._log.push(['endMeasure', restart, measureValues]);
return Promise.resolve(measureValues);
@ -282,20 +259,12 @@ class MockMetric extends Metric {
}
class MockReporter extends Reporter {
/** @internal */
private _log: any[];
constructor(log = null) {
super();
if (isBlank(log)) {
log = [];
}
this._log = log;
}
reportMeasureValues(values): Promise<any> {
constructor(private _log: any[] = []) { super(); }
reportMeasureValues(values: MeasureValues): Promise<any> {
this._log.push(['reportMeasureValues', values]);
return Promise.resolve(null);
}
reportSample(completeSample, validSample): Promise<any> {
reportSample(completeSample: MeasureValues[], validSample: MeasureValues[]): Promise<any> {
this._log.push(['reportSample', completeSample, validSample]);
return Promise.resolve(null);
}

View File

@ -7,7 +7,7 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Statistic} from 'benchpress/src/statistic';
import {Statistic} from '../src/statistic';
export function main() {
describe('statistic', () => {

View File

@ -6,36 +6,34 @@
* found in the LICENSE file at https://angular.io/license
*/
import {isPresent} from '@angular/facade/src/lang';
import {PerfLogEvent} from '../index';
import {isPresent} from '../src/facade/lang';
export class TraceEventFactory {
private _cat: string;
private _pid;
constructor(private _cat: string, private _pid: string) {}
constructor(cat, pid) {
this._cat = cat;
this._pid = pid;
}
create(ph, name, time, args = null) {
var res = {'name': name, 'cat': this._cat, 'ph': ph, 'ts': time, 'pid': this._pid};
create(ph: any, name: string, time: number, args: any = null) {
var res:
PerfLogEvent = {'name': name, 'cat': this._cat, 'ph': ph, 'ts': time, 'pid': this._pid};
if (isPresent(args)) {
res['args'] = args;
}
return res;
}
markStart(name, time) { return this.create('b', name, time); }
markStart(name: string, time: number) { return this.create('b', name, time); }
markEnd(name, time) { return this.create('e', name, time); }
markEnd(name: string, time: number) { return this.create('e', name, time); }
start(name, time, args = null) { return this.create('B', name, time, args); }
start(name: string, time: number, args: any = null) { return this.create('B', name, time, args); }
end(name, time, args = null) { return this.create('E', name, time, args); }
end(name: string, time: number, args: any = null) { return this.create('E', name, time, args); }
instant(name, time, args = null) { return this.create('i', name, time, args); }
instant(name: string, time: number, args: any = null) {
return this.create('i', name, time, args);
}
complete(name, time, duration, args = null) {
complete(name: string, time: number, duration: number, args: any = null) {
var res = this.create('X', name, time, args);
res['dur'] = duration;
return res;

View File

@ -7,15 +7,16 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {ListWrapper} from '@angular/facade/src/collection';
import {Date, DateWrapper} from '@angular/facade/src/lang';
import {MeasureValues, ReflectiveInjector, RegressionSlopeValidator} from 'benchpress/common';
import {MeasureValues, ReflectiveInjector, RegressionSlopeValidator} from '../../index';
import {ListWrapper} from '../../src/facade/collection';
import {Date, DateWrapper} from '../../src/facade/lang';
export function main() {
describe('regression slope validator', () => {
var validator;
var validator: RegressionSlopeValidator;
function createValidator({size, metric}) {
function createValidator({size, metric}: {size: number, metric: string}) {
validator = ReflectiveInjector
.resolveAndCreate([
RegressionSlopeValidator.PROVIDERS,
@ -60,6 +61,6 @@ export function main() {
});
}
function mv(runIndex, time, values) {
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
}

View File

@ -7,15 +7,16 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {ListWrapper} from '@angular/facade/src/collection';
import {Date, DateWrapper} from '@angular/facade/src/lang';
import {MeasureValues, ReflectiveInjector, SizeValidator, Validator} from 'benchpress/common';
import {MeasureValues, ReflectiveInjector, SizeValidator, Validator} from '../../index';
import {ListWrapper} from '../../src/facade/collection';
import {Date, DateWrapper} from '../../src/facade/lang';
export function main() {
describe('size validator', () => {
var validator;
var validator: SizeValidator;
function createValidator(size) {
function createValidator(size: number) {
validator =
ReflectiveInjector
.resolveAndCreate(
@ -45,6 +46,6 @@ export function main() {
});
}
function mv(runIndex, time, values) {
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
}

View File

@ -7,17 +7,19 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {StringWrapper, isPresent} from '@angular/facade/src/lang';
import {Options, ReflectiveInjector, WebDriverExtension} from 'benchpress/common';
import {Options, ReflectiveInjector, WebDriverExtension} from '../index';
import {StringWrapper, isPresent} from '../src/facade/lang';
export function main() {
function createExtension(ids: any[], caps) {
function createExtension(ids: any[], caps: any) {
return new Promise<any>((res, rej) => {
try {
res(ReflectiveInjector
.resolveAndCreate([
ids.map((id) => { return {provide: id, useValue: new MockExtension(id)}; }),
{provide: Options.CAPABILITIES, useValue: caps}, WebDriverExtension.bindTo(ids)
{provide: Options.CAPABILITIES, useValue: caps},
WebDriverExtension.provideFirstSupported(ids)
])
.get(WebDriverExtension));
} catch (e) {
@ -26,17 +28,18 @@ export function main() {
});
}
describe('WebDriverExtension.bindTo', () => {
describe('WebDriverExtension.provideFirstSupported', () => {
it('should bind the extension that matches the capabilities',
inject([AsyncTestCompleter], (async) => {
it('should provide the extension that matches the capabilities',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(['m1', 'm2', 'm3'], {'browser': 'm2'}).then((m) => {
expect(m.id).toEqual('m2');
async.done();
});
}));
it('should throw if there is no match', inject([AsyncTestCompleter], (async) => {
it('should throw if there is no match',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(['m1'], {'browser': 'm2'}).catch((err) => {
expect(isPresent(err)).toBe(true);
async.done();
@ -46,12 +49,7 @@ export function main() {
}
class MockExtension extends WebDriverExtension {
id: string;
constructor(id) {
super();
this.id = id;
}
constructor(public id: string) { super(); }
supports(capabilities: {[key: string]: any}): boolean {
return StringWrapper.equals(capabilities['browser'], this.id);

View File

@ -7,9 +7,9 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Json, isBlank} from '@angular/facade/src/lang';
import {ChromeDriverExtension, Options, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from 'benchpress/common';
import {ChromeDriverExtension, Options, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
import {Json, isBlank} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory';
export function main() {
@ -19,8 +19,8 @@ export function main() {
var CHROME45_USER_AGENT =
'"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2499.0 Safari/537.36"';
var log;
var extension;
var log: any[];
var extension: ChromeDriverExtension;
var blinkEvents = new TraceEventFactory('blink.console', 'pid0');
var v8Events = new TraceEventFactory('v8', 'pid0');
@ -35,7 +35,7 @@ export function main() {
var normEvents = new TraceEventFactory('timeline', 'pid0');
function createExtension(
perfRecords = null, userAgent = null,
perfRecords: any[] = null, userAgent: string = null,
messageMethod = 'Tracing.dataCollected'): WebDriverExtension {
if (isBlank(perfRecords)) {
perfRecords = [];
@ -56,21 +56,24 @@ export function main() {
return extension;
}
it('should force gc via window.gc()', inject([AsyncTestCompleter], (async) => {
it('should force gc via window.gc()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().gc().then((_) => {
expect(log).toEqual([['executeScript', 'window.gc()']]);
async.done();
});
}));
it('should mark the timeline via console.time()', inject([AsyncTestCompleter], (async) => {
it('should mark the timeline via console.time()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeBegin('someName').then((_) => {
expect(log).toEqual([['executeScript', `console.time('someName');`]]);
async.done();
});
}));
it('should mark the timeline via console.timeEnd()', inject([AsyncTestCompleter], (async) => {
it('should mark the timeline via console.timeEnd()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeEnd('someName', null).then((_) => {
expect(log).toEqual([['executeScript', `console.timeEnd('someName');`]]);
async.done();
@ -78,7 +81,7 @@ export function main() {
}));
it('should mark the timeline via console.time() and console.timeEnd()',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeEnd('name1', 'name2').then((_) => {
expect(log).toEqual(
[['executeScript', `console.timeEnd('name1');console.time('name2');`]]);
@ -88,7 +91,7 @@ export function main() {
describe('readPerfLog Chrome44', () => {
it('should normalize times to ms and forward ph and pid event properties',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineEvents.complete('FunctionCall', 1100, 5500, null)])
.readPerfLog()
.then((events) => {
@ -99,8 +102,9 @@ export function main() {
});
}));
it('should normalize "tdur" to "dur"', inject([AsyncTestCompleter], (async) => {
var event = chromeTimelineEvents.create('X', 'FunctionCall', 1100, null);
it('should normalize "tdur" to "dur"',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var event: any = chromeTimelineEvents.create('X', 'FunctionCall', 1100, null);
event['tdur'] = 5500;
createExtension([event]).readPerfLog().then((events) => {
expect(events).toEqual([
@ -110,7 +114,8 @@ export function main() {
});
}));
it('should report FunctionCall events as "script"', inject([AsyncTestCompleter], (async) => {
it('should report FunctionCall events as "script"',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineEvents.start('FunctionCall', 0)])
.readPerfLog()
.then((events) => {
@ -121,7 +126,7 @@ export function main() {
});
}));
it('should report gc', inject([AsyncTestCompleter], (async) => {
it('should report gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([
chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}),
chromeTimelineEvents.end('GCEvent', 2000, {'usedHeapSizeAfter': 0}),
@ -137,7 +142,7 @@ export function main() {
}));
it('should ignore major gc from different processes',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([
chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}),
v8EventsOtherProcess.start('majorGC', 1100, null),
@ -154,7 +159,7 @@ export function main() {
});
}));
it('should report major gc', inject([AsyncTestCompleter], (async) => {
it('should report major gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([
chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}),
v8Events.start('majorGC', 1100, null),
@ -172,7 +177,8 @@ export function main() {
}));
['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint'].forEach((recordType) => {
it(`should report ${recordType} as "render"`, inject([AsyncTestCompleter], (async) => {
it(`should report ${recordType} as "render"`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([
chromeTimelineEvents.start(recordType, 1234),
chromeTimelineEvents.end(recordType, 2345)
@ -188,7 +194,8 @@ export function main() {
}));
});
it('should ignore FunctionCalls from webdriver', inject([AsyncTestCompleter], (async) => {
it('should ignore FunctionCalls from webdriver',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineEvents.start(
'FunctionCall', 0, {'data': {'scriptName': 'InjectedScript'}})])
.readPerfLog()
@ -203,7 +210,7 @@ export function main() {
describe('readPerfLog Chrome45', () => {
it('should normalize times to ms and forward ph and pid event properties',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[chromeTimelineV8Events.complete('FunctionCall', 1100, 5500, null)],
CHROME45_USER_AGENT)
@ -216,8 +223,9 @@ export function main() {
});
}));
it('should normalize "tdur" to "dur"', inject([AsyncTestCompleter], (async) => {
var event = chromeTimelineV8Events.create('X', 'FunctionCall', 1100, null);
it('should normalize "tdur" to "dur"',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var event: any = chromeTimelineV8Events.create('X', 'FunctionCall', 1100, null);
event['tdur'] = 5500;
createExtension([event], CHROME45_USER_AGENT).readPerfLog().then((events) => {
expect(events).toEqual([
@ -227,7 +235,8 @@ export function main() {
});
}));
it('should report FunctionCall events as "script"', inject([AsyncTestCompleter], (async) => {
it('should report FunctionCall events as "script"',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineV8Events.start('FunctionCall', 0)], CHROME45_USER_AGENT)
.readPerfLog()
.then((events) => {
@ -238,7 +247,7 @@ export function main() {
});
}));
it('should report minor gc', inject([AsyncTestCompleter], (async) => {
it('should report minor gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[
chromeTimelineV8Events.start('MinorGC', 1000, {'usedHeapSizeBefore': 1000}),
@ -256,7 +265,7 @@ export function main() {
});
}));
it('should report major gc', inject([AsyncTestCompleter], (async) => {
it('should report major gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[
chromeTimelineV8Events.start('MajorGC', 1000, {'usedHeapSizeBefore': 1000}),
@ -275,7 +284,8 @@ export function main() {
}));
['Layout', 'UpdateLayerTree', 'Paint'].forEach((recordType) => {
it(`should report ${recordType} as "render"`, inject([AsyncTestCompleter], (async) => {
it(`should report ${recordType} as "render"`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[
chrome45TimelineEvents.start(recordType, 1234),
@ -293,7 +303,8 @@ export function main() {
}));
});
it(`should report UpdateLayoutTree as "render"`, inject([AsyncTestCompleter], (async) => {
it(`should report UpdateLayoutTree as "render"`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[
chromeBlinkTimelineEvents.start('UpdateLayoutTree', 1234),
@ -312,7 +323,8 @@ export function main() {
it('should ignore FunctionCalls from webdriver', inject([AsyncTestCompleter], (async) => {
it('should ignore FunctionCalls from webdriver',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineV8Events.start(
'FunctionCall', 0, {'data': {'scriptName': 'InjectedScript'}})])
.readPerfLog()
@ -323,7 +335,7 @@ export function main() {
}));
it('should ignore FunctionCalls with empty scriptName',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[chromeTimelineV8Events.start('FunctionCall', 0, {'data': {'scriptName': ''}})])
.readPerfLog()
@ -333,7 +345,8 @@ export function main() {
});
}));
it('should report navigationStart', inject([AsyncTestCompleter], (async) => {
it('should report navigationStart',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[chromeBlinkUserTimingEvents.start('navigationStart', 1234)], CHROME45_USER_AGENT)
.readPerfLog()
@ -343,7 +356,7 @@ export function main() {
});
}));
it('should report receivedData', inject([AsyncTestCompleter], (async) => {
it('should report receivedData', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[chrome45TimelineEvents.instant(
'ResourceReceivedData', 1234, {'data': {'encodedDataLength': 987}})],
@ -356,7 +369,7 @@ export function main() {
});
}));
it('should report sendRequest', inject([AsyncTestCompleter], (async) => {
it('should report sendRequest', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[chrome45TimelineEvents.instant(
'ResourceSendRequest', 1234,
@ -374,7 +387,7 @@ export function main() {
describe('readPerfLog (common)', () => {
it('should execute a dummy script before reading them',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
// TODO(tbosch): This seems to be a bug in ChromeDriver:
// Sometimes it does not report the newest events of the performance log
// to the WebDriver client unless a script is executed...
@ -385,7 +398,8 @@ export function main() {
}));
['Rasterize', 'CompositeLayers'].forEach((recordType) => {
it(`should report ${recordType} as "render"`, inject([AsyncTestCompleter], (async) => {
it(`should report ${recordType} as "render"`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[
chromeTimelineEvents.start(recordType, 1234),
@ -405,7 +419,7 @@ export function main() {
describe('frame metrics', () => {
it('should report ImplThreadRenderingStats as frame event',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([benchmarkEvents.instant(
'BenchmarkInstrumentation::ImplThreadRenderingStats', 1100,
{'data': {'frame_count': 1}})])
@ -419,7 +433,7 @@ export function main() {
}));
it('should not report ImplThreadRenderingStats with zero frames',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([benchmarkEvents.instant(
'BenchmarkInstrumentation::ImplThreadRenderingStats', 1100,
{'data': {'frame_count': 0}})])
@ -431,7 +445,7 @@ export function main() {
}));
it('should throw when ImplThreadRenderingStats contains more than one frame',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([benchmarkEvents.instant(
'BenchmarkInstrumentation::ImplThreadRenderingStats', 1100,
@ -447,7 +461,8 @@ export function main() {
});
it('should report begin timestamps', inject([AsyncTestCompleter], (async) => {
it('should report begin timestamps',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([blinkEvents.create('S', 'someName', 1000)])
.readPerfLog()
.then((events) => {
@ -456,7 +471,8 @@ export function main() {
});
}));
it('should report end timestamps', inject([AsyncTestCompleter], (async) => {
it('should report end timestamps',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([blinkEvents.create('F', 'someName', 1000)])
.readPerfLog()
.then((events) => {
@ -465,7 +481,8 @@ export function main() {
});
}));
it('should throw an error on buffer overflow', inject([AsyncTestCompleter], (async) => {
it('should throw an error on buffer overflow',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[
@ -497,12 +514,12 @@ class MockDriverAdapter extends WebDriverAdapter {
super();
}
executeScript(script) {
executeScript(script: string) {
this._log.push(['executeScript', script]);
return Promise.resolve(null);
}
logs(type) {
logs(type: string) {
this._log.push(['logs', type]);
if (type === 'performance') {
return Promise.resolve(this._events.map((event) => {

View File

@ -7,19 +7,19 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Json, isBlank, isPresent} from '@angular/facade/src/lang';
import {IOsDriverExtension, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from 'benchpress/common';
import {IOsDriverExtension, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
import {Json, isBlank, isPresent} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory';
export function main() {
describe('ios driver extension', () => {
var log;
var extension;
var log: any[];
var extension: IOsDriverExtension;
var normEvents = new TraceEventFactory('timeline', 'pid0');
function createExtension(perfRecords = null): WebDriverExtension {
function createExtension(perfRecords: any[] = null): WebDriverExtension {
if (isBlank(perfRecords)) {
perfRecords = [];
}
@ -38,14 +38,16 @@ export function main() {
expect(() => createExtension().gc()).toThrowError('Force GC is not supported on iOS');
});
it('should mark the timeline via console.time()', inject([AsyncTestCompleter], (async) => {
it('should mark the timeline via console.time()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeBegin('someName').then((_) => {
expect(log).toEqual([['executeScript', `console.time('someName');`]]);
async.done();
});
}));
it('should mark the timeline via console.timeEnd()', inject([AsyncTestCompleter], (async) => {
it('should mark the timeline via console.timeEnd()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeEnd('someName', null).then((_) => {
expect(log).toEqual([['executeScript', `console.timeEnd('someName');`]]);
async.done();
@ -53,7 +55,7 @@ export function main() {
}));
it('should mark the timeline via console.time() and console.timeEnd()',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeEnd('name1', 'name2').then((_) => {
expect(log).toEqual(
[['executeScript', `console.timeEnd('name1');console.time('name2');`]]);
@ -64,7 +66,7 @@ export function main() {
describe('readPerfLog', () => {
it('should execute a dummy script before reading them',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
// TODO(tbosch): This seems to be a bug in ChromeDriver:
// Sometimes it does not report the newest events of the performance log
// to the WebDriver client unless a script is executed...
@ -74,28 +76,31 @@ export function main() {
});
}));
it('should report FunctionCall records as "script"', inject([AsyncTestCompleter], (async) => {
it('should report FunctionCall records as "script"',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([durationRecord('FunctionCall', 1, 5)]).readPerfLog().then((events) => {
expect(events).toEqual([normEvents.start('script', 1), normEvents.end('script', 5)]);
async.done();
});
}));
it('should ignore FunctionCalls from webdriver', inject([AsyncTestCompleter], (async) => {
it('should ignore FunctionCalls from webdriver',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([internalScriptRecord(1, 5)]).readPerfLog().then((events) => {
expect(events).toEqual([]);
async.done();
});
}));
it('should report begin time', inject([AsyncTestCompleter], (async) => {
it('should report begin time', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([timeBeginRecord('someName', 12)]).readPerfLog().then((events) => {
expect(events).toEqual([normEvents.markStart('someName', 12)]);
async.done();
});
}));
it('should report end timestamps', inject([AsyncTestCompleter], (async) => {
it('should report end timestamps',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([timeEndRecord('someName', 12)]).readPerfLog().then((events) => {
expect(events).toEqual([normEvents.markEnd('someName', 12)]);
async.done();
@ -104,7 +109,8 @@ export function main() {
['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint', 'Rasterize', 'CompositeLayers']
.forEach((recordType) => {
it(`should report ${recordType}`, inject([AsyncTestCompleter], (async) => {
it(`should report ${recordType}`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([durationRecord(recordType, 0, 1)])
.readPerfLog()
.then((events) => {
@ -118,7 +124,7 @@ export function main() {
});
it('should walk children', inject([AsyncTestCompleter], (async) => {
it('should walk children', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([durationRecord('FunctionCall', 1, 5, [timeBeginRecord('someName', 2)])])
.readPerfLog()
.then((events) => {
@ -141,22 +147,22 @@ export function main() {
});
}
function timeBeginRecord(name, time) {
function timeBeginRecord(name: string, time: number) {
return {'type': 'Time', 'startTime': time, 'data': {'message': name}};
}
function timeEndRecord(name, time) {
function timeEndRecord(name: string, time: number) {
return {'type': 'TimeEnd', 'startTime': time, 'data': {'message': name}};
}
function durationRecord(type, startTime, endTime, children = null) {
function durationRecord(type: string, startTime: number, endTime: number, children: any[] = null) {
if (isBlank(children)) {
children = [];
}
return {'type': type, 'startTime': startTime, 'endTime': endTime, 'children': children};
}
function internalScriptRecord(startTime, endTime) {
function internalScriptRecord(startTime: number, endTime: number) {
return {
'type': 'FunctionCall',
'startTime': startTime,
@ -168,12 +174,12 @@ function internalScriptRecord(startTime, endTime) {
class MockDriverAdapter extends WebDriverAdapter {
constructor(private _log: any[], private _perfRecords: any[]) { super(); }
executeScript(script) {
executeScript(script: string) {
this._log.push(['executeScript', script]);
return Promise.resolve(null);
}
logs(type) {
logs(type: string) {
this._log.push(['logs', type]);
if (type === 'performance') {
return Promise.resolve(this._perfRecords.map(function(record) {

View File

@ -0,0 +1,26 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"lib": ["es6", "dom"],
"noImplicitAny": true,
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@angular/core": ["../../../dist/packages-dist/core"]
},
"experimentalDecorators": true,
"rootDir": ".",
"sourceRoot": ".",
"outDir": "../../../dist/packages-dist/benchpress",
"declaration": true
},
"exclude": ["integrationtest"],
"files": [
"index.ts",
"../../../node_modules/@types/node/index.d.ts",
"../../../node_modules/@types/jasmine/index.d.ts",
"../../node_modules/@types/protractor/index.d.ts",
"../../node_modules/@types/selenium-webdriver/index.d.ts"
]
}

View File

@ -1,23 +0,0 @@
{
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"experimentalDecorators": true,
"module": "commonjs",
"moduleResolution": "node",
"outDir": "../../dist/all/benchpress",
"noImplicitAny": false,
"noFallthroughCasesInSwitch": true,
"paths": {
"selenium-webdriver": ["../../node_modules/@types/selenium-webdriver/index.d.ts"],
"rxjs/*": ["../../node_modules/rxjs/*"],
"@angular/*": ["../../dist/all/@angular/*"],
"benchpress/*": ["./*"]
},
"rootDir": ".",
"inlineSourceMap": true,
"lib": ["es5", "dom", "es2015.promise", "es2015.collection", "es2015.iterable"],
"skipDefaultLibCheck": true,
"target": "es5"
}
}

View File

@ -1,14 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
// This file contains all ambient imports needed to compile the modules/ source code
/// <reference path="../../node_modules/@types/node/index.d.ts" />
/// <reference path="../../node_modules/@types/jasmine/index.d.ts" />
/// <reference path="../../node_modules/@types/protractor/index.d.ts" />
/// <reference path="../../node_modules/@types/selenium-webdriver/index.d.ts" />

View File

@ -28,7 +28,6 @@
"benchmarks/e2e_test/old",
"benchmarks/src/old",
"benchmarks_external",
"benchpress",
"payload_tests",
"rollup-test",
"@angular/compiler-cli/integrationtest"

View File

@ -72,7 +72,8 @@ if (platform == 'node') {
processOutputEmitterCodeGen,
[
'node', 'dist/tools/cjs-jasmine', '--', '@angular/**/*_spec.js',
'@angular/compiler-cli/test/**/*_spec.js'
'@angular/compiler-cli/test/**/*_spec.js',
'@angular/benchpress/test/**/*_spec.js'
]
]
},