mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
* 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
140 lines
4.6 KiB
JavaScript
140 lines
4.6 KiB
JavaScript
import { isPresent, isBlank, Date, DateWrapper } from 'angular2/src/facade/lang';
|
|
import { Promise, PromiseWrapper } from 'angular2/src/facade/async';
|
|
import { StringMapWrapper, StringMap, List, ListWrapper } from 'angular2/src/facade/collection';
|
|
import { bind, OpaqueToken } from 'angular2/di';
|
|
|
|
import { Metric } from './metric';
|
|
import { Validator } from './validator';
|
|
import { Reporter } from './reporter';
|
|
import { WebDriverExtension } from './web_driver_extension';
|
|
import { WebDriverAdapter } from './web_driver_adapter';
|
|
|
|
import { Options } from './common_options';
|
|
import { MeasureValues} from './measure_values';
|
|
|
|
/**
|
|
* The Sampler owns the sample loop:
|
|
* 1. calls the prepare/execute callbacks,
|
|
* 2. gets data from the metric
|
|
* 3. asks the validator for a valid sample
|
|
* 4. reports the new data to the reporter
|
|
* 5. loop until there is a valid sample
|
|
*/
|
|
export class Sampler {
|
|
// TODO(tbosch): use static values when our transpiler supports them
|
|
static get BINDINGS() { return _BINDINGS; }
|
|
|
|
_driver:WebDriverAdapter;
|
|
_driverExtension:WebDriverExtension;
|
|
_metric:Metric;
|
|
_reporter:Reporter;
|
|
_validator:Validator;
|
|
_forceGc:boolean;
|
|
_prepare:Function;
|
|
_execute:Function;
|
|
_now:Function;
|
|
|
|
constructor({
|
|
driver, driverExtension, metric, reporter, validator, forceGc, prepare, execute, now
|
|
}:{
|
|
driver: WebDriverAdapter,
|
|
driverExtension: WebDriverExtension, metric: Metric, reporter: Reporter,
|
|
validator: Validator, prepare: Function, execute: Function, now: Function
|
|
}={}) {
|
|
this._driver = driver;
|
|
this._driverExtension = driverExtension;
|
|
this._metric = metric;
|
|
this._reporter = reporter;
|
|
this._validator = validator;
|
|
this._forceGc = forceGc;
|
|
this._prepare = prepare;
|
|
this._execute = execute;
|
|
this._now = now;
|
|
}
|
|
|
|
sample():Promise<SampleState> {
|
|
var loop;
|
|
loop = (lastState) => {
|
|
return this._iterate(lastState)
|
|
.then( (newState) => {
|
|
if (isPresent(newState.validSample)) {
|
|
return newState;
|
|
} else {
|
|
return loop(newState);
|
|
}
|
|
});
|
|
}
|
|
return this._gcIfNeeded().then( (_) => loop(new SampleState([], null)) );
|
|
}
|
|
|
|
_gcIfNeeded() {
|
|
if (this._forceGc) {
|
|
return this._driverExtension.gc();
|
|
} else {
|
|
return PromiseWrapper.resolve(null);
|
|
}
|
|
}
|
|
|
|
_iterate(lastState) {
|
|
var resultPromise;
|
|
if (isPresent(this._prepare)) {
|
|
resultPromise = this._driver.waitFor(this._prepare)
|
|
.then( (_) => this._gcIfNeeded() );
|
|
} else {
|
|
resultPromise = PromiseWrapper.resolve(null);
|
|
}
|
|
if (isPresent(this._prepare) || lastState.completeSample.length === 0) {
|
|
resultPromise = resultPromise.then( (_) => this._metric.beginMeasure() );
|
|
}
|
|
return resultPromise
|
|
.then( (_) => this._driver.waitFor(this._execute) )
|
|
.then( (_) => this._gcIfNeeded() )
|
|
.then( (_) => this._metric.endMeasure(isBlank(this._prepare)) )
|
|
.then( (measureValues) => this._report(lastState, measureValues) );
|
|
}
|
|
|
|
_report(state:SampleState, metricValues:StringMap):Promise<SampleState> {
|
|
var measureValues = new MeasureValues(state.completeSample.length, this._now(), metricValues);
|
|
var completeSample = ListWrapper.concat(state.completeSample, [measureValues]);
|
|
var validSample = this._validator.validate(completeSample);
|
|
var resultPromise = this._reporter.reportMeasureValues(measureValues);
|
|
if (isPresent(validSample)) {
|
|
resultPromise = resultPromise.then( (_) => this._reporter.reportSample(completeSample, validSample) )
|
|
}
|
|
return resultPromise.then( (_) => new SampleState(completeSample, validSample) );
|
|
}
|
|
|
|
}
|
|
|
|
export class SampleState {
|
|
completeSample:List;
|
|
validSample:List;
|
|
|
|
constructor(completeSample: List, validSample: List) {
|
|
this.completeSample = completeSample;
|
|
this.validSample = validSample;
|
|
}
|
|
}
|
|
|
|
var _BINDINGS = [
|
|
bind(Sampler).toFactory(
|
|
(driver, driverExtension, metric, reporter, validator, forceGc, prepare, execute, now) => new Sampler({
|
|
driver: driver,
|
|
driverExtension: driverExtension,
|
|
reporter: reporter,
|
|
validator: validator,
|
|
metric: metric,
|
|
forceGc: forceGc,
|
|
// 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
|
|
}),
|
|
[
|
|
WebDriverAdapter, WebDriverExtension, Metric, Reporter, Validator,
|
|
Options.FORCE_GC, Options.PREPARE, Options.EXECUTE, Options.NOW
|
|
]
|
|
)
|
|
];
|