Closed
Bug 1366356
Opened 8 years ago
Closed 8 years ago
Decrease the process priority of content processes that are not running a foreground tab
Categories
(Core :: DOM: Content Processes, enhancement)
Core
DOM: Content Processes
Tracking
()
Tracking | Status | |
---|---|---|
firefox55 | --- | fixed |
People
(Reporter: mstange, Assigned: baku)
References
(Blocks 2 open bugs)
Details
Attachments
(2 files, 3 obsolete files)
8.36 KB,
patch
|
smaug
:
review+
|
Details | Diff | Splinter Review |
5.43 KB,
patch
|
smaug
:
review+
|
Details | Diff | Splinter Review |
No description provided.
Comment 1•8 years ago
|
||
Having some API to notify processes when they have some foreground tabs or no foreground tabs at all would be really nice. We could for example try to do compacting GC a bit more aggressively on background processes.
Comment 2•8 years ago
|
||
We have a dom/ipc/ProcessPriorityManager that is supposed to fiddle with process priorities but currently is pretty much useless dead code that does not do anything at all on platform. I was about to remove that... do you plan to use that code?
I'm not a big fan of process priority setting in general and would prefer a different solution to handle background tabs. We own every message/event loop and every threads in all content processes, so we should not wait for the OS to decide what to slow down and how, and let that be different on all platforms.
Reporter | ||
Comment 3•8 years ago
|
||
(In reply to Gabor Krizsanits [:krizsa :gabor] from comment #2)
> I'm not a big fan of process priority setting in general and would prefer a
> different solution to handle background tabs. We own every message/event
> loop and every threads in all content processes, so we should not wait for
> the OS to decide what to slow down and how, and let that be different on all
> platforms.
I don't really understand how this would work. You still want multiple content processes to be able to run code in parallel, don't you? And if those parallel executions compete for resources, you want to give the OS a hint about which one it should prioritize.
Comment 4•8 years ago
|
||
(In reply to Markus Stange [:mstange] from comment #3)
> (In reply to Gabor Krizsanits [:krizsa :gabor] from comment #2)
> > I'm not a big fan of process priority setting in general and would prefer a
> > different solution to handle background tabs. We own every message/event
> > loop and every threads in all content processes, so we should not wait for
> > the OS to decide what to slow down and how, and let that be different on all
> > platforms.
>
> I don't really understand how this would work. You still want multiple
> content processes to be able to run code in parallel, don't you? And if
> those parallel executions compete for resources, you want to give the OS a
> hint about which one it should prioritize.
The processes related to background tabs can go to sleep frequently for a short interval giving more CPU time for the process of the front tab doing his work. I think it should be a goal not to get into a situation where our browser hogs all the CPU's and we have to juggle which of the tabs starve less while we render the users machine useless. With multiple content processes where each process hosts multiple main threads I think it's essential to think about load balancing sooner than later and just setting the process priority at OS level won't be enough. I'm not saying though, that we should not do that too, that's why I asked Ehsan if he wants to keep the old process priority manager and transform it into something that is functional or wants to do a fresh start.
Flags: needinfo?(ehsan)
Comment 5•8 years ago
|
||
I think starting with the existing code makes sense. baku, is this something you would be interested to work on?
Flags: needinfo?(ehsan) → needinfo?(amarchesini)
Assignee | ||
Comment 6•8 years ago
|
||
Yes, I take this.
Assignee: nobody → amarchesini
Flags: needinfo?(amarchesini)
Updated•8 years ago
|
Whiteboard: [qf]
Assignee | ||
Updated•8 years ago
|
Assignee | ||
Updated•8 years ago
|
Assignee | ||
Comment 7•8 years ago
|
||
After several cleaning steps, I think this class is finally ready to be used on desktop. It is still behind pref, but enabling it should be OK, because we don't have yet the SetProcessPriority() implementation for linux/mac/windows.
Doing some research, the next step is to use:
. on linux: setpriority. See https://linux.die.net/man/2/setpriority
. on mac: task_policy_set. See https://developer.apple.com/library/content/documentation/Darwin/Conceptual/KernelProgramming/scheduler/scheduler.html
. on windows: SetPriorityClass. See https://msdn.microsoft.com/en-us/library/windows/desktop/ms685100(v=vs.85).aspx
Attachment #8873358 -
Flags: review?(bugs)
Assignee | ||
Comment 8•8 years ago
|
||
Attachment #8873358 -
Attachment is obsolete: true
Attachment #8873358 -
Flags: review?(bugs)
Attachment #8873378 -
Flags: review?(bugs)
Comment 9•8 years ago
|
||
(In reply to Andrea Marchesini [:baku] from comment #7)
> . on linux: setpriority. See https://linux.die.net/man/2/setpriority
You might want to check out cgroups instead, setpriority() has the severe limitation that it doesn't allow to change the priority of an entire process in a non-racy way. Changes applied to the process' pid affect only the first thread of that process (i.e. the one with the tid == pid), other threads are unaffected. So to reschedule an entire process you have to call setpriority() on every single thread which is inevitably racy.
Because of a kernel bug in early Android versions in B2G we were originally forced to use setpriority() which lead to this horrifying, racy contraption to change the priority of a process (bug 861441):
https://hg.mozilla.org/mozilla-central/file/51bf50daff2f/hal/gonk/GonkHal.cpp#l1065
We later switched to cgroups (bug 1081871) and never looked back.
You will most certainly need a different approach since Firefox doesn't have the same amount of control we had on the system in b2g, so I can't guarantee that cgroups are the right solution, but I'm pretty sure that setpriority() isn't the right one.
Comment 10•8 years ago
|
||
Comment on attachment 8873378 [details] [diff] [review]
visibility.patch
I'd rather store only active tabs in the hashtable. That way ComputePriority wouldn't be so slow when there are lots of tabs. It would be just
if (!mTabParentActivity.IsEmpty()) {
return PROCESS_PRIORITY_FOREGROUND;
}
Though, better to rename to mActiveTabParents or so.
Attachment #8873378 -
Flags: review?(bugs) → review-
Updated•8 years ago
|
Whiteboard: [qf] → [qf:p1]
Assignee | ||
Comment 11•8 years ago
|
||
Attachment #8873378 -
Attachment is obsolete: true
Attachment #8873733 -
Flags: review?(bugs)
Assignee | ||
Comment 12•8 years ago
|
||
Attachment #8873826 -
Flags: review?(bugs)
Comment 13•8 years ago
|
||
Comment on attachment 8873733 [details] [diff] [review]
visibility.patch
># HG changeset patch
># User Andrea Marchesini <amarchesini@mozilla.com>
># Parent 8bb591801f9b3615d27ddfa6eb3788cb1296bc67
>
>diff --git a/dom/ipc/ProcessPriorityManager.cpp b/dom/ipc/ProcessPriorityManager.cpp
>--- a/dom/ipc/ProcessPriorityManager.cpp
>+++ b/dom/ipc/ProcessPriorityManager.cpp
>@@ -21,16 +21,17 @@
> #include "nsIObserverService.h"
> #include "StaticPtr.h"
> #include "nsIMozBrowserFrame.h"
> #include "nsIObserver.h"
> #include "nsITimer.h"
> #include "nsIPropertyBag2.h"
> #include "nsComponentManagerUtils.h"
> #include "nsCRT.h"
>+#include "nsTHashtable.h"
>
> using namespace mozilla;
> using namespace mozilla::dom;
> using namespace mozilla::hal;
>
> #ifdef XP_WIN
> #include <process.h>
> #define getpid _getpid
>@@ -144,16 +145,18 @@ public:
> hal::ProcessPriority aOldPriority);
>
> /**
> * Implements WakeLockObserver, used to monitor wake lock changes in the
> * main process.
> */
> virtual void Notify(const WakeLockInformation& aInfo) override;
>
>+ void TabActivityChanged(TabParent* aTabParent, bool aIsActive);
>+
> /**
> * Call ShutDown before destroying the ProcessPriorityManager because
> * WakeLockObserver hols a strong reference to it.
> */
> void ShutDown();
>
> private:
> static bool sPrefsEnabled;
>@@ -262,16 +265,18 @@ public:
> BACKGROUND_GRACE_PERIOD,
> };
>
> void ScheduleResetPriority(TimeoutPref aTimeoutPref);
> void ResetPriority();
> void ResetPriorityNow();
> void SetPriorityNow(ProcessPriority aPriority);
>
>+ void TabActivityChanged(TabParent* aTabParent, bool aIsActive);
>+
> void ShutDown();
>
> private:
> static uint32_t sBackgroundPerceivableGracePeriodMS;
> static uint32_t sBackgroundGracePeriodMS;
>
> void FireTestOnlyObserverNotification(
> const char* aTopic,
>@@ -288,16 +293,19 @@ private:
> bool mHoldsHighPriorityWakeLock;
>
> /**
> * Used to implement NameWithComma().
> */
> nsAutoCString mNameWithComma;
>
> nsCOMPtr<nsITimer> mResetPriorityTimer;
>+
>+ // This hashtable contains the list of active TabId for this process.
>+ nsTHashtable<nsUint64HashKey> mActiveTabParents;
> };
>
> /* static */ bool ProcessPriorityManagerImpl::sInitialized = false;
> /* static */ bool ProcessPriorityManagerImpl::sPrefsEnabled = false;
> /* static */ bool ProcessPriorityManagerImpl::sRemoteTabsDisabled = true;
> /* static */ bool ProcessPriorityManagerImpl::sTestMode = false;
> /* static */ bool ProcessPriorityManagerImpl::sPrefListenersRegistered = false;
> /* static */ StaticRefPtr<ProcessPriorityManagerImpl>
>@@ -533,16 +541,30 @@ ProcessPriorityManagerImpl::Notify(const
> mHighPriority = false;
> }
>
> LOG("Got wake lock changed event. "
> "Now mHighPriorityParent = %d\n", mHighPriority);
> }
> }
>
>+void
>+ProcessPriorityManagerImpl::TabActivityChanged(TabParent* aTabParent,
>+ bool aIsActive)
>+{
>+ ContentParent* cp = aTabParent->Manager()->AsContentParent();
>+ RefPtr<ParticularProcessPriorityManager> pppm =
>+ GetParticularProcessPriorityManager(cp);
>+ if (!pppm) {
>+ return;
>+ }
>+
>+ pppm->TabActivityChanged(aTabParent, aIsActive);
>+}
>+
> NS_IMPL_ISUPPORTS(ParticularProcessPriorityManager,
> nsIObserver,
> nsITimerCallback,
> nsISupportsWeakReference);
>
> ParticularProcessPriorityManager::ParticularProcessPriorityManager(
> ContentParent* aContentParent)
> : mContentParent(aContentParent)
>@@ -719,16 +741,23 @@ ParticularProcessPriorityManager::OnTabP
> nsCOMPtr<nsITabParent> tp = do_QueryInterface(aSubject);
> NS_ENSURE_TRUE_VOID(tp);
>
> MOZ_ASSERT(XRE_IsParentProcess());
> if (TabParent::GetFrom(tp)->Manager() != mContentParent) {
> return;
> }
>
>+ uint64_t tabId;
>+ if (NS_WARN_IF(NS_FAILED(tp->GetTabId(&tabId)))) {
>+ return;
>+ }
>+
>+ mActiveTabParents.RemoveEntry(tabId);
>+
> ResetPriority();
> }
>
> void
> ParticularProcessPriorityManager::ResetPriority()
> {
> ProcessPriority processPriority = ComputePriority();
> if (mPriority == PROCESS_PRIORITY_UNKNOWN ||
>@@ -794,18 +823,19 @@ ProcessPriority
> ParticularProcessPriorityManager::CurrentPriority()
> {
> return mPriority;
> }
>
> ProcessPriority
> ParticularProcessPriorityManager::ComputePriority()
> {
>- // TODO...
>- return PROCESS_PRIORITY_FOREGROUND;
>+ if (!mActiveTabParents.IsEmpty()) {
>+ return PROCESS_PRIORITY_FOREGROUND;
>+ }
>
> if (mHoldsCPUWakeLock || mHoldsHighPriorityWakeLock) {
> return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE;
> }
>
> return PROCESS_PRIORITY_BACKGROUND;
> }
>
>@@ -844,16 +874,31 @@ ParticularProcessPriorityManager::SetPri
> Unused << mContentParent->SendNotifyProcessPriorityChanged(mPriority);
> }
>
> FireTestOnlyObserverNotification("process-priority-set",
> ProcessPriorityToString(mPriority));
> }
>
> void
>+ParticularProcessPriorityManager::TabActivityChanged(TabParent* aTabParent,
>+ bool aIsActive)
>+{
>+ MOZ_ASSERT(aTabParent);
>+
>+ if (!aIsActive) {
>+ mActiveTabParents.RemoveEntry(aTabParent->GetTabId());
>+ } else {
>+ mActiveTabParents.PutEntry(aTabParent->GetTabId());
>+ }
>+
>+ ResetPriority();
>+}
>+
>+void
> ParticularProcessPriorityManager::ShutDown()
> {
> MOZ_ASSERT(mContentParent);
>
> UnregisterWakeLockObserver(this);
>
> if (mResetPriorityTimer) {
> mResetPriorityTimer->Cancel();
>@@ -1018,9 +1063,24 @@ ProcessPriorityManager::SetProcessPriori
>
> /* static */ bool
> ProcessPriorityManager::CurrentProcessIsForeground()
> {
> return ProcessPriorityManagerChild::Singleton()->
> CurrentProcessIsForeground();
> }
>
>+/* static */ void
>+ProcessPriorityManager::TabActivityChanged(TabParent* aTabParent,
>+ bool aIsActive)
>+{
>+ MOZ_ASSERT(aTabParent);
>+
>+ ProcessPriorityManagerImpl* singleton =
>+ ProcessPriorityManagerImpl::GetSingleton();
>+ if (!singleton) {
>+ return;
>+ }
>+
>+ singleton->TabActivityChanged(aTabParent, aIsActive);
>+}
>+
> } // namespace mozilla
>diff --git a/dom/ipc/ProcessPriorityManager.h b/dom/ipc/ProcessPriorityManager.h
>--- a/dom/ipc/ProcessPriorityManager.h
>+++ b/dom/ipc/ProcessPriorityManager.h
>@@ -7,16 +7,17 @@
> #ifndef mozilla_ProcessPriorityManager_h_
> #define mozilla_ProcessPriorityManager_h_
>
> #include "mozilla/HalTypes.h"
>
> namespace mozilla {
> namespace dom {
> class ContentParent;
>+class TabParent;
> } // namespace dom
>
> /**
> * This class sets the priority of subprocesses in response to explicit
> * requests and events in the system.
> *
> * A process's priority changes e.g. when it goes into the background via
> * mozbrowser's setVisible(false). Process priority affects CPU scheduling and
>@@ -63,16 +64,18 @@ public:
> * Returns true iff this process's priority is FOREGROUND*.
> *
> * Note that because process priorities are set in the main process, it's
> * possible for this method to return a stale value. So be careful about
> * what you use this for.
> */
> static bool CurrentProcessIsForeground();
>
>+ static void TabActivityChanged(dom::TabParent* aTabParent, bool aIsActive);
>+
> private:
> ProcessPriorityManager();
> DISALLOW_EVIL_CONSTRUCTORS(ProcessPriorityManager);
> };
>
> } // namespace mozilla
>
> #endif
>diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp
>--- a/dom/ipc/TabParent.cpp
>+++ b/dom/ipc/TabParent.cpp
>@@ -93,16 +93,17 @@
> #include "nsIAuthPrompt2.h"
> #include "gfxDrawable.h"
> #include "ImageOps.h"
> #include "UnitTransforms.h"
> #include <algorithm>
> #include "mozilla/WebBrowserPersistDocumentParent.h"
> #include "nsIGroupedSHistory.h"
> #include "PartialSHistory.h"
>+#include "ProcessPriorityManager.h"
> #include "nsString.h"
>
> #ifdef XP_WIN
> #include "mozilla/plugins/PluginWidgetParent.h"
> #endif
>
> #if defined(XP_WIN) && defined(ACCESSIBILITY)
> #include "mozilla/a11y/AccessibleWrap.h"
>@@ -2640,16 +2641,20 @@ TabParent::SetDocShellIsActive(bool isAc
> // SetDocShellIsActive requests are ignored.
> mLayerTreeEpoch++;
>
> // docshell is consider prerendered only if not active yet
> mIsPrerendered &= !isActive;
> mDocShellIsActive = isActive;
> Unused << SendSetDocShellIsActive(isActive, mPreserveLayers, mLayerTreeEpoch);
>
>+ // Let's inform the priority manager. This operation can end up with the
>+ // changing of the process priority.
>+ ProcessPriorityManager::TabActivityChanged(this, isActive);
>+
> // Ask the child to repaint using the PHangMonitor channel/thread (which may
> // be less congested).
> if (isActive) {
> ContentParent* cp = Manager()->AsContentParent();
> cp->ForceTabPaint(this, mLayerTreeEpoch);
> }
>
> return NS_OK;
Attachment #8873733 -
Flags: review?(bugs) → review+
Comment 14•8 years ago
|
||
Comment on attachment 8873826 [details] [diff] [review]
part 2 - enabling
But do we have backend of this ready?
Attachment #8873826 -
Flags: review?(bugs) → review+
Assignee | ||
Comment 15•8 years ago
|
||
I have something read-ish for linux. No mac, no windows. I'll submit a patch for linux probably on Monday.
Assignee | ||
Comment 16•8 years ago
|
||
I uploaded the wrong patch. This is the right now for enabling this feature.
Attachment #8873826 -
Attachment is obsolete: true
Attachment #8874083 -
Flags: review?(bugs)
Comment 17•8 years ago
|
||
Comment on attachment 8874083 [details] [diff] [review]
part 2 - enabling
Why do we want to get rid of the pref?
And if we remove the pref, method name ProcessPriorityManagerImpl::PrefsEnabled()
doesn't make sense.
I think we could keep dom.ipc.processPriorityManager.enabled for now, at least for testing.
then
return hal::SetProcessPrioritySupported() && !sRemoteTabsDisabled;
->
return sPrefsEnabled && hal::SetProcessPrioritySupported() && !sRemoteTabsDisabled;
Attachment #8874083 -
Flags: review?(bugs) → review+
Comment 18•8 years ago
|
||
Is this patch ready / able to land, or are we waiting until after the soft freeze?
Flags: needinfo?(amarchesini)
Assignee | ||
Comment 19•8 years ago
|
||
These patches are ready to land. But we need the platform-specific part. I wrote the linux one. We need the windows and mac ones.
Flags: needinfo?(amarchesini)
Comment 20•8 years ago
|
||
(In reply to Andrea Marchesini [:baku] from comment #19)
> These patches are ready to land. But we need the platform-specific part. I
> wrote the linux one. We need the windows and mac ones.
I think I or dmajor may be able to help with the Windows parts. I don't see a Linux specific patch here so I don't know which APIs you need.
For the Mac version you can ask help from mstange or spohl. But I think this can land without Mac support initially, that's not really important. Windows is the important platform to support. We can support OSX opportunistically.
Assignee | ||
Comment 21•8 years ago
|
||
Linux patch is still in testing. I want to file a separate bug for it.
About the API we should use, see comments 7 and 9.
Comment 22•8 years ago
|
||
Pushed by amarchesini@mozilla.com:
https://hg.mozilla.org/integration/mozilla-inbound/rev/a8011068db5a
Decrease the process priority of content processes that are not running a foreground tab - part 1 - visibility logic, r=smaug
https://hg.mozilla.org/integration/mozilla-inbound/rev/d95970dc9b7d
Decrease the process priority of content processes that are not running a foreground tab - part 2 - enabled if the platform specific code is ready, r=smaug
Comment 23•8 years ago
|
||
https://hg.mozilla.org/mozilla-central/rev/a8011068db5a
https://hg.mozilla.org/mozilla-central/rev/d95970dc9b7d
Status: NEW → RESOLVED
Closed: 8 years ago
status-firefox55:
--- → fixed
Resolution: --- → FIXED
Target Milestone: --- → mozilla55
Updated•3 years ago
|
Performance Impact: --- → P1
Whiteboard: [qf:p1]
You need to log in
before you can comment on or make changes to this bug.
Description
•