зеркало из https://github.com/mozilla/gecko-dev.git
Bug 818307: Part 1 - Add annotation support to ChromeHangs; r=vladan
This commit is contained in:
Родитель
6d7ed02a07
Коммит
ca4ee88bc5
|
@ -63,6 +63,7 @@
|
|||
#include "mozilla/PoisonIOInterposer.h"
|
||||
#include "mozilla/StartupTimeline.h"
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
#include "mozilla/HangMonitor.h"
|
||||
#include "shared-libraries.h"
|
||||
#endif
|
||||
|
||||
|
@ -72,6 +73,7 @@ namespace {
|
|||
|
||||
using namespace base;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::HangMonitor;
|
||||
|
||||
template<class EntryType>
|
||||
class AutoHashtable : public nsTHashtable<EntryType>
|
||||
|
@ -208,14 +210,38 @@ CombinedStacks::SizeOfExcludingThis() const {
|
|||
|
||||
class HangReports {
|
||||
public:
|
||||
size_t SizeOfExcludingThis() const;
|
||||
/**
|
||||
* This struct encapsulates information for an individual ChromeHang annotation.
|
||||
* mHangIndex is the index of the corresponding ChromeHang.
|
||||
*/
|
||||
struct AnnotationInfo {
|
||||
AnnotationInfo(uint32_t aHangIndex,
|
||||
HangAnnotations* aAnnotations)
|
||||
: mHangIndex(aHangIndex)
|
||||
, mAnnotations(aAnnotations)
|
||||
{}
|
||||
AnnotationInfo(const AnnotationInfo& aOther)
|
||||
: mHangIndex(aOther.mHangIndex)
|
||||
, mAnnotations(aOther.mAnnotations)
|
||||
{}
|
||||
~AnnotationInfo() {}
|
||||
uint32_t mHangIndex;
|
||||
mutable nsAutoPtr<HangAnnotations> mAnnotations;
|
||||
};
|
||||
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
void AddHang(const Telemetry::ProcessedStack& aStack, uint32_t aDuration,
|
||||
int32_t aSystemUptime, int32_t aFirefoxUptime);
|
||||
int32_t aSystemUptime, int32_t aFirefoxUptime,
|
||||
HangAnnotations* aAnnotations);
|
||||
uint32_t GetDuration(unsigned aIndex) const;
|
||||
int32_t GetSystemUptime(unsigned aIndex) const;
|
||||
int32_t GetFirefoxUptime(unsigned aIndex) const;
|
||||
const std::vector<AnnotationInfo>& GetAnnotationInfo() const;
|
||||
const CombinedStacks& GetStacks() const;
|
||||
private:
|
||||
/**
|
||||
* This struct encapsulates the data for an individual ChromeHang, excluding
|
||||
* annotations.
|
||||
*/
|
||||
struct HangInfo {
|
||||
// Hang duration (in seconds)
|
||||
uint32_t mDuration;
|
||||
|
@ -225,6 +251,7 @@ private:
|
|||
int32_t mFirefoxUptime;
|
||||
};
|
||||
std::vector<HangInfo> mHangInfo;
|
||||
std::vector<AnnotationInfo> mAnnotationInfo;
|
||||
CombinedStacks mStacks;
|
||||
};
|
||||
|
||||
|
@ -232,19 +259,30 @@ void
|
|||
HangReports::AddHang(const Telemetry::ProcessedStack& aStack,
|
||||
uint32_t aDuration,
|
||||
int32_t aSystemUptime,
|
||||
int32_t aFirefoxUptime) {
|
||||
int32_t aFirefoxUptime,
|
||||
HangAnnotations* aAnnotations) {
|
||||
HangInfo info = { aDuration, aSystemUptime, aFirefoxUptime };
|
||||
mHangInfo.push_back(info);
|
||||
if (aAnnotations) {
|
||||
AnnotationInfo ainfo(static_cast<uint32_t>(mHangInfo.size() - 1),
|
||||
aAnnotations);
|
||||
mAnnotationInfo.push_back(ainfo);
|
||||
}
|
||||
mStacks.AddStack(aStack);
|
||||
}
|
||||
|
||||
size_t
|
||||
HangReports::SizeOfExcludingThis() const {
|
||||
HangReports::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
|
||||
size_t n = 0;
|
||||
n += mStacks.SizeOfExcludingThis();
|
||||
// This is a crude approximation. See comment on
|
||||
// CombinedStacks::SizeOfExcludingThis.
|
||||
n += mHangInfo.capacity() * sizeof(HangInfo);
|
||||
n += mAnnotationInfo.capacity() * sizeof(AnnotationInfo);
|
||||
for (std::vector<AnnotationInfo>::const_iterator i = mAnnotationInfo.begin(),
|
||||
e = mAnnotationInfo.end(); i != e; ++i) {
|
||||
n += i->mAnnotations->SizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -268,6 +306,11 @@ HangReports::GetFirefoxUptime(unsigned aIndex) const {
|
|||
return mHangInfo[aIndex].mFirefoxUptime;
|
||||
}
|
||||
|
||||
const std::vector<HangReports::AnnotationInfo>&
|
||||
HangReports::GetAnnotationInfo() const {
|
||||
return mAnnotationInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* IOInterposeObserver recording statistics of main-thread I/O during execution,
|
||||
* aimed at consumption by TelemetryImpl
|
||||
|
@ -575,7 +618,8 @@ public:
|
|||
static void RecordChromeHang(uint32_t aDuration,
|
||||
Telemetry::ProcessedStack &aStack,
|
||||
int32_t aSystemUptime,
|
||||
int32_t aFirefoxUptime);
|
||||
int32_t aFirefoxUptime,
|
||||
HangAnnotations* aAnnotations);
|
||||
#endif
|
||||
static void RecordThreadHangStats(Telemetry::ThreadHangStats& aStats);
|
||||
static nsresult GetHistogramEnumId(const char *name, Telemetry::ID *id);
|
||||
|
@ -1798,7 +1842,9 @@ TelemetryImpl::GetChromeHangs(JSContext *cx, JS::MutableHandle<JS::Value> ret)
|
|||
JS::Rooted<JSObject*> durationArray(cx, JS_NewArrayObject(cx, 0));
|
||||
JS::Rooted<JSObject*> systemUptimeArray(cx, JS_NewArrayObject(cx, 0));
|
||||
JS::Rooted<JSObject*> firefoxUptimeArray(cx, JS_NewArrayObject(cx, 0));
|
||||
if (!durationArray || !systemUptimeArray || !firefoxUptimeArray) {
|
||||
JS::Rooted<JSObject*> annotationsArray(cx, JS_NewArrayObject(cx, 0));
|
||||
if (!durationArray || !systemUptimeArray || !firefoxUptimeArray ||
|
||||
!annotationsArray) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -1820,6 +1866,13 @@ TelemetryImpl::GetChromeHangs(JSContext *cx, JS::MutableHandle<JS::Value> ret)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ok = JS_DefineProperty(cx, fullReportObj, "annotations", annotationsArray,
|
||||
JSPROP_ENUMERATE);
|
||||
if (!ok) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
const size_t length = stacks.GetStackCount();
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
if (!JS_SetElement(cx, durationArray, i, mHangReports.GetDuration(i))) {
|
||||
|
@ -1831,6 +1884,49 @@ TelemetryImpl::GetChromeHangs(JSContext *cx, JS::MutableHandle<JS::Value> ret)
|
|||
if (!JS_SetElement(cx, firefoxUptimeArray, i, mHangReports.GetFirefoxUptime(i))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
const std::vector<HangReports::AnnotationInfo>& annotationInfo =
|
||||
mHangReports.GetAnnotationInfo();
|
||||
uint32_t annotationsArrayIndex = 0;
|
||||
for (std::vector<HangReports::AnnotationInfo>::const_iterator
|
||||
ai = annotationInfo.begin(), e = annotationInfo.end(); ai != e;
|
||||
++ai, ++annotationsArrayIndex) {
|
||||
JS::Rooted<JSObject*> keyValueArray(cx, JS_NewArrayObject(cx, 0));
|
||||
if (!keyValueArray) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
JS::RootedValue indexValue(cx);
|
||||
indexValue.setNumber(ai->mHangIndex);
|
||||
if (!JS_SetElement(cx, keyValueArray, 0, indexValue)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
JS::Rooted<JSObject*> jsAnnotation(cx, JS_NewObject(cx, nullptr,
|
||||
JS::NullPtr(),
|
||||
JS::NullPtr()));
|
||||
if (!jsAnnotation) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsAutoPtr<HangAnnotations::Enumerator> annotationsEnum;
|
||||
if (!ai->mAnnotations->GetEnumerator(annotationsEnum.StartAssignment())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsAutoString key;
|
||||
nsAutoString value;
|
||||
while (annotationsEnum->Next(key, value)) {
|
||||
JS::RootedValue jsValue(cx);
|
||||
jsValue.setString(JS_NewUCStringCopyN(cx, value.get(), value.Length()));
|
||||
if (!JS_DefineUCProperty(cx, jsAnnotation, key.get(), key.Length(),
|
||||
jsValue, JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
if (!JS_SetElement(cx, keyValueArray, 1, jsAnnotation)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (!JS_SetElement(cx, annotationsArray, annotationsArrayIndex,
|
||||
keyValueArray)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -2543,7 +2639,8 @@ void
|
|||
TelemetryImpl::RecordChromeHang(uint32_t aDuration,
|
||||
Telemetry::ProcessedStack &aStack,
|
||||
int32_t aSystemUptime,
|
||||
int32_t aFirefoxUptime)
|
||||
int32_t aFirefoxUptime,
|
||||
HangAnnotations* aAnnotations)
|
||||
{
|
||||
if (!sTelemetry || !sTelemetry->mCanRecord)
|
||||
return;
|
||||
|
@ -2551,7 +2648,8 @@ TelemetryImpl::RecordChromeHang(uint32_t aDuration,
|
|||
MutexAutoLock hangReportMutex(sTelemetry->mHangReportsMutex);
|
||||
|
||||
sTelemetry->mHangReports.AddHang(aStack, aDuration,
|
||||
aSystemUptime, aFirefoxUptime);
|
||||
aSystemUptime, aFirefoxUptime,
|
||||
aAnnotations);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2641,7 +2739,7 @@ TelemetryImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
|||
n += mTrackedDBs.SizeOfExcludingThis(aMallocSizeOf);
|
||||
{ // Scope for mHangReportsMutex lock
|
||||
MutexAutoLock lock(mHangReportsMutex);
|
||||
n += mHangReports.SizeOfExcludingThis();
|
||||
n += mHangReports.SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
{ // Scope for mThreadHangStatsMutex lock
|
||||
MutexAutoLock lock(mThreadHangStatsMutex);
|
||||
|
@ -2797,10 +2895,11 @@ void Init()
|
|||
void RecordChromeHang(uint32_t duration,
|
||||
ProcessedStack &aStack,
|
||||
int32_t aSystemUptime,
|
||||
int32_t aFirefoxUptime)
|
||||
int32_t aFirefoxUptime,
|
||||
HangAnnotations* aAnnotations)
|
||||
{
|
||||
TelemetryImpl::RecordChromeHang(duration, aStack,
|
||||
aSystemUptime, aFirefoxUptime);
|
||||
aSystemUptime, aFirefoxUptime, aAnnotations);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@ namespace base {
|
|||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace HangMonitor {
|
||||
class HangAnnotations;
|
||||
}
|
||||
namespace Telemetry {
|
||||
|
||||
#include "TelemetryHistogramEnums.h"
|
||||
|
@ -195,12 +198,14 @@ class ProcessedStack;
|
|||
* @param aStack - Array of PCs from the hung call stack
|
||||
* @param aSystemUptime - System uptime at the time of the hang, in minutes
|
||||
* @param aFirefoxUptime - Firefox uptime at the time of the hang, in minutes
|
||||
* @param aAnnotations - Any annotations to be added to the report
|
||||
*/
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
void RecordChromeHang(uint32_t aDuration,
|
||||
ProcessedStack &aStack,
|
||||
int32_t aSystemUptime,
|
||||
int32_t aFirefoxUptime);
|
||||
int32_t aFirefoxUptime,
|
||||
mozilla::HangMonitor::HangAnnotations* aAnnotations = nullptr);
|
||||
#endif
|
||||
|
||||
class ThreadHangStats;
|
||||
|
|
|
@ -5,15 +5,21 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/HangMonitor.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "mozilla/BackgroundHangMonitor.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/ProcessedStack.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsStackWalk.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
|
@ -68,6 +74,9 @@ static const int32_t DEFAULT_CHROME_HANG_INTERVAL = 5;
|
|||
|
||||
// Maximum number of PCs to gather from the stack
|
||||
static const int32_t MAX_CALL_STACK_PCS = 400;
|
||||
|
||||
// Chrome hang annotators
|
||||
static StaticAutoPtr<std::set<Annotator*>> gAnnotators;
|
||||
#endif
|
||||
|
||||
// PrefChangedFunc
|
||||
|
@ -113,6 +122,162 @@ Crash()
|
|||
}
|
||||
|
||||
#ifdef REPORT_CHROME_HANGS
|
||||
class ChromeHangAnnotations : public HangAnnotations
|
||||
{
|
||||
public:
|
||||
ChromeHangAnnotations();
|
||||
~ChromeHangAnnotations();
|
||||
|
||||
void AddAnnotation(const nsAString& aName, const int32_t aData) MOZ_OVERRIDE;
|
||||
void AddAnnotation(const nsAString& aName, const double aData) MOZ_OVERRIDE;
|
||||
void AddAnnotation(const nsAString& aName, const nsAString& aData) MOZ_OVERRIDE;
|
||||
void AddAnnotation(const nsAString& aName, const nsACString& aData) MOZ_OVERRIDE;
|
||||
void AddAnnotation(const nsAString& aName, const bool aData) MOZ_OVERRIDE;
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
|
||||
bool IsEmpty() const MOZ_OVERRIDE;
|
||||
bool GetEnumerator(Enumerator** aOutEnum) MOZ_OVERRIDE;
|
||||
|
||||
typedef std::pair<nsString, nsString> AnnotationType;
|
||||
typedef std::vector<AnnotationType> VectorType;
|
||||
typedef VectorType::const_iterator IteratorType;
|
||||
|
||||
private:
|
||||
VectorType mAnnotations;
|
||||
};
|
||||
|
||||
ChromeHangAnnotations::ChromeHangAnnotations()
|
||||
{
|
||||
MOZ_COUNT_CTOR(ChromeHangAnnotations);
|
||||
}
|
||||
|
||||
ChromeHangAnnotations::~ChromeHangAnnotations()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ChromeHangAnnotations);
|
||||
}
|
||||
|
||||
void
|
||||
ChromeHangAnnotations::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
|
||||
ChromeHangAnnotations::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
|
||||
ChromeHangAnnotations::AddAnnotation(const nsAString& aName, const nsAString& aData)
|
||||
{
|
||||
AnnotationType annotation = std::make_pair(nsString(aName), nsString(aData));
|
||||
mAnnotations.push_back(annotation);
|
||||
}
|
||||
|
||||
void
|
||||
ChromeHangAnnotations::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
|
||||
ChromeHangAnnotations::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:
|
||||
ChromeHangAnnotationEnumerator(const ChromeHangAnnotations::VectorType& aAnnotations);
|
||||
~ChromeHangAnnotationEnumerator();
|
||||
|
||||
virtual bool Next(nsAString& aOutName, nsAString& aOutValue);
|
||||
|
||||
private:
|
||||
ChromeHangAnnotations::IteratorType mIterator;
|
||||
ChromeHangAnnotations::IteratorType mEnd;
|
||||
};
|
||||
|
||||
ChromeHangAnnotationEnumerator::ChromeHangAnnotationEnumerator(
|
||||
const ChromeHangAnnotations::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
|
||||
ChromeHangAnnotations::IsEmpty() const
|
||||
{
|
||||
return mAnnotations.empty();
|
||||
}
|
||||
|
||||
size_t
|
||||
ChromeHangAnnotations::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;
|
||||
}
|
||||
|
||||
bool
|
||||
ChromeHangAnnotations::GetEnumerator(HangAnnotations::Enumerator** aOutEnum)
|
||||
{
|
||||
if (!aOutEnum) {
|
||||
return false;
|
||||
}
|
||||
*aOutEnum = nullptr;
|
||||
if (mAnnotations.empty()) {
|
||||
return false;
|
||||
}
|
||||
*aOutEnum = new ChromeHangAnnotationEnumerator(mAnnotations);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
ChromeStackWalker(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure)
|
||||
{
|
||||
|
@ -163,6 +328,22 @@ GetChromeHangReport(Telemetry::ProcessedStack& aStack,
|
|||
aFirefoxUptime = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ChromeHangAnnotatorCallout(ChromeHangAnnotations& aAnnotations)
|
||||
{
|
||||
gMonitor->AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(gAnnotators);
|
||||
if (!gAnnotators) {
|
||||
return;
|
||||
}
|
||||
for (std::set<Annotator*>::iterator i = gAnnotators->begin(),
|
||||
e = gAnnotators->end();
|
||||
i != e; ++i) {
|
||||
(*i)->AnnotateHang(aAnnotations);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
|
@ -182,6 +363,7 @@ ThreadMain(void*)
|
|||
Telemetry::ProcessedStack stack;
|
||||
int32_t systemUptime = -1;
|
||||
int32_t firefoxUptime = -1;
|
||||
nsAutoPtr<ChromeHangAnnotations> annotations = new ChromeHangAnnotations();
|
||||
#endif
|
||||
|
||||
while (true) {
|
||||
|
@ -209,6 +391,7 @@ ThreadMain(void*)
|
|||
// the minimum hang duration has been reached (not when the hang ends)
|
||||
if (waitCount == 2) {
|
||||
GetChromeHangReport(stack, systemUptime, firefoxUptime);
|
||||
ChromeHangAnnotatorCallout(*annotations);
|
||||
}
|
||||
#else
|
||||
// This is the crash-on-hang feature.
|
||||
|
@ -226,9 +409,11 @@ ThreadMain(void*)
|
|||
#ifdef REPORT_CHROME_HANGS
|
||||
if (waitCount >= 2) {
|
||||
uint32_t hangDuration = PR_IntervalToSeconds(now - lastTimestamp);
|
||||
Telemetry::RecordChromeHang(hangDuration, stack,
|
||||
systemUptime, firefoxUptime);
|
||||
Telemetry::RecordChromeHang(hangDuration, stack, systemUptime,
|
||||
firefoxUptime, annotations->IsEmpty() ?
|
||||
nullptr : annotations.forget());
|
||||
stack.Clear();
|
||||
annotations = new ChromeHangAnnotations();
|
||||
}
|
||||
#endif
|
||||
lastTimestamp = timestamp;
|
||||
|
@ -268,6 +453,7 @@ Startup()
|
|||
if (!winMainThreadHandle) {
|
||||
return;
|
||||
}
|
||||
gAnnotators = new std::set<Annotator*>();
|
||||
#endif
|
||||
|
||||
// Don't actually start measuring hangs until we hit the main event loop.
|
||||
|
@ -306,6 +492,11 @@ Shutdown()
|
|||
|
||||
delete gMonitor;
|
||||
gMonitor = nullptr;
|
||||
|
||||
#ifdef REPORT_CHROME_HANGS
|
||||
// gAnnotators is a StaticAutoPtr, so we just need to null it out.
|
||||
gAnnotators = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -394,5 +585,25 @@ Suspend()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
RegisterAnnotator(Annotator& aAnnotator)
|
||||
{
|
||||
#ifdef REPORT_CHROME_HANGS
|
||||
MonitorAutoLock lock(*gMonitor);
|
||||
MOZ_ASSERT(gAnnotators);
|
||||
gAnnotators->insert(&aAnnotator);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
UnregisterAnnotator(Annotator& aAnnotator)
|
||||
{
|
||||
#ifdef REPORT_CHROME_HANGS
|
||||
MonitorAutoLock lock(*gMonitor);
|
||||
MOZ_ASSERT(gAnnotators);
|
||||
gAnnotators->erase(&aAnnotator);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace HangMonitor
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
#ifndef mozilla_HangMonitor_h
|
||||
#define mozilla_HangMonitor_h
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace HangMonitor {
|
||||
|
||||
|
@ -38,6 +41,57 @@ void Startup();
|
|||
*/
|
||||
void Shutdown();
|
||||
|
||||
/**
|
||||
* This class declares an abstraction for a data type that encapsulates all
|
||||
* of the annotations being reported by a registered hang Annotator.
|
||||
*/
|
||||
class HangAnnotations
|
||||
{
|
||||
public:
|
||||
virtual ~HangAnnotations() {}
|
||||
|
||||
virtual void AddAnnotation(const nsAString& aName, const int32_t aData) = 0;
|
||||
virtual void AddAnnotation(const nsAString& aName, const double aData) = 0;
|
||||
virtual void AddAnnotation(const nsAString& aName, const nsAString& aData) = 0;
|
||||
virtual void AddAnnotation(const nsAString& aName, const nsACString& aData) = 0;
|
||||
virtual void AddAnnotation(const nsAString& aName, const bool aData) = 0;
|
||||
|
||||
class Enumerator
|
||||
{
|
||||
public:
|
||||
virtual ~Enumerator() {}
|
||||
virtual bool Next(nsAString& aOutName, nsAString& aOutValue) = 0;
|
||||
};
|
||||
|
||||
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
|
||||
virtual bool IsEmpty() const = 0;
|
||||
virtual bool GetEnumerator(Enumerator **aOutEnum) = 0;
|
||||
};
|
||||
|
||||
class Annotator
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* NB: This function is always called by the HangMonitor thread.
|
||||
* Plan accordingly.
|
||||
*/
|
||||
virtual void AnnotateHang(HangAnnotations& aAnnotations) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers an Annotator to be called when a hang is detected.
|
||||
* @param aAnnotator Reference to an object that implements the
|
||||
* HangMonitor::Annotator interface.
|
||||
*/
|
||||
void RegisterAnnotator(Annotator& aAnnotator);
|
||||
|
||||
/**
|
||||
* Registers an Annotator that was previously registered via RegisterAnnotator.
|
||||
* @param aAnnotator Reference to an object that implements the
|
||||
* HangMonitor::Annotator interface.
|
||||
*/
|
||||
void UnregisterAnnotator(Annotator& aAnnotator);
|
||||
|
||||
/**
|
||||
* Notify the hang monitor of activity which will reset its internal timer.
|
||||
*
|
||||
|
|
Загрузка…
Ссылка в новой задаче