diff options
Diffstat (limited to 'xpcom/threads/HangAnnotations.cpp')
-rw-r--r-- | xpcom/threads/HangAnnotations.cpp | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/xpcom/threads/HangAnnotations.cpp b/xpcom/threads/HangAnnotations.cpp new file mode 100644 index 000000000..529b57b8e --- /dev/null +++ b/xpcom/threads/HangAnnotations.cpp @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/HangAnnotations.h" + +#include <vector> + +#include "MainThreadUtils.h" +#include "mozilla/DebugOnly.h" +#include "nsXULAppAPI.h" + +namespace mozilla { +namespace HangMonitor { + +// Chrome hang annotators. This can go away once BHR has completely replaced +// ChromeHangs. +static StaticAutoPtr<Observer::Annotators> gChromehangAnnotators; + +class BrowserHangAnnotations : public HangAnnotations +{ +public: + BrowserHangAnnotations(); + ~BrowserHangAnnotations(); + + void AddAnnotation(const nsAString& aName, const int32_t aData) override; + void AddAnnotation(const nsAString& aName, const double aData) override; + void AddAnnotation(const nsAString& aName, const nsAString& aData) override; + void AddAnnotation(const nsAString& aName, const nsACString& aData) override; + void AddAnnotation(const nsAString& aName, const bool aData) override; + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override; + bool IsEmpty() const override; + UniquePtr<Enumerator> GetEnumerator() override; + + typedef std::pair<nsString, nsString> AnnotationType; + typedef std::vector<AnnotationType> VectorType; + typedef VectorType::const_iterator IteratorType; + +private: + VectorType mAnnotations; +}; + +BrowserHangAnnotations::BrowserHangAnnotations() +{ + MOZ_COUNT_CTOR(BrowserHangAnnotations); +} + +BrowserHangAnnotations::~BrowserHangAnnotations() +{ + MOZ_COUNT_DTOR(BrowserHangAnnotations); +} + +void +BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const int32_t aData) +{ + nsString dataString; + dataString.AppendInt(aData); + AnnotationType annotation = std::make_pair(nsString(aName), dataString); + mAnnotations.push_back(annotation); +} + +void +BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const double aData) +{ + nsString dataString; + dataString.AppendFloat(aData); + AnnotationType annotation = std::make_pair(nsString(aName), dataString); + mAnnotations.push_back(annotation); +} + +void +BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const nsAString& aData) +{ + AnnotationType annotation = std::make_pair(nsString(aName), nsString(aData)); + mAnnotations.push_back(annotation); +} + +void +BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const nsACString& aData) +{ + nsString dataString; + AppendUTF8toUTF16(aData, dataString); + AnnotationType annotation = std::make_pair(nsString(aName), dataString); + mAnnotations.push_back(annotation); +} + +void +BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const bool aData) +{ + nsString dataString; + dataString += aData ? NS_LITERAL_STRING("true") : NS_LITERAL_STRING("false"); + AnnotationType annotation = std::make_pair(nsString(aName), dataString); + mAnnotations.push_back(annotation); +} + +/** + * This class itself does not use synchronization but it (and its parent object) + * should be protected by mutual exclusion in some way. In Telemetry the chrome + * hang data is protected via TelemetryImpl::mHangReportsMutex. + */ +class ChromeHangAnnotationEnumerator : public HangAnnotations::Enumerator +{ +public: + explicit ChromeHangAnnotationEnumerator(const BrowserHangAnnotations::VectorType& aAnnotations); + ~ChromeHangAnnotationEnumerator(); + + virtual bool Next(nsAString& aOutName, nsAString& aOutValue); + +private: + BrowserHangAnnotations::IteratorType mIterator; + BrowserHangAnnotations::IteratorType mEnd; +}; + +ChromeHangAnnotationEnumerator::ChromeHangAnnotationEnumerator( + const BrowserHangAnnotations::VectorType& aAnnotations) + : mIterator(aAnnotations.begin()) + , mEnd(aAnnotations.end()) +{ + MOZ_COUNT_CTOR(ChromeHangAnnotationEnumerator); +} + +ChromeHangAnnotationEnumerator::~ChromeHangAnnotationEnumerator() +{ + MOZ_COUNT_DTOR(ChromeHangAnnotationEnumerator); +} + +bool +ChromeHangAnnotationEnumerator::Next(nsAString& aOutName, nsAString& aOutValue) +{ + aOutName.Truncate(); + aOutValue.Truncate(); + if (mIterator == mEnd) { + return false; + } + aOutName = mIterator->first; + aOutValue = mIterator->second; + ++mIterator; + return true; +} + +bool +BrowserHangAnnotations::IsEmpty() const +{ + return mAnnotations.empty(); +} + +size_t +BrowserHangAnnotations::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const +{ + size_t result = sizeof(mAnnotations) + + mAnnotations.capacity() * sizeof(AnnotationType); + for (IteratorType i = mAnnotations.begin(), e = mAnnotations.end(); i != e; + ++i) { + result += i->first.SizeOfExcludingThisIfUnshared(aMallocSizeOf); + result += i->second.SizeOfExcludingThisIfUnshared(aMallocSizeOf); + } + + return result; +} + +UniquePtr<HangAnnotations::Enumerator> +BrowserHangAnnotations::GetEnumerator() +{ + if (mAnnotations.empty()) { + return nullptr; + } + return MakeUnique<ChromeHangAnnotationEnumerator>(mAnnotations); +} + +namespace Observer { + +Annotators::Annotators() + : mMutex("HangMonitor::Annotators::mMutex") +{ + MOZ_COUNT_CTOR(Annotators); +} + +Annotators::~Annotators() +{ + MOZ_ASSERT(mAnnotators.empty()); + MOZ_COUNT_DTOR(Annotators); +} + +bool +Annotators::Register(Annotator& aAnnotator) +{ + MutexAutoLock lock(mMutex); + auto result = mAnnotators.insert(&aAnnotator); + return result.second; +} + +bool +Annotators::Unregister(Annotator& aAnnotator) +{ + MutexAutoLock lock(mMutex); + DebugOnly<std::set<Annotator*>::size_type> numErased; + numErased = mAnnotators.erase(&aAnnotator); + MOZ_ASSERT(numErased == 1); + return mAnnotators.empty(); +} + +UniquePtr<HangAnnotations> +Annotators::GatherAnnotations() +{ + auto annotations = MakeUnique<BrowserHangAnnotations>(); + { // Scope for lock + MutexAutoLock lock(mMutex); + for (std::set<Annotator*>::iterator i = mAnnotators.begin(), + e = mAnnotators.end(); + i != e; ++i) { + (*i)->AnnotateHang(*annotations); + } + } + if (annotations->IsEmpty()) { + return nullptr; + } + return Move(annotations); +} + +} // namespace Observer + +void +RegisterAnnotator(Annotator& aAnnotator) +{ + BackgroundHangMonitor::RegisterAnnotator(aAnnotator); + // We still register annotators for ChromeHangs + if (NS_IsMainThread() && + GeckoProcessType_Default == XRE_GetProcessType()) { + if (!gChromehangAnnotators) { + gChromehangAnnotators = new Observer::Annotators(); + } + gChromehangAnnotators->Register(aAnnotator); + } +} + +void +UnregisterAnnotator(Annotator& aAnnotator) +{ + BackgroundHangMonitor::UnregisterAnnotator(aAnnotator); + // We still register annotators for ChromeHangs + if (NS_IsMainThread() && + GeckoProcessType_Default == XRE_GetProcessType()) { + if (gChromehangAnnotators->Unregister(aAnnotator)) { + gChromehangAnnotators = nullptr; + } + } +} + +UniquePtr<HangAnnotations> +ChromeHangAnnotatorCallout() +{ + if (!gChromehangAnnotators) { + return nullptr; + } + return gChromehangAnnotators->GatherAnnotations(); +} + +} // namespace HangMonitor +} // namespace mozilla |