refactor(bench press): rename metrics and adapt them to the features of the browser
* Rename metrics, add `Time` suffix to all so that they are more consistent * iOS does not give us `gc` metrics, so they should not be reported * Rename `scriptMicroAvg` into `microScriptTimeAvg` * Rename previous `script` metric into `pureScriptTime` metric, and keep `scriptTime` metric as the overall time, so that we still have a shared metric across devices independent of the supported browser features * `microScriptTimeAvg` is now based on overall `scriptTime`, including gc and render time. * Move more shared DI tokens into `common_options` (previously `sample_options`). Closes #930
This commit is contained in:
parent
75ecaf02b9
commit
21a293b017
|
@ -1,14 +1,18 @@
|
||||||
import { bind } from 'angular2/di';
|
import { bind } from 'angular2/di';
|
||||||
import { JsonFileReporter } from './common';
|
import { Options } from './common';
|
||||||
|
|
||||||
export * from './common';
|
export * from './common';
|
||||||
export { SeleniumWebDriverAdapter } from './src/webdriver/selenium_webdriver_adapter';
|
export { SeleniumWebDriverAdapter } from './src/webdriver/selenium_webdriver_adapter';
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
|
||||||
// Note: Can't do the `require` call in a facade as it can't be loaded into the browser!
|
// TODO(tbosch): right now we bind the `writeFile` method
|
||||||
JsonFileReporter.BINDINGS.push(
|
// in benchpres/benchpress.es6. This does not work for Dart,
|
||||||
bind(JsonFileReporter.WRITE_FILE).toValue(writeFile)
|
// 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_BINDINGS.push(
|
||||||
|
bind(Options.WRITE_FILE).toValue(writeFile)
|
||||||
);
|
);
|
||||||
|
|
||||||
function writeFile(filename, content) {
|
function writeFile(filename, content) {
|
||||||
|
|
|
@ -2,7 +2,7 @@ export { Sampler, SampleState } from './src/sampler';
|
||||||
export { Metric } from './src/metric';
|
export { Metric } from './src/metric';
|
||||||
export { Validator } from './src/validator';
|
export { Validator } from './src/validator';
|
||||||
export { Reporter } from './src/reporter';
|
export { Reporter } from './src/reporter';
|
||||||
export { WebDriverExtension } from './src/web_driver_extension';
|
export { WebDriverExtension, PerfLogFeatures } from './src/web_driver_extension';
|
||||||
export { WebDriverAdapter } from './src/web_driver_adapter';
|
export { WebDriverAdapter } from './src/web_driver_adapter';
|
||||||
export { SizeValidator } from './src/validator/size_validator';
|
export { SizeValidator } from './src/validator/size_validator';
|
||||||
export { RegressionSlopeValidator } from './src/validator/regression_slope_validator';
|
export { RegressionSlopeValidator } from './src/validator/regression_slope_validator';
|
||||||
|
@ -13,7 +13,7 @@ export { PerflogMetric } from './src/metric/perflog_metric';
|
||||||
export { ChromeDriverExtension } from './src/webdriver/chrome_driver_extension';
|
export { ChromeDriverExtension } from './src/webdriver/chrome_driver_extension';
|
||||||
export { IOsDriverExtension } from './src/webdriver/ios_driver_extension';
|
export { IOsDriverExtension } from './src/webdriver/ios_driver_extension';
|
||||||
export { Runner } from './src/runner';
|
export { Runner } from './src/runner';
|
||||||
export { Options } from './src/sample_options';
|
export { Options } from './src/common_options';
|
||||||
export { MeasureValues } from './src/measure_values';
|
export { MeasureValues } from './src/measure_values';
|
||||||
export { MultiMetric } from './src/metric/multi_metric';
|
export { MultiMetric } from './src/metric/multi_metric';
|
||||||
export { MultiReporter } from './src/reporter/multi_reporter';
|
export { MultiReporter } from './src/reporter/multi_reporter';
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { bind, OpaqueToken } from 'angular2/di';
|
import { bind, OpaqueToken } from 'angular2/di';
|
||||||
|
import { DateWrapper } from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
export class Options {
|
export class Options {
|
||||||
|
static get DEFAULT_BINDINGS() { return _DEFAULT_BINDINGS; }
|
||||||
// TODO(tbosch): use static initializer when our transpiler supports it
|
// TODO(tbosch): use static initializer when our transpiler supports it
|
||||||
static get SAMPLE_ID() { return _SAMPLE_ID; }
|
static get SAMPLE_ID() { return _SAMPLE_ID; }
|
||||||
// TODO(tbosch): use static initializer when our transpiler supports it
|
// TODO(tbosch): use static initializer when our transpiler supports it
|
||||||
|
@ -23,6 +25,10 @@ export class Options {
|
||||||
* Used for micro benchmarks.
|
* Used for micro benchmarks.
|
||||||
**/
|
**/
|
||||||
static get MICRO_ITERATIONS() { return _MICRO_ITERATIONS; }
|
static get MICRO_ITERATIONS() { return _MICRO_ITERATIONS; }
|
||||||
|
// 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; }
|
||||||
}
|
}
|
||||||
|
|
||||||
var _SAMPLE_ID = new OpaqueToken('Options.sampleId');
|
var _SAMPLE_ID = new OpaqueToken('Options.sampleId');
|
||||||
|
@ -34,3 +40,13 @@ var _EXECUTE = new OpaqueToken('Options.execute');
|
||||||
var _CAPABILITIES = new OpaqueToken('Options.capabilities');
|
var _CAPABILITIES = new OpaqueToken('Options.capabilities');
|
||||||
var _USER_AGENT = new OpaqueToken('Options.userAgent');
|
var _USER_AGENT = new OpaqueToken('Options.userAgent');
|
||||||
var _MICRO_ITERATIONS = new OpaqueToken('Options.microIterations');
|
var _MICRO_ITERATIONS = new OpaqueToken('Options.microIterations');
|
||||||
|
var _NOW = new OpaqueToken('Options.now');
|
||||||
|
var _WRITE_FILE = new OpaqueToken('Options.writeFile');
|
||||||
|
|
||||||
|
var _DEFAULT_BINDINGS = [
|
||||||
|
bind(_DEFAULT_DESCRIPTION).toValue({}),
|
||||||
|
bind(_SAMPLE_DESCRIPTION).toValue({}),
|
||||||
|
bind(_FORCE_GC).toValue(false),
|
||||||
|
bind(_PREPARE).toValue(false),
|
||||||
|
bind(_NOW).toValue( () => DateWrapper.now() )
|
||||||
|
];
|
|
@ -3,9 +3,9 @@ import { isPresent, isBlank, int, BaseException, StringWrapper, Math } from 'ang
|
||||||
import { ListWrapper, StringMap, StringMapWrapper } from 'angular2/src/facade/collection';
|
import { ListWrapper, StringMap, StringMapWrapper } from 'angular2/src/facade/collection';
|
||||||
import { bind, OpaqueToken } from 'angular2/di';
|
import { bind, OpaqueToken } from 'angular2/di';
|
||||||
|
|
||||||
import { WebDriverExtension } from '../web_driver_extension';
|
import { WebDriverExtension, PerfLogFeatures } from '../web_driver_extension';
|
||||||
import { Metric } from '../metric';
|
import { Metric } from '../metric';
|
||||||
import { Options } from '../sample_options';
|
import { Options } from '../common_options';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A metric that reads out the performance log
|
* A metric that reads out the performance log
|
||||||
|
@ -21,6 +21,7 @@ export class PerflogMetric extends Metric {
|
||||||
_measureCount:int;
|
_measureCount:int;
|
||||||
_setTimeout:Function;
|
_setTimeout:Function;
|
||||||
_microIterations:int;
|
_microIterations:int;
|
||||||
|
_perfLogFeatures:PerfLogFeatures;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param driverExtension
|
* @param driverExtension
|
||||||
|
@ -35,19 +36,24 @@ export class PerflogMetric extends Metric {
|
||||||
this._measureCount = 0;
|
this._measureCount = 0;
|
||||||
this._setTimeout = setTimeout;
|
this._setTimeout = setTimeout;
|
||||||
this._microIterations = microIterations;
|
this._microIterations = microIterations;
|
||||||
|
this._perfLogFeatures = driverExtension.perfLogFeatures();
|
||||||
}
|
}
|
||||||
|
|
||||||
describe():StringMap {
|
describe():StringMap {
|
||||||
var res = {
|
var res = {
|
||||||
'script': 'script execution time in ms',
|
'scriptTime': 'script execution time in ms, including gc and render',
|
||||||
'render': 'render time in ms',
|
'pureScriptTime': 'script execution time in ms, without gc nor render'
|
||||||
'gcTime': 'gc time in ms',
|
|
||||||
'gcAmount': 'gc amount in kbytes',
|
|
||||||
'majorGcTime': 'time of major gcs in ms',
|
|
||||||
'majorGcAmount': 'amount of major gcs in kbytes'
|
|
||||||
};
|
};
|
||||||
|
if (this._perfLogFeatures.render) {
|
||||||
|
res['renderTime'] = 'render time in and ouside of script in ms';
|
||||||
|
}
|
||||||
|
if (this._perfLogFeatures.gc) {
|
||||||
|
res['gcTime'] = 'gc time in and ouside of script in ms';
|
||||||
|
res['gcAmount'] = 'gc amount in kbytes';
|
||||||
|
res['majorGcTime'] = 'time of major gcs in ms';
|
||||||
|
}
|
||||||
if (this._microIterations > 0) {
|
if (this._microIterations > 0) {
|
||||||
res['scriptMicroAvg'] = 'average script time for a micro iteration';
|
res['microScriptTimeAvg'] = 'average script time for a micro iteration';
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -120,17 +126,22 @@ export class PerflogMetric extends Metric {
|
||||||
|
|
||||||
_aggregateEvents(events, markName) {
|
_aggregateEvents(events, markName) {
|
||||||
var result = {
|
var result = {
|
||||||
'script': 0,
|
'scriptTime': 0,
|
||||||
'render': 0,
|
'pureScriptTime': 0
|
||||||
'gcTime': 0,
|
|
||||||
'gcAmount': 0,
|
|
||||||
'majorGcTime': 0,
|
|
||||||
'majorGcAmount': 0
|
|
||||||
};
|
};
|
||||||
|
if (this._perfLogFeatures.gc) {
|
||||||
|
result['gcTime'] = 0;
|
||||||
|
result['majorGcTime'] = 0;
|
||||||
|
result['gcAmount'] = 0;
|
||||||
|
}
|
||||||
|
if (this._perfLogFeatures.render) {
|
||||||
|
result['renderTime'] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
var markStartEvent = null;
|
var markStartEvent = null;
|
||||||
var markEndEvent = null;
|
var markEndEvent = null;
|
||||||
var gcTimeInScript = 0;
|
var gcTimeInScript = 0;
|
||||||
|
var renderTimeInScript = 0;
|
||||||
|
|
||||||
var intervalStarts = {};
|
var intervalStarts = {};
|
||||||
events.forEach( (event) => {
|
events.forEach( (event) => {
|
||||||
|
@ -149,26 +160,30 @@ export class PerflogMetric extends Metric {
|
||||||
var duration = event['ts'] - startEvent['ts'];
|
var duration = event['ts'] - startEvent['ts'];
|
||||||
intervalStarts[name] = null;
|
intervalStarts[name] = null;
|
||||||
if (StringWrapper.equals(name, 'gc')) {
|
if (StringWrapper.equals(name, 'gc')) {
|
||||||
var amount = (startEvent['args']['usedHeapSize'] - event['args']['usedHeapSize']) / 1000;
|
|
||||||
result['gcTime'] += duration;
|
result['gcTime'] += duration;
|
||||||
|
var amount = (startEvent['args']['usedHeapSize'] - event['args']['usedHeapSize']) / 1000;
|
||||||
result['gcAmount'] += amount;
|
result['gcAmount'] += amount;
|
||||||
var majorGc = event['args']['majorGc'];
|
var majorGc = event['args']['majorGc'];
|
||||||
if (isPresent(majorGc) && majorGc) {
|
if (isPresent(majorGc) && majorGc) {
|
||||||
result['majorGcTime'] += duration;
|
result['majorGcTime'] += duration;
|
||||||
result['majorGcAmount'] += amount;
|
|
||||||
}
|
}
|
||||||
if (isPresent(intervalStarts['script'])) {
|
if (isPresent(intervalStarts['script'])) {
|
||||||
gcTimeInScript += duration;
|
gcTimeInScript += duration;
|
||||||
}
|
}
|
||||||
} else if (StringWrapper.equals(name, 'script') || StringWrapper.equals(name, 'render')) {
|
} else if (StringWrapper.equals(name, 'render')) {
|
||||||
result[name] += duration;
|
result['renderTime'] += duration;
|
||||||
|
if (isPresent(intervalStarts['script'])) {
|
||||||
|
renderTimeInScript += duration;
|
||||||
|
}
|
||||||
|
} else if (StringWrapper.equals(name, 'script')) {
|
||||||
|
result['scriptTime'] += duration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
result['script'] -= gcTimeInScript;
|
result['pureScriptTime'] = result['scriptTime'] - gcTimeInScript - renderTimeInScript;
|
||||||
if (this._microIterations > 0) {
|
if (this._microIterations > 0) {
|
||||||
result['scriptMicroAvg'] = result['script'] / this._microIterations;
|
result['microScriptTimeAvg'] = result['scriptTime'] / this._microIterations;
|
||||||
}
|
}
|
||||||
return isPresent(markStartEvent) && isPresent(markEndEvent) ? result : null;
|
return isPresent(markStartEvent) && isPresent(markEndEvent) ? result : null;
|
||||||
}
|
}
|
||||||
|
@ -183,7 +198,8 @@ var _MARK_NAME_PREFIX = 'benchpress';
|
||||||
var _SET_TIMEOUT = new OpaqueToken('PerflogMetric.setTimeout');
|
var _SET_TIMEOUT = new OpaqueToken('PerflogMetric.setTimeout');
|
||||||
var _BINDINGS = [
|
var _BINDINGS = [
|
||||||
bind(PerflogMetric).toFactory(
|
bind(PerflogMetric).toFactory(
|
||||||
(driverExtension, setTimeout, microIterations) => new PerflogMetric(driverExtension, setTimeout, microIterations),
|
(driverExtension, setTimeout, microIterations) =>
|
||||||
|
new PerflogMetric(driverExtension, setTimeout, microIterations),
|
||||||
[WebDriverExtension, _SET_TIMEOUT, Options.MICRO_ITERATIONS]
|
[WebDriverExtension, _SET_TIMEOUT, Options.MICRO_ITERATIONS]
|
||||||
),
|
),
|
||||||
bind(_SET_TIMEOUT).toValue( (fn, millis) => PromiseWrapper.setTimeout(fn, millis) ),
|
bind(_SET_TIMEOUT).toValue( (fn, millis) => PromiseWrapper.setTimeout(fn, millis) ),
|
||||||
|
|
|
@ -7,16 +7,12 @@ import { bind, OpaqueToken } from 'angular2/di';
|
||||||
import { Reporter } from '../reporter';
|
import { Reporter } from '../reporter';
|
||||||
import { SampleDescription } from '../sample_description';
|
import { SampleDescription } from '../sample_description';
|
||||||
import { MeasureValues } from '../measure_values';
|
import { MeasureValues } from '../measure_values';
|
||||||
|
import { Options } from '../common_options';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A reporter that writes results into a json file.
|
* A reporter that writes results into a json file.
|
||||||
* TODO(tbosch): right now we bind the `writeFile` method
|
|
||||||
* in benchpres/benchpress.es6. This does not work for Dart,
|
|
||||||
* find another way...
|
|
||||||
*/
|
*/
|
||||||
export class JsonFileReporter extends Reporter {
|
export class JsonFileReporter extends Reporter {
|
||||||
// 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
|
// TODO(tbosch): use static values when our transpiler supports them
|
||||||
static get PATH() { return _PATH; }
|
static get PATH() { return _PATH; }
|
||||||
static get BINDINGS() { return _BINDINGS; }
|
static get BINDINGS() { return _BINDINGS; }
|
||||||
|
@ -24,12 +20,14 @@ export class JsonFileReporter extends Reporter {
|
||||||
_writeFile:Function;
|
_writeFile:Function;
|
||||||
_path:string;
|
_path:string;
|
||||||
_description:SampleDescription;
|
_description:SampleDescription;
|
||||||
|
_now:Function;
|
||||||
|
|
||||||
constructor(sampleDescription, path, writeFile) {
|
constructor(sampleDescription, path, writeFile, now) {
|
||||||
super();
|
super();
|
||||||
this._description = sampleDescription;
|
this._description = sampleDescription;
|
||||||
this._path = path;
|
this._path = path;
|
||||||
this._writeFile = writeFile;
|
this._writeFile = writeFile;
|
||||||
|
this._now = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
reportMeasureValues(measureValues:MeasureValues):Promise {
|
reportMeasureValues(measureValues:MeasureValues):Promise {
|
||||||
|
@ -42,17 +40,16 @@ export class JsonFileReporter extends Reporter {
|
||||||
'completeSample': completeSample,
|
'completeSample': completeSample,
|
||||||
'validSample': validSample
|
'validSample': validSample
|
||||||
});
|
});
|
||||||
var filePath = `${this._path}/${this._description.id}_${DateWrapper.toMillis(DateWrapper.now())}.json`;
|
var filePath = `${this._path}/${this._description.id}_${DateWrapper.toMillis(this._now())}.json`;
|
||||||
return this._writeFile(filePath, content);
|
return this._writeFile(filePath, content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _WRITE_FILE = new OpaqueToken('JsonFileReporter.writeFile');
|
|
||||||
var _PATH = new OpaqueToken('JsonFileReporter.path');
|
var _PATH = new OpaqueToken('JsonFileReporter.path');
|
||||||
var _BINDINGS = [
|
var _BINDINGS = [
|
||||||
bind(JsonFileReporter).toFactory(
|
bind(JsonFileReporter).toFactory(
|
||||||
(sampleDescription, path, writeFile) => new JsonFileReporter(sampleDescription, path, writeFile),
|
(sampleDescription, path, writeFile, now) => new JsonFileReporter(sampleDescription, path, writeFile, now),
|
||||||
[SampleDescription, _PATH, _WRITE_FILE]
|
[SampleDescription, _PATH, Options.WRITE_FILE, Options.NOW]
|
||||||
),
|
),
|
||||||
bind(_PATH).toValue('.')
|
bind(_PATH).toValue('.')
|
||||||
];
|
];
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { SampleDescription } from './sample_description';
|
||||||
import { WebDriverAdapter } from './web_driver_adapter';
|
import { WebDriverAdapter } from './web_driver_adapter';
|
||||||
import { Reporter } from './reporter';
|
import { Reporter } from './reporter';
|
||||||
import { Metric } from './metric';
|
import { Metric } from './metric';
|
||||||
import { Options } from './sample_options';
|
import { Options } from './common_options';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Runner is the main entry point for executing a sample run.
|
* The Runner is the main entry point for executing a sample run.
|
||||||
|
@ -56,6 +56,7 @@ export class Runner {
|
||||||
}
|
}
|
||||||
|
|
||||||
var _DEFAULT_BINDINGS = [
|
var _DEFAULT_BINDINGS = [
|
||||||
|
Options.DEFAULT_BINDINGS,
|
||||||
Sampler.BINDINGS,
|
Sampler.BINDINGS,
|
||||||
ConsoleReporter.BINDINGS,
|
ConsoleReporter.BINDINGS,
|
||||||
RegressionSlopeValidator.BINDINGS,
|
RegressionSlopeValidator.BINDINGS,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { StringMapWrapper, ListWrapper, StringMap } from 'angular2/src/facade/co
|
||||||
import { bind, OpaqueToken } from 'angular2/di';
|
import { bind, OpaqueToken } from 'angular2/di';
|
||||||
import { Validator } from './validator';
|
import { Validator } from './validator';
|
||||||
import { Metric } from './metric';
|
import { Metric } from './metric';
|
||||||
import { Options } from './sample_options';
|
import { Options } from './common_options';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SampleDescription merges all available descriptions about a sample
|
* SampleDescription merges all available descriptions about a sample
|
||||||
|
@ -47,7 +47,5 @@ var _BINDINGS = [
|
||||||
Metric, Options.SAMPLE_ID, Options.FORCE_GC, Options.USER_AGENT,
|
Metric, Options.SAMPLE_ID, Options.FORCE_GC, Options.USER_AGENT,
|
||||||
Validator, Options.DEFAULT_DESCRIPTION, Options.SAMPLE_DESCRIPTION
|
Validator, Options.DEFAULT_DESCRIPTION, Options.SAMPLE_DESCRIPTION
|
||||||
]
|
]
|
||||||
),
|
)
|
||||||
bind(Options.DEFAULT_DESCRIPTION).toValue({}),
|
|
||||||
bind(Options.SAMPLE_DESCRIPTION).toValue({})
|
|
||||||
];
|
];
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { Reporter } from './reporter';
|
||||||
import { WebDriverExtension } from './web_driver_extension';
|
import { WebDriverExtension } from './web_driver_extension';
|
||||||
import { WebDriverAdapter } from './web_driver_adapter';
|
import { WebDriverAdapter } from './web_driver_adapter';
|
||||||
|
|
||||||
import { Options } from './sample_options';
|
import { Options } from './common_options';
|
||||||
import { MeasureValues} from './measure_values';
|
import { MeasureValues} from './measure_values';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,8 +23,6 @@ import { MeasureValues} from './measure_values';
|
||||||
export class Sampler {
|
export class Sampler {
|
||||||
// TODO(tbosch): use static values when our transpiler supports them
|
// TODO(tbosch): use static values when our transpiler supports them
|
||||||
static get BINDINGS() { return _BINDINGS; }
|
static get BINDINGS() { return _BINDINGS; }
|
||||||
// TODO(tbosch): use static values when our transpiler supports them
|
|
||||||
static get TIME() { return _TIME; }
|
|
||||||
|
|
||||||
_driver:WebDriverAdapter;
|
_driver:WebDriverAdapter;
|
||||||
_driverExtension:WebDriverExtension;
|
_driverExtension:WebDriverExtension;
|
||||||
|
@ -34,14 +32,14 @@ export class Sampler {
|
||||||
_forceGc:boolean;
|
_forceGc:boolean;
|
||||||
_prepare:Function;
|
_prepare:Function;
|
||||||
_execute:Function;
|
_execute:Function;
|
||||||
_time:Function;
|
_now:Function;
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
driver, driverExtension, metric, reporter, validator, forceGc, prepare, execute, time
|
driver, driverExtension, metric, reporter, validator, forceGc, prepare, execute, now
|
||||||
}:{
|
}:{
|
||||||
driver: WebDriverAdapter,
|
driver: WebDriverAdapter,
|
||||||
driverExtension: WebDriverExtension, metric: Metric, reporter: Reporter,
|
driverExtension: WebDriverExtension, metric: Metric, reporter: Reporter,
|
||||||
validator: Validator, prepare: Function, execute: Function, time: Function
|
validator: Validator, prepare: Function, execute: Function, now: Function
|
||||||
}={}) {
|
}={}) {
|
||||||
this._driver = driver;
|
this._driver = driver;
|
||||||
this._driverExtension = driverExtension;
|
this._driverExtension = driverExtension;
|
||||||
|
@ -51,7 +49,7 @@ export class Sampler {
|
||||||
this._forceGc = forceGc;
|
this._forceGc = forceGc;
|
||||||
this._prepare = prepare;
|
this._prepare = prepare;
|
||||||
this._execute = execute;
|
this._execute = execute;
|
||||||
this._time = time;
|
this._now = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
sample():Promise<SampleState> {
|
sample():Promise<SampleState> {
|
||||||
|
@ -96,7 +94,7 @@ export class Sampler {
|
||||||
}
|
}
|
||||||
|
|
||||||
_report(state:SampleState, metricValues:StringMap):Promise<SampleState> {
|
_report(state:SampleState, metricValues:StringMap):Promise<SampleState> {
|
||||||
var measureValues = new MeasureValues(state.completeSample.length, this._time(), metricValues);
|
var measureValues = new MeasureValues(state.completeSample.length, this._now(), metricValues);
|
||||||
var completeSample = ListWrapper.concat(state.completeSample, [measureValues]);
|
var completeSample = ListWrapper.concat(state.completeSample, [measureValues]);
|
||||||
var validSample = this._validator.validate(completeSample);
|
var validSample = this._validator.validate(completeSample);
|
||||||
var resultPromise = this._reporter.reportMeasureValues(measureValues);
|
var resultPromise = this._reporter.reportMeasureValues(measureValues);
|
||||||
|
@ -118,11 +116,9 @@ export class SampleState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _TIME = new OpaqueToken('Sampler.time');
|
|
||||||
|
|
||||||
var _BINDINGS = [
|
var _BINDINGS = [
|
||||||
bind(Sampler).toFactory(
|
bind(Sampler).toFactory(
|
||||||
(driver, driverExtension, metric, reporter, validator, forceGc, prepare, execute, time) => new Sampler({
|
(driver, driverExtension, metric, reporter, validator, forceGc, prepare, execute, now) => new Sampler({
|
||||||
driver: driver,
|
driver: driver,
|
||||||
driverExtension: driverExtension,
|
driverExtension: driverExtension,
|
||||||
reporter: reporter,
|
reporter: reporter,
|
||||||
|
@ -134,14 +130,11 @@ var _BINDINGS = [
|
||||||
// special null object, which is expensive.
|
// special null object, which is expensive.
|
||||||
prepare: prepare !== false ? prepare : null,
|
prepare: prepare !== false ? prepare : null,
|
||||||
execute: execute,
|
execute: execute,
|
||||||
time: time
|
now: now
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
WebDriverAdapter, WebDriverExtension, Metric, Reporter, Validator,
|
WebDriverAdapter, WebDriverExtension, Metric, Reporter, Validator,
|
||||||
Options.FORCE_GC, Options.PREPARE, Options.EXECUTE, _TIME
|
Options.FORCE_GC, Options.PREPARE, Options.EXECUTE, Options.NOW
|
||||||
]
|
]
|
||||||
),
|
)
|
||||||
bind(Options.FORCE_GC).toValue(false),
|
|
||||||
bind(Options.PREPARE).toValue(false),
|
|
||||||
bind(_TIME).toValue( () => DateWrapper.now() )
|
|
||||||
];
|
];
|
||||||
|
|
|
@ -65,5 +65,5 @@ var _BINDINGS = [
|
||||||
[_SAMPLE_SIZE, _METRIC]
|
[_SAMPLE_SIZE, _METRIC]
|
||||||
),
|
),
|
||||||
bind(_SAMPLE_SIZE).toValue(10),
|
bind(_SAMPLE_SIZE).toValue(10),
|
||||||
bind(_METRIC).toValue('script')
|
bind(_METRIC).toValue('scriptTime')
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { bind, Injector, OpaqueToken } from 'angular2/di';
|
import { bind, Injector, OpaqueToken } from 'angular2/di';
|
||||||
|
|
||||||
import { BaseException, ABSTRACT, isBlank } from 'angular2/src/facade/lang';
|
import { BaseException, ABSTRACT, isBlank, isPresent } from 'angular2/src/facade/lang';
|
||||||
import { Promise, PromiseWrapper } from 'angular2/src/facade/async';
|
import { Promise, PromiseWrapper } from 'angular2/src/facade/async';
|
||||||
import { List, ListWrapper, StringMap } from 'angular2/src/facade/collection';
|
import { List, ListWrapper, StringMap } from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
import { Options } from './sample_options';
|
import { Options } from './common_options';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A WebDriverExtension implements extended commands of the webdriver protocol
|
* A WebDriverExtension implements extended commands of the webdriver protocol
|
||||||
|
@ -64,9 +64,23 @@ export class WebDriverExtension {
|
||||||
throw new BaseException('NYI');
|
throw new BaseException('NYI');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
perfLogFeatures():PerfLogFeatures {
|
||||||
|
throw new BaseException('NYI');
|
||||||
|
}
|
||||||
|
|
||||||
supports(capabilities:StringMap):boolean {
|
supports(capabilities:StringMap):boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class PerfLogFeatures {
|
||||||
|
render:boolean;
|
||||||
|
gc:boolean;
|
||||||
|
|
||||||
|
constructor({render, gc} = {}) {
|
||||||
|
this.render = isPresent(render) && render;
|
||||||
|
this.gc = isPresent(gc) && gc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var _CHILDREN = new OpaqueToken('WebDriverExtension.children');
|
var _CHILDREN = new OpaqueToken('WebDriverExtension.children');
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
Json, isPresent, isBlank, RegExpWrapper, StringWrapper, BaseException, NumberWrapper
|
Json, isPresent, isBlank, RegExpWrapper, StringWrapper, BaseException, NumberWrapper
|
||||||
} from 'angular2/src/facade/lang';
|
} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
import { WebDriverExtension } from '../web_driver_extension';
|
import { WebDriverExtension, PerfLogFeatures } from '../web_driver_extension';
|
||||||
import { WebDriverAdapter } from '../web_driver_adapter';
|
import { WebDriverAdapter } from '../web_driver_adapter';
|
||||||
import { Promise } from 'angular2/src/facade/async';
|
import { Promise } from 'angular2/src/facade/async';
|
||||||
|
|
||||||
|
@ -111,6 +111,13 @@ export class ChromeDriverExtension extends WebDriverExtension {
|
||||||
return normalizedEvents;
|
return normalizedEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
perfLogFeatures():PerfLogFeatures {
|
||||||
|
return new PerfLogFeatures({
|
||||||
|
render: true,
|
||||||
|
gc: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
supports(capabilities:StringMap):boolean {
|
supports(capabilities:StringMap):boolean {
|
||||||
return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'chrome');
|
return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'chrome');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { bind } from 'angular2/di';
|
import { bind } from 'angular2/di';
|
||||||
import { ListWrapper, StringMap } from 'angular2/src/facade/collection';
|
import { ListWrapper, StringMap } from 'angular2/src/facade/collection';
|
||||||
import {
|
import {
|
||||||
Json, isPresent, isBlank, RegExpWrapper, StringWrapper
|
Json, isPresent, isBlank, RegExpWrapper, StringWrapper, BaseException
|
||||||
} from 'angular2/src/facade/lang';
|
} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
import { WebDriverExtension } from '../web_driver_extension';
|
import { WebDriverExtension, PerfLogFeatures } from '../web_driver_extension';
|
||||||
import { WebDriverAdapter } from '../web_driver_adapter';
|
import { WebDriverAdapter } from '../web_driver_adapter';
|
||||||
import { Promise } from 'angular2/src/facade/async';
|
import { Promise } from 'angular2/src/facade/async';
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ export class IOsDriverExtension extends WebDriverExtension {
|
||||||
}
|
}
|
||||||
|
|
||||||
gc() {
|
gc() {
|
||||||
return this._driver.executeScript('window.gc()');
|
throw new BaseException('Force GC is not supported on iOS');
|
||||||
}
|
}
|
||||||
|
|
||||||
timeBegin(name:string):Promise {
|
timeBegin(name:string):Promise {
|
||||||
|
@ -81,14 +81,8 @@ export class IOsDriverExtension extends WebDriverExtension {
|
||||||
StringWrapper.equals(type, 'CompositeLayers')) {
|
StringWrapper.equals(type, 'CompositeLayers')) {
|
||||||
ListWrapper.push(events, createStartEvent('render', startTime));
|
ListWrapper.push(events, createStartEvent('render', startTime));
|
||||||
endEvent = createEndEvent('render', endTime);
|
endEvent = createEndEvent('render', endTime);
|
||||||
} else if (StringWrapper.equals(type, 'GCEvent')) {
|
|
||||||
ListWrapper.push(events, createStartEvent('gc', startTime, {
|
|
||||||
'usedHeapSize': 0
|
|
||||||
}));
|
|
||||||
endEvent = createEndEvent('gc', endTime, {
|
|
||||||
'usedHeapSize': -data['usedHeapSizeDelta']
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
// Note: ios used to support GCEvent up until iOS 6 :-(
|
||||||
if (isPresent(record['children'])) {
|
if (isPresent(record['children'])) {
|
||||||
this._convertPerfRecordsToEvents(record['children'], events);
|
this._convertPerfRecordsToEvents(record['children'], events);
|
||||||
}
|
}
|
||||||
|
@ -99,6 +93,12 @@ export class IOsDriverExtension extends WebDriverExtension {
|
||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
perfLogFeatures():PerfLogFeatures {
|
||||||
|
return new PerfLogFeatures({
|
||||||
|
render: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
supports(capabilities:StringMap):boolean {
|
supports(capabilities:StringMap):boolean {
|
||||||
return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'safari');
|
return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'safari');
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,13 @@ import {
|
||||||
|
|
||||||
import { List, ListWrapper } from 'angular2/src/facade/collection';
|
import { List, ListWrapper } from 'angular2/src/facade/collection';
|
||||||
import { PromiseWrapper, Promise } from 'angular2/src/facade/async';
|
import { PromiseWrapper, Promise } from 'angular2/src/facade/async';
|
||||||
import { isPresent } from 'angular2/src/facade/lang';
|
import { isPresent, isBlank } from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
import { Metric, PerflogMetric, WebDriverExtension, bind, Injector, Options } from 'benchpress/common';
|
import {
|
||||||
|
Metric, PerflogMetric, WebDriverExtension,
|
||||||
|
PerfLogFeatures,
|
||||||
|
bind, Injector, Options
|
||||||
|
} from 'benchpress/common';
|
||||||
|
|
||||||
import { TraceEventFactory } from '../trace_event_factory';
|
import { TraceEventFactory } from '../trace_event_factory';
|
||||||
|
|
||||||
|
@ -23,15 +27,19 @@ export function main() {
|
||||||
var commandLog;
|
var commandLog;
|
||||||
var eventFactory = new TraceEventFactory('timeline', 'pid0');
|
var eventFactory = new TraceEventFactory('timeline', 'pid0');
|
||||||
|
|
||||||
function createMetric(perfLogs, microIterations = 0) {
|
function createMetric(perfLogs, microIterations = 0, perfLogFeatures = null) {
|
||||||
commandLog = [];
|
commandLog = [];
|
||||||
|
if (isBlank(perfLogFeatures)) {
|
||||||
|
perfLogFeatures = new PerfLogFeatures({render: true, gc: true});
|
||||||
|
}
|
||||||
var bindings = [
|
var bindings = [
|
||||||
|
Options.DEFAULT_BINDINGS,
|
||||||
PerflogMetric.BINDINGS,
|
PerflogMetric.BINDINGS,
|
||||||
bind(PerflogMetric.SET_TIMEOUT).toValue( (fn, millis) => {
|
bind(PerflogMetric.SET_TIMEOUT).toValue( (fn, millis) => {
|
||||||
ListWrapper.push(commandLog, ['setTimeout', millis]);
|
ListWrapper.push(commandLog, ['setTimeout', millis]);
|
||||||
fn();
|
fn();
|
||||||
}),
|
}),
|
||||||
bind(WebDriverExtension).toValue(new MockDriverExtension(perfLogs, commandLog)),
|
bind(WebDriverExtension).toValue(new MockDriverExtension(perfLogs, commandLog, perfLogFeatures)),
|
||||||
bind(Options.MICRO_ITERATIONS).toValue(microIterations)
|
bind(Options.MICRO_ITERATIONS).toValue(microIterations)
|
||||||
];
|
];
|
||||||
return new Injector(bindings).get(PerflogMetric);
|
return new Injector(bindings).get(PerflogMetric);
|
||||||
|
@ -39,8 +47,29 @@ export function main() {
|
||||||
|
|
||||||
describe('perflog metric', () => {
|
describe('perflog metric', () => {
|
||||||
|
|
||||||
it('should describe itself', () => {
|
it('should describe itself based on the perfLogFeatrues', () => {
|
||||||
expect(createMetric([[]]).describe()['script']).toBe('script execution time in ms');
|
expect(createMetric([[]], 0, new PerfLogFeatures()).describe()).toEqual({
|
||||||
|
'scriptTime': 'script execution time in ms, including gc and render',
|
||||||
|
'pureScriptTime': 'script execution time in ms, without gc nor render'
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(createMetric([[]], 0, new PerfLogFeatures({
|
||||||
|
render: true,
|
||||||
|
gc: false
|
||||||
|
})).describe()).toEqual({
|
||||||
|
'scriptTime': 'script execution time in ms, including gc and render',
|
||||||
|
'pureScriptTime': 'script execution time in ms, without gc nor render',
|
||||||
|
'renderTime': 'render time in and ouside of script in ms',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(createMetric([[]]).describe()).toEqual({
|
||||||
|
'scriptTime': 'script execution time in ms, including gc and render',
|
||||||
|
'pureScriptTime': 'script execution time in ms, without gc nor render',
|
||||||
|
'renderTime': 'render time in and ouside of script in ms',
|
||||||
|
'gcTime': 'gc time in and ouside of script in ms',
|
||||||
|
'gcAmount': 'gc amount in kbytes',
|
||||||
|
'majorGcTime': 'time of major gcs in ms'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('beginMeasure', () => {
|
describe('beginMeasure', () => {
|
||||||
|
@ -76,7 +105,7 @@ export function main() {
|
||||||
['timeEnd', 'benchpress0', null],
|
['timeEnd', 'benchpress0', null],
|
||||||
'readPerfLog'
|
'readPerfLog'
|
||||||
]);
|
]);
|
||||||
expect(data['script']).toBe(2);
|
expect(data['scriptTime']).toBe(2);
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -128,7 +157,7 @@ export function main() {
|
||||||
[ 'setTimeout', 100 ],
|
[ 'setTimeout', 100 ],
|
||||||
'readPerfLog'
|
'readPerfLog'
|
||||||
]);
|
]);
|
||||||
expect(data['script']).toBe(3);
|
expect(data['scriptTime']).toBe(3);
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -144,7 +173,7 @@ export function main() {
|
||||||
metric.beginMeasure()
|
metric.beginMeasure()
|
||||||
.then( (_) => metric.endMeasure(true) )
|
.then( (_) => metric.endMeasure(true) )
|
||||||
.then( (data) => {
|
.then( (data) => {
|
||||||
expect(data['script']).toBe(0);
|
expect(data['scriptTime']).toBe(0);
|
||||||
return metric.endMeasure(true)
|
return metric.endMeasure(true)
|
||||||
})
|
})
|
||||||
.then( (data) => {
|
.then( (data) => {
|
||||||
|
@ -155,7 +184,7 @@ export function main() {
|
||||||
['timeEnd', 'benchpress1', 'benchpress2'],
|
['timeEnd', 'benchpress1', 'benchpress2'],
|
||||||
'readPerfLog'
|
'readPerfLog'
|
||||||
]);
|
]);
|
||||||
expect(data['script']).toBe(3);
|
expect(data['scriptTime']).toBe(3);
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -179,7 +208,7 @@ export function main() {
|
||||||
eventFactory.start('script', 0),
|
eventFactory.start('script', 0),
|
||||||
eventFactory.end('script', 5)
|
eventFactory.end('script', 5)
|
||||||
]).then((data) => {
|
]).then((data) => {
|
||||||
expect(data['script']).toBe(5);
|
expect(data['scriptTime']).toBe(5);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -191,7 +220,7 @@ export function main() {
|
||||||
eventFactory.start('script', 10),
|
eventFactory.start('script', 10),
|
||||||
eventFactory.end('script', 17)
|
eventFactory.end('script', 17)
|
||||||
]).then((data) => {
|
]).then((data) => {
|
||||||
expect(data['script']).toBe(12);
|
expect(data['scriptTime']).toBe(12);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -200,7 +229,7 @@ export function main() {
|
||||||
aggregate([
|
aggregate([
|
||||||
eventFactory.end('script', 10)
|
eventFactory.end('script', 10)
|
||||||
]).then((data) => {
|
]).then((data) => {
|
||||||
expect(data['script']).toBe(0);
|
expect(data['scriptTime']).toBe(0);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -209,7 +238,7 @@ export function main() {
|
||||||
aggregate([
|
aggregate([
|
||||||
eventFactory.start('script', 10)
|
eventFactory.start('script', 10)
|
||||||
]).then((data) => {
|
]).then((data) => {
|
||||||
expect(data['script']).toBe(0);
|
expect(data['scriptTime']).toBe(0);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -227,22 +256,30 @@ export function main() {
|
||||||
metric.beginMeasure()
|
metric.beginMeasure()
|
||||||
.then( (_) => metric.endMeasure(false) )
|
.then( (_) => metric.endMeasure(false) )
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
expect(data['script']).toBe(5);
|
expect(data['scriptTime']).toBe(5);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
['script', 'render'].forEach( (metricName) => {
|
it('should support scriptTime metric', inject([AsyncTestCompleter], (async) => {
|
||||||
it(`should support ${metricName} metric`, inject([AsyncTestCompleter], (async) => {
|
aggregate([
|
||||||
aggregate([
|
eventFactory.start('script', 0),
|
||||||
eventFactory.start(metricName, 0),
|
eventFactory.end('script', 5)
|
||||||
eventFactory.end(metricName, 5)
|
]).then((data) => {
|
||||||
]).then((data) => {
|
expect(data['scriptTime']).toBe(5);
|
||||||
expect(data[metricName]).toBe(5);
|
async.done();
|
||||||
async.done();
|
});
|
||||||
});
|
}));
|
||||||
}));
|
|
||||||
});
|
it('should support renderTime metric', inject([AsyncTestCompleter], (async) => {
|
||||||
|
aggregate([
|
||||||
|
eventFactory.start('render', 0),
|
||||||
|
eventFactory.end('render', 5)
|
||||||
|
]).then((data) => {
|
||||||
|
expect(data['renderTime']).toBe(5);
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
it('should support gcTime/gcAmount metric', inject([AsyncTestCompleter], (async) => {
|
it('should support gcTime/gcAmount metric', inject([AsyncTestCompleter], (async) => {
|
||||||
aggregate([
|
aggregate([
|
||||||
|
@ -252,55 +289,55 @@ export function main() {
|
||||||
expect(data['gcTime']).toBe(5);
|
expect(data['gcTime']).toBe(5);
|
||||||
expect(data['gcAmount']).toBe(1.5);
|
expect(data['gcAmount']).toBe(1.5);
|
||||||
expect(data['majorGcTime']).toBe(0);
|
expect(data['majorGcTime']).toBe(0);
|
||||||
expect(data['majorGcAmount']).toBe(0);
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should support majorGcTime/majorGcAmount metric', inject([AsyncTestCompleter], (async) => {
|
it('should support majorGcTime metric', inject([AsyncTestCompleter], (async) => {
|
||||||
aggregate([
|
aggregate([
|
||||||
eventFactory.start('gc', 0, {'usedHeapSize': 2500}),
|
eventFactory.start('gc', 0, {'usedHeapSize': 2500}),
|
||||||
eventFactory.end('gc', 5, {'usedHeapSize': 1000, 'majorGc': true})
|
eventFactory.end('gc', 5, {'usedHeapSize': 1000, 'majorGc': true})
|
||||||
]).then((data) => {
|
]).then((data) => {
|
||||||
expect(data['gcTime']).toBe(5);
|
expect(data['gcTime']).toBe(5);
|
||||||
expect(data['gcAmount']).toBe(1.5);
|
|
||||||
expect(data['majorGcTime']).toBe(5);
|
expect(data['majorGcTime']).toBe(5);
|
||||||
expect(data['majorGcAmount']).toBe(1.5);
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should subtract gcTime in script from script time', inject([AsyncTestCompleter], (async) => {
|
it('should support pureScriptTime = scriptTime-gcTime-renderTime', inject([AsyncTestCompleter], (async) => {
|
||||||
aggregate([
|
aggregate([
|
||||||
eventFactory.start('script', 0),
|
eventFactory.start('script', 0),
|
||||||
eventFactory.start('gc', 1, {'usedHeapSize': 1000}),
|
eventFactory.start('gc', 1, {'usedHeapSize': 1000}),
|
||||||
eventFactory.end('gc', 4, {'usedHeapSize': 0}),
|
eventFactory.end('gc', 4, {'usedHeapSize': 0}),
|
||||||
eventFactory.end('script', 5)
|
eventFactory.start('render', 4),
|
||||||
|
eventFactory.end('render', 5),
|
||||||
|
eventFactory.end('script', 6)
|
||||||
]).then((data) => {
|
]).then((data) => {
|
||||||
expect(data['script']).toBe(2);
|
expect(data['scriptTime']).toBe(6);
|
||||||
|
expect(data['pureScriptTime']).toBe(2);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('microIterations', () => {
|
describe('microIterations', () => {
|
||||||
|
|
||||||
it('should not report scriptMicroAvg if microIterations = 0', inject([AsyncTestCompleter], (async) => {
|
it('should not report microScriptTimeAvg if microIterations = 0', inject([AsyncTestCompleter], (async) => {
|
||||||
aggregate([
|
aggregate([
|
||||||
eventFactory.start('script', 0),
|
eventFactory.start('script', 0),
|
||||||
eventFactory.end('script', 5)
|
eventFactory.end('script', 5)
|
||||||
], 0).then((data) => {
|
], 0).then((data) => {
|
||||||
expect(isPresent(data['scriptMicroAvg'])).toBe(false);
|
expect(isPresent(data['microScriptTimeAvg'])).toBe(false);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should report scriptMicroAvg', inject([AsyncTestCompleter], (async) => {
|
it('should report microScriptTimeAvg', inject([AsyncTestCompleter], (async) => {
|
||||||
aggregate([
|
aggregate([
|
||||||
eventFactory.start('script', 0),
|
eventFactory.start('script', 0),
|
||||||
eventFactory.end('script', 5)
|
eventFactory.end('script', 5)
|
||||||
], 4).then((data) => {
|
], 4).then((data) => {
|
||||||
expect(data['script']).toBe(5);
|
expect(data['scriptTime']).toBe(5);
|
||||||
expect(data['scriptMicroAvg']).toBe(5/4);
|
expect(data['microScriptTimeAvg']).toBe(5/4);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -315,10 +352,12 @@ export function main() {
|
||||||
class MockDriverExtension extends WebDriverExtension {
|
class MockDriverExtension extends WebDriverExtension {
|
||||||
_perfLogs:List;
|
_perfLogs:List;
|
||||||
_commandLog:List;
|
_commandLog:List;
|
||||||
constructor(perfLogs, commandLog) {
|
_perfLogFeatures:PerfLogFeatures;
|
||||||
|
constructor(perfLogs, commandLog, perfLogFeatures) {
|
||||||
super();
|
super();
|
||||||
this._perfLogs = perfLogs;
|
this._perfLogs = perfLogs;
|
||||||
this._commandLog = commandLog;
|
this._commandLog = commandLog;
|
||||||
|
this._perfLogFeatures = perfLogFeatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
timeBegin(name):Promise {
|
timeBegin(name):Promise {
|
||||||
|
@ -331,6 +370,10 @@ class MockDriverExtension extends WebDriverExtension {
|
||||||
return PromiseWrapper.resolve(null);
|
return PromiseWrapper.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
perfLogFeatures():PerfLogFeatures {
|
||||||
|
return this._perfLogFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
readPerfLog():Promise {
|
readPerfLog():Promise {
|
||||||
ListWrapper.push(this._commandLog, 'readPerfLog');
|
ListWrapper.push(this._commandLog, 'readPerfLog');
|
||||||
if (this._perfLogs.length > 0) {
|
if (this._perfLogs.length > 0) {
|
||||||
|
|
|
@ -17,7 +17,8 @@ import { PromiseWrapper } from 'angular2/src/facade/async';
|
||||||
import {
|
import {
|
||||||
bind, Injector,
|
bind, Injector,
|
||||||
SampleDescription,
|
SampleDescription,
|
||||||
MeasureValues
|
MeasureValues,
|
||||||
|
Options
|
||||||
} from 'benchpress/common';
|
} from 'benchpress/common';
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,7 +33,8 @@ export function main() {
|
||||||
JsonFileReporter.BINDINGS,
|
JsonFileReporter.BINDINGS,
|
||||||
bind(SampleDescription).toValue(new SampleDescription(sampleId, descriptions, metrics)),
|
bind(SampleDescription).toValue(new SampleDescription(sampleId, descriptions, metrics)),
|
||||||
bind(JsonFileReporter.PATH).toValue(path),
|
bind(JsonFileReporter.PATH).toValue(path),
|
||||||
bind(JsonFileReporter.WRITE_FILE).toValue((filename, content) => {
|
bind(Options.NOW).toValue( () => DateWrapper.fromMillis(1234) ),
|
||||||
|
bind(Options.WRITE_FILE).toValue((filename, content) => {
|
||||||
loggedFile = {
|
loggedFile = {
|
||||||
'filename': filename,
|
'filename': filename,
|
||||||
'content': content
|
'content': content
|
||||||
|
|
|
@ -50,15 +50,17 @@ export function main() {
|
||||||
if (isBlank(driverExtension)) {
|
if (isBlank(driverExtension)) {
|
||||||
driverExtension = new MockDriverExtension([]);
|
driverExtension = new MockDriverExtension([]);
|
||||||
}
|
}
|
||||||
var bindings = ListWrapper.concat(Sampler.BINDINGS, [
|
var bindings = [
|
||||||
|
Options.DEFAULT_BINDINGS,
|
||||||
|
Sampler.BINDINGS,
|
||||||
bind(Metric).toValue(metric),
|
bind(Metric).toValue(metric),
|
||||||
bind(Reporter).toValue(reporter),
|
bind(Reporter).toValue(reporter),
|
||||||
bind(WebDriverAdapter).toValue(driver),
|
bind(WebDriverAdapter).toValue(driver),
|
||||||
bind(WebDriverExtension).toValue(driverExtension),
|
bind(WebDriverExtension).toValue(driverExtension),
|
||||||
bind(Options.EXECUTE).toValue(execute),
|
bind(Options.EXECUTE).toValue(execute),
|
||||||
bind(Validator).toValue(validator),
|
bind(Validator).toValue(validator),
|
||||||
bind(Sampler.TIME).toValue( () => DateWrapper.fromMillis(time++) )
|
bind(Options.NOW).toValue( () => DateWrapper.fromMillis(time++) )
|
||||||
]);
|
];
|
||||||
if (isPresent(prepare)) {
|
if (isPresent(prepare)) {
|
||||||
ListWrapper.push(bindings, bind(Options.PREPARE).toValue(prepare));
|
ListWrapper.push(bindings, bind(Options.PREPARE).toValue(prepare));
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,9 @@ export function main() {
|
||||||
return extension;
|
return extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should force gc via window.gc()', inject([AsyncTestCompleter], (async) => {
|
it('should throw on forcing gc', () => {
|
||||||
createExtension().gc().then( (_) => {
|
expect( () => createExtension().gc() ).toThrowError('Force GC is not supported on iOS');
|
||||||
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) => {
|
||||||
createExtension().timeBegin('someName').then( (_) => {
|
createExtension().timeBegin('someName').then( (_) => {
|
||||||
|
@ -124,18 +121,6 @@ export function main() {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should report gc', inject([AsyncTestCompleter], (async) => {
|
|
||||||
createExtension([
|
|
||||||
gcRecord(1, 3, 21)
|
|
||||||
]).readPerfLog().then( (events) => {
|
|
||||||
expect(events).toEqual([
|
|
||||||
normEvents.start('gc', 1, {'usedHeapSize': 0}),
|
|
||||||
normEvents.end('gc', 3, {'usedHeapSize': -21}),
|
|
||||||
]);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint', 'Rasterize', 'CompositeLayers'].forEach( (recordType) => {
|
['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint', 'Rasterize', 'CompositeLayers'].forEach( (recordType) => {
|
||||||
it(`should report ${recordType}`, inject([AsyncTestCompleter], (async) => {
|
it(`should report ${recordType}`, inject([AsyncTestCompleter], (async) => {
|
||||||
createExtension([
|
createExtension([
|
||||||
|
@ -224,17 +209,6 @@ function internalScriptRecord(startTime, endTime) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function gcRecord(startTime, endTime, gcAmount) {
|
|
||||||
return {
|
|
||||||
'type': 'GCEvent',
|
|
||||||
'startTime': startTime,
|
|
||||||
'endTime': endTime,
|
|
||||||
'data': {
|
|
||||||
'usedHeapSizeDelta': gcAmount
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class MockDriverAdapter extends WebDriverAdapter {
|
class MockDriverAdapter extends WebDriverAdapter {
|
||||||
_log:List;
|
_log:List;
|
||||||
_perfRecords:List;
|
_perfRecords:List;
|
||||||
|
|
Loading…
Reference in New Issue