Bug 1448040 - Remove HangMonitor/ChromeHangs r=Nika

Fairly straightforward, just a blanket removal. Haven't heard
anything on dev-platform or fx-data-dev regarding this removal,
so I think it's likely safe to remove on Nightly, and we can
revert if anyone makes a fuss.

As part of removing the HangMonitor, I renamed a few things and
reorganized the namespaces to not depend on a HangMonitor
namespace. Hopefully this doesn't produce too much noise in the
diff, it just seemed appropriate to move everything around
rather than keep dangling vestiges of the old system.

MozReview-Commit-ID: 8C8NFnOP5GU

--HG--
extra : rebase_source : dd000a05bfc2da40c586644d33ca4508fa5330f6
This commit is contained in:
Doug Thayer 2018-04-29 18:21:20 -07:00
parent 3652708f31
commit 10ff9c706f
48 changed files with 260 additions and 1400 deletions

View File

@ -33,6 +33,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/AutoTimelineMarker.h"
#include "mozilla/BackgroundHangMonitor.h"
#include "mozilla/Base64.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/DebugOnly.h"
@ -600,7 +601,7 @@ NS_IMPL_ISUPPORTS(nsContentUtils::nsContentUtilsReporter, nsIMemoryReporter)
* user interaction status.
*/
class nsContentUtils::UserInteractionObserver final : public nsIObserver
, public HangMonitor::Annotator
, public BackgroundHangAnnotator
{
public:
NS_DECL_ISUPPORTS
@ -608,7 +609,7 @@ public:
void Init();
void Shutdown();
void AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) override;
void AnnotateHang(BackgroundHangAnnotations& aAnnotations) override;
static Atomic<bool> sUserActive;
@ -10780,13 +10781,13 @@ nsContentUtils::UserInteractionObserver::Init()
obs->AddObserver(this, kUserInteractionInactive, false);
obs->AddObserver(this, kUserInteractionActive, false);
// We can't register ourselves as an annotator yet, as the HangMonitor hasn't
// started yet. It will have started by the time we have the chance to spin
// the event loop.
// We can't register ourselves as an annotator yet, as the
// BackgroundHangMonitor hasn't started yet. It will have started by the
// time we have the chance to spin the event loop.
RefPtr<UserInteractionObserver> self = this;
NS_DispatchToMainThread(
NS_NewRunnableFunction("nsContentUtils::UserInteractionObserver::Init",
[=]() { HangMonitor::RegisterAnnotator(*self); }));
[=]() { BackgroundHangMonitor::RegisterAnnotator(*self); }));
}
void
@ -10798,15 +10799,15 @@ nsContentUtils::UserInteractionObserver::Shutdown()
obs->RemoveObserver(this, kUserInteractionActive);
}
HangMonitor::UnregisterAnnotator(*this);
BackgroundHangMonitor::UnregisterAnnotator(*this);
}
/**
* NB: This function is always called by the HangMonitor thread.
* NB: This function is always called by the BackgroundHangMonitor thread.
* Plan accordingly
*/
void
nsContentUtils::UserInteractionObserver::AnnotateHang(HangMonitor::HangAnnotations& aAnnotations)
nsContentUtils::UserInteractionObserver::AnnotateHang(BackgroundHangAnnotations& aAnnotations)
{
// NOTE: Only annotate the hang report if the user is known to be interacting.
if (sUserActive) {

View File

@ -15,6 +15,7 @@
#include "HandlerServiceChild.h"
#include "mozilla/Attributes.h"
#include "mozilla/BackgroundHangMonitor.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/Preferences.h"
#include "mozilla/ProcessHangMonitorIPC.h"
@ -510,15 +511,15 @@ ConsoleListener::Observe(nsIConsoleMessage* aMessage)
#ifdef NIGHTLY_BUILD
/**
* The singleton of this class is registered with the HangMonitor as an
* The singleton of this class is registered with the BackgroundHangMonitor as an
* annotator, so that the hang monitor can record whether or not there were
* pending input events when the thread hung.
*/
class PendingInputEventHangAnnotator final
: public HangMonitor::Annotator
: public BackgroundHangAnnotator
{
public:
virtual void AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) override
virtual void AnnotateHang(BackgroundHangAnnotations& aAnnotations) override
{
int32_t pending = ContentChild::GetSingleton()->GetPendingInputEvents();
if (pending > 0) {
@ -712,7 +713,7 @@ ContentChild::Init(MessageLoop* aIOLoop,
// only affect a single thread.
SystemGroup::Dispatch(TaskCategory::Other,
NS_NewRunnableFunction("RegisterPendingInputEventHangAnnotator", [] {
HangMonitor::RegisterAnnotator(
BackgroundHangMonitor::RegisterAnnotator(
PendingInputEventHangAnnotator::sSingleton);
}));
#endif
@ -3054,7 +3055,7 @@ ContentChild::ShutdownInternal()
mShuttingDown = true;
#ifdef NIGHTLY_BUILD
HangMonitor::UnregisterAnnotator(PendingInputEventHangAnnotator::sSingleton);
BackgroundHangMonitor::UnregisterAnnotator(PendingInputEventHangAnnotator::sSingleton);
#endif
if (mPolicy) {

View File

@ -9,6 +9,7 @@
#include "base/process_util.h"
#include "mozilla/Attributes.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/BackgroundHangMonitor.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/ipc/CrashReporterClient.h"
@ -660,7 +661,7 @@ PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath,
mSandboxLevel = aSandboxLevel;
mRunID = GeckoChildProcessHost::GetUniqueID();
mozilla::HangMonitor::RegisterAnnotator(*this);
mozilla::BackgroundHangMonitor::RegisterAnnotator(*this);
}
PluginModuleChromeParent::~PluginModuleChromeParent()
@ -713,7 +714,7 @@ PluginModuleChromeParent::~PluginModuleChromeParent()
}
#endif
mozilla::HangMonitor::UnregisterAnnotator(*this);
mozilla::BackgroundHangMonitor::UnregisterAnnotator(*this);
}
void
@ -992,16 +993,16 @@ PluginModuleChromeParent::ExitedCxxStack()
}
/**
* This function is always called by the HangMonitor thread.
* This function is always called by the BackgroundHangMonitor thread.
*/
void
PluginModuleChromeParent::AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations)
PluginModuleChromeParent::AnnotateHang(mozilla::BackgroundHangAnnotations& aAnnotations)
{
uint32_t flags = mHangAnnotationFlags;
if (flags) {
/* We don't actually annotate anything specifically for kInPluginCall;
we use it to determine whether to annotate other things. It will
be pretty obvious from the ChromeHang stack that we're in a plugin
be pretty obvious from the hang stack that we're in a plugin
call when the hang occurred. */
if (flags & kHangUIShown) {
aAnnotations.AddAnnotation(NS_LITERAL_STRING("HangUIShown"),

View File

@ -353,7 +353,7 @@ class PluginModuleContentParent : public PluginModuleParent
class PluginModuleChromeParent
: public PluginModuleParent
, public mozilla::HangMonitor::Annotator
, public mozilla::BackgroundHangAnnotator
{
friend class mozilla::ipc::CrashReporterHost;
using TerminateChildProcessCallback =
@ -477,7 +477,7 @@ private:
PluginInstanceParent* GetManagingInstance(mozilla::ipc::IProtocol* aProtocol);
virtual void
AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations) override;
AnnotateHang(mozilla::BackgroundHangAnnotations& aAnnotations) override;
virtual bool ShouldContinueFromReplyTimeout() override;

View File

@ -9,9 +9,9 @@
#include "GeckoProfiler.h"
#include "MainThreadUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/BackgroundHangMonitor.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/HangMonitor.h"
#include "mozilla/mscom/SpinEvent.h"
#include "mozilla/RefPtr.h"
#include "mozilla/SystemGroup.h"
@ -181,7 +181,7 @@ MainThreadInvoker::Invoke(already_AddRefed<nsIRunnable>&& aRunnable)
MainThreadInvoker::MainThreadAPC(ULONG_PTR aParam)
{
AUTO_PROFILER_THREAD_WAKE;
mozilla::HangMonitor::NotifyActivity(mozilla::HangMonitor::kGeneralActivity);
mozilla::BackgroundHangMonitor().NotifyActivity();
MOZ_ASSERT(NS_IsMainThread());
auto runnable = reinterpret_cast<SyncRunnable*>(aParam);
runnable->APCRun();

View File

@ -7,7 +7,6 @@ user_pref("security.fileuri.strict_origin_policy", false);
user_pref("dom.allow_scripts_to_close_windows", true);
user_pref("dom.disable_open_during_load", false);
user_pref("dom.max_script_run_time", 0);
user_pref("hangmonitor.timeout", 0);
user_pref("dom.max_chrome_script_run_time", 0);
user_pref("javascript.allow.mailnews", true);
user_pref("javascript.options.showInConsole", true);

View File

@ -3115,12 +3115,6 @@ pref("input_event_queue.default_duration_per_event", 1);
// required to process the following input events.
pref("input_event_queue.count_for_prediction", 9);
// Hang monitor timeout after which we kill the browser, in seconds
// (0 is disabled)
// Disabled on all platforms per bug 705748 until the found issues are
// resolved.
pref("hangmonitor.timeout", 0);
pref("plugins.load_appdir_plugins", false);
// If true, plugins will be click to play
pref("plugins.click_to_play", false);

View File

@ -92,9 +92,6 @@ class GeckoInstance(object):
# Do not scan Wifi
"geo.wifi.scan": False,
# No hang monitor
"hangmonitor.timeout": 0,
"javascript.options.showInConsole": True,
# Enable Marionette component

View File

@ -216,9 +216,6 @@ const RECOMMENDED_PREFS = new Map([
// Do not scan Wifi
["geo.wifi.scan", false],
// No hang monitor
["hangmonitor.timeout", 0],
// Show chrome errors and warnings in the error console
["javascript.options.showInConsole", true],

View File

@ -202,9 +202,9 @@ public:
// Stack of current hang
HangStack mHangStack;
// Annotations for the current hang
HangMonitor::HangAnnotations mAnnotations;
BackgroundHangAnnotations mAnnotations;
// Annotators registered for this thread
HangMonitor::Observer::Annotators mAnnotators;
BackgroundHangAnnotators mAnnotators;
// The name of the runnable which is hanging the current process
nsCString mRunnableName;
// The name of the thread which is being monitored
@ -488,12 +488,6 @@ BackgroundHangThread::ReportHang(TimeDuration aHangTime)
// Recovered from a hang; called on the monitor thread
// mManager->mLock IS locked
nsTArray<HangAnnotation> annotations;
for (auto& annotation : mAnnotations) {
HangAnnotation annot(annotation.mName, annotation.mValue);
annotations.AppendElement(std::move(annot));
}
HangDetails hangDetails(
aHangTime,
nsDependentCString(XRE_ChildProcessTypeToString(XRE_GetProcessType())),
@ -501,7 +495,7 @@ BackgroundHangThread::ReportHang(TimeDuration aHangTime)
mThreadName,
mRunnableName,
std::move(mHangStack),
std::move(annotations)
std::move(mAnnotations)
);
// If the hang processing thread exists, we can process the native stack
@ -767,7 +761,7 @@ BackgroundHangMonitor::NotifyWait()
}
bool
BackgroundHangMonitor::RegisterAnnotator(HangMonitor::Annotator& aAnnotator)
BackgroundHangMonitor::RegisterAnnotator(BackgroundHangAnnotator& aAnnotator)
{
#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
BackgroundHangThread* thisThread = BackgroundHangThread::FindThread();
@ -781,7 +775,7 @@ BackgroundHangMonitor::RegisterAnnotator(HangMonitor::Annotator& aAnnotator)
}
bool
BackgroundHangMonitor::UnregisterAnnotator(HangMonitor::Annotator& aAnnotator)
BackgroundHangMonitor::UnregisterAnnotator(BackgroundHangAnnotator& aAnnotator)
{
#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
BackgroundHangThread* thisThread = BackgroundHangThread::FindThread();

View File

@ -189,7 +189,7 @@ public:
* @param aAnnotator annotator to register
* @return true if the annotator was registered, otherwise false.
*/
static bool RegisterAnnotator(HangMonitor::Annotator& aAnnotator);
static bool RegisterAnnotator(BackgroundHangAnnotator& aAnnotator);
/**
* Unregister an annotator that was previously registered via
@ -197,7 +197,7 @@ public:
* @param aAnnotator annotator to unregister
* @return true if there are still remaining annotators registered
*/
static bool UnregisterAnnotator(HangMonitor::Annotator& aAnnotator);
static bool UnregisterAnnotator(BackgroundHangAnnotator& aAnnotator);
};
} // namespace mozilla

View File

@ -0,0 +1,102 @@
/* -*- 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"
#include "mozilla/BackgroundHangMonitor.h"
namespace mozilla {
void
BackgroundHangAnnotations::AddAnnotation(const nsString& aName, const int32_t aData)
{
nsAutoString dataString;
dataString.AppendInt(aData);
AppendElement(HangAnnotation(aName, dataString));
}
void
BackgroundHangAnnotations::AddAnnotation(const nsString& aName, const double aData)
{
nsAutoString dataString;
dataString.AppendFloat(aData);
AppendElement(HangAnnotation(aName, dataString));
}
void
BackgroundHangAnnotations::AddAnnotation(const nsString& aName, const nsString& aData)
{
AppendElement(HangAnnotation(aName, aData));
}
void
BackgroundHangAnnotations::AddAnnotation(const nsString& aName, const nsCString& aData)
{
NS_ConvertUTF8toUTF16 dataString(aData);
AppendElement(HangAnnotation(aName, dataString));
}
void
BackgroundHangAnnotations::AddAnnotation(const nsString& aName, const bool aData)
{
if (aData) {
AppendElement(HangAnnotation(aName, NS_LITERAL_STRING("true")));
} else {
AppendElement(HangAnnotation(aName, NS_LITERAL_STRING("false")));
}
}
BackgroundHangAnnotators::BackgroundHangAnnotators()
: mMutex("BackgroundHangAnnotators::mMutex")
{
MOZ_COUNT_CTOR(BackgroundHangAnnotators);
}
BackgroundHangAnnotators::~BackgroundHangAnnotators()
{
MOZ_ASSERT(mAnnotators.empty());
MOZ_COUNT_DTOR(BackgroundHangAnnotators);
}
bool
BackgroundHangAnnotators::Register(BackgroundHangAnnotator& aAnnotator)
{
MutexAutoLock lock(mMutex);
auto result = mAnnotators.insert(&aAnnotator);
return result.second;
}
bool
BackgroundHangAnnotators::Unregister(BackgroundHangAnnotator& aAnnotator)
{
MutexAutoLock lock(mMutex);
DebugOnly<std::set<BackgroundHangAnnotator*>::size_type> numErased;
numErased = mAnnotators.erase(&aAnnotator);
MOZ_ASSERT(numErased == 1);
return mAnnotators.empty();
}
BackgroundHangAnnotations
BackgroundHangAnnotators::GatherAnnotations()
{
BackgroundHangAnnotations annotations;
{ // Scope for lock
MutexAutoLock lock(mMutex);
for (std::set<BackgroundHangAnnotator*>::iterator i = mAnnotators.begin(),
e = mAnnotators.end();
i != e; ++i) {
(*i)->AnnotateHang(annotations);
}
}
return annotations;
}
} // namespace mozilla

View File

@ -0,0 +1,75 @@
/* -*- 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/. */
#ifndef mozilla_HangAnnotations_h
#define mozilla_HangAnnotations_h
#include <set>
#include "mozilla/HangTypes.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Mutex.h"
#include "mozilla/Vector.h"
#include "nsString.h"
#include "nsTArray.h"
#include "mozilla/ipc/IPDLParamTraits.h"
namespace mozilla {
/**
* This class extends nsTArray<HangAnnotation> with some methods for adding
* annotations being reported by a registered hang Annotator.
*/
class BackgroundHangAnnotations : public nsTArray<HangAnnotation>
{
public:
void AddAnnotation(const nsString& aName, const int32_t aData);
void AddAnnotation(const nsString& aName, const double aData);
void AddAnnotation(const nsString& aName, const nsString& aData);
void AddAnnotation(const nsString& aName, const nsCString& aData);
void AddAnnotation(const nsString& aName, const bool aData);
};
class BackgroundHangAnnotator
{
public:
/**
* NB: This function is always called by the BackgroundHangMonitor thread.
* Plan accordingly.
*/
virtual void AnnotateHang(BackgroundHangAnnotations& aAnnotations) = 0;
};
class BackgroundHangAnnotators
{
public:
BackgroundHangAnnotators();
~BackgroundHangAnnotators();
bool Register(BackgroundHangAnnotator& aAnnotator);
bool Unregister(BackgroundHangAnnotator& aAnnotator);
BackgroundHangAnnotations GatherAnnotations();
private:
Mutex mMutex;
std::set<BackgroundHangAnnotator*> mAnnotators;
};
namespace ipc {
template<>
struct IPDLParamTraits<mozilla::BackgroundHangAnnotations>
: public IPDLParamTraits<nsTArray<mozilla::HangAnnotation>>
{
typedef mozilla::BackgroundHangAnnotations paramType;
};
} // namespace ipc
} // namespace mozilla
#endif // mozilla_HangAnnotations_h

View File

@ -33,11 +33,13 @@ XPIDL_MODULE = 'backgroundhangmonitor'
EXPORTS.mozilla += [
'BackgroundHangMonitor.h',
'HangAnnotations.h',
'HangDetails.h',
]
UNIFIED_SOURCES += [
'BackgroundHangMonitor.cpp',
'HangAnnotations.cpp',
'HangDetails.cpp',
]

View File

@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CombinedStacks.h"
#include "HangAnnotations.h"
#include "mozilla/HangAnnotations.h"
#include "jsapi.h"

View File

@ -1,148 +0,0 @@
/* -*- 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 "HangReports.h"
namespace mozilla {
namespace Telemetry {
using namespace HangMonitor;
// This utility function generates a string key that is used to index the annotations
// in a hash map from |HangReports::AddHang|.
nsresult
ComputeAnnotationsKey(const HangAnnotations& aAnnotations, nsAString& aKeyOut)
{
if (aAnnotations.IsEmpty()) {
return NS_ERROR_FAILURE;
}
for (auto& annotation : aAnnotations) {
aKeyOut.Append(annotation.mName);
aKeyOut.Append(annotation.mValue);
}
return NS_OK;
}
#if defined(MOZ_GECKO_PROFILER)
/** The maximum number of stacks that we're keeping for hang reports. */
const size_t kMaxHangStacksKept = 50;
void
HangReports::AddHang(const Telemetry::ProcessedStack& aStack,
uint32_t aDuration,
int32_t aSystemUptime,
int32_t aFirefoxUptime,
HangAnnotations&& aAnnotations) {
// Append the new stack to the stack's circular queue.
size_t hangIndex = mStacks.AddStack(aStack);
// Append the hang info at the same index, in mHangInfo.
HangInfo info = { aDuration, aSystemUptime, aFirefoxUptime };
if (mHangInfo.size() < kMaxHangStacksKept) {
mHangInfo.push_back(info);
} else {
mHangInfo[hangIndex] = info;
// Remove any reference to the stack overwritten in the circular queue
// from the annotations.
PruneStackReferences(hangIndex);
}
nsAutoString annotationsKey;
// Generate a key to index aAnnotations in the hash map.
nsresult rv = ComputeAnnotationsKey(aAnnotations, annotationsKey);
if (NS_FAILED(rv)) {
return;
}
AnnotationInfo* annotationsEntry = mAnnotationInfo.Get(annotationsKey);
if (annotationsEntry) {
// If the key is already in the hash map, append the index of the chrome hang
// to its indices.
annotationsEntry->mHangIndices.AppendElement(hangIndex);
return;
}
// If the key was not found, add the annotations to the hash map.
mAnnotationInfo.Put(annotationsKey, new AnnotationInfo(hangIndex, std::move(aAnnotations)));
}
/**
* This function removes links to discarded chrome hangs stacks and prunes unused
* annotations.
*/
void
HangReports::PruneStackReferences(const size_t aRemovedStackIndex) {
// We need to adjust the indices that link annotations to chrome hangs. Since we
// removed a stack, we must remove all references to it and prune annotations
// linked to no stacks.
for (auto iter = mAnnotationInfo.Iter(); !iter.Done(); iter.Next()) {
nsTArray<uint32_t>& stackIndices = iter.Data()->mHangIndices;
size_t toRemove = stackIndices.NoIndex;
for (size_t k = 0; k < stackIndices.Length(); k++) {
// Is this index referencing the removed stack?
if (stackIndices[k] == aRemovedStackIndex) {
toRemove = k;
break;
}
}
// Remove the index referencing the old stack from the annotation.
if (toRemove != stackIndices.NoIndex) {
stackIndices.RemoveElementAt(toRemove);
}
// If this annotation no longer references any stack, drop it.
if (!stackIndices.Length()) {
iter.Remove();
}
}
}
#endif
size_t
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.ShallowSizeOfExcludingThis(aMallocSizeOf);
n += mAnnotationInfo.Count() * sizeof(AnnotationInfo);
for (auto iter = mAnnotationInfo.ConstIter(); !iter.Done(); iter.Next()) {
n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
auto& annotations = iter.Data()->mAnnotations;
n += annotations.ShallowSizeOfExcludingThis(aMallocSizeOf);
}
return n;
}
const CombinedStacks&
HangReports::GetStacks() const {
return mStacks;
}
uint32_t
HangReports::GetDuration(unsigned aIndex) const {
return mHangInfo[aIndex].mDuration;
}
int32_t
HangReports::GetSystemUptime(unsigned aIndex) const {
return mHangInfo[aIndex].mSystemUptime;
}
int32_t
HangReports::GetFirefoxUptime(unsigned aIndex) const {
return mHangInfo[aIndex].mFirefoxUptime;
}
const nsClassHashtable<nsStringHashKey, HangReports::AnnotationInfo>&
HangReports::GetAnnotationInfo() const {
return mAnnotationInfo;
}
} // namespace Telemetry
} // namespace mozilla

View File

@ -1,90 +0,0 @@
/* -*- Mode: C++; tab-width: 2; 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/. */
#ifndef HangReports_h__
#define HangReports_h__
#include <vector>
#include "mozilla/HangAnnotations.h"
#include "ProcessedStack.h"
#include "nsTArray.h"
#include "nsString.h"
#include "nsClassHashtable.h"
#include "CombinedStacks.h"
namespace mozilla {
namespace Telemetry {
nsresult
ComputeAnnotationsKey(const HangMonitor::HangAnnotations& aAnnotations, nsAString& aKeyOut);
class HangReports {
public:
/**
* This struct encapsulates information for an individual ChromeHang annotation.
* mHangIndex is the index of the corresponding ChromeHang.
*/
struct AnnotationInfo {
AnnotationInfo(uint32_t aHangIndex,
HangMonitor::HangAnnotations&& aAnnotations)
: mAnnotations(std::move(aAnnotations))
{
mHangIndices.AppendElement(aHangIndex);
}
AnnotationInfo(AnnotationInfo&& aOther)
: mHangIndices(aOther.mHangIndices)
, mAnnotations(std::move(aOther.mAnnotations))
{}
~AnnotationInfo() = default;
AnnotationInfo& operator=(AnnotationInfo&& aOther)
{
mHangIndices = aOther.mHangIndices;
mAnnotations = std::move(aOther.mAnnotations);
return *this;
}
// To save memory, a single AnnotationInfo can be associated to multiple chrome
// hangs. The following array holds the index of each related chrome hang.
nsTArray<uint32_t> mHangIndices;
HangMonitor::HangAnnotations mAnnotations;
private:
// Force move constructor
AnnotationInfo(const AnnotationInfo& aOther) = delete;
void operator=(const AnnotationInfo& aOther) = delete;
};
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
#if defined(MOZ_GECKO_PROFILER)
void AddHang(const Telemetry::ProcessedStack& aStack, uint32_t aDuration,
int32_t aSystemUptime, int32_t aFirefoxUptime,
HangMonitor::HangAnnotations&& aAnnotations);
void PruneStackReferences(const size_t aRemovedStackIndex);
#endif
uint32_t GetDuration(unsigned aIndex) const;
int32_t GetSystemUptime(unsigned aIndex) const;
int32_t GetFirefoxUptime(unsigned aIndex) const;
const nsClassHashtable<nsStringHashKey, 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;
// System uptime (in minutes) at the time of the hang
int32_t mSystemUptime;
// Firefox uptime (in minutes) at the time of the hang
int32_t mFirefoxUptime;
};
std::vector<HangInfo> mHangInfo;
nsClassHashtable<nsStringHashKey, AnnotationInfo> mAnnotationInfo;
CombinedStacks mStacks;
};
} // namespace Telemetry
} // namespace mozilla
#endif // CombinedStacks_h__

View File

@ -82,13 +82,11 @@
#include "mozilla/IOInterposer.h"
#include "mozilla/PoisonIOInterposer.h"
#include "mozilla/StartupTimeline.h"
#include "mozilla/HangMonitor.h"
#if defined(XP_WIN)
#include "mozilla/WinDllServices.h"
#endif
#include "nsNativeCharsetUtils.h"
#include "nsProxyRelease.h"
#include "HangReports.h"
#if defined(MOZ_GECKO_PROFILER)
#include "shared-libraries.h"
@ -102,7 +100,6 @@
namespace {
using namespace mozilla;
using namespace mozilla::HangMonitor;
using Telemetry::Common::AutoHashtable;
using Telemetry::Common::ToJSString;
using Telemetry::Common::GetCurrentProduct;
@ -110,9 +107,7 @@ using Telemetry::Common::SetCurrentProduct;
using Telemetry::Common::SupportedProduct;
using mozilla::dom::Promise;
using mozilla::dom::AutoJSAPI;
using mozilla::Telemetry::HangReports;
using mozilla::Telemetry::CombinedStacks;
using mozilla::Telemetry::ComputeAnnotationsKey;
using mozilla::Telemetry::TelemetryIOInterposeObserver;
#if defined(MOZ_GECKO_PROFILER)
@ -149,13 +144,6 @@ public:
static void ShutdownTelemetry();
static void RecordSlowStatement(const nsACString &sql, const nsACString &dbName,
uint32_t delay);
#if defined(MOZ_GECKO_PROFILER)
static void RecordChromeHang(uint32_t aDuration,
Telemetry::ProcessedStack &aStack,
int32_t aSystemUptime,
int32_t aFirefoxUptime,
HangAnnotations&& aAnnotations);
#endif
#if defined(MOZ_GECKO_PROFILER)
static void DoStackCapture(const nsACString& aKey);
#endif
@ -205,8 +193,6 @@ private:
AutoHashtable<SlowSQLEntryType> mPrivateSQL;
AutoHashtable<SlowSQLEntryType> mSanitizedSQL;
Mutex mHashMutex;
HangReports mHangReports;
Mutex mHangReportsMutex;
Atomic<bool> mCanRecordBase;
Atomic<bool> mCanRecordExtended;
@ -495,7 +481,6 @@ TelemetryImpl::AsyncFetchTelemetryData(nsIFetchTelemetryDataCallback *aCallback)
TelemetryImpl::TelemetryImpl()
: mHashMutex("Telemetry::mHashMutex")
, mHangReportsMutex("Telemetry::mHangReportsMutex")
, mCanRecordBase(false)
, mCanRecordExtended(false)
, mCachedTelemetryData(false)
@ -513,7 +498,6 @@ TelemetryImpl::~TelemetryImpl() {
// This is still racey as access to these collections is guarded using sTelemetry.
// We will fix this in bug 1367344.
MutexAutoLock hashLock(mHashMutex);
MutexAutoLock hangReportsLock(mHangReportsMutex);
}
void
@ -652,122 +636,6 @@ TelemetryImpl::GetMaximalNumberOfConcurrentThreads(uint32_t *ret)
return NS_OK;
}
NS_IMETHODIMP
TelemetryImpl::GetChromeHangs(JSContext *cx, JS::MutableHandle<JS::Value> ret)
{
MutexAutoLock hangReportMutex(mHangReportsMutex);
const CombinedStacks& stacks = mHangReports.GetStacks();
JS::Rooted<JSObject*> fullReportObj(cx, CreateJSStackObject(cx, stacks));
if (!fullReportObj) {
return NS_ERROR_FAILURE;
}
ret.setObject(*fullReportObj);
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));
JS::Rooted<JSObject*> annotationsArray(cx, JS_NewArrayObject(cx, 0));
if (!durationArray || !systemUptimeArray || !firefoxUptimeArray ||
!annotationsArray) {
return NS_ERROR_FAILURE;
}
bool ok = JS_DefineProperty(cx, fullReportObj, "durations",
durationArray, JSPROP_ENUMERATE);
if (!ok) {
return NS_ERROR_FAILURE;
}
ok = JS_DefineProperty(cx, fullReportObj, "systemUptime",
systemUptimeArray, JSPROP_ENUMERATE);
if (!ok) {
return NS_ERROR_FAILURE;
}
ok = JS_DefineProperty(cx, fullReportObj, "firefoxUptime",
firefoxUptimeArray, JSPROP_ENUMERATE);
if (!ok) {
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_DefineElement(cx, durationArray, i, mHangReports.GetDuration(i),
JSPROP_ENUMERATE)) {
return NS_ERROR_FAILURE;
}
if (!JS_DefineElement(cx, systemUptimeArray, i, mHangReports.GetSystemUptime(i),
JSPROP_ENUMERATE)) {
return NS_ERROR_FAILURE;
}
if (!JS_DefineElement(cx, firefoxUptimeArray, i, mHangReports.GetFirefoxUptime(i),
JSPROP_ENUMERATE)) {
return NS_ERROR_FAILURE;
}
size_t annotationIndex = 0;
const nsClassHashtable<nsStringHashKey, HangReports::AnnotationInfo>& annotationInfo =
mHangReports.GetAnnotationInfo();
for (auto iter = annotationInfo.ConstIter(); !iter.Done(); iter.Next()) {
const HangReports::AnnotationInfo* info = iter.Data();
JS::Rooted<JSObject*> keyValueArray(cx, JS_NewArrayObject(cx, 0));
if (!keyValueArray) {
return NS_ERROR_FAILURE;
}
// Create an array containing all the indices of the chrome hangs relative to this
// annotation.
JS::Rooted<JS::Value> indicesArray(cx);
if (!mozilla::dom::ToJSValue(cx, info->mHangIndices, &indicesArray)) {
return NS_ERROR_OUT_OF_MEMORY;
}
// We're saving the annotation as [[indices], {annotation-data}], so add the indices
// array as the first element of that structure.
if (!JS_DefineElement(cx, keyValueArray, 0, indicesArray, JSPROP_ENUMERATE)) {
return NS_ERROR_FAILURE;
}
// Create the annotations object...
JS::Rooted<JSObject*> jsAnnotation(cx, JS_NewPlainObject(cx));
if (!jsAnnotation) {
return NS_ERROR_FAILURE;
}
for (auto& annot : info->mAnnotations) {
JS::RootedValue jsValue(cx);
jsValue.setString(JS_NewUCStringCopyN(cx, annot.mValue.get(), annot.mValue.Length()));
if (!JS_DefineUCProperty(cx, jsAnnotation, annot.mName.get(), annot.mName.Length(),
jsValue, JSPROP_ENUMERATE)) {
return NS_ERROR_FAILURE;
}
}
// ... and append it after the indices array.
if (!JS_DefineElement(cx, keyValueArray, 1, jsAnnotation, JSPROP_ENUMERATE)) {
return NS_ERROR_FAILURE;
}
if (!JS_DefineElement(cx, annotationsArray, annotationIndex++,
keyValueArray, JSPROP_ENUMERATE)) {
return NS_ERROR_FAILURE;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
TelemetryImpl::SnapshotCapturedStacks(bool clear, JSContext *cx, JS::MutableHandle<JS::Value> ret)
{
@ -1587,22 +1455,6 @@ TelemetryImpl::RecordIceCandidates(const uint32_t iceCandidateBitmask,
}
#if defined(MOZ_GECKO_PROFILER)
void
TelemetryImpl::RecordChromeHang(uint32_t aDuration,
Telemetry::ProcessedStack &aStack,
int32_t aSystemUptime,
int32_t aFirefoxUptime,
HangAnnotations&& aAnnotations)
{
if (!sTelemetry || !TelemetryHistogram::CanRecordExtended())
return;
MutexAutoLock hangReportMutex(sTelemetry->mHangReportsMutex);
sTelemetry->mHangReports.AddHang(aStack, aDuration,
aSystemUptime, aFirefoxUptime,
std::move(aAnnotations));
}
void
TelemetryImpl::DoStackCapture(const nsACString& aKey) {
@ -1899,10 +1751,6 @@ TelemetryImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
n += mPrivateSQL.SizeOfExcludingThis(aMallocSizeOf);
n += mSanitizedSQL.SizeOfExcludingThis(aMallocSizeOf);
}
{ // Scope for mHangReportsMutex lock
MutexAutoLock lock(mHangReportsMutex);
n += mHangReports.SizeOfExcludingThis(aMallocSizeOf);
}
// It's a bit gross that we measure this other stuff that lives outside of
// TelemetryImpl... oh well.
@ -2160,22 +2008,9 @@ void Init()
}
#if defined(MOZ_GECKO_PROFILER)
void RecordChromeHang(uint32_t duration,
ProcessedStack &aStack,
int32_t aSystemUptime,
int32_t aFirefoxUptime,
HangAnnotations&& aAnnotations)
{
TelemetryImpl::RecordChromeHang(duration, aStack,
aSystemUptime, aFirefoxUptime,
std::move(aAnnotations));
}
void CaptureStack(const nsACString& aKey)
{
#ifdef MOZ_GECKO_PROFILER
TelemetryImpl::DoStackCapture(aKey);
#endif
}
#endif

View File

@ -29,9 +29,6 @@
*****************************************************************************/
namespace mozilla {
namespace HangMonitor {
class HangAnnotations;
} // namespace HangMonitor
namespace Telemetry {
struct HistogramAccumulation;
@ -488,12 +485,6 @@ class ProcessedStack;
* @param aAnnotations - Any annotations to be added to the report
*/
#if defined(MOZ_GECKO_PROFILER)
void RecordChromeHang(uint32_t aDuration,
ProcessedStack &aStack,
int32_t aSystemUptime,
int32_t aFirefoxUptime,
mozilla::HangMonitor::HangAnnotations&& aAnnotations);
/**
* Record the current thread's call stack on demand. Note that, the stack is
* only captured once. Subsequent calls result in incrementing the capture

View File

@ -1130,7 +1130,6 @@ var Impl = {
// Add extended set measurements common to chrome & content processes
if (Telemetry.canRecordExtended) {
payloadObj.chromeHangs = protect(() => Telemetry.chromeHangs);
payloadObj.log = [];
payloadObj.webrtc = protect(() => Telemetry.webrtcStats);
}

View File

@ -61,7 +61,7 @@ Structure:
// The following properties may all be null if we fail to collect them.
histograms: {...},
keyedHistograms: {...},
chromeHangs: {...},
chromeHangs: {...}, // removed in firefox 62
threadHangStats: [...], // obsolete in firefox 57, use the 'bhr' ping
capturedStacks: {...},
log: [...], // obsolete in firefox 61, use Event Telemetry or Scalars
@ -349,6 +349,9 @@ Structure:
chromeHangs
-----------
As of Firefox 62, chromeHangs has been removed. Please look to the bhr ping for
similar functionality.
Contains the statistics about the hangs happening exclusively on the main thread of the parent process. Precise C++ stacks are reported. This is only available on Nightly Release on Windows, when building using "--enable-profiling" switch.
Some limits are applied:

View File

@ -64,7 +64,6 @@ EXPORTS.mozilla += [
SOURCES += [
'CombinedStacks.cpp',
'geckoview/TelemetryGeckoViewPersistence.cpp',
'HangReports.cpp',
'ipc/TelemetryIPC.cpp',
'ipc/TelemetryIPCAccumulator.cpp',
'ProcessedStack.cpp',

View File

@ -128,14 +128,6 @@ interface nsITelemetry : nsISupports
*/
readonly attribute uint32_t maximalNumberOfConcurrentThreads;
/*
* An array of chrome hang reports. Each element is a hang report represented
* as an object containing the hang duration, call stack PCs and information
* about modules in memory.
*/
[implicit_jscontext]
readonly attribute jsval chromeHangs;
/*
* Record the current thread's call stack on demand. Note that, the stack is
* only captured at the first call. All subsequent calls result in incrementing

View File

@ -1829,7 +1829,7 @@ add_task(async function test_schedulerNothingDue() {
add_task(async function test_pingExtendedStats() {
const EXTENDED_PAYLOAD_FIELDS = [
"chromeHangs", "log", "slowSQL", "fileIOReports", "lateWrites",
"log", "slowSQL", "fileIOReports", "lateWrites",
"addonDetails", "webrtc"
];

View File

@ -999,32 +999,6 @@ function SymbolicationRequest_fetchSymbols() {
this.symbolRequest.send(requestJSON);
};
var ChromeHangs = {
symbolRequest: null,
/**
* Renders raw chrome hang data
*/
render: function ChromeHangs_render(chromeHangs) {
setHasData("chrome-hangs-section", !!chromeHangs);
if (!chromeHangs) {
return;
}
let stacks = chromeHangs.stacks;
let memoryMap = chromeHangs.memoryMap;
let durations = chromeHangs.durations;
StackRenderer.renderStacks("chrome-hangs", stacks, memoryMap,
(index) => this.renderHangHeader(index, durations));
},
renderHangHeader: function ChromeHangs_renderHangHeader(aIndex, aDurations) {
StackRenderer.renderHeader("chrome-hangs", [aIndex + 1, aDurations[aIndex]]);
}
};
var CapturedStacks = {
symbolRequest: null,
@ -1227,7 +1201,6 @@ var Search = {
// A list of ids of sections that do not support search.
blacklist: [
"late-writes-section",
"chrome-hangs-section",
"raw-payload-section"
],
@ -1994,30 +1967,6 @@ function setupListeners() {
Settings.detachObservers();
}, {once: true});
document.getElementById("chrome-hangs-fetch-symbols").addEventListener("click",
function() {
if (!gPingData) {
return;
}
let hangs = gPingData.payload.chromeHangs;
let req = new SymbolicationRequest("chrome-hangs",
ChromeHangs.renderHangHeader,
hangs.memoryMap,
hangs.stacks,
hangs.durations);
req.fetchSymbols();
});
document.getElementById("chrome-hangs-hide-symbols").addEventListener("click",
function() {
if (!gPingData) {
return;
}
ChromeHangs.render(gPingData.payload.chromeHangs);
});
document.getElementById("captured-stacks-fetch-symbols").addEventListener("click",
function() {
if (!gPingData) {
@ -2406,9 +2355,6 @@ function displayRichPingData(ping, updatePayloadList) {
LateWritesSingleton.renderLateWrites(payload.lateWrites);
// Show chrome hang stacks
ChromeHangs.render(payload.chromeHangs);
// Show simple measurements
SimpleMeasurements.render(payload);

View File

@ -66,9 +66,6 @@
<div class="category" value="slow-sql-section">
<span class="category-name">&aboutTelemetry.slowSqlSection;</span>
</div>
<div class="category" value="chrome-hangs-section">
<span class="category-name">&aboutTelemetry.chromeHangsSection;</span>
</div>
<div class="category" value="addon-details-section">
<span class="category-name">&aboutTelemetry.addonDetailsSection;</span>
</div>
@ -194,12 +191,6 @@
<div id="slow-sql-tables" class="data"></div>
</section>
<section id="chrome-hangs-section">
<a id="chrome-hangs-fetch-symbols" href="">&aboutTelemetry.fetchStackSymbols;</a>
<a id="chrome-hangs-hide-symbols" href="">&aboutTelemetry.hideStackSymbols;</a>
<div id="chrome-hangs" class="data"></div>
</section>
<section id="late-writes-section">
<a id="late-writes-fetch-symbols" href="">&aboutTelemetry.fetchStackSymbols;</a>
<a id="late-writes-hide-symbols" href="">&aboutTelemetry.hideStackSymbols;</a>

View File

@ -199,14 +199,6 @@ unit. Before submission, the filenames of the files are linked:
- **uuid.dmp** - *plugin process dump file*
- **uuid-<other>.dmp** - *other process dump file as listed in additional_minidumps*
Browser Hangs
=============
There is a feature of Firefox that will crash Firefox if it stops processing
messages after a certain period of time. This feature doesn't work well and is
disabled by default. See ``xpcom/threads/HangMonitor.cpp``. Hang crashes
are annotated with ``Hang=1``.
about:crashes
=============

View File

@ -37,7 +37,6 @@
<!ENTITY aboutTelemetry.eventsSection "Events">
<!ENTITY aboutTelemetry.simpleMeasurementsSection "Simple Measurements">
<!ENTITY aboutTelemetry.slowSqlSection "Slow SQL Statements">
<!ENTITY aboutTelemetry.chromeHangsSection "Browser Hangs">
<!ENTITY aboutTelemetry.addonDetailsSection "Add-on Details">
<!ENTITY aboutTelemetry.capturedStacksSection "Captured Stacks">
<!ENTITY aboutTelemetry.lateWritesSection "Late Writes">

View File

@ -81,10 +81,6 @@ keysHeader = Property
namesHeader = Name
valuesHeader = Value
# LOCALIZATION NOTE(chrome-hangs-title):
# - %1$S is replaced by the number of the hang
# - %2$S is replaced by the duration of the hang
chrome-hangs-title = Hang Report #%1$S (%2$S seconds)
# LOCALIZATION NOTE(captured-stacks-title):
# - %1$S is replaced by the string key for this stack
# - %2$S is replaced by the number of times this stack was captured

View File

@ -145,15 +145,15 @@ public:
{
explicit IMEEvent(Functor&& l) : nsAppShell::LambdaEvent<Functor>(std::move(l)) {}
nsAppShell::Event::Type ActivityType() const override
bool IsUIEvent() const override
{
using GES = GeckoEditableSupport;
if (this->lambda.IsTarget(&GES::OnKeyEvent) ||
this->lambda.IsTarget(&GES::OnImeReplaceText) ||
this->lambda.IsTarget(&GES::OnImeUpdateComposition)) {
return nsAppShell::Event::Type::kUIActivity;
return true;
}
return nsAppShell::Event::Type::kGeneralActivity;
return false;
}
void Run() override

View File

@ -19,6 +19,8 @@ UNIFIED_SOURCES += [
'Utils.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [

View File

@ -741,7 +741,7 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
AUTO_PROFILER_LABEL("nsAppShell::ProcessNextNativeEvent:Wait",
IDLE);
mozilla::HangMonitor::Suspend();
mozilla::BackgroundHangMonitor().NotifyWait();
curEvent = mEventQueue.Pop(/* mayWait */ true);
}
@ -750,7 +750,7 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
if (!curEvent)
return false;
mozilla::HangMonitor::NotifyActivity(curEvent->ActivityType());
mozilla::BackgroundHangMonitor().NotifyActivity();
curEvent->Run();
return true;

View File

@ -8,7 +8,7 @@
#include <time.h>
#include "mozilla/HangMonitor.h"
#include "mozilla/BackgroundHangMonitor.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Monitor.h"
#include "mozilla/Move.h"
@ -36,8 +36,6 @@ class nsAppShell :
public:
struct Event : mozilla::LinkedListElement<Event>
{
typedef mozilla::HangMonitor::ActivityType Type;
static uint64_t GetTime()
{
timespec time;
@ -64,9 +62,9 @@ public:
queue.insertBack(this);
}
virtual Type ActivityType() const
virtual bool IsUIEvent() const
{
return Type::kGeneralActivity;
return false;
}
};
@ -248,8 +246,7 @@ protected:
}
#ifdef EARLY_BETA_OR_EARLIER
const size_t latencyType = (event->ActivityType() ==
Event::Type::kUIActivity) ? LATENCY_UI : LATENCY_OTHER;
const size_t latencyType = event->IsUIEvent() ? LATENCY_UI : LATENCY_OTHER;
const uint64_t latency = Event::GetTime() - event->mPostTime;
sLatencyCount[latencyType]++;

View File

@ -353,9 +353,9 @@ class nsWindow::NPZCSupport final
return mLambda(window);
}
nsAppShell::Event::Type ActivityType() const override
bool IsUIEvent() const override
{
return nsAppShell::Event::Type::kUIActivity;
return true;
}
};

View File

@ -30,7 +30,7 @@
#include "nsChildView.h"
#include "nsToolkit.h"
#include "TextInputHandler.h"
#include "mozilla/HangMonitor.h"
#include "mozilla/BackgroundHangMonitor.h"
#include "GeckoProfiler.h"
#include "ScreenHelperCocoa.h"
#include "mozilla/widget/ScreenManager.h"
@ -136,7 +136,8 @@ static bool gAppShellMethodsSwizzled = false;
// into non-idle code. So we basically unset the IDLE category from the inside.
AUTO_PROFILER_LABEL("-[GeckoNSApplication sendEvent:]", OTHER);
mozilla::HangMonitor::NotifyActivity();
mozilla::BackgroundHangMonitor().NotifyActivity();
if ([anEvent type] == NSApplicationDefined &&
[anEvent subtype] == kEventSubtypeTrace) {
mozilla::SignalTracerThread();
@ -172,12 +173,12 @@ static bool gAppShellMethodsSwizzled = false;
AUTO_PROFILER_LABEL("-[GeckoNSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]", IDLE);
if (expiration) {
mozilla::HangMonitor::Suspend();
mozilla::BackgroundHangMonitor().NotifyWait();
}
NSEvent* nextEvent = [super nextEventMatchingMask:mask
untilDate:expiration inMode:mode dequeue:flag];
if (expiration) {
mozilla::HangMonitor::NotifyActivity();
mozilla::BackgroundHangMonitor().NotifyActivity();
}
return nextEvent;
}
@ -613,7 +614,7 @@ nsAppShell::ProcessNextNativeEvent(bool aMayWait)
EventTargetRef eventDispatcherTarget = GetEventDispatcherTarget();
if (aMayWait) {
mozilla::HangMonitor::Suspend();
mozilla::BackgroundHangMonitor().NotifyWait();
}
// Only call -[NSApp sendEvent:] (and indirectly send user-input events to
@ -639,7 +640,7 @@ nsAppShell::ProcessNextNativeEvent(bool aMayWait)
inMode:currentMode
dequeue:YES];
if (nextEvent) {
mozilla::HangMonitor::NotifyActivity();
mozilla::BackgroundHangMonitor().NotifyActivity();
[NSApp sendEvent:nextEvent];
eventProcessed = true;
}

View File

@ -14,7 +14,7 @@
#include "nsWindow.h"
#include "mozilla/Logging.h"
#include "prenv.h"
#include "mozilla/HangMonitor.h"
#include "mozilla/BackgroundHangMonitor.h"
#include "mozilla/Unused.h"
#include "mozilla/WidgetUtils.h"
#include "GeckoProfiler.h"
@ -46,14 +46,14 @@ static GPollFunc sPollFunc;
static gint
PollWrapper(GPollFD *ufds, guint nfsd, gint timeout_)
{
mozilla::HangMonitor::Suspend();
mozilla::BackgroundHangMonitor().NotifyWait();
gint result;
{
AUTO_PROFILER_LABEL("PollWrapper", IDLE);
AUTO_PROFILER_THREAD_SLEEP;
result = (*sPollFunc)(ufds, nfsd, timeout_);
}
mozilla::HangMonitor::NotifyActivity();
mozilla::BackgroundHangMonitor().NotifyActivity();
return result;
}

View File

@ -15,10 +15,10 @@
#include "nsWindowDefs.h"
#include "KeyboardLayout.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/BackgroundHangMonitor.h"
#include "mozilla/dom/MouseEventBinding.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/HangMonitor.h"
#include "mozilla/Preferences.h"
#include "mozilla/RefPtr.h"
#include "mozilla/WindowsVersion.h"
@ -764,7 +764,7 @@ WinUtils::WaitForMessage(DWORD aTimeoutMs)
// We executed an APC that would have woken up the hang monitor. Since
// there are no more APCs pending and we are now going to sleep again,
// we should notify the hang monitor.
mozilla::HangMonitor::Suspend();
mozilla::BackgroundHangMonitor().NotifyWait();
}
continue;
}

View File

@ -15,7 +15,7 @@
#include "nsString.h"
#include "WinIMEHandler.h"
#include "mozilla/widget/AudioSession.h"
#include "mozilla/HangMonitor.h"
#include "mozilla/BackgroundHangMonitor.h"
#include "nsIDOMWakeLockListener.h"
#include "nsIPowerManagerService.h"
#include "mozilla/StaticPtr.h"
@ -529,9 +529,7 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
} else {
// If we had UI activity we would be processing it now so we know we
// have either kUIActivity or kActivityNoUIAVail.
mozilla::HangMonitor::NotifyActivity(
uiMessage ? mozilla::HangMonitor::kUIActivity :
mozilla::HangMonitor::kActivityNoUIAVail);
mozilla::BackgroundHangMonitor().NotifyActivity();
if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST &&
IMEHandler::ProcessRawKeyMessage(msg)) {
@ -552,7 +550,7 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
}
} else if (mayWait) {
// Block and wait for any posted application message
mozilla::HangMonitor::Suspend();
mozilla::BackgroundHangMonitor().NotifyWait();
{
AUTO_PROFILER_LABEL("nsAppShell::ProcessNextNativeEvent::Wait", IDLE);
AUTO_PROFILER_THREAD_SLEEP;

View File

@ -182,7 +182,7 @@
#include "nsIContent.h"
#include "mozilla/HangMonitor.h"
#include "mozilla/BackgroundHangMonitor.h"
#include "WinIMEHandler.h"
#include "npapi.h"
@ -4957,20 +4957,6 @@ DisplaySystemMenu(HWND hWnd, nsSizeMode sizeMode, bool isRtl, int32_t x, int32_t
return false;
}
inline static mozilla::HangMonitor::ActivityType ActivityTypeForMessage(UINT msg)
{
if ((msg >= WM_KEYFIRST && msg <= WM_IME_KEYLAST) ||
(msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) ||
(msg >= MOZ_WM_MOUSEWHEEL_FIRST && msg <= MOZ_WM_MOUSEWHEEL_LAST) ||
(msg >= NS_WM_IMEFIRST && msg <= NS_WM_IMELAST)) {
return mozilla::HangMonitor::kUIActivity;
}
// This may not actually be right, but we don't want to reset the timer if
// we're not actually processing a UI message.
return mozilla::HangMonitor::kActivityUIAVail;
}
// The WndProc procedure for all nsWindows in this toolkit. This merely catches
// exceptions and passes the real work to WindowProcInternal. See bug 587406
// and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx
@ -4978,7 +4964,7 @@ LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
{
mozilla::ipc::CancelCPOWs();
HangMonitor::NotifyActivity(ActivityTypeForMessage(msg));
BackgroundHangMonitor().NotifyActivity();
return mozilla::CallWindowProcCrashProtected(WindowProcInternal, hWnd, msg, wParam, lParam);
}

View File

@ -107,7 +107,6 @@ extern nsresult nsStringInputStreamConstructor(nsISupports*, REFNSIID, void**);
#include <locale.h>
#include "mozilla/Services.h"
#include "mozilla/Omnijar.h"
#include "mozilla/HangMonitor.h"
#include "mozilla/ScriptPreloader.h"
#include "mozilla/SystemGroup.h"
#include "mozilla/Telemetry.h"
@ -739,7 +738,6 @@ NS_InitXPCOM2(nsIServiceManager** aResult,
mozilla::Telemetry::Init();
mozilla::HangMonitor::Startup();
mozilla::BackgroundHangMonitor::Startup();
const MessageLoop* const loop = MessageLoop::current();
@ -798,7 +796,6 @@ NS_InitMinimalXPCOM()
SharedThreadPool::InitStatics();
mozilla::Telemetry::Init();
mozilla::HangMonitor::Startup();
mozilla::BackgroundHangMonitor::Startup();
return NS_OK;
@ -864,7 +861,7 @@ nsresult
ShutdownXPCOM(nsIServiceManager* aServMgr)
{
// Make sure the hang monitor is enabled for shutdown.
HangMonitor::NotifyActivity();
BackgroundHangMonitor().NotifyActivity();
if (!NS_IsMainThread()) {
MOZ_CRASH("Shutdown on wrong thread");
@ -937,7 +934,7 @@ ShutdownXPCOM(nsIServiceManager* aServMgr)
NS_ProcessPendingEvents(thread);
HangMonitor::NotifyActivity();
BackgroundHangMonitor().NotifyActivity();
// Late-write checks needs to find the profile directory, so it has to
// be initialized before mozilla::services::Shutdown or (because of
@ -1090,7 +1087,6 @@ ShutdownXPCOM(nsIServiceManager* aServMgr)
Omnijar::CleanUp();
HangMonitor::Shutdown();
BackgroundHangMonitor::Shutdown();
delete sMainHangMonitor;

View File

@ -187,7 +187,7 @@ CPUUsageWatcher::Init()
CPUUsageWatcher* self = this;
NS_DispatchToMainThread(
NS_NewRunnableFunction("CPUUsageWatcher::Init",
[=]() { HangMonitor::RegisterAnnotator(*self); }));
[=]() { BackgroundHangMonitor::RegisterAnnotator(*self); }));
return Ok();
}
@ -196,7 +196,7 @@ void
CPUUsageWatcher::Uninit()
{
if (mInitialized) {
HangMonitor::UnregisterAnnotator(*this);
BackgroundHangMonitor::UnregisterAnnotator(*this);
}
mInitialized = false;
}
@ -239,7 +239,7 @@ CPUUsageWatcher::CollectCPUUsage()
}
void
CPUUsageWatcher::AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) {
CPUUsageWatcher::AnnotateHang(BackgroundHangAnnotations& aAnnotations) {
if (!mInitialized) {
return;
}
@ -265,7 +265,7 @@ CPUUsageWatcher::CollectCPUUsage()
return Ok();
}
void CPUUsageWatcher::AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) {}
void CPUUsageWatcher::AnnotateHang(BackgroundHangAnnotations& aAnnotations) {}
#endif // CPU_USAGE_WATCHER_ACTIVE

View File

@ -10,6 +10,7 @@
#include <stdint.h>
#include "mozilla/HangAnnotations.h"
#include "mozilla/BackgroundHangMonitor.h"
// We only support OSX and Windows, because on Linux we're forced to read
// from /proc/stat in order to get global CPU values. We would prefer to not
@ -31,13 +32,13 @@ enum CPUUsageWatcherError : uint8_t
};
class CPUUsageHangAnnotator
: public HangMonitor::Annotator
: public BackgroundHangAnnotator
{
public:
};
class CPUUsageWatcher
: public HangMonitor::Annotator
: public BackgroundHangAnnotator
{
public:
#ifdef CPU_USAGE_WATCHER_ACTIVE
@ -62,7 +63,7 @@ public:
// usage values between now and the last time it was called.
Result<Ok, CPUUsageWatcherError> CollectCPUUsage();
void AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) final;
void AnnotateHang(BackgroundHangAnnotations& aAnnotations) final;
private:
#ifdef CPU_USAGE_WATCHER_ACTIVE
bool mInitialized;

View File

@ -1,175 +0,0 @@
/* -*- 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"
#include "mozilla/BackgroundHangMonitor.h"
namespace mozilla {
namespace HangMonitor {
// Chrome hang annotators. This can go away once BHR has completely replaced
// ChromeHangs.
static StaticAutoPtr<Observer::Annotators> gChromehangAnnotators;
void
HangAnnotations::AddAnnotation(const nsAString& aName, const int32_t aData)
{
nsAutoString dataString;
dataString.AppendInt(aData);
AppendElement(Annotation(aName, dataString));
}
void
HangAnnotations::AddAnnotation(const nsAString& aName, const double aData)
{
nsAutoString dataString;
dataString.AppendFloat(aData);
AppendElement(Annotation(aName, dataString));
}
void
HangAnnotations::AddAnnotation(const nsAString& aName, const nsAString& aData)
{
AppendElement(Annotation(aName, aData));
}
void
HangAnnotations::AddAnnotation(const nsAString& aName, const nsACString& aData)
{
NS_ConvertUTF8toUTF16 dataString(aData);
AppendElement(Annotation(aName, dataString));
}
void
HangAnnotations::AddAnnotation(const nsAString& aName, const bool aData)
{
if (aData) {
AppendElement(Annotation(aName, NS_LITERAL_STRING("true")));
} else {
AppendElement(Annotation(aName, NS_LITERAL_STRING("false")));
}
}
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();
}
HangAnnotations
Annotators::GatherAnnotations()
{
HangAnnotations annotations;
{ // Scope for lock
MutexAutoLock lock(mMutex);
for (std::set<Annotator*>::iterator i = mAnnotators.begin(),
e = mAnnotators.end();
i != e; ++i) {
(*i)->AnnotateHang(annotations);
}
}
return 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;
}
}
}
HangAnnotations
ChromeHangAnnotatorCallout()
{
if (!gChromehangAnnotators) {
return HangAnnotations();
}
return gChromehangAnnotators->GatherAnnotations();
}
} // namespace HangMonitor
} // namespace mozilla
namespace IPC {
using mozilla::HangMonitor::Annotation;
void
ParamTraits<Annotation>::Write(Message* aMsg, const Annotation& aParam)
{
WriteParam(aMsg, aParam.mName);
WriteParam(aMsg, aParam.mValue);
}
bool
ParamTraits<Annotation>::Read(const Message* aMsg,
PickleIterator* aIter,
Annotation* aResult)
{
if (!ReadParam(aMsg, aIter, &aResult->mName)) {
return false;
}
if (!ReadParam(aMsg, aIter, &aResult->mValue)) {
return false;
}
return true;
}
} // namespace IPC

View File

@ -1,127 +0,0 @@
/* -*- 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/. */
#ifndef mozilla_HangAnnotations_h
#define mozilla_HangAnnotations_h
#include <set>
#include "ipc/IPCMessageUtils.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Mutex.h"
#include "mozilla/Vector.h"
#include "nsString.h"
#include "nsTArray.h"
namespace mozilla {
namespace HangMonitor {
/**
* This type represents an individual hang annotation.
*/
class Annotation
{
public:
Annotation() {}
Annotation(const nsAString& aName, const nsAString& aValue)
: mName(aName), mValue(aValue)
{}
nsString mName;
nsString mValue;
};
/**
* This class extends nsTArray<Annotation> with some methods for adding
* annotations being reported by a registered hang Annotator.
*/
class HangAnnotations : public nsTArray<Annotation>
{
public:
void AddAnnotation(const nsAString& aName, const int32_t aData);
void AddAnnotation(const nsAString& aName, const double aData);
void AddAnnotation(const nsAString& aName, const nsAString& aData);
void AddAnnotation(const nsAString& aName, const nsACString& aData);
void AddAnnotation(const nsAString& aName, const bool aData);
};
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);
/**
* Gathers annotations. This function should be called by ChromeHangs.
* @return HangAnnotations object.
*/
HangAnnotations ChromeHangAnnotatorCallout();
namespace Observer {
class Annotators
{
public:
Annotators();
~Annotators();
bool Register(Annotator& aAnnotator);
bool Unregister(Annotator& aAnnotator);
HangAnnotations GatherAnnotations();
private:
Mutex mMutex;
std::set<Annotator*> mAnnotators;
};
} // namespace Observer
} // namespace HangMonitor
} // namespace mozilla
namespace IPC {
template<>
class ParamTraits<mozilla::HangMonitor::HangAnnotations>
: public ParamTraits<nsTArray<mozilla::HangMonitor::Annotation>>
{
public:
typedef mozilla::HangMonitor::HangAnnotations paramType;
};
template<>
class ParamTraits<mozilla::HangMonitor::Annotation>
{
public:
typedef mozilla::HangMonitor::Annotation paramType;
static void Write(Message* aMsg, const paramType& aParam);
static bool Read(const Message* aMsg,
PickleIterator* aIter,
paramType* aResult);
};
} // namespace IPC
#endif // mozilla_HangAnnotations_h

View File

@ -1,424 +0,0 @@
/* -*- 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/HangMonitor.h"
#include "mozilla/Atomics.h"
#include "mozilla/BackgroundHangMonitor.h"
#include "mozilla/Monitor.h"
#include "mozilla/Preferences.h"
#include "mozilla/ProcessedStack.h"
#include "mozilla/Telemetry.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/UniquePtr.h"
#include "nsExceptionHandler.h"
#include "nsReadableUtils.h"
#include "nsThreadUtils.h"
#include "mozilla/StackWalk.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
#include "GeckoProfiler.h"
#ifdef XP_WIN
#include <windows.h>
#endif
#if defined(MOZ_GECKO_PROFILER) && defined(MOZ_PROFILING) && defined(XP_WIN)
#define REPORT_CHROME_HANGS
#endif
namespace mozilla {
namespace HangMonitor {
/**
* A flag which may be set from within a debugger to disable the hang
* monitor.
*/
volatile bool gDebugDisableHangMonitor = false;
const char kHangMonitorPrefName[] = "hangmonitor.timeout";
#ifdef REPORT_CHROME_HANGS
const char kTelemetryPrefName[] = "toolkit.telemetry.enabled";
#endif
// Monitor protects gShutdown and gTimeout, but not gTimestamp which rely on
// being atomically set by the processor; synchronization doesn't really matter
// in this use case.
Monitor* gMonitor;
// The timeout preference, in seconds.
int32_t gTimeout;
PRThread* gThread;
// Set when shutdown begins to signal the thread to exit immediately.
bool gShutdown;
// The timestamp of the last event notification, or PR_INTERVAL_NO_WAIT if
// we're currently not processing events.
Atomic<PRIntervalTime> gTimestamp(PR_INTERVAL_NO_WAIT);
#ifdef REPORT_CHROME_HANGS
// Main thread ID used in reporting chrome hangs under Windows
static HANDLE winMainThreadHandle = nullptr;
// Default timeout for reporting chrome hangs to Telemetry (5 seconds)
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;
#endif
// PrefChangedFunc
void
PrefChanged(const char*, void*)
{
int32_t newval = Preferences::GetInt(kHangMonitorPrefName);
#ifdef REPORT_CHROME_HANGS
// Monitor chrome hangs on the profiling branch if Telemetry enabled
if (newval == 0) {
bool telemetryEnabled = Preferences::GetBool(kTelemetryPrefName);
if (telemetryEnabled) {
newval = DEFAULT_CHROME_HANG_INTERVAL;
}
}
#endif
MonitorAutoLock lock(*gMonitor);
if (newval != gTimeout) {
gTimeout = newval;
lock.Notify();
}
}
void
Crash()
{
if (gDebugDisableHangMonitor) {
return;
}
#ifdef XP_WIN
if (::IsDebuggerPresent()) {
return;
}
#endif
// If you change this, you must also deal with the threadsafety of AnnotateCrashReport in
// non-chrome processes!
if (GeckoProcessType_Default == XRE_GetProcessType()) {
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Hang"),
NS_LITERAL_CSTRING("1"));
CrashReporter::SetMinidumpAnalysisAllThreads();
}
MOZ_CRASH("HangMonitor triggered");
}
#ifdef REPORT_CHROME_HANGS
static void
ChromeStackWalker(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure)
{
MOZ_ASSERT(aClosure);
std::vector<uintptr_t>* stack =
static_cast<std::vector<uintptr_t>*>(aClosure);
if (stack->size() == MAX_CALL_STACK_PCS) {
return;
}
MOZ_ASSERT(stack->size() < MAX_CALL_STACK_PCS);
stack->push_back(reinterpret_cast<uintptr_t>(aPC));
}
static void
GetChromeHangReport(Telemetry::ProcessedStack& aStack,
int32_t& aSystemUptime,
int32_t& aFirefoxUptime)
{
MOZ_ASSERT(winMainThreadHandle);
// The thread we're about to suspend might have the alloc lock
// so allocate ahead of time
std::vector<uintptr_t> rawStack;
rawStack.reserve(MAX_CALL_STACK_PCS);
DWORD ret = ::SuspendThread(winMainThreadHandle);
bool suspended = false;
if (ret != (DWORD)-1) {
// SuspendThread is asynchronous, so the thread may still be running. Use
// GetThreadContext to ensure it's really suspended.
// See https://blogs.msdn.microsoft.com/oldnewthing/20150205-00/?p=44743.
CONTEXT context;
context.ContextFlags = CONTEXT_CONTROL;
if (::GetThreadContext(winMainThreadHandle, &context)) {
suspended = true;
}
}
if (!suspended) {
if (ret != (DWORD)-1) {
MOZ_ALWAYS_TRUE(::ResumeThread(winMainThreadHandle) != DWORD(-1));
}
return;
}
MozStackWalkThread(ChromeStackWalker, /* skipFrames */ 0, /* maxFrames */ 0,
&rawStack, winMainThreadHandle, nullptr);
ret = ::ResumeThread(winMainThreadHandle);
if (ret == (DWORD)-1) {
return;
}
aStack = Telemetry::GetStackAndModules(rawStack);
// Record system uptime (in minutes) at the time of the hang
aSystemUptime = ((GetTickCount() / 1000) - (gTimeout * 2)) / 60;
// Record Firefox uptime (in minutes) at the time of the hang
bool error;
TimeStamp processCreation = TimeStamp::ProcessCreation(&error);
if (!error) {
TimeDuration td = TimeStamp::Now() - processCreation;
aFirefoxUptime = (static_cast<int32_t>(td.ToSeconds()) - (gTimeout * 2)) / 60;
} else {
aFirefoxUptime = -1;
}
}
#endif
void
ThreadMain(void*)
{
AUTO_PROFILER_REGISTER_THREAD("Hang Monitor");
NS_SetCurrentThreadName("Hang Monitor");
MonitorAutoLock lock(*gMonitor);
// In order to avoid issues with the hang monitor incorrectly triggering
// during a general system stop such as sleeping, the monitor thread must
// run twice to trigger hang protection.
PRIntervalTime lastTimestamp = 0;
int waitCount = 0;
#ifdef REPORT_CHROME_HANGS
Telemetry::ProcessedStack stack;
int32_t systemUptime = -1;
int32_t firefoxUptime = -1;
HangAnnotations annotations;
#endif
while (true) {
if (gShutdown) {
return; // Exit the thread
}
// avoid rereading the volatile value in this loop
PRIntervalTime timestamp = gTimestamp;
PRIntervalTime now = PR_IntervalNow();
if (timestamp != PR_INTERVAL_NO_WAIT &&
now < timestamp) {
// 32-bit overflow, reset for another waiting period
timestamp = 1; // lowest legal PRInterval value
}
if (timestamp != PR_INTERVAL_NO_WAIT &&
timestamp == lastTimestamp &&
gTimeout > 0) {
++waitCount;
#ifdef REPORT_CHROME_HANGS
// Capture the chrome-hang stack + Firefox & system uptimes after
// the minimum hang duration has been reached (not when the hang ends)
if (waitCount == 2) {
GetChromeHangReport(stack, systemUptime, firefoxUptime);
annotations = ChromeHangAnnotatorCallout();
}
#else
// This is the crash-on-hang feature.
// See bug 867313 for the quirk in the waitCount comparison
if (waitCount >= 2) {
int32_t delay =
int32_t(PR_IntervalToSeconds(now - timestamp));
if (delay >= gTimeout) {
MonitorAutoUnlock unlock(*gMonitor);
Crash();
}
}
#endif
} else {
#ifdef REPORT_CHROME_HANGS
if (waitCount >= 2) {
uint32_t hangDuration = PR_IntervalToSeconds(now - lastTimestamp);
Telemetry::RecordChromeHang(hangDuration, stack, systemUptime,
firefoxUptime, std::move(annotations));
stack.Clear();
}
#endif
lastTimestamp = timestamp;
waitCount = 0;
}
TimeDuration timeout;
if (gTimeout <= 0) {
timeout = TimeDuration::Forever();
} else {
timeout = TimeDuration::FromMilliseconds(gTimeout * 500);
}
lock.Wait(timeout);
}
}
void
Startup()
{
if (GeckoProcessType_Default != XRE_GetProcessType() &&
GeckoProcessType_Content != XRE_GetProcessType()) {
return;
}
MOZ_ASSERT(!gMonitor, "Hang monitor already initialized");
gMonitor = new Monitor("HangMonitor");
Preferences::RegisterCallback(PrefChanged, kHangMonitorPrefName);
PrefChanged(nullptr, nullptr);
#ifdef REPORT_CHROME_HANGS
Preferences::RegisterCallback(PrefChanged, kTelemetryPrefName);
winMainThreadHandle =
OpenThread(THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId());
if (!winMainThreadHandle) {
return;
}
#endif
// Don't actually start measuring hangs until we hit the main event loop.
// This potentially misses a small class of really early startup hangs,
// but avoids dealing with some xpcshell tests and other situations which
// start XPCOM but don't ever start the event loop.
Suspend();
gThread = PR_CreateThread(PR_USER_THREAD,
ThreadMain,
nullptr, PR_PRIORITY_LOW, PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD, 0);
}
void
Shutdown()
{
if (GeckoProcessType_Default != XRE_GetProcessType() &&
GeckoProcessType_Content != XRE_GetProcessType()) {
return;
}
MOZ_ASSERT(gMonitor, "Hang monitor not started");
{
// Scope the lock we're going to delete later
MonitorAutoLock lock(*gMonitor);
gShutdown = true;
lock.Notify();
}
// thread creation could theoretically fail
if (gThread) {
PR_JoinThread(gThread);
gThread = nullptr;
}
delete gMonitor;
gMonitor = nullptr;
}
static bool
IsUIMessageWaiting()
{
#ifndef XP_WIN
return false;
#else
// There should never be mouse, keyboard, or IME messages in a message queue
// in the content process, so don't waste time making multiple PeekMessage
// calls.
if (GeckoProcessType_Content == XRE_GetProcessType()) {
return false;
}
#define NS_WM_IMEFIRST WM_IME_SETCONTEXT
#define NS_WM_IMELAST WM_IME_KEYUP
BOOL haveUIMessageWaiting = FALSE;
MSG msg;
haveUIMessageWaiting |= ::PeekMessageW(&msg, nullptr, WM_KEYFIRST,
WM_IME_KEYLAST, PM_NOREMOVE);
haveUIMessageWaiting |= ::PeekMessageW(&msg, nullptr, NS_WM_IMEFIRST,
NS_WM_IMELAST, PM_NOREMOVE);
haveUIMessageWaiting |= ::PeekMessageW(&msg, nullptr, WM_MOUSEFIRST,
WM_MOUSELAST, PM_NOREMOVE);
return haveUIMessageWaiting;
#endif
}
void
NotifyActivity(ActivityType aActivityType)
{
MOZ_ASSERT(NS_IsMainThread(),
"HangMonitor::Notify called from off the main thread.");
// Determine the activity type more specifically
if (aActivityType == kGeneralActivity) {
aActivityType = IsUIMessageWaiting() ? kActivityUIAVail :
kActivityNoUIAVail;
}
// Calculate the cumulative amount of lag time since the last UI message
static uint32_t cumulativeUILagMS = 0;
switch (aActivityType) {
case kActivityNoUIAVail:
cumulativeUILagMS = 0;
break;
case kActivityUIAVail:
case kUIActivity:
if (gTimestamp != PR_INTERVAL_NO_WAIT) {
cumulativeUILagMS += PR_IntervalToMilliseconds(PR_IntervalNow() -
gTimestamp);
}
break;
default:
break;
}
// This is not a locked activity because PRTimeStamp is a 32-bit quantity
// which can be read/written atomically, and we don't want to pay locking
// penalties here.
gTimestamp = PR_IntervalNow();
// If we have UI activity we should reset the timer and report it
if (aActivityType == kUIActivity) {
mozilla::Telemetry::Accumulate(mozilla::Telemetry::EVENTLOOP_UI_ACTIVITY_EXP_MS,
cumulativeUILagMS);
cumulativeUILagMS = 0;
}
if (gThread && !gShutdown) {
mozilla::BackgroundHangMonitor().NotifyActivity();
}
}
void
Suspend()
{
MOZ_ASSERT(NS_IsMainThread(),
"HangMonitor::Suspend called from off the main thread.");
// Because gTimestamp changes this resets the wait count.
gTimestamp = PR_INTERVAL_NO_WAIT;
if (gThread && !gShutdown) {
mozilla::BackgroundHangMonitor().NotifyWait();
}
}
} // namespace HangMonitor
} // namespace mozilla

View File

@ -1,58 +0,0 @@
/* -*- 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/. */
#ifndef mozilla_HangMonitor_h
#define mozilla_HangMonitor_h
namespace mozilla {
namespace HangMonitor {
/**
* Signifies the type of activity in question
*/
enum ActivityType
{
/* There is activity and it is known to be UI related activity. */
kUIActivity,
/* There is non UI activity and no UI activity is pending */
kActivityNoUIAVail,
/* There is non UI activity and UI activity is known to be pending */
kActivityUIAVail,
/* There is non UI activity and UI activity pending is unknown */
kGeneralActivity
};
/**
* Start monitoring hangs. Should be called by the XPCOM startup process only.
*/
void Startup();
/**
* Stop monitoring hangs and join the thread.
*/
void Shutdown();
/**
* Notify the hang monitor of activity which will reset its internal timer.
*
* @param activityType The type of activity being reported.
* @see ActivityType
*/
void NotifyActivity(ActivityType activityType = kGeneralActivity);
/*
* Notify the hang monitor that the browser is now idle and no detection should
* be done.
*/
void Suspend();
} // namespace HangMonitor
} // namespace mozilla
#endif // mozilla_HangMonitor_h

View File

@ -44,8 +44,6 @@ EXPORTS.mozilla += [
'CPUUsageWatcher.h',
'DeadlockDetector.h',
'EventQueue.h',
'HangAnnotations.h',
'HangMonitor.h',
'IdleTaskRunner.h',
'LazyIdleThread.h',
'MainThreadIdlePeriod.h',
@ -82,8 +80,6 @@ UNIFIED_SOURCES += [
'CooperativeThreadPool.cpp',
'CPUUsageWatcher.cpp',
'EventQueue.cpp',
'HangAnnotations.cpp',
'HangMonitor.cpp',
'InputEventStatistics.cpp',
'LabeledEventQueue.cpp',
'LazyIdleThread.cpp',

View File

@ -21,10 +21,10 @@
#include "nsCOMPtr.h"
#include "nsQueryObject.h"
#include "pratom.h"
#include "mozilla/BackgroundHangMonitor.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/Logging.h"
#include "nsIObserverService.h"
#include "mozilla/HangMonitor.h"
#include "mozilla/IOInterposer.h"
#include "mozilla/ipc/MessageChannel.h"
#include "mozilla/ipc/BackgroundChild.h"
@ -992,7 +992,7 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult)
LOG(("THRD(%p) running [%p]\n", this, event.get()));
if (MAIN_THREAD == mIsMainThread) {
HangMonitor::NotifyActivity();
BackgroundHangMonitor().NotifyActivity();
}
bool schedulerLoggingEnabled = mozilla::StaticPrefs::dom_performance_enable_scheduler_timing();
@ -1219,7 +1219,7 @@ nsThread::DoMainThreadSpecificProcessing(bool aReallyWait)
ipc::CancelCPOWs();
if (aReallyWait) {
HangMonitor::Suspend();
BackgroundHangMonitor().NotifyWait();
}
// Fire a memory pressure notification, if one is pending.