feat: optionally save complete performance log in chrome benchpress tests (#27551)
If RAW_PERFLOG_PATH is passed in as an option, benchpress saves chrome's performance log to a json file. This allows developers to download the json file and upload it to their browser to get a breakdown of chrome-side resource usage during a test. PR Close #27551
This commit is contained in:
parent
2ea4f690e4
commit
d42f32cc61
|
@ -26,6 +26,7 @@ export class Options {
|
||||||
static RECEIVED_DATA = new InjectionToken('Options.receivedData');
|
static RECEIVED_DATA = new InjectionToken('Options.receivedData');
|
||||||
static REQUEST_COUNT = new InjectionToken('Options.requestCount');
|
static REQUEST_COUNT = new InjectionToken('Options.requestCount');
|
||||||
static CAPTURE_FRAMES = new InjectionToken('Options.frameCapture');
|
static CAPTURE_FRAMES = new InjectionToken('Options.frameCapture');
|
||||||
|
static RAW_PERFLOG_PATH = new InjectionToken('Options.rawPerflogPath');
|
||||||
static DEFAULT_PROVIDERS = [
|
static DEFAULT_PROVIDERS = [
|
||||||
{provide: Options.DEFAULT_DESCRIPTION, useValue: {}},
|
{provide: Options.DEFAULT_DESCRIPTION, useValue: {}},
|
||||||
{provide: Options.SAMPLE_DESCRIPTION, useValue: {}},
|
{provide: Options.SAMPLE_DESCRIPTION, useValue: {}},
|
||||||
|
@ -36,7 +37,8 @@ export class Options {
|
||||||
{provide: Options.RECEIVED_DATA, useValue: false},
|
{provide: Options.RECEIVED_DATA, useValue: false},
|
||||||
{provide: Options.REQUEST_COUNT, useValue: false},
|
{provide: Options.REQUEST_COUNT, useValue: false},
|
||||||
{provide: Options.CAPTURE_FRAMES, useValue: false},
|
{provide: Options.CAPTURE_FRAMES, useValue: false},
|
||||||
{provide: Options.WRITE_FILE, useValue: writeFile}
|
{provide: Options.WRITE_FILE, useValue: writeFile},
|
||||||
|
{provide: Options.RAW_PERFLOG_PATH, useValue: null}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Inject, Injectable, StaticProvider} from '@angular/core';
|
import {Inject, Injectable, StaticProvider} from '@angular/core';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
import {Options} from '../common_options';
|
import {Options} from '../common_options';
|
||||||
import {WebDriverAdapter} from '../web_driver_adapter';
|
import {WebDriverAdapter} from '../web_driver_adapter';
|
||||||
|
@ -23,15 +24,19 @@ import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_e
|
||||||
export class ChromeDriverExtension extends WebDriverExtension {
|
export class ChromeDriverExtension extends WebDriverExtension {
|
||||||
static PROVIDERS = <StaticProvider>[{
|
static PROVIDERS = <StaticProvider>[{
|
||||||
provide: ChromeDriverExtension,
|
provide: ChromeDriverExtension,
|
||||||
deps: [WebDriverAdapter, Options.USER_AGENT]
|
deps: [WebDriverAdapter, Options.USER_AGENT, Options.RAW_PERFLOG_PATH]
|
||||||
}];
|
}];
|
||||||
|
|
||||||
private _majorChromeVersion: number;
|
private _majorChromeVersion: number;
|
||||||
private _firstRun = true;
|
private _firstRun = true;
|
||||||
|
private _rawPerflogPath: string|null;
|
||||||
|
|
||||||
constructor(private _driver: WebDriverAdapter, @Inject(Options.USER_AGENT) userAgent: string) {
|
constructor(
|
||||||
|
private driver: WebDriverAdapter, @Inject(Options.USER_AGENT) userAgent: string,
|
||||||
|
@Inject(Options.RAW_PERFLOG_PATH) rawPerflogPath: string|null) {
|
||||||
super();
|
super();
|
||||||
this._majorChromeVersion = this._parseChromeVersion(userAgent);
|
this._majorChromeVersion = this._parseChromeVersion(userAgent);
|
||||||
|
this._rawPerflogPath = rawPerflogPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _parseChromeVersion(userAgent: string): number {
|
private _parseChromeVersion(userAgent: string): number {
|
||||||
|
@ -49,16 +54,16 @@ export class ChromeDriverExtension extends WebDriverExtension {
|
||||||
return parseInt(v, 10);
|
return parseInt(v, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
gc() { return this._driver.executeScript('window.gc()'); }
|
gc() { return this.driver.executeScript('window.gc()'); }
|
||||||
|
|
||||||
async timeBegin(name: string): Promise<any> {
|
async timeBegin(name: string): Promise<any> {
|
||||||
if (this._firstRun) {
|
if (this._firstRun) {
|
||||||
this._firstRun = false;
|
this._firstRun = false;
|
||||||
// Before the first run, read out the existing performance logs
|
// Before the first run, read out the existing performance logs
|
||||||
// so that the chrome buffer does not fill up.
|
// so that the chrome buffer does not fill up.
|
||||||
await this._driver.logs('performance');
|
await this.driver.logs('performance');
|
||||||
}
|
}
|
||||||
return this._driver.executeScript(`performance.mark('${name}-bpstart');`);
|
return this.driver.executeScript(`performance.mark('${name}-bpstart');`);
|
||||||
}
|
}
|
||||||
|
|
||||||
timeEnd(name: string, restartName: string|null = null): Promise<any> {
|
timeEnd(name: string, restartName: string|null = null): Promise<any> {
|
||||||
|
@ -66,7 +71,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
|
||||||
if (restartName) {
|
if (restartName) {
|
||||||
script += `performance.mark('${restartName}-bpstart');`;
|
script += `performance.mark('${restartName}-bpstart');`;
|
||||||
}
|
}
|
||||||
return this._driver.executeScript(script);
|
return this.driver.executeScript(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
// See [Chrome Trace Event
|
// See [Chrome Trace Event
|
||||||
|
@ -74,8 +79,8 @@ export class ChromeDriverExtension extends WebDriverExtension {
|
||||||
readPerfLog(): Promise<PerfLogEvent[]> {
|
readPerfLog(): Promise<PerfLogEvent[]> {
|
||||||
// TODO(tbosch): Chromedriver bug https://code.google.com/p/chromedriver/issues/detail?id=1098
|
// TODO(tbosch): Chromedriver bug https://code.google.com/p/chromedriver/issues/detail?id=1098
|
||||||
// Need to execute at least one command so that the browser logs can be read out!
|
// Need to execute at least one command so that the browser logs can be read out!
|
||||||
return this._driver.executeScript('1+1')
|
return this.driver.executeScript('1+1')
|
||||||
.then((_) => this._driver.logs('performance'))
|
.then((_) => this.driver.logs('performance'))
|
||||||
.then((entries) => {
|
.then((entries) => {
|
||||||
const events: PerfLogEvent[] = [];
|
const events: PerfLogEvent[] = [];
|
||||||
entries.forEach((entry: any) => {
|
entries.forEach((entry: any) => {
|
||||||
|
@ -87,6 +92,10 @@ export class ChromeDriverExtension extends WebDriverExtension {
|
||||||
throw new Error('The DevTools trace buffer filled during the test!');
|
throw new Error('The DevTools trace buffer filled during the test!');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this._rawPerflogPath && events.length) {
|
||||||
|
fs.appendFileSync(this._rawPerflogPath, JSON.stringify(events));
|
||||||
|
}
|
||||||
return this._convertPerfRecordsToEvents(events);
|
return this._convertPerfRecordsToEvents(events);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,8 @@ import {TraceEventFactory} from '../trace_event_factory';
|
||||||
provide: WebDriverAdapter,
|
provide: WebDriverAdapter,
|
||||||
useValue: new MockDriverAdapter(log, perfRecords, messageMethod)
|
useValue: new MockDriverAdapter(log, perfRecords, messageMethod)
|
||||||
},
|
},
|
||||||
{provide: Options.USER_AGENT, useValue: userAgent}
|
{provide: Options.USER_AGENT, useValue: userAgent},
|
||||||
|
{provide: Options.RAW_PERFLOG_PATH, useValue: null}
|
||||||
])
|
])
|
||||||
.get(ChromeDriverExtension);
|
.get(ChromeDriverExtension);
|
||||||
return extension;
|
return extension;
|
||||||
|
|
Loading…
Reference in New Issue