mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 700508 - Disallow non-leaf memory reporters (attempt 2). r=jlebar.
--HG-- extra : rebase_source : 040e3e7093f019caf7157a316e5fc75654eb5d65
This commit is contained in:
parent
9ffe60c17b
commit
09267e90dd
@ -368,9 +368,10 @@ function update()
|
|||||||
content.appendChild(div);
|
content.appendChild(div);
|
||||||
}
|
}
|
||||||
|
|
||||||
// There are two kinds of TreeNode. Those that correspond to Reporters
|
// There are two kinds of TreeNode.
|
||||||
// have more properties. The remainder are just scaffolding nodes for the
|
// - Leaf TreeNodes correspond to Reporters and have more properties.
|
||||||
// tree, whose values are derived from their children.
|
// - Non-leaf TreeNodes are just scaffolding nodes for the tree; their values
|
||||||
|
// are derived from their children.
|
||||||
function TreeNode(aName)
|
function TreeNode(aName)
|
||||||
{
|
{
|
||||||
// Nb: _units is not needed, it's always UNITS_BYTES.
|
// Nb: _units is not needed, it's always UNITS_BYTES.
|
||||||
@ -380,7 +381,7 @@ function TreeNode(aName)
|
|||||||
// - _amount (which is never |kUnknown|)
|
// - _amount (which is never |kUnknown|)
|
||||||
// - _description
|
// - _description
|
||||||
//
|
//
|
||||||
// TreeNodes corresponding to Reporters have these properties added later:
|
// Leaf TreeNodes have these properties added later:
|
||||||
// - _kind
|
// - _kind
|
||||||
// - _nMerged (if > 1)
|
// - _nMerged (if > 1)
|
||||||
// - _hasProblem (only defined if true)
|
// - _hasProblem (only defined if true)
|
||||||
@ -421,8 +422,9 @@ function buildTree(aReporters, aTreeName)
|
|||||||
// build the tree but only fill the properties that we can with a top-down
|
// build the tree but only fill the properties that we can with a top-down
|
||||||
// traversal.
|
// traversal.
|
||||||
|
|
||||||
// Is there any reporter which matches aTreeName? If not, we'll create a
|
// There should always be at least one matching reporter when |aTreeName| is
|
||||||
// dummy one.
|
// "explicit". But there may be zero for "map" trees; if that happens,
|
||||||
|
// bail.
|
||||||
var foundReporter = false;
|
var foundReporter = false;
|
||||||
for (var path in aReporters) {
|
for (var path in aReporters) {
|
||||||
if (aReporters[path].treeNameMatches(aTreeName)) {
|
if (aReporters[path].treeNameMatches(aTreeName)) {
|
||||||
@ -430,9 +432,8 @@ function buildTree(aReporters, aTreeName)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!foundReporter) {
|
if (!foundReporter) {
|
||||||
// We didn't find any reporters for this tree, so bail.
|
assert(aTreeName !== 'explicit');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,7 +477,7 @@ function buildTree(aReporters, aTreeName)
|
|||||||
var path = aPrepath ? aPrepath + '/' + aT._name : aT._name;
|
var path = aPrepath ? aPrepath + '/' + aT._name : aT._name;
|
||||||
if (aT._kids.length === 0) {
|
if (aT._kids.length === 0) {
|
||||||
// Leaf node. Must have a reporter.
|
// Leaf node. Must have a reporter.
|
||||||
assert(aT._kind !== undefined, "aT._kind !== undefined");
|
assert(aT._kind !== undefined, "aT._kind is undefined for leaf node");
|
||||||
aT._description = getDescription(aReporters, path);
|
aT._description = getDescription(aReporters, path);
|
||||||
var amount = getBytes(aReporters, path);
|
var amount = getBytes(aReporters, path);
|
||||||
if (amount !== kUnknown) {
|
if (amount !== kUnknown) {
|
||||||
@ -486,35 +487,15 @@ function buildTree(aReporters, aTreeName)
|
|||||||
aT._hasProblem = true;
|
aT._hasProblem = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Non-leaf node. Get the size of the children.
|
// Non-leaf node. Derive its size and description entirely from its
|
||||||
|
// children.
|
||||||
|
assert(aT._kind === undefined, "aT._kind is defined for non-leaf node");
|
||||||
var childrenBytes = 0;
|
var childrenBytes = 0;
|
||||||
for (var i = 0; i < aT._kids.length; i++) {
|
for (var i = 0; i < aT._kids.length; i++) {
|
||||||
// Allow for kUnknown, treat it like 0.
|
|
||||||
childrenBytes += fillInTree(aT._kids[i], path);
|
childrenBytes += fillInTree(aT._kids[i], path);
|
||||||
}
|
}
|
||||||
if (aT._kind !== undefined) {
|
aT._amount = childrenBytes;
|
||||||
aT._description = getDescription(aReporters, path);
|
aT._description = "The sum of all entries below '" + aT._name + "'.";
|
||||||
var amount = getBytes(aReporters, path);
|
|
||||||
if (amount !== kUnknown) {
|
|
||||||
// Non-leaf node with its own reporter. Use the reporter and add
|
|
||||||
// an "other" child node.
|
|
||||||
aT._amount = amount;
|
|
||||||
var other = new TreeNode("other");
|
|
||||||
other._description = "All unclassified " + aT._name + " memory.",
|
|
||||||
other._amount = aT._amount - childrenBytes,
|
|
||||||
aT._kids.push(other);
|
|
||||||
} else {
|
|
||||||
// Non-leaf node with a reporter that returns kUnknown.
|
|
||||||
// Use the sum of the children and mark it as problematic.
|
|
||||||
aT._amount = childrenBytes;
|
|
||||||
aT._hasProblem = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Non-leaf node without its own reporter. Derive its size and
|
|
||||||
// description entirely from its children.
|
|
||||||
aT._amount = childrenBytes;
|
|
||||||
aT._description = "The sum of all entries below '" + aT._name + "'.";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert(aT._amount !== kUnknown, "aT._amount !== kUnknown");
|
assert(aT._amount !== kUnknown, "aT._amount !== kUnknown");
|
||||||
return aT._amount;
|
return aT._amount;
|
||||||
@ -542,49 +523,46 @@ function buildTree(aReporters, aTreeName)
|
|||||||
* Do some work which only makes sense for the 'explicit' tree.
|
* Do some work which only makes sense for the 'explicit' tree.
|
||||||
*/
|
*/
|
||||||
function fixUpExplicitTree(aT, aReporters) {
|
function fixUpExplicitTree(aT, aReporters) {
|
||||||
// Determine how many bytes are reported by heap reporters. Be careful
|
// Determine how many bytes are reported by heap reporters.
|
||||||
// with non-leaf reporters; if we count a non-leaf reporter we don't want
|
|
||||||
// to count any of its child reporters.
|
|
||||||
var s = "";
|
var s = "";
|
||||||
function getKnownHeapUsedBytes(aT)
|
function getKnownHeapUsedBytes(aT)
|
||||||
{
|
{
|
||||||
if (aT._kind === KIND_HEAP) {
|
var n = 0;
|
||||||
return aT._amount;
|
if (aT._kids.length === 0) {
|
||||||
|
// Leaf node.
|
||||||
|
assert(aT._kind !== undefined, "aT._kind is undefined for leaf node");
|
||||||
|
n = aT._kind === KIND_HEAP ? aT._amount : 0;
|
||||||
} else {
|
} else {
|
||||||
var n = 0;
|
|
||||||
for (var i = 0; i < aT._kids.length; i++) {
|
for (var i = 0; i < aT._kids.length; i++) {
|
||||||
n += getKnownHeapUsedBytes(aT._kids[i]);
|
n += getKnownHeapUsedBytes(aT._kids[i]);
|
||||||
}
|
}
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A special case: compute the derived "heap-unclassified" value. Don't
|
// A special case: compute the derived "heap-unclassified" value. Don't
|
||||||
// mark "heap-allocated" when we get its size because we want it to appear
|
// mark "heap-allocated" when we get its size because we want it to appear
|
||||||
// in the "Other Measurements" list.
|
// in the "Other Measurements" list.
|
||||||
var heapUsedBytes = getBytes(aReporters, "heap-allocated", true);
|
var heapAllocatedBytes = getBytes(aReporters, "heap-allocated", true);
|
||||||
var unknownHeapUsedBytes = 0;
|
var heapUnclassifiedT = new TreeNode("heap-unclassified");
|
||||||
var hasProblem = true;
|
if (heapAllocatedBytes !== kUnknown) {
|
||||||
if (heapUsedBytes !== kUnknown) {
|
heapUnclassifiedT._amount =
|
||||||
unknownHeapUsedBytes = heapUsedBytes - getKnownHeapUsedBytes(aT);
|
heapAllocatedBytes - getKnownHeapUsedBytes(aT);
|
||||||
hasProblem = false;
|
} else {
|
||||||
|
heapUnclassifiedT._amount = 0;
|
||||||
|
heapUnclassifiedT._hasProblem = true;
|
||||||
}
|
}
|
||||||
var heapUnclassified = new TreeNode("heap-unclassified");
|
|
||||||
// This kindToString() ensures the "(Heap)" prefix is set without having to
|
// This kindToString() ensures the "(Heap)" prefix is set without having to
|
||||||
// set the _kind property, which would mean that there is a corresponding
|
// set the _kind property, which would mean that there is a corresponding
|
||||||
// Reporter for this TreeNode (which isn't true).
|
// Reporter for this TreeNode (which isn't true).
|
||||||
heapUnclassified._description =
|
heapUnclassifiedT._description =
|
||||||
kindToString(KIND_HEAP) +
|
kindToString(KIND_HEAP) +
|
||||||
"Memory not classified by a more specific reporter. This includes " +
|
"Memory not classified by a more specific reporter. This includes " +
|
||||||
"waste due to internal fragmentation in the heap allocator (caused " +
|
"slop bytes due to internal fragmentation in the heap allocator "
|
||||||
"when the allocator rounds up request sizes).";
|
"(caused when the allocator rounds up request sizes).";
|
||||||
heapUnclassified._amount = unknownHeapUsedBytes;
|
|
||||||
if (hasProblem) {
|
|
||||||
heapUnclassified._hasProblem = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
aT._kids.push(heapUnclassified);
|
aT._kids.push(heapUnclassifiedT);
|
||||||
aT._amount += unknownHeapUsedBytes;
|
aT._amount += heapUnclassifiedT._amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,11 +17,16 @@
|
|||||||
var mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
var mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
||||||
getService(Ci.nsIMemoryReporterManager);
|
getService(Ci.nsIMemoryReporterManager);
|
||||||
|
|
||||||
|
// Access mgr.explicit and mgr.resident just to make sure they don't crash.
|
||||||
|
// We can't check their actual values because they're non-deterministic.
|
||||||
|
var dummy = mgr.explicit;
|
||||||
|
dummy = mgr.resident;
|
||||||
|
|
||||||
// Remove all the real reporters and multi-reporters; save them to
|
// Remove all the real reporters and multi-reporters; save them to
|
||||||
// restore at the end.
|
// restore at the end.
|
||||||
var e = mgr.enumerateReporters();
|
var e = mgr.enumerateReporters();
|
||||||
var realReporters = [];
|
var realReporters = [];
|
||||||
var dummy = 0;
|
dummy = 0;
|
||||||
while (e.hasMoreElements()) {
|
while (e.hasMoreElements()) {
|
||||||
var r = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
|
var r = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
|
||||||
// Get the |amount| field, even though we don't use it, just to test
|
// Get the |amount| field, even though we don't use it, just to test
|
||||||
@ -80,18 +85,18 @@
|
|||||||
f("", "explicit/b/b", HEAP, 75 * MB),
|
f("", "explicit/b/b", HEAP, 75 * MB),
|
||||||
f("", "explicit/b/c/a", HEAP, 70 * MB),
|
f("", "explicit/b/c/a", HEAP, 70 * MB),
|
||||||
f("", "explicit/b/c/b", HEAP, 2 * MB), // omitted
|
f("", "explicit/b/c/b", HEAP, 2 * MB), // omitted
|
||||||
f("", "explicit/g", HEAP, 1 * MB), // internal, dup: merge
|
|
||||||
f("", "explicit/g/a", HEAP, 6 * MB),
|
f("", "explicit/g/a", HEAP, 6 * MB),
|
||||||
f("", "explicit/g/b", HEAP, 5 * MB),
|
f("", "explicit/g/b", HEAP, 5 * MB),
|
||||||
|
f("", "explicit/g/other", HEAP, 4 * MB),
|
||||||
f("", "other1", OTHER, 111 * MB),
|
f("", "other1", OTHER, 111 * MB),
|
||||||
f2("", "other4", OTHER, COUNT_CUMULATIVE, 888)
|
f2("", "other4", OTHER, COUNT_CUMULATIVE, 888)
|
||||||
];
|
];
|
||||||
var fakeMultiReporters = [
|
var fakeMultiReporters = [
|
||||||
{ collectReports: function(cbObj, closure) {
|
{ collectReports: function(cbObj, closure) {
|
||||||
function f(p, k, u, a) { cbObj.callback("", p, k, u, a, "(desc)", closure); }
|
function f(p, k, u, a) { cbObj.callback("", p, k, u, a, "(desc)", closure); }
|
||||||
f("explicit/c", NONHEAP, BYTES, 100 * MB),
|
f("explicit/c/d", NONHEAP, BYTES, 13 * MB),
|
||||||
f("explicit/c/d", NONHEAP, BYTES, 13 * MB), // subsumed by parent
|
f("explicit/c/d", NONHEAP, BYTES, 10 * MB), // dup
|
||||||
f("explicit/c/d", NONHEAP, BYTES, 10 * MB), // dup, subsumed by parent
|
f("explicit/c/other", NONHEAP, BYTES, 77 * MB),
|
||||||
f("explicit/cc", NONHEAP, BYTES, 13 * MB);
|
f("explicit/cc", NONHEAP, BYTES, 13 * MB);
|
||||||
f("explicit/cc", NONHEAP, BYTES, 10 * MB); // dup
|
f("explicit/cc", NONHEAP, BYTES, 10 * MB); // dup
|
||||||
f("explicit/d", NONHEAP, BYTES, 499 * KB); // omitted
|
f("explicit/d", NONHEAP, BYTES, 499 * KB); // omitted
|
||||||
@ -102,7 +107,6 @@
|
|||||||
},
|
},
|
||||||
{ collectReports: function(cbObj, closure) {
|
{ collectReports: function(cbObj, closure) {
|
||||||
function f(p, k, u, a) { cbObj.callback("", p, k, u, a, "(desc)", closure); }
|
function f(p, k, u, a) { cbObj.callback("", p, k, u, a, "(desc)", closure); }
|
||||||
f("explicit/g", HEAP, BYTES, 14 * MB); // internal
|
|
||||||
f("other3", OTHER, COUNT, 777);
|
f("other3", OTHER, COUNT, 777);
|
||||||
f("other2", OTHER, BYTES, 222 * MB);
|
f("other2", OTHER, BYTES, 222 * MB);
|
||||||
f("perc2", OTHER, PERCENTAGE, 10000);
|
f("perc2", OTHER, PERCENTAGE, 10000);
|
||||||
@ -137,10 +141,6 @@
|
|||||||
// and subsequent processes.
|
// and subsequent processes.
|
||||||
is(mgr.explicit, 500*MB + (100 + 13 + 10)*MB + 599*KB, "mgr.explicit");
|
is(mgr.explicit, 500*MB + (100 + 13 + 10)*MB + 599*KB, "mgr.explicit");
|
||||||
|
|
||||||
// Access mgr.resident just to make sure it doesn't crash. We can't check
|
|
||||||
// its actual value because it's non-deterministic.
|
|
||||||
dummy = mgr.resident;
|
|
||||||
|
|
||||||
var fakeReporters2 = [
|
var fakeReporters2 = [
|
||||||
f("2nd", "heap-allocated", OTHER, 1000 * MB),
|
f("2nd", "heap-allocated", OTHER, 1000 * MB),
|
||||||
f("2nd", "heap-unallocated",OTHER, 100 * MB),
|
f("2nd", "heap-unallocated",OTHER, 100 * MB),
|
||||||
@ -159,7 +159,6 @@
|
|||||||
// kUnknown should be handled gracefully for "heap-allocated", non-leaf
|
// kUnknown should be handled gracefully for "heap-allocated", non-leaf
|
||||||
// reporters, leaf-reporters, "other" reporters, and duplicated reporters.
|
// reporters, leaf-reporters, "other" reporters, and duplicated reporters.
|
||||||
f("3rd", "heap-allocated", OTHER, kUnknown),
|
f("3rd", "heap-allocated", OTHER, kUnknown),
|
||||||
f("3rd", "explicit/a", HEAP, kUnknown),
|
|
||||||
f("3rd", "explicit/a/b", HEAP, 333 * MB),
|
f("3rd", "explicit/a/b", HEAP, 333 * MB),
|
||||||
f("3rd", "explicit/a/c", HEAP, 444 * MB),
|
f("3rd", "explicit/a/c", HEAP, 444 * MB),
|
||||||
f("3rd", "explicit/a/c", HEAP, kUnknown), // dup: merge
|
f("3rd", "explicit/a/c", HEAP, kUnknown), // dup: merge
|
||||||
@ -201,7 +200,7 @@ Explicit Allocations\n\
|
|||||||
│ └──20.00 MB (03.21%) -- g\n\
|
│ └──20.00 MB (03.21%) -- g\n\
|
||||||
│ └──20.00 MB (03.21%) -- h\n\
|
│ └──20.00 MB (03.21%) -- h\n\
|
||||||
│ └──20.00 MB (03.21%) -- i\n\
|
│ └──20.00 MB (03.21%) -- i\n\
|
||||||
├───15.00 MB (02.41%) -- g [2]\n\
|
├───15.00 MB (02.41%) -- g\n\
|
||||||
│ ├───6.00 MB (00.96%) -- a\n\
|
│ ├───6.00 MB (00.96%) -- a\n\
|
||||||
│ ├───5.00 MB (00.80%) -- b\n\
|
│ ├───5.00 MB (00.80%) -- b\n\
|
||||||
│ └───4.00 MB (00.64%) -- other\n\
|
│ └───4.00 MB (00.64%) -- other\n\
|
||||||
@ -253,7 +252,7 @@ Other Measurements\n\
|
|||||||
\n\
|
\n\
|
||||||
Explicit Allocations\n\
|
Explicit Allocations\n\
|
||||||
777.00 MB (100.0%) -- explicit\n\
|
777.00 MB (100.0%) -- explicit\n\
|
||||||
├──777.00 MB (100.0%) -- a [*]\n\
|
├──777.00 MB (100.0%) -- a\n\
|
||||||
│ ├──444.00 MB (57.14%) -- c [2]\n\
|
│ ├──444.00 MB (57.14%) -- c [2]\n\
|
||||||
│ ├──333.00 MB (42.86%) -- b\n\
|
│ ├──333.00 MB (42.86%) -- b\n\
|
||||||
│ └────0.00 MB (00.00%) -- (1 omitted)\n\
|
│ └────0.00 MB (00.00%) -- (1 omitted)\n\
|
||||||
@ -286,7 +285,7 @@ Explicit Allocations\n\
|
|||||||
│ └──20,971,520 B (03.21%) -- g\n\
|
│ └──20,971,520 B (03.21%) -- g\n\
|
||||||
│ └──20,971,520 B (03.21%) -- h\n\
|
│ └──20,971,520 B (03.21%) -- h\n\
|
||||||
│ └──20,971,520 B (03.21%) -- i\n\
|
│ └──20,971,520 B (03.21%) -- i\n\
|
||||||
├───15,728,640 B (02.41%) -- g [2]\n\
|
├───15,728,640 B (02.41%) -- g\n\
|
||||||
│ ├───6,291,456 B (00.96%) -- a\n\
|
│ ├───6,291,456 B (00.96%) -- a\n\
|
||||||
│ ├───5,242,880 B (00.80%) -- b\n\
|
│ ├───5,242,880 B (00.80%) -- b\n\
|
||||||
│ └───4,194,304 B (00.64%) -- other\n\
|
│ └───4,194,304 B (00.64%) -- other\n\
|
||||||
@ -339,7 +338,7 @@ Other Measurements\n\
|
|||||||
\n\
|
\n\
|
||||||
Explicit Allocations\n\
|
Explicit Allocations\n\
|
||||||
814,743,552 B (100.0%) -- explicit\n\
|
814,743,552 B (100.0%) -- explicit\n\
|
||||||
├──814,743,552 B (100.0%) -- a [*]\n\
|
├──814,743,552 B (100.0%) -- a\n\
|
||||||
│ ├──465,567,744 B (57.14%) -- c [2]\n\
|
│ ├──465,567,744 B (57.14%) -- c [2]\n\
|
||||||
│ ├──349,175,808 B (42.86%) -- b\n\
|
│ ├──349,175,808 B (42.86%) -- b\n\
|
||||||
│ └────────────0 B (00.00%) -- d [*] [2]\n\
|
│ └────────────0 B (00.00%) -- d [*] [2]\n\
|
||||||
|
@ -79,21 +79,21 @@ interface nsIMemoryReporter : nsISupports
|
|||||||
* mmap/VirtualAlloc/vm_allocate) or a heap-level allocation (eg.
|
* mmap/VirtualAlloc/vm_allocate) or a heap-level allocation (eg.
|
||||||
* malloc/calloc/operator new).
|
* malloc/calloc/operator new).
|
||||||
*
|
*
|
||||||
* Each reporter can be viewed as representing a node in a tree rooted at
|
* Each reporter can be viewed as representing a leaf node in a tree
|
||||||
* "explicit". Not all nodes of the tree need have an associated reporter.
|
* rooted at "explicit". Internal nodes of the tree don't have
|
||||||
* So, for example, the reporters "explicit/a/b", "explicit/a/c",
|
* reporters. So, for example, the reporters "explicit/a/b",
|
||||||
* "explicit/d", "explicit/d/e", and "explicit/d/f" define this tree:
|
* "explicit/a/c", "explicit/d/e", and "explicit/d/f" define this tree:
|
||||||
*
|
*
|
||||||
* explicit
|
* explicit
|
||||||
* |--a
|
* |--a
|
||||||
* | |--b [*]
|
* | |--b [*]
|
||||||
* | \--c [*]
|
* | \--c [*]
|
||||||
* \--d [*]
|
* \--d
|
||||||
* |--e [*]
|
* |--e [*]
|
||||||
* \--f [*]
|
* \--f [*]
|
||||||
*
|
*
|
||||||
* Nodes marked with a [*] have a reporter. Notice that "explicit/a" is
|
* Nodes marked with a [*] have a reporter. Notice that the internal
|
||||||
* implicitly defined.
|
* nodes are implicitly defined by the paths.
|
||||||
*
|
*
|
||||||
* A node's children divide their parent's memory into disjoint pieces.
|
* A node's children divide their parent's memory into disjoint pieces.
|
||||||
* So in the example above, |a| may not count any allocations counted by
|
* So in the example above, |a| may not count any allocations counted by
|
||||||
@ -119,7 +119,7 @@ interface nsIMemoryReporter : nsISupports
|
|||||||
* calloc, realloc, memalign, operator new, or operator new[]. Reporters
|
* calloc, realloc, memalign, operator new, or operator new[]. Reporters
|
||||||
* in this category must have units UNITS_BYTES and must have a path
|
* in this category must have units UNITS_BYTES and must have a path
|
||||||
* starting with "explicit".
|
* starting with "explicit".
|
||||||
|
*
|
||||||
* - NONHEAP: memory which the program explicitly allocated, but does not
|
* - NONHEAP: memory which the program explicitly allocated, but does not
|
||||||
* live on the heap. Such memory is commonly allocated by calling one of
|
* live on the heap. Such memory is commonly allocated by calling one of
|
||||||
* the OS's memory-mapping functions (e.g. mmap, VirtualAlloc, or
|
* the OS's memory-mapping functions (e.g. mmap, VirtualAlloc, or
|
||||||
|
@ -681,17 +681,17 @@ struct MemoryReport {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// This is just a wrapper for InfallibleTArray<MemoryReport> that implements
|
// This is just a wrapper for PRInt64 that implements nsISupports, so it can be
|
||||||
// nsISupports, so it can be passed to nsIMemoryMultiReporter::CollectReports.
|
// passed to nsIMemoryMultiReporter::CollectReports.
|
||||||
class MemoryReportsWrapper : public nsISupports {
|
class PRInt64Wrapper : public nsISupports {
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
MemoryReportsWrapper(InfallibleTArray<MemoryReport> *r) : mReports(r) { }
|
PRInt64Wrapper() : mValue(0) { }
|
||||||
InfallibleTArray<MemoryReport> *mReports;
|
PRInt64 mValue;
|
||||||
};
|
};
|
||||||
NS_IMPL_ISUPPORTS0(MemoryReportsWrapper)
|
NS_IMPL_ISUPPORTS0(PRInt64Wrapper)
|
||||||
|
|
||||||
class MemoryReportCallback : public nsIMemoryMultiReporterCallback
|
class ExplicitNonHeapCountingCallback : public nsIMemoryMultiReporterCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
@ -699,50 +699,40 @@ public:
|
|||||||
NS_IMETHOD Callback(const nsACString &aProcess, const nsACString &aPath,
|
NS_IMETHOD Callback(const nsACString &aProcess, const nsACString &aPath,
|
||||||
PRInt32 aKind, PRInt32 aUnits, PRInt64 aAmount,
|
PRInt32 aKind, PRInt32 aUnits, PRInt64 aAmount,
|
||||||
const nsACString &aDescription,
|
const nsACString &aDescription,
|
||||||
nsISupports *aWrappedMRs)
|
nsISupports *aWrappedExplicitNonHeap)
|
||||||
{
|
{
|
||||||
if (aKind == nsIMemoryReporter::KIND_NONHEAP &&
|
if (aKind == nsIMemoryReporter::KIND_NONHEAP &&
|
||||||
PromiseFlatCString(aPath).Find("explicit") == 0 &&
|
PromiseFlatCString(aPath).Find("explicit") == 0 &&
|
||||||
aAmount != PRInt64(-1))
|
aAmount != PRInt64(-1))
|
||||||
{
|
{
|
||||||
MemoryReportsWrapper *wrappedMRs =
|
PRInt64Wrapper *wrappedPRInt64 =
|
||||||
static_cast<MemoryReportsWrapper *>(aWrappedMRs);
|
static_cast<PRInt64Wrapper *>(aWrappedExplicitNonHeap);
|
||||||
MemoryReport mr(aPath, aAmount);
|
wrappedPRInt64->mValue += aAmount;
|
||||||
wrappedMRs->mReports->AppendElement(mr);
|
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
NS_IMPL_ISUPPORTS1(
|
NS_IMPL_ISUPPORTS1(
|
||||||
MemoryReportCallback
|
ExplicitNonHeapCountingCallback
|
||||||
, nsIMemoryMultiReporterCallback
|
, nsIMemoryMultiReporterCallback
|
||||||
)
|
)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Is path1 a prefix, and thus a parent, of path2? Eg. "a/b" is a parent of
|
|
||||||
// "a/b/c", but "a/bb" is not.
|
|
||||||
static bool
|
|
||||||
isParent(const nsACString &path1, const nsACString &path2)
|
|
||||||
{
|
|
||||||
if (path1.Length() >= path2.Length())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const nsACString& subStr = Substring(path2, 0, path1.Length());
|
|
||||||
return subStr.Equals(path1) && path2[path1.Length()] == '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMemoryReporterManager::GetExplicit(PRInt64 *aExplicit)
|
nsMemoryReporterManager::GetExplicit(PRInt64 *aExplicit)
|
||||||
{
|
{
|
||||||
|
NS_ENSURE_ARG_POINTER(aExplicit);
|
||||||
|
*aExplicit = 0;
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
bool more;
|
||||||
|
|
||||||
// Get "heap-allocated" and all the KIND_NONHEAP measurements from normal
|
// Get "heap-allocated" and all the KIND_NONHEAP measurements from normal
|
||||||
// (i.e. non-multi) "explicit" reporters.
|
// (i.e. non-multi) "explicit" reporters.
|
||||||
PRInt64 heapAllocated = PRInt64(-1);
|
PRInt64 heapAllocated = PRInt64(-1);
|
||||||
InfallibleTArray<MemoryReport> explicitNonHeapNormalReports;
|
PRInt64 explicitNonHeapNormalSize = 0;
|
||||||
nsCOMPtr<nsISimpleEnumerator> e;
|
nsCOMPtr<nsISimpleEnumerator> e;
|
||||||
EnumerateReporters(getter_AddRefs(e));
|
EnumerateReporters(getter_AddRefs(e));
|
||||||
bool more;
|
|
||||||
while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
|
while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
|
||||||
nsCOMPtr<nsIMemoryReporter> r;
|
nsCOMPtr<nsIMemoryReporter> r;
|
||||||
e->GetNext(getter_AddRefs(r));
|
e->GetNext(getter_AddRefs(r));
|
||||||
@ -758,8 +748,8 @@ nsMemoryReporterManager::GetExplicit(PRInt64 *aExplicit)
|
|||||||
// We're only interested in NONHEAP explicit reporters and
|
// We're only interested in NONHEAP explicit reporters and
|
||||||
// the 'heap-allocated' reporter.
|
// the 'heap-allocated' reporter.
|
||||||
if (kind == nsIMemoryReporter::KIND_NONHEAP &&
|
if (kind == nsIMemoryReporter::KIND_NONHEAP &&
|
||||||
path.Find("explicit") == 0) {
|
path.Find("explicit") == 0)
|
||||||
|
{
|
||||||
PRInt64 amount;
|
PRInt64 amount;
|
||||||
rv = r->GetAmount(&amount);
|
rv = r->GetAmount(&amount);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
@ -767,45 +757,20 @@ nsMemoryReporterManager::GetExplicit(PRInt64 *aExplicit)
|
|||||||
// Just skip any NONHEAP reporters that fail, because
|
// Just skip any NONHEAP reporters that fail, because
|
||||||
// "heap-allocated" is the most important one.
|
// "heap-allocated" is the most important one.
|
||||||
if (amount != PRInt64(-1)) {
|
if (amount != PRInt64(-1)) {
|
||||||
MemoryReport mr(path, amount);
|
explicitNonHeapNormalSize += amount;
|
||||||
explicitNonHeapNormalReports.AppendElement(mr);
|
|
||||||
}
|
}
|
||||||
} else if (path.Equals("heap-allocated")) {
|
} else if (path.Equals("heap-allocated")) {
|
||||||
rv = r->GetAmount(&heapAllocated);
|
rv = r->GetAmount(&heapAllocated);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we don't have "heap-allocated", give up, because the result would be
|
// If we don't have "heap-allocated", give up, because the result would be
|
||||||
// horribly inaccurate.
|
// horribly inaccurate.
|
||||||
if (heapAllocated == PRInt64(-1)) {
|
if (heapAllocated == PRInt64(-1)) {
|
||||||
*aExplicit = PRInt64(-1);
|
*aExplicit = PRInt64(-1);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
|
||||||
|
|
||||||
// Sum all the explicit, NONHEAP reports from normal reporters.
|
|
||||||
// Ignore (by zeroing its amount) any normal reporter that is a child of
|
|
||||||
// another normal reporter. Eg. if we have "explicit/a" and
|
|
||||||
// "explicit/a/b", zero the latter. This is quadratic in the number of
|
|
||||||
// explicit NONHEAP reporters, but there shouldn't be many.
|
|
||||||
//
|
|
||||||
// XXX: bug 700508 will remove the need for this
|
|
||||||
//
|
|
||||||
for (PRUint32 i = 0; i < explicitNonHeapNormalReports.Length(); i++) {
|
|
||||||
const nsCString &iPath = explicitNonHeapNormalReports[i].path;
|
|
||||||
for (PRUint32 j = i + 1; j < explicitNonHeapNormalReports.Length(); j++) {
|
|
||||||
const nsCString &jPath = explicitNonHeapNormalReports[j].path;
|
|
||||||
if (isParent(iPath, jPath)) {
|
|
||||||
explicitNonHeapNormalReports[j].amount = 0;
|
|
||||||
} else if (isParent(jPath, iPath)) {
|
|
||||||
explicitNonHeapNormalReports[i].amount = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PRInt64 explicitNonHeapNormalSize = 0;
|
|
||||||
for (PRUint32 i = 0; i < explicitNonHeapNormalReports.Length(); i++) {
|
|
||||||
explicitNonHeapNormalSize += explicitNonHeapNormalReports[i].amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For each multi-reporter we could call CollectReports and filter out the
|
// For each multi-reporter we could call CollectReports and filter out the
|
||||||
// non-explicit, non-NONHEAP measurements. But that's lots of wasted work,
|
// non-explicit, non-NONHEAP measurements. But that's lots of wasted work,
|
||||||
@ -817,9 +782,9 @@ nsMemoryReporterManager::GetExplicit(PRInt64 *aExplicit)
|
|||||||
// guarantees the two measurement paths are equivalent. This is wise
|
// guarantees the two measurement paths are equivalent. This is wise
|
||||||
// because it's easy for memory reporters to have bugs.)
|
// because it's easy for memory reporters to have bugs.)
|
||||||
|
|
||||||
|
PRInt64 explicitNonHeapMultiSize = 0;
|
||||||
nsCOMPtr<nsISimpleEnumerator> e2;
|
nsCOMPtr<nsISimpleEnumerator> e2;
|
||||||
EnumerateMultiReporters(getter_AddRefs(e2));
|
EnumerateMultiReporters(getter_AddRefs(e2));
|
||||||
PRInt64 explicitNonHeapMultiSize = 0;
|
|
||||||
while (NS_SUCCEEDED(e2->HasMoreElements(&more)) && more) {
|
while (NS_SUCCEEDED(e2->HasMoreElements(&more)) && more) {
|
||||||
nsCOMPtr<nsIMemoryMultiReporter> r;
|
nsCOMPtr<nsIMemoryMultiReporter> r;
|
||||||
e2->GetNext(getter_AddRefs(r));
|
e2->GetNext(getter_AddRefs(r));
|
||||||
@ -830,36 +795,18 @@ nsMemoryReporterManager::GetExplicit(PRInt64 *aExplicit)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
InfallibleTArray<MemoryReport> explicitNonHeapMultiReports;
|
nsRefPtr<ExplicitNonHeapCountingCallback> cb =
|
||||||
nsRefPtr<MemoryReportCallback> cb = new MemoryReportCallback();
|
new ExplicitNonHeapCountingCallback();
|
||||||
nsRefPtr<MemoryReportsWrapper> wrappedMRs =
|
nsRefPtr<PRInt64Wrapper> wrappedExplicitNonHeapMultiSize2 =
|
||||||
new MemoryReportsWrapper(&explicitNonHeapMultiReports);
|
new PRInt64Wrapper();
|
||||||
nsCOMPtr<nsISimpleEnumerator> e3;
|
nsCOMPtr<nsISimpleEnumerator> e3;
|
||||||
EnumerateMultiReporters(getter_AddRefs(e3));
|
EnumerateMultiReporters(getter_AddRefs(e3));
|
||||||
while (NS_SUCCEEDED(e3->HasMoreElements(&more)) && more) {
|
while (NS_SUCCEEDED(e3->HasMoreElements(&more)) && more) {
|
||||||
nsCOMPtr<nsIMemoryMultiReporter> r;
|
nsCOMPtr<nsIMemoryMultiReporter> r;
|
||||||
e3->GetNext(getter_AddRefs(r));
|
e3->GetNext(getter_AddRefs(r));
|
||||||
r->CollectReports(cb, wrappedMRs);
|
r->CollectReports(cb, wrappedExplicitNonHeapMultiSize2);
|
||||||
}
|
|
||||||
|
|
||||||
// Sum all the explicit, NONHEAP reports from multi-reporters.
|
|
||||||
// XXX: identical to the explicitNonHeapNormalReports case above; bug
|
|
||||||
// 700508 will remove the need for this
|
|
||||||
for (PRUint32 i = 0; i < explicitNonHeapMultiReports.Length(); i++) {
|
|
||||||
const nsCString &iPath = explicitNonHeapMultiReports[i].path;
|
|
||||||
for (PRUint32 j = i + 1; j < explicitNonHeapMultiReports.Length(); j++) {
|
|
||||||
const nsCString &jPath = explicitNonHeapMultiReports[j].path;
|
|
||||||
if (isParent(iPath, jPath)) {
|
|
||||||
explicitNonHeapMultiReports[j].amount = 0;
|
|
||||||
} else if (isParent(jPath, iPath)) {
|
|
||||||
explicitNonHeapMultiReports[i].amount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PRInt64 explicitNonHeapMultiSize2 = 0;
|
|
||||||
for (PRUint32 i = 0; i < explicitNonHeapMultiReports.Length(); i++) {
|
|
||||||
explicitNonHeapMultiSize2 += explicitNonHeapMultiReports[i].amount;
|
|
||||||
}
|
}
|
||||||
|
PRInt64 explicitNonHeapMultiSize2 = wrappedExplicitNonHeapMultiSize2->mValue;
|
||||||
|
|
||||||
// Check the two measurements give the same result.
|
// Check the two measurements give the same result.
|
||||||
NS_ASSERTION(explicitNonHeapMultiSize == explicitNonHeapMultiSize2,
|
NS_ASSERTION(explicitNonHeapMultiSize == explicitNonHeapMultiSize2,
|
||||||
@ -867,7 +814,6 @@ nsMemoryReporterManager::GetExplicit(PRInt64 *aExplicit)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
*aExplicit = heapAllocated + explicitNonHeapNormalSize + explicitNonHeapMultiSize;
|
*aExplicit = heapAllocated + explicitNonHeapNormalSize + explicitNonHeapMultiSize;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user