Bug 1475896 - Add telemetry for GC marking rate. r=jonco, data-review=chutten
authorYoshi Cheng-Hao Huang <allstars.chh@gmail.com>
Mon, 19 Nov 2018 16:06:08 +0100
changeset 450676 9670d2fdc1660e6c43ce0e6adb0cc0aba1461d8a
parent 450675 ca19ff7f1891dd8a29300d145747d77d6efdd505
child 450677 466d0030af6d5528864fa88ff1a733f77a65d867
push id110518
push userallstars.chh@gmail.com
push dateFri, 14 Dec 2018 16:11:00 +0000
treeherdermozilla-inbound@9670d2fdc166 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1475896
milestone66.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 1475896 - Add telemetry for GC marking rate. r=jonco, data-review=chutten
js/src/gc/GC.cpp
js/src/gc/GCMarker.h
js/src/gc/Marking.cpp
js/src/gc/Statistics.cpp
js/src/jsfriendapi.h
js/xpconnect/src/XPCJSRuntime.cpp
toolkit/components/telemetry/Histograms.json
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -4261,16 +4261,17 @@ bool GCRuntime::beginMarkPhase(JS::gcrea
    * arenaAllocatedDuringGC().
    */
   for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
     zone->arenas.clearFreeLists();
   }
 
   marker.start();
   GCMarker* gcmarker = &marker;
+  gcmarker->clearMarkCount();
 
   {
     gcstats::AutoPhase ap1(stats(), gcstats::PhaseKind::PREPARE);
     AutoLockHelperThreadState helperLock;
 
     /*
      * Clear all mark state for the zones we are collecting. This is linear
      * in the size of the heap we are collecting and so can be slow. Do this
--- a/js/src/gc/GCMarker.h
+++ b/js/src/gc/GCMarker.h
@@ -310,16 +310,19 @@ class GCMarker : public JSTracer {
   size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
 #ifdef DEBUG
   bool shouldCheckCompartments() { return strictCompartmentChecking; }
 #endif
 
   void markEphemeronValues(gc::Cell* markedCell, gc::WeakEntryVector& entry);
 
+  size_t getMarkCount() const { return markCount; }
+  void clearMarkCount() { markCount = 0; }
+
   static GCMarker* fromTracer(JSTracer* trc) {
     MOZ_ASSERT(trc->isMarkingTracer());
     return static_cast<GCMarker*>(trc);
   }
 
  private:
 #ifdef DEBUG
   void checkZone(void* p);
@@ -394,16 +397,19 @@ class GCMarker : public JSTracer {
   MainThreadData<js::gc::Arena*> unmarkedArenaStackTop;
 
   /*
    * If the weakKeys table OOMs, disable the linear algorithm and fall back
    * to iterating until the next GC.
    */
   MainThreadData<bool> linearWeakMarkingDisabled_;
 
+  /* The count of marked objects during GC. */
+  size_t markCount;
+
 #ifdef DEBUG
   /* Count of arenas that are currently in the stack. */
   MainThreadData<size_t> markLaterArenas;
 
   /* Assert that start and stop are called with correct ordering. */
   MainThreadData<bool> started;
 
   /*
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -966,21 +966,20 @@ static bool TraceKindParticipatesInCC(JS
 template <typename T>
 bool js::GCMarker::mark(T* thing) {
   if (IsInsideNursery(thing)) {
     return false;
   }
   AssertShouldMarkInZone(thing);
   TenuredCell* cell = TenuredCell::fromPointer(thing);
 
-  if (!TypeParticipatesInCC<T>::value) {
-    return cell->markIfUnmarked(MarkColor::Black);
-  }
-
-  return cell->markIfUnmarked(markColor());
+  MarkColor color = TypeParticipatesInCC<T>::value ? markColor()
+                                                   : MarkColor::Black;
+  markCount++;
+  return cell->markIfUnmarked(color);
 }
 
 /*** Inline, Eager GC Marking ***********************************************/
 
 // Each of the eager, inline marking paths is directly preceeded by the
 // out-of-line, generic tracing code for comparison. Both paths must end up
 // traversing equivalent subgraphs.
 
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -976,17 +976,21 @@ void Statistics::beginGC(JSGCInvocationK
 void Statistics::endGC() {
   TimeDuration sccTotal, sccLongest;
   sccDurations(&sccTotal, &sccLongest);
 
   runtime->addTelemetry(JS_TELEMETRY_GC_IS_ZONE_GC,
                         !zoneStats.isFullCollection());
   TimeDuration markTotal = SumPhase(PhaseKind::MARK, phaseTimes);
   TimeDuration markRootsTotal = SumPhase(PhaseKind::MARK_ROOTS, phaseTimes);
-  runtime->addTelemetry(JS_TELEMETRY_GC_MARK_MS, t(markTotal));
+  double markTime = t(markTotal);
+  size_t markCount = runtime->gc.marker.getMarkCount();
+  double markRate = markCount / markTime;
+  runtime->addTelemetry(JS_TELEMETRY_GC_MARK_MS, markTime);
+  runtime->addTelemetry(JS_TELEMETRY_GC_MARK_RATE, markRate);
   runtime->addTelemetry(JS_TELEMETRY_GC_SWEEP_MS, t(phaseTimes[Phase::SWEEP]));
   if (runtime->gc.isCompactingGc()) {
     runtime->addTelemetry(JS_TELEMETRY_GC_COMPACT_MS,
                           t(phaseTimes[Phase::COMPACT]));
   }
   runtime->addTelemetry(JS_TELEMETRY_GC_MARK_ROOTS_MS, t(markRootsTotal));
   runtime->addTelemetry(JS_TELEMETRY_GC_MARK_GRAY_MS,
                         t(phaseTimes[Phase::SWEEP_MARK_GRAY]));
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -146,16 +146,17 @@ enum {
   JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS,
   JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS,
   JS_TELEMETRY_GC_MINOR_REASON,
   JS_TELEMETRY_GC_MINOR_REASON_LONG,
   JS_TELEMETRY_GC_MINOR_US,
   JS_TELEMETRY_GC_NURSERY_BYTES,
   JS_TELEMETRY_GC_PRETENURE_COUNT,
   JS_TELEMETRY_GC_NURSERY_PROMOTION_RATE,
+  JS_TELEMETRY_GC_MARK_RATE,
   JS_TELEMETRY_PRIVILEGED_PARSER_COMPILE_LAZY_AFTER_MS,
   JS_TELEMETRY_WEB_PARSER_COMPILE_LAZY_AFTER_MS,
   JS_TELEMETRY_END
 };
 
 typedef void (*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample,
                                                   const char* key);
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2643,16 +2643,19 @@ static void AccumulateTelemetryCallback(
       break;
     case JS_TELEMETRY_WEB_PARSER_COMPILE_LAZY_AFTER_MS:
       Telemetry::Accumulate(Telemetry::JS_WEB_PARSER_COMPILE_LAZY_AFTER_MS,
                             sample);
       break;
     case JS_TELEMETRY_GC_NURSERY_PROMOTION_RATE:
       Telemetry::Accumulate(Telemetry::GC_NURSERY_PROMOTION_RATE, sample);
       break;
+    case JS_TELEMETRY_GC_MARK_RATE:
+      Telemetry::Accumulate(Telemetry::GC_MARK_RATE, sample);
+      break;
     default:
       MOZ_ASSERT_UNREACHABLE("Unexpected JS_TELEMETRY id");
   }
 }
 
 static void SetUseCounterCallback(JSObject* obj, JSUseCounter counter) {
   switch (counter) {
     case JSUseCounter::ASMJS:
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -865,16 +865,27 @@
     "alert_emails": ["dev-telemetry-gc-alerts@mozilla.org", "jcoppeard@mozilla.com"],
     "expires_in_version": "never",
     "kind": "linear",
     "high": 100,
     "n_buckets": 50,
     "bug_numbers": [1485299],
     "description": "The percentage of nursery objects that were promoted to tenured heap."
   },
+  "GC_MARK_RATE": {
+    "record_in_processes": ["main", "content"],
+    "alert_emails": ["dev-telemetry-gc-alerts@mozilla.org", "jcoppeard@mozilla.com"],
+    "expires_in_version": "never",
+    "kind": "linear",
+    "low": 1000,
+    "high": 1000000,
+    "n_buckets": 100,
+    "bug_numbers": [1475896],
+    "description": "The number of objects marked per ms during GC."
+  },
   "GEOLOCATION_ACCURACY_EXPONENTIAL": {
     "record_in_processes": ["main", "content"],
     "expires_in_version": "never",
     "kind": "exponential",
     "releaseChannelCollection": "opt-out",
     "bug_numbers": [1507925],
     "high": 100000,
     "n_buckets": 50,