author | Justin Lebar <justin.lebar@gmail.com> |
Fri, 22 Feb 2013 23:24:28 -0500 | |
changeset 122715 | 67bee77ac7e37ab95dfd47c35783ccef47af570c |
parent 122714 | 93ccd4912321292701928ab69dd3885e1f088927 |
child 122716 | 1d8799803f37bb83cc8ce5f997206999b25ccb28 |
push id | 23456 |
push user | jlebar@mozilla.com |
push date | Sat, 23 Feb 2013 04:27:49 +0000 |
treeherder | mozilla-inbound@67bee77ac7e3 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | cjones |
bugs | 842679 |
milestone | 22.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/ipc/ProcessPriorityManager.cpp +++ b/dom/ipc/ProcessPriorityManager.cpp @@ -156,25 +156,31 @@ public: * ProcessPriorityManager.h::TemporarilyLockProcessPriority(). */ void TemporarilyLockProcessPriority(); /** * Recompute this process's priority and apply it, potentially after a brief * delay. * - * If the new priority is FOREGROUND*, it takes effect immediately. + * If we are transitioning to a priority that is "lower" than the current + * priority (as defined below), that transition happens after a grace period. + * Otherwise the transition happens immediately. + * + * For the purposes of deciding whether to apply a grace period, the + * hierarchy of priorities is * - * If the new priority is a BACKGROUND* priority and this process's priority - * is currently a BACKGROUND* priority, the new priority takes effect - * immediately. + * - UNKNOWN + * - FOREGROUND_HIGH + * - FOREGROUND + * - BACKGROUND* * - * But if the new priority is a BACKGROUND* priority and this process is not - * currently in the background, we schedule a timer and run - * ResetPriorityNow() after a short period of time. + * So for example, a transition between any two BACKGROUND* priorites happens + * immediately, but a transition from UNKNOWN to FOREGROUND_HIGH happens + * after a grace period. */ void ResetPriority(); /** * Recompute this process's priority and apply it immediately. */ void ResetPriorityNow(); @@ -197,21 +203,29 @@ private: */ ProcessPriority GetBackgroundPriority(); /** * Compute whether this process is in the foreground and return the result. */ bool ComputeIsInForeground(); + + /** + * Set this process's priority to the appropriate FOREGROUND* priority + * immediately if we're upgrading its priority, and after a grace period if + * we're downgrading it or if the current priority is unknown. + */ + void SetIsForeground(); + /** * Set this process's priority to the appropriate FOREGROUND* priority * immediately. */ - void SetIsForeground(); + void SetIsForegroundNow(); /** * Set this process's priority to the appropriate BACKGROUND* priority * immediately. */ void SetIsBackgroundNow(); /** @@ -226,31 +240,36 @@ private: bool mHoldsCPUWakeLock; // Tracks whether this process holds the "high-priority" lock. bool mHoldsHighPriorityWakeLock; // mProcessPriority tracks the priority we've given this process in hal. ProcessPriority mProcessPriority; + // Have we seen at least one tab-child-created event yet? Until this is + // true, ResetPriority() and ResetPriorityNow() do nothing. + bool mObservedTabChildCreated; + nsTArray<nsWeakPtr> mWindows; // When this timer expires, we set mResetPriorityTimer to null and run // ResetPriorityNow(). nsCOMPtr<nsITimer> mResetPriorityTimer; nsWeakPtr mMemoryMinimizerRunnable; }; NS_IMPL_ISUPPORTS2(ProcessPriorityManager, nsIObserver, nsIDOMEventListener) ProcessPriorityManager::ProcessPriorityManager() : mHoldsCPUWakeLock(false) , mHoldsHighPriorityWakeLock(false) , mProcessPriority(ProcessPriority(-1)) + , mObservedTabChildCreated(false) { // When our parent process forked us, it may have set our process's priority // to one of a few of the process priorities, depending on exactly why this // process was created. // // We don't know which priority we were given, so we set mProcessPriority to // -1 so that the next time ResetPriorityNow is run, we'll definitely call // into hal and set our priority. @@ -264,16 +283,17 @@ ProcessPriorityManager::Init() // We can't do this in the constructor because we need to hold a strong ref // to |this| before calling these methods. // // Notice that we track /window/ creation and destruction even though our // notion of "is-foreground" is tied to /docshell/ activity. We do this // because docshells don't fire an event when their visibility changes, but // windows do. nsCOMPtr<nsIObserverService> os = services::GetObserverService(); + os->AddObserver(this, "tab-child-created", /* ownsWeak = */ false); os->AddObserver(this, "content-document-global-created", /* ownsWeak = */ false); os->AddObserver(this, "inner-window-destroyed", /* ownsWeak = */ false); os->AddObserver(this, "audio-channel-agent-changed", /* ownsWeak = */ false); os->AddObserver(this, "process-priority:reset-now", /* ownsWeak = */ false); RegisterWakeLockObserver(this); // This process may already hold the CPU lock; for example, our parent may @@ -290,17 +310,20 @@ ProcessPriorityManager::Init() } NS_IMETHODIMP ProcessPriorityManager::Observe( nsISupports* aSubject, const char* aTopic, const PRUnichar* aData) { - if (!strcmp(aTopic, "content-document-global-created")) { + if (!strcmp(aTopic, "tab-child-created")) { + mObservedTabChildCreated = true; + ResetPriority(); + } else if (!strcmp(aTopic, "content-document-global-created")) { OnContentDocumentGlobalCreated(aSubject); } else if (!strcmp(aTopic, "inner-window-destroyed") || !strcmp(aTopic, "audio-channel-agent-changed")) { ResetPriority(); } else if (!strcmp(aTopic, "process-priority:reset-now")) { LOG("Got process-priority:reset-now notification."); ResetPriorityNow(); } else { @@ -445,32 +468,44 @@ ProcessPriorityManager::GetBackgroundPri PROCESS_PRIORITY_BACKGROUND_HOMESCREEN : PROCESS_PRIORITY_BACKGROUND; } void ProcessPriorityManager::ResetPriority() { + if (!mObservedTabChildCreated) { + LOG("ResetPriority bailing because we haven't observed " + "a tab-child-created event."); + return; + } + if (ComputeIsInForeground()) { SetIsForeground(); } else if (IsBackgroundPriority(mProcessPriority)) { // If we're already in the background, recompute our background priority // and set it immediately. SetIsBackgroundNow(); } else { ScheduleResetPriority("backgroundGracePeriodMS"); } } void ProcessPriorityManager::ResetPriorityNow() { + if (!mObservedTabChildCreated) { + LOG("ResetPriorityNow bailing because we haven't observed " + "a tab-child-created event."); + return; + } + if (ComputeIsInForeground()) { - SetIsForeground(); + SetIsForegroundNow(); } else { SetIsBackgroundNow(); } } bool ProcessPriorityManager::ComputeIsInForeground() { @@ -523,16 +558,32 @@ ProcessPriorityManager::ComputeIsInForeg return !allHidden; } void ProcessPriorityManager::SetIsForeground() { ProcessPriority foregroundPriority = GetForegroundPriority(); + + if (mProcessPriority == PROCESS_PRIORITY_UNKNOWN || + foregroundPriority < mProcessPriority) { + LOG("Giving grace period to %s -> %s transition.", + ProcessPriorityToString(mProcessPriority), + ProcessPriorityToString(foregroundPriority)); + ScheduleResetPriority("backgroundGracePeriodMS"); + } else { + SetIsForegroundNow(); + } +} + +void +ProcessPriorityManager::SetIsForegroundNow() +{ + ProcessPriority foregroundPriority = GetForegroundPriority(); if (foregroundPriority == mProcessPriority) { return; } // Cancel the memory minimization procedure we might have started. nsCOMPtr<nsICancelableRunnable> runnable = do_QueryReferent(mMemoryMinimizerRunnable); if (runnable) {