fix(benchpress): make benchpress fit for chrome 45
Closes #3411 Closes #3982
This commit is contained in:

committed by
Michael Goderbauer

parent
d8c5ab232c
commit
67b9414268
@ -13,10 +13,11 @@ import {
|
||||
import {WebDriverExtension, PerfLogFeatures} from '../web_driver_extension';
|
||||
import {WebDriverAdapter} from '../web_driver_adapter';
|
||||
import {Promise} from 'angular2/src/core/facade/async';
|
||||
import {Options} from '../common_options';
|
||||
|
||||
/**
|
||||
* Set the following 'traceCategories' to collect metrics in Chrome:
|
||||
* 'v8,blink.console,disabled-by-default-devtools.timeline'
|
||||
* 'v8,blink.console,disabled-by-default-devtools.timeline,devtools.timeline'
|
||||
*
|
||||
* In order to collect the frame rate related metrics, add 'benchmark'
|
||||
* to the list above.
|
||||
@ -25,7 +26,27 @@ export class ChromeDriverExtension extends WebDriverExtension {
|
||||
// TODO(tbosch): use static values when our transpiler supports them
|
||||
static get BINDINGS(): Binding[] { return _BINDINGS; }
|
||||
|
||||
constructor(private _driver: WebDriverAdapter) { super(); }
|
||||
private _majorChromeVersion: number;
|
||||
|
||||
constructor(private _driver: WebDriverAdapter, userAgent: string) {
|
||||
super();
|
||||
this._majorChromeVersion = this._parseChromeVersion(userAgent);
|
||||
}
|
||||
|
||||
private _parseChromeVersion(userAgent: string): number {
|
||||
if (isBlank(userAgent)) {
|
||||
return -1;
|
||||
}
|
||||
var v = StringWrapper.split(userAgent, /Chrom(e|ium)\//g)[2];
|
||||
if (isBlank(v)) {
|
||||
return -1;
|
||||
}
|
||||
v = StringWrapper.split(v, /\./g)[0];
|
||||
if (isBlank(v)) {
|
||||
return -1;
|
||||
}
|
||||
return NumberWrapper.parseInt(v, 10);
|
||||
}
|
||||
|
||||
gc() { return this._driver.executeScript('window.gc()'); }
|
||||
|
||||
@ -63,54 +84,19 @@ export class ChromeDriverExtension extends WebDriverExtension {
|
||||
});
|
||||
}
|
||||
|
||||
_convertPerfRecordsToEvents(chromeEvents: Array<StringMap<string, any>>,
|
||||
normalizedEvents: Array<StringMap<string, any>> = null) {
|
||||
private _convertPerfRecordsToEvents(chromeEvents: Array<StringMap<string, any>>,
|
||||
normalizedEvents: Array<StringMap<string, any>> = null) {
|
||||
if (isBlank(normalizedEvents)) {
|
||||
normalizedEvents = [];
|
||||
}
|
||||
var majorGCPids = {};
|
||||
chromeEvents.forEach((event) => {
|
||||
var cat = event['cat'];
|
||||
var categories = this._parseCategories(event['cat']);
|
||||
var name = event['name'];
|
||||
var args = event['args'];
|
||||
var pid = event['pid'];
|
||||
var ph = event['ph'];
|
||||
if (StringWrapper.equals(cat, 'disabled-by-default-devtools.timeline')) {
|
||||
if (StringWrapper.equals(name, 'FunctionCall') &&
|
||||
(isBlank(args) || isBlank(args['data']) ||
|
||||
!StringWrapper.equals(args['data']['scriptName'], 'InjectedScript'))) {
|
||||
normalizedEvents.push(normalizeEvent(event, {'name': 'script'}));
|
||||
|
||||
} else if (StringWrapper.equals(name, 'RecalculateStyles') ||
|
||||
StringWrapper.equals(name, 'Layout') ||
|
||||
StringWrapper.equals(name, 'UpdateLayerTree') ||
|
||||
StringWrapper.equals(name, 'Paint') || StringWrapper.equals(name, 'Rasterize') ||
|
||||
StringWrapper.equals(name, 'CompositeLayers')) {
|
||||
normalizedEvents.push(normalizeEvent(event, {'name': 'render'}));
|
||||
|
||||
} else if (StringWrapper.equals(name, 'GCEvent')) {
|
||||
var normArgs = {
|
||||
'usedHeapSize': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] :
|
||||
args['usedHeapSizeBefore']
|
||||
};
|
||||
if (StringWrapper.equals(event['ph'], 'E')) {
|
||||
normArgs['majorGc'] = isPresent(majorGCPids[pid]) && majorGCPids[pid];
|
||||
}
|
||||
majorGCPids[pid] = false;
|
||||
normalizedEvents.push(normalizeEvent(event, {'name': 'gc', 'args': normArgs}));
|
||||
}
|
||||
|
||||
} else if (StringWrapper.equals(cat, 'blink.console')) {
|
||||
if (this._isEvent(categories, name, ['blink.console'])) {
|
||||
normalizedEvents.push(normalizeEvent(event, {'name': name}));
|
||||
|
||||
} else if (StringWrapper.equals(cat, 'v8')) {
|
||||
if (StringWrapper.equals(name, 'majorGC')) {
|
||||
if (StringWrapper.equals(ph, 'B')) {
|
||||
majorGCPids[pid] = true;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (StringWrapper.equals(cat, 'benchmark')) {
|
||||
} else if (this._isEvent(categories, name, ['benchmark'],
|
||||
'BenchmarkInstrumentation::ImplThreadRenderingStats')) {
|
||||
// TODO(goderbauer): Instead of BenchmarkInstrumentation::ImplThreadRenderingStats the
|
||||
// following events should be used (if available) for more accurate measurments:
|
||||
// 1st choice: vsync_before - ground truth on Android
|
||||
@ -118,26 +104,118 @@ export class ChromeDriverExtension extends WebDriverExtension {
|
||||
// new surfaces framework (not broadly enabled yet)
|
||||
// 3rd choice: BenchmarkInstrumentation::ImplThreadRenderingStats - fallback event that is
|
||||
// allways available if something is rendered
|
||||
if (StringWrapper.equals(name, 'BenchmarkInstrumentation::ImplThreadRenderingStats')) {
|
||||
var frameCount = event['args']['data']['frame_count'];
|
||||
if (frameCount > 1) {
|
||||
throw new BaseException('multi-frame render stats not supported');
|
||||
}
|
||||
if (frameCount == 1) {
|
||||
normalizedEvents.push(normalizeEvent(event, {'name': 'frame'}));
|
||||
}
|
||||
var frameCount = event['args']['data']['frame_count'];
|
||||
if (frameCount > 1) {
|
||||
throw new BaseException('multi-frame render stats not supported');
|
||||
}
|
||||
if (frameCount == 1) {
|
||||
normalizedEvents.push(normalizeEvent(event, {'name': 'frame'}));
|
||||
}
|
||||
} else if (this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'],
|
||||
'Rasterize') ||
|
||||
this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'],
|
||||
'CompositeLayers')) {
|
||||
normalizedEvents.push(normalizeEvent(event, {'name': 'render'}));
|
||||
} else if (this._majorChromeVersion < 45) {
|
||||
var normalizedEvent = this._processAsPreChrome45Event(event, categories, majorGCPids);
|
||||
if (normalizedEvent != null) normalizedEvents.push(normalizedEvent);
|
||||
} else {
|
||||
var normalizedEvent = this._processAsPostChrome44Event(event, categories);
|
||||
if (normalizedEvent != null) normalizedEvents.push(normalizedEvent);
|
||||
}
|
||||
});
|
||||
return normalizedEvents;
|
||||
}
|
||||
|
||||
private _processAsPreChrome45Event(event, categories, majorGCPids) {
|
||||
var name = event['name'];
|
||||
var args = event['args'];
|
||||
var pid = event['pid'];
|
||||
var ph = event['ph'];
|
||||
if (this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'],
|
||||
'FunctionCall') &&
|
||||
(isBlank(args) || isBlank(args['data']) ||
|
||||
!StringWrapper.equals(args['data']['scriptName'], 'InjectedScript'))) {
|
||||
return normalizeEvent(event, {'name': 'script'});
|
||||
} else if (this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'],
|
||||
'RecalculateStyles') ||
|
||||
this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'],
|
||||
'Layout') ||
|
||||
this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'],
|
||||
'UpdateLayerTree') ||
|
||||
this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'],
|
||||
'Paint')) {
|
||||
return normalizeEvent(event, {'name': 'render'});
|
||||
} else if (this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'],
|
||||
'GCEvent')) {
|
||||
var normArgs = {
|
||||
'usedHeapSize': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] :
|
||||
args['usedHeapSizeBefore']
|
||||
};
|
||||
if (StringWrapper.equals(ph, 'E')) {
|
||||
normArgs['majorGc'] = isPresent(majorGCPids[pid]) && majorGCPids[pid];
|
||||
}
|
||||
majorGCPids[pid] = false;
|
||||
return normalizeEvent(event, {'name': 'gc', 'args': normArgs});
|
||||
} else if (this._isEvent(categories, name, ['v8'], 'majorGC') &&
|
||||
StringWrapper.equals(ph, 'B')) {
|
||||
majorGCPids[pid] = true;
|
||||
}
|
||||
return null; // nothing useful in this event
|
||||
}
|
||||
|
||||
private _processAsPostChrome44Event(event, categories) {
|
||||
var name = event['name'];
|
||||
var args = event['args'];
|
||||
if (this._isEvent(categories, name, ['devtools.timeline', 'v8'], 'MajorGC')) {
|
||||
var normArgs = {
|
||||
'majorGc': true,
|
||||
'usedHeapSize': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] :
|
||||
args['usedHeapSizeBefore']
|
||||
};
|
||||
return normalizeEvent(event, {'name': 'gc', 'args': normArgs});
|
||||
} else if (this._isEvent(categories, name, ['devtools.timeline', 'v8'], 'MinorGC')) {
|
||||
var normArgs = {
|
||||
'majorGc': false,
|
||||
'usedHeapSize': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] :
|
||||
args['usedHeapSizeBefore']
|
||||
};
|
||||
return normalizeEvent(event, {'name': 'gc', 'args': normArgs});
|
||||
} else if (this._isEvent(categories, name, ['devtools.timeline', 'v8'], 'FunctionCall') &&
|
||||
(isBlank(args) || isBlank(args['data']) ||
|
||||
!StringWrapper.equals(args['data']['scriptName'], 'InjectedScript'))) {
|
||||
return normalizeEvent(event, {'name': 'script'});
|
||||
} else if (this._isEvent(categories, name, ['devtools.timeline', 'blink'],
|
||||
'UpdateLayoutTree')) {
|
||||
return normalizeEvent(event, {'name': 'render'});
|
||||
} else if (this._isEvent(categories, name, ['devtools.timeline'], 'UpdateLayerTree') ||
|
||||
this._isEvent(categories, name, ['devtools.timeline'], 'Layout') ||
|
||||
this._isEvent(categories, name, ['devtools.timeline'], 'Paint')) {
|
||||
return normalizeEvent(event, {'name': 'render'});
|
||||
}
|
||||
return null; // nothing useful in this event
|
||||
}
|
||||
|
||||
private _parseCategories(categories: string): string[] {
|
||||
return StringWrapper.split(categories, /,/g);
|
||||
}
|
||||
|
||||
private _isEvent(eventCategories: string[], eventName: string, expectedCategories: string[],
|
||||
expectedName: string = null): boolean {
|
||||
var hasCategories = ListWrapper.reduce(expectedCategories, (value, cat) => {
|
||||
return value && ListWrapper.contains(eventCategories, cat);
|
||||
}, true);
|
||||
return isBlank(expectedName) ? hasCategories :
|
||||
hasCategories && StringWrapper.equals(eventName, expectedName);
|
||||
}
|
||||
|
||||
perfLogFeatures(): PerfLogFeatures {
|
||||
return new PerfLogFeatures({render: true, gc: true, frameCapture: true});
|
||||
}
|
||||
|
||||
supports(capabilities: StringMap<string, any>): boolean {
|
||||
return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'chrome');
|
||||
return this._majorChromeVersion != -1 &&
|
||||
StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'chrome');
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,5 +242,6 @@ function normalizeEvent(chromeEvent: StringMap<string, any>, data: StringMap<str
|
||||
|
||||
var _BINDINGS = [
|
||||
bind(ChromeDriverExtension)
|
||||
.toFactory((driver) => new ChromeDriverExtension(driver), [WebDriverAdapter])
|
||||
.toFactory((driver, userAgent) => new ChromeDriverExtension(driver, userAgent),
|
||||
[WebDriverAdapter, Options.USER_AGENT])
|
||||
];
|
||||
|
Reference in New Issue
Block a user