Bug 650161 - Report GC invocation kind in stats r=terrence
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 29 Oct 2014 16:52:05 +0000
changeset 212990 3479b8c7cc8d4ce6d4af9853cc2c086beea28c43
parent 212989 f05aa42d06e9a06855db5e1d70b93e23f2073386
child 212991 0259e2c45c3d7bb796e87b11f5eea261e11d09ea
push id27738
push usercbook@mozilla.com
push dateThu, 30 Oct 2014 13:46:07 +0000
treeherdermozilla-central@1aa1b23d799e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs650161
milestone36.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 650161 - Report GC invocation kind in stats r=terrence
js/src/gc/Statistics.cpp
js/src/gc/Statistics.h
js/src/jsgc.cpp
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -238,16 +238,26 @@ class gcstats::StatisticsSerializer
 /*
  * If this fails, then you can either delete this assertion and allow all
  * larger-numbered reasons to pile up in the last telemetry bucket, or switch
  * to GC_REASON_3 and bump the max value.
  */
 JS_STATIC_ASSERT(JS::gcreason::NUM_TELEMETRY_REASONS >= JS::gcreason::NUM_REASONS);
 
 const char *
+js::gcstats::ExplainInvocationKind(JSGCInvocationKind gckind)
+{
+    MOZ_ASSERT(gckind == GC_NORMAL || gckind == GC_SHRINK);
+    if (gckind == GC_NORMAL)
+         return "Normal";
+    else
+         return "Shrinking";
+}
+
+const char *
 js::gcstats::ExplainReason(JS::gcreason::Reason reason)
 {
     switch (reason) {
 #define SWITCH_REASON(name)                         \
         case JS::gcreason::name:                    \
           return #name;
         GCREASONS(SWITCH_REASON)
 
@@ -455,29 +465,31 @@ Statistics::formatDescription()
     int64_t sccTotal, sccLongest;
     sccDurations(&sccTotal, &sccLongest);
 
     double mmu20 = computeMMU(20 * PRMJ_USEC_PER_MSEC);
     double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC);
 
     const char *format =
 "=================================================================\n\
+  Invocation Kind: %s\n\
   Reason: %s\n\
   Incremental: %s%s\n\
   Zones Collected: %d of %d\n\
   Compartments Collected: %d of %d\n\
   MinorGCs since last GC: %d\n\
   MMU 20ms:%.1f%%; 50ms:%.1f%%\n\
   SCC Sweep Total (MaxPause): %.3fms (%.3fms)\n\
   HeapSize: %.3f MiB\n\
   Chunk Delta (magnitude): %+d  (%d)\n\
 ";
     char buffer[1024];
     memset(buffer, 0, sizeof(buffer));
     JS_snprintf(buffer, sizeof(buffer), format,
+                ExplainInvocationKind(gckind),
                 ExplainReason(slices[0].reason),
                 nonincrementalReason ? "no - " : "yes",
                                                   nonincrementalReason ? nonincrementalReason : "",
                 zoneStats.collectedZoneCount, zoneStats.zoneCount,
                 zoneStats.collectedCompartmentCount, zoneStats.compartmentCount,
                 counts[STAT_MINOR_GC],
                 mmu20 * 100., mmu50 * 100.,
                 t(sccTotal), t(sccLongest),
@@ -704,23 +716,24 @@ Statistics::printStats()
                 t(total),
                 t(phaseTimes[PHASE_MARK]),
                 t(phaseTimes[PHASE_SWEEP]));
     }
     fflush(fp);
 }
 
 void
-Statistics::beginGC()
+Statistics::beginGC(JSGCInvocationKind kind)
 {
     PodArrayZero(phaseStartTimes);
     PodArrayZero(phaseTimes);
 
     slices.clearAndFree();
     sccTimes.clearAndFree();
+    gckind = kind;
     nonincrementalReason = nullptr;
 
     preBytes = runtime->gc.usage.gcBytes();
 }
 
 void
 Statistics::endGC()
 {
@@ -752,23 +765,24 @@ Statistics::endGC()
         (*cb)(JS_TELEMETRY_GC_MMU_50, mmu50 * 100);
     }
 
     if (fp)
         printStats();
 }
 
 void
-Statistics::beginSlice(const ZoneGCStats &zoneStats, JS::gcreason::Reason reason)
+Statistics::beginSlice(const ZoneGCStats &zoneStats, JSGCInvocationKind gckind,
+                       JS::gcreason::Reason reason)
 {
     this->zoneStats = zoneStats;
 
     bool first = runtime->gc.state() == gc::NO_INCREMENTAL;
     if (first)
-        beginGC();
+        beginGC(gckind);
 
     SliceData data(reason, PRMJ_Now(), GetPageFaultCount());
     if (!slices.append(data))
         CrashAtUnhandlableOOM("Failed to allocate statistics slice.");
 
     if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback)
         (*cb)(JS_TELEMETRY_GC_REASON, reason);
 
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -7,16 +7,17 @@
 #ifndef gc_Statistics_h
 #define gc_Statistics_h
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/UniquePtr.h"
 
 #include "jsalloc.h"
+#include "jsgc.h"
 #include "jspubtd.h"
 
 #include "js/GCAPI.h"
 #include "js/Vector.h"
 
 struct JSCompartment;
 
 namespace js {
@@ -108,17 +109,18 @@ struct Statistics
 {
     explicit Statistics(JSRuntime *rt);
     ~Statistics();
 
     void beginPhase(Phase phase);
     void endPhase(Phase phase);
     void endParallelPhase(Phase phase, const GCParallelTask *task);
 
-    void beginSlice(const ZoneGCStats &zoneStats, JS::gcreason::Reason reason);
+    void beginSlice(const ZoneGCStats &zoneStats, JSGCInvocationKind gckind,
+                    JS::gcreason::Reason reason);
     void endSlice();
 
     void reset(const char *reason) { slices.back().resetReason = reason; }
     void nonincremental(const char *reason) { nonincrementalReason = reason; }
 
     void count(Stat s) {
         MOZ_ASSERT(s < STAT_LIMIT);
         counts[s]++;
@@ -147,16 +149,18 @@ struct Statistics
     /*
      * GCs can't really nest, but a second GC can be triggered from within the
      * JSGC_END callback.
      */
     int gcDepth;
 
     ZoneGCStats zoneStats;
 
+    JSGCInvocationKind gckind;
+
     const char *nonincrementalReason;
 
     struct SliceData {
         SliceData(JS::gcreason::Reason reason, int64_t start, size_t startFaults)
           : reason(reason), resetReason(nullptr), start(start), startFaults(startFaults)
         {
             mozilla::PodArrayZero(phaseTimes);
         }
@@ -197,17 +201,17 @@ struct Statistics
 #endif
     mozilla::DebugOnly<size_t> phaseNestingDepth;
 
     /* Sweep times for SCCs of compartments. */
     Vector<int64_t, 0, SystemAllocPolicy> sccTimes;
 
     JS::GCSliceCallback sliceCallback;
 
-    void beginGC();
+    void beginGC(JSGCInvocationKind kind);
     void endGC();
 
     void gcDuration(int64_t *total, int64_t *maxPause);
     void sccDurations(int64_t *total, int64_t *maxPause);
     void printStats();
     bool formatData(StatisticsSerializer &ss, uint64_t timestamp);
 
     UniqueChars formatDescription();
@@ -215,22 +219,23 @@ struct Statistics
     UniqueChars formatTotals();
     UniqueChars formatPhaseTimes(int64_t *phaseTimes);
 
     double computeMMU(int64_t resolution);
 };
 
 struct AutoGCSlice
 {
-    AutoGCSlice(Statistics &stats, const ZoneGCStats &zoneStats, JS::gcreason::Reason reason
+    AutoGCSlice(Statistics &stats, const ZoneGCStats &zoneStats, JSGCInvocationKind gckind,
+                JS::gcreason::Reason reason
                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : stats(stats)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-        stats.beginSlice(zoneStats, reason);
+        stats.beginSlice(zoneStats, gckind, reason);
     }
     ~AutoGCSlice() { stats.endSlice(); }
 
     Statistics &stats;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 struct AutoPhase
@@ -291,14 +296,15 @@ struct AutoSCC
     }
 
     Statistics &stats;
     unsigned scc;
     int64_t start;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
+const char *ExplainInvocationKind(JSGCInvocationKind gckind);
 const char *ExplainReason(JS::gcreason::Reason reason);
 
 } /* namespace gcstats */
 } /* namespace js */
 
 #endif /* gc_Statistics_h */
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -5979,17 +5979,17 @@ GCRuntime::collect(bool incremental, int
         return;
 #endif
 
     MOZ_ASSERT_IF(!incremental || budget != SliceBudget::Unlimited, JSGC_INCREMENTAL);
 
     AutoStopVerifyingBarriers av(rt, reason == JS::gcreason::SHUTDOWN_CC ||
                                      reason == JS::gcreason::DESTROY_RUNTIME);
 
-    gcstats::AutoGCSlice agc(stats, scanZonesBeforeGC(), reason);
+    gcstats::AutoGCSlice agc(stats, scanZonesBeforeGC(), gckind, reason);
 
     cleanUpEverything = ShouldCleanUpEverything(reason, gckind);
 
     bool repeat = false;
     do {
         /*
          * Let the API user decide to defer a GC if it wants to (unless this
          * is the last context). Invoke the callback regardless.