Process-level suspend/throttle of content/plugins [e10s]

RESOLVED WONTFIX

Status

()

Core
IPC
--
enhancement
RESOLVED WONTFIX
7 years ago
7 years ago

People

(Reporter: azakai, Unassigned)

Tracking

Firefox Tracking Flags

(Not tracked)

Details

Attachments

(1 attachment, 1 obsolete attachment)

(Reporter)

Description

7 years ago
It would be useful to allow content and/or plugin process to be suspended (frozen completely) or throttled (limited in CPU use) by chrome. Potential uses:

1. Suspend or throttle background tabs in order to save power on mobile devices
2. Throttle plugins so they don't needlessly consume lots of CPU
3. Suspend content when panning on mobile devices (to free up CPU) or during certain other situations
4. Suspend all content&plugins when idle, like a screensaver, in order to save power on mobile devices

The main motivation for this arose in the mobile context (https://wiki.mozilla.org/Mobile/Powersaving#OS-level_process_control ), but it should be useful on desktop Firefox as well.

One way to implement this in e10s is to use OS-level commands on processes. I have a working demo of suspend and throttle on both regular desktop Firefox on Linux and Fennec on an N900, by basically just sending SIG_STOP, SIG_CONT to the process (once to suspend, or at high frequency to throttle). So this is very simple to implement, and the OS guarantees it will work properly (whereas if we work hard to implement this in our own code, we will need to carefully suspend JS, animations, etc. etc. separately).

This is Linux-specific at this point. Not sure if similar things can be done elsewhere or not. But even if it is just Linux, it would be very useful for mobile devices (especially if this works not just on Maemo but also, as we hope, on Android - need to test that).

The actual implementation, as mentioned above, is fairly trivial (and there is a working demo). A bigger question is how to properly integrate this in the code. Some thoughts:

1. Would be nice to have this scriptable, so the UI JS code can customize how this works. Also, this would allow people to write addons that provide GUIs for this or otherwise customize it (example uses: let you throttle plugin processes at will; let you specify a list of websites to *not* suspend when in the background - like music-playing sites - while all the rest are suspended; etc.).
2. At the C++ level, perhaps an interface to this should be added to the TabParent or ContentProcessParent? On a lower level than that, would we want to add the actual signal-sending commands to the Chromium 'Process' class? (to live alongside the Terminate etc. functions there)
3. The actual functionality we want to expose should include throttling a content or plugin process to X% CPU, where 100% means stop throttling/suspending, 0% means suspend, and anything in the middle means throttle, and a command to return the current throttle setting of the process. Also useful to expose is the CPU % of each process (code deciding what to throttle/suspend might want to know that).
How do you know that, when you throttle a content or plugin process, you aren't also throttling something in the foreground tab?

Also, how do you ensure that you aren't sending messages or sending RPC calls to the throttled process, so that the hang detector doesn't kick in and kill it?

This sounds *really* complicated to get right.
(Reporter)

Comment 2

7 years ago
(In reply to comment #1)
> How do you know that, when you throttle a content or plugin process, you aren't
> also throttling something in the foreground tab?

In some cases it is definitely hard to decide *what* to throttle, so the user experience isn't disrupted. But for other use cases it is easier, for example, throttling content substantially (say to 5%) in order to save power when idle on a mobile device.

So it would be hard to *completely* fulfill the potential in this approach, but to gain substantial benefits should be fairly easy. And a lot of the other stuff would be the responsibility of a higher level, like an addon that has a whitelist of sites that are ok to throttle, and when/how, or implements some other custom behavior that the addon knows is ok.

> 
> Also, how do you ensure that you aren't sending messages or sending RPC calls
> to the throttled process, so that the hang detector doesn't kick in and kill
> it?
> 

Good point, the hang detector needs to be made aware of suspend settings - that is, to not detect a process as hanging when it is suspended. Would that be difficult?

(For throttling, as opposed to suspending, there should be no issue anyhow, I think?)

Comment 3

7 years ago
Alon, do you have some experimental patch for suspending with SIGSTOP and SIGCONT when going to idle? I'm now looking for a place where to do this.
it require very careful user notification setup (UI) and huge warning which is clearly explain that  after this kind of "SUSPEND" page might be broken.
(Reporter)

Comment 5

7 years ago
(In reply to comment #3)
> Alon, do you have some experimental patch for suspending with SIGSTOP and
> SIGCONT when going to idle? I'm now looking for a place where to do this.

I had just a very quick and dirty patch for this. It was basically just to send those signals in response to pressing a button. The core part is

+#include "signal.h"
+#include "bits/signum.h"
+
+void
+ContentProcessParent::suspendChild(PRBool suspend)
+{
+    pid_t pid = mSubprocess->GetChildProcessHandle();
+    kill(pid, suspend ? SIGSTOP : SIGCONT);
+}

When I have time I will try to work out the proper interfaces and implementation for this.

Updated

7 years ago
Depends on: 581314
(Reporter)

Comment 6

7 years ago
Created attachment 462175 [details] [diff] [review]
Patch

This patch implements both freezing/unfreezing and also throttling to arbitrary percentages. It provides a scriptable interface so addons can do e.g.

  let cp = Cc["@mozilla.org/contentparent;1"].getService(Ci.nsIContentParent);
  cp.childThrottling = 50; // 50% throttling

100% throttling means freeze entirely; 0% throttling means unfreeze and run normally.

Example use: An addon that has a blacklist of sites to run more slowly, which are known to be CPU hogs.

(When we have 1 process per tab, the interface can be expanded for that. For now, it assumes a single content process.)
Attachment #462175 - Flags: feedback?(jonkhemming)
Attachment #462175 - Flags: feedback?(benjamin)
(Reporter)

Updated

7 years ago
Blocks: 579982, 581314
No longer depends on: 581314
Comment on attachment 462175 [details] [diff] [review]
Patch

I don't mind the interface, but I do mind that you're trying to expose it via XPCOM services: just expose it via the <xul:browser> its attached to.

I do fear that this will be misused because people don't understand that one ContentParent will affect multiple tabs, and so I don't think we should check this in unless there's a compelling reason to do so. Maybe we can focus on fennec 2.0 blockers instead?
Attachment #462175 - Flags: feedback?(benjamin) → feedback-
(Reporter)

Comment 8

7 years ago
Well, this bug blocks bug 579982, which is a fennec 2.0 blocker (the specific problem there can be fixed with the more general approach in this bug). I'll ask about marking this bug as blocking fennec 2.0.

I see your point about how this can be confusing with one ContentParent affecting multiple tabs. It seemed to make sense as I was writing it since ContentParent is a global singleton, and this does behave like a singleton in the parent, which freezes all the child content (hence the XPCOM service). I guess basically what I was thinking of is a function "[freeze|throttle]AllChildContent()" - that's what is needed here. Where would the proper place to put that be?
(Reporter)

Updated

7 years ago
tracking-fennec: --- → ?

Updated

7 years ago
tracking-fennec: ? → 2.0+
(Reporter)

Comment 9

7 years ago
Created attachment 468471 [details] [diff] [review]
IdleService Patch

How about this approach, to let the idle service handle suspend/resume of content? The connection is that suspend/resume of content is done in concert with idle states of the device.

And this avoids the problem mentioned earlier of it being confusing to do this on ContentParent.
Attachment #462175 - Attachment is obsolete: true
Attachment #468471 - Flags: feedback?(benjamin)
Attachment #462175 - Flags: feedback?(jonkhemming)
(Reporter)

Comment 10

7 years ago
bsmedberg is against this approach, as being too risky.

Instead we should fix the specific issues that can use CPU, namely

* setTimeout/Interval
* incoming network data
* plugins (probably very hard to do in general)
* animations (bug 359608)

Also we should use device-specific approaches to this (like if a mobile phone OS has a 'suspended' state).
Status: NEW → RESOLVED
tracking-fennec: 2.0+ → ---
Last Resolved: 7 years ago
Resolution: --- → WONTFIX
(Reporter)

Updated

7 years ago
Attachment #468471 - Flags: feedback?(benjamin)
(Reporter)

Updated

7 years ago
No longer blocks: 579982
I am not sure that bsmedberg is completely against this approach -- he can speak to the exact concern he has.  Misuse is an issue, of course.  This approach is a hammer that we can stop out cpu pegs quite easily.
(Reporter)

Updated

7 years ago
No longer blocks: 581314
You need to log in before you can comment on or make changes to this bug.