Bug 1335148 - Part 2: Introduce notification for end of memory pressure. r=gsvelto,snorp
authorJan Henning <jh+bugzilla@buttercookie.de>
Fri, 30 Mar 2018 13:26:24 +0200
changeset 417625 6e79931930ee4bf830f79efc2322093b6e6190be
parent 417624 d8e7c56a2a858c4f05dc20a199d43dd74729c3e3
child 417626 36e95b6ba7a6fcebf06030e449ad2cf4b73ae9a2
push id33974
push userncsoregi@mozilla.com
push dateThu, 10 May 2018 09:47:43 +0000
treeherdermozilla-central@b52b2eb81d1e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgsvelto, snorp
bugs1335148
milestone62.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
Bug 1335148 - Part 2: Introduce notification for end of memory pressure. r=gsvelto,snorp For Fennec on Android, if we haven't received memory pressure notifications from the OS for a certain amount of time (in the order of ~15 mins), we assume that we're no longer under memory pressure. In order to turn the bfcache back on when that happens, we now want to be able to forward this fact to Gecko as well. Unfortunately, the way memory pressure is tracked using an atomic variable doesn't easily allow to fully extend the existing priority rules between "new" and "ongoing" to include a new "stopping of memory pressure" event. Since we're not using Dispatch*Eventual*MemoryPressure on Android and therefore the queuing priority behaviour isn't actually relevant for us, we just ignore that and only enforce that a pending "new" memory pressure event takes priority over a "stop" event. MozReview-Commit-ID: 90C9KogUyvf
xpcom/threads/nsMemoryPressure.cpp
xpcom/threads/nsMemoryPressure.h
xpcom/threads/nsThread.cpp
--- a/xpcom/threads/nsMemoryPressure.cpp
+++ b/xpcom/threads/nsMemoryPressure.cpp
@@ -22,30 +22,31 @@ NS_GetPendingMemoryPressure()
   int32_t value = sMemoryPressurePending.exchange(MemPressure_None);
   return MemoryPressureState(value);
 }
 
 void
 NS_DispatchEventualMemoryPressure(MemoryPressureState aState)
 {
   /*
-   * A new memory pressure event erases an ongoing memory pressure, but an
-   * existing "new" memory pressure event takes precedence over a new "ongoing"
-   * memory pressure event.
+   * A new memory pressure event erases an ongoing (or stop of) memory pressure,
+   * but an existing "new" memory pressure event takes precedence over a new
+   * "ongoing" or "stop" memory pressure event.
    */
   switch (aState) {
     case MemPressure_None:
       sMemoryPressurePending = MemPressure_None;
       break;
     case MemPressure_New:
       sMemoryPressurePending = MemPressure_New;
       break;
     case MemPressure_Ongoing:
+    case MemPressure_Stopping:
       sMemoryPressurePending.compareExchange(MemPressure_None,
-                                             MemPressure_Ongoing);
+                                             aState);
       break;
   }
 }
 
 nsresult
 NS_DispatchMemoryPressure(MemoryPressureState aState)
 {
   NS_DispatchEventualMemoryPressure(aState);
--- a/xpcom/threads/nsMemoryPressure.h
+++ b/xpcom/threads/nsMemoryPressure.h
@@ -35,17 +35,28 @@ enum MemoryPressureState
    *
    * In case of conflict with an new memory pressue, the new memory pressure
    * takes precedence over an ongoing memory pressure.  The reason being
    * that if no events are processed between 2 notifications (new followed
    * by ongoing, or ongoing followed by a new) we want to be as aggresive as
    * possible on the clean-up of the memory.  After all, we are trying to
    * keep Gecko alive as long as possible.
    */
-  MemPressure_Ongoing
+  MemPressure_Ongoing,
+
+  /*
+   * Memory pressure stopped.
+   *
+   * We're no longer under acute memory pressure, so we might want to have a
+   * chance of (cautiously) re-enabling some things we previously turned off.
+   * As above, an already enqueued new memory pressure event takes precedence.
+   * The priority ordering between concurrent attempts to queue both stopped
+   * and ongoing memory pressure is currently not defined.
+   */
+  MemPressure_Stopping
 };
 
 /**
  * Return and erase the latest state of the memory pressure event set by any of
  * the corresponding dispatch function.
  */
 MemoryPressureState
 NS_GetPendingMemoryPressure();
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -1263,21 +1263,25 @@ nsThread::DoMainThreadSpecificProcessing
 
   // Fire a memory pressure notification, if one is pending.
   if (!ShuttingDown()) {
     MemoryPressureState mpPending = NS_GetPendingMemoryPressure();
     if (mpPending != MemPressure_None) {
       nsCOMPtr<nsIObserverService> os = services::GetObserverService();
 
       if (os) {
-        // Use no-forward to prevent the notifications from being transferred to
-        // the children of this process.
-        os->NotifyObservers(nullptr, "memory-pressure",
-                            mpPending == MemPressure_New ? u"low-memory-no-forward" :
-                            u"low-memory-ongoing-no-forward");
+        if (mpPending == MemPressure_Stopping) {
+          os->NotifyObservers(nullptr, "memory-pressure-stop", nullptr);
+        } else {
+          // Use no-forward to prevent the notifications from being transferred to
+          // the children of this process.
+          os->NotifyObservers(nullptr, "memory-pressure",
+                              mpPending == MemPressure_New ? u"low-memory-no-forward" :
+                              u"low-memory-ongoing-no-forward");
+        }
       } else {
         NS_WARNING("Can't get observer service!");
       }
     }
   }
 
   if (!ShuttingDown()) {
     SaveMemoryReportNearOOM(ShouldSaveMemoryReport::kMaybeReport);