Skip to content

Commit

Permalink
perf: make network quiet threshold configurable per pass (#2220)
Browse files Browse the repository at this point in the history
* perf: make network quiet threshold configurable per pass

* lower it more

* split into 3 thresholds

* add comments
  • Loading branch information
patrickhulce committed May 13, 2017
1 parent ba618ce commit d99b5ad
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 31 deletions.
8 changes: 7 additions & 1 deletion lighthouse-core/config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ module.exports = {
"passes": [{
"passName": "defaultPass",
"recordTrace": true,
"pauseBeforeTraceEndMs": 5000,
"pauseAfterLoadMs": 5000,
"networkQuietThresholdMs": 5000,
"pauseAfterNetworkQuietMs": 2500,
"useThrottling": true,
"gatherers": [
"url",
Expand All @@ -29,6 +31,8 @@ module.exports = {
{
"passName": "offlinePass",
"useThrottling": false,
// Just wait for onload
"networkQuietThresholdMs": 0,
"gatherers": [
"service-worker",
"offline",
Expand All @@ -38,6 +42,8 @@ module.exports = {
{
"passName": "redirectPass",
"useThrottling": false,
// Just wait for onload
"networkQuietThresholdMs": 0,
// Speed up the redirect pass by blocking stylesheets, fonts, and images
"blockedUrlPatterns": ["*.css", "*.jpg", "*.jpeg", "*.png", "*.gif", "*.svg", "*.ttf", "*.woff", "*.woff2"],
"gatherers": [
Expand Down
74 changes: 47 additions & 27 deletions lighthouse-core/gather/driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,18 @@ const URL = require('../lib/url-shim');
const log = require('../lib/log.js');
const DevtoolsLog = require('./devtools-log');

const PAUSE_AFTER_LOAD = 5000;
// Controls how long to wait after onLoad before continuing
const DEFAULT_PAUSE_AFTER_LOAD = 0;
// Controls how long to wait between network requests before determining the network is quiet
const DEFAULT_NETWORK_QUIET_THRESHOLD = 5000;
// Controls how long to wait after network quiet before continuing
const DEFAULT_PAUSE_AFTER_NETWORK_QUIET = 0;

const _uniq = arr => Array.from(new Set(arr));

class Driver {
static get MAX_WAIT_FOR_FULLY_LOADED() {
return 25 * 1000;
return 30 * 1000;
}

/**
Expand Down Expand Up @@ -378,42 +383,46 @@ class Driver {

/**
* Returns a promise that resolves when the network has been idle for
* `pauseAfterLoadMs` ms and a method to cancel internal network listeners and
* `networkQuietThresholdMs` ms and a method to cancel internal network listeners and
* timeout.
* @param {string} pauseAfterLoadMs
* @param {number} networkQuietThresholdMs
* @param {number} pauseAfterNetworkQuietMs
* @return {{promise: !Promise, cancel: function()}}
* @private
*/
_waitForNetworkIdle(pauseAfterLoadMs) {
_waitForNetworkIdle(networkQuietThresholdMs, pauseAfterNetworkQuietMs) {
let idleTimeout;
let cancel;

const promise = new Promise((resolve, reject) => {
const onIdle = () => {
// eslint-disable-next-line no-use-before-define
this._networkStatusMonitor.once('networkbusy', onBusy);
this._networkStatusMonitor.once('network-2-busy', onBusy);
idleTimeout = setTimeout(_ => {
cancel();
resolve();
}, pauseAfterLoadMs);
}, networkQuietThresholdMs);
};

const onBusy = () => {
this._networkStatusMonitor.once('networkidle', onIdle);
this._networkStatusMonitor.once('network-2-idle', onIdle);
clearTimeout(idleTimeout);
};

cancel = () => {
clearTimeout(idleTimeout);
this._networkStatusMonitor.removeListener('networkbusy', onBusy);
this._networkStatusMonitor.removeListener('networkidle', onIdle);
this._networkStatusMonitor.removeListener('network-2-busy', onBusy);
this._networkStatusMonitor.removeListener('network-2-idle', onIdle);
};

if (this._networkStatusMonitor.isIdle()) {
if (this._networkStatusMonitor.is2Idle()) {
onIdle();
} else {
onBusy();
}
}).then(() => {
// Once idle has been determined wait another pauseAfterLoadMs
return new Promise(resolve => setTimeout(resolve, pauseAfterNetworkQuietMs));
});

return {
Expand Down Expand Up @@ -452,29 +461,34 @@ class Driver {

/**
* Returns a promise that resolves when:
* - it's been pauseAfterLoadMs milliseconds after both onload and the network
* - it's been networkQuietThresholdMs milliseconds after both onload and the network
* has gone idle, or
* - maxWaitForLoadedMs milliseconds have passed.
* See https://github.com/GoogleChrome/lighthouse/issues/627 for more.
* @param {number} pauseAfterLoadMs
* @param {number} networkQuietThresholdMs
* @param {number} pauseAfterNetworkQuietMs
* @param {number} maxWaitForLoadedMs
* @return {!Promise}
* @private
*/
_waitForFullyLoaded(pauseAfterLoadMs, maxWaitForLoadedMs) {
_waitForFullyLoaded(pauseAfterLoadMs, networkQuietThresholdMs, pauseAfterNetworkQuietMs,
maxWaitForLoadedMs) {
let maxTimeoutHandle;

// Listener for onload. Resolves pauseAfterLoadMs ms after load.
const waitForLoadEvent = this._waitForLoadEvent(pauseAfterLoadMs);
// Network listener. Resolves when the network has been idle for pauseAfterLoadMs.
const waitForNetworkIdle = this._waitForNetworkIdle(pauseAfterLoadMs);
// Network listener. Resolves pauseAfterNetworkQuietMs after when the network has been idle for
// networkQuietThresholdMs.
const waitForNetworkIdle = this._waitForNetworkIdle(networkQuietThresholdMs,
pauseAfterNetworkQuietMs);

// Wait for both load promises. Resolves on cleanup function the clears load
// timeout timer.
const loadPromise = Promise.all([
waitForLoadEvent.promise,
waitForNetworkIdle.promise
]).then(_ => {
]).then(() => {
return function() {
log.verbose('Driver', 'loadEventFired and network considered idle');
clearTimeout(maxTimeoutHandle);
Expand Down Expand Up @@ -554,15 +568,25 @@ class Driver {
gotoURL(url, options = {}) {
const waitForLoad = options.waitForLoad || false;
const disableJS = options.disableJavaScript || false;
const pauseAfterLoadMs = (options.flags && options.flags.pauseAfterLoad) || PAUSE_AFTER_LOAD;
const maxWaitMs = (options.flags && options.flags.maxWaitForLoad) ||
Driver.MAX_WAIT_FOR_FULLY_LOADED;

let pauseAfterLoadMs = options.config && options.config.pauseAfterLoadMs;
let networkQuietThresholdMs = options.config && options.config.networkQuietThresholdMs;
let pauseAfterNetworkQuietMs = options.config && options.config.pauseAfterNetworkQuietMs;
let maxWaitMs = options.flags && options.flags.maxWaitForLoad;

/* eslint-disable max-len */
if (typeof pauseAfterLoadMs !== 'number') pauseAfterLoadMs = DEFAULT_PAUSE_AFTER_LOAD;
if (typeof networkQuietThresholdMs !== 'number') networkQuietThresholdMs = DEFAULT_NETWORK_QUIET_THRESHOLD;
if (typeof pauseAfterNetworkQuietMs !== 'number') pauseAfterNetworkQuietMs = DEFAULT_PAUSE_AFTER_NETWORK_QUIET;
if (typeof maxWaitMs !== 'number') maxWaitMs = Driver.MAX_WAIT_FOR_FULLY_LOADED;
/* eslint-enable max-len */

return this._beginNetworkStatusMonitoring(url)
.then(_ => this.sendCommand('Page.enable'))
.then(_ => this.sendCommand('Emulation.setScriptExecutionDisabled', {value: disableJS}))
.then(_ => this.sendCommand('Page.navigate', {url}))
.then(_ => waitForLoad && this._waitForFullyLoaded(pauseAfterLoadMs, maxWaitMs))
.then(_ => waitForLoad && this._waitForFullyLoaded(pauseAfterLoadMs,
networkQuietThresholdMs, pauseAfterNetworkQuietMs, maxWaitMs))
.then(_ => this._endNetworkStatusMonitoring());
}

Expand Down Expand Up @@ -689,20 +713,16 @@ class Driver {
.then(_ => this.sendCommand('Tracing.start', tracingOpts));
}

/**
* @param {number=} pauseBeforeTraceEndMs Wait this many milliseconds before ending the trace
*/
endTrace(pauseBeforeTraceEndMs = 0) {
endTrace() {
return new Promise((resolve, reject) => {
// When the tracing has ended this will fire with a stream handle.
this.once('Tracing.tracingComplete', streamHandle => {
this._readTraceFromStream(streamHandle)
.then(traceContents => resolve(traceContents), reject);
});

// Issue the command to stop tracing after an optional delay.
// Audits like TTI may require slightly longer trace to find a minimum window size.
setTimeout(() => this.sendCommand('Tracing.end').catch(reject), pauseBeforeTraceEndMs);
// Issue the command to stop tracing.
return this.sendCommand('Tracing.end').catch(reject);
});
}

Expand Down
3 changes: 2 additions & 1 deletion lighthouse-core/gather/gather-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class GatherRunner {
waitForLoad: true,
disableJavaScript: !!options.disableJavaScript,
flags: options.flags,
config: options.config,
}).then(finalUrl => {
options.url = finalUrl;
});
Expand Down Expand Up @@ -248,7 +249,7 @@ class GatherRunner {
if (config.recordTrace) {
pass = pass.then(_ => {
log.log('status', 'Retrieving trace');
return driver.endTrace(config.pauseBeforeTraceEndMs);
return driver.endTrace();
}).then(traceContents => {
// Before Chrome 54.0.2816 (codereview.chromium.org/2161583004),
// traceContents was an array of trace events; after, traceContents is
Expand Down
13 changes: 13 additions & 0 deletions lighthouse-core/lib/network-recorder.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ class NetworkRecorder extends EventEmitter {
return this.activeRequestCount() === 0;
}

is2Idle() {
return this.activeRequestCount() <= 2;
}

/**
* Listener for the NetworkManager's RequestStarted event, which includes both
* web socket and normal request creation.
Expand All @@ -70,6 +74,11 @@ class NetworkRecorder extends EventEmitter {
if (activeCount === 1) {
this.emit('networkbusy');
}

// If exactly three requests in progress, we've transitioned from 2-idle to 2-busy.
if (activeCount === 3) {
this.emit('network-2-busy');
}
}

/**
Expand All @@ -92,6 +101,10 @@ class NetworkRecorder extends EventEmitter {
if (this.isIdle()) {
this.emit('networkidle');
}

if (this.is2Idle()) {
this.emit('network-2-idle');
}
}

// There are a few differences between the debugging protocol naming and
Expand Down
4 changes: 2 additions & 2 deletions lighthouse-core/test/gather/driver-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ describe('Browser Driver', () => {

const loadOptions = {
waitForLoad: true,
flags: {
pauseAfterLoad: 1
config: {
networkQuietThresholdMs: 1
}
};

Expand Down

0 comments on commit d99b5ad

Please sign in to comment.