author | Jim Chen <nchen@mozilla.com> |
Fri, 22 Nov 2013 14:17:31 -0500 | |
changeset 157181 | 5365478bdea9ca9e1eb8299a5f3705a907e34955 |
parent 157180 | 4c31b0875e214c33a4abce64b9e8e27d2ef135f6 |
child 157182 | 94c3daf6e24247cf1df06674cd97078256e29b0f |
push id | 25703 |
push user | philringnalda@gmail.com |
push date | Sat, 23 Nov 2013 16:19:02 +0000 |
treeherder | mozilla-central@ad6589ed742c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | froydnj |
bugs | 932865 |
milestone | 28.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
|
--- a/xpcom/threads/BackgroundHangMonitor.cpp +++ b/xpcom/threads/BackgroundHangMonitor.cpp @@ -1,23 +1,25 @@ /* -*- Mode: C++; tab-width: 8; 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/. */ #include "mozilla/BackgroundHangMonitor.h" #include "mozilla/LinkedList.h" #include "mozilla/Monitor.h" +#include "mozilla/Move.h" #include "mozilla/StaticPtr.h" #include "mozilla/Telemetry.h" #include "mozilla/ThreadHangStats.h" #include "mozilla/ThreadLocal.h" #include "prinrval.h" #include "prthread.h" +#include "ThreadStackHelper.h" #include <algorithm> namespace mozilla { /** * BackgroundHangManager is the global object that * manages all instances of BackgroundHangThread. @@ -112,26 +114,30 @@ public: // 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; + // Platform-specific helper to get hang stacks + ThreadStackHelper mStackHelper; + // Stack of current hang + Telemetry::HangHistogram::Stack mHangStack; // 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; + void ReportHang(PRIntervalTime aHangTime); // Report a permanent hang; aManager->mLock IS locked void ReportPermaHang() const; // Called by BackgroundHangMonitor::NotifyActivity void NotifyActivity(); // Called by BackgroundHangMonitor::NotifyWait void NotifyWait() { NotifyActivity(); @@ -248,16 +254,17 @@ BackgroundHangManager::RunMonitorThread( currentThread->mWaiting = true; currentThread->ReportPermaHang(); continue; } if (MOZ_LIKELY(!currentThread->mHanging)) { if (MOZ_UNLIKELY(hangTime >= currentThread->mTimeout)) { // A hang started + currentThread->mStackHelper.GetStack(currentThread->mHangStack); currentThread->mHangStart = interval; currentThread->mHanging = true; } } else { if (MOZ_LIKELY(interval != currentThread->mHangStart)) { // A hang ended currentThread->ReportHang(intervalNow - currentThread->mHangStart); currentThread->mHanging = false; @@ -327,22 +334,33 @@ BackgroundHangThread::~BackgroundHangThr sTlsKey.set(nullptr); } // Move our copy of ThreadHangStats to Telemetry storage Telemetry::RecordThreadHangStats(mStats); } void -BackgroundHangThread::ReportHang(PRIntervalTime aHangTime) const +BackgroundHangThread::ReportHang(PRIntervalTime aHangTime) { // Recovered from a hang; called on the monitor thread // mManager->mLock IS locked - // TODO: Add telemetry reporting for hangs + Telemetry::HangHistogram newHistogram(Move(mHangStack)); + for (Telemetry::HangHistogram* oldHistogram = mStats.mHangs.begin(); + oldHistogram != mStats.mHangs.end(); oldHistogram++) { + if (newHistogram == *oldHistogram) { + // New histogram matches old one + oldHistogram->Add(aHangTime); + return; + } + } + // Add new histogram + newHistogram.Add(aHangTime); + mStats.mHangs.append(Move(newHistogram)); } void BackgroundHangThread::ReportPermaHang() const { // Permanently hanged; called on the monitor thread // mManager->mLock IS locked @@ -356,16 +374,17 @@ BackgroundHangThread::NotifyActivity() if (mWaiting) { mInterval = intervalNow; mWaiting = false; /* We have to wake up the manager thread because when all threads are waiting, the manager thread waits indefinitely as well. */ mManager->Wakeup(); } else { PRIntervalTime duration = intervalNow - mInterval; + mStats.mActivity.Add(duration); if (MOZ_UNLIKELY(duration >= mTimeout)) { /* Wake up the manager thread to tell it that a hang ended */ mManager->Wakeup(); } mInterval = intervalNow; } } @@ -393,29 +412,31 @@ BackgroundHangThread::FindThread() return nullptr; } void BackgroundHangMonitor::Startup() { MOZ_ASSERT(!BackgroundHangManager::sInstance, "Already initialized"); + ThreadStackHelper::Startup(); BackgroundHangThread::Startup(); BackgroundHangManager::sInstance = new BackgroundHangManager(); } void BackgroundHangMonitor::Shutdown() { MOZ_ASSERT(BackgroundHangManager::sInstance, "Not initialized"); /* Scope our lock inside Shutdown() because the sInstance object can be destroyed as soon as we set sInstance to nullptr below, and we don't want to hold the lock when it's being destroyed. */ BackgroundHangManager::sInstance->Shutdown(); BackgroundHangManager::sInstance = nullptr; + ThreadStackHelper::Shutdown(); } BackgroundHangMonitor::BackgroundHangMonitor(const char* aName, uint32_t aTimeoutMs, uint32_t aMaxTimeoutMs) : mThread(BackgroundHangThread::FindThread()) { if (!mThread) {