--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -28,16 +28,17 @@
#include "gfxDrawable.h"
#include "gfxPrefs.h"
#include "ImageOps.h"
#include "mozAutoDocUpdate.h"
#include "mozilla/ArrayUtils.h"
#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"
#include "mozilla/LoadInfo.h"
#include "mozilla/dom/BlobURLProtocolHandler.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/CustomElementRegistry.h"
#include "mozilla/dom/MessageBroadcaster.h"
@@ -595,25 +596,25 @@ NS_IMPL_ISUPPORTS(nsContentUtils::nsCont
* interacting with the browser. It listens to observer events to toggle the
* value of the sUserActive static.
*
* This class is an internal implementation detail.
* nsContentUtils::GetUserIsInteracting() should be used to access current
* user interaction status.
*/
class nsContentUtils::UserInteractionObserver final : public nsIObserver
- , public HangMonitor::Annotator
+ , public BackgroundHangAnnotator
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
void Init();
void Shutdown();
- void AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) override;
+ void AnnotateHang(BackgroundHangAnnotations& aAnnotations) override;
static Atomic<bool> sUserActive;
private:
~UserInteractionObserver() {}
};
/* static */
@@ -10775,43 +10776,43 @@ void
nsContentUtils::UserInteractionObserver::Init()
{
// Listen for the observer messages from EventStateManager which are telling
// us whether or not the user is interacting.
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
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
nsContentUtils::UserInteractionObserver::Shutdown()
{
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->RemoveObserver(this, kUserInteractionInactive);
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) {
aAnnotations.AddAnnotation(NS_LITERAL_STRING("UserInteracting"), true);
}
}
NS_IMETHODIMP
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -10,16 +10,17 @@
#include "ContentChild.h"
#include "GeckoProfiler.h"
#include "TabChild.h"
#include "HandlerServiceChild.h"
#include "mozilla/Attributes.h"
+#include "mozilla/BackgroundHangMonitor.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/Preferences.h"
#include "mozilla/ProcessHangMonitorIPC.h"
#include "mozilla/Unused.h"
#include "mozilla/StaticPrefs.h"
#include "mozilla/TelemetryIPC.h"
#include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
#include "mozilla/docshell/OfflineCacheUpdateChild.h"
@@ -505,25 +506,25 @@ ConsoleListener::Observe(nsIConsoleMessa
nsresult rv = aMessage->GetMessageMoz(getter_Copies(msg));
NS_ENSURE_SUCCESS(rv, rv);
mChild->SendConsoleMessage(msg);
return NS_OK;
}
#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) {
aAnnotations.AddAnnotation(NS_LITERAL_STRING("PendingInput"), pending);
}
}
static PendingInputEventHangAnnotator sSingleton;
@@ -707,17 +708,17 @@ ContentChild::Init(MessageLoop* aIOLoop,
SetProcessName(NS_LITERAL_STRING("Web Content"));
#ifdef NIGHTLY_BUILD
// NOTE: We have to register the annotator on the main thread, as annotators
// only affect a single thread.
SystemGroup::Dispatch(TaskCategory::Other,
NS_NewRunnableFunction("RegisterPendingInputEventHangAnnotator", [] {
- HangMonitor::RegisterAnnotator(
+ BackgroundHangMonitor::RegisterAnnotator(
PendingInputEventHangAnnotator::sSingleton);
}));
#endif
return true;
}
void
@@ -3049,17 +3050,17 @@ ContentChild::ShutdownInternal()
&ContentChild::ShutdownInternal),
100);
return;
}
mShuttingDown = true;
#ifdef NIGHTLY_BUILD
- HangMonitor::UnregisterAnnotator(PendingInputEventHangAnnotator::sSingleton);
+ BackgroundHangMonitor::UnregisterAnnotator(PendingInputEventHangAnnotator::sSingleton);
#endif
if (mPolicy) {
mPolicy->Deactivate();
mPolicy = nullptr;
}
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -4,16 +4,17 @@
* 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/plugins/PluginModuleParent.h"
#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"
#include "mozilla/ipc/CrashReporterHost.h"
#include "mozilla/dom/Element.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/ipc/MessageChannel.h"
#include "mozilla/ipc/ProtocolUtils.h"
@@ -655,17 +656,17 @@ PluginModuleChromeParent::PluginModuleCh
#endif
, mIsBlocklisted(false)
, mIsCleaningFromTimeout(false)
{
NS_ASSERTION(mSubprocess, "Out of memory!");
mSandboxLevel = aSandboxLevel;
mRunID = GeckoChildProcessHost::GetUniqueID();
- mozilla::HangMonitor::RegisterAnnotator(*this);
+ mozilla::BackgroundHangMonitor::RegisterAnnotator(*this);
}
PluginModuleChromeParent::~PluginModuleChromeParent()
{
if (!OkToCleanup()) {
MOZ_CRASH("unsafe destruction");
}
@@ -708,17 +709,17 @@ PluginModuleChromeParent::~PluginModuleC
Preferences::UnregisterCallback(TimeoutChanged, kHangUIMinDisplayPref, this);
if (mHangUIParent) {
delete mHangUIParent;
mHangUIParent = nullptr;
}
#endif
- mozilla::HangMonitor::UnregisterAnnotator(*this);
+ mozilla::BackgroundHangMonitor::UnregisterAnnotator(*this);
}
void
PluginModuleChromeParent::WriteExtraDataForMinidump()
{
// mCrashReporterMutex is already held by the caller
mCrashReporterMutex.AssertCurrentThreadOwns();
@@ -987,26 +988,26 @@ PluginModuleChromeParent::ExitedCxxStack
{
mHangAnnotationFlags = 0;
#ifdef XP_WIN
FinishHangUI();
#endif
}
/**
- * 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"),
true);
}
if (flags & kHangUIContinued) {
aAnnotations.AddAnnotation(NS_LITERAL_STRING("HangUIContinued"),
true);
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -348,17 +348,17 @@ class PluginModuleContentParent : public
static PluginModuleContentParent* sSavedModuleParent;
uint32_t mPluginId;
};
class PluginModuleChromeParent
: public PluginModuleParent
- , public mozilla::HangMonitor::Annotator
+ , public mozilla::BackgroundHangAnnotator
{
friend class mozilla::ipc::CrashReporterHost;
using TerminateChildProcessCallback =
mozilla::ipc::CrashReporterHost::CallbackWrapper<bool>;
using TakeFullMinidumpCallback =
mozilla::ipc::CrashReporterHost::CallbackWrapper<nsString>;
public:
/**
@@ -472,17 +472,17 @@ private:
void
ExitedCxxStack() override;
mozilla::ipc::IProtocol* GetInvokingProtocol();
PluginInstanceParent* GetManagingInstance(mozilla::ipc::IProtocol* aProtocol);
virtual void
- AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations) override;
+ AnnotateHang(mozilla::BackgroundHangAnnotations& aAnnotations) override;
virtual bool ShouldContinueFromReplyTimeout() override;
void ProcessFirstMinidump();
void WriteExtraDataForMinidump();
void RetainPluginRef();
void ReleasePluginRef();
--- a/ipc/mscom/MainThreadInvoker.cpp
+++ b/ipc/mscom/MainThreadInvoker.cpp
@@ -4,19 +4,19 @@
* 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/mscom/MainThreadInvoker.h"
#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"
#include "private/prpriv.h" // For PR_GetThreadID
#include <winternl.h> // For NTSTATUS and NTAPI
namespace {
@@ -176,17 +176,17 @@ MainThreadInvoker::Invoke(already_AddRef
mDuration = syncRunnable->GetDuration();
return result;
}
/* static */ VOID CALLBACK
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();
NS_RELEASE(runnable);
}
} // namespace mscom
} // namespace mozilla
--- a/js/src/tests/user.js
+++ b/js/src/tests/user.js
@@ -2,17 +2,16 @@ user_pref("app.update.enabled", false);
user_pref("browser.dom.window.dump.enabled", true);
user_pref("browser.sessionstore.resume_from_crash", false);
user_pref("browser.shell.checkDefaultBrowser", false);
user_pref("browser.xul.error_pages.enabled", true);
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);
user_pref("layout.css.report_errors", true);
user_pref("browser.warnOnQuit", false);
user_pref("browser.cache.check_doc_frequency", 1);
user_pref("extensions.checkCompatibility", false);
user_pref("extensions.checkUpdateSecurity", false);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3110,22 +3110,16 @@ pref("input_event_queue.duration.min", 1
// The default amount of time (milliseconds) required for handling a input
// event.
pref("input_event_queue.default_duration_per_event", 1);
// The number of processed input events we use to predict the amount of time
// 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);
// This only supports one hidden ctp plugin, edit nsPluginArray.cpp if adding a second
pref("plugins.navigator.hidden_ctp_plugin", "");
// The default value for nsIPluginTag.enabledState (STATE_ENABLED = 2)
--- a/testing/marionette/client/marionette_driver/geckoinstance.py
+++ b/testing/marionette/client/marionette_driver/geckoinstance.py
@@ -87,19 +87,16 @@ class GeckoInstance(object):
"general.useragent.updates.enabled": False,
# Always use network provider for geolocation tests
# so we bypass the OSX dialog raised by the corelocation provider
"geo.provider.testing": True,
# Do not scan Wifi
"geo.wifi.scan": False,
- # No hang monitor
- "hangmonitor.timeout": 0,
-
"javascript.options.showInConsole": True,
# Enable Marionette component
"marionette.enabled": True,
# (deprecated and can be removed when Firefox 60 ships)
"marionette.defaultPrefs.enabled": True,
# Disable recommended automation prefs in CI
--- a/testing/marionette/components/marionette.js
+++ b/testing/marionette/components/marionette.js
@@ -211,19 +211,16 @@ const RECOMMENDED_PREFS = new Map([
// Always use network provider for geolocation tests so we bypass the
// macOS dialog raised by the corelocation provider
["geo.provider.testing", true],
// 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],
// Do not prompt with long usernames or passwords in URLs
["network.http.phishy-userpass-length", 255],
// Do not prompt for temporary redirects
["network.http.prompt-temp-redirect", false],
--- a/toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.cpp
+++ b/toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.cpp
@@ -197,19 +197,19 @@ public:
BackgroundHangMonitor::ThreadType mThreadType;
#ifdef MOZ_GECKO_PROFILER
// Platform-specific helper to get hang stacks
ThreadStackHelper mStackHelper;
#endif
// 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
nsCString mThreadName;
BackgroundHangThread(const char* aName,
uint32_t aTimeoutMs,
uint32_t aMaxTimeoutMs,
@@ -483,30 +483,24 @@ BackgroundHangThread::~BackgroundHangThr
}
void
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())),
VoidString(),
mThreadName,
mRunnableName,
std::move(mHangStack),
- std::move(annotations)
+ std::move(mAnnotations)
);
// If the hang processing thread exists, we can process the native stack
// on it. Otherwise, we are unable to report a native stack, so we just
// report without one.
if (mManager->mHangProcessingThread) {
nsCOMPtr<nsIRunnable> processHangStackRunnable =
new ProcessHangStackRunnable(std::move(hangDetails));
@@ -762,31 +756,31 @@ BackgroundHangMonitor::NotifyWait()
if (Telemetry::CanRecordExtended()) {
mThread->NotifyWait();
}
#endif
}
bool
-BackgroundHangMonitor::RegisterAnnotator(HangMonitor::Annotator& aAnnotator)
+BackgroundHangMonitor::RegisterAnnotator(BackgroundHangAnnotator& aAnnotator)
{
#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
BackgroundHangThread* thisThread = BackgroundHangThread::FindThread();
if (!thisThread) {
return false;
}
return thisThread->mAnnotators.Register(aAnnotator);
#else
return false;
#endif
}
bool
-BackgroundHangMonitor::UnregisterAnnotator(HangMonitor::Annotator& aAnnotator)
+BackgroundHangMonitor::UnregisterAnnotator(BackgroundHangAnnotator& aAnnotator)
{
#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
BackgroundHangThread* thisThread = BackgroundHangThread::FindThread();
if (!thisThread) {
return false;
}
return thisThread->mAnnotators.Unregister(aAnnotator);
#else
--- a/toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.h
+++ b/toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.h
@@ -184,22 +184,22 @@ public:
*/
void NotifyWait();
/**
* Register an annotator with BHR for the current thread.
* @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
* RegisterAnnotator.
* @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
#endif // mozilla_BackgroundHangMonitor_h
new file mode 100644
--- /dev/null
+++ b/toolkit/components/backgroundhangmonitor/HangAnnotations.cpp
@@ -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
new file mode 100644
--- /dev/null
+++ b/toolkit/components/backgroundhangmonitor/HangAnnotations.h
@@ -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
--- a/toolkit/components/backgroundhangmonitor/moz.build
+++ b/toolkit/components/backgroundhangmonitor/moz.build
@@ -28,21 +28,23 @@ if CONFIG['NIGHTLY_BUILD'] and \
XPIDL_SOURCES += [
'nsIHangDetails.idl',
]
XPIDL_MODULE = 'backgroundhangmonitor'
EXPORTS.mozilla += [
'BackgroundHangMonitor.h',
+ 'HangAnnotations.h',
'HangDetails.h',
]
UNIFIED_SOURCES += [
'BackgroundHangMonitor.cpp',
+ 'HangAnnotations.cpp',
'HangDetails.cpp',
]
IPDL_SOURCES += [
'HangTypes.ipdlh',
]
if CONFIG['MOZ_GECKO_PROFILER']:
--- a/toolkit/components/telemetry/CombinedStacks.cpp
+++ b/toolkit/components/telemetry/CombinedStacks.cpp
@@ -1,16 +1,15 @@
/* -*- 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 "CombinedStacks.h"
-#include "HangAnnotations.h"
#include "mozilla/HangAnnotations.h"
#include "jsapi.h"
namespace mozilla {
namespace Telemetry {
// The maximum number of chrome hangs stacks that we're keeping.
const size_t kMaxChromeStacksKept = 50;
deleted file mode 100644
--- a/toolkit/components/telemetry/HangReports.cpp
+++ /dev/null
@@ -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
deleted file mode 100644
--- a/toolkit/components/telemetry/HangReports.h
+++ /dev/null
@@ -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__
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -77,47 +77,42 @@
#include "mozilla/FStream.h"
#include "mozilla/ProcessedStack.h"
#include "mozilla/Mutex.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPtr.h"
#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"
#include "KeyedStackCapturer.h"
#endif // MOZ_GECKO_PROFILER
#if defined(MOZ_TELEMETRY_GECKOVIEW)
#include "geckoview/TelemetryGeckoViewPersistence.h"
#endif
namespace {
using namespace mozilla;
-using namespace mozilla::HangMonitor;
using Telemetry::Common::AutoHashtable;
using Telemetry::Common::ToJSString;
using Telemetry::Common::GetCurrentProduct;
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)
using mozilla::Telemetry::KeyedStackCapturer;
#endif
// This is not a member of TelemetryImpl because we want to record I/O during
// startup.
@@ -145,23 +140,16 @@ class TelemetryImpl final
public:
void InitMemoryReporter();
static already_AddRefed<nsITelemetry> CreateTelemetryInstance();
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
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
struct Stat {
uint32_t hitCount;
uint32_t totalTime;
};
struct StmtStats {
@@ -200,18 +188,16 @@ private:
bool includePrivateSql);
void ReadLateWritesStacks(nsIFile* aProfileDir);
static TelemetryImpl *sTelemetry;
AutoHashtable<SlowSQLEntryType> mPrivateSQL;
AutoHashtable<SlowSQLEntryType> mSanitizedSQL;
Mutex mHashMutex;
- HangReports mHangReports;
- Mutex mHangReportsMutex;
Atomic<bool> mCanRecordBase;
Atomic<bool> mCanRecordExtended;
#if defined(MOZ_GECKO_PROFILER)
// Stores data about stacks captured on demand.
KeyedStackCapturer mStackCapturer;
#endif
@@ -490,17 +476,16 @@ TelemetryImpl::AsyncFetchTelemetryData(n
profileDir);
targetThread->Dispatch(event, NS_DISPATCH_NORMAL);
return NS_OK;
}
TelemetryImpl::TelemetryImpl()
: mHashMutex("Telemetry::mHashMutex")
- , mHangReportsMutex("Telemetry::mHangReportsMutex")
, mCanRecordBase(false)
, mCanRecordExtended(false)
, mCachedTelemetryData(false)
, mLastShutdownTime(0)
, mFailedLockCount(0)
{
// We expect TelemetryHistogram::InitializeGlobalState() to have been
// called before we get to this point.
@@ -508,17 +493,16 @@ TelemetryImpl::TelemetryImpl()
}
TelemetryImpl::~TelemetryImpl() {
UnregisterWeakMemoryReporter(this);
// 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
TelemetryImpl::InitMemoryReporter() {
RegisterWeakMemoryReporter(this);
}
bool
@@ -648,132 +632,16 @@ TelemetryImpl::GetWebrtcStats(JSContext
NS_IMETHODIMP
TelemetryImpl::GetMaximalNumberOfConcurrentThreads(uint32_t *ret)
{
*ret = nsThreadManager::get().GetHighestNumberOfThreads();
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)
{
#if defined(MOZ_GECKO_PROFILER)
nsresult rv = mStackCapturer.ReflectCapturedStacks(cx, ret);
if (clear) {
mStackCapturer.Clear();
}
return rv;
@@ -1582,32 +1450,16 @@ TelemetryImpl::RecordIceCandidates(const
{
if (!sTelemetry || !TelemetryHistogram::CanRecordExtended())
return;
sTelemetry->mWebrtcTelemetry.RecordIceCandidateMask(iceCandidateBitmask, success);
}
#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) {
if (Telemetry::CanRecordExtended() && XRE_IsParentProcess()) {
sTelemetry->mStackCapturer.Capture(aKey);
}
}
#endif
@@ -1894,20 +1746,16 @@ TelemetryImpl::SizeOfIncludingThis(mozil
n += TelemetryHistogram::GetMapShallowSizesOfExcludingThis(aMallocSizeOf);
n += TelemetryScalar::GetMapShallowSizesOfExcludingThis(aMallocSizeOf);
n += mWebrtcTelemetry.SizeOfExcludingThis(aMallocSizeOf);
{ // Scope for mHashMutex lock
MutexAutoLock lock(mHashMutex);
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.
if (sTelemetryIOObserver) {
n += sTelemetryIOObserver->SizeOfIncludingThis(aMallocSizeOf);
}
n += TelemetryHistogram::GetHistogramSizesofIncludingThis(aMallocSizeOf);
@@ -2155,32 +2003,19 @@ void Init()
{
// Make the service manager hold a long-lived reference to the service
nsCOMPtr<nsITelemetry> telemetryService =
do_GetService("@mozilla.org/base/telemetry;1");
MOZ_ASSERT(telemetryService);
}
#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
void
WriteFailedProfileLock(nsIFile* aProfileDir)
{
nsCOMPtr<nsIFile> file;
nsresult rv = GetFailedProfileLockFile(getter_AddRefs(file), aProfileDir);
--- a/toolkit/components/telemetry/Telemetry.h
+++ b/toolkit/components/telemetry/Telemetry.h
@@ -24,19 +24,16 @@
* For documentation on how to add and use new Telemetry probes, see:
* https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Adding_a_new_Telemetry_probe
*
* For more general information on Telemetry see:
* https://wiki.mozilla.org/Telemetry
*****************************************************************************/
namespace mozilla {
-namespace HangMonitor {
- class HangAnnotations;
-} // namespace HangMonitor
namespace Telemetry {
struct HistogramAccumulation;
struct KeyedHistogramAccumulation;
struct ScalarAction;
struct KeyedScalarAction;
struct ChildEventData;
@@ -483,22 +480,16 @@ class ProcessedStack;
*
* @param aDuration - Approximate duration of main thread hang, in seconds
* @param aStack - Array of PCs from the hung call stack
* @param aSystemUptime - System uptime at the time of the hang, in minutes
* @param aFirefoxUptime - Firefox uptime at the time of the hang, in minutes
* @param aAnnotations - Any annotations to be added to the report
*/
#if defined(MOZ_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
* counter.
*
* @param aKey - A user defined key associated with the captured stack.
*
* NOTE: Unwinding call stacks is an expensive operation performance-wise.
--- a/toolkit/components/telemetry/TelemetrySession.jsm
+++ b/toolkit/components/telemetry/TelemetrySession.jsm
@@ -1125,17 +1125,16 @@ var Impl = {
// Payload common to chrome and content processes.
let payloadObj = {
ver: PAYLOAD_VERSION,
simpleMeasurements,
};
// Add extended set measurements common to chrome & content processes
if (Telemetry.canRecordExtended) {
- payloadObj.chromeHangs = protect(() => Telemetry.chromeHangs);
payloadObj.log = [];
payloadObj.webrtc = protect(() => Telemetry.webrtcStats);
}
if (Utils.isContentProcess) {
return payloadObj;
}
--- a/toolkit/components/telemetry/docs/data/main-ping.rst
+++ b/toolkit/components/telemetry/docs/data/main-ping.rst
@@ -56,17 +56,17 @@ Structure:
},
processes: {...},
simpleMeasurements: {...},
// 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
webrtc: {...},
gc: {...},
fileIOReports: {...},
lateWrites: {...},
addonDetails: {...},
@@ -344,16 +344,19 @@ Structure:
],
"captures": [["string-key", stack-index, count], ... ]
}
.. _chromeHangs:
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:
* Reported chrome hang stacks are limited in depth to 50 entries.
* The maximum number of reported stacks is 50.
The module names can contain unicode characters.
--- a/toolkit/components/telemetry/moz.build
+++ b/toolkit/components/telemetry/moz.build
@@ -59,17 +59,16 @@ EXPORTS.mozilla += [
'ipc/TelemetryIPC.h',
'ProcessedStack.h',
'Telemetry.h',
]
SOURCES += [
'CombinedStacks.cpp',
'geckoview/TelemetryGeckoViewPersistence.cpp',
- 'HangReports.cpp',
'ipc/TelemetryIPC.cpp',
'ipc/TelemetryIPCAccumulator.cpp',
'ProcessedStack.cpp',
'Telemetry.cpp',
'TelemetryCommon.cpp',
'TelemetryEvent.cpp',
'TelemetryHistogram.cpp',
'TelemetryIOInterposeObserver.cpp',
--- a/toolkit/components/telemetry/nsITelemetry.idl
+++ b/toolkit/components/telemetry/nsITelemetry.idl
@@ -124,24 +124,16 @@ interface nsITelemetry : nsISupports
/**
* A number representing the highest number of concurrent threads
* reached during this session.
*/
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
* the capture counter without doing actual stack unwinding.
*
* @param aKey - A user defined key associated with the captured stack.
*
* NOTE: Unwinding call stacks is an expensive operation performance-wise.
*/
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
@@ -1824,17 +1824,17 @@ add_task(async function test_schedulerNo
Assert.ok(!(await OS.File.exists(ABORTED_FILE)));
await TelemetryController.testShutdown();
PingServer.resetPingHandler();
});
add_task(async function test_pingExtendedStats() {
const EXTENDED_PAYLOAD_FIELDS = [
- "chromeHangs", "log", "slowSQL", "fileIOReports", "lateWrites",
+ "log", "slowSQL", "fileIOReports", "lateWrites",
"addonDetails", "webrtc"
];
if (AppConstants.platform == "android") {
EXTENDED_PAYLOAD_FIELDS.push("UIMeasurements");
}
// Reset telemetry and disable sending extended statistics.
--- a/toolkit/content/aboutTelemetry.js
+++ b/toolkit/content/aboutTelemetry.js
@@ -994,42 +994,16 @@ function SymbolicationRequest_fetchSymbo
this.symbolRequest.setRequestHeader("Content-type", "application/json");
this.symbolRequest.setRequestHeader("Content-length",
requestJSON.length);
this.symbolRequest.setRequestHeader("Connection", "close");
this.symbolRequest.onreadystatechange = this.handleSymbolResponse.bind(this);
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,
render: function CapturedStacks_render(payload) {
// Retrieve captured stacks from telemetry payload.
let capturedStacks = "processes" in payload && "parent" in payload.processes
? payload.processes.parent.capturedStacks
: false;
@@ -1222,17 +1196,16 @@ var Histogram = {
var Search = {
HASH_SEARCH: "search=",
// A list of ids of sections that do not support search.
blacklist: [
"late-writes-section",
- "chrome-hangs-section",
"raw-payload-section"
],
// Pass if: all non-empty array items match (case-sensitive)
isPassText(subject, filter) {
for (let item of filter) {
if (item.length && !subject.includes(item)) {
return false; // mismatch and not a spurious space
@@ -1989,40 +1962,16 @@ function setupListeners() {
search.addEventListener("input", Search.searchHandler);
// Clean up observers when page is closed
window.addEventListener("unload",
function(aEvent) {
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) {
return;
}
let capturedStacks = gPingData.payload.processes.parent.capturedStacks;
let req = new SymbolicationRequest("captured-stacks",
CapturedStacks.renderCaptureHeader,
@@ -2401,17 +2350,14 @@ function displayRichPingData(ping, updat
// Show event data.
Events.render(payload);
// Show captured stacks.
CapturedStacks.render(payload);
LateWritesSingleton.renderLateWrites(payload.lateWrites);
- // Show chrome hang stacks
- ChromeHangs.render(payload.chromeHangs);
-
// Show simple measurements
SimpleMeasurements.render(payload);
}
window.addEventListener("load", onLoad);
--- a/toolkit/content/aboutTelemetry.xhtml
+++ b/toolkit/content/aboutTelemetry.xhtml
@@ -61,19 +61,16 @@
<span class="category-name">&aboutTelemetry.eventsSection;</span>
</div>
<div class="category" value="simple-measurements-section">
<span class="category-name">&aboutTelemetry.simpleMeasurementsSection;</span>
</div>
<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>
<div class="category" value="captured-stacks-section">
<span class="category-name">&aboutTelemetry.capturedStacksSection;</span>
</div>
<div class="category" value="late-writes-section">
<span class="category-name">&aboutTelemetry.lateWritesSection;</span>
@@ -189,22 +186,16 @@
<div id="simple-measurements" class="data"></div>
</section>
<section id="slow-sql-section">
<p id="sql-warning">&aboutTelemetry.fullSqlWarning;</p>
<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>
<div id="late-writes" class="data"></div>
</section>
<section id="addon-details-section">
<div id="addon-details" class="data"></div>
--- a/toolkit/crashreporter/docs/index.rst
+++ b/toolkit/crashreporter/docs/index.rst
@@ -194,24 +194,16 @@ but there will be multiple dump files: a
one for the plugin process, and perhaps also additional dumps for the Flash
sandbox and broker processes. All of these files are submitted together as a
unit. Before submission, the filenames of the files are linked:
- **uuid.ini** - *annotations, includes an additional_minidumps field*
- **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
=============
If the crash reporter subsystem is enabled, the *about:crashes*
page will be registered with the application. This page provides
information about previous and submitted crashes.
It is also possible to submit crashes from *about:crashes*.
--- a/toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd
+++ b/toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd
@@ -32,17 +32,16 @@
<!ENTITY aboutTelemetry.sessionInfoSection "Session Information">
<!ENTITY aboutTelemetry.scalarsSection "Scalars">
<!ENTITY aboutTelemetry.keyedScalarsSection "Keyed Scalars">
<!ENTITY aboutTelemetry.histogramsSection "Histograms">
<!ENTITY aboutTelemetry.keyedHistogramsSection "Keyed Histograms">
<!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">
<!ENTITY aboutTelemetry.rawPayloadSection "Raw Payload">
<!ENTITY aboutTelemetry.raw "Raw JSON">
<!ENTITY aboutTelemetry.fullSqlWarning "NOTE: Slow SQL debugging is enabled. Full SQL strings may be displayed below but they will not be submitted to Telemetry.">
<!ENTITY aboutTelemetry.fetchStackSymbols "Fetch function names for stacks">
--- a/toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
+++ b/toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
@@ -76,20 +76,16 @@ addonTableDetails = Details
# LOCALIZATION NOTE(addonProvider):
# - %1$S is replaced by the name of an Add-on Provider (e.g. “XPI”, “Plugin”)
addonProvider = %1$S Provider
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
captured-stacks-title = %1$S (capture count: %2$S)
# LOCALIZATION NOTE(late-writes-title):
# - %1$S is replaced by the number of the late write
late-writes-title = Late Write #%1$S
--- a/widget/android/GeckoEditableSupport.h
+++ b/widget/android/GeckoEditableSupport.h
@@ -140,25 +140,25 @@ class GeckoEditableSupport final
public:
template<typename Functor>
static void OnNativeCall(Functor&& aCall)
{
struct IMEEvent : nsAppShell::LambdaEvent<Functor>
{
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
{
if (!this->lambda.GetNativeObject()) {
// Ignore stale calls after disposal.
jni::GetGeckoThreadEnv()->ExceptionClear();
return;
--- a/widget/android/jni/moz.build
+++ b/widget/android/jni/moz.build
@@ -14,14 +14,16 @@ EXPORTS.mozilla.jni += [
'Types.h',
'Utils.h',
]
UNIFIED_SOURCES += [
'Utils.cpp',
]
+include('/ipc/chromium/chromium-config.mozbuild')
+
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/widget',
'/widget/android',
]
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -736,26 +736,26 @@ nsAppShell::ProcessNextNativeEvent(bool
// wait for new events.
if (jni::IsAvailable() && XRE_IsParentProcess() &&
AndroidBridge::Bridge()->PumpMessageLoop()) {
return true;
}
AUTO_PROFILER_LABEL("nsAppShell::ProcessNextNativeEvent:Wait",
IDLE);
- mozilla::HangMonitor::Suspend();
+ mozilla::BackgroundHangMonitor().NotifyWait();
curEvent = mEventQueue.Pop(/* mayWait */ true);
}
}
if (!curEvent)
return false;
- mozilla::HangMonitor::NotifyActivity(curEvent->ActivityType());
+ mozilla::BackgroundHangMonitor().NotifyActivity();
curEvent->Run();
return true;
}
void
nsAppShell::SyncRunEvent(Event&& event,
UniquePtr<Event>(*eventFactory)(UniquePtr<Event>&&))
--- a/widget/android/nsAppShell.h
+++ b/widget/android/nsAppShell.h
@@ -3,17 +3,17 @@
* 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 nsAppShell_h__
#define nsAppShell_h__
#include <time.h>
-#include "mozilla/HangMonitor.h"
+#include "mozilla/BackgroundHangMonitor.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Monitor.h"
#include "mozilla/Move.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/TypeTraits.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "mozilla/jni/Natives.h"
@@ -31,18 +31,16 @@ void NotifyEvent();
class nsWindow;
class nsAppShell :
public nsBaseAppShell
{
public:
struct Event : mozilla::LinkedListElement<Event>
{
- typedef mozilla::HangMonitor::ActivityType Type;
-
static uint64_t GetTime()
{
timespec time;
if (clock_gettime(CLOCK_MONOTONIC, &time)) {
return 0ull;
}
return uint64_t(time.tv_sec) * 1000000000ull + time.tv_nsec;
}
@@ -59,19 +57,19 @@ public:
virtual ~Event() {}
virtual void Run() = 0;
virtual void PostTo(mozilla::LinkedList<Event>& queue)
{
queue.insertBack(this);
}
- virtual Type ActivityType() const
+ virtual bool IsUIEvent() const
{
- return Type::kGeneralActivity;
+ return false;
}
};
template<typename T>
class LambdaEvent : public Event
{
protected:
T lambda;
@@ -243,18 +241,17 @@ protected:
// Ownership of event object transfers to the return value.
mozilla::UniquePtr<Event> event(mQueue.popFirst());
if (!event || !event->mPostTime) {
return event;
}
#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]++;
sLatencyTime[latencyType] += latency;
#endif
return event;
}
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -348,19 +348,19 @@ class nsWindow::NPZCSupport final
return;
}
nsWindow* const window = npzcSupport->mWindow;
window->UserActivity();
return mLambda(window);
}
- nsAppShell::Event::Type ActivityType() const override
+ bool IsUIEvent() const override
{
- return nsAppShell::Event::Type::kUIActivity;
+ return true;
}
};
template<typename Lambda>
void PostInputEvent(Lambda&& aLambda)
{
// Use priority queue for input events.
nsAppShell::PostEvent(MakeUnique<InputEvent<Lambda>>(
--- a/widget/cocoa/nsAppShell.mm
+++ b/widget/cocoa/nsAppShell.mm
@@ -25,17 +25,17 @@
#include "nsIInterfaceRequestor.h"
#include "nsIWebBrowserChrome.h"
#include "nsObjCExceptions.h"
#include "nsCocoaFeatures.h"
#include "nsCocoaUtils.h"
#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"
#include "HeadlessScreenHelper.h"
#include "pratom.h"
#if !defined(RELEASE_OR_BETA) || defined(DEBUG)
#include "nsSandboxViolationSink.h"
#endif
@@ -131,17 +131,18 @@ static bool gAppShellMethodsSwizzled = f
- (void)sendEvent:(NSEvent *)anEvent
{
// Mark this function as non-idle because it's one of the exit points from
// the event loop (running inside of -[GeckoNSApplication nextEventMatchingMask:...])
// 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();
return;
}
[super sendEvent:anEvent];
}
@@ -167,22 +168,22 @@ static bool gAppShellMethodsSwizzled = f
// idleness but isn't perfect. For example, sometimes there's some Cocoa-
// internal activity that's triggered from the event loop, and we'll
// misidentify the stacks for that activity as idle because there's no Gecko
// code on the stack that can change the stack's category to something
// non-idle.
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;
}
@end
// AppShellDelegate
//
@@ -608,17 +609,17 @@ nsAppShell::ProcessNextNativeEvent(bool
waitUntil = [NSDate distantFuture];
NSRunLoop* currentRunLoop = [NSRunLoop currentRunLoop];
EventQueueRef currentEventQueue = GetCurrentEventQueue();
EventTargetRef eventDispatcherTarget = GetEventDispatcherTarget();
if (aMayWait) {
- mozilla::HangMonitor::Suspend();
+ mozilla::BackgroundHangMonitor().NotifyWait();
}
// Only call -[NSApp sendEvent:] (and indirectly send user-input events to
// Gecko) if aMayWait is true. Tbis ensures most calls to -[NSApp
// sendEvent:] happen under nsAppShell::Run(), at the lowest level of
// recursion -- thereby making it less likely Gecko will process user-input
// events in the wrong order or skip some of them. It also avoids eating
// too much CPU in nsBaseAppShell::OnProcessNextEvent() (which calls
@@ -634,17 +635,17 @@ nsAppShell::ProcessNextNativeEvent(bool
currentMode = [currentRunLoop currentMode];
if (!currentMode)
currentMode = NSDefaultRunLoopMode;
NSEvent *nextEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:waitUntil
inMode:currentMode
dequeue:YES];
if (nextEvent) {
- mozilla::HangMonitor::NotifyActivity();
+ mozilla::BackgroundHangMonitor().NotifyActivity();
[NSApp sendEvent:nextEvent];
eventProcessed = true;
}
} else {
// AcquireFirstMatchingEventInQueue() doesn't spin the (native) event
// loop, though it does queue up any newly available events from the
// window server.
EventRef currentEvent = AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL,
--- a/widget/gtk/nsAppShell.cpp
+++ b/widget/gtk/nsAppShell.cpp
@@ -9,17 +9,17 @@
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <gdk/gdk.h>
#include "nsAppShell.h"
#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"
#include "nsIPowerManagerService.h"
#ifdef MOZ_ENABLE_DBUS
#include "WakeLockListener.h"
#endif
#include "gfxPlatform.h"
@@ -41,24 +41,24 @@ LazyLogModule gWidgetDragLog("WidgetDrag
LazyLogModule gWidgetDrawLog("WidgetDraw");
static GPollFunc sPollFunc;
// Wrapper function to disable hang monitoring while waiting in poll().
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;
}
#ifdef MOZ_WIDGET_GTK
// For bug 726483.
static decltype(GtkContainerClass::check_resize) sReal_gtk_window_check_resize;
static void
--- a/widget/windows/WinUtils.cpp
+++ b/widget/windows/WinUtils.cpp
@@ -10,20 +10,20 @@
#include <winioctl.h>
#include "gfxPlatform.h"
#include "gfxUtils.h"
#include "nsWindow.h"
#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"
#include "mozilla/Unused.h"
#include "nsIContentPolicy.h"
#include "nsContentUtils.h"
#include "mozilla/Logging.h"
@@ -759,17 +759,17 @@ WinUtils::WaitForMessage(DWORD aTimeoutM
break;
}
#if defined(ACCESSIBILITY)
if (result == WAIT_IO_COMPLETION) {
if (NS_IsMainThread()) {
// 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;
}
#endif // defined(ACCESSIBILITY)
// Sent messages (via SendMessage and friends) are processed differently
// than queued messages (via PostMessage); the destination window procedure
// of the sent message is called during (Get|Peek)Message. Since PeekMessage
--- a/widget/windows/nsAppShell.cpp
+++ b/widget/windows/nsAppShell.cpp
@@ -10,17 +10,17 @@
#include "nsThreadUtils.h"
#include "WinUtils.h"
#include "WinTaskbar.h"
#include "WinMouseScrollHandler.h"
#include "nsWindowDefs.h"
#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"
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "GeckoProfiler.h"
#include "nsComponentManagerUtils.h"
#include "ScreenHelperWin.h"
@@ -524,19 +524,17 @@ nsAppShell::ProcessNextNativeEvent(bool
if (gotMessage) {
if (msg.message == WM_QUIT) {
::PostQuitMessage(msg.wParam);
Exit();
} 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)) {
continue; // the message is consumed.
}
// Store Printer Properties messages for reposting, because they are not
// processed by a window procedure, but are explicitly waited for in the
@@ -547,17 +545,17 @@ nsAppShell::ProcessNextNativeEvent(bool
continue;
}
::TranslateMessage(&msg);
::DispatchMessageW(&msg);
}
} 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;
WinUtils::WaitForMessage();
}
}
} while (!gotMessage && mayWait);
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -177,17 +177,17 @@
#include "nsWindowDefs.h"
#include "nsCrashOnException.h"
#include "nsIXULRuntime.h"
#include "nsIContent.h"
-#include "mozilla/HangMonitor.h"
+#include "mozilla/BackgroundHangMonitor.h"
#include "WinIMEHandler.h"
#include "npapi.h"
#include <d3d11.h>
#include "InkCollector.h"
@@ -4952,38 +4952,24 @@ DisplaySystemMenu(HWND hWnd, nsSizeMode
if (cmd) {
PostMessage(hWnd, WM_SYSCOMMAND, cmd, 0);
return true;
}
}
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
LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
mozilla::ipc::CancelCPOWs();
- HangMonitor::NotifyActivity(ActivityTypeForMessage(msg));
+ BackgroundHangMonitor().NotifyActivity();
return mozilla::CallWindowProcCrashProtected(WindowProcInternal, hWnd, msg, wParam, lParam);
}
LRESULT CALLBACK nsWindow::WindowProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (::GetWindowLongPtrW(hWnd, GWLP_ID) == eFakeTrackPointScrollableID) {
// This message was sent to the FAKETRACKPOINTSCROLLABLE.
--- a/xpcom/build/XPCOMInit.cpp
+++ b/xpcom/build/XPCOMInit.cpp
@@ -102,17 +102,16 @@ extern nsresult nsStringInputStreamConst
#include "nsMemoryInfoDumper.h"
#include "nsSecurityConsoleMessage.h"
#include "nsMessageLoop.h"
#include "nss.h"
#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"
#include "mozilla/BackgroundHangMonitor.h"
#include "nsChromeRegistry.h"
#include "nsChromeProtocolHandler.h"
#include "mozilla/PoisonIOInterposer.h"
@@ -734,17 +733,16 @@ NS_InitXPCOM2(nsIServiceManager** aResul
RegisterStrongMemoryReporter(new ICUReporter());
RegisterStrongMemoryReporter(new OggReporter());
#ifdef MOZ_VPX
RegisterStrongMemoryReporter(new VPXReporter());
#endif
mozilla::Telemetry::Init();
- mozilla::HangMonitor::Startup();
mozilla::BackgroundHangMonitor::Startup();
const MessageLoop* const loop = MessageLoop::current();
sMainHangMonitor = new mozilla::BackgroundHangMonitor(
loop->thread_name().c_str(),
loop->transient_hang_timeout(),
loop->permanent_hang_timeout());
@@ -793,17 +791,16 @@ NS_InitMinimalXPCOM()
// Global cycle collector initialization.
if (!nsCycleCollector_init()) {
return NS_ERROR_UNEXPECTED;
}
SharedThreadPool::InitStatics();
mozilla::Telemetry::Init();
- mozilla::HangMonitor::Startup();
mozilla::BackgroundHangMonitor::Startup();
return NS_OK;
}
//
// NS_ShutdownXPCOM()
//
@@ -859,17 +856,17 @@ SetGMPMemoryFunctions()
}
}
#endif
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");
}
nsresult rv;
nsCOMPtr<nsISimpleEnumerator> moduleLoaders;
@@ -932,17 +929,17 @@ ShutdownXPCOM(nsIServiceManager* aServMg
// Shutdown all remaining threads. This method does not return until
// all threads created using the thread manager (with the exception of
// the main thread) have exited.
nsThreadManager::get().Shutdown();
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
// xpcshell tests replacing the service) modules being unloaded.
mozilla::InitLateWriteChecks();
// We save the "xpcom-shutdown-loaders" observers to notify after
// the observerservice is gone.
@@ -1085,17 +1082,16 @@ ShutdownXPCOM(nsIServiceManager* aServMg
sCommandLineWasInitialized = false;
}
delete sExitManager;
sExitManager = nullptr;
Omnijar::CleanUp();
- HangMonitor::Shutdown();
BackgroundHangMonitor::Shutdown();
delete sMainHangMonitor;
sMainHangMonitor = nullptr;
NS_LogTerm();
return NS_OK;
--- a/xpcom/threads/CPUUsageWatcher.cpp
+++ b/xpcom/threads/CPUUsageWatcher.cpp
@@ -182,26 +182,26 @@ CPUUsageWatcher::Init()
mGlobalUpdateTime = globalTimes.updateTime;
mGlobalUsageTime = globalTimes.usageTime;
mInitialized = true;
CPUUsageWatcher* self = this;
NS_DispatchToMainThread(
NS_NewRunnableFunction("CPUUsageWatcher::Init",
- [=]() { HangMonitor::RegisterAnnotator(*self); }));
+ [=]() { BackgroundHangMonitor::RegisterAnnotator(*self); }));
return Ok();
}
void
CPUUsageWatcher::Uninit()
{
if (mInitialized) {
- HangMonitor::UnregisterAnnotator(*this);
+ BackgroundHangMonitor::UnregisterAnnotator(*this);
}
mInitialized = false;
}
Result<Ok, CPUUsageWatcherError>
CPUUsageWatcher::CollectCPUUsage()
{
if (!mInitialized) {
@@ -234,17 +234,17 @@ CPUUsageWatcher::CollectCPUUsage()
mExternalUsageRatio = std::max(0.0f,
globalUsageNormalized - processUsageNormalized);
return Ok();
}
void
-CPUUsageWatcher::AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) {
+CPUUsageWatcher::AnnotateHang(BackgroundHangAnnotations& aAnnotations) {
if (!mInitialized) {
return;
}
if (mExternalUsageRatio > mExternalUsageThreshold) {
aAnnotations.AddAnnotation(NS_LITERAL_STRING("ExternalCPUHigh"), true);
}
}
@@ -260,13 +260,13 @@ CPUUsageWatcher::Init()
void CPUUsageWatcher::Uninit() {}
Result<Ok, CPUUsageWatcherError>
CPUUsageWatcher::CollectCPUUsage()
{
return Ok();
}
-void CPUUsageWatcher::AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) {}
+void CPUUsageWatcher::AnnotateHang(BackgroundHangAnnotations& aAnnotations) {}
#endif // CPU_USAGE_WATCHER_ACTIVE
} // namespace mozilla
--- a/xpcom/threads/CPUUsageWatcher.h
+++ b/xpcom/threads/CPUUsageWatcher.h
@@ -5,16 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_CPUUsageWatcher_h
#define mozilla_CPUUsageWatcher_h
#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
// eat that cost for this.
#if defined(NIGHTLY_BUILD) && (defined(XP_WIN) || defined(XP_MACOSX))
#define CPU_USAGE_WATCHER_ACTIVE
#endif
@@ -26,23 +27,23 @@ enum CPUUsageWatcherError : uint8_t
GetNumberOfProcessorsError,
GetProcessTimesError,
GetSystemTimesError,
HostStatisticsError,
ProcStatError,
};
class CPUUsageHangAnnotator
- : public HangMonitor::Annotator
+ : public BackgroundHangAnnotator
{
public:
};
class CPUUsageWatcher
- : public HangMonitor::Annotator
+ : public BackgroundHangAnnotator
{
public:
#ifdef CPU_USAGE_WATCHER_ACTIVE
CPUUsageWatcher()
: mInitialized(false)
, mExternalUsageThreshold(0)
, mExternalUsageRatio(0)
, mProcessUsageTime(0)
@@ -57,17 +58,17 @@ public:
void Uninit();
// Updates necessary values to allow AnnotateHang to function. This must be
// called on some semi-regular basis, as it will calculate the mean CPU
// 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;
// The threshold above which we will mark a hang as occurring under high
// external CPU usage conditions
float mExternalUsageThreshold;
// The CPU usage (0-1) external to our process, averaged between the two
// most recent monitor thread runs
deleted file mode 100644
--- a/xpcom/threads/HangAnnotations.cpp
+++ /dev/null
@@ -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
deleted file mode 100644
--- a/xpcom/threads/HangAnnotations.h
+++ /dev/null
@@ -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
deleted file mode 100644
--- a/xpcom/threads/HangMonitor.cpp
+++ /dev/null
@@ -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
deleted file mode 100644
--- a/xpcom/threads/HangMonitor.h
+++ /dev/null
@@ -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
--- a/xpcom/threads/moz.build
+++ b/xpcom/threads/moz.build
@@ -39,18 +39,16 @@ EXPORTS.mozilla += [
'AbstractEventQueue.h',
'AbstractThread.h',
'BlockingResourceBase.h',
'CondVar.h',
'CooperativeThreadPool.h',
'CPUUsageWatcher.h',
'DeadlockDetector.h',
'EventQueue.h',
- 'HangAnnotations.h',
- 'HangMonitor.h',
'IdleTaskRunner.h',
'LazyIdleThread.h',
'MainThreadIdlePeriod.h',
'Monitor.h',
'MozPromise.h',
'Mutex.h',
'PerformanceCounter.h',
'Queue.h',
@@ -77,18 +75,16 @@ SOURCES += [
]
UNIFIED_SOURCES += [
'AbstractThread.cpp',
'BlockingResourceBase.cpp',
'CooperativeThreadPool.cpp',
'CPUUsageWatcher.cpp',
'EventQueue.cpp',
- 'HangAnnotations.cpp',
- 'HangMonitor.cpp',
'InputEventStatistics.cpp',
'LabeledEventQueue.cpp',
'LazyIdleThread.cpp',
'MainThreadIdlePeriod.cpp',
'nsEnvironment.cpp',
'nsILabelableRunnable.cpp',
'nsMemoryPressure.cpp',
'nsProcessCommon.cpp',
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -16,20 +16,20 @@
#include "mozilla/ReentrantMonitor.h"
#include "nsMemoryPressure.h"
#include "nsThreadManager.h"
#include "nsIClassInfoImpl.h"
#include "nsAutoPtr.h"
#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"
#include "mozilla/Preferences.h"
#include "mozilla/Scheduler.h"
#include "mozilla/SchedulerGroup.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPrefs.h"
@@ -987,17 +987,17 @@ nsThread::ProcessNextEvent(bool aMayWait
}
*aResult = (event.get() != nullptr);
if (event) {
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();
if (schedulerLoggingEnabled
&& mNestedEventLoopDepth > mCurrentEventLoopDepth
&& mCurrentPerformanceCounter) {
// This is a recursive call, we're saving the time
// spent in the parent event if the runnable is linked to a DocGroup.
@@ -1214,17 +1214,17 @@ nsThread::SetScriptObserver(mozilla::Cyc
void
nsThread::DoMainThreadSpecificProcessing(bool aReallyWait)
{
MOZ_ASSERT(mIsMainThread == MAIN_THREAD);
ipc::CancelCPOWs();
if (aReallyWait) {
- HangMonitor::Suspend();
+ BackgroundHangMonitor().NotifyWait();
}
// Fire a memory pressure notification, if one is pending.
if (!ShuttingDown()) {
MemoryPressureState mpPending = NS_GetPendingMemoryPressure();
if (mpPending != MemPressure_None) {
nsCOMPtr<nsIObserverService> os = services::GetObserverService();