Mypal/xpcom/threads/HangAnnotations.cpp

262 lines
7.0 KiB
C++

/* -*- 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/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