зеркало из https://github.com/mozilla/gecko-dev.git
Bug 946407 - Reimplement DumpMemoryInfoToTempDir in terms of GetReports. r=njn
This winds up exposing things in the nsIMemoryReporterManager interface that arguably don't belong at that level of abstraction -- "minimize memory usage first" and DMD -- in order to take advantage of the infrastructure that GetReports already has for managing the child processes.
This commit is contained in:
Родитель
341a6e1a03
Коммит
76ab6d796b
|
@ -172,14 +172,24 @@ static bool sNuwaForking = false;
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class MemoryReportRequestChild : public PMemoryReportRequestChild
|
||||
class MemoryReportRequestChild : public PMemoryReportRequestChild,
|
||||
public nsIRunnable
|
||||
{
|
||||
public:
|
||||
MemoryReportRequestChild();
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
MemoryReportRequestChild(uint32_t aGeneration, const nsAString& aDMDDumpIdent);
|
||||
virtual ~MemoryReportRequestChild();
|
||||
NS_IMETHOD Run();
|
||||
private:
|
||||
uint32_t mGeneration;
|
||||
nsString mDMDDumpIdent;
|
||||
};
|
||||
|
||||
MemoryReportRequestChild::MemoryReportRequestChild()
|
||||
NS_IMPL_ISUPPORTS1(MemoryReportRequestChild, nsIRunnable)
|
||||
|
||||
MemoryReportRequestChild::MemoryReportRequestChild(uint32_t aGeneration, const nsAString& aDMDDumpIdent)
|
||||
: mGeneration(aGeneration), mDMDDumpIdent(aDMDDumpIdent)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MemoryReportRequestChild);
|
||||
}
|
||||
|
@ -518,9 +528,13 @@ ContentChild::InitXPCOM()
|
|||
}
|
||||
|
||||
PMemoryReportRequestChild*
|
||||
ContentChild::AllocPMemoryReportRequestChild(const uint32_t& generation)
|
||||
ContentChild::AllocPMemoryReportRequestChild(const uint32_t& generation,
|
||||
const bool &minimizeMemoryUsage,
|
||||
const nsString& aDMDDumpIdent)
|
||||
{
|
||||
return new MemoryReportRequestChild();
|
||||
MemoryReportRequestChild *actor = new MemoryReportRequestChild(generation, aDMDDumpIdent);
|
||||
actor->AddRef();
|
||||
return actor;
|
||||
}
|
||||
|
||||
// This is just a wrapper for InfallibleTArray<MemoryReport> that implements
|
||||
|
@ -567,25 +581,44 @@ NS_IMPL_ISUPPORTS1(
|
|||
bool
|
||||
ContentChild::RecvPMemoryReportRequestConstructor(
|
||||
PMemoryReportRequestChild* child,
|
||||
const uint32_t& generation)
|
||||
const uint32_t& generation,
|
||||
const bool& minimizeMemoryUsage,
|
||||
const nsString& aDMDDumpIdent)
|
||||
{
|
||||
MemoryReportRequestChild *actor = static_cast<MemoryReportRequestChild*>(child);
|
||||
nsresult rv;
|
||||
|
||||
if (minimizeMemoryUsage) {
|
||||
nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
|
||||
rv = mgr->MinimizeMemoryUsage(actor);
|
||||
// mgr will eventually call actor->Run()
|
||||
} else {
|
||||
rv = actor->Run();
|
||||
}
|
||||
|
||||
return !NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP MemoryReportRequestChild::Run()
|
||||
{
|
||||
ContentChild *child = static_cast<ContentChild*>(Manager());
|
||||
nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
|
||||
|
||||
InfallibleTArray<MemoryReport> reports;
|
||||
|
||||
nsCString process;
|
||||
GetProcessName(process);
|
||||
AppendProcessId(process);
|
||||
child->GetProcessName(process);
|
||||
child->AppendProcessId(process);
|
||||
|
||||
// Run the reporters. The callback will turn each measurement into a
|
||||
// MemoryReport.
|
||||
nsRefPtr<MemoryReportsWrapper> wrappedReports =
|
||||
new MemoryReportsWrapper(&reports);
|
||||
nsRefPtr<MemoryReportCallback> cb = new MemoryReportCallback(process);
|
||||
mgr->GetReportsForThisProcess(cb, wrappedReports);
|
||||
mgr->GetReportsForThisProcessExtended(cb, wrappedReports, mDMDDumpIdent);
|
||||
|
||||
child->Send__delete__(child, generation, reports);
|
||||
return true;
|
||||
bool sent = Send__delete__(this, mGeneration, reports);
|
||||
return sent ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -602,19 +635,7 @@ ContentChild::RecvAudioChannelNotify()
|
|||
bool
|
||||
ContentChild::DeallocPMemoryReportRequestChild(PMemoryReportRequestChild* actor)
|
||||
{
|
||||
delete actor;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvDumpMemoryInfoToTempDir(const nsString& aIdentifier,
|
||||
const bool& aMinimizeMemoryUsage,
|
||||
const bool& aDumpChildProcesses)
|
||||
{
|
||||
nsCOMPtr<nsIMemoryInfoDumper> dumper = do_GetService("@mozilla.org/memory-info-dumper;1");
|
||||
|
||||
dumper->DumpMemoryInfoToTempDir(aIdentifier, aMinimizeMemoryUsage,
|
||||
aDumpChildProcesses);
|
||||
static_cast<MemoryReportRequestChild*>(actor)->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -115,22 +115,21 @@ public:
|
|||
virtual bool DeallocPIndexedDBChild(PIndexedDBChild* aActor) MOZ_OVERRIDE;
|
||||
|
||||
virtual PMemoryReportRequestChild*
|
||||
AllocPMemoryReportRequestChild(const uint32_t& generation) MOZ_OVERRIDE;
|
||||
|
||||
AllocPMemoryReportRequestChild(const uint32_t& generation,
|
||||
const bool &minimizeMemoryUsage,
|
||||
const nsString &aDMDDumpIdent) MOZ_OVERRIDE;
|
||||
virtual bool
|
||||
DeallocPMemoryReportRequestChild(PMemoryReportRequestChild* actor) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* child,
|
||||
const uint32_t& generation) MOZ_OVERRIDE;
|
||||
const uint32_t& generation,
|
||||
const bool &minimizeMemoryUsage,
|
||||
const nsString &aDMDDumpIdent) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvAudioChannelNotify() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvDumpMemoryInfoToTempDir(const nsString& aIdentifier,
|
||||
const bool& aMinimizeMemoryUsage,
|
||||
const bool& aDumpChildProcesses) MOZ_OVERRIDE;
|
||||
virtual bool
|
||||
RecvDumpGCAndCCLogsToFile(const nsString& aIdentifier,
|
||||
const bool& aDumpAllTraces,
|
||||
|
|
|
@ -2040,10 +2040,28 @@ ContentParent::Observe(nsISupports* aSubject,
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
else if (!strcmp(aTopic, "child-memory-reporter-request")) {
|
||||
bool isNuwa = false;
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (!IsNuwaProcess())
|
||||
isNuwa = IsNuwaProcess();
|
||||
#endif
|
||||
unused << SendPMemoryReportRequestConstructor((uint32_t)(uintptr_t)aData);
|
||||
if (!isNuwa) {
|
||||
unsigned generation;
|
||||
int minimize, identOffset = -1;
|
||||
nsDependentString msg(aData);
|
||||
NS_ConvertUTF16toUTF8 cmsg(msg);
|
||||
|
||||
if (sscanf(cmsg.get(),
|
||||
"generation=%x minimize=%d DMDident=%n",
|
||||
&generation, &minimize, &identOffset) < 2
|
||||
|| 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] == '=');
|
||||
unused << SendPMemoryReportRequestConstructor(
|
||||
generation, minimize, nsString(Substring(msg, identOffset)));
|
||||
}
|
||||
}
|
||||
else if (!strcmp(aTopic, "child-gc-request")){
|
||||
unused << SendGarbageCollect();
|
||||
|
@ -2504,7 +2522,9 @@ ContentParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor)
|
|||
}
|
||||
|
||||
PMemoryReportRequestParent*
|
||||
ContentParent::AllocPMemoryReportRequestParent(const uint32_t& generation)
|
||||
ContentParent::AllocPMemoryReportRequestParent(const uint32_t& generation,
|
||||
const bool &minimizeMemoryUsage,
|
||||
const nsString &aDMDDumpIdent)
|
||||
{
|
||||
MemoryReportRequestParent* parent = new MemoryReportRequestParent();
|
||||
return parent;
|
||||
|
|
|
@ -359,7 +359,9 @@ private:
|
|||
virtual bool DeallocPIndexedDBParent(PIndexedDBParent* aActor) MOZ_OVERRIDE;
|
||||
|
||||
virtual PMemoryReportRequestParent*
|
||||
AllocPMemoryReportRequestParent(const uint32_t& generation) MOZ_OVERRIDE;
|
||||
AllocPMemoryReportRequestParent(const uint32_t& generation,
|
||||
const bool &minimizeMemoryUsage,
|
||||
const nsString &aDMDDumpIdent) MOZ_OVERRIDE;
|
||||
virtual bool DeallocPMemoryReportRequestParent(PMemoryReportRequestParent* actor) MOZ_OVERRIDE;
|
||||
|
||||
virtual PTestShellParent* AllocPTestShellParent() MOZ_OVERRIDE;
|
||||
|
|
|
@ -259,7 +259,7 @@ child:
|
|||
*/
|
||||
async SetProcessPrivileges(ChildPrivileges privs);
|
||||
|
||||
PMemoryReportRequest(uint32_t generation);
|
||||
PMemoryReportRequest(uint32_t generation, bool minimizeMemoryUsage, nsString DMDDumpIdent);
|
||||
|
||||
/**
|
||||
* Notify the AudioChannelService in the child processes.
|
||||
|
@ -268,20 +268,11 @@ child:
|
|||
|
||||
async SpeakerManagerNotify();
|
||||
|
||||
/**
|
||||
* Do a memory info dump to a file in our temp directory.
|
||||
*
|
||||
* For documentation on the args, see
|
||||
* MemoryInfoDumper::dumpMemoryInfoToTempDir.
|
||||
*/
|
||||
async DumpMemoryInfoToTempDir(nsString identifier,
|
||||
bool minimizeMemoryUsage,
|
||||
bool dumpChildProcesses);
|
||||
/**
|
||||
* Dump this process's GC and CC logs.
|
||||
*
|
||||
* For documentation on the args, see
|
||||
* MemoryInfoDumper::dumpGCAndCCLogsToFile.
|
||||
* For documentation on the args, see dumpGCAndCCLogsToFile in
|
||||
* nsIMemoryInfoDumper.idl
|
||||
*/
|
||||
async DumpGCAndCCLogsToFile(nsString identifier,
|
||||
bool dumpAllTraces,
|
||||
|
|
|
@ -1412,8 +1412,7 @@ XPCJSRuntime::OutOfMemoryCallback(JSContext *cx)
|
|||
|
||||
// If this fails, it fails silently.
|
||||
dumper->DumpMemoryInfoToTempDir(NS_LITERAL_STRING("due-to-JS-OOM"),
|
||||
/* minimizeMemoryUsage = */ false,
|
||||
/* dumpChildProcesses = */ false);
|
||||
/* minimizeMemoryUsage = */ false);
|
||||
}
|
||||
|
||||
size_t
|
||||
|
|
|
@ -60,6 +60,6 @@ var MemoryObserver = {
|
|||
|
||||
dumpMemoryStats: function(aLabel) {
|
||||
let memDumper = Cc["@mozilla.org/memory-info-dumper;1"].getService(Ci.nsIMemoryInfoDumper);
|
||||
memDumper.dumpMemoryInfoToTempDir(aLabel, false, true);
|
||||
memDumper.dumpMemoryInfoToTempDir(aLabel, /* minimize = */ false);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ interface nsIFinishDumpingCallback : nsISupports
|
|||
void callback(in nsISupports data);
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(294df03b-e2ae-4fdd-b4fc-4c66a501e0ef)]
|
||||
[scriptable, builtinclass, uuid(815bf31b-f5bd-425d-85c3-4657a7a91dad)]
|
||||
interface nsIMemoryInfoDumper : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -94,19 +94,17 @@ interface nsIMemoryInfoDumper : nsISupports
|
|||
|
||||
/**
|
||||
* Similar to dumpMemoryReportsToNamedFile, this method dumps gzipped memory
|
||||
* reports for this process and possibly its child processes (and their
|
||||
* children, recursively) to a file in the tmp directory called
|
||||
* memory-reports-<identifier>-<pid>.json.gz (or something similar, such as
|
||||
* memory-reports-<identifier>-<pid>-1.json.gz; no existing file will be
|
||||
* overwritten).
|
||||
* reports for this process and its child processes to files in the tmp
|
||||
* directory called memory-reports-<identifier>-<pid>.json.gz (or something
|
||||
* similar, such as memory-reports-<identifier>-<pid>-1.json.gz; no existing
|
||||
* file will be overwritten).
|
||||
*
|
||||
* If DMD is enabled, this method also dumps gzipped DMD output to a file in
|
||||
* the tmp directory called dmd-<identifier>-<pid>.txt.gz (or something
|
||||
* similar; again, no existing file will be overwritten).
|
||||
*
|
||||
* @param aIdentifier this identifier will appear in the filename of our
|
||||
* about:memory dump and those of our children (if aDumpChildProcesses is
|
||||
* true).
|
||||
* about:memory dump and those of our children.
|
||||
*
|
||||
* If the identifier is empty, the implementation may set it arbitrarily
|
||||
* and use that new value for its own dump and the dumps of its child
|
||||
|
@ -116,15 +114,10 @@ interface nsIMemoryInfoDumper : nsISupports
|
|||
* @param aMinimizeMemoryUsage indicates whether we should run a series of
|
||||
* gc/cc's in an attempt to reduce our memory usage before collecting our
|
||||
* memory report.
|
||||
*
|
||||
* @param aDumpChildProcesses indicates whether we should call
|
||||
* dumpMemoryInfoToTempDir in our child processes. If
|
||||
* so, the child processes will also dump their children, and so on.
|
||||
*/
|
||||
void dumpMemoryInfoToTempDir(
|
||||
in AString aIdentifier,
|
||||
in bool aMinimizeMemoryUsage,
|
||||
in bool aDumpChildProcesses);
|
||||
in bool aMinimizeMemoryUsage);
|
||||
|
||||
/**
|
||||
* Dump GC and CC logs to files in the OS's temp directory (or in
|
||||
|
|
|
@ -178,7 +178,7 @@ interface nsIFinishReportingCallback : nsISupports
|
|||
void callback(in nsISupports data);
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(12e08b1b-6590-4f78-996b-d9062c17e856)]
|
||||
[scriptable, builtinclass, uuid(b6e5ec8a-71d9-48db-8ae9-68b4c5bbf2c3)]
|
||||
interface nsIMemoryReporterManager : nsISupports
|
||||
{
|
||||
/*
|
||||
|
@ -242,6 +242,21 @@ interface nsIMemoryReporterManager : nsISupports
|
|||
in nsIFinishReportingCallback finishReporting,
|
||||
in nsISupports finishReportingData);
|
||||
|
||||
/*
|
||||
* As above, but: If |minimizeMemoryUsage| is true, then each process will
|
||||
* minimize its memory usage (see the |minimizeMemoryUsage| method) before
|
||||
* gathering its report. If DMD is enabled and |DMDDumpIdent| is non-empty
|
||||
* then write a DMD report to a file in the usual temporary directory (see
|
||||
* |dumpMemoryInfoToTempDir| in |nsIMemoryInfoDumper|.)
|
||||
*/
|
||||
[noscript] void
|
||||
getReportsExtended(in nsIMemoryReporterCallback handleReport,
|
||||
in nsISupports handleReportData,
|
||||
in nsIFinishReportingCallback finishReporting,
|
||||
in nsISupports finishReportingData,
|
||||
in boolean minimizeMemoryUsage,
|
||||
in AString DMDDumpIdent);
|
||||
|
||||
/*
|
||||
* Get memory reports in the current process only. |handleReport| is called
|
||||
* for each report.
|
||||
|
@ -249,6 +264,16 @@ interface nsIMemoryReporterManager : nsISupports
|
|||
void getReportsForThisProcess(in nsIMemoryReporterCallback handleReport,
|
||||
in nsISupports handleReportData);
|
||||
|
||||
/*
|
||||
* As above, but if DMD is enabled and |DMDDumpIdent| is non-empty
|
||||
* then write a DMD report to a file in the usual temporary directory (see
|
||||
* |dumpMemoryInfoToTempDir| in |nsIMemoryInfoDumper|.)
|
||||
*/
|
||||
[noscript] void
|
||||
getReportsForThisProcessExtended(in nsIMemoryReporterCallback handleReport,
|
||||
in nsISupports handleReportData,
|
||||
in AString DMDDumpIdent);
|
||||
|
||||
/*
|
||||
* The memory reporter manager, for the most part, treats reporters
|
||||
* registered with it as a black box. However, there are some
|
||||
|
|
|
@ -60,25 +60,21 @@ class DumpMemoryInfoToTempDirRunnable : public nsRunnable
|
|||
{
|
||||
public:
|
||||
DumpMemoryInfoToTempDirRunnable(const nsAString& aIdentifier,
|
||||
bool aMinimizeMemoryUsage,
|
||||
bool aDumpChildProcesses)
|
||||
bool aMinimizeMemoryUsage)
|
||||
: mIdentifier(aIdentifier)
|
||||
, mMinimizeMemoryUsage(aMinimizeMemoryUsage)
|
||||
, mDumpChildProcesses(aDumpChildProcesses)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsCOMPtr<nsIMemoryInfoDumper> dumper = do_GetService("@mozilla.org/memory-info-dumper;1");
|
||||
dumper->DumpMemoryInfoToTempDir(mIdentifier, mMinimizeMemoryUsage,
|
||||
mDumpChildProcesses);
|
||||
dumper->DumpMemoryInfoToTempDir(mIdentifier, mMinimizeMemoryUsage);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
const nsString mIdentifier;
|
||||
const bool mMinimizeMemoryUsage;
|
||||
const bool mDumpChildProcesses;
|
||||
};
|
||||
|
||||
class GCAndCCLogDumpRunnable : public nsRunnable
|
||||
|
@ -357,8 +353,7 @@ public:
|
|||
bool doMMUFirst = signum == sDumpAboutMemoryAfterMMUSignum;
|
||||
nsRefPtr<DumpMemoryInfoToTempDirRunnable> runnable =
|
||||
new DumpMemoryInfoToTempDirRunnable(/* identifier = */ EmptyString(),
|
||||
doMMUFirst,
|
||||
/* dumpChildProcesses = */ true);
|
||||
doMMUFirst);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
else if (signum == sGCAndCCDumpSignum) {
|
||||
|
@ -520,8 +515,7 @@ public:
|
|||
LOG("FifoWatcher dispatching memory report runnable.");
|
||||
nsRefPtr<DumpMemoryInfoToTempDirRunnable> runnable =
|
||||
new DumpMemoryInfoToTempDirRunnable(/* identifier = */ EmptyString(),
|
||||
doMMUMemoryReport,
|
||||
/* dumpChildProcesses = */ true);
|
||||
doMMUMemoryReport);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
} else if (doAllTracesGCCCDump || doSmallGCCCDump) {
|
||||
LOG("FifoWatcher dispatching GC/CC log runnable.");
|
||||
|
@ -830,25 +824,38 @@ DumpFooter(nsIGZFileWriter* aWriter)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
DumpProcessMemoryReportsToGZFileWriter(nsGZFileWriter* aWriter)
|
||||
class TempDirMemoryFinishCallback MOZ_FINAL : public nsIFinishReportingCallback
|
||||
{
|
||||
nsresult rv = DumpHeader(aWriter);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// Process reporters.
|
||||
nsCOMPtr<nsIMemoryReporterManager> mgr =
|
||||
do_GetService("@mozilla.org/memory-reporter-manager;1");
|
||||
nsRefPtr<DumpReportCallback> dumpReport = new DumpReportCallback(aWriter);
|
||||
mgr->GetReportsForThisProcess(dumpReport, nullptr);
|
||||
TempDirMemoryFinishCallback(nsGZFileWriter *aWriter,
|
||||
nsIFile *aTmpFile,
|
||||
const nsCString &aFilename,
|
||||
const nsString &aIdentifier)
|
||||
: mrWriter(aWriter)
|
||||
, mrTmpFile(aTmpFile)
|
||||
, mrFilename(aFilename)
|
||||
, mIdentifier(aIdentifier)
|
||||
{}
|
||||
|
||||
return DumpFooter(aWriter);
|
||||
}
|
||||
NS_IMETHOD Callback(nsISupports *aData);
|
||||
|
||||
nsresult
|
||||
DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier)
|
||||
private:
|
||||
nsRefPtr<nsGZFileWriter> mrWriter;
|
||||
nsCOMPtr<nsIFile> mrTmpFile;
|
||||
nsCString mrFilename;
|
||||
nsString mIdentifier;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(TempDirMemoryFinishCallback, nsIFinishReportingCallback)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemoryInfoDumper::DumpMemoryInfoToTempDir(const nsAString& aIdentifier,
|
||||
bool aMinimizeMemoryUsage)
|
||||
{
|
||||
MOZ_ASSERT(!aIdentifier.IsEmpty());
|
||||
nsString identifier(aIdentifier);
|
||||
EnsureNonEmptyIdentifier(identifier);
|
||||
|
||||
#ifdef MOZ_DMD
|
||||
// Clear DMD's reportedness state before running the memory reporters, to
|
||||
|
@ -870,7 +877,12 @@ DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier)
|
|||
// Note that |mrFilename| is missing the "incomplete-" prefix; we'll tack
|
||||
// that on in a moment.
|
||||
nsCString mrFilename;
|
||||
MakeFilename("memory-report", aIdentifier, "json.gz", mrFilename);
|
||||
// The "unified" indicates that we merge the memory reports from all
|
||||
// processes and write out one file, rather than a separate file for
|
||||
// each process as was the case before bug 946407. This is so that
|
||||
// the get_about_memory.py script in the B2G repository can
|
||||
// determine when it's done waiting for files to appear.
|
||||
MakeFilename("unified-memory-report", identifier, "json.gz", mrFilename);
|
||||
|
||||
nsCOMPtr<nsIFile> mrTmpFile;
|
||||
nsresult rv;
|
||||
|
@ -886,9 +898,29 @@ DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier)
|
|||
return rv;
|
||||
|
||||
// Dump the memory reports to the file.
|
||||
DumpProcessMemoryReportsToGZFileWriter(mrWriter);
|
||||
rv = DumpHeader(mrWriter);
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
return rv;
|
||||
|
||||
// Process reporters.
|
||||
nsCOMPtr<nsIMemoryReporterManager> mgr =
|
||||
do_GetService("@mozilla.org/memory-reporter-manager;1");
|
||||
nsRefPtr<DumpReportCallback> dumpReport = new DumpReportCallback(mrWriter);
|
||||
nsRefPtr<nsIFinishReportingCallback> finishReport =
|
||||
new TempDirMemoryFinishCallback(mrWriter, mrTmpFile, mrFilename, identifier);
|
||||
rv = mgr->GetReportsExtended(dumpReport, nullptr,
|
||||
finishReport, nullptr,
|
||||
aMinimizeMemoryUsage,
|
||||
identifier);
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef MOZ_DMD
|
||||
nsresult
|
||||
nsMemoryInfoDumper::DumpDMD(const nsAString &aIdentifier)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Create a filename like dmd-<identifier>-<pid>.txt.gz, which will be used
|
||||
// if DMD is enabled.
|
||||
nsCString dmdFilename;
|
||||
|
@ -916,9 +948,19 @@ DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier)
|
|||
dmd::Dump(w);
|
||||
|
||||
rv = dmdWriter->Finish();
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
return rv;
|
||||
}
|
||||
#endif // MOZ_DMD
|
||||
|
||||
NS_IMETHODIMP
|
||||
TempDirMemoryFinishCallback::Callback(nsISupports *aData)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = DumpFooter(mrWriter);
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
return rv;
|
||||
#endif // MOZ_DMD
|
||||
|
||||
// The call to Finish() deallocates the memory allocated by mrWriter's first
|
||||
// DUMP() call (within DumpProcessMemoryReportsToGZFileWriter()). Because
|
||||
|
@ -978,44 +1020,6 @@ DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier)
|
|||
return cs->LogStringMessage(msg.get());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemoryInfoDumper::DumpMemoryInfoToTempDir(const nsAString& aIdentifier,
|
||||
bool aMinimizeMemoryUsage,
|
||||
bool aDumpChildProcesses)
|
||||
{
|
||||
nsString identifier(aIdentifier);
|
||||
EnsureNonEmptyIdentifier(identifier);
|
||||
|
||||
// Kick off memory report dumps in our child processes, if applicable. We
|
||||
// do this before doing our own report because writing a report may be I/O
|
||||
// bound, in which case we want to busy the CPU with other reports while we
|
||||
// work on our own.
|
||||
if (aDumpChildProcesses) {
|
||||
nsTArray<ContentParent*> children;
|
||||
ContentParent::GetAll(children);
|
||||
for (uint32_t i = 0; i < children.Length(); i++) {
|
||||
unused << children[i]->SendDumpMemoryInfoToTempDir(
|
||||
identifier, aMinimizeMemoryUsage, aDumpChildProcesses);
|
||||
}
|
||||
}
|
||||
|
||||
if (aMinimizeMemoryUsage) {
|
||||
// Minimize memory usage, then run DumpMemoryInfoToTempDir again.
|
||||
nsRefPtr<DumpMemoryInfoToTempDirRunnable> callback =
|
||||
new DumpMemoryInfoToTempDirRunnable(identifier,
|
||||
/* minimizeMemoryUsage = */ false,
|
||||
/* dumpChildProcesses = */ false);
|
||||
nsCOMPtr<nsIMemoryReporterManager> mgr =
|
||||
do_GetService("@mozilla.org/memory-reporter-manager;1");
|
||||
if (NS_WARN_IF(!mgr))
|
||||
return NS_ERROR_FAILURE;
|
||||
mgr->MinimizeMemoryUsage(callback);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return DumpProcessMemoryInfoToTempDir(identifier);
|
||||
}
|
||||
|
||||
// This dumps the JSON footer and closes the file, and then calls the given
|
||||
// nsIFinishDumpingCallback.
|
||||
class FinishReportingCallback MOZ_FINAL : public nsIFinishReportingCallback
|
||||
|
|
|
@ -38,6 +38,9 @@ public:
|
|||
* instead.
|
||||
*/
|
||||
static nsresult OpenTempFile(const nsACString &aFilename, nsIFile* *aFile);
|
||||
#ifdef MOZ_DMD
|
||||
static nsresult DumpDMD(const nsAString &aIdentifier);
|
||||
#endif
|
||||
};
|
||||
|
||||
#define NS_MEMORY_INFO_DUMPER_CID \
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsMemoryReporterManager.h"
|
||||
#include "nsITimer.h"
|
||||
|
@ -952,6 +953,23 @@ nsMemoryReporterManager::GetReports(
|
|||
nsIFinishReportingCallback* aFinishReporting,
|
||||
nsISupports* aFinishReportingData)
|
||||
{
|
||||
return GetReportsExtended(aHandleReport, aHandleReportData,
|
||||
aFinishReporting, aFinishReportingData,
|
||||
/* minimize = */ false,
|
||||
/* DMDident = */ nsString());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemoryReporterManager::GetReportsExtended(
|
||||
nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aHandleReportData,
|
||||
nsIFinishReportingCallback* aFinishReporting,
|
||||
nsISupports* aFinishReportingData,
|
||||
bool aMinimize,
|
||||
const nsAString& aDMDDumpIdent)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Memory reporters are not necessarily threadsafe, so this function must
|
||||
// be called from the main thread.
|
||||
if (!NS_IsMainThread()) {
|
||||
|
@ -979,16 +997,19 @@ nsMemoryReporterManager::GetReports(
|
|||
do_GetService("@mozilla.org/observer-service;1");
|
||||
NS_ENSURE_STATE(obs);
|
||||
|
||||
// Casting the uint32_t generation to |const char16_t*| is a hack, but
|
||||
// simpler than converting the number to an actual string.
|
||||
nsPrintfCString genStr("generation=%x minimize=%d DMDident=",
|
||||
generation, aMinimize ? 1 : 0);
|
||||
nsAutoString msg = NS_ConvertUTF8toUTF16(genStr);
|
||||
msg += aDMDDumpIdent;
|
||||
|
||||
obs->NotifyObservers(nullptr, "child-memory-reporter-request",
|
||||
(const char16_t*)(uintptr_t)generation);
|
||||
msg.get());
|
||||
|
||||
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE);
|
||||
nsresult rv = timer->InitWithFuncCallback(TimeoutCallback,
|
||||
this, kTimeoutLengthMS,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
rv = timer->InitWithFuncCallback(TimeoutCallback,
|
||||
this, kTimeoutLengthMS,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mGetReportsState = new GetReportsState(generation,
|
||||
|
@ -997,16 +1018,40 @@ nsMemoryReporterManager::GetReports(
|
|||
aHandleReport,
|
||||
aHandleReportData,
|
||||
aFinishReporting,
|
||||
aFinishReportingData);
|
||||
aFinishReportingData,
|
||||
aDMDDumpIdent);
|
||||
} else {
|
||||
mGetReportsState = new GetReportsState(generation,
|
||||
nullptr,
|
||||
/* mNumChildProcesses = */ 0,
|
||||
aHandleReport,
|
||||
aHandleReportData,
|
||||
aFinishReporting,
|
||||
aFinishReportingData,
|
||||
aDMDDumpIdent);
|
||||
}
|
||||
|
||||
if (aMinimize) {
|
||||
rv = MinimizeMemoryUsage(NS_NewRunnableMethod(this, &nsMemoryReporterManager::StartGettingReports));
|
||||
} else {
|
||||
rv = StartGettingReports();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMemoryReporterManager::StartGettingReports()
|
||||
{
|
||||
GetReportsState *s = mGetReportsState;
|
||||
|
||||
// Get reports for this process.
|
||||
GetReportsForThisProcess(aHandleReport, aHandleReportData);
|
||||
GetReportsForThisProcessExtended(s->mHandleReport, s->mHandleReportData,
|
||||
s->mDMDDumpIdent);
|
||||
|
||||
// If there are no child processes, we can finish up immediately.
|
||||
return (mNumChildProcesses == 0)
|
||||
? aFinishReporting->Callback(aFinishReportingData)
|
||||
: NS_OK;
|
||||
return (s->mNumChildProcesses == 0)
|
||||
? FinishReporting()
|
||||
: NS_OK;
|
||||
}
|
||||
|
||||
typedef nsCOMArray<nsIMemoryReporter> MemoryReporterArray;
|
||||
|
@ -1031,6 +1076,17 @@ NS_IMETHODIMP
|
|||
nsMemoryReporterManager::GetReportsForThisProcess(
|
||||
nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aHandleReportData)
|
||||
{
|
||||
return GetReportsForThisProcessExtended(aHandleReport,
|
||||
aHandleReportData,
|
||||
nsString());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemoryReporterManager::GetReportsForThisProcessExtended(
|
||||
nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aHandleReportData,
|
||||
const nsAString& aDMDDumpIdent)
|
||||
{
|
||||
// Memory reporters are not necessarily threadsafe, so this function must
|
||||
// be called from the main thread.
|
||||
|
@ -1038,6 +1094,14 @@ nsMemoryReporterManager::GetReportsForThisProcess(
|
|||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
#ifdef MOZ_DMD
|
||||
if (!aDMDDumpIdent.IsEmpty()) {
|
||||
// Clear DMD's reportedness state before running the memory
|
||||
// reporters, to avoid spurious twice-reported warnings.
|
||||
dmd::ClearReports();
|
||||
}
|
||||
#endif
|
||||
|
||||
MemoryReporterArray allReporters;
|
||||
{
|
||||
mozilla::MutexAutoLock autoLock(mMutex);
|
||||
|
@ -1048,6 +1112,12 @@ nsMemoryReporterManager::GetReportsForThisProcess(
|
|||
allReporters[i]->CollectReports(aHandleReport, aHandleReportData);
|
||||
}
|
||||
|
||||
#ifdef MOZ_DMD
|
||||
if (!aDMDDumpIdent.IsEmpty()) {
|
||||
return nsMemoryInfoDumper::DumpDMD(aDMDDumpIdent);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1136,7 +1206,7 @@ nsMemoryReporterManager::TimeoutCallback(nsITimer* aTimer, void* aData)
|
|||
mgr->FinishReporting();
|
||||
}
|
||||
|
||||
void
|
||||
nsresult
|
||||
nsMemoryReporterManager::FinishReporting()
|
||||
{
|
||||
// Memory reporting only happens on the main thread.
|
||||
|
@ -1151,11 +1221,12 @@ nsMemoryReporterManager::FinishReporting()
|
|||
// Call this before deleting |mGetReportsState|. That way, if
|
||||
// |mFinishReportData| calls GetReports(), it will silently abort, as
|
||||
// required.
|
||||
(void)mGetReportsState->mFinishReporting->Callback(
|
||||
nsresult rv = mGetReportsState->mFinishReporting->Callback(
|
||||
mGetReportsState->mFinishReportingData);
|
||||
|
||||
delete mGetReportsState;
|
||||
mGetReportsState = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -117,7 +117,7 @@ public:
|
|||
void HandleChildReports(
|
||||
const uint32_t& generation,
|
||||
const InfallibleTArray<mozilla::dom::MemoryReport>& aChildReports);
|
||||
void FinishReporting();
|
||||
nsresult FinishReporting();
|
||||
|
||||
// Functions that (a) implement distinguished amounts, and (b) are outside of
|
||||
// this module.
|
||||
|
@ -157,9 +157,12 @@ public:
|
|||
private:
|
||||
nsresult RegisterReporterHelper(nsIMemoryReporter* aReporter,
|
||||
bool aForce, bool aStrongRef);
|
||||
nsresult StartGettingReports();
|
||||
|
||||
static void TimeoutCallback(nsITimer* aTimer, void* aData);
|
||||
static const uint32_t kTimeoutLengthMS = 5000;
|
||||
// Note: this timeout needs to be long enough to allow for the
|
||||
// possibility of DMD reports and/or running on a low-end phone.
|
||||
static const uint32_t kTimeoutLengthMS = 50000;
|
||||
|
||||
mozilla::Mutex mMutex;
|
||||
bool mIsRegistrationBlocked;
|
||||
|
@ -184,13 +187,15 @@ private:
|
|||
nsCOMPtr<nsISupports> mHandleReportData;
|
||||
nsCOMPtr<nsIFinishReportingCallback> mFinishReporting;
|
||||
nsCOMPtr<nsISupports> mFinishReportingData;
|
||||
nsString mDMDDumpIdent;
|
||||
|
||||
GetReportsState(uint32_t aGeneration, nsITimer* aTimer,
|
||||
uint32_t aNumChildProcesses,
|
||||
nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aHandleReportData,
|
||||
nsIFinishReportingCallback* aFinishReporting,
|
||||
nsISupports* aFinishReportingData)
|
||||
nsISupports* aFinishReportingData,
|
||||
const nsAString &aDMDDumpIdent)
|
||||
: mGeneration(aGeneration)
|
||||
, mTimer(aTimer)
|
||||
, mNumChildProcesses(aNumChildProcesses)
|
||||
|
@ -199,6 +204,7 @@ private:
|
|||
, mHandleReportData(aHandleReportData)
|
||||
, mFinishReporting(aFinishReporting)
|
||||
, mFinishReportingData(aFinishReportingData)
|
||||
, mDMDDumpIdent(aDMDDumpIdent)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче