mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
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:
parent
3652708f31
commit
10ff9c706f
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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"),
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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],
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
102
toolkit/components/backgroundhangmonitor/HangAnnotations.cpp
Normal file
102
toolkit/components/backgroundhangmonitor/HangAnnotations.cpp
Normal 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
|
75
toolkit/components/backgroundhangmonitor/HangAnnotations.h
Normal file
75
toolkit/components/backgroundhangmonitor/HangAnnotations.h
Normal 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
|
@ -33,11 +33,13 @@ XPIDL_MODULE = 'backgroundhangmonitor'
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'BackgroundHangMonitor.h',
|
||||
'HangAnnotations.h',
|
||||
'HangDetails.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'BackgroundHangMonitor.cpp',
|
||||
'HangAnnotations.cpp',
|
||||
'HangDetails.cpp',
|
||||
]
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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
|
@ -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__
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -64,7 +64,6 @@ EXPORTS.mozilla += [
|
||||
SOURCES += [
|
||||
'CombinedStacks.cpp',
|
||||
'geckoview/TelemetryGeckoViewPersistence.cpp',
|
||||
'HangReports.cpp',
|
||||
'ipc/TelemetryIPC.cpp',
|
||||
'ipc/TelemetryIPCAccumulator.cpp',
|
||||
'ProcessedStack.cpp',
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
];
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
=============
|
||||
|
||||
|
@ -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">
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -19,6 +19,8 @@ UNIFIED_SOURCES += [
|
||||
'Utils.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
|
@ -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;
|
||||
|
@ -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]++;
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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',
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user