feat(benchpress): add receivedData + requestCount to PerflogMetric

Closes #5750
This commit is contained in:
Olivier Chafik 2015-12-10 01:15:55 +00:00 committed by Olivier Chafik
parent 24dcd267b8
commit fe1dd77d94
7 changed files with 234 additions and 51 deletions

View File

@ -175,6 +175,20 @@ In addition to that, one extra binding needs to be passed to benchpress in tests
benchpress.sample(bindings: [bp.bind(bp.Options.CAPTURE_FRAMES).toValue(true)], ... ) benchpress.sample(bindings: [bp.bind(bp.Options.CAPTURE_FRAMES).toValue(true)], ... )
# Requests Metrics
Benchpress can also record the number of requests sent and count the received "encoded" bytes since [window.performance.timing.navigationStart](http://www.w3.org/TR/navigation-timing/#dom-performancetiming-navigationstart):
- `receivedData`: number of bytes received since the last navigation start
- `requestCount`: number of requests sent since the last navigation start
To collect these metrics, you need the following corresponding extra bindings:
benchpress.sample(bindings: [
bp.bind(bp.Options.RECEIVED_DATA).toValue(true),
bp.bind(bp.Options.REQUEST_COUNT).toValue(true)
], ... )
# Best practices # Best practices
* Use normalized environments * Use normalized environments

View File

@ -26,6 +26,10 @@ export class Options {
// TODO(tbosch): use static values when our transpiler supports them // TODO(tbosch): use static values when our transpiler supports them
static get MICRO_METRICS() { return _MICRO_METRICS; } static get MICRO_METRICS() { return _MICRO_METRICS; }
// TODO(tbosch): use static values when our transpiler supports them // 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 get CAPTURE_FRAMES() { return _CAPTURE_FRAMES; }
} }
@ -40,6 +44,8 @@ var _USER_AGENT = new OpaqueToken('Options.userAgent');
var _MICRO_METRICS = new OpaqueToken('Options.microMetrics'); var _MICRO_METRICS = new OpaqueToken('Options.microMetrics');
var _NOW = new OpaqueToken('Options.now'); var _NOW = new OpaqueToken('Options.now');
var _WRITE_FILE = new OpaqueToken('Options.writeFile'); 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 _CAPTURE_FRAMES = new OpaqueToken('Options.frameCapture');
var _DEFAULT_PROVIDERS = [ var _DEFAULT_PROVIDERS = [
@ -50,5 +56,7 @@ var _DEFAULT_PROVIDERS = [
provide(_PREPARE, {useValue: false}), provide(_PREPARE, {useValue: false}),
provide(_MICRO_METRICS, {useValue: {}}), provide(_MICRO_METRICS, {useValue: {}}),
provide(_NOW, {useValue: () => DateWrapper.now()}), provide(_NOW, {useValue: () => DateWrapper.now()}),
provide(_RECEIVED_DATA, {useValue: false}),
provide(_REQUEST_COUNT, {useValue: false}),
provide(_CAPTURE_FRAMES, {useValue: false}) provide(_CAPTURE_FRAMES, {useValue: false})
]; ];

View File

@ -36,12 +36,18 @@ export class PerflogMetric extends Metric {
**/ **/
constructor(private _driverExtension: WebDriverExtension, private _setTimeout: Function, constructor(private _driverExtension: WebDriverExtension, private _setTimeout: Function,
private _microMetrics: {[key: string]: any}, private _forceGc: boolean, private _microMetrics: {[key: string]: any}, private _forceGc: boolean,
private _captureFrames: boolean) { private _captureFrames: boolean, private _receivedData: boolean,
private _requestCount: boolean) {
super(); super();
this._remainingEvents = []; this._remainingEvents = [];
this._measureCount = 0; this._measureCount = 0;
this._perfLogFeatures = _driverExtension.perfLogFeatures(); this._perfLogFeatures = _driverExtension.perfLogFeatures();
if (!this._perfLogFeatures.userTiming) {
// User timing is needed for navigationStart.
this._receivedData = false;
this._requestCount = false;
}
} }
describe(): {[key: string]: any} { describe(): {[key: string]: any} {
@ -61,6 +67,12 @@ export class PerflogMetric extends Metric {
res['forcedGcAmount'] = 'forced gc amount in kbytes'; res['forcedGcAmount'] = 'forced gc amount in kbytes';
} }
} }
if (this._receivedData) {
res['receivedData'] = 'encoded bytes received since navigationStart';
}
if (this._requestCount) {
res['requestCount'] = 'count of requests sent since navigationStart';
}
if (this._captureFrames) { if (this._captureFrames) {
if (!this._perfLogFeatures.frameCapture) { if (!this._perfLogFeatures.frameCapture) {
var warningMsg = 'WARNING: Metric requested, but not supported by driver'; var warningMsg = 'WARNING: Metric requested, but not supported by driver';
@ -188,6 +200,12 @@ export class PerflogMetric extends Metric {
result['frameTime.smooth'] = 0; result['frameTime.smooth'] = 0;
} }
StringMapWrapper.forEach(this._microMetrics, (desc, name) => { result[name] = 0; }); StringMapWrapper.forEach(this._microMetrics, (desc, name) => { result[name] = 0; });
if (this._receivedData) {
result['receivedData'] = 0;
}
if (this._requestCount) {
result['requestCount'] = 0;
}
var markStartEvent = null; var markStartEvent = null;
var markEndEvent = null; var markEndEvent = null;
@ -217,6 +235,22 @@ export class PerflogMetric extends Metric {
markEndEvent = event; markEndEvent = event;
} }
let isInstant = StringWrapper.equals(ph, 'I') || StringWrapper.equals(ph, 'i');
if (this._requestCount && StringWrapper.equals(name, 'sendRequest')) {
result['requestCount'] += 1;
} else if (this._receivedData && StringWrapper.equals(name, 'receivedData') && isInstant) {
result['receivedData'] += event['args']['encodedDataLength'];
} else if (StringWrapper.equals(name, 'navigationStart')) {
// We count data + requests since the last navigationStart
// (there might be chrome extensions loaded by selenium before our page, so there
// will likely be more than one navigationStart).
if (this._receivedData) {
result['receivedData'] = 0;
}
if (this._requestCount) {
result['requestCount'] = 0;
}
}
if (isPresent(markStartEvent) && isBlank(markEndEvent) && if (isPresent(markStartEvent) && isBlank(markEndEvent) &&
event['pid'] === markStartEvent['pid']) { event['pid'] === markStartEvent['pid']) {
if (StringWrapper.equals(ph, 'b') && StringWrapper.equals(name, _MARK_NAME_FRAME_CAPUTRE)) { if (StringWrapper.equals(ph, 'b') && StringWrapper.equals(name, _MARK_NAME_FRAME_CAPUTRE)) {
@ -236,7 +270,7 @@ export class PerflogMetric extends Metric {
frameCaptureEndEvent = event; frameCaptureEndEvent = event;
} }
if (StringWrapper.equals(ph, 'I') || StringWrapper.equals(ph, 'i')) { if (isInstant) {
if (isPresent(frameCaptureStartEvent) && isBlank(frameCaptureEndEvent) && if (isPresent(frameCaptureStartEvent) && isBlank(frameCaptureEndEvent) &&
StringWrapper.equals(name, 'frame')) { StringWrapper.equals(name, 'frame')) {
frameTimestamps.push(event['ts']); frameTimestamps.push(event['ts']);
@ -332,14 +366,17 @@ var _FRAME_TIME_SMOOTH_THRESHOLD = 17;
var _PROVIDERS = [ var _PROVIDERS = [
bind(PerflogMetric) bind(PerflogMetric)
.toFactory( .toFactory(
(driverExtension, setTimeout, microMetrics, forceGc, captureFrames) => (driverExtension, setTimeout, microMetrics, forceGc, captureFrames, receivedData,
new PerflogMetric(driverExtension, setTimeout, microMetrics, forceGc, captureFrames), requestCount) => new PerflogMetric(driverExtension, setTimeout, microMetrics, forceGc,
captureFrames, receivedData, requestCount),
[ [
WebDriverExtension, WebDriverExtension,
_SET_TIMEOUT, _SET_TIMEOUT,
Options.MICRO_METRICS, Options.MICRO_METRICS,
Options.FORCE_GC, Options.FORCE_GC,
Options.CAPTURE_FRAMES Options.CAPTURE_FRAMES,
Options.RECEIVED_DATA,
Options.REQUEST_COUNT
]), ]),
provide(_SET_TIMEOUT, {useValue: (fn, millis) => TimerWrapper.setTimeout(fn, millis)}) provide(_SET_TIMEOUT, {useValue: (fn, millis) => TimerWrapper.setTimeout(fn, millis)})
]; ];

View File

@ -66,12 +66,15 @@ export class PerfLogFeatures {
render: boolean; render: boolean;
gc: boolean; gc: boolean;
frameCapture: boolean; frameCapture: boolean;
userTiming: boolean;
constructor({render = false, gc = false, frameCapture = false}: constructor(
{render?: boolean, gc?: boolean, frameCapture?: boolean} = {}) { {render = false, gc = false, frameCapture = false, userTiming = false}:
{render?: boolean, gc?: boolean, frameCapture?: boolean, userTiming?: boolean} = {}) {
this.render = render; this.render = render;
this.gc = gc; this.gc = gc;
this.frameCapture = frameCapture; this.frameCapture = frameCapture;
this.userTiming = userTiming;
} }
} }

View File

@ -193,6 +193,15 @@ export class ChromeDriverExtension extends WebDriverExtension {
this._isEvent(categories, name, ['devtools.timeline'], 'Layout') || this._isEvent(categories, name, ['devtools.timeline'], 'Layout') ||
this._isEvent(categories, name, ['devtools.timeline'], 'Paint')) { this._isEvent(categories, name, ['devtools.timeline'], 'Paint')) {
return normalizeEvent(event, {'name': 'render'}); return normalizeEvent(event, {'name': 'render'});
} else if (this._isEvent(categories, name, ['devtools.timeline'], 'ResourceReceivedData')) {
let normArgs = {'encodedDataLength': args['data']['encodedDataLength']};
return normalizeEvent(event, {'name': 'receivedData', 'args': normArgs});
} else if (this._isEvent(categories, name, ['devtools.timeline'], 'ResourceSendRequest')) {
let data = args['data'];
let normArgs = {'url': data['url'], 'method': data['requestMethod']};
return normalizeEvent(event, {'name': 'sendRequest', 'args': normArgs});
} else if (this._isEvent(categories, name, ['blink.user_timing'], 'navigationStart')) {
return normalizeEvent(event, {'name': name});
} }
return null; // nothing useful in this event return null; // nothing useful in this event
} }
@ -208,7 +217,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
} }
perfLogFeatures(): PerfLogFeatures { perfLogFeatures(): PerfLogFeatures {
return new PerfLogFeatures({render: true, gc: true, frameCapture: true}); return new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
} }
supports(capabilities: {[key: string]: any}): boolean { supports(capabilities: {[key: string]: any}): boolean {

View File

@ -32,11 +32,18 @@ export function main() {
var commandLog: any[]; var commandLog: any[];
var eventFactory = new TraceEventFactory('timeline', 'pid0'); var eventFactory = new TraceEventFactory('timeline', 'pid0');
function createMetric(perfLogs, microMetrics = null, perfLogFeatures = null, forceGc = null, function createMetric(perfLogs, perfLogFeatures,
captureFrames = null) { {microMetrics, forceGc, captureFrames, receivedData, requestCount}: {
microMetrics?: {[key: string]: string},
forceGc?: boolean,
captureFrames?: boolean,
receivedData?: boolean,
requestCount?: boolean
} = {}) {
commandLog = []; commandLog = [];
if (isBlank(perfLogFeatures)) { if (isBlank(perfLogFeatures)) {
perfLogFeatures = new PerfLogFeatures({render: true, gc: true, frameCapture: true}); perfLogFeatures =
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
} }
if (isBlank(microMetrics)) { if (isBlank(microMetrics)) {
microMetrics = StringMapWrapper.create(); microMetrics = StringMapWrapper.create();
@ -59,6 +66,12 @@ export function main() {
if (isPresent(captureFrames)) { if (isPresent(captureFrames)) {
bindings.push(bind(Options.CAPTURE_FRAMES).toValue(captureFrames)); bindings.push(bind(Options.CAPTURE_FRAMES).toValue(captureFrames));
} }
if (isPresent(receivedData)) {
bindings.push(bind(Options.RECEIVED_DATA).toValue(receivedData));
}
if (isPresent(requestCount)) {
bindings.push(bind(Options.REQUEST_COUNT).toValue(requestCount));
}
return Injector.resolveAndCreate(bindings).get(PerflogMetric); return Injector.resolveAndCreate(bindings).get(PerflogMetric);
} }
@ -72,20 +85,20 @@ export function main() {
} }
it('should describe itself based on the perfLogFeatrues', () => { it('should describe itself based on the perfLogFeatrues', () => {
expect(sortedKeys(createMetric([[]], null, new PerfLogFeatures()).describe())) expect(sortedKeys(createMetric([[]], new PerfLogFeatures()).describe()))
.toEqual(['pureScriptTime', 'scriptTime']); .toEqual(['pureScriptTime', 'scriptTime']);
expect(sortedKeys(createMetric([[]], null, new PerfLogFeatures({render: true, gc: false})) expect(
.describe())) sortedKeys(createMetric([[]], new PerfLogFeatures({render: true, gc: false})).describe()))
.toEqual(['pureScriptTime', 'renderTime', 'scriptTime']); .toEqual(['pureScriptTime', 'renderTime', 'scriptTime']);
expect(sortedKeys(createMetric([[]]).describe())) expect(sortedKeys(createMetric([[]], null).describe()))
.toEqual( .toEqual(
['gcAmount', 'gcTime', 'majorGcTime', 'pureScriptTime', 'renderTime', 'scriptTime']); ['gcAmount', 'gcTime', 'majorGcTime', 'pureScriptTime', 'renderTime', 'scriptTime']);
expect( expect(sortedKeys(
sortedKeys(createMetric([[]], null, new PerfLogFeatures({render: true, gc: true}), true) createMetric([[]], new PerfLogFeatures({render: true, gc: true}), {forceGc: true})
.describe())) .describe()))
.toEqual([ .toEqual([
'forcedGcAmount', 'forcedGcAmount',
'forcedGcTime', 'forcedGcTime',
@ -96,16 +109,23 @@ export function main() {
'renderTime', 'renderTime',
'scriptTime' 'scriptTime'
]); ]);
expect(sortedKeys(createMetric([[]], new PerfLogFeatures({userTiming: true}),
{receivedData: true, requestCount: true})
.describe()))
.toEqual(['pureScriptTime', 'receivedData', 'requestCount', 'scriptTime']);
}); });
it('should describe itself based on micro metrics', () => { it('should describe itself based on micro metrics', () => {
var description = createMetric([[]], {'myMicroMetric': 'someDesc'}).describe(); var description =
createMetric([[]], null, {microMetrics: {'myMicroMetric': 'someDesc'}}).describe();
expect(description['myMicroMetric']).toEqual('someDesc'); expect(description['myMicroMetric']).toEqual('someDesc');
}); });
it('should describe itself if frame capture is requested and available', () => { it('should describe itself if frame capture is requested and available', () => {
var description = var description =
createMetric([[]], null, new PerfLogFeatures({frameCapture: true}), null, true) createMetric([[]], new PerfLogFeatures({frameCapture: true}), {captureFrames: true})
.describe(); .describe();
expect(description['frameTime.mean']).not.toContain('WARNING'); expect(description['frameTime.mean']).not.toContain('WARNING');
expect(description['frameTime.best']).not.toContain('WARNING'); expect(description['frameTime.best']).not.toContain('WARNING');
@ -115,7 +135,7 @@ export function main() {
it('should describe itself if frame capture is requested and not available', () => { it('should describe itself if frame capture is requested and not available', () => {
var description = var description =
createMetric([[]], null, new PerfLogFeatures({frameCapture: false}), null, true) createMetric([[]], new PerfLogFeatures({frameCapture: false}), {captureFrames: true})
.describe(); .describe();
expect(description['frameTime.mean']).toContain('WARNING'); expect(description['frameTime.mean']).toContain('WARNING');
expect(description['frameTime.best']).toContain('WARNING'); expect(description['frameTime.best']).toContain('WARNING');
@ -126,7 +146,7 @@ export function main() {
describe('beginMeasure', () => { describe('beginMeasure', () => {
it('should not force gc and mark the timeline', inject([AsyncTestCompleter], (async) => { it('should not force gc and mark the timeline', inject([AsyncTestCompleter], (async) => {
var metric = createMetric([[]]); var metric = createMetric([[]], null);
metric.beginMeasure().then((_) => { metric.beginMeasure().then((_) => {
expect(commandLog).toEqual([['timeBegin', 'benchpress0']]); expect(commandLog).toEqual([['timeBegin', 'benchpress0']]);
@ -135,7 +155,7 @@ export function main() {
})); }));
it('should force gc and mark the timeline', inject([AsyncTestCompleter], (async) => { it('should force gc and mark the timeline', inject([AsyncTestCompleter], (async) => {
var metric = createMetric([[]], null, null, true); var metric = createMetric([[]], null, {forceGc: true});
metric.beginMeasure().then((_) => { metric.beginMeasure().then((_) => {
expect(commandLog).toEqual([['gc'], ['timeBegin', 'benchpress0']]); expect(commandLog).toEqual([['gc'], ['timeBegin', 'benchpress0']]);
@ -157,7 +177,7 @@ export function main() {
eventFactory.markEnd('benchpress0', 10) eventFactory.markEnd('benchpress0', 10)
] ]
]; ];
var metric = createMetric(events); var metric = createMetric(events, null);
metric.beginMeasure() metric.beginMeasure()
.then((_) => metric.endMeasure(false)) .then((_) => metric.endMeasure(false))
.then((data) => { .then((data) => {
@ -182,7 +202,7 @@ export function main() {
], ],
[eventFactory.markEnd('benchpress1', 3)] [eventFactory.markEnd('benchpress1', 3)]
]; ];
var metric = createMetric(events); var metric = createMetric(events, null);
metric.beginMeasure() metric.beginMeasure()
.then((_) => metric.endMeasure(true)) .then((_) => metric.endMeasure(true))
.then((_) => metric.endMeasure(true)) .then((_) => metric.endMeasure(true))
@ -211,7 +231,7 @@ export function main() {
eventFactory.markEnd('benchpress0', 10) eventFactory.markEnd('benchpress0', 10)
] ]
]; ];
var metric = createMetric(events); var metric = createMetric(events, null);
metric.beginMeasure() metric.beginMeasure()
.then((_) => metric.endMeasure(false)) .then((_) => metric.endMeasure(false))
.then((data) => { .then((data) => {
@ -247,7 +267,7 @@ export function main() {
eventFactory.markEnd('benchpress1', 6) eventFactory.markEnd('benchpress1', 6)
] ]
]; ];
var metric = createMetric(events); var metric = createMetric(events, null);
metric.beginMeasure() metric.beginMeasure()
.then((_) => metric.endMeasure(true)) .then((_) => metric.endMeasure(true))
.then((data) => { .then((data) => {
@ -287,7 +307,7 @@ export function main() {
}); });
it('should measure forced gc', inject([AsyncTestCompleter], (async) => { it('should measure forced gc', inject([AsyncTestCompleter], (async) => {
var metric = createMetric(events, null, null, true); var metric = createMetric(events, null, {forceGc: true});
metric.beginMeasure() metric.beginMeasure()
.then((_) => metric.endMeasure(false)) .then((_) => metric.endMeasure(false))
.then((data) => { .then((data) => {
@ -309,7 +329,7 @@ export function main() {
})); }));
it('should restart after the forced gc if needed', inject([AsyncTestCompleter], (async) => { it('should restart after the forced gc if needed', inject([AsyncTestCompleter], (async) => {
var metric = createMetric(events, null, null, true); var metric = createMetric(events, null, {forceGc: true});
metric.beginMeasure() metric.beginMeasure()
.then((_) => metric.endMeasure(true)) .then((_) => metric.endMeasure(true))
.then((data) => { .then((data) => {
@ -325,10 +345,20 @@ export function main() {
describe('aggregation', () => { describe('aggregation', () => {
function aggregate(events: any[], microMetrics = null, captureFrames = null) { function aggregate(events: any[], {microMetrics, captureFrames, receivedData, requestCount}: {
microMetrics?: {[key: string]: string},
captureFrames?: boolean,
receivedData?: boolean,
requestCount?: boolean
} = {}) {
events.unshift(eventFactory.markStart('benchpress0', 0)); events.unshift(eventFactory.markStart('benchpress0', 0));
events.push(eventFactory.markEnd('benchpress0', 10)); events.push(eventFactory.markEnd('benchpress0', 10));
var metric = createMetric([events], microMetrics, null, null, captureFrames); var metric = createMetric([events], null, {
microMetrics: microMetrics,
captureFrames: captureFrames,
receivedData: receivedData,
requestCount: requestCount
});
return metric.beginMeasure().then((_) => metric.endMeasure(false)); return metric.beginMeasure().then((_) => metric.endMeasure(false));
} }
@ -342,7 +372,7 @@ export function main() {
eventFactory.instant('frame', 4), eventFactory.instant('frame', 4),
eventFactory.markEnd('frameCapture', 5) eventFactory.markEnd('frameCapture', 5)
], ],
null, true) {captureFrames: true})
.then((data) => { .then((data) => {
expect(data['frameTime.mean']).toBe(((3 - 1) + (4 - 3)) / 2); expect(data['frameTime.mean']).toBe(((3 - 1) + (4 - 3)) / 2);
async.done(); async.done();
@ -353,7 +383,7 @@ export function main() {
PromiseWrapper.catchError( PromiseWrapper.catchError(
aggregate( aggregate(
[eventFactory.instant('frame', 4), eventFactory.markEnd('frameCapture', 5)], [eventFactory.instant('frame', 4), eventFactory.markEnd('frameCapture', 5)],
null, true), {captureFrames: true}),
(err) => { (err) => {
expect(() => { throw err; }) expect(() => { throw err; })
.toThrowError('missing start event for frame capture'); .toThrowError('missing start event for frame capture');
@ -365,7 +395,7 @@ export function main() {
PromiseWrapper.catchError( PromiseWrapper.catchError(
aggregate( aggregate(
[eventFactory.markStart('frameCapture', 3), eventFactory.instant('frame', 4)], [eventFactory.markStart('frameCapture', 3), eventFactory.instant('frame', 4)],
null, true), {captureFrames: true}),
(err) => { (err) => {
expect(() => { throw err; }).toThrowError('missing end event for frame capture'); expect(() => { throw err; }).toThrowError('missing end event for frame capture');
async.done(); async.done();
@ -379,7 +409,7 @@ export function main() {
eventFactory.markStart('frameCapture', 3), eventFactory.markStart('frameCapture', 3),
eventFactory.markStart('frameCapture', 4) eventFactory.markStart('frameCapture', 4)
], ],
null, true), {captureFrames: true}),
(err) => { (err) => {
expect(() => { throw err; }) expect(() => { throw err; })
.toThrowError('can capture frames only once per benchmark run'); .toThrowError('can capture frames only once per benchmark run');
@ -399,7 +429,7 @@ export function main() {
it('should throw if frame capture is enabled, but nothing is captured', it('should throw if frame capture is enabled, but nothing is captured',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async) => {
PromiseWrapper.catchError(aggregate([], null, true), (err) => { PromiseWrapper.catchError(aggregate([], {captureFrames: true}), (err) => {
expect(() => { throw err; }) expect(() => { throw err; })
.toThrowError( .toThrowError(
'frame capture requested in benchpress, but no start event was found'); 'frame capture requested in benchpress, but no start event was found');
@ -419,7 +449,7 @@ export function main() {
eventFactory.instant('frame', 32), eventFactory.instant('frame', 32),
eventFactory.markEnd('frameCapture', 10) eventFactory.markEnd('frameCapture', 10)
], ],
null, true) {captureFrames: true})
.then((data) => { .then((data) => {
expect(data['frameTime.worst']).toBe(10); expect(data['frameTime.worst']).toBe(10);
expect(data['frameTime.best']).toBe(3); expect(data['frameTime.best']).toBe(3);
@ -437,7 +467,7 @@ export function main() {
eventFactory.instant('frame', 3), eventFactory.instant('frame', 3),
eventFactory.markEnd('frameCapture', 4) eventFactory.markEnd('frameCapture', 4)
], ],
null, true) {captureFrames: true})
.then((data) => { .then((data) => {
expect(data['frameTime.smooth']).toBe(1.0); expect(data['frameTime.smooth']).toBe(1.0);
async.done(); async.done();
@ -456,7 +486,7 @@ export function main() {
eventFactory.instant('frame', 24), eventFactory.instant('frame', 24),
eventFactory.markEnd('frameCapture', 4) eventFactory.markEnd('frameCapture', 4)
], ],
null, true) {captureFrames: true})
.then((data) => { .then((data) => {
expect(data['frameTime.smooth']).toBe(0.75); expect(data['frameTime.smooth']).toBe(0.75);
async.done(); async.done();
@ -518,16 +548,18 @@ export function main() {
it('should ignore events from different processed as the start mark', it('should ignore events from different processed as the start mark',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async) => {
var otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1'); var otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1');
var metric = createMetric([ var metric = createMetric(
[ [
eventFactory.markStart('benchpress0', 0), [
eventFactory.start('script', 0, null), eventFactory.markStart('benchpress0', 0),
eventFactory.end('script', 5, null), eventFactory.start('script', 0, null),
otherProcessEventFactory.start('script', 10, null), eventFactory.end('script', 5, null),
otherProcessEventFactory.end('script', 17, null), otherProcessEventFactory.start('script', 10, null),
eventFactory.markEnd('benchpress0', 20) otherProcessEventFactory.end('script', 17, null),
] eventFactory.markEnd('benchpress0', 20)
]); ]
],
null);
metric.beginMeasure() metric.beginMeasure()
.then((_) => metric.endMeasure(false)) .then((_) => metric.endMeasure(false))
.then((data) => { .then((data) => {
@ -594,6 +626,44 @@ export function main() {
}); });
})); }));
describe('receivedData',
() => {it('should report received data since last navigationStart',
inject([AsyncTestCompleter], (async) => {
aggregate(
[
eventFactory.instant('receivedData', 0, {'encodedDataLength': 1}),
eventFactory.instant('navigationStart', 1),
eventFactory.instant('receivedData', 2, {'encodedDataLength': 2}),
eventFactory.instant('navigationStart', 3),
eventFactory.instant('receivedData', 4, {'encodedDataLength': 4}),
eventFactory.instant('receivedData', 5, {'encodedDataLength': 8})
],
{receivedData: true})
.then((data) => {
expect(data['receivedData']).toBe(12);
async.done();
});
}))});
describe('requestCount',
() => {it('should report count of requests sent since last navigationStart',
inject([AsyncTestCompleter], (async) => {
aggregate(
[
eventFactory.instant('sendRequest', 0),
eventFactory.instant('navigationStart', 1),
eventFactory.instant('sendRequest', 2),
eventFactory.instant('navigationStart', 3),
eventFactory.instant('sendRequest', 4),
eventFactory.instant('sendRequest', 5)
],
{requestCount: true})
.then((data) => {
expect(data['requestCount']).toBe(2);
async.done();
});
}))});
describe('microMetrics', () => { describe('microMetrics', () => {
it('should report micro metrics', inject([AsyncTestCompleter], (async) => { it('should report micro metrics', inject([AsyncTestCompleter], (async) => {
@ -602,7 +672,7 @@ export function main() {
eventFactory.markStart('mm1', 0), eventFactory.markStart('mm1', 0),
eventFactory.markEnd('mm1', 5), eventFactory.markEnd('mm1', 5),
], ],
{'mm1': 'micro metric 1'}) {microMetrics: {'mm1': 'micro metric 1'}})
.then((data) => { .then((data) => {
expect(data['mm1']).toBe(5.0); expect(data['mm1']).toBe(5.0);
async.done(); async.done();
@ -627,7 +697,7 @@ export function main() {
eventFactory.markStart('mm1*20', 0), eventFactory.markStart('mm1*20', 0),
eventFactory.markEnd('mm1*20', 5), eventFactory.markEnd('mm1*20', 5),
], ],
{'mm1': 'micro metric 1'}) {microMetrics: {'mm1': 'micro metric 1'}})
.then((data) => { .then((data) => {
expect(data['mm1']).toBe(5 / 20); expect(data['mm1']).toBe(5 / 20);
async.done(); async.done();

View File

@ -44,6 +44,7 @@ export function main() {
var chrome45TimelineEvents = new TraceEventFactory('devtools.timeline', 'pid0'); var chrome45TimelineEvents = new TraceEventFactory('devtools.timeline', 'pid0');
var chromeTimelineV8Events = new TraceEventFactory('devtools.timeline,v8', 'pid0'); var chromeTimelineV8Events = new TraceEventFactory('devtools.timeline,v8', 'pid0');
var chromeBlinkTimelineEvents = new TraceEventFactory('blink,devtools.timeline', 'pid0'); var chromeBlinkTimelineEvents = new TraceEventFactory('blink,devtools.timeline', 'pid0');
var chromeBlinkUserTimingEvents = new TraceEventFactory('blink.user_timing', 'pid0');
var benchmarkEvents = new TraceEventFactory('benchmark', 'pid0'); var benchmarkEvents = new TraceEventFactory('benchmark', 'pid0');
var normEvents = new TraceEventFactory('timeline', 'pid0'); var normEvents = new TraceEventFactory('timeline', 'pid0');
@ -354,7 +355,48 @@ export function main() {
}); });
})); }));
it('should report navigationStart', inject([AsyncTestCompleter], (async) => {
createExtension([chromeBlinkUserTimingEvents.start('navigationStart', 1234)],
CHROME45_USER_AGENT)
.readPerfLog()
.then((events) => {
expect(events).toEqual([normEvents.start('navigationStart', 1.234)]);
async.done();
});
}));
it('should report receivedData', inject([AsyncTestCompleter], (async) => {
createExtension(
[
chrome45TimelineEvents.instant('ResourceReceivedData', 1234,
{'data': {'encodedDataLength': 987}})
],
CHROME45_USER_AGENT)
.readPerfLog()
.then((events) => {
expect(events).toEqual(
[normEvents.instant('receivedData', 1.234, {'encodedDataLength': 987})]);
async.done();
});
}));
it('should report sendRequest', inject([AsyncTestCompleter], (async) => {
createExtension(
[
chrome45TimelineEvents.instant(
'ResourceSendRequest', 1234,
{'data': {'url': 'http://here', 'requestMethod': 'GET'}})
],
CHROME45_USER_AGENT)
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.instant('sendRequest', 1.234,
{'url': 'http://here', 'method': 'GET'})
]);
async.done();
});
}));
}); });
describe('readPerfLog (common)', () => { describe('readPerfLog (common)', () => {