forked from mirrors/gecko-dev
Bug 1459212 - Save memory reports for use in crash reports when low on memory r=dmajor,mccr8
This moves the code that detects very low memory scenarios and grabs memory reports from the main thread event-loop to the available memory tracker. Besides removing the overhead of the check from the event-loop code this increases the likeliness of the reports being gathered by sampling at a higher frequency but only when we already detected a low-memory scenario. Last but not least this add checks for low commit-space detection alongside low virtual-memory detection. Differential Revision: https://phabricator.services.mozilla.com/D3669 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
940e4e9f2c
commit
afec91a1db
7 changed files with 34 additions and 121 deletions
|
|
@ -5340,18 +5340,6 @@ ContentParent::RecvNotifyPushSubscriptionModifiedObservers(const nsCString& aSco
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvNotifyLowMemory()
|
||||
{
|
||||
MarkAsTroubled();
|
||||
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::DOM_CONTENTPROCESS_TROUBLED_DUE_TO_MEMORY, 1);
|
||||
|
||||
nsThread::SaveMemoryReportNearOOM(nsThread::ShouldSaveMemoryReport::kForceReport);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ContentParent::BroadcastBlobURLRegistration(const nsACString& aURI,
|
||||
BlobImpl* aBlobImpl,
|
||||
|
|
|
|||
|
|
@ -1222,8 +1222,6 @@ public:
|
|||
virtual mozilla::ipc::IPCResult RecvNotifyPushSubscriptionModifiedObservers(const nsCString& aScope,
|
||||
const IPC::Principal& aPrincipal) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvNotifyLowMemory() override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvGetFilesRequest(const nsID& aID,
|
||||
const nsString& aDirectoryPath,
|
||||
const bool& aRecursiveFlag) override;
|
||||
|
|
|
|||
|
|
@ -1123,13 +1123,6 @@ parent:
|
|||
async NotifyPushSubscriptionChangeObservers(nsCString scope,
|
||||
Principal principal);
|
||||
|
||||
/**
|
||||
* Tell the parent process that the child process is low on memory. This
|
||||
* allows the parent process to save a memory report that can potentially be
|
||||
* sent with a crash report from the content process.
|
||||
*/
|
||||
async NotifyLowMemory();
|
||||
|
||||
async GetFilesRequest(nsID aID, nsString aDirectory, bool aRecursiveFlag);
|
||||
async DeleteGetFilesRequest(nsID aID);
|
||||
|
||||
|
|
|
|||
|
|
@ -950,21 +950,6 @@ media:
|
|||
|
||||
# The following section contains content process base counters.
|
||||
dom.contentprocess:
|
||||
troubled_due_to_memory:
|
||||
bug_numbers:
|
||||
- 1305091
|
||||
description: >
|
||||
The number of content processes that were marked as troubled because
|
||||
it was running low on virtual memory.
|
||||
expires: "58"
|
||||
kind: uint
|
||||
notification_emails:
|
||||
- benjamin@smedbergs.us
|
||||
- mconley@mozilla.com
|
||||
release_channel_collection: opt-in
|
||||
record_in_processes:
|
||||
- 'main'
|
||||
|
||||
buildID_mismatch:
|
||||
bug_numbers:
|
||||
- 1366808
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#if defined(XP_WIN)
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsICrashReporter.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsMemoryPressure.h"
|
||||
#endif
|
||||
|
|
@ -46,6 +47,7 @@ public:
|
|||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
nsAvailableMemoryWatcher();
|
||||
nsresult Init();
|
||||
|
||||
private:
|
||||
|
|
@ -57,8 +59,8 @@ private:
|
|||
static const size_t kLowVirtualMemoryThreshold = 256 * 1024 * 1024;
|
||||
#endif
|
||||
|
||||
// Fire a low-memory notification if we have less than this many bytes of commit
|
||||
// space (physical memory plus page file) left.
|
||||
// Fire a low-memory notification if we have less than this many bytes of
|
||||
// commit space (physical memory plus page file) left.
|
||||
static const size_t kLowCommitSpaceThreshold = 256 * 1024 * 1024;
|
||||
|
||||
// Fire a low-memory notification if we have less than this many bytes of
|
||||
|
|
@ -80,12 +82,15 @@ private:
|
|||
static bool IsPhysicalMemoryLow(const MEMORYSTATUSEX& aStat);
|
||||
|
||||
~nsAvailableMemoryWatcher() {};
|
||||
bool OngoingMemoryPressure() { return mUnderMemoryPressure; }
|
||||
void AdjustPollingInterval(const bool aLowMemory);
|
||||
void SendMemoryPressureEvent();
|
||||
void MaybeSaveMemoryReport();
|
||||
void Shutdown();
|
||||
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
bool mUnderMemoryPressure;
|
||||
bool mSavedReport;
|
||||
};
|
||||
|
||||
const char* const nsAvailableMemoryWatcher::kObserverTopics[] = {
|
||||
|
|
@ -96,6 +101,13 @@ const char* const nsAvailableMemoryWatcher::kObserverTopics[] = {
|
|||
|
||||
NS_IMPL_ISUPPORTS(nsAvailableMemoryWatcher, nsIObserver, nsITimerCallback)
|
||||
|
||||
nsAvailableMemoryWatcher::nsAvailableMemoryWatcher()
|
||||
: mTimer(nullptr)
|
||||
, mUnderMemoryPressure(false)
|
||||
, mSavedReport(false)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAvailableMemoryWatcher::Init()
|
||||
{
|
||||
|
|
@ -173,11 +185,25 @@ nsAvailableMemoryWatcher::IsPhysicalMemoryLow(const MEMORYSTATUSEX& aStat)
|
|||
void
|
||||
nsAvailableMemoryWatcher::SendMemoryPressureEvent()
|
||||
{
|
||||
MemoryPressureState state = mUnderMemoryPressure ? MemPressure_Ongoing
|
||||
: MemPressure_New;
|
||||
MemoryPressureState state = OngoingMemoryPressure() ? MemPressure_Ongoing
|
||||
: MemPressure_New;
|
||||
NS_DispatchEventualMemoryPressure(state);
|
||||
}
|
||||
|
||||
void
|
||||
nsAvailableMemoryWatcher::MaybeSaveMemoryReport()
|
||||
{
|
||||
if (!mSavedReport && OngoingMemoryPressure()) {
|
||||
nsCOMPtr<nsICrashReporter> cr =
|
||||
do_GetService("@mozilla.org/toolkit/crash-reporter;1");
|
||||
if (cr) {
|
||||
if (NS_SUCCEEDED(cr->SaveMemoryReport())) {
|
||||
mSavedReport = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAvailableMemoryWatcher::AdjustPollingInterval(const bool aLowMemory)
|
||||
{
|
||||
|
|
@ -185,7 +211,7 @@ nsAvailableMemoryWatcher::AdjustPollingInterval(const bool aLowMemory)
|
|||
// We entered a low-memory state, wait for a longer interval before polling
|
||||
// again as there's no point in rapidly sending further notifications.
|
||||
mTimer->SetDelay(kLowMemoryNotificationIntervalMS);
|
||||
} else if (mUnderMemoryPressure) {
|
||||
} else if (OngoingMemoryPressure()) {
|
||||
// We were under memory pressure but we're not anymore, resume polling at
|
||||
// a faster pace.
|
||||
mTimer->SetDelay(kPollingIntervalMS);
|
||||
|
|
@ -210,6 +236,9 @@ nsAvailableMemoryWatcher::Notify(nsITimer* aTimer)
|
|||
|
||||
if (lowMemory) {
|
||||
SendMemoryPressureEvent();
|
||||
MaybeSaveMemoryReport();
|
||||
} else {
|
||||
mSavedReport = false; // Save a new report if memory gets low again
|
||||
}
|
||||
|
||||
AdjustPollingInterval(lowMemory);
|
||||
|
|
|
|||
|
|
@ -41,15 +41,12 @@
|
|||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsICrashReporter.h"
|
||||
#include "nsThreadSyncDispatch.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "InputEventStatistics.h"
|
||||
#include "ThreadEventTarget.h"
|
||||
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
|
||||
#ifdef XP_LINUX
|
||||
#ifdef __GLIBC__
|
||||
#include <gnu/libc-version.h>
|
||||
|
|
@ -593,71 +590,6 @@ nsThread::InitCommon()
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Tell the crash reporter to save a memory report if our heuristics determine
|
||||
// that an OOM failure is likely to occur soon.
|
||||
// Memory usage will not be checked more than every 30 seconds or saved more
|
||||
// than every 3 minutes
|
||||
// If |aShouldSave == kForceReport|, a report will be saved regardless of
|
||||
// whether the process is low on memory or not. However, it will still not be
|
||||
// saved if a report was saved less than 3 minutes ago.
|
||||
bool
|
||||
nsThread::SaveMemoryReportNearOOM(ShouldSaveMemoryReport aShouldSave)
|
||||
{
|
||||
// Keep an eye on memory usage (cheap, ~7ms) somewhat frequently,
|
||||
// but save memory reports (expensive, ~75ms) less frequently.
|
||||
const size_t kLowMemoryCheckSeconds = 30;
|
||||
const size_t kLowMemorySaveSeconds = 3 * 60;
|
||||
|
||||
static TimeStamp nextCheck = TimeStamp::NowLoRes()
|
||||
+ TimeDuration::FromSeconds(kLowMemoryCheckSeconds);
|
||||
static bool recentlySavedReport = false; // Keeps track of whether a report
|
||||
// was saved last time we checked
|
||||
|
||||
// Are we checking again too soon?
|
||||
TimeStamp now = TimeStamp::NowLoRes();
|
||||
if ((aShouldSave == ShouldSaveMemoryReport::kMaybeReport ||
|
||||
recentlySavedReport) && now < nextCheck) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool needMemoryReport = (aShouldSave == ShouldSaveMemoryReport::kForceReport);
|
||||
#ifdef XP_WIN // XXX implement on other platforms as needed
|
||||
// If the report is forced there is no need to check whether it is necessary
|
||||
if (aShouldSave != ShouldSaveMemoryReport::kForceReport) {
|
||||
const size_t LOWMEM_THRESHOLD_VIRTUAL = 200 * 1024 * 1024;
|
||||
MEMORYSTATUSEX statex;
|
||||
statex.dwLength = sizeof(statex);
|
||||
if (GlobalMemoryStatusEx(&statex)) {
|
||||
if (statex.ullAvailVirtual < LOWMEM_THRESHOLD_VIRTUAL) {
|
||||
needMemoryReport = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (needMemoryReport) {
|
||||
if (XRE_IsContentProcess()) {
|
||||
dom::ContentChild* cc = dom::ContentChild::GetSingleton();
|
||||
if (cc) {
|
||||
cc->SendNotifyLowMemory();
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsICrashReporter> cr =
|
||||
do_GetService("@mozilla.org/toolkit/crash-reporter;1");
|
||||
if (cr) {
|
||||
cr->SaveMemoryReport();
|
||||
}
|
||||
}
|
||||
recentlySavedReport = true;
|
||||
nextCheck = now + TimeDuration::FromSeconds(kLowMemorySaveSeconds);
|
||||
} else {
|
||||
recentlySavedReport = false;
|
||||
nextCheck = now + TimeDuration::FromSeconds(kLowMemoryCheckSeconds);
|
||||
}
|
||||
|
||||
return recentlySavedReport;
|
||||
}
|
||||
|
||||
#ifdef MOZ_CANARY
|
||||
int sCanaryOutputFD = -1;
|
||||
#endif
|
||||
|
|
@ -1425,10 +1357,6 @@ nsThread::DoMainThreadSpecificProcessing(bool aReallyWait)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ShuttingDown()) {
|
||||
SaveMemoryReportNearOOM(ShouldSaveMemoryReport::kMaybeReport);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
|||
|
|
@ -100,14 +100,6 @@ public:
|
|||
|
||||
void WaitForAllAsynchronousShutdowns();
|
||||
|
||||
enum class ShouldSaveMemoryReport
|
||||
{
|
||||
kMaybeReport,
|
||||
kForceReport
|
||||
};
|
||||
|
||||
static bool SaveMemoryReportNearOOM(ShouldSaveMemoryReport aShouldSave);
|
||||
|
||||
static const uint32_t kRunnableNameBufSize = 1000;
|
||||
static mozilla::Array<char, kRunnableNameBufSize> sMainThreadRunnableName;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue