From 6b38c6d632e1d4e354d2dc0199bddba939fc914e Mon Sep 17 00:00:00 2001 From: Gabriele Svelto Date: Wed, 25 Feb 2015 09:37:38 +0100 Subject: [PATCH] Bug 892371 - Adjust oom_score_adj values for foreground processes according to an LRU policy. r=dhylands, r=khuey --- b2g/app/b2g.js | 9 +- .../mochitest/browserElementTestHelpers.js | 24 +- .../priority/test_BackgroundLRU.html | 2 +- dom/ipc/ProcessPriorityManager.cpp | 456 +++++++----------- dom/ipc/ProcessPriorityManager.h | 12 - dom/ipc/tests/test_NuwaProcessCreation.html | 2 +- dom/ipc/tests/test_NuwaProcessDeadlock.html | 2 +- hal/Hal.cpp | 7 +- hal/fallback/FallbackProcessPriority.cpp | 6 +- hal/gonk/GonkHal.cpp | 14 +- hal/sandbox/SandboxHal.cpp | 4 +- 11 files changed, 214 insertions(+), 324 deletions(-) diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 15e14ab5da6..733d4de8000 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -703,10 +703,11 @@ pref("dom.ipc.processPriorityManager.backgroundGracePeriodMS", 1000); pref("dom.ipc.processPriorityManager.backgroundPerceivableGracePeriodMS", 5000); pref("dom.ipc.processPriorityManager.temporaryPriorityLockMS", 5000); -// Number of different background levels for background processes. We use -// these different levels to force the low-memory killer to kill processes in -// a LRU order. -pref("dom.ipc.processPriorityManager.backgroundLRUPoolLevels", 5); +// Number of different background/foreground levels for background/foreground +// processes. We use these different levels to force the low-memory killer to +// kill processes in a LRU order. +pref("dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels", 5); +pref("dom.ipc.processPriorityManager.FOREGROUND.LRUPoolLevels", 3); // Kernel parameters for process priorities. These affect how processes are // killed on low-memory and their relative CPU priorities. diff --git a/dom/browser-element/mochitest/browserElementTestHelpers.js b/dom/browser-element/mochitest/browserElementTestHelpers.js index 5f494777b2f..5b1f8e27f3e 100644 --- a/dom/browser-element/mochitest/browserElementTestHelpers.js +++ b/dom/browser-element/mochitest/browserElementTestHelpers.js @@ -50,9 +50,9 @@ const browserElementTestHelpers = { enableProcessPriorityManager: function() { this._setPrefs( + ['dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels', 2], ['dom.ipc.processPriorityManager.testMode', true], - ['dom.ipc.processPriorityManager.enabled', true], - ['dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2] + ['dom.ipc.processPriorityManager.enabled', true] ); }, @@ -187,28 +187,28 @@ function expectPriorityChange(childID, expectedPriority) { }); } -// Returns a promise which is resolved or rejected the next time the background -// process childID changes its priority. We resolve if the backgroundLRU -// matches expectedBackgroundLRU and we reject otherwise. +// Returns a promise which is resolved or rejected the next time the +// process childID changes its priority. We resolve if the LRU parameter +// matches expectedLRU and we reject otherwise. -function expectPriorityWithBackgroundLRUSet(childID, expectedBackgroundLRU) { +function expectPriorityWithLRUSet(childID, expectedLRU) { return new Promise(function(resolve, reject) { browserElementTestHelpers.addProcessPriorityObserver( - 'process-priority-with-background-LRU-set', + 'process-priority-with-LRU-set', function(subject, topic, data) { - var [id, priority, backgroundLRU] = data.split(":"); + var [id, priority, lru] = data.split(":"); if (id != childID) { return; } - is(backgroundLRU, expectedBackgroundLRU, - 'Expected backgroundLRU ' + backgroundLRU + + is(lru, expectedLRU, + 'Expected LRU ' + lru + ' of childID ' + childID + - ' to change to ' + expectedBackgroundLRU); + ' to change to ' + expectedLRU); - if (backgroundLRU == expectedBackgroundLRU) { + if (lru == expectedLRU) { resolve(); } else { reject(); diff --git a/dom/browser-element/mochitest/priority/test_BackgroundLRU.html b/dom/browser-element/mochitest/priority/test_BackgroundLRU.html index 183c2671ef9..6ba902127e9 100644 --- a/dom/browser-element/mochitest/priority/test_BackgroundLRU.html +++ b/dom/browser-element/mochitest/priority/test_BackgroundLRU.html @@ -49,7 +49,7 @@ function runTest() { // We wait until another one is set to background, too. // Once there are two in background, the first one (LRU order) // should have 'backgroundLRU' equals 1 - var p = expectPriorityWithBackgroundLRUSet(childID, '1'); + var p = expectPriorityWithLRUSet(childID, '1'); iframe2.setVisible(false); return p; diff --git a/dom/ipc/ProcessPriorityManager.cpp b/dom/ipc/ProcessPriorityManager.cpp index 24b06c2c398..0bcc327d2c8 100644 --- a/dom/ipc/ProcessPriorityManager.cpp +++ b/dom/ipc/ProcessPriorityManager.cpp @@ -10,6 +10,7 @@ #include "mozilla/dom/Element.h" #include "mozilla/dom/TabParent.h" #include "mozilla/Hal.h" +#include "mozilla/IntegerPrintfMacros.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "mozilla/unused.h" @@ -54,17 +55,18 @@ # define LOGP(fmt, ...) \ __android_log_print(ANDROID_LOG_INFO, \ "Gecko:ProcessPriorityManager", \ - "[%schild-id=%llu, pid=%d] " fmt, \ + "[%schild-id=%" PRIu64 ", pid=%d] " fmt, \ NameWithComma().get(), \ - (long long unsigned) ChildID(), Pid(), ## __VA_ARGS__) + static_cast(ChildID()), Pid(), ## __VA_ARGS__) #elif defined(ENABLE_LOGGING) # define LOG(fmt, ...) \ printf("ProcessPriorityManager - " fmt "\n", ##__VA_ARGS__) # define LOGP(fmt, ...) \ - printf("ProcessPriorityManager[%schild-id=%llu, pid=%d] - " fmt "\n", \ + printf("ProcessPriorityManager[%schild-id=%" PRIu64 ", pid=%d] - " \ + fmt "\n", \ NameWithComma().get(), \ - (unsigned long long) ChildID(), Pid(), ##__VA_ARGS__) + static_cast(ChildID()), Pid(), ##__VA_ARGS__) #elif defined(PR_LOGGING) static PRLogModuleInfo* @@ -80,9 +82,9 @@ ("ProcessPriorityManager - " fmt, ##__VA_ARGS__)) # define LOGP(fmt, ...) \ PR_LOG(GetPPMLog(), PR_LOG_DEBUG, \ - ("ProcessPriorityManager[%schild-id=%llu, pid=%d] - " fmt, \ + ("ProcessPriorityManager[%schild-id=%" PRIu64 ", pid=%d] - " fmt, \ NameWithComma().get(), \ - (unsigned long long) ChildID(), Pid(), ##__VA_ARGS__)) + static_cast(ChildID()), Pid(), ##__VA_ARGS__)) #else #define LOG(fmt, ...) #define LOGP(fmt, ...) @@ -96,6 +98,42 @@ namespace { class ParticularProcessPriorityManager; +class ProcessLRUPool MOZ_FINAL +{ +public: + /** + * Creates a new process LRU pool for the specified priority. + */ + ProcessLRUPool(ProcessPriority aPriority, uint32_t aBias); + + /** + * Used to remove a particular process priority manager from the LRU pool + * when the associated ContentParent is destroyed or its priority changes. + */ + void Remove(ParticularProcessPriorityManager* aParticularManager); + + /** + * Used to add a particular process priority manager into the LRU pool when + * the associated ContentParent's priority changes. + */ + void Add(ParticularProcessPriorityManager* aParticularManager); + +private: + ProcessPriority mPriority; + uint32_t mLRUPoolLevels; + uint32_t mLRUPoolSize; + uint32_t mBias; + nsTArray mLRUPool; + + uint32_t CalculateLRULevel(uint32_t aLRUPoolIndex); + + void AdjustLRUValues( + nsTArray::index_type aStart, + bool removed); + + DISALLOW_EVIL_CONSTRUCTORS(ProcessLRUPool); +}; + /** * This singleton class does the work to implement the process priority manager * in the main process. This class may not be used in child processes. (You @@ -129,7 +167,7 @@ public: */ void SetProcessPriority(ContentParent* aContentParent, ProcessPriority aPriority, - uint32_t aBackgroundLRU = 0); + uint32_t aLRU = 0); /** * If a magic testing-only pref is set, notify the observer service on the @@ -179,8 +217,17 @@ private: nsDataHashtable > mParticularManagers; + /** True if the main process is holding a high-priority wakelock */ bool mHighPriority; + + /** Contains the PIDs of child processes holding high-priority wakelocks */ nsTHashtable mHighPriorityChildIDs; + + /** Contains a pseudo-LRU list of background processes */ + ProcessLRUPool mBackgroundLRUPool; + + /** Contains a pseudo-LRU list of foreground processes */ + ProcessLRUPool mForegroundLRUPool; }; /** @@ -262,7 +309,7 @@ public: void ScheduleResetPriority(const char* aTimeoutPref); void ResetPriority(); void ResetPriorityNow(); - void SetPriorityNow(ProcessPriority aPriority, uint32_t aBackgroundLRU = 0); + void SetPriorityNow(ProcessPriority aPriority, uint32_t aLRU = 0); void ShutDown(); @@ -278,6 +325,7 @@ private: ContentParent* mContentParent; uint64_t mChildID; ProcessPriority mPriority; + uint32_t mLRU; bool mHoldsCPUWakeLock; bool mHoldsHighPriorityWakeLock; @@ -289,46 +337,6 @@ private: nsCOMPtr mResetPriorityTimer; }; -class BackgroundProcessLRUPool MOZ_FINAL -{ -public: - static BackgroundProcessLRUPool* Singleton(); - - /** - * Used to remove a ContentParent from background LRU pool when - * it is destroyed or its priority changed from BACKGROUND to others. - */ - void RemoveFromBackgroundLRUPool(ContentParent* aContentParent); - - /** - * Used to add a ContentParent into background LRU pool when - * its priority changed to BACKGROUND from others. - */ - void AddIntoBackgroundLRUPool(ContentParent* aContentParent); - -private: - static StaticAutoPtr sSingleton; - - int32_t mLRUPoolLevels; - int32_t mLRUPoolSize; - int32_t mLRUPoolAvailableIndex; - nsTArray mLRUPool; - - uint32_t CalculateLRULevel(uint32_t aBackgroundLRUPoolIndex); - - nsresult UpdateAvailableIndexInLRUPool( - ContentParent* aContentParent, - int32_t aTargetIndex = -1); - - void ShiftLRUPool(); - - void EnsureLRUPool(); - - BackgroundProcessLRUPool(); - DISALLOW_EVIL_CONSTRUCTORS(BackgroundProcessLRUPool); - -}; - /* static */ bool ProcessPriorityManagerImpl::sInitialized = false; /* static */ bool ProcessPriorityManagerImpl::sPrefListenersRegistered = false; /* static */ StaticRefPtr @@ -399,6 +407,8 @@ ProcessPriorityManagerImpl::GetSingleton() ProcessPriorityManagerImpl::ProcessPriorityManagerImpl() : mHighPriority(false) + , mBackgroundLRUPool(PROCESS_PRIORITY_BACKGROUND, 1) + , mForegroundLRUPool(PROCESS_PRIORITY_FOREGROUND, 0) { MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); RegisterWakeLockObserver(this); @@ -473,13 +483,13 @@ ProcessPriorityManagerImpl::GetParticularProcessPriorityManager( void ProcessPriorityManagerImpl::SetProcessPriority(ContentParent* aContentParent, ProcessPriority aPriority, - uint32_t aBackgroundLRU) + uint32_t aLRU) { MOZ_ASSERT(aContentParent); nsRefPtr pppm = GetParticularProcessPriorityManager(aContentParent); if (pppm) { - pppm->SetPriorityNow(aPriority, aBackgroundLRU); + pppm->SetPriorityNow(aPriority, aLRU); } } @@ -507,6 +517,10 @@ ProcessPriorityManagerImpl::ObserveContentParentDestroyed(nsISupports* aSubject) nsRefPtr pppm; mParticularManagers.Get(childID, &pppm); if (pppm) { + // Unconditionally remove the manager from the pools + mBackgroundLRUPool.Remove(pppm); + mForegroundLRUPool.Remove(pppm); + pppm->ShutDown(); mParticularManagers.Remove(childID); @@ -528,21 +542,32 @@ ProcessPriorityManagerImpl::NotifyProcessPriorityChanged( ParticularProcessPriorityManager* aParticularManager, ProcessPriority aOldPriority) { - /* We're interested only in changes to/from FOREGROUND_HIGH as we use we - * need to track high priority processes so that we can react to their - * presence. */ + ProcessPriority newPriority = aParticularManager->CurrentPriority(); + bool isPreallocated = aParticularManager->IsPreallocated(); - if (aOldPriority < PROCESS_PRIORITY_FOREGROUND_HIGH && - aParticularManager->CurrentPriority() < - PROCESS_PRIORITY_FOREGROUND_HIGH) { - - return; + if (newPriority == PROCESS_PRIORITY_BACKGROUND && + aOldPriority != PROCESS_PRIORITY_BACKGROUND && + !isPreallocated) { + mBackgroundLRUPool.Add(aParticularManager); + } else if (newPriority != PROCESS_PRIORITY_BACKGROUND && + aOldPriority == PROCESS_PRIORITY_BACKGROUND && + !isPreallocated) { + mBackgroundLRUPool.Remove(aParticularManager); } - if (aParticularManager->CurrentPriority() >= - PROCESS_PRIORITY_FOREGROUND_HIGH) { + if (newPriority == PROCESS_PRIORITY_FOREGROUND && + aOldPriority != PROCESS_PRIORITY_FOREGROUND) { + mForegroundLRUPool.Add(aParticularManager); + } else if (newPriority != PROCESS_PRIORITY_FOREGROUND && + aOldPriority == PROCESS_PRIORITY_FOREGROUND) { + mForegroundLRUPool.Remove(aParticularManager); + } + + if (newPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH && + aOldPriority < PROCESS_PRIORITY_FOREGROUND_HIGH) { mHighPriorityChildIDs.PutEntry(aParticularManager->ChildID()); - } else { + } else if (newPriority < PROCESS_PRIORITY_FOREGROUND_HIGH && + aOldPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH) { mHighPriorityChildIDs.RemoveEntry(aParticularManager->ChildID()); } } @@ -575,6 +600,7 @@ ParticularProcessPriorityManager::ParticularProcessPriorityManager( : mContentParent(aContentParent) , mChildID(aContentParent->ChildID()) , mPriority(PROCESS_PRIORITY_UNKNOWN) + , mLRU(0) , mHoldsCPUWakeLock(false) , mHoldsHighPriorityWakeLock(false) { @@ -937,51 +963,31 @@ ParticularProcessPriorityManager::ComputePriority() void ParticularProcessPriorityManager::SetPriorityNow(ProcessPriority aPriority, - uint32_t aBackgroundLRU) + uint32_t aLRU) { if (aPriority == PROCESS_PRIORITY_UNKNOWN) { MOZ_ASSERT(false); return; } - if (aBackgroundLRU > 0 && - aPriority == PROCESS_PRIORITY_BACKGROUND && - mPriority == PROCESS_PRIORITY_BACKGROUND) { - hal::SetProcessPriority(Pid(), mPriority, aBackgroundLRU); - - nsPrintfCString ProcessPriorityWithBackgroundLRU("%s:%d", - ProcessPriorityToString(mPriority), aBackgroundLRU); - - FireTestOnlyObserverNotification("process-priority-with-background-LRU-set", - ProcessPriorityWithBackgroundLRU.get()); - } - - if (!mContentParent || - !ProcessPriorityManagerImpl::PrefsEnabled() || - (mPriority == aPriority)) { + if (!ProcessPriorityManagerImpl::PrefsEnabled() || + !mContentParent || + ((mPriority == aPriority) && (mLRU == aLRU))) { return; } - // If the prefs were disabled after this ParticularProcessPriorityManager was - // created, we can at least avoid any further calls to - // hal::SetProcessPriority. Supporting dynamic enabling/disabling of the - // ProcessPriorityManager is mostly for testing. - if (!ProcessPriorityManagerImpl::PrefsEnabled()) { + if ((mPriority == aPriority) && (mLRU != aLRU)) { + mLRU = aLRU; + hal::SetProcessPriority(Pid(), mPriority, aLRU); + + nsPrintfCString processPriorityWithLRU("%s:%d", + ProcessPriorityToString(mPriority), aLRU); + + FireTestOnlyObserverNotification("process-priority-with-LRU-set", + processPriorityWithLRU.get()); return; } - if (aPriority == PROCESS_PRIORITY_BACKGROUND && - mPriority != PROCESS_PRIORITY_BACKGROUND && - !IsPreallocated()) { - ProcessPriorityManager::AddIntoBackgroundLRUPool(mContentParent); - } - - if (aPriority != PROCESS_PRIORITY_BACKGROUND && - mPriority == PROCESS_PRIORITY_BACKGROUND && - !IsPreallocated()) { - ProcessPriorityManager::RemoveFromBackgroundLRUPool(mContentParent); - } - LOGP("Changing priority from %s to %s.", ProcessPriorityToString(mPriority), ProcessPriorityToString(aPriority)); @@ -1018,10 +1024,6 @@ ParticularProcessPriorityManager::ShutDown() mResetPriorityTimer = nullptr; } - if (mPriority == PROCESS_PRIORITY_BACKGROUND && !IsPreallocated()) { - ProcessPriorityManager::RemoveFromBackgroundLRUPool(mContentParent); - } - mContentParent = nullptr; } @@ -1162,179 +1164,112 @@ ProcessPriorityManagerChild::CurrentProcessIsHighPriority() mCachedPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH; } -/* static */ StaticAutoPtr -BackgroundProcessLRUPool::sSingleton; - -/* static */ BackgroundProcessLRUPool* -BackgroundProcessLRUPool::Singleton() +ProcessLRUPool::ProcessLRUPool(ProcessPriority aPriority, uint32_t aBias) + : mPriority(aPriority) + , mLRUPoolLevels(1) + , mBias(aBias) { - if (!sSingleton) { - sSingleton = new BackgroundProcessLRUPool(); - ClearOnShutdown(&sSingleton); - } - return sSingleton; -} - -BackgroundProcessLRUPool::BackgroundProcessLRUPool() -{ - EnsureLRUPool(); -} - -uint32_t -BackgroundProcessLRUPool::CalculateLRULevel(uint32_t aBackgroundLRUPoolIndex) -{ - // Set LRU level of each background process and maintain LRU buffer as below: - - // Priority background : LRU0 - // Priority background+1: LRU1, LRU2 - // Priority background+2: LRU3, LRU4, LRU5, LRU6 - // Priority background+3: LRU7, LRU8, LRU9, LRU10, LRU11, LRU12, LRU13, LRU14 - // ... - // Priority background+L-1: 2^(number of background LRU pool levels - 1) - // (End of buffer) - - return (uint32_t)(log((float)aBackgroundLRUPoolIndex) / log(2.0)); -} - -void -BackgroundProcessLRUPool::EnsureLRUPool() -{ - // We set mBackgroundLRUPoolLevels according to our pref. + // We set mLRUPoolLevels according to our pref. // This value is used to set background process LRU pool - if (!NS_SUCCEEDED(Preferences::GetInt( - "dom.ipc.processPriorityManager.backgroundLRUPoolLevels", - &mLRUPoolLevels))) { - mLRUPoolLevels = 1; - } + const char* str = ProcessPriorityToString(aPriority); + nsPrintfCString pref("dom.ipc.processPriorityManager.%s.LRUPoolLevels", str); - if (mLRUPoolLevels <= 0) { - MOZ_CRASH(); - } + Preferences::GetUint(pref.get(), &mLRUPoolLevels); // GonkHal defines OOM_ADJUST_MAX is 15 and b2g.js defines // PROCESS_PRIORITY_BACKGROUND's oom_score_adj is 667 and oom_adj is 10. // This means we can only have at most (15 -10 + 1) = 6 background LRU levels. - // See bug 822325 comment 49 - MOZ_ASSERT(mLRUPoolLevels <= 6); + // Similarly we can have at most 4 foreground LRU levels. We should really be + // getting rid of oom_adj and just rely on oom_score_adj only which would + // lift this constraint. + MOZ_ASSERT(aPriority != PROCESS_PRIORITY_BACKGROUND || mLRUPoolLevels <= 6); + MOZ_ASSERT(aPriority != PROCESS_PRIORITY_FOREGROUND || mLRUPoolLevels <= 4); // LRU pool size = 2 ^ (number of background LRU pool levels) - 1 mLRUPoolSize = (1 << mLRUPoolLevels) - 1; - mLRUPoolAvailableIndex = 0; + LOG("Making %s LRU pool with size(%d)", str, mLRUPoolSize); +} - LOG("Making background LRU pool with size(%d)", mLRUPoolSize); +uint32_t +ProcessLRUPool::CalculateLRULevel(uint32_t aLRU) +{ + // This is used to compute the LRU adjustment for the specified LRU position. + // We use power-of-two groups with increasing adjustments that look like the + // following: - mLRUPool.InsertElementsAt(0, mLRUPoolSize, (ContentParent*)nullptr); + // Priority : LRU0, LRU1 + // Priority+1: LRU2, LRU3 + // Priority+2: LRU4, LRU5, LRU6, LRU7 + // Priority+3: LRU8, LRU9, LRU10, LRU11, LRU12, LRU12, LRU13, LRU14, LRU15 + // ... + // Priority+L-1: 2^(number of LRU pool levels - 1) + // (End of buffer) + + // Biasing the input can be used to shift the assignment + + int exp; + unused << frexp(static_cast(aLRU), &exp); + uint32_t level = std::max(exp - 1, 0); + + return std::min(mLRUPoolLevels - 1, level); } void -BackgroundProcessLRUPool::RemoveFromBackgroundLRUPool( - ContentParent* aContentParent) +ProcessLRUPool::Remove(ParticularProcessPriorityManager* aParticularManager) { - for (int32_t i = 0; i < mLRUPoolSize; i++) { - if (mLRUPool[i]) { - if (mLRUPool[i]->ChildID() == aContentParent->ChildID()) { + nsTArray::index_type index = + mLRUPool.IndexOf(aParticularManager); - mLRUPool[i] = nullptr; - LOG("Remove ChildID(%llu) from LRU pool", aContentParent->ChildID()); - - // After we remove this ContentParent from LRU pool, we still need to - // update the available index if the index of removed one is less than - // the available index we already have. - UpdateAvailableIndexInLRUPool(aContentParent, i); - break; - } - } - } -} - -nsresult -BackgroundProcessLRUPool::UpdateAvailableIndexInLRUPool( - ContentParent* aContentParent, - int32_t aTargetIndex) -{ - // If we specify which index we want to assign to mLRUPoolAvailableIndex, - // We have to make sure the index in LRUPool doesn't point to any - // ContentParent. - if (aTargetIndex >= 0 && aTargetIndex < mLRUPoolSize && - aTargetIndex < mLRUPoolAvailableIndex && - !mLRUPool[aTargetIndex]) { - mLRUPoolAvailableIndex = aTargetIndex; - return NS_OK; - } - - // When we didn't specify any legal aTargetIndex, then we just check - // whether current mLRUPoolAvailableIndex points to any ContentParent or not. - if (mLRUPoolAvailableIndex >= 0 && mLRUPoolAvailableIndex < mLRUPoolSize && - !(mLRUPool[mLRUPoolAvailableIndex])) { - return NS_OK; - } - - // Both above way failed. So now we have to find proper value - // for mLRUPoolAvailableIndex. - // We are looking for an available index. We only shift process with - // LRU less than the available index should have, so we stop update - // mLRUPoolAvailableIndex from the for loop once we got a candidate. - mLRUPoolAvailableIndex = -1; - - for (int32_t i = 0; i < mLRUPoolSize; i++) { - if (mLRUPool[i]) { - if (mLRUPool[i]->ChildID() == aContentParent->ChildID()) { - LOG("ChildID(%llu) already in LRU pool", aContentParent->ChildID()); - MOZ_ASSERT(false); - return NS_ERROR_UNEXPECTED; - } - continue; - } else { - if (mLRUPoolAvailableIndex == -1) { - mLRUPoolAvailableIndex = i; - } - } - } - - // If the LRUPool is already full, mLRUPoolAvailableIndex is still -1 after - // above loop finished. We should set mLRUPoolAvailableIndex - // to mLRUPoolSize - 1 in this case. Here uses the mod operator to do it: - // New mLRUPoolAvailableIndex either equals old mLRUPoolAvailableIndex, or - // mLRUPoolSize - 1 if old mLRUPoolAvailableIndex is -1. - mLRUPoolAvailableIndex = - (mLRUPoolAvailableIndex + mLRUPoolSize) % mLRUPoolSize; - - return NS_OK; -} - -void -BackgroundProcessLRUPool::ShiftLRUPool() -{ - for (int32_t i = mLRUPoolAvailableIndex; i > 0; i--) { - mLRUPool[i] = mLRUPool[i - 1]; - // Check whether i+1 is power of Two. - // If so, then it crossed a LRU group boundary and - // we need to assign its new process priority LRU. - if (!((i + 1) & i)) { - ProcessPriorityManagerImpl::GetSingleton()->SetProcessPriority( - mLRUPool[i], PROCESS_PRIORITY_BACKGROUND, CalculateLRULevel(i + 1)); - } - } -} - -void -BackgroundProcessLRUPool::AddIntoBackgroundLRUPool( - ContentParent* aContentParent) -{ - // We have to make sure that we have correct available index in LRU pool - if (!NS_SUCCEEDED( - UpdateAvailableIndexInLRUPool(aContentParent))) { + if (index == nsTArray::NoIndex) { return; } + mLRUPool.RemoveElementAt(index); + AdjustLRUValues(index, /* removed */ true); + + LOG("Remove ChildID(%" PRIu64 ") from %s LRU pool", + static_cast(aParticularManager->ChildID()), + ProcessPriorityToString(mPriority)); +} + +/* + * Adjust the LRU values of all the processes in an LRU pool. When true the + * `removed` parameter indicates that the processes were shifted left because + * an element was removed; otherwise it means the elements were shifted right + * as an element was added. + */ +void +ProcessLRUPool::AdjustLRUValues( + nsTArray::index_type aStart, + bool removed) +{ + uint32_t adj = (removed ? 1 : 0) + mBias; + + for (nsTArray::index_type i = aStart; + i < mLRUPool.Length(); + i++) { + /* Check whether i is a power of two. If so, then it crossed a LRU group + * boundary and we need to assign its new process priority LRU. Note that + * depending on the direction and the bias this test will pick different + * elements. */ + if (((i + adj) & (i + adj - 1)) == 0) { + mLRUPool[i]->SetPriorityNow(mPriority, CalculateLRULevel(i + mBias)); + } + } +} + +void +ProcessLRUPool::Add(ParticularProcessPriorityManager* aParticularManager) +{ // Shift the list in the pool, so we have room at index 0 for the newly added - // ContentParent - ShiftLRUPool(); + // manager + mLRUPool.InsertElementAt(0, aParticularManager); + AdjustLRUValues(1, /* removed */ false); - mLRUPool[0] = aContentParent; - - LOG("Add ChildID(%llu) into LRU pool", aContentParent->ChildID()); + LOG("Add ChildID(%" PRIu64 ") into %s LRU pool", + static_cast(aParticularManager->ChildID()), + ProcessPriorityToString(mPriority)); } } // anonymous namespace @@ -1361,31 +1296,6 @@ ProcessPriorityManager::SetProcessPriority(ContentParent* aContentParent, } } -/* static */ void -ProcessPriorityManager::RemoveFromBackgroundLRUPool( - ContentParent* aContentParent) -{ - MOZ_ASSERT(aContentParent); - - BackgroundProcessLRUPool* singleton = - BackgroundProcessLRUPool::Singleton(); - if (singleton) { - singleton->RemoveFromBackgroundLRUPool(aContentParent); - } -} - -/* static */ void -ProcessPriorityManager::AddIntoBackgroundLRUPool(ContentParent* aContentParent) -{ - MOZ_ASSERT(aContentParent); - - BackgroundProcessLRUPool* singleton = - BackgroundProcessLRUPool::Singleton(); - if (singleton) { - singleton->AddIntoBackgroundLRUPool(aContentParent); - } -} - /* static */ bool ProcessPriorityManager::CurrentProcessIsForeground() { diff --git a/dom/ipc/ProcessPriorityManager.h b/dom/ipc/ProcessPriorityManager.h index 58d222c7807..df25e94faa5 100644 --- a/dom/ipc/ProcessPriorityManager.h +++ b/dom/ipc/ProcessPriorityManager.h @@ -74,18 +74,6 @@ public: */ static bool AnyProcessHasHighPriority(); - /** - * Used to remove a ContentParent from background LRU pool when - * it is destroyed or its priority changed from BACKGROUND to others. - */ - static void RemoveFromBackgroundLRUPool(dom::ContentParent* aContentParent); - - /** - * Used to add a ContentParent into background LRU pool when - * its priority changed to BACKGROUND from others. - */ - static void AddIntoBackgroundLRUPool(dom::ContentParent* aContentParent); - private: ProcessPriorityManager(); DISALLOW_EVIL_CONSTRUCTORS(ProcessPriorityManager); diff --git a/dom/ipc/tests/test_NuwaProcessCreation.html b/dom/ipc/tests/test_NuwaProcessCreation.html index ea005d857aa..9ee6223885d 100644 --- a/dom/ipc/tests/test_NuwaProcessCreation.html +++ b/dom/ipc/tests/test_NuwaProcessCreation.html @@ -51,7 +51,7 @@ function setPref(pref, value) { setPref('dom.ipc.processPriorityManager.testMode', true); setPref('dom.ipc.processPriorityManager.enabled', true); -setPref('dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2); +setPref('dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels', 2); function runTest() { diff --git a/dom/ipc/tests/test_NuwaProcessDeadlock.html b/dom/ipc/tests/test_NuwaProcessDeadlock.html index 63aefdd7b42..8dd13075cd4 100644 --- a/dom/ipc/tests/test_NuwaProcessDeadlock.html +++ b/dom/ipc/tests/test_NuwaProcessDeadlock.html @@ -51,7 +51,7 @@ function setPref(pref, value) { setPref('dom.ipc.processPriorityManager.testMode', true); setPref('dom.ipc.processPriorityManager.enabled', true); -setPref('dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2); +setPref('dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels', 2); setPref('dom.ipc.processPrelaunch.testMode', true); // For testing deadlock. function runTest() diff --git a/hal/Hal.cpp b/hal/Hal.cpp index f798f02046b..880a20bc2bb 100644 --- a/hal/Hal.cpp +++ b/hal/Hal.cpp @@ -861,14 +861,11 @@ SetAlarm(int32_t aSeconds, int32_t aNanoseconds) } void -SetProcessPriority(int aPid, - ProcessPriority aPriority, - uint32_t aBackgroundLRU) +SetProcessPriority(int aPid, ProcessPriority aPriority, uint32_t aLRU) { // n.b. The sandboxed implementation crashes; SetProcessPriority works only // from the main process. - MOZ_ASSERT(aBackgroundLRU == 0 || aPriority == PROCESS_PRIORITY_BACKGROUND); - PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority, aBackgroundLRU)); + PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority, aLRU)); } void diff --git a/hal/fallback/FallbackProcessPriority.cpp b/hal/fallback/FallbackProcessPriority.cpp index 34ce57ed43c..3c85f75d29a 100644 --- a/hal/fallback/FallbackProcessPriority.cpp +++ b/hal/fallback/FallbackProcessPriority.cpp @@ -11,12 +11,10 @@ namespace mozilla { namespace hal_impl { void -SetProcessPriority(int aPid, - ProcessPriority aPriority, - uint32_t aBackgroundLRU) +SetProcessPriority(int aPid, ProcessPriority aPriority, uint32_t aLRU) { HAL_LOG("FallbackProcessPriority - SetProcessPriority(%d, %s, %u)\n", - aPid, ProcessPriorityToString(aPriority), aBackgroundLRU); + aPid, ProcessPriorityToString(aPriority), aLRU); } } // hal_impl diff --git a/hal/gonk/GonkHal.cpp b/hal/gonk/GonkHal.cpp index 777e0980953..5cba23f0568 100644 --- a/hal/gonk/GonkHal.cpp +++ b/hal/gonk/GonkHal.cpp @@ -1199,12 +1199,12 @@ OomAdjOfOomScoreAdj(int aOomScoreAdj) } static void -RoundOomScoreAdjUpWithBackroundLRU(int& aOomScoreAdj, uint32_t aBackgroundLRU) +RoundOomScoreAdjUpWithLRU(int& aOomScoreAdj, uint32_t aLRU) { // We want to add minimum value to round OomScoreAdj up according to - // the steps by aBackgroundLRU. + // the steps by aLRU. aOomScoreAdj += - ceil(((float)OOM_SCORE_ADJ_MAX / OOM_ADJUST_MAX) * aBackgroundLRU); + ceil(((float)OOM_SCORE_ADJ_MAX / OOM_ADJUST_MAX) * aLRU); } #define OOM_LOG(level, args...) __android_log_print(level, "OomLogger", ##args) @@ -1790,12 +1790,10 @@ EnsureKernelLowMemKillerParamsSet() } void -SetProcessPriority(int aPid, - ProcessPriority aPriority, - uint32_t aBackgroundLRU) +SetProcessPriority(int aPid, ProcessPriority aPriority, uint32_t aLRU) { HAL_LOG("SetProcessPriority(pid=%d, priority=%d, LRU=%u)", - aPid, aPriority, aBackgroundLRU); + aPid, aPriority, aLRU); // If this is the first time SetProcessPriority was called, set the kernel's // OOM parameters according to our prefs. @@ -1810,7 +1808,7 @@ SetProcessPriority(int aPid, int oomScoreAdj = pc->OomScoreAdj(); - RoundOomScoreAdjUpWithBackroundLRU(oomScoreAdj, aBackgroundLRU); + RoundOomScoreAdjUpWithLRU(oomScoreAdj, aLRU); // We try the newer interface first, and fall back to the older interface // on failure. diff --git a/hal/sandbox/SandboxHal.cpp b/hal/sandbox/SandboxHal.cpp index 5cb6fc99f56..e61c2989e1a 100644 --- a/hal/sandbox/SandboxHal.cpp +++ b/hal/sandbox/SandboxHal.cpp @@ -355,9 +355,7 @@ SetAlarm(int32_t aSeconds, int32_t aNanoseconds) } void -SetProcessPriority(int aPid, - ProcessPriority aPriority, - uint32_t aBackgroundLRU) +SetProcessPriority(int aPid, ProcessPriority aPriority, uint32_t aLRU) { NS_RUNTIMEABORT("Only the main process may set processes' priorities."); }