Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cpu throttle #747

Merged
merged 11 commits into from
Oct 26, 2016
Merged

Add cpu throttle #747

merged 11 commits into from
Oct 26, 2016

Conversation

wardpeet
Copy link
Collaborator

@wardpeet wardpeet commented Oct 5, 2016

No description provided.

@wardpeet
Copy link
Collaborator Author

wardpeet commented Oct 5, 2016

is there any way I can check if throttling actually works?

@paulirish
Copy link
Member

is there any way I can check if throttling actually works?

iterations = 0;
while (iterations < 1000){
   somethingExpensive();
   iterations++;
}

run that in a script tag in the head and our existing perf metrics should capture the cost.

function disableCPUThrottling(driver) {
return driver.sendCommand('Emulation.setCPUThrottlingRate', NO_CPU_THROTTLE_METRICS);
}

Copy link
Member

Choose a reason for hiding this comment

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

Just a thought: I'm curious if it's possible for us to get clever with Lighthouse's usage of CPU throttling. As throttling is relative to the system you're testing on, you can experience some pretty wildly different results. 5x throttling on a high-end Mac is going to be different to 5x throttling on a lower end computer. I wonder if it might be possible to do a pass that could determine system "highendness" and normalize throttling accordingly.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I see, we could use require('os') and check cpu ghz
require('os').cpus()

[ { model: 'Intel(R) Core(TM) i7-5557U CPU @ 3.10GHz',
    speed: 3100,
    times: { user: 6248100, nice: 0, sys: 5165850, idle: 28768980, irq: 0 } },
  { model: 'Intel(R) Core(TM) i7-5557U CPU @ 3.10GHz',
    speed: 3100,
    times: { user: 2609450, nice: 0, sys: 1979810, idle: 35592290, irq: 0 } },
  { model: 'Intel(R) Core(TM) i7-5557U CPU @ 3.10GHz',
    speed: 3100,
    times: { user: 5899370, nice: 0, sys: 4368220, idle: 29913970, irq: 0 } },
  { model: 'Intel(R) Core(TM) i7-5557U CPU @ 3.10GHz',
    speed: 3100,
    times: { user: 2701570, nice: 0, sys: 2006030, idle: 35473940, irq: 0 } } ]

Copy link
Member

Choose a reason for hiding this comment

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

Prolly worth seeing what senor @paulirish thinks of the idea :)

Copy link
Member

@paulirish paulirish Oct 5, 2016

Choose a reason for hiding this comment

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

Ayup, previous discussion over in #33.

We definitely want something browser friendly, so I don't think we should rely on advertised clock speed via the os module.

IMO calibrating the throttling rate so that all machines achieve an even result is totally worthwhile, but it's something we should start with a design doc and a framework for measurement. IMO the x5 multiplier will tide us over for a while, and we can pick up calibration in a quarter or so.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We could use https://developer.chrome.com/extensions/system_cpu in the extension and require('os') in the cli and update it later if we know a better solution

Copy link
Member

Choose a reason for hiding this comment

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

IMO the 5X will tide us over for a while, and we can pick up calibration in a quarter or so.

👍

Copy link
Member

Choose a reason for hiding this comment

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

FWIW an early patch for cpu throttling allowed the user to put in their octane results. We would use those to compare against saved results for mobile devices.

@@ -492,7 +492,8 @@ class Driver {
beginEmulation() {
return Promise.all([
emulation.enableNexus5X(this),
emulation.enableNetworkThrottling(this)
emulation.enableNetworkThrottling(this),
Copy link
Member

Choose a reason for hiding this comment

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

can you add the disable flags in this PR too?
#646 (comment)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will do

Copy link
Member

Choose a reason for hiding this comment

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

while you're in there... :)

can you add the --disable-device-emulation flag as well? So you'll be adding all three: --disable-device-emulation --disable-cpu-throttling --disable-network-throttling

Copy link
Collaborator Author

@wardpeet wardpeet Oct 11, 2016

Choose a reason for hiding this comment

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

should I remove --mobile? or keep it as a shortcut?

Copy link
Member

Choose a reason for hiding this comment

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

yes. :)

@@ -492,7 +492,8 @@ class Driver {
beginEmulation() {
return Promise.all([
emulation.enableNexus5X(this),
emulation.enableNetworkThrottling(this)
emulation.enableNetworkThrottling(this),
//emulation.enableCPUThrottling(this),
Copy link
Member

Choose a reason for hiding this comment

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

CPU throttling should be on by default. Disabled if turned off by the flag.

If users are running LH against real phones, they'll have to do --disable-device-emulation --disable-cpu-throttling --disable-network-throttling themselves for now.

Copy link
Member

Choose a reason for hiding this comment

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

Worth this PR including a one-liner comment to the README that mentions that requirement for real phones?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will do

Copy link
Member

Choose a reason for hiding this comment

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

Thanks @wardpeet!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@wardpeet
Copy link
Collaborator Author

I have to update the tests so travis will fail but you can already have a look :)

@@ -61,6 +61,9 @@ const cli = yargs
], 'Configuration:')
.describe({
'mobile': 'Emulates a Nexus 5X',
Copy link
Member

Choose a reason for hiding this comment

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

let's nuke the mobile flag. sorry i wasn't explicit about that but that's what i meant to say in #646

beginEmulation(flags) {
let emulations = [];

if (!flags.enableDeviceEmulation && flags.mobile) {
Copy link
Member

Choose a reason for hiding this comment

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

enable -> disable?

Copy link
Member

Choose a reason for hiding this comment

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

you coming back on these? would love the help. needed these flags yesterday. :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yes fixing this now :p

@wardpeet
Copy link
Collaborator Author

wardpeet commented Oct 14, 2016

@paulirish fixed and updated with tests
sadly I don't like the test cases, maybe we should add some kind of mock framework?

Copy link
Member

@brendankenny brendankenny left a comment

Choose a reason for hiding this comment

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

review!

@@ -506,7 +517,7 @@ class Driver {

/**
* Enable internet connection, using emulated mobile settings if
* `options.flags.mobile` is true.
* `options.flags.disableNetworkThrottling` is false.
Copy link
Member

Choose a reason for hiding this comment

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

mobile flag is still used below

emulation.enableNetworkThrottling(this)
]);
beginEmulation(flags) {
let emulations = [];
Copy link
Member

Choose a reason for hiding this comment

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

const

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Reason why I don't use const here is because I modify the object. When using const I assume the data is not going to be changed. But I can change it :)

// Enable emulation if required.
return Promise.resolve(options.flags.mobile && driver.beginEmulation())
// Enable emulation
// Will check what emulation needs to be done based on flags
Copy link
Member

Choose a reason for hiding this comment

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

one line comment, maybe // Enable emulation based on flags ?

return Promise.resolve(options.flags.mobile && driver.beginEmulation())
// Enable emulation
// Will check what emulation needs to be done based on flags
return Promise.resolve(driver.beginEmulation(options.flags))
Copy link
Member

Choose a reason for hiding this comment

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

can drop the Promise.resolve, just return driver.beginEmulation(options.flags)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

correct :) returns a promise anyway

--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]
--mobile Emulates a Nexus 5X [default: true]
Copy link
Member

Choose a reason for hiding this comment

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

--mobile still here. This needs to be regenerated?

Copy link
Member

Choose a reason for hiding this comment

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

@wardpeet can you file an followup issue for our calibration-based throttling?

Copy link
Collaborator Author

@wardpeet wardpeet Oct 24, 2016

Choose a reason for hiding this comment

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

```

## Lighthouse w/ mobile devices

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.

Run the cli with --disable-device-emulation=true configuration to disable device emulation.
Copy link
Member

Choose a reason for hiding this comment

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

don't need the =true here. Run the cli with --disable-device-emulation flag to disable device emulation.?

Copy link
Member

@paulirish paulirish left a comment

Choose a reason for hiding this comment

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

I think we're done here once things from brendan and I are addressed. Excited about this!

emulations.push(emulation.enableNetworkThrottling(this));
}

if (!flags.disableCpuThrottling) {
Copy link
Member

Choose a reason for hiding this comment

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

Let's make the cpu throttle disabled by default to start. Once the other stuff like #784 is all done we can flip that flag.

--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]
--mobile Emulates a Nexus 5X [default: true]
Copy link
Member

Choose a reason for hiding this comment

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

@wardpeet can you file an followup issue for our calibration-based throttling?

@@ -47,6 +47,31 @@ class TestGathererNoArtifact {

const fakeDriver = require('./fake-driver');

function getMockedEmulationDriver(deviceEmulation, networkThrottle, cpuThrottle) {
Copy link
Member

Choose a reason for hiding this comment

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

rename to emulationFn, netThrottleFn, cpuThrottleFn

};
let createEmulationCheck = variable => () => {
tests[variable] = true;

Copy link
Member

Choose a reason for hiding this comment

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

nuke empty line on this and the others

sendCommand(command) {
switch (command) {
case 'Network.emulateNetworkConditions':
return Promise.resolve(networkThrottle && networkThrottle());
Copy link
Member

Choose a reason for hiding this comment

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

Just wondering if we could do these a tad dryer..

         case 'Network.emulateNetworkConditions':
            fn = netThrottleFn;
// ...
        }
        return Promise.resolve(fn && fn());

wdyt?

@wardpeet
Copy link
Collaborator Author

will have some time today to address these issue, we had some storage crisis.

Copy link
Member

@paulirish paulirish left a comment

Choose a reason for hiding this comment

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

yup this works for me. Thanks so much for making this happen!

will wait for @brendankenny brendan to +1 before landing..

@paulirish
Copy link
Member

@wardpeet can you resolve the conflicts in preparation to land?

@wardpeet
Copy link
Collaborator Author

Yes will merge

Copy link
Member

@brendankenny brendankenny left a comment

Choose a reason for hiding this comment

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

looking good. I'll take a last look once the merge conflicts are resolved

@@ -100,7 +104,7 @@ Example: --output-path=./lighthouse-results.html`
.choices('output', Object.keys(Printer.OUTPUT_MODE))

// default values
.default('mobile', true)
.default('disable-cpu-throttling', true)
Copy link
Member

Choose a reason for hiding this comment

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

this default should be in driver.beginEmulation() as well, since without it there, anyone using LH as a module will be cpu throttled

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

added to gather-runner

```

## Lighthouse w/ mobile devices

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.

Run the cli with --disable-device-emulation configuration to disable device emulation.
Copy link
Member

Choose a reason for hiding this comment

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

it seems like you'd want to run with all three --disable-* flags when running on a real device?

Copy link
Collaborator Author

@wardpeet wardpeet Oct 25, 2016

Choose a reason for hiding this comment

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

Not always because you might still need network throttling. And cpu throttling is disabled by default.

@wardpeet
Copy link
Collaborator Author

Will have to cleanup gather-runner-test in another PR with the connection Class. But for now the tests work again

@googlebot
Copy link

We found a Contributor License Agreement for you (the sender of this pull request) and all commit authors, but as best as we can tell these commits were authored by someone else. If that's the case, please add them to this pull request and have them confirm that they're okay with these commits being contributed to Google. If we're mistaken and you did author these commits, just reply here to confirm.

@wardpeet
Copy link
Collaborator Author

@paulirish thanks :)

@paulirish
Copy link
Member

Without cpu throttling:
image

With cpu throttling:
image

@paulirish
Copy link
Member

Landing! Thanks for the hookup on this, @wardpeet!
_

Keep in mind that CPU throttling is landing but disabled by default until proper UI is added. (#568, #784)

If you want to use it... lighthouse --disable-cpu-throttling=false ...

@paulirish paulirish merged commit 5cf4c13 into master Oct 26, 2016
@paulirish paulirish deleted the feature/cpu-throttle branch October 26, 2016 16:52
andrewrota pushed a commit to andrewrota/lighthouse that referenced this pull request Jan 13, 2017
Keep in mind that CPU throttling now available but disabled by default until proper UI is added. (GoogleChrome#568, GoogleChrome#784)

If you want to use it: `--disable-cpu-throttling=false`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants