Bug 844313 - Call GC more likely when there are lots of Events to collect, r=mccr8
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Thu, 07 Mar 2013 20:53:19 +0200
changeset 124141 c1ef9a062a881813022c38d51d66c71546a21dab
parent 124140 e0d9902b2bbfe9829cdd888b58f6fa7d4e0e1507
child 124142 fed3eba78414639f448d9e1c02a60983f2c2daf1
push id24408
push userryanvm@gmail.com
push dateFri, 08 Mar 2013 04:58:11 +0000
treeherdermozilla-central@cb432984d5ce [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs844313
milestone22.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 844313 - Call GC more likely when there are lots of Events to collect, r=mccr8
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMTouchEvent.cpp
content/events/src/nsDOMTouchEvent.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -17,16 +17,17 @@
 #include "nsIContent.h"
 #include "nsIPresShell.h"
 #include "nsIDocument.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsGkAtoms.h"
 #include "nsMutationEvent.h"
 #include "nsContentUtils.h"
+#include "nsJSEnvironment.h"
 #include "nsIURI.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScriptError.h"
 #include "mozilla/Preferences.h"
 #include "nsJSUtils.h"
 #include "DictionaryHelpers.h"
 #include "nsLayoutUtils.h"
 #include "nsIScrollableFrame.h"
@@ -71,16 +72,17 @@ nsDOMEvent::nsDOMEvent(nsPresContext* aP
           ...
         }
      */
     mEvent = new nsEvent(false, 0);
     mEvent->time = PR_Now();
   }
 
   InitPresContextData(aPresContext);
+  nsJSContext::LikelyShortLivingObjectCreated();
 }
 
 void
 nsDOMEvent::InitPresContextData(nsPresContext* aPresContext)
 {
   mPresContext = aPresContext;
   // Get the explicit original target (if it's anonymous make it null)
   {
--- a/content/events/src/nsDOMTouchEvent.cpp
+++ b/content/events/src/nsDOMTouchEvent.cpp
@@ -133,16 +133,17 @@ nsDOMTouch::Equals(nsIDOMTouch* aTouch)
          (mRotationAngle != orientation) ||
          (mRadius.x != radiusX) || (mRadius.y != radiusY);
 }
 
 // TouchList
 nsDOMTouchList::nsDOMTouchList(nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches)
 {
   mPoints.AppendElements(aTouches);
+  nsJSContext::LikelyShortLivingObjectCreated();
 }
 
 DOMCI_DATA(TouchList, nsDOMTouchList)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMTouchList)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIDOMTouchList)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TouchList)
--- a/content/events/src/nsDOMTouchEvent.h
+++ b/content/events/src/nsDOMTouchEvent.h
@@ -5,16 +5,17 @@
 #ifndef nsDOMTouchEvent_h_
 #define nsDOMTouchEvent_h_
 
 #include "nsDOMUIEvent.h"
 #include "nsIDOMTouchEvent.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "mozilla/Attributes.h"
+#include "nsJSEnvironment.h"
 
 class nsDOMTouch MOZ_FINAL : public nsIDOMTouch
 {
 public:
   nsDOMTouch(nsIDOMEventTarget* aTarget,
              int32_t aIdentifier,
              int32_t aPageX,
              int32_t aPageY,
@@ -36,16 +37,17 @@ public:
       mPointsInitialized = true;
       mRadius.x = aRadiusX;
       mRadius.y = aRadiusY;
       mRotationAngle = aRotationAngle;
       mForce = aForce;
 
       mChanged = false;
       mMessage = 0;
+      nsJSContext::LikelyShortLivingObjectCreated();
     }
   nsDOMTouch(int32_t aIdentifier,
              nsIntPoint aPoint,
              nsIntPoint aRadius,
              float aRotationAngle,
              float aForce)
     {
       mIdentifier = aIdentifier;
@@ -55,16 +57,17 @@ public:
       mRefPoint = aPoint;
       mPointsInitialized = false;
       mRadius = aRadius;
       mRotationAngle = aRotationAngle;
       mForce = aForce;
 
       mChanged = false;
       mMessage = 0;
+      nsJSContext::LikelyShortLivingObjectCreated();
     }
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMTouch)
   NS_DECL_NSIDOMTOUCH
   void InitializePoints(nsPresContext* aPresContext, nsEvent* aEvent)
   {
     if (mPointsInitialized) {
       return;
@@ -99,17 +102,20 @@ protected:
 
 class nsDOMTouchList MOZ_FINAL : public nsIDOMTouchList
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMTouchList)
   NS_DECL_NSIDOMTOUCHLIST
 
-  nsDOMTouchList() { }
+  nsDOMTouchList()
+  {
+    nsJSContext::LikelyShortLivingObjectCreated();
+  }
   nsDOMTouchList(nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches);
 
   void Append(nsIDOMTouch* aPoint)
   {
     mPoints.AppendElement(aPoint);
   }
 
   nsIDOMTouch* GetItemAt(uint32_t aIndex)
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -159,16 +159,17 @@ static bool sHasRunGC;
 // have an easy place to know when a load ends or is interrupted in
 // all cases. This counter also gets reset if we end up GC'ing while
 // we're waiting for a slow page to load. IOW, this count may be 0
 // even when there are pending loads.
 static uint32_t sPendingLoadCount;
 static bool sLoadingInProgress;
 
 static uint32_t sCCollectedWaitingForGC;
+static uint32_t sLikelyShortLivingObjectsNeedingGC;
 static bool sPostGCEventsToConsole;
 static bool sPostGCEventsToObserver;
 static bool sDisableExplicitCompartmentGC;
 static uint32_t sCCTimerFireCount = 0;
 static uint32_t sMinForgetSkippableTime = UINT32_MAX;
 static uint32_t sMaxForgetSkippableTime = 0;
 static uint32_t sTotalForgetSkippableTime = 0;
 static uint32_t sRemovedPurples = 0;
@@ -2766,17 +2767,18 @@ nsJSContext::CycleCollectNow(nsICycleCol
   // Prepare to actually run the CC.
   bool mergingCC = DoMergingCC(aForced);
   nsCycleCollectorResults ccResults;
   nsCycleCollector_collect(mergingCC, &ccResults, aListener);
   sCCollectedWaitingForGC += ccResults.mFreedRefCounted + ccResults.mFreedGCed;
 
   // If we collected a substantial amount of cycles, poke the GC since more objects
   // might be unreachable now.
-  if (sCCollectedWaitingForGC > 250) {
+  if (sCCollectedWaitingForGC > 250 ||
+      sLikelyShortLivingObjectsNeedingGC > 2500) {
     PokeGC(JS::gcreason::CC_WAITING);
   }
 
   PRTime endCCTime = PR_Now();
 
   // Log information about the CC via telemetry, JSON and the console.
   uint32_t ccNowDuration = TimeBetween(start, endCCTime);
   Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FINISH_IGC, finishedIGC);
@@ -2805,24 +2807,25 @@ nsJSContext::CycleCollectNow(nsICycleCol
     }
 
     nsCString gcMsg;
     if (ccResults.mForcedGC) {
       gcMsg.AssignLiteral(", forced a GC");
     }
 
     NS_NAMED_MULTILINE_LITERAL_STRING(kFmt,
-      NS_LL("CC(T+%.1f) duration: %lums, suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu RCed and %lu GCed (%lu waiting for GC)%s\n")
+      NS_LL("CC(T+%.1f) duration: %lums, suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu RCed and %lu GCed (%lu|%lu waiting for GC)%s\n")
       NS_LL("ForgetSkippable %lu times before CC, min: %lu ms, max: %lu ms, avg: %lu ms, total: %lu ms, sync: %lu ms, removed: %lu"));
     nsString msg;
     msg.Adopt(nsTextFormatter::smprintf(kFmt.get(), double(delta) / PR_USEC_PER_SEC,
                                         ccNowDuration, suspected,
                                         ccResults.mVisitedRefCounted, ccResults.mVisitedGCed, mergeMsg.get(),
                                         ccResults.mFreedRefCounted, ccResults.mFreedGCed,
-                                        sCCollectedWaitingForGC, gcMsg.get(),
+                                        sCCollectedWaitingForGC, sLikelyShortLivingObjectsNeedingGC,
+                                        gcMsg.get(),
                                         sForgetSkippableBeforeCC,
                                         minForgetSkippableTime / PR_USEC_PER_MSEC,
                                         sMaxForgetSkippableTime / PR_USEC_PER_MSEC,
                                         (sTotalForgetSkippableTime / cleanups) /
                                           PR_USEC_PER_MSEC,
                                         sTotalForgetSkippableTime / PR_USEC_PER_MSEC,
                                         skippableDuration, sRemovedPurples));
     nsCOMPtr<nsIConsoleService> cs =
@@ -2841,32 +2844,34 @@ nsJSContext::CycleCollectNow(nsICycleCol
          NS_LL("\"suspected\": %lu, ")
          NS_LL("\"visited\": { ")
              NS_LL("\"RCed\": %lu, ")
              NS_LL("\"GCed\": %lu }, ")
          NS_LL("\"collected\": { ")
              NS_LL("\"RCed\": %lu, ")
              NS_LL("\"GCed\": %lu }, ")
          NS_LL("\"waiting_for_gc\": %lu, ")
+         NS_LL("\"short_living_objects_waiting_for_gc\": %lu, ")
          NS_LL("\"forced_gc\": %d, ")
          NS_LL("\"forget_skippable\": { ")
              NS_LL("\"times_before_cc\": %lu, ")
              NS_LL("\"min\": %lu, ")
              NS_LL("\"max\": %lu, ")
              NS_LL("\"avg\": %lu, ")
              NS_LL("\"total\": %lu, ")
              NS_LL("\"removed\": %lu } ")
        NS_LL("}"));
     nsString json;
     json.Adopt(nsTextFormatter::smprintf(kJSONFmt.get(), endCCTime,
                                          ccNowDuration, gcDuration, skippableDuration,
                                          suspected,
                                          ccResults.mVisitedRefCounted, ccResults.mVisitedGCed,
                                          ccResults.mFreedRefCounted, ccResults.mFreedGCed,
                                          sCCollectedWaitingForGC,
+                                         sLikelyShortLivingObjectsNeedingGC,
                                          ccResults.mForcedGC,
                                          sForgetSkippableBeforeCC,
                                          minForgetSkippableTime / PR_USEC_PER_MSEC,
                                          sMaxForgetSkippableTime / PR_USEC_PER_MSEC,
                                          (sTotalForgetSkippableTime / cleanups) /
                                            PR_USEC_PER_MSEC,
                                          sTotalForgetSkippableTime / PR_USEC_PER_MSEC,
                                          sRemovedPurples));
@@ -3229,16 +3234,17 @@ DOMGCSliceCallback(JSRuntime *aRt, JS::G
     }
   }
 
   if (aProgress == JS::GC_CYCLE_END) {
     // May need to kill the inter-slice GC timer
     nsJSContext::KillInterSliceGCTimer();
 
     sCCollectedWaitingForGC = 0;
+    sLikelyShortLivingObjectsNeedingGC = 0;
     sCleanupsSinceLastGC = 0;
     sNeedsFullCC = true;
     sHasRunGC = true;
     nsJSContext::MaybePokeCC();
 
     if (aDesc.isCompartment_) {
       ++sCompartmentGCCount;
       if (!sFullGCTimer && !sShuttingDown) {
@@ -3320,16 +3326,22 @@ nsJSContext::DropScriptObject(void* aScr
 void
 nsJSContext::ReportPendingException()
 {
   if (mIsInitialized) {
     nsJSUtils::ReportPendingException(mContext);
   }
 }
 
+void
+nsJSContext::LikelyShortLivingObjectCreated()
+{
+  ++sLikelyShortLivingObjectsNeedingGC;
+}
+
 /**********************************************************************
  * nsJSRuntime implementation
  *********************************************************************/
 
 // QueryInterface implementation for nsJSRuntime
 NS_INTERFACE_MAP_BEGIN(nsJSRuntime)
   NS_INTERFACE_MAP_ENTRY(nsIScriptRuntime)
 NS_INTERFACE_MAP_END
@@ -3355,16 +3367,17 @@ nsJSRuntime::Startup()
   sGCTimer = sFullGCTimer = sCCTimer = nullptr;
   sCCLockedOut = false;
   sCCLockedOutTime = 0;
   sLastCCEndTime = 0;
   sHasRunGC = false;
   sPendingLoadCount = 0;
   sLoadingInProgress = false;
   sCCollectedWaitingForGC = 0;
+  sLikelyShortLivingObjectsNeedingGC = 0;
   sPostGCEventsToConsole = false;
   sDisableExplicitCompartmentGC = false;
   sNeedsFullCC = false;
   gNameSpaceManager = nullptr;
   sRuntimeService = nullptr;
   sRuntime = nullptr;
   sIsInitialized = false;
   sDidShutdown = false;
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -143,16 +143,19 @@ public:
   static void PokeShrinkGCBuffers();
   static void KillShrinkGCBuffersTimer();
 
   static void MaybePokeCC();
   static void KillCCTimer();
   static void KillFullGCTimer();
   static void KillInterSliceGCTimer();
 
+  // Calling LikelyShortLivingObjectCreated() makes a GC more likely.
+  static void LikelyShortLivingObjectCreated();
+
   virtual void GC(JS::gcreason::Reason aReason);
 
   static uint32_t CleanupsSinceLastGC();
 
   nsIScriptGlobalObject* GetCachedGlobalObject()
   {
     // Verify that we have a global so that this
     // does always return a null when GetGlobalObject() is null.