Bug 1322560 - Inject detailed GC timing info into profiles, r=mstange
☠☠ backed out by f36cff1ee55f ☠ ☠
authorSteve Fink <sfink@mozilla.com>
Thu, 27 Apr 2017 20:52:15 -0700
changeset 355584 5fe280e53d4f474f5f16ff834e0b9cf55745d746
parent 355583 4dee851a0d45655260ace1c01eb4dd9e9905942f
child 355585 3b458dc06af44ee788cb86dee6611b66ce0ebe5b
push id89703
push usersfink@mozilla.com
push dateFri, 28 Apr 2017 18:04:28 +0000
treeherdermozilla-inbound@2cd1662bcc5b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1322560
milestone55.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 1322560 - Inject detailed GC timing info into profiles, r=mstange
tools/profiler/core/ProfileJSONWriter.h
tools/profiler/core/ProfilerMarkers.cpp
tools/profiler/public/ProfilerMarkers.h
xpcom/base/CycleCollectedJSContext.cpp
xpcom/base/CycleCollectedJSRuntime.cpp
--- a/tools/profiler/core/ProfileJSONWriter.h
+++ b/tools/profiler/core/ProfileJSONWriter.h
@@ -97,16 +97,23 @@ public:
     for (uint32_t i = 0; i < aCount; i++) {
       NullElement();
     }
   }
 
   void Splice(const ChunkedJSONWriteFunc* aFunc);
   void Splice(const char* aStr);
 
+  // Splice the given JSON directly in, without quoting.
+  void SplicedJSONProperty(const char* aMaybePropertyName,
+                           const char* aJsonValue)
+  {
+    Scalar(aMaybePropertyName, aJsonValue);
+  }
+
   // Takes the chunks from aFunc and write them. If move is not possible
   // (e.g., using OStreamJSONWriteFunc), aFunc's chunks are copied and its
   // storage cleared.
   virtual void TakeAndSplice(ChunkedJSONWriteFunc* aFunc);
 };
 
 class SpliceableChunkedJSONWriter : public SpliceableJSONWriter
 {
--- a/tools/profiler/core/ProfilerMarkers.cpp
+++ b/tools/profiler/core/ProfilerMarkers.cpp
@@ -265,8 +265,36 @@ void
 VsyncPayload::StreamPayload(SpliceableJSONWriter& aWriter,
                             const TimeStamp& aStartTime,
                             UniqueStacks& aUniqueStacks)
 {
   aWriter.DoubleProperty("vsync",
                          (mVsyncTimestamp - aStartTime).ToMilliseconds());
   aWriter.StringProperty("category", "VsyncTimestamp");
 }
+
+void
+GCSliceMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
+                                    const mozilla::TimeStamp& aStartTime,
+                                    UniqueStacks& aUniqueStacks)
+{
+  MOZ_ASSERT(mTimingJSON);
+  streamCommonProps("GCSlice", aWriter, aStartTime, aUniqueStacks);
+  if (mTimingJSON) {
+    aWriter.SplicedJSONProperty("timings", mTimingJSON.get());
+  } else {
+    aWriter.NullProperty("timings");
+  }
+}
+
+void
+GCMajorMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
+                                    const mozilla::TimeStamp& aStartTime,
+                                    UniqueStacks& aUniqueStacks)
+{
+  MOZ_ASSERT(mTimingJSON);
+  streamCommonProps("GCMajor", aWriter, aStartTime, aUniqueStacks);
+  if (mTimingJSON) {
+    aWriter.SplicedJSONProperty("timings", mTimingJSON.get());
+  } else {
+    aWriter.NullProperty("timings");
+  }
+}
--- a/tools/profiler/public/ProfilerMarkers.h
+++ b/tools/profiler/public/ProfilerMarkers.h
@@ -6,16 +6,17 @@
 #ifndef PROFILER_MARKERS_H
 #define PROFILER_MARKERS_H
 
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Attributes.h"
 
 #include "GeckoProfiler.h"
 
+#include "js/Utility.h"
 #include "gfxASurface.h"
 
 namespace mozilla {
 namespace layers {
 class Layer;
 } // namespace layers
 } // namespace mozilla
 
@@ -230,9 +231,49 @@ public:
 
 private:
   mozilla::TimeStamp mCpuTimeStart;
   mozilla::TimeStamp mCpuTimeEnd;
   uint64_t mGpuTimeStart;
   uint64_t mGpuTimeEnd;
 };
 
+class GCSliceMarkerPayload : public ProfilerMarkerPayload
+{
+public:
+  GCSliceMarkerPayload(const mozilla::TimeStamp& aStartTime,
+                       const mozilla::TimeStamp& aEndTime,
+                       JS::UniqueChars&& aTimingJSON)
+   : ProfilerMarkerPayload(aStartTime, aEndTime, nullptr),
+     mTimingJSON(mozilla::Move(aTimingJSON))
+  {}
+
+  virtual ~GCSliceMarkerPayload() {}
+
+  void StreamPayload(SpliceableJSONWriter& aWriter,
+                     const mozilla::TimeStamp& aStartTime,
+                     UniqueStacks& aUniqueStacks) override;
+
+private:
+  JS::UniqueChars mTimingJSON;
+};
+
+class GCMajorMarkerPayload : public ProfilerMarkerPayload
+{
+public:
+  GCMajorMarkerPayload(const mozilla::TimeStamp& aStartTime,
+                       const mozilla::TimeStamp& aEndTime,
+                       JS::UniqueChars&& aTimingJSON)
+   : ProfilerMarkerPayload(aStartTime, aEndTime, nullptr),
+     mTimingJSON(mozilla::Move(aTimingJSON))
+  {}
+
+  virtual ~GCMajorMarkerPayload() {}
+
+  void StreamPayload(SpliceableJSONWriter& aWriter,
+                     const mozilla::TimeStamp& aStartTime,
+                     UniqueStacks& aUniqueStacks) override;
+
+private:
+  JS::UniqueChars mTimingJSON;
+};
+
 #endif // PROFILER_MARKERS_H
--- a/xpcom/base/CycleCollectedJSContext.cpp
+++ b/xpcom/base/CycleCollectedJSContext.cpp
@@ -21,16 +21,17 @@
 #include "mozilla/dom/ProfileTimelineMarkerBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseBinding.h"
 #include "mozilla/dom/PromiseDebugging.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "jsprf.h"
 #include "js/Debug.h"
 #include "js/GCAPI.h"
+#include "js/Utility.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollectionNoteRootCallback.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCycleCollector.h"
 #include "nsDOMJSUtils.h"
 #include "nsJSUtils.h"
 #include "nsWrapperCache.h"
 #include "nsStringBuffer.h"
@@ -40,16 +41,20 @@
 #endif
 
 #include "nsIException.h"
 #include "nsIPlatformInfo.h"
 #include "nsThread.h"
 #include "nsThreadUtils.h"
 #include "xpcpublic.h"
 
+#ifdef MOZ_GECKO_PROFILER
+#include "ProfilerMarkers.h"
+#endif
+
 using namespace mozilla;
 using namespace mozilla::dom;
 
 namespace mozilla {
 
 CycleCollectedJSContext::CycleCollectedJSContext()
   : mIsPrimaryContext(true)
   , mRuntime(nullptr)
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -823,16 +823,30 @@ CycleCollectedJSRuntime::GCCallback(JSCo
 /* static */ void
 CycleCollectedJSRuntime::GCSliceCallback(JSContext* aContext,
                                          JS::GCProgress aProgress,
                                          const JS::GCDescription& aDesc)
 {
   CycleCollectedJSRuntime* self = CycleCollectedJSRuntime::Get();
   MOZ_ASSERT(CycleCollectedJSContext::Get()->Context() == aContext);
 
+#ifdef MOZ_GECKO_PROFILER
+  if (aProgress == JS::GC_CYCLE_END) {
+    auto payload = new GCSliceMarkerPayload(aDesc.lastSliceStart(aContext),
+                                            aDesc.lastSliceEnd(aContext),
+                                            aDesc.sliceToJSON(aContext));
+    PROFILER_MARKER_PAYLOAD("GCSlice", payload);
+  } else if (aProgress == JS::GC_SLICE_END) {
+    auto payload = new GCMajorMarkerPayload(aDesc.startTime(aContext),
+                                            aDesc.endTime(aContext),
+                                            aDesc.summaryToJSON(aContext));
+    PROFILER_MARKER_PAYLOAD("GCMajor", payload);
+  }
+#endif
+
   if (aProgress == JS::GC_CYCLE_END) {
     JS::gcreason::Reason reason = aDesc.reason_;
     Unused <<
       NS_WARN_IF(NS_FAILED(DebuggerOnGCRunnable::Enqueue(aContext, aDesc)) &&
                  reason != JS::gcreason::SHUTDOWN_CC &&
                  reason != JS::gcreason::DESTROY_RUNTIME &&
                  reason != JS::gcreason::XPCONNECT_SHUTDOWN);
   }