Bug 1019101 - Add a way to get the max CC pause during a given period of time. r=smaug
authorAndrew McCreight <continuation@gmail.com>
Sat, 14 Jun 2014 16:43:45 -0700
changeset 188763 057973613987672beacba1843afb30bb2f466623
parent 188762 315b89ffbe126c61f653cb54957d5ab3f475c45c
child 188764 7cafd3d4f0d7b8e037114b96518dde99665d4a44
push idunknown
push userunknown
push dateunknown
reviewerssmaug
bugs1019101
milestone33.0a1
Bug 1019101 - Add a way to get the max CC pause during a given period of time. r=smaug
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
js/xpconnect/idl/xpccomponents.idl
js/xpconnect/src/XPCComponents.cpp
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1805,16 +1805,22 @@ TimeUntilNow(TimeStamp start)
   if (start.IsNull()) {
     return 0;
   }
   return TimeBetween(start, TimeStamp::Now());
 }
 
 struct CycleCollectorStats
 {
+  void Init()
+  {
+    Clear();
+    mMaxSliceTimeSinceClear = 0;
+  }
+
   void Clear()
   {
     mBeginSliceTime = TimeStamp();
     mEndSliceTime = TimeStamp();
     mBeginTime = TimeStamp();
     mMaxGCDuration = 0;
     mRanSyncForgetSkippable = false;
     mSuspected = 0;
@@ -1832,16 +1838,17 @@ struct CycleCollectorStats
     if (mBeginSliceTime.IsNull()) {
       // We already called this method from EndCycleCollectionCallback for this slice.
       return;
     }
 
     mEndSliceTime = TimeStamp::Now();
     uint32_t sliceTime = TimeBetween(mBeginSliceTime, mEndSliceTime);
     mMaxSliceTime = std::max(mMaxSliceTime, sliceTime);
+    mMaxSliceTimeSinceClear = std::max(mMaxSliceTimeSinceClear, sliceTime);
     mTotalSliceTime += sliceTime;
     mBeginSliceTime = TimeStamp();
     MOZ_ASSERT(mExtraForgetSkippableCalls == 0, "Forget to reset extra forget skippable calls?");
   }
 
   void RunForgetSkippable();
 
   // Time the current slice began, including any GC finishing.
@@ -1864,16 +1871,19 @@ struct CycleCollectorStats
 
   // The longest duration spent on sync forget skippable in any slice of the
   // current CC.
   uint32_t mMaxSkippableDuration;
 
   // The longest pause of any slice in the current CC.
   uint32_t mMaxSliceTime;
 
+  // The longest slice time since ClearMaxCCSliceTime() was called.
+  uint32_t mMaxSliceTimeSinceClear;
+
   // The total amount of time spent actually running the current CC.
   uint32_t mTotalSliceTime;
 
   // True if we were locked out by the GC in any slice of the current CC.
   bool mAnyLockedOut;
 
   int32_t mExtraForgetSkippableCalls;
 };
@@ -1989,16 +1999,28 @@ nsJSContext::RunCycleCollectorWorkSlice(
   PROFILER_LABEL("nsJSContext", "RunCycleCollectorWorkSlice",
     js::ProfileEntry::Category::CC);
 
   gCCStats.PrepareForCycleCollectionSlice();
   nsCycleCollector_collectSliceWork(aWorkBudget);
   gCCStats.FinishCycleCollectionSlice();
 }
 
+void
+nsJSContext::ClearMaxCCSliceTime()
+{
+  gCCStats.mMaxSliceTimeSinceClear = 0;
+}
+
+uint32_t
+nsJSContext::GetMaxCCSliceTimeSinceClear()
+{
+  return gCCStats.mMaxSliceTimeSinceClear;
+}
+
 static void
 ICCTimerFired(nsITimer* aTimer, void* aClosure)
 {
   if (sDidShutdown) {
     return;
   }
 
   // Ignore ICC timer fires during IGC. Running ICC during an IGC will cause us
@@ -2714,17 +2736,17 @@ mozilla::dom::StartupJSEnvironment()
   gNameSpaceManager = nullptr;
   sRuntimeService = nullptr;
   sRuntime = nullptr;
   sIsInitialized = false;
   sDidShutdown = false;
   sShuttingDown = false;
   sContextCount = 0;
   sSecurityManager = nullptr;
-  gCCStats.Clear();
+  gCCStats.Init();
   sExpensiveCollectorPokes = 0;
 }
 
 static void
 ReportAllJSExceptionsPrefChangedCallback(const char* aPrefName, void* aClosure)
 {
   bool reportAll = Preferences::GetBool(aPrefName, false);
   nsContentUtils::XPConnect()->SetReportAllJSExceptions(reportAll);
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -96,16 +96,20 @@ public:
   static void RunCycleCollectorSlice();
 
   // Run a cycle collector slice, using the given work budget.
   static void RunCycleCollectorWorkSlice(int64_t aWorkBudget);
 
   static void BeginCycleCollectionCallback();
   static void EndCycleCollectionCallback(mozilla::CycleCollectorResults &aResults);
 
+  // Return the longest CC slice time since ClearMaxCCSliceTime() was last called.
+  static uint32_t GetMaxCCSliceTimeSinceClear();
+  static void ClearMaxCCSliceTime();
+
   static void RunNextCollectorTimer();
 
   static void PokeGC(JS::gcreason::Reason aReason, int aDelay = 0);
   static void KillGCTimer();
 
   static void PokeShrinkGCBuffers();
   static void KillShrinkGCBuffersTimer();
 
--- a/js/xpconnect/idl/xpccomponents.idl
+++ b/js/xpconnect/idl/xpccomponents.idl
@@ -116,17 +116,17 @@ interface nsIXPCComponents_utils_Sandbox
 interface ScheduledGCCallback : nsISupports
 {
     void callback();
 };
 
 /**
 * interface of Components.utils
 */
-[scriptable, uuid(a485ba50-e208-11e3-8b68-0800200c9a66)]
+[scriptable, uuid(76ef3a80-f24d-11e3-ac10-0800200c9a66)]
 interface nsIXPCComponents_Utils : nsISupports
 {
 
     /* reportError is designed to be called from JavaScript only.
      *
      * It will report a JS Error object to the JS console, and return. It
      * is meant for use in exception handler blocks which want to "eat"
      * an exception, but still want to report it to the console.
@@ -286,16 +286,32 @@ interface nsIXPCComponents_Utils : nsISu
      * The cost of calling Traverse() on a single object is set as 1.
      * For testing.
      */
     void ccSlice(in long long budget);
 
     /*
      * To be called from JS only.
      *
+     * Return the longest cycle collector slice time since the last
+     * time clearMaxCCTime() was called.
+     */
+    long getMaxCCSliceTimeSinceClear();
+
+    /*
+     * To be called from JS only.
+     *
+     * Reset the internal max slice time value used for
+     * getMaxCCSliceTimeSinceClear().
+     */
+    void clearMaxCCTime();
+
+    /*
+     * To be called from JS only.
+     *
      * Force an immediate shrinking garbage collection cycle.
      */
     void forceShrinkingGC();
 
     /*
      * Schedule a garbage collection cycle for a point in the future when no JS
      * is running. Call the provided function once this has occurred.
      */
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2812,16 +2812,32 @@ nsXPCComponents_Utils::FinishCC()
 /* void ccSlice(in long long budget); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::CcSlice(int64_t budget)
 {
     nsJSContext::RunCycleCollectorWorkSlice(budget);
     return NS_OK;
 }
 
+/* long getMaxCCSliceTimeSinceClear(); */
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetMaxCCSliceTimeSinceClear(int32_t *out)
+{
+    *out = nsJSContext::GetMaxCCSliceTimeSinceClear();
+    return NS_OK;
+}
+
+/* void clearMaxCCTime(); */
+NS_IMETHODIMP
+nsXPCComponents_Utils::ClearMaxCCTime()
+{
+    nsJSContext::ClearMaxCCSliceTime();
+    return NS_OK;
+}
+
 /* void forceShrinkingGC (); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::ForceShrinkingGC()
 {
     JSRuntime* rt = nsXPConnect::GetRuntimeInstance()->Runtime();
     PrepareForFullGC(rt);
     ShrinkingGC(rt, gcreason::COMPONENT_UTILS);
     return NS_OK;