зеркало из https://github.com/mozilla/gecko-dev.git
Bug 857382 (part 1) - Correctly handle memory report files that have no measurements in the "explicit" or "other" sections. r=kats.
--HG-- extra : rebase_source : 2fa86e1a5b0729f2deee3f1f15989685fb2e5d77
This commit is contained in:
Родитель
0f42b73899
Коммит
4317cc9ffe
|
@ -511,6 +511,8 @@ function onLoadAboutMemory()
|
|||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
function doGC()
|
||||
{
|
||||
Cu.forceGC();
|
||||
|
@ -542,8 +544,6 @@ function doMeasure()
|
|||
addChildObserversAndUpdate(updateAboutMemoryFromReporters);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Top-level function that does the work of generating the page from the memory
|
||||
* reporters.
|
||||
|
@ -690,6 +690,16 @@ function updateAboutMemoryFromClipboard()
|
|||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// |PColl| is short for "process collection".
|
||||
function PColl()
|
||||
{
|
||||
this._trees = {};
|
||||
this._degenerates = {};
|
||||
this._heapTotal = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes reports (whether from reporters or from a file) and append the
|
||||
* main part of the page.
|
||||
|
@ -706,12 +716,10 @@ function updateAboutMemoryFromClipboard()
|
|||
function appendAboutMemoryMain(aProcess, aHasMozMallocUsableSize,
|
||||
aForceShowSmaps)
|
||||
{
|
||||
let treesByProcess = {}, degeneratesByProcess = {}, heapTotalByProcess = {};
|
||||
getTreesByProcess(aProcess, treesByProcess, degeneratesByProcess,
|
||||
heapTotalByProcess, aForceShowSmaps);
|
||||
let pcollsByProcess = getPCollsByProcess(aProcess, aForceShowSmaps);
|
||||
|
||||
// Sort our list of processes.
|
||||
let processes = Object.keys(treesByProcess);
|
||||
// Sort the processes.
|
||||
let processes = Object.keys(pcollsByProcess);
|
||||
processes.sort(function(aProcessA, aProcessB) {
|
||||
assert(aProcessA != aProcessB,
|
||||
"Elements of Object.keys() should be unique, but " +
|
||||
|
@ -726,8 +734,8 @@ function appendAboutMemoryMain(aProcess, aHasMozMallocUsableSize,
|
|||
}
|
||||
|
||||
// Then sort by resident size.
|
||||
let nodeA = degeneratesByProcess[aProcessA]['resident'];
|
||||
let nodeB = degeneratesByProcess[aProcessB]['resident'];
|
||||
let nodeA = pcollsByProcess[aProcessA]._degenerates['resident'];
|
||||
let nodeB = pcollsByProcess[aProcessB]._degenerates['resident'];
|
||||
let residentA = nodeA ? nodeA._amount : -1;
|
||||
let residentB = nodeB ? nodeB._amount : -1;
|
||||
|
||||
|
@ -755,20 +763,13 @@ function appendAboutMemoryMain(aProcess, aHasMozMallocUsableSize,
|
|||
let section = appendElement(gMain, 'div', 'section');
|
||||
|
||||
appendProcessAboutMemoryElements(section, process,
|
||||
treesByProcess[process],
|
||||
degeneratesByProcess[process],
|
||||
heapTotalByProcess[process],
|
||||
pcollsByProcess[process]._trees,
|
||||
pcollsByProcess[process]._degenerates,
|
||||
pcollsByProcess[process]._heapTotal,
|
||||
aHasMozMallocUsableSize);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// This regexp matches sentences and sentence fragments, i.e. strings that
|
||||
// start with a capital letter and ends with a '.'. (The final sentence may be
|
||||
// in parentheses, so a ')' might appear after the '.'.)
|
||||
const gSentenceRegExp = /^[A-Z].*\.\)?$/m;
|
||||
|
||||
/**
|
||||
* This function reads all the memory reports, and puts that data in structures
|
||||
* that will be used to generate the page.
|
||||
|
@ -776,23 +777,20 @@ const gSentenceRegExp = /^[A-Z].*\.\)?$/m;
|
|||
* @param aProcessMemoryReports
|
||||
* Function that extracts the memory reports from the reporters or from
|
||||
* file.
|
||||
* @param aTreesByProcess
|
||||
* Table of non-degenerate trees, indexed by process, which this
|
||||
* function appends to.
|
||||
* @param aDegeneratesByProcess
|
||||
* Table of degenerate trees, indexed by process, which this function
|
||||
* appends to.
|
||||
* @param aHeapTotalByProcess
|
||||
* Table of heap total counts, indexed by process, which this function
|
||||
* appends to.
|
||||
* @param aForceShowSmaps
|
||||
* True if we should show the smaps memory reporters even if we're not
|
||||
* in verbose mode.
|
||||
* @return The table of PColls by process.
|
||||
*/
|
||||
function getTreesByProcess(aProcessMemoryReports, aTreesByProcess,
|
||||
aDegeneratesByProcess, aHeapTotalByProcess,
|
||||
aForceShowSmaps)
|
||||
function getPCollsByProcess(aProcessMemoryReports, aForceShowSmaps)
|
||||
{
|
||||
let pcollsByProcess = {};
|
||||
|
||||
// This regexp matches sentences and sentence fragments, i.e. strings that
|
||||
// start with a capital letter and ends with a '.'. (The final sentence may
|
||||
// be in parentheses, so a ')' might appear after the '.'.)
|
||||
const gSentenceRegExp = /^[A-Z].*\.\)?$/m;
|
||||
|
||||
// Ignore the "smaps" multi-reporter in non-verbose mode unless we're reading
|
||||
// from a file or the clipboard, and ignore the "compartments" and
|
||||
// "ghost-windows" multi-reporters all the time. (Note that reports from
|
||||
|
@ -849,20 +847,17 @@ function getTreesByProcess(aProcessMemoryReports, aTreesByProcess,
|
|||
let unsafeName0 = unsafeNames[0];
|
||||
let isDegenerate = unsafeNames.length === 1;
|
||||
|
||||
// Get the appropriate trees table (non-degenerate or degenerate) for the
|
||||
// process, creating it if necessary.
|
||||
let t;
|
||||
let thingsByProcess =
|
||||
isDegenerate ? aDegeneratesByProcess : aTreesByProcess;
|
||||
let things = thingsByProcess[process];
|
||||
if (!thingsByProcess[process]) {
|
||||
things = thingsByProcess[process] = {};
|
||||
// Get the PColl table for the process, creating it if necessary.
|
||||
let pcoll = pcollsByProcess[process];
|
||||
if (!pcollsByProcess[process]) {
|
||||
pcoll = pcollsByProcess[process] = new PColl();
|
||||
}
|
||||
|
||||
// Get the root node, creating it if necessary.
|
||||
t = things[unsafeName0];
|
||||
let psubcoll = isDegenerate ? pcoll._degenerates : pcoll._trees;
|
||||
let t = psubcoll[unsafeName0];
|
||||
if (!t) {
|
||||
t = things[unsafeName0] =
|
||||
t = psubcoll[unsafeName0] =
|
||||
new TreeNode(unsafeName0, aUnits, isDegenerate);
|
||||
}
|
||||
|
||||
|
@ -884,10 +879,7 @@ function getTreesByProcess(aProcessMemoryReports, aTreesByProcess,
|
|||
|
||||
// Update the heap total if necessary.
|
||||
if (unsafeName0 === "explicit" && aKind == KIND_HEAP) {
|
||||
if (!aHeapTotalByProcess[process]) {
|
||||
aHeapTotalByProcess[process] = 0;
|
||||
}
|
||||
aHeapTotalByProcess[process] += aAmount;
|
||||
pcollsByProcess[process]._heapTotal += aAmount;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -903,6 +895,8 @@ function getTreesByProcess(aProcessMemoryReports, aTreesByProcess,
|
|||
}
|
||||
|
||||
aProcessMemoryReports(ignoreSingle, ignoreMulti, handleReport);
|
||||
|
||||
return pcollsByProcess;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -1221,18 +1215,19 @@ function appendProcessAboutMemoryElements(aP, aProcess, aTrees, aDegenerates,
|
|||
let hasKnownHeapAllocated;
|
||||
{
|
||||
let treeName = "explicit";
|
||||
let t = aTrees[treeName];
|
||||
assertInput(t, "no explicit reports");
|
||||
fillInTree(t);
|
||||
hasKnownHeapAllocated =
|
||||
aDegenerates &&
|
||||
addHeapUnclassifiedNode(t, aDegenerates["heap-allocated"], aHeapTotal);
|
||||
sortTreeAndInsertAggregateNodes(t._amount, t);
|
||||
t._description = kTreeDescriptions[treeName];
|
||||
let pre = appendSectionHeader(aP, kSectionNames[treeName]);
|
||||
appendTreeElements(pre, t, aProcess, "");
|
||||
let t = aTrees[treeName];
|
||||
if (t) {
|
||||
fillInTree(t);
|
||||
hasKnownHeapAllocated =
|
||||
aDegenerates &&
|
||||
addHeapUnclassifiedNode(t, aDegenerates["heap-allocated"], aHeapTotal);
|
||||
sortTreeAndInsertAggregateNodes(t._amount, t);
|
||||
t._description = kTreeDescriptions[treeName];
|
||||
appendTreeElements(pre, t, aProcess, "");
|
||||
delete aTrees[treeName];
|
||||
}
|
||||
appendTextNode(aP, "\n"); // gives nice spacing when we cut and paste
|
||||
delete aTrees[treeName];
|
||||
}
|
||||
|
||||
// The smaps trees, which are only present in aTrees in verbose mode or when
|
||||
|
@ -1242,14 +1237,14 @@ function appendProcessAboutMemoryElements(aP, aProcess, aTrees, aDegenerates,
|
|||
// unsafePath.
|
||||
let t = aTrees[aTreeName];
|
||||
if (t) {
|
||||
let pre = appendSectionHeader(aP, kSectionNames[aTreeName]);
|
||||
fillInTree(t);
|
||||
sortTreeAndInsertAggregateNodes(t._amount, t);
|
||||
t._description = kTreeDescriptions[aTreeName];
|
||||
t._hideKids = true; // smaps trees are always initially collapsed
|
||||
let pre = appendSectionHeader(aP, kSectionNames[aTreeName]);
|
||||
appendTreeElements(pre, t, aProcess, "");
|
||||
appendTextNode(aP, "\n"); // gives nice spacing when we cut and paste
|
||||
delete aTrees[aTreeName];
|
||||
appendTextNode(aP, "\n"); // gives nice spacing when we cut and paste
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -5,6 +5,12 @@
|
|||
{"process": "Main Process (pid NNN)", "path": "heap-allocated", "kind": 2, "units": 0, "amount": 262144000, "description": "Heap allocated."},
|
||||
{"process": "Main Process (pid NNN)", "path": "other/b", "kind": 2, "units": 0, "amount": 104857, "description": "Other b."},
|
||||
{"process": "Main Process (pid NNN)", "path": "other/a", "kind": 2, "units": 0, "amount": 209715, "description": "Other a."},
|
||||
{"process": "Main Process (pid NNN)", "path": "explicit/a/b", "kind": 1, "units": 0, "amount": 52428800, "description": "A b."}
|
||||
{"process": "Main Process (pid NNN)", "path": "explicit/a/b", "kind": 1, "units": 0, "amount": 52428800, "description": "A b."},
|
||||
|
||||
{"process": "Explicit-only process", "path": "explicit/a/b", "kind": 1, "units": 0, "amount": 100000, "description": "A b."},
|
||||
|
||||
{"process": "Other-only process", "path": "a/b", "kind": 1, "units": 0, "amount": 100000, "description": "A b."},
|
||||
{"process": "Other-only process", "path": "a/c", "kind": 1, "units": 0, "amount": 100000, "description": "A c."},
|
||||
{"process": "Other-only process", "path": "heap-allocated", "kind": 1, "units": 0, "amount": 500000, "description": "D."}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -175,10 +175,50 @@
|
|||
}
|
||||
}
|
||||
|
||||
// This is pretty simple output, but that's ok; this file is about testing
|
||||
// the loading of data from file. If we got this far, we're doing fine.
|
||||
let expectedGood =
|
||||
"\
|
||||
Explicit-only process\n\
|
||||
\n\
|
||||
WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is not shown and the 'explicit' tree shows less memory than it should.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
0.10 MB (100.0%) -- explicit\n\
|
||||
└──0.10 MB (100.0%) ── a/b\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
Main Process (pid NNN)\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──200.00 MB (80.00%) ── heap-unclassified\n\
|
||||
└───50.00 MB (20.00%) ── a/b\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
0.30 MB (100.0%) -- other\n\
|
||||
├──0.20 MB (66.67%) ── a\n\
|
||||
└──0.10 MB (33.33%) ── b\n\
|
||||
\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
Other-only process\n\
|
||||
\n\
|
||||
WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is not shown and the 'explicit' tree shows less memory than it should.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
0.19 MB (100.0%) -- a\n\
|
||||
├──0.10 MB (50.00%) ── b\n\
|
||||
└──0.10 MB (50.00%) ── c\n\
|
||||
\n\
|
||||
0.48 MB ── heap-allocated\n\
|
||||
\n\
|
||||
";
|
||||
|
||||
let expectedGood2 =
|
||||
"\
|
||||
Main Process (pid NNN)\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
|
@ -206,7 +246,7 @@ Invalid memory report(s): missing 'hasMozMallocUsableSize' property";
|
|||
{ frameId: "amGoodFrame", filename: "memory-reports-good.json", expected: expectedGood, dumpFirst: false },
|
||||
|
||||
// This dumps to a file and then reads it back in. The output is the same as the first test.
|
||||
{ frameId: "amGoodFrame2", filename: "memory-reports-dumped.json.gz", expected: expectedGood, dumpFirst: true },
|
||||
{ frameId: "amGoodFrame2", filename: "memory-reports-dumped.json.gz", expected: expectedGood2, dumpFirst: true },
|
||||
|
||||
// This loads a pre-existing file that is invalid.
|
||||
{ frameId: "amBadFrame", filename: "memory-reports-bad.json", expected: expectedBad, dumpFirst: false }
|
||||
|
|
|
@ -89,6 +89,16 @@
|
|||
// the loading of data from file. If we got this far, we're doing fine.
|
||||
let expectedGood =
|
||||
"\
|
||||
Explicit-only process\n\
|
||||
\n\
|
||||
WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is not shown and the 'explicit' tree shows less memory than it should.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
0.10 MB (100.0%) -- explicit\n\
|
||||
└──0.10 MB (100.0%) ── a/b\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
Main Process (pid NNN)\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
|
@ -104,6 +114,19 @@ Other Measurements\n\
|
|||
\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
Other-only process\n\
|
||||
\n\
|
||||
WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is not shown and the 'explicit' tree shows less memory than it should.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
0.19 MB (100.0%) -- a\n\
|
||||
├──0.10 MB (50.00%) ── b\n\
|
||||
└──0.10 MB (50.00%) ── c\n\
|
||||
\n\
|
||||
0.48 MB ── heap-allocated\n\
|
||||
\n\
|
||||
";
|
||||
|
||||
// This is the output for a malformed data file.
|
||||
|
|
Загрузка…
Ссылка в новой задаче