Bug 1159506 - Make GC events use TimeStamp. r=terrence
authorTom Tromey <tromey@mozilla.com>
Wed, 17 Jun 2015 15:14:00 -0400
changeset 267634 35091aff4234a3972cbc3b1cbe0de5f239f84cdf
parent 267633 df3415259fd58919248853d8f374838e338605fe
child 267635 53f268e9ab04ce53aa611444ccb038293a27aa1e
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-esr52@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1159506
milestone41.0a1
Bug 1159506 - Make GC events use TimeStamp. r=terrence
js/public/GCAPI.h
js/src/gc/Statistics.cpp
js/src/gc/Statistics.h
js/src/vm/Debugger.cpp
toolkit/devtools/shared/timeline.js
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -280,18 +280,18 @@ class GarbageCollectionEvent
     // Reference to a nullable, non-owned, statically allocated C string. If the
     // collection was forced to be non-incremental, this is a short reason of
     // why the GC could not perform an incremental collection.
     const char* nonincrementalReason;
 
     // Represents a single slice of a possibly multi-slice incremental garbage
     // collection.
     struct Collection {
-        int64_t startTimestamp;
-        int64_t endTimestamp;
+        double startTimestamp;
+        double endTimestamp;
     };
 
     // The set of garbage collection slices that made up this GC cycle.
     mozilla::Vector<Collection> collections;
 
     GarbageCollectionEvent(const GarbageCollectionEvent& rhs) = delete;
     GarbageCollectionEvent& operator=(const GarbageCollectionEvent& rhs) = delete;
 
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -926,17 +926,17 @@ Statistics::beginSlice(const ZoneGCStats
                        SliceBudget budget, JS::gcreason::Reason reason)
 {
     this->zoneStats = zoneStats;
 
     bool first = !runtime->gc.isIncrementalGCInProgress();
     if (first)
         beginGC(gckind);
 
-    SliceData data(budget, reason, PRMJ_Now(), GetPageFaultCount());
+    SliceData data(budget, reason, PRMJ_Now(), JS_GetCurrentEmbedderTime(), GetPageFaultCount());
     if (!slices.append(data)) {
         // OOM testing fails if we CrashAtUnhandlableOOM here.
         aborted = true;
         return;
     }
 
     runtime->addTelemetry(JS_TELEMETRY_GC_REASON, reason);
 
@@ -949,16 +949,17 @@ Statistics::beginSlice(const ZoneGCStats
     }
 }
 
 void
 Statistics::endSlice()
 {
     if (!aborted) {
         slices.back().end = PRMJ_Now();
+        slices.back().endTimestamp = JS_GetCurrentEmbedderTime();
         slices.back().endFaults = GetPageFaultCount();
 
         int64_t sliceTime = slices.back().end - slices.back().start;
         runtime->addTelemetry(JS_TELEMETRY_GC_SLICE_MS, t(sliceTime));
         runtime->addTelemetry(JS_TELEMETRY_GC_RESET, !!slices.back().resetReason);
 
         if (slices.back().budget.isTimeBudget()) {
             int64_t budget = slices.back().budget.timeBudget.budget;
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -206,29 +206,32 @@ struct Statistics
         if (phaseNestingDepth == 1)
             return phaseNesting[0] == PHASE_MUTATOR ? PHASE_NONE : phaseNesting[0];
         return phaseNesting[phaseNestingDepth - 1];
     }
 
     static const size_t MAX_NESTING = 20;
 
     struct SliceData {
-        SliceData(SliceBudget budget, JS::gcreason::Reason reason, int64_t start, size_t startFaults)
+        SliceData(SliceBudget budget, JS::gcreason::Reason reason, int64_t start,
+                  double startTimestamp, size_t startFaults)
           : budget(budget), reason(reason),
             resetReason(nullptr),
-            start(start), startFaults(startFaults)
+            start(start), startTimestamp(startTimestamp),
+            startFaults(startFaults)
         {
             for (auto i : mozilla::MakeRange(NumTimingArrays))
                 mozilla::PodArrayZero(phaseTimes[i]);
         }
 
         SliceBudget budget;
         JS::gcreason::Reason reason;
         const char* resetReason;
         int64_t start, end;
+        double startTimestamp, endTimestamp;
         size_t startFaults, endFaults;
         PhaseTimeTable phaseTimes;
 
         int64_t duration() const { return end - start; }
     };
 
     typedef Vector<SliceData, 8, SystemAllocPolicy> SliceDataVector;
     typedef SliceDataVector::ConstRange SliceRange;
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -8051,18 +8051,18 @@ GarbageCollectionEvent::Create(JSRuntime
             // same.
             data->reason = gcstats::ExplainReason(range.front().reason);
             MOZ_ASSERT(data->reason);
         }
 
         if (!data->collections.growBy(1))
             return nullptr;
 
-        data->collections.back().startTimestamp = range.front().start;
-        data->collections.back().endTimestamp = range.front().end;
+        data->collections.back().startTimestamp = range.front().startTimestamp;
+        data->collections.back().endTimestamp = range.front().endTimestamp;
     }
 
 
     return data;
 }
 
 static bool
 DefineStringProperty(JSContext* cx, HandleObject obj, PropertyName* propName, const char* strVal)
--- a/toolkit/devtools/shared/timeline.js
+++ b/toolkit/devtools/shared/timeline.js
@@ -177,19 +177,16 @@ let Timeline = exports.Timeline = Class(
    *         will be created regardless (to hook into GC events), but this determines
    *         whether or not a `memory` event gets fired.
    * @option {boolean} withTicks
    *         Boolean indicating whether a `ticks` event is fired and a FramerateActor
    *         is created.
    */
   start: Task.async(function *({ withMemory, withTicks }) {
     let startTime = this._startTime = this.docShells[0].now();
-    // Store the start time from unix epoch so we can normalize
-    // markers from the memory actor
-    this._unixStartTime = Date.now();
 
     if (this._isRecording) {
       return startTime;
     }
 
     this._isRecording = true;
     this._stackFrames = new StackFrameCache();
     this._stackFrames.initFrames();
@@ -261,25 +258,22 @@ let Timeline = exports.Timeline = Class(
    * why there was a GC, and may contain a `nonincrementalReason` when SpiderMonkey could
    * not incrementally collect garbage.
    */
   _onGarbageCollection: function ({ collections, reason, nonincrementalReason }) {
     if (!this._isRecording || !this.docShells.length) {
       return;
     }
 
-    // Normalize the start time to docshell start time, and convert it
-    // to microseconds.
-    let startTime = (this._unixStartTime - this._startTime) * 1000;
     let endTime = this.docShells[0].now();
 
     events.emit(this, "markers", collections.map(({ startTimestamp: start, endTimestamp: end }) => {
       return {
         name: "GarbageCollection",
         causeName: reason,
         nonincrementalReason: nonincrementalReason,
         // Both timestamps are in microseconds -- convert to milliseconds to match other markers
-        start: (start - startTime) / 1000,
-        end: (end - startTime) / 1000
+        start: start,
+        end: end
       };
     }), endTime);
   },
 });