Add cpu throttling (#747)
Keep in mind that CPU throttling now available but disabled by default until proper UI is added. (#568, #784) If you want to use it: `--disable-cpu-throttling=false`
This commit is contained in:
Родитель
cf2b3d3ff9
Коммит
5cf4c131ff
|
@ -65,7 +65,9 @@ const cli = yargs
|
|||
'perf'
|
||||
], 'Configuration:')
|
||||
.describe({
|
||||
'mobile': 'Emulates a Nexus 5X',
|
||||
'disable-device-emulation': 'Disable Nexus 5X emulation',
|
||||
'disable-cpu-throttling': 'Disable CPU throttling',
|
||||
'disable-network-throttling': 'Disable network throttling',
|
||||
'save-assets': 'Save the trace contents & screenshots to disk',
|
||||
'save-artifacts': 'Save all gathered artifacts to disk',
|
||||
'list-all-audits': 'Prints a list of all available audits and exits',
|
||||
|
@ -88,11 +90,13 @@ Example: --output-path=./lighthouse-results.html`
|
|||
|
||||
// boolean values
|
||||
.boolean([
|
||||
'disable-device-emulation',
|
||||
'disable-cpu-throttling',
|
||||
'disable-network-throttling',
|
||||
'save-assets',
|
||||
'save-artifacts',
|
||||
'list-all-audits',
|
||||
'list-trace-categories',
|
||||
'mobile',
|
||||
'perf',
|
||||
'skip-autolaunch',
|
||||
'select-chrome',
|
||||
|
@ -103,7 +107,7 @@ Example: --output-path=./lighthouse-results.html`
|
|||
.choices('output', Printer.GetValidOutputOptions())
|
||||
|
||||
// default values
|
||||
.default('mobile', true)
|
||||
.default('disable-cpu-throttling', true)
|
||||
.default('output', Printer.GetValidOutputOptions()[Printer.OutputMode.pretty])
|
||||
.default('output-path', 'stdout')
|
||||
.check(argv => {
|
||||
|
|
|
@ -453,11 +453,22 @@ class Driver {
|
|||
return this.sendCommand('Runtime.enable');
|
||||
}
|
||||
|
||||
beginEmulation() {
|
||||
return Promise.all([
|
||||
emulation.enableNexus5X(this),
|
||||
emulation.enableNetworkThrottling(this)
|
||||
]);
|
||||
beginEmulation(flags) {
|
||||
const emulations = [];
|
||||
|
||||
if (!flags.disableDeviceEmulation) {
|
||||
emulations.push(emulation.enableNexus5X(this));
|
||||
}
|
||||
|
||||
if (!flags.disableNetworkThrottling) {
|
||||
emulations.push(emulation.enableNetworkThrottling(this));
|
||||
}
|
||||
|
||||
if (!flags.disableCpuThrottling) {
|
||||
emulations.push(emulation.enableCPUThrottling(this));
|
||||
}
|
||||
|
||||
return Promise.all(emulations);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -470,13 +481,13 @@ class Driver {
|
|||
|
||||
/**
|
||||
* Enable internet connection, using emulated mobile settings if
|
||||
* `options.flags.mobile` is true.
|
||||
* `options.flags.disableNetworkThrottling` is false.
|
||||
* @param {!Object} options
|
||||
* @return {!Promise}
|
||||
*/
|
||||
goOnline(options) {
|
||||
return this.sendCommand('Network.enable').then(_ => {
|
||||
if (options.flags.mobile) {
|
||||
if (!options.flags.disableNetworkThrottling) {
|
||||
return emulation.enableNetworkThrottling(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -84,8 +84,8 @@ class GatherRunner {
|
|||
|
||||
static setupDriver(driver, options) {
|
||||
log.log('status', 'Initializing…');
|
||||
// Enable emulation if required.
|
||||
return Promise.resolve(options.flags.mobile && driver.beginEmulation())
|
||||
// Enable emulation based on flags
|
||||
return driver.beginEmulation(options.flags)
|
||||
.then(_ => driver.enableRuntimeEvents())
|
||||
.then(_ => driver.cleanAndDisableBrowserCaches())
|
||||
.then(_ => driver.clearDataForOrigin(options.url));
|
||||
|
@ -204,10 +204,9 @@ class GatherRunner {
|
|||
return Promise.reject(new Error('You must provide a config'));
|
||||
}
|
||||
|
||||
// Default mobile emulation and page loading to true.
|
||||
// The extension will switch these off initially.
|
||||
if (typeof options.flags.mobile === 'undefined') {
|
||||
options.flags.mobile = true;
|
||||
// CPU throttling is temporarily off by default
|
||||
if (typeof options.flags.disableCpuThrottling === 'undefined') {
|
||||
options.flags.disableCpuThrottling = true;
|
||||
}
|
||||
|
||||
passes = this.instantiateGatherers(passes, options.config.configDir);
|
||||
|
|
|
@ -63,6 +63,13 @@ const NO_THROTTLING_METRICS = {
|
|||
offline: false
|
||||
};
|
||||
|
||||
const NO_CPU_THROTTLE_METRICS = {
|
||||
rate: 1
|
||||
};
|
||||
const CPU_THROTTLE_METRICS = {
|
||||
rate: 5
|
||||
};
|
||||
|
||||
function enableNexus5X(driver) {
|
||||
/**
|
||||
* Finalizes touch emulation by enabling `"ontouchstart" in window` feature detect
|
||||
|
@ -113,9 +120,19 @@ function goOffline(driver) {
|
|||
return driver.sendCommand('Network.emulateNetworkConditions', OFFLINE_METRICS);
|
||||
}
|
||||
|
||||
function enableCPUThrottling(driver) {
|
||||
return driver.sendCommand('Emulation.setCPUThrottlingRate', CPU_THROTTLE_METRICS);
|
||||
}
|
||||
|
||||
function disableCPUThrottling(driver) {
|
||||
return driver.sendCommand('Emulation.setCPUThrottlingRate', NO_CPU_THROTTLE_METRICS);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
enableNexus5X,
|
||||
enableNetworkThrottling,
|
||||
disableNetworkThrottling,
|
||||
enableCPUThrottling,
|
||||
disableCPUThrottling,
|
||||
goOffline
|
||||
};
|
||||
|
|
|
@ -30,12 +30,6 @@ class Runner {
|
|||
// Clean opts input.
|
||||
opts.flags = opts.flags || {};
|
||||
|
||||
// Default mobile emulation and page loading to true.
|
||||
// The extension will switch these off initially.
|
||||
if (typeof opts.flags.mobile === 'undefined') {
|
||||
opts.flags.mobile = true;
|
||||
}
|
||||
|
||||
const config = opts.config;
|
||||
|
||||
// save the initialUrl provided by the user
|
||||
|
|
|
@ -47,6 +47,39 @@ class TestGathererNoArtifact {
|
|||
|
||||
const fakeDriver = require('./fake-driver');
|
||||
|
||||
function getMockedEmulationDriver(emulationFn, netThrottleFn, cpuThrottleFn) {
|
||||
const Driver = require('../../gather/driver');
|
||||
const Connection = require('../../gather/connections/connection');
|
||||
const EmulationDriver = class extends Driver {
|
||||
enableRuntimeEvents() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
cleanAndDisableBrowserCaches() {}
|
||||
clearDataForOrigin() {}
|
||||
};
|
||||
const EmulationMock = class extends Connection {
|
||||
sendCommand(command) {
|
||||
let fn = null;
|
||||
switch (command) {
|
||||
case 'Network.emulateNetworkConditions':
|
||||
fn = netThrottleFn;
|
||||
break;
|
||||
case 'Emulation.setCPUThrottlingRate':
|
||||
fn = cpuThrottleFn;
|
||||
break;
|
||||
case 'Emulation.setDeviceMetricsOverride':
|
||||
fn = emulationFn;
|
||||
break;
|
||||
default:
|
||||
fn = null;
|
||||
break;
|
||||
}
|
||||
return Promise.resolve(fn && fn());
|
||||
}
|
||||
};
|
||||
return new EmulationDriver(new EmulationMock());
|
||||
}
|
||||
|
||||
describe('GatherRunner', function() {
|
||||
it('loads a page', () => {
|
||||
const driver = {
|
||||
|
@ -77,55 +110,113 @@ describe('GatherRunner', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('sets up the driver to begin emulation when mobile == true', () => {
|
||||
let calledEmulation = false;
|
||||
const driver = {
|
||||
beginEmulation() {
|
||||
calledEmulation = true;
|
||||
return Promise.resolve();
|
||||
},
|
||||
enableRuntimeEvents() {
|
||||
return Promise.resolve();
|
||||
},
|
||||
cleanAndDisableBrowserCaches() {
|
||||
return Promise.resolve();
|
||||
},
|
||||
clearDataForOrigin() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
it('sets up the driver to begin emulation when all emulation flags are undefined', () => {
|
||||
const tests = {
|
||||
calledDeviceEmulation: false,
|
||||
calledNetworkEmulation: false,
|
||||
calledCpuEmulation: false,
|
||||
};
|
||||
const createEmulationCheck = variable => () => {
|
||||
tests[variable] = true;
|
||||
|
||||
return GatherRunner.setupDriver(driver, {
|
||||
flags: {
|
||||
mobile: true
|
||||
}
|
||||
}).then(_ => {
|
||||
assert.equal(calledEmulation, true);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not set up the driver to begin emulation when mobile == false', () => {
|
||||
let calledEmulation = false;
|
||||
const driver = {
|
||||
beginEmulation() {
|
||||
calledEmulation = true;
|
||||
return Promise.resolve();
|
||||
},
|
||||
enableRuntimeEvents() {
|
||||
return Promise.resolve();
|
||||
},
|
||||
cleanAndDisableBrowserCaches() {
|
||||
return Promise.resolve();
|
||||
},
|
||||
clearDataForOrigin() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const driver = getMockedEmulationDriver(
|
||||
createEmulationCheck('calledDeviceEmulation'),
|
||||
createEmulationCheck('calledNetworkEmulation'),
|
||||
createEmulationCheck('calledCpuEmulation')
|
||||
);
|
||||
|
||||
return GatherRunner.setupDriver(driver, {
|
||||
flags: {}
|
||||
}).then(_ => {
|
||||
assert.equal(calledEmulation, false);
|
||||
assert.equal(tests.calledDeviceEmulation, true);
|
||||
assert.equal(tests.calledNetworkEmulation, true);
|
||||
assert.equal(tests.calledCpuEmulation, true);
|
||||
});
|
||||
});
|
||||
|
||||
it(`sets up the driver to stop device emulation when
|
||||
disableDeviceEmulation flag is true`, () => {
|
||||
const tests = {
|
||||
calledDeviceEmulation: false,
|
||||
calledNetworkEmulation: false,
|
||||
calledCpuEmulation: false,
|
||||
};
|
||||
const createEmulationCheck = variable => () => {
|
||||
tests[variable] = true;
|
||||
return true;
|
||||
};
|
||||
const driver = getMockedEmulationDriver(
|
||||
createEmulationCheck('calledDeviceEmulation', false),
|
||||
createEmulationCheck('calledNetworkEmulation', true),
|
||||
createEmulationCheck('calledCpuEmulation', true)
|
||||
);
|
||||
|
||||
return GatherRunner.setupDriver(driver, {
|
||||
flags: {
|
||||
disableDeviceEmulation: true,
|
||||
}
|
||||
}).then(_ => {
|
||||
assert.equal(tests.calledDeviceEmulation, false);
|
||||
assert.equal(tests.calledNetworkEmulation, true);
|
||||
assert.equal(tests.calledCpuEmulation, true);
|
||||
});
|
||||
});
|
||||
|
||||
it(`sets up the driver to stop network throttling when
|
||||
disableNetworkThrottling flag is true`, () => {
|
||||
const tests = {
|
||||
calledDeviceEmulation: false,
|
||||
calledNetworkEmulation: false,
|
||||
calledCpuEmulation: false,
|
||||
};
|
||||
const createEmulationCheck = variable => () => {
|
||||
tests[variable] = true;
|
||||
return true;
|
||||
};
|
||||
const driver = getMockedEmulationDriver(
|
||||
createEmulationCheck('calledDeviceEmulation'),
|
||||
createEmulationCheck('calledNetworkEmulation'),
|
||||
createEmulationCheck('calledCpuEmulation')
|
||||
);
|
||||
|
||||
return GatherRunner.setupDriver(driver, {
|
||||
flags: {
|
||||
disableNetworkThrottling: true,
|
||||
}
|
||||
}).then(_ => {
|
||||
assert.equal(tests.calledDeviceEmulation, true);
|
||||
assert.equal(tests.calledNetworkEmulation, false);
|
||||
assert.equal(tests.calledCpuEmulation, true);
|
||||
});
|
||||
});
|
||||
|
||||
it(`sets up the driver to stop cpu throttling when
|
||||
disableCpuThrottling flag is true`, () => {
|
||||
const tests = {
|
||||
calledDeviceEmulation: false,
|
||||
calledNetworkEmulation: false,
|
||||
calledCpuEmulation: false,
|
||||
};
|
||||
const createEmulationCheck = variable => () => {
|
||||
tests[variable] = true;
|
||||
return true;
|
||||
};
|
||||
const driver = getMockedEmulationDriver(
|
||||
createEmulationCheck('calledDeviceEmulation'),
|
||||
createEmulationCheck('calledNetworkEmulation'),
|
||||
createEmulationCheck('calledCpuEmulation')
|
||||
);
|
||||
|
||||
return GatherRunner.setupDriver(driver, {
|
||||
flags: {
|
||||
disableCpuThrottling: true,
|
||||
}
|
||||
}).then(_ => {
|
||||
assert.equal(tests.calledDeviceEmulation, true);
|
||||
assert.equal(tests.calledNetworkEmulation, true);
|
||||
assert.equal(tests.calledCpuEmulation, false);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ document.addEventListener('DOMContentLoaded', _ => {
|
|||
.then(selectedAudits => {
|
||||
return background.runLighthouseInExtension({
|
||||
flags: {
|
||||
mobile: true
|
||||
disableCpuThrottling: true
|
||||
},
|
||||
restoreCleanState: true
|
||||
}, selectedAudits);
|
||||
|
|
34
readme.md
34
readme.md
|
@ -116,28 +116,30 @@ $ lighthouse --help
|
|||
lighthouse <url>
|
||||
|
||||
Logging:
|
||||
--verbose Displays verbose logging [boolean]
|
||||
--quiet Displays no progress or debug logs [boolean]
|
||||
--verbose Displays verbose logging [boolean]
|
||||
--quiet Displays no progress or debug logs [boolean]
|
||||
|
||||
Configuration:
|
||||
--mobile Emulates a Nexus 5X [default: true]
|
||||
--save-assets Save the trace contents & screenshots to disk [boolean]
|
||||
--save-artifacts Save all gathered artifacts to disk [boolean]
|
||||
--list-all-audits Prints a list of all available audits and exits [boolean]
|
||||
--list-trace-categories Prints a list of all required trace categories and exits [boolean]
|
||||
--config-path The path to the config JSON.
|
||||
--perf Use a performance-test-only configuration [boolean]
|
||||
--disable-device-emulation Disable device emulation [boolean]
|
||||
--disable-cpu-throttling Disable cpu throttling [boolean]
|
||||
--disable-network-throttling Disable network throttling [boolean]
|
||||
--save-assets Save the trace contents & screenshots to disk [boolean]
|
||||
--save-artifacts Save all gathered artifacts to disk [boolean]
|
||||
--list-all-audits Prints a list of all available audits and exits [boolean]
|
||||
--list-trace-categories Prints a list of all required trace categories and exits [boolean]
|
||||
--config-path The path to the config JSON.
|
||||
--perf Use a performance-test-only configuration [boolean]
|
||||
|
||||
Output:
|
||||
--output Reporter for the results
|
||||
[choices: "pretty", "json", "html"] [default: "pretty"]
|
||||
[choices: "pretty", "json", "html"] [default: "pretty"]
|
||||
--output-path The file path to output the results
|
||||
Example: --output-path=./lighthouse-results.html [default: "stdout"]
|
||||
Example: --output-path=./lighthouse-results.html [default: "stdout"]
|
||||
|
||||
Options:
|
||||
--help Show help [boolean]
|
||||
--version Show version number [boolean]
|
||||
--skip-autolaunch Skip autolaunch of Chrome when accessing port 9222 fails [boolean]
|
||||
--help Show help [boolean]
|
||||
--version Show version number [boolean]
|
||||
--skip-autolaunch Skip autolaunch of Chrome when accessing port 9222 fails [boolean]
|
||||
--select-chrome Interactively choose version of Chrome to use when multiple
|
||||
installations are found [boolean]
|
||||
```
|
||||
|
@ -146,6 +148,8 @@ Options:
|
|||
|
||||
Lighthouse can run against a real mobile device. You can follow the [Remote Debugging on Android (Legacy Workflow)](https://developer.chrome.com/devtools/docs/remote-debugging-legacy) up through step 3.3, but the TL;DR is install & run adb, enable USB debugging, then port forward 9222 from the device to the machine with Lighthouse.
|
||||
|
||||
You'll likely want to use the CLI flags `--disable-device-emulation --disable-cpu-throttling` and potentially `--disable-network-throttling`.
|
||||
|
||||
```sh
|
||||
$ adb kill-server
|
||||
|
||||
|
@ -156,7 +160,7 @@ $ adb devices -l
|
|||
|
||||
$ adb forward tcp:9222 localabstract:chrome_devtools_remote
|
||||
|
||||
$ lighthouse --mobile false https://mysite.com
|
||||
$ lighthouse --disable-device-emulation --disable-cpu-throttling https://mysite.com
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
|
Загрузка…
Ссылка в новой задаче