Bug 932865 - Add way for telemetry to iterate over active threads; r=froydnj
authorJim Chen <nchen@mozilla.com>
Fri, 22 Nov 2013 14:17:31 -0500
changeset 157080 c4834a9ec4c8eaaf2c92df6e0fb0f37ff9744025
parent 157079 288456164d94cf77ac4eab6f12c16da3194aa30a
child 157081 c32c0526e7b56e40eb2d4cab666a9634850039e6
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)
reviewersfroydnj
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 way for telemetry to iterate over active threads; r=froydnj
xpcom/threads/BackgroundHangMonitor.cpp
xpcom/threads/BackgroundHangMonitor.h
--- a/xpcom/threads/BackgroundHangMonitor.cpp
+++ b/xpcom/threads/BackgroundHangMonitor.cpp
@@ -2,16 +2,17 @@
 /* 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/. */
 
 #include "mozilla/BackgroundHangMonitor.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/StaticPtr.h"
+#include "mozilla/ThreadHangStats.h"
 #include "mozilla/ThreadLocal.h"
 
 #include "prinrval.h"
 #include "prthread.h"
 
 #include <algorithm>
 
 namespace mozilla {
@@ -98,30 +99,30 @@ public:
 
   static void Startup()
   {
     /* We can tolerate init() failing.
        The if block turns off warn_unused_result. */
     if (!sTlsKey.init()) {}
   }
 
-  // Name of the thread
-  const nsAutoCString mThreadName;
   // Hang timeout in ticks
   const PRIntervalTime mTimeout;
   // PermaHang timeout in ticks
   const PRIntervalTime mMaxTimeout;
   // Time at last activity
   PRIntervalTime mInterval;
   // Time when a hang started
   PRIntervalTime mHangStart;
   // Is the thread in a hang
   bool mHanging;
   // Is the thread in a waiting state
   bool mWaiting;
+  // Statistics for telemetry
+  Telemetry::ThreadHangStats mStats;
 
   BackgroundHangThread(const char* aName,
                        uint32_t aTimeoutMs,
                        uint32_t aMaxTimeoutMs);
   ~BackgroundHangThread();
 
   // Report a hang; aManager->mLock IS locked
   void ReportHang(PRIntervalTime aHangTime) const;
@@ -287,23 +288,23 @@ BackgroundHangManager::RunMonitorThread(
 }
 
 
 BackgroundHangThread::BackgroundHangThread(const char* aName,
                                            uint32_t aTimeoutMs,
                                            uint32_t aMaxTimeoutMs)
   : mManager(BackgroundHangManager::sInstance)
   , mThreadID(PR_GetCurrentThread())
-  , mThreadName(aName)
   , mTimeout(PR_MillisecondsToInterval(aTimeoutMs))
   , mMaxTimeout(PR_MillisecondsToInterval(aMaxTimeoutMs))
   , mInterval(mManager->mIntervalNow)
   , mHangStart(mInterval)
   , mHanging(false)
   , mWaiting(true)
+  , mStats(aName)
 {
   if (sTlsKey.initialized()) {
     sTlsKey.set(this);
   }
   // Lock here because LinkedList is not thread-safe
   MonitorAutoLock autoLock(mManager->mLock);
   // Add to thread list
   mManager->mHangThreads.insertBack(this);
@@ -435,9 +436,30 @@ BackgroundHangMonitor::NotifyActivity()
 }
 
 void
 BackgroundHangMonitor::NotifyWait()
 {
   mThread->NotifyWait();
 }
 
+
+/* Because we are iterating through the BackgroundHangThread linked list,
+   we need to take a lock. Using MonitorAutoLock as a base class makes
+   sure all of that is taken care of for us. */
+BackgroundHangMonitor::ThreadHangStatsIterator::ThreadHangStatsIterator()
+  : MonitorAutoLock(BackgroundHangManager::sInstance->mLock)
+  , mThread(BackgroundHangManager::sInstance->mHangThreads.getFirst())
+{
+}
+
+Telemetry::ThreadHangStats*
+BackgroundHangMonitor::ThreadHangStatsIterator::GetNext()
+{
+  if (!mThread) {
+    return nullptr;
+  }
+  Telemetry::ThreadHangStats* stats = &mThread->mStats;
+  mThread = mThread->getNext();
+  return stats;
+}
+
 } // namespace mozilla
--- a/xpcom/threads/BackgroundHangMonitor.h
+++ b/xpcom/threads/BackgroundHangMonitor.h
@@ -2,21 +2,26 @@
 /* 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_BackgroundHangMonitor_h
 #define mozilla_BackgroundHangMonitor_h
 
 #include "mozilla/RefPtr.h"
+#include "mozilla/Monitor.h"
 
 #include <stdint.h>
 
 namespace mozilla {
 
+namespace Telemetry {
+class ThreadHangStats;
+};
+
 class BackgroundHangThread;
 
 /**
  * The background hang monitor is responsible for detecting and reporting
  * hangs in background (non-main) threads. A thread registers itself using
  * the BackgroundHangMonitor object and periodically calls its methods to
  * inform the hang monitor of the thread's activity. Each thread is given
  * a thread name, a timeout, and a maximum timeout. If one of the thread's
@@ -97,16 +102,54 @@ class BackgroundHangThread;
  */
 class BackgroundHangMonitor
 {
 private:
   RefPtr<BackgroundHangThread> mThread;
 
 public:
   /**
+   * ThreadHangStatsIterator is used to iterate through the ThreadHangStats
+   * associated with each active monitored thread. Because of an internal
+   * lock while this object is alive, a thread must use only one instance
+   * of this class at a time and must iterate through the list as fast as
+   * possible. The following example shows using the iterator:
+   *
+   * {
+   *   // Scope the iter variable so it's destroyed as soon as we're done
+   *   BackgroundHangMonitor::ThreadHangStatsIterator iter;
+   *   for (ThreadHangStats* histogram = iter.GetNext();
+   *        histogram; histogram = iter.GetNext()) {
+   *     // Process histogram
+   *   }
+   * }
+   */
+  class ThreadHangStatsIterator : public MonitorAutoLock
+  {
+  private:
+    BackgroundHangThread* mThread;
+
+    ThreadHangStatsIterator(const ThreadHangStatsIterator&);
+    ThreadHangStatsIterator& operator=(const ThreadHangStatsIterator&);
+
+  public:
+    /**
+     * Create an ThreadHangStatsIterator instance and take the internal lock.
+     * Internal lock is released on destruction.
+     */
+    ThreadHangStatsIterator();
+
+    /**
+     * Get the next item in the list; the first call returns the first item.
+     * Returns nullptr at the end of the list.
+     */
+    Telemetry::ThreadHangStats* GetNext();
+  };
+
+  /**
    * Enable hang monitoring.
    * Must return before using BackgroundHangMonitor.
    */
   static void Startup();
 
   /**
    * Disable hang monitoring.
    * Can be called without destroying all BackgroundHangMonitors first.