Bug 903131 - Add save GC/CC logs buttons to about:memory. r=njn,mccr8.

- Added buttons, JS to trigger logs to be generated.
- Added out params to return log paths.
- Added attributes to cycle collector interface to export log paths.

--HG--
extra : rebase_source : cbce2c62b577c820fd099706d72ab7b20992a00a
This commit is contained in:
Eric Rahm 2014-01-31 14:43:08 -08:00
parent 225b0cbc1c
commit d7d546ac18
8 changed files with 183 additions and 8 deletions

View File

@ -554,8 +554,9 @@ ContentChild::RecvDumpGCAndCCLogsToFile(const nsString& aIdentifier,
{
nsCOMPtr<nsIMemoryInfoDumper> dumper = do_GetService("@mozilla.org/memory-info-dumper;1");
nsString gcLogPath, ccLogPath;
dumper->DumpGCAndCCLogsToFile(aIdentifier, aDumpAllTraces,
aDumpChildProcesses);
aDumpChildProcesses, gcLogPath, ccLogPath);
return true;
}

View File

@ -283,6 +283,13 @@ function onLoad()
"process to reduce memory usage in other ways, e.g. by " +
"flushing various caches.";
const GCAndCCLogDesc = "Save garbage collection log and concise cycle " +
"collection log.\n" +
"WARNING: These logs may be large (>1GB).";
const GCAndCCAllLogDesc = "Save garbage collection log and verbose cycle " +
"collection log.\n" +
"WARNING: These logs may be large (>1GB).";
let ops = appendElement(header, "div", "");
let row1 = appendElement(ops, "div", "opsRow");
@ -318,10 +325,19 @@ function onLoad()
appendButton(row3, CCDesc, doCC, "CC");
appendButton(row3, MMDesc, doMMU, "Minimize memory usage");
let row4 = appendElement(ops, "div", "opsRow");
appendElementWithText(row4, "div", "opsRowLabel", "Save GC & CC logs");
appendButton(row4, GCAndCCLogDesc,
saveGCLogAndConciseCCLog, "Save concise", 'saveLogsConcise');
appendButton(row4, GCAndCCAllLogDesc,
saveGCLogAndVerboseCCLog, "Save verbose", 'saveLogsVerbose');
// Generate the main div, where content ("section" divs) will go. It's
// hidden at first.
gMain = appendElement(document.body, 'div', '');
gMain.id = 'mainDiv';
// Generate the footer. It's hidden at first.
@ -385,6 +401,39 @@ function doMeasure()
updateAboutMemoryFromReporters();
}
function saveGCLogAndConciseCCLog()
{
dumpGCLogAndCCLog(false);
}
function saveGCLogAndVerboseCCLog()
{
dumpGCLogAndCCLog(true);
}
function dumpGCLogAndCCLog(aVerbose)
{
let gcLogPath = {};
let ccLogPath = {};
let dumper = Cc["@mozilla.org/memory-info-dumper;1"]
.getService(Ci.nsIMemoryInfoDumper);
updateMainAndFooter("Saving logs...", HIDE_FOOTER);
dumper.dumpGCAndCCLogsToFile("", aVerbose, /* dumpChildProcesses = */ false,
gcLogPath, ccLogPath);
updateMainAndFooter("", HIDE_FOOTER);
let section = appendElement(gMain, 'div', "section");
appendElementWithText(section, 'div', "",
"Saved GC log to " + gcLogPath.value);
let ccLogType = aVerbose ? "verbose" : "concise";
appendElementWithText(section, 'div', "",
"Saved " + ccLogType + " CC log to " + ccLogPath.value);
}
/**
* Top-level function that does the work of generating the page from the memory
* reporters.

View File

@ -11,6 +11,7 @@ support-files =
[test_aboutmemory3.xul]
[test_aboutmemory4.xul]
[test_aboutmemory5.xul]
[test_aboutmemory6.xul]
[test_memoryReporters.xul]
[test_memoryReporters2.xul]
[test_sqliteMultiReporter.xul]

View File

@ -0,0 +1,88 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<window title="about:memory"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<!-- This file tests the saving of GC and CC logs in both concise and
verbose formats. -->
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml"></body>
<iframe id="amFrame" height="400" src="about:memory"></iframe>
<script type="application/javascript">
<![CDATA[
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
function onFocus() {
let frame = document.getElementById("amFrame");
frame.focus();
// Checks that a file exists on the local file system and removes it if it
// is present.
function checkForFileAndRemove(aFilename) {
let localFile = Cc["@mozilla.org/file/local;1"]
.createInstance(Ci.nsILocalFile);
localFile.initWithPath(aFilename);
let exists = localFile.exists();
if (exists) {
localFile.remove(/* recursive = */ false);
}
return exists;
}
// Given a save log button, triggers the action and checks if both CC & GC
// logs were written to disk.
function saveLogs(aLogButton, aCCLogType)
{
// trigger the log saving
aLogButton.click();
// mainDiv
// |-> section
// | -> div gc log path
// | -> div cc log path
let mainDiv = frame.contentWindow.document.getElementById("mainDiv");
let logNodes = mainDiv.childNodes[0];
// we expect 2 logs listed
let numOfLogs = logNodes.childNodes.length;
ok(numOfLogs == 2, "two log entries generated")
// grab the path portion of the text
let gcLogPath = logNodes.childNodes[0].textContent
.replace("Saved GC log to ", "");
let ccLogPath = logNodes.childNodes[1].textContent
.replace("Saved " + aCCLogType + " CC log to ", "");
// check that the files actually exist
ok(checkForFileAndRemove(gcLogPath), "GC log file exists");
ok(checkForFileAndRemove(ccLogPath), "CC log file exists");
}
// get the log buttons to test
let saveConcise = frame.contentWindow.document
.getElementById("saveLogsConcise");
let saveVerbose = frame.contentWindow.document
.getElementById("saveLogsVerbose");
saveLogs(saveConcise, "concise");
saveLogs(saveVerbose, "verbose");
SimpleTest.finish();
}
SimpleTest.waitForFocus(onFocus);
SimpleTest.waitForExplicitFinish();
]]>
</script>
</window>

View File

@ -1407,6 +1407,18 @@ public:
return NS_OK;
}
NS_IMETHOD GetGcLogPath(nsAString &aPath)
{
aPath = mGCLogPath;
return NS_OK;
}
NS_IMETHOD GetCcLogPath(nsAString &aPath)
{
aPath = mCCLogPath;
return NS_OK;
}
NS_IMETHOD Begin()
{
mCurrentAddress.AssignLiteral("0x");
@ -1459,6 +1471,8 @@ public:
nsString msg = NS_LITERAL_STRING("Garbage Collector log dumped to ") +
gcLogPath;
cs->LogStringMessage(msg.get());
mGCLogPath = gcLogPath;
}
// Open a file for dumping the CC graph. We again prefix with
@ -1616,6 +1630,8 @@ public:
nsString msg = NS_LITERAL_STRING("Cycle Collector log dumped to ") +
ccLogPath;
cs->LogStringMessage(msg.get());
mCCLogPath = ccLogPath;
}
}
return NS_OK;
@ -1713,6 +1729,8 @@ private:
bool mDisableLog;
bool mWantAfterProcessing;
nsString mFilenameIdentifier;
nsString mGCLogPath;
nsString mCCLogPath;
nsCString mCurrentAddress;
mozilla::LinkedList<CCGraphDescriber> mDescribers;
};

View File

@ -50,6 +50,12 @@ interface nsICycleCollectorListener : nsISupports
// This string will appear somewhere in the log's filename.
attribute AString filenameIdentifier;
// This string will indicate the full path of the GC log if enabled.
readonly attribute AString gcLogPath;
// This string will indicate the full path of the CC log if enabled.
readonly attribute AString ccLogPath;
void begin();
void noteRefCountedObject (in unsigned long long aAddress,
in unsigned long aRefCount,

View File

@ -152,8 +152,14 @@ interface nsIMemoryInfoDumper : nsISupports
* @param aDumpChildProcesses indicates whether we should call
* DumpGCAndCCLogsToFile in our child processes. If so, the child processes
* will dump their children, and so on.
*
* @param aGCLogPath The full path of the file that the GC log was written to.
*
* @param aCCLogPath The full path of the file that the CC log was written to.
*/
void dumpGCAndCCLogsToFile(in AString aIdentifier,
in bool aDumpAllTraces,
in bool aDumpChildProcesses);
in bool aDumpChildProcesses,
out AString aGCLogPath,
out AString aCCLogPath);
};

View File

@ -97,8 +97,9 @@ public:
nsCOMPtr<nsIMemoryInfoDumper> dumper =
do_GetService("@mozilla.org/memory-info-dumper;1");
dumper->DumpGCAndCCLogsToFile(
mIdentifier, mDumpAllTraces, mDumpChildProcesses);
nsString ccLogPath, gcLogPath;
dumper->DumpGCAndCCLogsToFile(mIdentifier, mDumpAllTraces,
mDumpChildProcesses, gcLogPath, ccLogPath);
return NS_OK;
}
@ -573,10 +574,11 @@ EnsureNonEmptyIdentifier(nsAString& aIdentifier)
}
NS_IMETHODIMP
nsMemoryInfoDumper::DumpGCAndCCLogsToFile(
const nsAString& aIdentifier,
bool aDumpAllTraces,
bool aDumpChildProcesses)
nsMemoryInfoDumper::DumpGCAndCCLogsToFile(const nsAString& aIdentifier,
bool aDumpAllTraces,
bool aDumpChildProcesses,
nsAString& aGCLogPath,
nsAString& aCCLogPath)
{
nsString identifier(aIdentifier);
EnsureNonEmptyIdentifier(identifier);
@ -601,6 +603,10 @@ nsMemoryInfoDumper::DumpGCAndCCLogsToFile(
}
nsJSContext::CycleCollectNow(logger);
logger->GetGcLogPath(aGCLogPath);
logger->GetCcLogPath(aCCLogPath);
return NS_OK;
}