Bug 1128768: Part 4 - Update telemetry to serialize BHR hang annotations; r=gfritzsche
authorAaron Klotz <aklotz@mozilla.com>
Mon, 09 Mar 2015 16:34:42 -0600
changeset 232675 2f0b44330ffb6aca66f4caa0f6ea38cbd5b15f6a
parent 232674 c3501a329f69bad4ab9f90bc827c69758f1a5d49
child 232676 0df0abc0f58c00de5997ae89225006a5d47da593
push id28390
push usercbook@mozilla.com
push dateTue, 10 Mar 2015 12:54:55 +0000
treeherdermozilla-central@c42e7e3bb0a0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgfritzsche
bugs1128768
milestone39.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 1128768: Part 4 - Update telemetry to serialize BHR hang annotations; r=gfritzsche
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/ThreadHangStats.h
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -238,43 +238,43 @@ CombinedStacks::SizeOfExcludingThis() co
 class HangReports {
 public:
   /**
    * This struct encapsulates information for an individual ChromeHang annotation.
    * mHangIndex is the index of the corresponding ChromeHang.
    */
   struct AnnotationInfo {
     AnnotationInfo(uint32_t aHangIndex,
-                   UniquePtr<HangAnnotations> aAnnotations)
+                   HangAnnotationsPtr aAnnotations)
       : mHangIndex(aHangIndex)
       , mAnnotations(Move(aAnnotations))
     {}
     AnnotationInfo(AnnotationInfo&& aOther)
       : mHangIndex(aOther.mHangIndex)
       , mAnnotations(Move(aOther.mAnnotations))
     {}
     ~AnnotationInfo() {}
     AnnotationInfo& operator=(AnnotationInfo&& aOther)
     {
       mHangIndex = aOther.mHangIndex;
       mAnnotations = Move(aOther.mAnnotations);
       return *this;
     }
     uint32_t mHangIndex;
-    UniquePtr<HangAnnotations> mAnnotations;
+    HangAnnotationsPtr mAnnotations;
 
   private:
     // Force move constructor
     AnnotationInfo(const AnnotationInfo& aOther) = delete;
     void operator=(const AnnotationInfo& aOther) = delete;
   };
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   void AddHang(const Telemetry::ProcessedStack& aStack, uint32_t aDuration,
                int32_t aSystemUptime, int32_t aFirefoxUptime,
-               UniquePtr<HangAnnotations> aAnnotations);
+               HangAnnotationsPtr aAnnotations);
   uint32_t GetDuration(unsigned aIndex) const;
   int32_t GetSystemUptime(unsigned aIndex) const;
   int32_t GetFirefoxUptime(unsigned aIndex) const;
   const nsTArray<AnnotationInfo>& GetAnnotationInfo() const;
   const CombinedStacks& GetStacks() const;
 private:
   /**
    * This struct encapsulates the data for an individual ChromeHang, excluding
@@ -293,17 +293,17 @@ private:
   CombinedStacks mStacks;
 };
 
 void
 HangReports::AddHang(const Telemetry::ProcessedStack& aStack,
                      uint32_t aDuration,
                      int32_t aSystemUptime,
                      int32_t aFirefoxUptime,
-                     UniquePtr<HangAnnotations> aAnnotations) {
+                     HangAnnotationsPtr aAnnotations) {
   HangInfo info = { aDuration, aSystemUptime, aFirefoxUptime };
   mHangInfo.push_back(info);
   if (aAnnotations) {
     AnnotationInfo ainfo(static_cast<uint32_t>(mHangInfo.size() - 1),
                          Move(aAnnotations));
     mAnnotationInfo.AppendElement(Move(ainfo));
   }
   mStacks.AddStack(aStack);
@@ -653,17 +653,17 @@ public:
   static void ShutdownTelemetry();
   static void RecordSlowStatement(const nsACString &sql, const nsACString &dbName,
                                   uint32_t delay);
 #if defined(MOZ_ENABLE_PROFILER_SPS)
   static void RecordChromeHang(uint32_t aDuration,
                                Telemetry::ProcessedStack &aStack,
                                int32_t aSystemUptime,
                                int32_t aFirefoxUptime,
-                               UniquePtr<HangAnnotations> aAnnotations);
+                               HangAnnotationsPtr aAnnotations);
 #endif
   static void RecordThreadHangStats(Telemetry::ThreadHangStats& aStats);
   static nsresult GetHistogramEnumId(const char *name, Telemetry::ID *id);
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
   struct Stat {
     uint32_t hitCount;
     uint32_t totalTime;
   };
@@ -2835,30 +2835,73 @@ CreateJSHangStack(JSContext* cx, const T
     if (!JS_DefineElement(cx, ret, i, string, JSPROP_ENUMERATE)) {
       return nullptr;
     }
   }
   return ret;
 }
 
 static JSObject*
+CreateJSHangAnnotations(JSContext* cx, const HangAnnotationsVector& annotations)
+{
+  JS::RootedObject annotationsArray(cx, JS_NewArrayObject(cx, 0));
+  if (!annotationsArray) {
+    return nullptr;
+  }
+  size_t annotationIndex = 0;
+  for (const HangAnnotationsPtr *i = annotations.begin(), *e = annotations.end();
+       i != e; ++i) {
+    JS::RootedObject jsAnnotation(cx, JS_NewPlainObject(cx));
+    if (!jsAnnotation) {
+      continue;
+    }
+    const HangAnnotationsPtr& curAnnotations = *i;
+    UniquePtr<HangAnnotations::Enumerator> annotationsEnum =
+      curAnnotations->GetEnumerator();
+    if (!annotationsEnum) {
+      continue;
+    }
+    nsAutoString key;
+    nsAutoString value;
+    while (annotationsEnum->Next(key, value)) {
+      JS::RootedValue jsValue(cx);
+      jsValue.setString(JS_NewUCStringCopyN(cx, value.get(), value.Length()));
+      if (!JS_DefineUCProperty(cx, jsAnnotation, key.get(), key.Length(),
+                               jsValue, JSPROP_ENUMERATE)) {
+        return nullptr;
+      }
+    }
+    if (!JS_SetElement(cx, annotationsArray, annotationIndex, jsAnnotation)) {
+      continue;
+    }
+    ++annotationIndex;
+  }
+  return annotationsArray;
+}
+
+static JSObject*
 CreateJSHangHistogram(JSContext* cx, const Telemetry::HangHistogram& hang)
 {
   JS::RootedObject ret(cx, JS_NewPlainObject(cx));
   if (!ret) {
     return nullptr;
   }
 
   JS::RootedObject stack(cx, CreateJSHangStack(cx, hang.GetStack()));
   JS::RootedObject time(cx, CreateJSTimeHistogram(cx, hang));
+  auto& hangAnnotations = hang.GetAnnotations();
+  JS::RootedObject annotations(cx, CreateJSHangAnnotations(cx, hangAnnotations));
 
   if (!stack ||
       !time ||
+      !annotations ||
       !JS_DefineProperty(cx, ret, "stack", stack, JSPROP_ENUMERATE) ||
-      !JS_DefineProperty(cx, ret, "histogram", time, JSPROP_ENUMERATE)) {
+      !JS_DefineProperty(cx, ret, "histogram", time, JSPROP_ENUMERATE) ||
+      (!hangAnnotations.empty() && // <-- Only define annotations when nonempty
+        !JS_DefineProperty(cx, ret, "annotations", annotations, JSPROP_ENUMERATE))) {
     return nullptr;
   }
 
   if (!hang.GetNativeStack().empty()) {
     JS::RootedObject native(cx, CreateJSHangStack(cx, hang.GetNativeStack()));
     if (!native ||
         !JS_DefineProperty(cx, ret, "nativeStack", native, JSPROP_ENUMERATE)) {
       return nullptr;
@@ -2894,16 +2937,17 @@ CreateJSThreadHangStats(JSContext* cx, c
     JS::RootedObject obj(cx, CreateJSHangHistogram(cx, thread.mHangs[i]));
     if (!JS_DefineElement(cx, hangs, i, obj, JSPROP_ENUMERATE)) {
       return nullptr;
     }
   }
   if (!JS_DefineProperty(cx, ret, "hangs", hangs, JSPROP_ENUMERATE)) {
     return nullptr;
   }
+
   return ret;
 }
 
 NS_IMETHODIMP
 TelemetryImpl::GetThreadHangStats(JSContext* cx, JS::MutableHandle<JS::Value> ret)
 {
   JS::RootedObject retObj(cx, JS_NewArrayObject(cx, 0));
   if (!retObj) {
@@ -3329,22 +3373,22 @@ TelemetryImpl::RecordSlowStatement(const
 }
 
 #if defined(MOZ_ENABLE_PROFILER_SPS)
 void
 TelemetryImpl::RecordChromeHang(uint32_t aDuration,
                                 Telemetry::ProcessedStack &aStack,
                                 int32_t aSystemUptime,
                                 int32_t aFirefoxUptime,
-                                UniquePtr<HangAnnotations> aAnnotations)
+                                HangAnnotationsPtr aAnnotations)
 {
   if (!sTelemetry || !sTelemetry->mCanRecord)
     return;
 
-  UniquePtr<HangAnnotations> annotations;
+  HangAnnotationsPtr annotations;
   // We only pass aAnnotations if it is not empty.
   if (aAnnotations && !aAnnotations->IsEmpty()) {
     annotations = Move(aAnnotations);
   }
 
   MutexAutoLock hangReportMutex(sTelemetry->mHangReportsMutex);
 
   sTelemetry->mHangReports.AddHang(aStack, aDuration,
@@ -3603,17 +3647,17 @@ void Init()
   MOZ_ASSERT(telemetryService);
 }
 
 #if defined(MOZ_ENABLE_PROFILER_SPS)
 void RecordChromeHang(uint32_t duration,
                       ProcessedStack &aStack,
                       int32_t aSystemUptime,
                       int32_t aFirefoxUptime,
-                      UniquePtr<HangAnnotations> aAnnotations)
+                      HangAnnotationsPtr aAnnotations)
 {
   TelemetryImpl::RecordChromeHang(duration, aStack,
                                   aSystemUptime, aFirefoxUptime,
                                   Move(aAnnotations));
 }
 #endif
 
 void RecordThreadHangStats(ThreadHangStats& aStats)
--- a/toolkit/components/telemetry/ThreadHangStats.h
+++ b/toolkit/components/telemetry/ThreadHangStats.h
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_BackgroundHangTelemetry_h
 #define mozilla_BackgroundHangTelemetry_h
 
 #include "mozilla/Array.h"
 #include "mozilla/Assertions.h"
+#include "mozilla/HangAnnotations.h"
 #include "mozilla/Move.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/Vector.h"
 
 #include "nsString.h"
 #include "prinrval.h"
 
@@ -114,50 +115,64 @@ class HangHistogram : public TimeHistogr
 private:
   static uint32_t GetHash(const HangStack& aStack);
 
   HangStack mStack;
   // Native stack that corresponds to the pseudostack in mStack
   HangStack mNativeStack;
   // Use a hash to speed comparisons
   const uint32_t mHash;
+  // Annotations attributed to this stack
+  HangMonitor::HangAnnotationsVector mAnnotations;
 
 public:
   explicit HangHistogram(HangStack&& aStack)
     : mStack(mozilla::Move(aStack))
     , mHash(GetHash(mStack))
   {
   }
   HangHistogram(HangHistogram&& aOther)
     : TimeHistogram(mozilla::Move(aOther))
     , mStack(mozilla::Move(aOther.mStack))
     , mNativeStack(mozilla::Move(aOther.mNativeStack))
     , mHash(mozilla::Move(aOther.mHash))
+    , mAnnotations(mozilla::Move(aOther.mAnnotations))
   {
   }
   bool operator==(const HangHistogram& aOther) const;
   bool operator!=(const HangHistogram& aOther) const
   {
     return !operator==(aOther);
   }
   const HangStack& GetStack() const {
     return mStack;
   }
   HangStack& GetNativeStack() {
     return mNativeStack;
   }
   const HangStack& GetNativeStack() const {
     return mNativeStack;
   }
+  const HangMonitor::HangAnnotationsVector& GetAnnotations() const {
+    return mAnnotations;
+  }
+  void Add(PRIntervalTime aTime, HangMonitor::HangAnnotationsPtr aAnnotations) {
+    TimeHistogram::Add(aTime);
+    if (aAnnotations) {
+      mAnnotations.append(Move(aAnnotations));
+    }
+  }
 };
 
 /* Thread hang stats consist of
  - thread name
  - time histogram of all task run times
- - hang histograms of individual hangs. */
+ - hang histograms of individual hangs
+ - annotations for each hang
+*/
 class ThreadHangStats
 {
 private:
   nsAutoCString mName;
 
 public:
   TimeHistogram mActivity;
   mozilla::Vector<HangHistogram, 4> mHangs;