Bug 1366217 - Add more assertions to help track down LongestPhaseSelfTime crashes r=sfink
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 19 Jul 2017 09:37:18 +0100
changeset 418418 9b93d7a06157c365acbfbba173ce658393472035
parent 418417 c99d20ba408a4fd19bab0bc04ff926e73d838fbf
child 418419 91467cd8d9d4ce34e9b2271f7a240cfdc96cb706
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1366217
milestone56.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 1366217 - Add more assertions to help track down LongestPhaseSelfTime crashes r=sfink
js/src/gc/Statistics.cpp
js/src/gc/Statistics.h
js/src/vm/HelperThreads.cpp
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -924,16 +924,19 @@ Statistics::endNurseryCollection(JS::gcr
                                      reason);
     }
 }
 
 void
 Statistics::beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
                        SliceBudget budget, JS::gcreason::Reason reason)
 {
+    MOZ_ASSERT(phaseStack.empty() ||
+               (phaseStack.length() == 1 && phaseStack[0] == Phase::MUTATOR));
+
     this->zoneStats = zoneStats;
 
     bool first = !runtime->gc.isIncrementalGCInProgress();
     if (first)
         beginGC(gckind);
 
     if (!slices_.emplaceBack(budget,
                              reason,
@@ -957,16 +960,19 @@ Statistics::beginSlice(const ZoneGCStats
             (*sliceCallback)(cx, JS::GC_CYCLE_BEGIN, desc);
         (*sliceCallback)(cx, JS::GC_SLICE_BEGIN, desc);
     }
 }
 
 void
 Statistics::endSlice()
 {
+    MOZ_ASSERT(phaseStack.empty() ||
+               (phaseStack.length() == 1 && phaseStack[0] == Phase::MUTATOR));
+
     if (!aborted) {
         auto& slice = slices_.back();
         slice.end = TimeStamp::Now();
         slice.endFaults = GetPageFaultCount();
         slice.finalState = runtime->gc.state();
 
         TimeDuration sliceTime = slice.end - slice.start;
         runtime->addTelemetry(JS_TELEMETRY_GC_SLICE_MS, t(sliceTime));
@@ -1205,41 +1211,31 @@ Statistics::endPhase(PhaseKind phaseKind
     {
         resumePhases();
     }
 }
 
 void
 Statistics::recordParallelPhase(PhaseKind phaseKind, TimeDuration duration)
 {
+    MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime));
+
     Phase phase = lookupChildPhase(phaseKind);
 
     // Record the duration for all phases in the tree up to the root. This is
     // not strictly necessary but makes the invariant that parent phase times
     // include their children apply to both phaseTimes and parallelTimes.
     while (phase != Phase::NONE) {
         if (!slices_.empty())
             slices_.back().parallelTimes[phase] += duration;
         parallelTimes[phase] += duration;
         phase = phases[phase].parent;
     }
 }
 
-void
-Statistics::endParallelPhase(PhaseKind phaseKind, const GCParallelTask* task)
-{
-    Phase phase = lookupChildPhase(phaseKind);
-    phaseStack.popBack();
-
-    if (!slices_.empty())
-        slices_.back().phaseTimes[phase] += task->duration();
-    phaseTimes[phase] += task->duration();
-    phaseStartTimes[phase] = TimeStamp();
-}
-
 TimeStamp
 Statistics::beginSCC()
 {
     return TimeStamp::Now();
 }
 
 void
 Statistics::endSCC(unsigned scc, TimeStamp start)
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -126,17 +126,16 @@ struct Statistics
     explicit Statistics(JSRuntime* rt);
     ~Statistics();
 
     Statistics(const Statistics&) = delete;
     Statistics& operator=(const Statistics&) = delete;
 
     void beginPhase(PhaseKind phaseKind);
     void endPhase(PhaseKind phaseKind);
-    void endParallelPhase(PhaseKind phaseKind, const GCParallelTask* task);
     void recordParallelPhase(PhaseKind phaseKind, TimeDuration duration);
 
     // Occasionally, we may be in the middle of something that is tracked by
     // this class, and we need to do something unusual (eg evict the nursery)
     // that doesn't normally nest within the current phase. Suspend the
     // currently tracked phase stack, at which time the caller is free to do
     // other tracked operations.
     //
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -32,16 +32,17 @@
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
 
 using mozilla::ArrayLength;
 using mozilla::DebugOnly;
 using mozilla::Unused;
 using mozilla::TimeDuration;
+using mozilla::TimeStamp;
 
 namespace js {
 
 GlobalHelperThreadState* gHelperThreadState = nullptr;
 
 } // namespace js
 
 bool
@@ -1310,39 +1311,53 @@ js::GCParallelTask::joinWithLockHeld(Aut
 
 void
 js::GCParallelTask::join()
 {
     AutoLockHelperThreadState helperLock;
     joinWithLockHeld(helperLock);
 }
 
+static inline
+TimeDuration
+TimeSince(TimeStamp prev)
+{
+    TimeStamp now = TimeStamp::Now();
+#ifdef ANDROID
+    // Sadly this happens sometimes.
+    if (now < prev)
+        now = prev;
+#endif
+    MOZ_RELEASE_ASSERT(now >= prev);
+    return now - prev;
+}
+
 void
 js::GCParallelTask::runFromActiveCooperatingThread(JSRuntime* rt)
 {
     MOZ_ASSERT(state == NotStarted);
     MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(rt));
-    mozilla::TimeStamp timeStart = mozilla::TimeStamp::Now();
+    TimeStamp timeStart = TimeStamp::Now();
     run();
-    duration_ = mozilla::TimeStamp::Now() - timeStart;
+    duration_ = TimeSince(timeStart);
 }
 
 void
 js::GCParallelTask::runFromHelperThread(AutoLockHelperThreadState& locked)
 {
     AutoSetContextRuntime ascr(runtime());
     gc::AutoSetThreadIsPerformingGC performingGC;
 
     {
         AutoUnlockHelperThreadState parallelSection(locked);
-        mozilla::TimeStamp timeStart = mozilla::TimeStamp::Now();
+        TimeStamp timeStart = TimeStamp::Now();
         TlsContext.get()->heapState = JS::HeapState::MajorCollecting;
         run();
         TlsContext.get()->heapState = JS::HeapState::Idle;
-        duration_ = mozilla::TimeStamp::Now() - timeStart;
+        duration_ = TimeSince(timeStart);
     }
 
     state = Finished;
     HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
 }
 
 bool
 js::GCParallelTask::isRunningWithLockHeld(const AutoLockHelperThreadState& locked) const