X Tutup
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions modules/benchpress/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)], ... )

# 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

* Use normalized environments
Expand Down
8 changes: 8 additions & 0 deletions modules/benchpress/src/common_options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export class Options {
// TODO(tbosch): use static values when our transpiler supports them
static get MICRO_METRICS() { return _MICRO_METRICS; }
// 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; }
}

Expand All @@ -40,6 +44,8 @@ var _USER_AGENT = new OpaqueToken('Options.userAgent');
var _MICRO_METRICS = new OpaqueToken('Options.microMetrics');
var _NOW = new OpaqueToken('Options.now');
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 _DEFAULT_PROVIDERS = [
Expand All @@ -50,5 +56,7 @@ var _DEFAULT_PROVIDERS = [
provide(_PREPARE, {useValue: false}),
provide(_MICRO_METRICS, {useValue: {}}),
provide(_NOW, {useValue: () => DateWrapper.now()}),
provide(_RECEIVED_DATA, {useValue: false}),
provide(_REQUEST_COUNT, {useValue: false}),
provide(_CAPTURE_FRAMES, {useValue: false})
];
47 changes: 42 additions & 5 deletions modules/benchpress/src/metric/perflog_metric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,18 @@ export class PerflogMetric extends Metric {
**/
constructor(private _driverExtension: WebDriverExtension, private _setTimeout: Function,
private _microMetrics: {[key: string]: any}, private _forceGc: boolean,
private _captureFrames: boolean) {
private _captureFrames: boolean, private _receivedData: boolean,
private _requestCount: boolean) {
super();

this._remainingEvents = [];
this._measureCount = 0;
this._perfLogFeatures = _driverExtension.perfLogFeatures();
if (!this._perfLogFeatures.userTiming) {
// User timing is needed for navigationStart.
this._receivedData = false;
this._requestCount = false;
}
}

describe(): {[key: string]: any} {
Expand All @@ -61,6 +67,12 @@ export class PerflogMetric extends Metric {
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._perfLogFeatures.frameCapture) {
var warningMsg = 'WARNING: Metric requested, but not supported by driver';
Expand Down Expand Up @@ -188,6 +200,12 @@ export class PerflogMetric extends Metric {
result['frameTime.smooth'] = 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 markEndEvent = null;
Expand Down Expand Up @@ -217,6 +235,22 @@ export class PerflogMetric extends Metric {
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) &&
event['pid'] === markStartEvent['pid']) {
if (StringWrapper.equals(ph, 'b') && StringWrapper.equals(name, _MARK_NAME_FRAME_CAPUTRE)) {
Expand All @@ -236,7 +270,7 @@ export class PerflogMetric extends Metric {
frameCaptureEndEvent = event;
}

if (StringWrapper.equals(ph, 'I') || StringWrapper.equals(ph, 'i')) {
if (isInstant) {
if (isPresent(frameCaptureStartEvent) && isBlank(frameCaptureEndEvent) &&
StringWrapper.equals(name, 'frame')) {
frameTimestamps.push(event['ts']);
Expand Down Expand Up @@ -332,14 +366,17 @@ var _FRAME_TIME_SMOOTH_THRESHOLD = 17;
var _PROVIDERS = [
bind(PerflogMetric)
.toFactory(
(driverExtension, setTimeout, microMetrics, forceGc, captureFrames) =>
new PerflogMetric(driverExtension, setTimeout, microMetrics, forceGc, captureFrames),
(driverExtension, setTimeout, microMetrics, forceGc, captureFrames, receivedData,
requestCount) => new PerflogMetric(driverExtension, setTimeout, microMetrics, forceGc,
captureFrames, receivedData, requestCount),
[
WebDriverExtension,
_SET_TIMEOUT,
Options.MICRO_METRICS,
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)})
];
7 changes: 5 additions & 2 deletions modules/benchpress/src/web_driver_extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,15 @@ export class PerfLogFeatures {
render: boolean;
gc: boolean;
frameCapture: boolean;
userTiming: boolean;

constructor({render = false, gc = false, frameCapture = false}:
{render?: boolean, gc?: boolean, frameCapture?: boolean} = {}) {
constructor(
{render = false, gc = false, frameCapture = false, userTiming = false}:
{render?: boolean, gc?: boolean, frameCapture?: boolean, userTiming?: boolean} = {}) {
this.render = render;
this.gc = gc;
this.frameCapture = frameCapture;
this.userTiming = userTiming;
}
}

Expand Down
11 changes: 10 additions & 1 deletion modules/benchpress/src/webdriver/chrome_driver_extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,15 @@ export class ChromeDriverExtension extends WebDriverExtension {
this._isEvent(categories, name, ['devtools.timeline'], 'Layout') ||
this._isEvent(categories, name, ['devtools.timeline'], 'Paint')) {
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')) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add the category blink.user_timing to https://github.com/angular/angular/blob/master/protractor-shared.js#L41? Or is it automatically included via the categories v8,blink.console,devtools.timeline that we already have there?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to come for free through blink.console, actually.

return normalizeEvent(event, {'name': name});
}
return null; // nothing useful in this event
}
Expand All @@ -208,7 +217,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
}

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 {
Expand Down
Loading
X Tutup