mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Back out e05936099653 (bug 1154053) on suspicion of causing the hellish frequency of Android 2.3 robocop-2 crashes that resulted in this CLOSED TREE, a=bustage
This commit is contained in:
parent
1a25d3754b
commit
3fc48280b7
@ -424,7 +424,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const uint32_t mGeneration;
|
const uint32_t mGeneration;
|
||||||
// Non-null if we haven't yet called EndProcessReport() on it.
|
// Non-null if we haven't yet called EndChildReport() on it.
|
||||||
nsRefPtr<nsMemoryReporterManager> mReporterManager;
|
nsRefPtr<nsMemoryReporterManager> mReporterManager;
|
||||||
|
|
||||||
ContentParent* Owner()
|
ContentParent* Owner()
|
||||||
@ -464,7 +464,7 @@ void
|
|||||||
MemoryReportRequestParent::ActorDestroy(ActorDestroyReason aWhy)
|
MemoryReportRequestParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||||
{
|
{
|
||||||
if (mReporterManager) {
|
if (mReporterManager) {
|
||||||
mReporterManager->EndProcessReport(mGeneration, aWhy == Deletion);
|
mReporterManager->EndChildReport(mGeneration, aWhy == Deletion);
|
||||||
mReporterManager = nullptr;
|
mReporterManager = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -648,6 +648,7 @@ static const char* sObserverTopics[] = {
|
|||||||
"profile-before-change",
|
"profile-before-change",
|
||||||
NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
|
NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
|
||||||
NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
|
NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
|
||||||
|
"child-memory-reporter-request",
|
||||||
"memory-pressure",
|
"memory-pressure",
|
||||||
"child-gc-request",
|
"child-gc-request",
|
||||||
"child-cc-request",
|
"child-cc-request",
|
||||||
@ -1975,6 +1976,18 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tell the memory reporter manager that this ContentParent is going away.
|
||||||
|
nsRefPtr<nsMemoryReporterManager> mgr =
|
||||||
|
nsMemoryReporterManager::GetOrCreate();
|
||||||
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
|
bool isMemoryChild = !IsNuwaProcess();
|
||||||
|
#else
|
||||||
|
bool isMemoryChild = true;
|
||||||
|
#endif
|
||||||
|
if (mgr && isMemoryChild) {
|
||||||
|
mgr->DecrementNumChildProcesses();
|
||||||
|
}
|
||||||
|
|
||||||
// remove the global remote preferences observers
|
// remove the global remote preferences observers
|
||||||
Preferences::RemoveObserver(this, "");
|
Preferences::RemoveObserver(this, "");
|
||||||
|
|
||||||
@ -2248,6 +2261,15 @@ ContentParent::ContentParent(mozIApplication* aApp,
|
|||||||
|
|
||||||
IToplevelProtocol::SetTransport(mSubprocess->GetChannel());
|
IToplevelProtocol::SetTransport(mSubprocess->GetChannel());
|
||||||
|
|
||||||
|
if (!aIsNuwaProcess) {
|
||||||
|
// Tell the memory reporter manager that this ContentParent exists.
|
||||||
|
nsRefPtr<nsMemoryReporterManager> mgr =
|
||||||
|
nsMemoryReporterManager::GetOrCreate();
|
||||||
|
if (mgr) {
|
||||||
|
mgr->IncrementNumChildProcesses();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> extraArgs;
|
std::vector<std::string> extraArgs;
|
||||||
if (aIsNuwaProcess) {
|
if (aIsNuwaProcess) {
|
||||||
extraArgs.push_back("-nuwa");
|
extraArgs.push_back("-nuwa");
|
||||||
@ -2312,6 +2334,13 @@ ContentParent::ContentParent(ContentParent* aTemplate,
|
|||||||
aPid,
|
aPid,
|
||||||
*fd);
|
*fd);
|
||||||
|
|
||||||
|
// Tell the memory reporter manager that this ContentParent exists.
|
||||||
|
nsRefPtr<nsMemoryReporterManager> mgr =
|
||||||
|
nsMemoryReporterManager::GetOrCreate();
|
||||||
|
if (mgr) {
|
||||||
|
mgr->IncrementNumChildProcesses();
|
||||||
|
}
|
||||||
|
|
||||||
mSubprocess->LaunchAndWaitForProcessHandle();
|
mSubprocess->LaunchAndWaitForProcessHandle();
|
||||||
|
|
||||||
// Clone actors routed by aTemplate for this instance.
|
// Clone actors routed by aTemplate for this instance.
|
||||||
@ -3033,6 +3062,46 @@ ContentParent::Observe(nsISupports* aSubject,
|
|||||||
nsDependentString(aData)))
|
nsDependentString(aData)))
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(aTopic, "child-memory-reporter-request")) {
|
||||||
|
bool isNuwa = false;
|
||||||
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
|
isNuwa = IsNuwaProcess();
|
||||||
|
#endif
|
||||||
|
if (!isNuwa) {
|
||||||
|
unsigned generation;
|
||||||
|
int anonymize, minimize, identOffset = -1;
|
||||||
|
nsDependentString msg(aData);
|
||||||
|
NS_ConvertUTF16toUTF8 cmsg(msg);
|
||||||
|
|
||||||
|
if (sscanf(cmsg.get(),
|
||||||
|
"generation=%x anonymize=%d minimize=%d DMDident=%n",
|
||||||
|
&generation, &anonymize, &minimize, &identOffset) < 3
|
||||||
|
|| identOffset < 0) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
// The pre-%n part of the string should be all ASCII, so the byte
|
||||||
|
// offset in identOffset should be correct as a char offset.
|
||||||
|
MOZ_ASSERT(cmsg[identOffset - 1] == '=');
|
||||||
|
MaybeFileDesc dmdFileDesc = void_t();
|
||||||
|
#ifdef MOZ_DMD
|
||||||
|
nsAutoString dmdIdent(Substring(msg, identOffset));
|
||||||
|
if (!dmdIdent.IsEmpty()) {
|
||||||
|
FILE *dmdFile = nullptr;
|
||||||
|
nsresult rv = nsMemoryInfoDumper::OpenDMDFile(dmdIdent, Pid(), &dmdFile);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
// Proceed with the memory report as if DMD were disabled.
|
||||||
|
dmdFile = nullptr;
|
||||||
|
}
|
||||||
|
if (dmdFile) {
|
||||||
|
dmdFileDesc = FILEToFileDescriptor(dmdFile);
|
||||||
|
fclose(dmdFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
unused << SendPMemoryReportRequestConstructor(
|
||||||
|
generation, anonymize, minimize, dmdFileDesc);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (!strcmp(aTopic, "child-gc-request")){
|
else if (!strcmp(aTopic, "child-gc-request")){
|
||||||
unused << SendGarbageCollect();
|
unused << SendGarbageCollect();
|
||||||
}
|
}
|
||||||
|
@ -4749,13 +4749,3 @@ pref("dom.secureelement.enabled", false);
|
|||||||
// both composition string and data attribute of compositionupdate
|
// both composition string and data attribute of compositionupdate
|
||||||
// and compositionend events.
|
// and compositionend events.
|
||||||
pref("dom.compositionevent.allow_control_characters", false);
|
pref("dom.compositionevent.allow_control_characters", false);
|
||||||
|
|
||||||
#ifdef MOZ_WIDGET_GONK
|
|
||||||
// Bug 1154053: Serialize B2G memory reports; smaller devices are
|
|
||||||
// usually overcommitted on memory by using zRAM, so memory reporting
|
|
||||||
// causes memory pressure from uncompressing cold heap memory.
|
|
||||||
pref("memory.report_concurrency", 1);
|
|
||||||
#else
|
|
||||||
// Desktop probably doesn't have swapped-out children like that.
|
|
||||||
pref("memory.report_concurrency", 10);
|
|
||||||
#endif
|
|
||||||
|
@ -35,7 +35,6 @@
|
|||||||
|
|
||||||
let prefs = [
|
let prefs = [
|
||||||
["dom.ipc.processCount", 3], // Allow up to 3 child processes
|
["dom.ipc.processCount", 3], // Allow up to 3 child processes
|
||||||
["memory.report_concurrency", 2], // Cover more child handling cases
|
|
||||||
["memory.system_memory_reporter", true] // Test SystemMemoryReporter
|
["memory.system_memory_reporter", true] // Test SystemMemoryReporter
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -23,12 +23,9 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/PodOperations.h"
|
#include "mozilla/PodOperations.h"
|
||||||
#include "mozilla/Preferences.h"
|
|
||||||
#include "mozilla/Services.h"
|
#include "mozilla/Services.h"
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
#include "mozilla/dom/PMemoryReportRequestParent.h" // for dom::MemoryReport
|
#include "mozilla/dom/PMemoryReportRequestParent.h" // for dom::MemoryReport
|
||||||
#include "mozilla/dom/ContentParent.h"
|
|
||||||
#include "mozilla/ipc/FileDescriptorUtils.h"
|
|
||||||
|
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
#include <process.h>
|
#include <process.h>
|
||||||
@ -1249,6 +1246,7 @@ nsMemoryReporterManager::nsMemoryReporterManager()
|
|||||||
, mWeakReporters(new WeakReportersTable())
|
, mWeakReporters(new WeakReportersTable())
|
||||||
, mSavedStrongReporters(nullptr)
|
, mSavedStrongReporters(nullptr)
|
||||||
, mSavedWeakReporters(nullptr)
|
, mSavedWeakReporters(nullptr)
|
||||||
|
, mNumChildProcesses(0)
|
||||||
, mNextGeneration(1)
|
, mNextGeneration(1)
|
||||||
, mGetReportsState(nullptr)
|
, mGetReportsState(nullptr)
|
||||||
{
|
{
|
||||||
@ -1273,6 +1271,29 @@ nsMemoryReporterManager::~nsMemoryReporterManager()
|
|||||||
#define MEMORY_REPORTING_LOG(...)
|
#define MEMORY_REPORTING_LOG(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
nsMemoryReporterManager::IncrementNumChildProcesses()
|
||||||
|
{
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
MOZ_CRASH();
|
||||||
|
}
|
||||||
|
mNumChildProcesses++;
|
||||||
|
MEMORY_REPORTING_LOG("IncrementNumChildProcesses --> %d\n",
|
||||||
|
mNumChildProcesses);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsMemoryReporterManager::DecrementNumChildProcesses()
|
||||||
|
{
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
MOZ_CRASH();
|
||||||
|
}
|
||||||
|
MOZ_ASSERT(mNumChildProcesses > 0);
|
||||||
|
mNumChildProcesses--;
|
||||||
|
MEMORY_REPORTING_LOG("DecrementNumChildProcesses --> %d\n",
|
||||||
|
mNumChildProcesses);
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMemoryReporterManager::GetReports(
|
nsMemoryReporterManager::GetReports(
|
||||||
nsIHandleReportCallback* aHandleReport,
|
nsIHandleReportCallback* aHandleReport,
|
||||||
@ -1316,23 +1337,18 @@ nsMemoryReporterManager::GetReportsExtended(
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
MEMORY_REPORTING_LOG("GetReports (gen=%u)\n", generation);
|
MEMORY_REPORTING_LOG("GetReports (gen=%u, %d child(ren) present)\n",
|
||||||
|
generation, mNumChildProcesses);
|
||||||
|
|
||||||
uint32_t concurrency = Preferences::GetUint("memory.report_concurrency", 1);
|
|
||||||
MOZ_ASSERT(concurrency >= 1);
|
|
||||||
if (concurrency < 1) {
|
|
||||||
concurrency = 1;
|
|
||||||
}
|
|
||||||
mGetReportsState = new GetReportsState(generation,
|
mGetReportsState = new GetReportsState(generation,
|
||||||
aAnonymize,
|
aAnonymize,
|
||||||
aMinimize,
|
aMinimize,
|
||||||
concurrency,
|
mNumChildProcesses,
|
||||||
aHandleReport,
|
aHandleReport,
|
||||||
aHandleReportData,
|
aHandleReportData,
|
||||||
aFinishReporting,
|
aFinishReporting,
|
||||||
aFinishReportingData,
|
aFinishReportingData,
|
||||||
aDMDDumpIdent);
|
aDMDDumpIdent);
|
||||||
mGetReportsState->mChildrenPending = new nsTArray<nsRefPtr<mozilla::dom::ContentParent>>();
|
|
||||||
|
|
||||||
if (aMinimize) {
|
if (aMinimize) {
|
||||||
rv = MinimizeMemoryUsage(NS_NewRunnableMethod(
|
rv = MinimizeMemoryUsage(NS_NewRunnableMethod(
|
||||||
@ -1364,18 +1380,12 @@ nsMemoryReporterManager::StartGettingReports()
|
|||||||
GetReportsForThisProcessExtended(s->mHandleReport, s->mHandleReportData,
|
GetReportsForThisProcessExtended(s->mHandleReport, s->mHandleReportData,
|
||||||
s->mAnonymize, parentDMDFile);
|
s->mAnonymize, parentDMDFile);
|
||||||
|
|
||||||
nsTArray<ContentParent*> childWeakRefs;
|
MOZ_ASSERT(s->mNumChildProcessesCompleted == 0);
|
||||||
ContentParent::GetAll(childWeakRefs);
|
if (s->mNumChildProcesses > 0) {
|
||||||
if (!childWeakRefs.IsEmpty()) {
|
|
||||||
// Request memory reports from child processes. This happens
|
// Request memory reports from child processes. This happens
|
||||||
// after the parent report so that the parent's main thread will
|
// after the parent report so that the parent's main thread will
|
||||||
// be free to process the child reports, instead of causing them
|
// be free to process the child reports, instead of causing them
|
||||||
// to be buffered and consume (possibly scarce) memory.
|
// to be buffered and consume (possibly scarce) memory.
|
||||||
|
|
||||||
for (size_t i = 0; i < childWeakRefs.Length(); ++i) {
|
|
||||||
s->mChildrenPending->AppendElement(childWeakRefs[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||||
// Don't use NS_ENSURE_* here; can't return until the report is finished.
|
// Don't use NS_ENSURE_* here; can't return until the report is finished.
|
||||||
if (NS_WARN_IF(!timer)) {
|
if (NS_WARN_IF(!timer)) {
|
||||||
@ -1392,12 +1402,27 @@ nsMemoryReporterManager::StartGettingReports()
|
|||||||
|
|
||||||
MOZ_ASSERT(!s->mTimer);
|
MOZ_ASSERT(!s->mTimer);
|
||||||
s->mTimer.swap(timer);
|
s->mTimer.swap(timer);
|
||||||
}
|
|
||||||
|
|
||||||
// The parent's report is done; make note of that, and start
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||||
// launching child process reports (if any).
|
if (NS_WARN_IF(!obs)) {
|
||||||
EndProcessReport(s->mGeneration, true);
|
FinishReporting();
|
||||||
return NS_OK;
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsPrintfCString genStr("generation=%x anonymize=%d minimize=%d DMDident=",
|
||||||
|
s->mGeneration, s->mAnonymize ? 1 : 0,
|
||||||
|
s->mMinimize ? 1 : 0);
|
||||||
|
nsAutoString msg = NS_ConvertUTF8toUTF16(genStr);
|
||||||
|
msg += s->mDMDDumpIdent;
|
||||||
|
|
||||||
|
obs->NotifyObservers(nullptr, "child-memory-reporter-request",
|
||||||
|
msg.get());
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
} else {
|
||||||
|
// If there are no child processes, we can finish up immediately.
|
||||||
|
return FinishReporting();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef nsCOMArray<nsIMemoryReporter> MemoryReporterArray;
|
typedef nsCOMArray<nsIMemoryReporter> MemoryReporterArray;
|
||||||
@ -1477,12 +1502,17 @@ nsMemoryReporterManager::GetStateForGeneration(uint32_t aGeneration)
|
|||||||
GetReportsState* s = mGetReportsState;
|
GetReportsState* s = mGetReportsState;
|
||||||
|
|
||||||
if (!s) {
|
if (!s) {
|
||||||
// If we reach here, then:
|
// If we reach here, either:
|
||||||
//
|
//
|
||||||
// - A child process reported back too late, and no subsequent request
|
// - A child process reported back too late, and no subsequent request
|
||||||
// is in flight.
|
// is in flight.
|
||||||
//
|
//
|
||||||
// So there's nothing to be done. Just ignore it.
|
// - (Unlikely) A "child-memory-reporter-request" notification was
|
||||||
|
// triggered from somewhere other than GetReports(), causing child
|
||||||
|
// processes to report back when the nsMemoryReporterManager wasn't
|
||||||
|
// expecting it.
|
||||||
|
//
|
||||||
|
// Either way, there's nothing to be done. Just ignore it.
|
||||||
MEMORY_REPORTING_LOG(
|
MEMORY_REPORTING_LOG(
|
||||||
"HandleChildReports: no request in flight (aGen=%u)\n",
|
"HandleChildReports: no request in flight (aGen=%u)\n",
|
||||||
aGeneration);
|
aGeneration);
|
||||||
@ -1529,85 +1559,31 @@ nsMemoryReporterManager::HandleChildReport(
|
|||||||
s->mHandleReportData);
|
s->mHandleReportData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ bool
|
|
||||||
nsMemoryReporterManager::StartChildReport(mozilla::dom::ContentParent* aChild,
|
|
||||||
const GetReportsState* aState)
|
|
||||||
{
|
|
||||||
#ifdef MOZ_NUWA_PROCESS
|
|
||||||
if (aChild->IsNuwaProcess()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!aChild->IsAlive()) {
|
|
||||||
MEMORY_REPORTING_LOG("StartChildReports (gen=%u): child exited before"
|
|
||||||
" its report was started\n",
|
|
||||||
aState->mGeneration);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mozilla::dom::MaybeFileDesc dmdFileDesc = void_t();
|
|
||||||
#ifdef MOZ_DMD
|
|
||||||
if (!aState->mDMDDumpIdent.IsEmpty()) {
|
|
||||||
FILE *dmdFile = nullptr;
|
|
||||||
nsresult rv = nsMemoryInfoDumper::OpenDMDFile(aState->mDMDDumpIdent,
|
|
||||||
aChild->Pid(), &dmdFile);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
// Proceed with the memory report as if DMD were disabled.
|
|
||||||
dmdFile = nullptr;
|
|
||||||
}
|
|
||||||
if (dmdFile) {
|
|
||||||
dmdFileDesc = mozilla::ipc::FILEToFileDescriptor(dmdFile);
|
|
||||||
fclose(dmdFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return aChild->SendPMemoryReportRequestConstructor(
|
|
||||||
aState->mGeneration, aState->mAnonymize, aState->mMinimize, dmdFileDesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsMemoryReporterManager::EndProcessReport(uint32_t aGeneration, bool aSuccess)
|
nsMemoryReporterManager::EndChildReport(uint32_t aGeneration, bool aSuccess)
|
||||||
{
|
{
|
||||||
GetReportsState* s = GetStateForGeneration(aGeneration);
|
GetReportsState* s = GetStateForGeneration(aGeneration);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(s->mNumProcessesRunning > 0);
|
s->mNumChildProcessesCompleted++;
|
||||||
s->mNumProcessesRunning--;
|
|
||||||
s->mNumProcessesCompleted++;
|
|
||||||
MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): process %u %s"
|
|
||||||
" (%u running, %u pending)\n",
|
|
||||||
aGeneration, s->mNumProcessesCompleted,
|
|
||||||
aSuccess ? "completed" : "exited during report",
|
|
||||||
s->mNumProcessesRunning,
|
|
||||||
static_cast<unsigned>(s->mChildrenPending->Length()));
|
|
||||||
|
|
||||||
// Start pending children up to the concurrency limit.
|
if (aSuccess) {
|
||||||
while (s->mNumProcessesRunning < s->mConcurrencyLimit &&
|
MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): completed child %d\n",
|
||||||
!s->mChildrenPending->IsEmpty()) {
|
aGeneration, s->mNumChildProcessesCompleted);
|
||||||
// Pop last element from s->mChildrenPending
|
} else {
|
||||||
nsRefPtr<ContentParent> nextChild;
|
// Unfortunately, there's no way to indicate this in the report yet.
|
||||||
nextChild.swap(s->mChildrenPending->LastElement());
|
// (Also, we don't have the child's identifier at this point.)
|
||||||
s->mChildrenPending->TruncateLength(s->mChildrenPending->Length() - 1);
|
MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): child %d exited"
|
||||||
// Start report (if the child is still alive and not Nuwa).
|
" during report\n",
|
||||||
if (StartChildReport(nextChild, s)) {
|
aGeneration, s->mNumChildProcessesCompleted);
|
||||||
++s->mNumProcessesRunning;
|
|
||||||
MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): started child report"
|
|
||||||
" (%u running, %u pending)\n",
|
|
||||||
aGeneration, s->mNumProcessesRunning,
|
|
||||||
static_cast<unsigned>(s->mChildrenPending->Length()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If all the child processes (if any) have reported, we can cancel
|
// If all the child processes have reported, we can cancel the timer and
|
||||||
// the timer (if started) and finish up. Otherwise, just return.
|
// finish up. Otherwise, just return.
|
||||||
if (s->mNumProcessesRunning == 0) {
|
if (s->mNumChildProcessesCompleted >= s->mNumChildProcesses) {
|
||||||
MOZ_ASSERT(s->mChildrenPending->IsEmpty());
|
s->mTimer->Cancel();
|
||||||
if (s->mTimer) {
|
|
||||||
s->mTimer->Cancel();
|
|
||||||
}
|
|
||||||
FinishReporting();
|
FinishReporting();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1622,9 +1598,8 @@ nsMemoryReporterManager::TimeoutCallback(nsITimer* aTimer, void* aData)
|
|||||||
// crash regardless of DEBUG, and this way the compiler doesn't
|
// crash regardless of DEBUG, and this way the compiler doesn't
|
||||||
// complain about unused variables.
|
// complain about unused variables.
|
||||||
MOZ_RELEASE_ASSERT(s, "mgr->mGetReportsState");
|
MOZ_RELEASE_ASSERT(s, "mgr->mGetReportsState");
|
||||||
MEMORY_REPORTING_LOG("TimeoutCallback (s->gen=%u; %u running, %u pending)\n",
|
MEMORY_REPORTING_LOG("TimeoutCallback (s->gen=%u)\n",
|
||||||
s->mGeneration, s->mNumProcessesRunning,
|
s->mGeneration);
|
||||||
static_cast<unsigned>(s->mChildrenPending->Length()));
|
|
||||||
|
|
||||||
// We don't bother sending any kind of cancellation message to the child
|
// We don't bother sending any kind of cancellation message to the child
|
||||||
// processes that haven't reported back.
|
// processes that haven't reported back.
|
||||||
@ -1640,9 +1615,8 @@ nsMemoryReporterManager::FinishReporting()
|
|||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(mGetReportsState);
|
MOZ_ASSERT(mGetReportsState);
|
||||||
MEMORY_REPORTING_LOG("FinishReporting (s->gen=%u; %u processes reported)\n",
|
MEMORY_REPORTING_LOG("FinishReporting (s->gen=%u)\n",
|
||||||
mGetReportsState->mGeneration,
|
mGetReportsState->mGeneration);
|
||||||
mGetReportsState->mNumProcessesCompleted);
|
|
||||||
|
|
||||||
// Call this before deleting |mGetReportsState|. That way, if
|
// Call this before deleting |mGetReportsState|. That way, if
|
||||||
// |mFinishReportData| calls GetReports(), it will silently abort, as
|
// |mFinishReportData| calls GetReports(), it will silently abort, as
|
||||||
@ -1655,11 +1629,6 @@ nsMemoryReporterManager::FinishReporting()
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsMemoryReporterManager::GetReportsState::~GetReportsState()
|
|
||||||
{
|
|
||||||
delete mChildrenPending;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
CrashIfRefcountIsZero(nsISupports* aObj)
|
CrashIfRefcountIsZero(nsISupports* aObj)
|
||||||
{
|
{
|
||||||
|
@ -7,22 +7,21 @@
|
|||||||
#ifndef nsMemoryReporterManager_h__
|
#ifndef nsMemoryReporterManager_h__
|
||||||
#define nsMemoryReporterManager_h__
|
#define nsMemoryReporterManager_h__
|
||||||
|
|
||||||
#include "mozilla/Mutex.h"
|
|
||||||
#include "nsHashKeys.h"
|
|
||||||
#include "nsIMemoryReporter.h"
|
#include "nsIMemoryReporter.h"
|
||||||
#include "nsITimer.h"
|
#include "nsITimer.h"
|
||||||
#include "nsServiceManagerUtils.h"
|
#include "nsServiceManagerUtils.h"
|
||||||
|
#include "mozilla/Mutex.h"
|
||||||
#include "nsTHashtable.h"
|
#include "nsTHashtable.h"
|
||||||
|
#include "nsHashKeys.h"
|
||||||
|
|
||||||
|
class nsITimer;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
class ContentParent;
|
|
||||||
class MemoryReport;
|
class MemoryReport;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class nsITimer;
|
|
||||||
|
|
||||||
class nsMemoryReporterManager final : public nsIMemoryReporterManager
|
class nsMemoryReporterManager final : public nsIMemoryReporterManager
|
||||||
{
|
{
|
||||||
virtual ~nsMemoryReporterManager();
|
virtual ~nsMemoryReporterManager();
|
||||||
@ -44,27 +43,24 @@ public:
|
|||||||
typedef nsTHashtable<nsRefPtrHashKey<nsIMemoryReporter>> StrongReportersTable;
|
typedef nsTHashtable<nsRefPtrHashKey<nsIMemoryReporter>> StrongReportersTable;
|
||||||
typedef nsTHashtable<nsPtrHashKey<nsIMemoryReporter>> WeakReportersTable;
|
typedef nsTHashtable<nsPtrHashKey<nsIMemoryReporter>> WeakReportersTable;
|
||||||
|
|
||||||
|
void IncrementNumChildProcesses();
|
||||||
|
void DecrementNumChildProcesses();
|
||||||
|
|
||||||
// Inter-process memory reporting proceeds as follows.
|
// Inter-process memory reporting proceeds as follows.
|
||||||
//
|
//
|
||||||
// - GetReports() (declared within NS_DECL_NSIMEMORYREPORTERMANAGER)
|
// - GetReports() (declared within NS_DECL_NSIMEMORYREPORTERMANAGER)
|
||||||
// synchronously gets memory reports for the current process, sets up some
|
// synchronously gets memory reports for the current process, tells all
|
||||||
// state (mGetReportsState) for when child processes report back --
|
// child processes to get memory reports, and sets up some state
|
||||||
// including a timer -- and starts telling child processes to get memory
|
// (mGetReportsState) for when the child processes report back, including a
|
||||||
// reports. Control then returns to the main event loop.
|
// timer. Control then returns to the main event loop.
|
||||||
//
|
|
||||||
// The number of concurrent child process reports is limited by the pref
|
|
||||||
// "memory.report_concurrency" in order to prevent the memory overhead of
|
|
||||||
// memory reporting from causing problems, especially on B2G when swapping
|
|
||||||
// to compressed RAM; see bug 1154053.
|
|
||||||
//
|
//
|
||||||
// - HandleChildReport() is called (asynchronously) once per child process
|
// - HandleChildReport() is called (asynchronously) once per child process
|
||||||
// reporter callback.
|
// reporter callback.
|
||||||
//
|
//
|
||||||
// - EndProcessReport() is called (asynchronously) once per process that
|
// - EndChildReport() is called (asynchronously) once per child process that
|
||||||
// finishes reporting back, including the parent. If all processes do so
|
// finishes reporting back. If all child processes do so before time-out,
|
||||||
// before time-out, the timer is cancelled. If there are child processes
|
// the timer is cancelled. (The number of child processes is part of the
|
||||||
// whose requests have not yet been sent, they will be started until the
|
// saved request state.)
|
||||||
// concurrency limit is (again) reached.
|
|
||||||
//
|
//
|
||||||
// - TimeoutCallback() is called (asynchronously) if all the child processes
|
// - TimeoutCallback() is called (asynchronously) if all the child processes
|
||||||
// don't respond within the time threshold.
|
// don't respond within the time threshold.
|
||||||
@ -108,12 +104,12 @@ public:
|
|||||||
// is incomplete.
|
// is incomplete.
|
||||||
//
|
//
|
||||||
// Now, what what happens if a child process is created/destroyed in the
|
// Now, what what happens if a child process is created/destroyed in the
|
||||||
// middle of a request? Well, GetReportsState is initialized with an array
|
// middle of a request? Well, GetReportsState contains a copy of
|
||||||
// of child process actors as of when the report started. So...
|
// mNumChildProcesses which it uses to determine finished-ness. So...
|
||||||
//
|
//
|
||||||
// - If a process is created after reporting starts, it won't be sent a
|
// - If a process is created, it won't have received the request for reports,
|
||||||
// request for reports. So the reported data will reflect how things were
|
// and the GetReportsState's mNumChildProcesses won't account for it. So
|
||||||
// when the request began.
|
// the reported data will reflect how things were when the request began.
|
||||||
//
|
//
|
||||||
// - If a process is destroyed before it starts reporting back, the reported
|
// - If a process is destroyed before it starts reporting back, the reported
|
||||||
// data will reflect how things are when the request ends.
|
// data will reflect how things are when the request ends.
|
||||||
@ -131,7 +127,7 @@ public:
|
|||||||
//
|
//
|
||||||
void HandleChildReport(uint32_t aGeneration,
|
void HandleChildReport(uint32_t aGeneration,
|
||||||
const mozilla::dom::MemoryReport& aChildReport);
|
const mozilla::dom::MemoryReport& aChildReport);
|
||||||
void EndProcessReport(uint32_t aGeneration, bool aSuccess);
|
void EndChildReport(uint32_t aGeneration, bool aSuccess);
|
||||||
|
|
||||||
// Functions that (a) implement distinguished amounts, and (b) are outside of
|
// Functions that (a) implement distinguished amounts, and (b) are outside of
|
||||||
// this module.
|
// this module.
|
||||||
@ -203,6 +199,7 @@ private:
|
|||||||
StrongReportersTable* mSavedStrongReporters;
|
StrongReportersTable* mSavedStrongReporters;
|
||||||
WeakReportersTable* mSavedWeakReporters;
|
WeakReportersTable* mSavedWeakReporters;
|
||||||
|
|
||||||
|
uint32_t mNumChildProcesses;
|
||||||
uint32_t mNextGeneration;
|
uint32_t mNextGeneration;
|
||||||
|
|
||||||
struct GetReportsState
|
struct GetReportsState
|
||||||
@ -211,13 +208,8 @@ private:
|
|||||||
bool mAnonymize;
|
bool mAnonymize;
|
||||||
bool mMinimize;
|
bool mMinimize;
|
||||||
nsCOMPtr<nsITimer> mTimer;
|
nsCOMPtr<nsITimer> mTimer;
|
||||||
// This is a pointer to an nsTArray because otherwise C++ is
|
uint32_t mNumChildProcesses;
|
||||||
// unhappy unless this header includes ContentParent.h, which not
|
uint32_t mNumChildProcessesCompleted;
|
||||||
// everything that includes this header knows how to find.
|
|
||||||
nsTArray<nsRefPtr<mozilla::dom::ContentParent>>* mChildrenPending;
|
|
||||||
uint32_t mNumProcessesRunning;
|
|
||||||
uint32_t mNumProcessesCompleted;
|
|
||||||
uint32_t mConcurrencyLimit;
|
|
||||||
nsCOMPtr<nsIHandleReportCallback> mHandleReport;
|
nsCOMPtr<nsIHandleReportCallback> mHandleReport;
|
||||||
nsCOMPtr<nsISupports> mHandleReportData;
|
nsCOMPtr<nsISupports> mHandleReportData;
|
||||||
nsCOMPtr<nsIFinishReportingCallback> mFinishReporting;
|
nsCOMPtr<nsIFinishReportingCallback> mFinishReporting;
|
||||||
@ -225,7 +217,7 @@ private:
|
|||||||
nsString mDMDDumpIdent;
|
nsString mDMDDumpIdent;
|
||||||
|
|
||||||
GetReportsState(uint32_t aGeneration, bool aAnonymize, bool aMinimize,
|
GetReportsState(uint32_t aGeneration, bool aAnonymize, bool aMinimize,
|
||||||
uint32_t aConcurrencyLimit,
|
uint32_t aNumChildProcesses,
|
||||||
nsIHandleReportCallback* aHandleReport,
|
nsIHandleReportCallback* aHandleReport,
|
||||||
nsISupports* aHandleReportData,
|
nsISupports* aHandleReportData,
|
||||||
nsIFinishReportingCallback* aFinishReporting,
|
nsIFinishReportingCallback* aFinishReporting,
|
||||||
@ -234,10 +226,8 @@ private:
|
|||||||
: mGeneration(aGeneration)
|
: mGeneration(aGeneration)
|
||||||
, mAnonymize(aAnonymize)
|
, mAnonymize(aAnonymize)
|
||||||
, mMinimize(aMinimize)
|
, mMinimize(aMinimize)
|
||||||
, mChildrenPending(nullptr)
|
, mNumChildProcesses(aNumChildProcesses)
|
||||||
, mNumProcessesRunning(1) // reporting starts with the parent
|
, mNumChildProcessesCompleted(0)
|
||||||
, mNumProcessesCompleted(0)
|
|
||||||
, mConcurrencyLimit(aConcurrencyLimit)
|
|
||||||
, mHandleReport(aHandleReport)
|
, mHandleReport(aHandleReport)
|
||||||
, mHandleReportData(aHandleReportData)
|
, mHandleReportData(aHandleReportData)
|
||||||
, mFinishReporting(aFinishReporting)
|
, mFinishReporting(aFinishReporting)
|
||||||
@ -245,8 +235,6 @@ private:
|
|||||||
, mDMDDumpIdent(aDMDDumpIdent)
|
, mDMDDumpIdent(aDMDDumpIdent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
~GetReportsState();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// When this is non-null, a request is in flight. Note: We use manual
|
// When this is non-null, a request is in flight. Note: We use manual
|
||||||
@ -255,8 +243,6 @@ private:
|
|||||||
GetReportsState* mGetReportsState;
|
GetReportsState* mGetReportsState;
|
||||||
|
|
||||||
GetReportsState* GetStateForGeneration(uint32_t aGeneration);
|
GetReportsState* GetStateForGeneration(uint32_t aGeneration);
|
||||||
static bool StartChildReport(mozilla::dom::ContentParent* aChild,
|
|
||||||
const GetReportsState* aState);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NS_MEMORY_REPORTER_MANAGER_CID \
|
#define NS_MEMORY_REPORTER_MANAGER_CID \
|
||||||
|
Loading…
Reference in New Issue
Block a user