Bug 932865 - Add ThreadHangStats for collecting background hang telemetry; r=vladan
authorJim Chen <nchen@mozilla.com>
Fri, 22 Nov 2013 14:17:30 -0500
changeset 157077 eae56986faba12e48c928da9dc7b3147c242c271
parent 157076 1cd4e62f97c11f33d7b5905ae208ede1be82d15a
child 157078 18ba8691786d4ce7ccde7ecd00f33ccb633f49dc
push id36633
push usernchen@mozilla.com
push dateFri, 22 Nov 2013 19:20:41 +0000
treeherdermozilla-inbound@5365478bdea9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvladan
bugs932865
milestone28.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 932865 - Add ThreadHangStats for collecting background hang telemetry; r=vladan
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/ThreadHangStats.h
toolkit/components/telemetry/moz.build
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -8,16 +8,17 @@
 
 #include <fstream>
 
 #include <prio.h>
 
 #include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Likely.h"
+#include "mozilla/MathAlgorithms.h"
 
 #include "base/histogram.h"
 #include "base/pickle.h"
 #include "nsIComponentManager.h"
 #include "nsIServiceManager.h"
 #include "nsThreadManager.h"
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
@@ -2434,16 +2435,51 @@ WriteFailedProfileLock(nsIFile* aProfile
       break;
     }
     bytes += written;
     bytesLeft -= written;
   } while (bytesLeft > 0);
   seekStream->SetEOF();
 }
 
+
+void
+TimeHistogram::Add(PRIntervalTime aTime)
+{
+  uint32_t timeMs = PR_IntervalToMilliseconds(aTime);
+  size_t index = mozilla::FloorLog2(timeMs);
+  operator[](index)++;
+}
+
+uint32_t
+HangHistogram::GetHash(const Stack& aStack)
+{
+  uint32_t hash = 0;
+  for (const char* const* label = aStack.begin();
+       label != aStack.end(); label++) {
+    /* We only need to hash the pointer instead of the text content
+       because we are assuming constant pointers */
+    hash = AddToHash(hash, *label);
+  }
+  return hash;
+}
+
+bool
+HangHistogram::operator==(const HangHistogram& aOther) const
+{
+  if (mHash != aOther.mHash) {
+    return false;
+  }
+  if (mStack.length() != aOther.mStack.length()) {
+    return false;
+  }
+  return PodEqual(mStack.begin(), aOther.mStack.begin(), mStack.length());
+}
+
+
 } // namespace Telemetry
 } // namespace mozilla
 
 NSMODULE_DEFN(nsTelemetryModule) = &kTelemetryModule;
 
 /**
  * The XRE_TelemetryAdd function is to be used by embedding applications
  * that can't use mozilla::Telemetry::Accumulate() directly.
new file mode 100644
--- /dev/null
+++ b/toolkit/components/telemetry/ThreadHangStats.h
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/Move.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/PodOperations.h"
+#include "mozilla/Vector.h"
+
+#include "nsString.h"
+#include "prinrval.h"
+
+namespace mozilla {
+namespace Telemetry {
+
+static const size_t kTimeHistogramBuckets = 8 * sizeof(PRIntervalTime);
+
+/* TimeHistogram is an efficient histogram that puts time durations into
+   exponential (base 2) buckets; times are accepted in PRIntervalTime and
+   stored in milliseconds. */
+class TimeHistogram : public mozilla::Array<uint32_t, kTimeHistogramBuckets>
+{
+public:
+  TimeHistogram()
+  {
+    mozilla::PodArrayZero(*this);
+  }
+  void Add(PRIntervalTime aTime);
+};
+
+/* A hang histogram consists of a stack associated with the
+   hang, along with a time histogram of the hang times. */
+class HangHistogram : public TimeHistogram
+{
+public:
+  typedef mozilla::Vector<const char*, 8> Stack;
+
+private:
+  static uint32_t GetHash(const Stack& aStack);
+
+  Stack mStack;
+  // Use a hash to speed comparisons
+  const uint32_t mHash;
+
+public:
+  explicit HangHistogram(Stack&& aStack)
+    : mStack(mozilla::Move(aStack))
+    , mHash(GetHash(mStack))
+  {
+  }
+  HangHistogram(HangHistogram&& aOther)
+    : TimeHistogram(mozilla::Move(aOther))
+    , mStack(mozilla::Move(aOther.mStack))
+    , mHash(mozilla::Move(aOther.mHash))
+  {
+  }
+  bool operator==(const HangHistogram& aOther) const;
+  bool operator!=(const HangHistogram& aOther) const
+  {
+    return !operator==(aOther);
+  }
+  const Stack& GetStack() const {
+    return mStack;
+  }
+};
+
+/* Thread hang stats consist of
+ - thread name
+ - time histogram of all task run times
+ - hang histograms of individual hangs. */
+class ThreadHangStats
+{
+private:
+  nsAutoCString mName;
+
+public:
+  TimeHistogram mActivity;
+  mozilla::Vector<HangHistogram, 4> mHangs;
+
+  explicit ThreadHangStats(const char* aName)
+    : mName(aName)
+  {
+  }
+  ThreadHangStats(ThreadHangStats&& aOther)
+    : mName(mozilla::Move(aOther.mName))
+    , mActivity(mozilla::Move(aOther.mActivity))
+    , mHangs(mozilla::Move(aOther.mHangs))
+  {
+  }
+  const char* GetName() const {
+    return mName.get();
+  }
+};
+
+} // namespace Telemetry
+} // namespace mozilla
+#endif // mozilla_BackgroundHangTelemetry_h
--- a/toolkit/components/telemetry/moz.build
+++ b/toolkit/components/telemetry/moz.build
@@ -11,16 +11,17 @@ XPIDL_SOURCES += [
     'nsITelemetryPing.idl',
 ]
 
 XPIDL_MODULE = 'telemetry'
 
 EXPORTS.mozilla += [
     'ProcessedStack.h',
     'Telemetry.h',
+    'ThreadHangStats.h',
 ]
 
 SOURCES += [
     'Telemetry.cpp',
 ]
 
 EXTRA_COMPONENTS += [
     'TelemetryPing.manifest',