fix(benchpress): make code compile and unit tests green again
This commit is contained in:
@ -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();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
1
modules/@angular/benchpress/src/facade
Symbolic link
1
modules/@angular/benchpress/src/facade
Symbolic link
@ -0,0 +1 @@
|
||||
../../facade/src
|
@ -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'});
|
||||
|
@ -1,3 +0,0 @@
|
||||
library benchpress.src.firefox_extension.lib.main;
|
||||
|
||||
//no dart implementation
|
@ -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));
|
||||
}
|
||||
});
|
||||
|
@ -1,3 +0,0 @@
|
||||
library benchpress.src.firefox_extension.lib.parser_util;
|
||||
|
||||
//no dart implementation
|
@ -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.
|
||||
|
@ -1,3 +0,0 @@
|
||||
library benchpress.src.firefox_extension.lib.test_helper;
|
||||
|
||||
//no dart implementation
|
@ -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);
|
||||
});
|
||||
|
@ -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(
|
||||
|
@ -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'); }
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)}
|
||||
];
|
||||
|
@ -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]
|
||||
}];
|
||||
|
@ -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> {
|
||||
|
@ -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}
|
||||
];
|
||||
|
@ -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: '.'}
|
||||
];
|
||||
|
@ -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)));
|
||||
|
@ -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},
|
||||
];
|
||||
|
@ -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
|
||||
]
|
||||
}];
|
||||
|
@ -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
|
||||
]
|
||||
}];
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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'}
|
||||
];
|
||||
|
@ -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}
|
||||
];
|
||||
|
@ -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'); }
|
||||
|
@ -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'); }
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
@ -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]
|
||||
}];
|
||||
|
@ -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]
|
||||
}];
|
||||
|
@ -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]
|
||||
}];
|
||||
|
@ -1,3 +0,0 @@
|
||||
library benchpress.src.webdriver.selenium_webdriver_adapter;
|
||||
|
||||
//no dart implementation
|
@ -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: []
|
||||
}];
|
||||
|
Reference in New Issue
Block a user