refactor(benchpress): report forced gc metric separately
This commit is contained in:
@ -27,7 +27,7 @@ export function main() {
|
||||
var commandLog;
|
||||
var eventFactory = new TraceEventFactory('timeline', 'pid0');
|
||||
|
||||
function createMetric(perfLogs, microMetrics = null, perfLogFeatures = null) {
|
||||
function createMetric(perfLogs, microMetrics = null, perfLogFeatures = null, forceGc = null) {
|
||||
commandLog = [];
|
||||
if (isBlank(perfLogFeatures)) {
|
||||
perfLogFeatures = new PerfLogFeatures({render: true, gc: true});
|
||||
@ -45,34 +45,48 @@ export function main() {
|
||||
}),
|
||||
bind(WebDriverExtension).toValue(new MockDriverExtension(perfLogs, commandLog, perfLogFeatures))
|
||||
];
|
||||
if (isPresent(forceGc)) {
|
||||
ListWrapper.push(bindings, bind(Options.FORCE_GC).toValue(forceGc));
|
||||
}
|
||||
return Injector.resolveAndCreate(bindings).get(PerflogMetric);
|
||||
}
|
||||
|
||||
describe('perflog metric', () => {
|
||||
|
||||
it('should describe itself based on the perfLogFeatrues', () => {
|
||||
expect(createMetric([[]], null, new PerfLogFeatures()).describe()).toEqual({
|
||||
'scriptTime': 'script execution time in ms, including gc and render',
|
||||
'pureScriptTime': 'script execution time in ms, without gc nor render'
|
||||
function sortedKeys(stringMap) {
|
||||
var res = [];
|
||||
StringMapWrapper.forEach(stringMap, (_, key) => {
|
||||
ListWrapper.push(res, key);
|
||||
});
|
||||
res.sort();
|
||||
return res;
|
||||
}
|
||||
|
||||
expect(createMetric([[]], null, new PerfLogFeatures({
|
||||
it('should describe itself based on the perfLogFeatrues', () => {
|
||||
expect(sortedKeys(createMetric([[]], null, new PerfLogFeatures()).describe())).toEqual([
|
||||
'pureScriptTime', 'scriptTime'
|
||||
]);
|
||||
|
||||
expect(sortedKeys(createMetric([[]], null, 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',
|
||||
});
|
||||
})).describe())).toEqual([
|
||||
'pureScriptTime', 'renderTime', 'scriptTime'
|
||||
]);
|
||||
|
||||
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'
|
||||
});
|
||||
expect(sortedKeys(createMetric([[]]).describe())).toEqual([
|
||||
'gcAmount', 'gcTime', 'majorGcTime',
|
||||
'pureScriptTime', 'renderTime', 'scriptTime'
|
||||
]);
|
||||
|
||||
expect(sortedKeys(createMetric([[]], null, new PerfLogFeatures({
|
||||
render: true,
|
||||
gc: true
|
||||
}), true).describe())).toEqual([
|
||||
'forcedGcAmount', 'forcedGcTime',
|
||||
'gcAmount', 'gcTime', 'majorGcTime',
|
||||
'pureScriptTime', 'renderTime', 'scriptTime'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should describe itself based on micro metrics', () => {
|
||||
@ -84,7 +98,7 @@ export function main() {
|
||||
|
||||
describe('beginMeasure', () => {
|
||||
|
||||
it('should mark the timeline', inject([AsyncTestCompleter], (async) => {
|
||||
it('should not force gc and mark the timeline', inject([AsyncTestCompleter], (async) => {
|
||||
var metric = createMetric([[]]);
|
||||
metric.beginMeasure().then((_) => {
|
||||
expect(commandLog).toEqual([['timeBegin', 'benchpress0']]);
|
||||
@ -93,6 +107,15 @@ export function main() {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should force gc and mark the timeline', inject([AsyncTestCompleter], (async) => {
|
||||
var metric = createMetric([[]], null, null, true);
|
||||
metric.beginMeasure().then((_) => {
|
||||
expect(commandLog).toEqual([['gc'], ['timeBegin', 'benchpress0']]);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('endMeasure', () => {
|
||||
@ -200,6 +223,57 @@ export function main() {
|
||||
});
|
||||
}));
|
||||
|
||||
describe('with forced gc', () => {
|
||||
var events;
|
||||
beforeEach( () => {
|
||||
events = [
|
||||
[
|
||||
eventFactory.markStart('benchpress0', 0),
|
||||
eventFactory.start('script', 4),
|
||||
eventFactory.end('script', 6),
|
||||
eventFactory.markEnd('benchpress0', 10),
|
||||
eventFactory.markStart('benchpress1', 11),
|
||||
eventFactory.start('gc', 12, {'usedHeapSize': 2500}),
|
||||
eventFactory.end('gc', 15, {'usedHeapSize': 1000}),
|
||||
eventFactory.markEnd('benchpress1', 20)
|
||||
]
|
||||
];
|
||||
});
|
||||
|
||||
it('should measure forced gc', inject([AsyncTestCompleter], (async) => {
|
||||
var metric = createMetric(events, null, null, true);
|
||||
metric.beginMeasure()
|
||||
.then( (_) => metric.endMeasure(false) )
|
||||
.then( (data) => {
|
||||
expect(commandLog).toEqual([
|
||||
['gc'],
|
||||
['timeBegin', 'benchpress0'],
|
||||
['timeEnd', 'benchpress0', 'benchpress1'],
|
||||
'readPerfLog',
|
||||
['gc'],
|
||||
['timeEnd', 'benchpress1', null],
|
||||
'readPerfLog'
|
||||
]);
|
||||
expect(data['forcedGcTime']).toBe(3);
|
||||
expect(data['forcedGcAmount']).toBe(1.5);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should restart after the forced gc if needed', inject([AsyncTestCompleter], (async) => {
|
||||
var metric = createMetric(events, null, null, true);
|
||||
metric.beginMeasure()
|
||||
.then( (_) => metric.endMeasure(true) )
|
||||
.then( (data) => {
|
||||
expect(commandLog[5]).toEqual(['timeEnd', 'benchpress1', 'benchpress2']);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('aggregation', () => {
|
||||
@ -403,4 +477,9 @@ class MockDriverExtension extends WebDriverExtension {
|
||||
return PromiseWrapper.resolve([]);
|
||||
}
|
||||
}
|
||||
|
||||
gc():Promise {
|
||||
ListWrapper.push(this._commandLog, ['gc']);
|
||||
return PromiseWrapper.resolve(null);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import { ListWrapper, List } from 'angular2/src/facade/collection';
|
||||
import { PromiseWrapper, Promise } from 'angular2/src/facade/async';
|
||||
|
||||
import {
|
||||
Sampler, WebDriverAdapter, WebDriverExtension,
|
||||
Sampler, WebDriverAdapter,
|
||||
Validator, Metric, Reporter, Browser,
|
||||
bind, Injector, Options, MeasureValues
|
||||
} from 'benchpress/common';
|
||||
@ -29,11 +29,9 @@ export function main() {
|
||||
|
||||
function createSampler({
|
||||
driver,
|
||||
driverExtension,
|
||||
metric,
|
||||
reporter,
|
||||
validator,
|
||||
forceGc,
|
||||
prepare,
|
||||
execute
|
||||
} = {}) {
|
||||
@ -47,16 +45,12 @@ export function main() {
|
||||
if (isBlank(driver)) {
|
||||
driver = new MockDriverAdapter([]);
|
||||
}
|
||||
if (isBlank(driverExtension)) {
|
||||
driverExtension = new MockDriverExtension([]);
|
||||
}
|
||||
var bindings = [
|
||||
Options.DEFAULT_BINDINGS,
|
||||
Sampler.BINDINGS,
|
||||
bind(Metric).toValue(metric),
|
||||
bind(Reporter).toValue(reporter),
|
||||
bind(WebDriverAdapter).toValue(driver),
|
||||
bind(WebDriverExtension).toValue(driverExtension),
|
||||
bind(Options.EXECUTE).toValue(execute),
|
||||
bind(Validator).toValue(validator),
|
||||
bind(Options.NOW).toValue( () => DateWrapper.fromMillis(time++) )
|
||||
@ -64,9 +58,6 @@ export function main() {
|
||||
if (isPresent(prepare)) {
|
||||
ListWrapper.push(bindings, bind(Options.PREPARE).toValue(prepare));
|
||||
}
|
||||
if (isPresent(forceGc)) {
|
||||
ListWrapper.push(bindings, bind(Options.FORCE_GC).toValue(forceGc));
|
||||
}
|
||||
|
||||
sampler = Injector.resolveAndCreate(bindings).get(Sampler);
|
||||
}
|
||||
@ -97,13 +88,11 @@ export function main() {
|
||||
|
||||
}));
|
||||
|
||||
it('should call prepare, gc, beginMeasure, execute, gc, endMeasure for every iteration', inject([AsyncTestCompleter], (async) => {
|
||||
it('should call prepare, beginMeasure, execute, endMeasure for every iteration', inject([AsyncTestCompleter], (async) => {
|
||||
var workCount = 0;
|
||||
var log = [];
|
||||
createSampler({
|
||||
forceGc: true,
|
||||
metric: createCountingMetric(log),
|
||||
driverExtension: new MockDriverExtension(log),
|
||||
validator: createCountingValidator(2),
|
||||
prepare: () => {
|
||||
ListWrapper.push(log, `p${workCount++}`);
|
||||
@ -114,31 +103,24 @@ export function main() {
|
||||
});
|
||||
sampler.sample().then( (_) => {
|
||||
expect(log).toEqual([
|
||||
['gc'],
|
||||
'p0',
|
||||
['gc'],
|
||||
['beginMeasure'],
|
||||
'w1',
|
||||
['gc'],
|
||||
['endMeasure', false, {'script': 0}],
|
||||
'p2',
|
||||
['gc'],
|
||||
['beginMeasure'],
|
||||
'w3',
|
||||
['gc'],
|
||||
['endMeasure', false, {'script': 1}],
|
||||
]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should call execute, gc, endMeasure for every iteration if there is no prepare callback', inject([AsyncTestCompleter], (async) => {
|
||||
it('should call execute, endMeasure for every iteration if there is no prepare callback', inject([AsyncTestCompleter], (async) => {
|
||||
var log = [];
|
||||
var workCount = 0;
|
||||
createSampler({
|
||||
forceGc: true,
|
||||
metric: createCountingMetric(log),
|
||||
driverExtension: new MockDriverExtension(log),
|
||||
validator: createCountingValidator(2),
|
||||
execute: () => {
|
||||
ListWrapper.push(log, `w${workCount++}`);
|
||||
@ -147,34 +129,16 @@ export function main() {
|
||||
});
|
||||
sampler.sample().then( (_) => {
|
||||
expect(log).toEqual([
|
||||
['gc'],
|
||||
['beginMeasure'],
|
||||
'w0',
|
||||
['gc'],
|
||||
['endMeasure', true, {'script': 0}],
|
||||
'w1',
|
||||
['gc'],
|
||||
['endMeasure', true, {'script': 1}],
|
||||
]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not gc if the flag is not set', inject([AsyncTestCompleter], (async) => {
|
||||
var log = [];
|
||||
createSampler({
|
||||
metric: createCountingMetric(),
|
||||
driverExtension: new MockDriverExtension(log),
|
||||
validator: createCountingValidator(2),
|
||||
prepare: EMPTY_EXECUTE,
|
||||
execute: EMPTY_EXECUTE
|
||||
});
|
||||
sampler.sample().then( (_) => {
|
||||
expect(log).toEqual([]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should only collect metrics for execute and ignore metrics from prepare', inject([AsyncTestCompleter], (async) => {
|
||||
var scriptTime = 0;
|
||||
var iterationCount = 1;
|
||||
@ -307,21 +271,6 @@ class MockDriverAdapter extends WebDriverAdapter {
|
||||
}
|
||||
|
||||
|
||||
class MockDriverExtension extends WebDriverExtension {
|
||||
_log:List;
|
||||
constructor(log = null) {
|
||||
super();
|
||||
if (isBlank(log)) {
|
||||
log = [];
|
||||
}
|
||||
this._log = log;
|
||||
}
|
||||
gc():Promise {
|
||||
ListWrapper.push(this._log, ['gc']);
|
||||
return PromiseWrapper.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
class MockValidator extends Validator {
|
||||
_validate:Function;
|
||||
_log:List;
|
||||
|
Reference in New Issue
Block a user