mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 744311 (part 2) - Don't use -1 to represent "unknown" in memory reporters. r=jlebar.
--HG-- extra : rebase_source : 8f726aef17e5b814f5b740b453c9a67a1ef7646d
This commit is contained in:
parent
08dc2dae6b
commit
3a4aa126ba
@ -211,40 +211,22 @@ function processMemoryReporters(aMgr, aIgnoreSingle, aIgnoreMulti,
|
||||
aHandleReport(aProcess, aUnsafePath, aKind, aUnits, aAmount, aDescription);
|
||||
}
|
||||
|
||||
function handleException(aReporterStr, aUnsafePathOrName, aE)
|
||||
{
|
||||
// There are two exception cases that must be distinguished here.
|
||||
//
|
||||
// - We want to halt proceedings on exceptions thrown within this file
|
||||
// (i.e. assertion failures in handleReport); such exceptions contain
|
||||
// gAssertionFailureMsgPrefix in their string representation.
|
||||
//
|
||||
// - We want to continue on when faced with exceptions thrown outside this
|
||||
// file (e.g. within a multi-reporter).
|
||||
|
||||
let str = aE.toString();
|
||||
if (str.search(gAssertionFailureMsgPrefix) >= 0) {
|
||||
throw(aE);
|
||||
} else {
|
||||
debug("Bad memory " + aReporterStr + " '" + aUnsafePathOrName +
|
||||
"': " + aE);
|
||||
}
|
||||
}
|
||||
|
||||
let e = aMgr.enumerateReporters();
|
||||
while (e.hasMoreElements()) {
|
||||
let rOrig = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
|
||||
let unsafePath = rOrig.path;
|
||||
let unsafePath;
|
||||
try {
|
||||
unsafePath = rOrig.path;
|
||||
if (!aIgnoreSingle(unsafePath)) {
|
||||
handleReport(rOrig.process, unsafePath, rOrig.kind, rOrig.units,
|
||||
handleReport(rOrig.process, unsafePath, rOrig.kind, rOrig.units,
|
||||
rOrig.amount, rOrig.description);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
handleException("reporter", unsafePath, e);
|
||||
catch (ex) {
|
||||
debug("Exception thrown by memory reporter: " + unsafePath + ": " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
let e = aMgr.enumerateMultiReporters();
|
||||
while (e.hasMoreElements()) {
|
||||
let mrOrig = e.getNext().QueryInterface(Ci.nsIMemoryMultiReporter);
|
||||
@ -254,8 +236,22 @@ function processMemoryReporters(aMgr, aIgnoreSingle, aIgnoreMulti,
|
||||
mrOrig.collectReports(handleReport, null);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
handleException("multi-reporter", name, e);
|
||||
catch (ex) {
|
||||
// There are two exception cases that must be distinguished here.
|
||||
//
|
||||
// - We want to halt proceedings on exceptions thrown within this file
|
||||
// (i.e. assertion failures in handleReport); such exceptions contain
|
||||
// gAssertionFailureMsgPrefix in their string representation.
|
||||
//
|
||||
// - We want to continue on when faced with exceptions thrown outside
|
||||
// this file (i.e. when measuring an amount in collectReports).
|
||||
let str = ex.toString();
|
||||
if (str.search(gAssertionFailureMsgPrefix) >= 0) {
|
||||
throw(ex);
|
||||
} else {
|
||||
debug("Exception thrown within memory multi-reporter: " + name + ": " +
|
||||
ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -330,8 +326,6 @@ function appendElementWithText(aP, aTagName, aClassName, aText)
|
||||
// Code specific to about:memory
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
const kUnknown = -1; // used for an unknown _amount
|
||||
|
||||
const kTreeDescriptions = {
|
||||
'explicit' :
|
||||
"This tree covers explicit memory allocations by the application, both at the \
|
||||
@ -515,16 +509,11 @@ function Report(aUnsafePath, aKind, aUnits, aAmount, aDescription)
|
||||
}
|
||||
|
||||
Report.prototype = {
|
||||
// Sum the values (accounting for possible kUnknown amounts), and mark |this|
|
||||
// as a dup. We mark dups because it's useful to know when a report is
|
||||
// duplicated; it might be worth investigating and splitting up to have
|
||||
// non-duplicated names.
|
||||
// Sum the values and mark |this| as a dup. We mark dups because it's useful
|
||||
// to know when a report is duplicated; it might be worth investigating and
|
||||
// splitting up to have non-duplicated names.
|
||||
merge: function(r) {
|
||||
if (this._amount !== kUnknown && r._amount !== kUnknown) {
|
||||
this._amount += r._amount;
|
||||
} else if (this._amount === kUnknown && r._amount !== kUnknown) {
|
||||
this._amount = r._amount;
|
||||
}
|
||||
this._amount += r._amount;
|
||||
this._nMerged = this._nMerged ? this._nMerged + 1 : 2;
|
||||
},
|
||||
|
||||
@ -595,14 +584,13 @@ function TreeNode(aUnsafeName)
|
||||
this._unsafeName = aUnsafeName;
|
||||
this._kids = [];
|
||||
// Leaf TreeNodes have these properties added immediately after construction:
|
||||
// - _amount (which is never |kUnknown|)
|
||||
// - _amount
|
||||
// - _description
|
||||
// - _kind
|
||||
// - _nMerged (only defined if > 1)
|
||||
// - _isUnknown (only defined if true)
|
||||
//
|
||||
// Non-leaf TreeNodes have these properties added later:
|
||||
// - _amount (which is never |kUnknown|)
|
||||
// - _amount
|
||||
// - _description
|
||||
// - _hideKids (only defined if true)
|
||||
}
|
||||
@ -676,12 +664,7 @@ function buildTree(aReports, aTreeName)
|
||||
}
|
||||
}
|
||||
// Fill in extra details in the leaf node from the Report object.
|
||||
if (r._amount !== kUnknown) {
|
||||
u._amount = r._amount;
|
||||
} else {
|
||||
u._amount = 0;
|
||||
u._isUnknown = true;
|
||||
}
|
||||
u._amount = r._amount;
|
||||
u._description = r._description;
|
||||
u._kind = r._kind;
|
||||
if (r._nMerged) {
|
||||
@ -696,7 +679,6 @@ function buildTree(aReports, aTreeName)
|
||||
t = t._kids[0];
|
||||
|
||||
// Next, fill in the remaining properties bottom-up.
|
||||
// Note that this function never returns kUnknown.
|
||||
function fillInNonLeafNodes(aT)
|
||||
{
|
||||
if (aT._kids.length === 0) {
|
||||
@ -714,7 +696,6 @@ function buildTree(aReports, aTreeName)
|
||||
aT._description = "The sum of all entries below '" +
|
||||
flipBackslashes(aT._unsafeName) + "'.";
|
||||
}
|
||||
assert(aT._amount !== kUnknown, "aT._amount !== kUnknown");
|
||||
return aT._amount;
|
||||
}
|
||||
|
||||
@ -784,17 +765,12 @@ function fixUpExplicitTree(aT, aReports)
|
||||
// mark "heap-allocated" when we get its size because we want it to appear
|
||||
// in the "Other Measurements" list.
|
||||
let heapAllocatedReport = aReports["heap-allocated"];
|
||||
assert(heapAllocatedReport, "no 'heap-allocated' report");
|
||||
if (heapAllocatedReport === undefined)
|
||||
return false;
|
||||
|
||||
let heapAllocatedBytes = heapAllocatedReport._amount;
|
||||
let heapUnclassifiedT = new TreeNode("heap-unclassified");
|
||||
let hasKnownHeapAllocated = heapAllocatedBytes !== kUnknown;
|
||||
if (hasKnownHeapAllocated) {
|
||||
heapUnclassifiedT._amount =
|
||||
heapAllocatedBytes - getKnownHeapUsedBytes(aT);
|
||||
} else {
|
||||
heapUnclassifiedT._amount = 0;
|
||||
heapUnclassifiedT._isUnknown = true;
|
||||
}
|
||||
heapUnclassifiedT._amount = heapAllocatedBytes - getKnownHeapUsedBytes(aT);
|
||||
// This kindToString() ensures the "(Heap)" prefix is set without having to
|
||||
// set the _kind property, which would mean that there is a corresponding
|
||||
// Report object for this TreeNode object (which isn't true)
|
||||
@ -802,11 +778,9 @@ function fixUpExplicitTree(aT, aReports)
|
||||
"Memory not classified by a more specific reporter. This includes " +
|
||||
"slop bytes due to internal fragmentation in the heap allocator " +
|
||||
"(caused when the allocator rounds up request sizes).";
|
||||
|
||||
aT._kids.push(heapUnclassifiedT);
|
||||
aT._amount += heapUnclassifiedT._amount;
|
||||
|
||||
return hasKnownHeapAllocated;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -825,7 +799,6 @@ function sortTreeAndInsertAggregateNodes(aTotalBytes, aT)
|
||||
function isInsignificant(aT)
|
||||
{
|
||||
return !gVerbose &&
|
||||
aTotalBytes !== kUnknown &&
|
||||
(100 * aT._amount / aTotalBytes) < kSignificanceThresholdPerc;
|
||||
}
|
||||
|
||||
@ -897,15 +870,15 @@ function appendWarningElements(aP, aHasKnownHeapAllocated,
|
||||
appendElementWithText(aP, "p", "",
|
||||
"WARNING: the 'heap-allocated' memory reporter and the " +
|
||||
"moz_malloc_usable_size() function do not work for this platform " +
|
||||
"and/or configuration. This means that 'heap-unclassified' is zero " +
|
||||
"and the 'explicit' tree shows much less memory than it should.");
|
||||
"and/or configuration. This means that 'heap-unclassified' is not " +
|
||||
"shown and the 'explicit' tree shows much less memory than it should.");
|
||||
appendTextNode(aP, "\n\n");
|
||||
|
||||
} else if (!aHasKnownHeapAllocated) {
|
||||
appendElementWithText(aP, "p", "",
|
||||
"WARNING: the 'heap-allocated' memory reporter does not work for this " +
|
||||
"platform and/or configuration. This means that 'heap-unclassified' " +
|
||||
"is zero and the 'explicit' tree shows less memory than it should.");
|
||||
"is not shown and the 'explicit' tree shows less memory than it should.");
|
||||
appendTextNode(aP, "\n\n");
|
||||
|
||||
} else if (!aHasMozMallocUsableSize) {
|
||||
@ -1151,7 +1124,7 @@ const kHideKids = 1;
|
||||
const kShowKids = 2;
|
||||
|
||||
function appendMrNameSpan(aP, aKind, aKidsState, aDescription, aUnsafeName,
|
||||
aIsUnknown, aIsInvalid, aNMerged)
|
||||
aIsInvalid, aNMerged)
|
||||
{
|
||||
let text = "";
|
||||
if (aKidsState === kNoKids) {
|
||||
@ -1170,11 +1143,6 @@ function appendMrNameSpan(aP, aKind, aKidsState, aDescription, aUnsafeName,
|
||||
flipBackslashes(aUnsafeName));
|
||||
nameSpan.title = kindToString(aKind) + aDescription;
|
||||
|
||||
if (aIsUnknown) {
|
||||
let noteSpan = appendElementWithText(aP, "span", "mrNote", " [*]");
|
||||
noteSpan.title =
|
||||
"Warning: this memory reporter was unable to compute a useful value. ";
|
||||
}
|
||||
if (aIsInvalid) {
|
||||
let noteSpan = appendElementWithText(aP, "span", "mrNote", " [?!]");
|
||||
noteSpan.title =
|
||||
@ -1372,7 +1340,7 @@ function appendTreeElements(aPOuter, aT, aProcess)
|
||||
// the whole tree is non-heap.
|
||||
let kind = isExplicitTree ? aT._kind : undefined;
|
||||
appendMrNameSpan(d, kind, kidsState, aT._description, aT._unsafeName,
|
||||
aT._isUnknown, tIsInvalid, aT._nMerged);
|
||||
tIsInvalid, aT._nMerged);
|
||||
appendTextNode(d, "\n");
|
||||
|
||||
// In non-verbose mode, invalid nodes can be hidden in collapsed sub-trees.
|
||||
@ -1424,12 +1392,7 @@ function OtherReport(aUnsafePath, aUnits, aAmount, aDescription, aNMerged)
|
||||
// Nb: _kind is not needed, it's always KIND_OTHER.
|
||||
this._unsafePath = aUnsafePath;
|
||||
this._units = aUnits;
|
||||
if (aAmount === kUnknown) {
|
||||
this._amount = 0;
|
||||
this._isUnknown = true;
|
||||
} else {
|
||||
this._amount = aAmount;
|
||||
}
|
||||
this._amount = aAmount;
|
||||
this._description = aDescription;
|
||||
this._asString = this.toString();
|
||||
}
|
||||
@ -1451,9 +1414,8 @@ OtherReport.prototype = {
|
||||
switch (this._units) {
|
||||
case UNITS_BYTES:
|
||||
case UNITS_COUNT:
|
||||
case UNITS_COUNT_CUMULATIVE: return (n !== kUnknown && n < 0);
|
||||
case UNITS_PERCENTAGE: return (n !== kUnknown &&
|
||||
!(0 <= n && n <= 10000));
|
||||
case UNITS_COUNT_CUMULATIVE: return n < 0;
|
||||
case UNITS_PERCENTAGE: return !(0 <= n && n <= 10000);
|
||||
default:
|
||||
assert(false, "bad units in OtherReport.isInvalid");
|
||||
}
|
||||
@ -1514,7 +1476,7 @@ function appendOtherElements(aP, aReportsByProcess)
|
||||
}
|
||||
appendMrValueSpan(pre, pad(o._asString, maxStringLength, ' '), oIsInvalid);
|
||||
appendMrNameSpan(pre, KIND_OTHER, kNoKids, o._description, o._unsafePath,
|
||||
o._isUnknown, oIsInvalid);
|
||||
oIsInvalid);
|
||||
appendTextNode(pre, "\n");
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
||||
getService(Ci.nsIMemoryReporterManager);
|
||||
|
||||
@ -44,7 +45,6 @@
|
||||
// Setup various fake-but-deterministic reporters.
|
||||
const KB = 1024;
|
||||
const MB = KB * KB;
|
||||
const kUnknown = -1;
|
||||
const NONHEAP = Ci.nsIMemoryReporter.KIND_NONHEAP;
|
||||
const HEAP = Ci.nsIMemoryReporter.KIND_HEAP;
|
||||
const OTHER = Ci.nsIMemoryReporter.KIND_OTHER;
|
||||
@ -154,7 +154,15 @@
|
||||
// - but *not* "explicit/c/d" x 2
|
||||
// Check explicit now before we add the fake reporters for the fake 2nd
|
||||
// and subsequent processes.
|
||||
is(mgr.explicit, 500*MB + (100 + 13 + 10)*MB + 599*KB, "mgr.explicit");
|
||||
//
|
||||
// Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a
|
||||
// --enable-trace-malloc build. Allow for that exception, but *only* that
|
||||
// exception.
|
||||
try {
|
||||
is(mgr.explicit, 500*MB + (100 + 13 + 10)*MB + 599*KB, "mgr.explicit");
|
||||
} catch (ex) {
|
||||
is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception");
|
||||
}
|
||||
|
||||
let fakeReporters2 = [
|
||||
f("2nd", "heap-allocated", OTHER, 1000 * MB),
|
||||
@ -176,19 +184,9 @@
|
||||
f("2nd", "smaps/vsize/e", NONHEAP, 24*4*KB),
|
||||
f("2nd", "smaps/vsize/f", NONHEAP, 24*4*KB),
|
||||
|
||||
// kUnknown should be handled gracefully for "heap-allocated", non-leaf
|
||||
// reporters, leaf-reporters, "other" reporters, and duplicated reporters.
|
||||
f("3rd", "heap-allocated", OTHER, kUnknown),
|
||||
// Check that we can handle "heap-allocated" not being present.
|
||||
f("3rd", "explicit/a/b", HEAP, 333 * MB),
|
||||
f("3rd", "explicit/a/c", HEAP, 444 * MB),
|
||||
f("3rd", "explicit/a/c", HEAP, kUnknown), // dup: merge
|
||||
f("3rd", "explicit/a/d", HEAP, kUnknown),
|
||||
f("3rd", "explicit/a/d", HEAP, kUnknown), // dup: merge
|
||||
f("3rd", "explicit/b", NONHEAP, kUnknown),
|
||||
f2("3rd", "other1", OTHER, BYTES, kUnknown),
|
||||
f2("3rd", "other2", OTHER, COUNT, kUnknown),
|
||||
f2("3rd", "other3", OTHER, COUNT_CUMULATIVE, kUnknown),
|
||||
f2("3rd", "other4", OTHER, PERCENTAGE, kUnknown),
|
||||
|
||||
// Invalid values (negative, too-big) should be identified.
|
||||
f("4th", "heap-allocated", OTHER, 100 * MB),
|
||||
@ -285,22 +283,15 @@ Other Measurements\n\
|
||||
\n\
|
||||
3rd Process\n\
|
||||
\n\
|
||||
WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is zero and the 'explicit' tree shows less memory than it should.\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\
|
||||
\n\
|
||||
Explicit Allocations\n\
|
||||
777.00 MB (100.0%) -- explicit\n\
|
||||
├──777.00 MB (100.0%) -- a\n\
|
||||
│ ├──444.00 MB (57.14%) ── c [2]\n\
|
||||
│ ├──333.00 MB (42.86%) ── b\n\
|
||||
│ └────0.00 MB (00.00%) ── d [*] [2]\n\
|
||||
└────0.00 MB (00.00%) ++ (2 tiny)\n\
|
||||
└──777.00 MB (100.0%) -- a\n\
|
||||
├──444.00 MB (57.14%) ── c\n\
|
||||
└──333.00 MB (42.86%) ── b\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
0.00 MB ── heap-allocated [*]\n\
|
||||
0.00 MB ── other1 [*]\n\
|
||||
0 ── other2 [*]\n\
|
||||
0 ── other3 [*]\n\
|
||||
0.00% ── other4 [*]\n\
|
||||
\n\
|
||||
4th Process\n\
|
||||
\n\
|
||||
@ -444,23 +435,15 @@ Other Measurements\n\
|
||||
\n\
|
||||
3rd Process\n\
|
||||
\n\
|
||||
WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is zero and the 'explicit' tree shows less memory than it should.\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\
|
||||
\n\
|
||||
Explicit Allocations\n\
|
||||
814,743,552 B (100.0%) -- explicit\n\
|
||||
├──814,743,552 B (100.0%) -- a\n\
|
||||
│ ├──465,567,744 B (57.14%) ── c [2]\n\
|
||||
│ ├──349,175,808 B (42.86%) ── b\n\
|
||||
│ └────────────0 B (00.00%) ── d [*] [2]\n\
|
||||
├────────────0 B (00.00%) ── b [*]\n\
|
||||
└────────────0 B (00.00%) ── heap-unclassified [*]\n\
|
||||
└──814,743,552 B (100.0%) -- a\n\
|
||||
├──465,567,744 B (57.14%) ── c\n\
|
||||
└──349,175,808 B (42.86%) ── b\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
0 B ── heap-allocated [*]\n\
|
||||
0 B ── other1 [*]\n\
|
||||
0 ── other2 [*]\n\
|
||||
0 ── other3 [*]\n\
|
||||
0.00% ── other4 [*]\n\
|
||||
\n\
|
||||
4th Process\n\
|
||||
\n\
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
const kUnknown = -1;
|
||||
const NONHEAP = Ci.nsIMemoryReporter.KIND_NONHEAP;
|
||||
@ -94,7 +95,18 @@
|
||||
|
||||
// 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.
|
||||
let dummy = mgr.explicit;
|
||||
//
|
||||
// Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a
|
||||
// --enable-trace-malloc build. Allow for that exception, but *only* that
|
||||
// exception.
|
||||
let dummy;
|
||||
let haveExplicit = true;
|
||||
try {
|
||||
dummy = mgr.explicit;
|
||||
} catch (ex) {
|
||||
is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception");
|
||||
haveExplicit = false;
|
||||
}
|
||||
dummy = mgr.resident;
|
||||
|
||||
let e = mgr.enumerateReporters();
|
||||
@ -122,12 +134,15 @@
|
||||
aName + "'s size is reasonable");
|
||||
}
|
||||
|
||||
checkSpecialReport("explicit", explicitAmounts);
|
||||
checkSpecialReport("vsize", vsizeAmounts);
|
||||
checkSpecialReport("resident", residentAmounts);
|
||||
// If mgr.explicit failed, we won't have "heap-allocated" either.
|
||||
if (haveExplicit) {
|
||||
checkSpecialReport("explicit", explicitAmounts);
|
||||
checkSpecialReport("heap-allocated", heapAllocatedAmounts);
|
||||
}
|
||||
checkSpecialReport("vsize", vsizeAmounts);
|
||||
checkSpecialReport("resident", residentAmounts);
|
||||
checkSpecialReport("js-main-runtime-gc-heap-committed", jsGcHeapAmounts);
|
||||
checkSpecialReport("heap-allocated", heapAllocatedAmounts);
|
||||
checkSpecialReport("storage-sqlite", storageSqliteAmounts);
|
||||
checkSpecialReport("storage-sqlite", storageSqliteAmounts);
|
||||
|
||||
ok(areJsCompartmentsPresent, "js compartments are present");
|
||||
ok(isSandboxLocationShown, "sandbox locations are present");
|
||||
|
@ -370,43 +370,46 @@ TelemetryPing.prototype = {
|
||||
let e = mgr.enumerateReporters();
|
||||
while (e.hasMoreElements()) {
|
||||
let mr = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
|
||||
let id = MEM_HISTOGRAMS[mr.path];
|
||||
if (!id) {
|
||||
continue;
|
||||
}
|
||||
// mr.amount is expensive to read in some cases, so get it only once.
|
||||
let amount = mr.amount;
|
||||
if (amount == -1) {
|
||||
let id, mrPath, mrAmount, mrUnits;
|
||||
try {
|
||||
mrPath = mr.path;
|
||||
id = MEM_HISTOGRAMS[mrPath];
|
||||
if (!id) {
|
||||
continue;
|
||||
}
|
||||
mrAmount = mr.amount;
|
||||
mrUnits = mr.units;
|
||||
} catch (ex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let val;
|
||||
if (mr.units == Ci.nsIMemoryReporter.UNITS_BYTES) {
|
||||
val = Math.floor(amount / 1024);
|
||||
if (mrUnits == Ci.nsIMemoryReporter.UNITS_BYTES) {
|
||||
val = Math.floor(mrAmount / 1024);
|
||||
}
|
||||
else if (mr.units == Ci.nsIMemoryReporter.UNITS_COUNT) {
|
||||
val = amount;
|
||||
else if (mrUnits == Ci.nsIMemoryReporter.UNITS_COUNT) {
|
||||
val = mrAmount;
|
||||
}
|
||||
else if (mr.units == Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE) {
|
||||
else if (mrUnits == Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE) {
|
||||
// If the reporter gives us a cumulative count, we'll report the
|
||||
// difference in its value between now and our previous ping.
|
||||
|
||||
if (!(mr.path in this._prevValues)) {
|
||||
if (!(mrPath in this._prevValues)) {
|
||||
// If this is the first time we're reading this reporter, store its
|
||||
// current value but don't report it in the telemetry ping, so we
|
||||
// ignore the effect startup had on the reporter.
|
||||
this._prevValues[mr.path] = amount;
|
||||
this._prevValues[mrPath] = mrAmount;
|
||||
continue;
|
||||
}
|
||||
|
||||
val = amount - this._prevValues[mr.path];
|
||||
this._prevValues[mr.path] = amount;
|
||||
val = mrAmount - this._prevValues[mrPath];
|
||||
this._prevValues[mrPath] = mrAmount;
|
||||
}
|
||||
else {
|
||||
NS_ASSERT(false, "Can't handle memory reporter with units " + mr.units);
|
||||
NS_ASSERT(false, "Can't handle memory reporter with units " + mrUnits);
|
||||
continue;
|
||||
}
|
||||
this.addValue(mr.path, id, val);
|
||||
this.addValue(mrPath, id, val);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -209,8 +209,8 @@ interface nsIMemoryReporter : nsISupports
|
||||
readonly attribute PRInt32 units;
|
||||
|
||||
/*
|
||||
* The numeric value reported by this memory reporter. -1 means "unknown",
|
||||
* ie. something went wrong when getting the amount.
|
||||
* The numeric value reported by this memory reporter. Accesses can fail if
|
||||
* something goes wrong when getting the amount.
|
||||
*/
|
||||
readonly attribute PRInt64 amount;
|
||||
|
||||
@ -317,7 +317,7 @@ interface nsIMemoryReporterManager : nsISupports
|
||||
* Get the resident size (aka. RSS, physical memory used). This reporter
|
||||
* is special-cased because it's interesting, is available on all
|
||||
* platforms, and returns a meaningful result on all common platforms.
|
||||
* -1 means unknown.
|
||||
* Accesses can fail.
|
||||
*/
|
||||
readonly attribute PRInt64 resident;
|
||||
|
||||
@ -327,7 +327,7 @@ interface nsIMemoryReporterManager : nsISupports
|
||||
* calloc, operator new). (Nb: it covers all heap allocations, but will
|
||||
* miss any OS-level ones not covered by memory reporters.) This reporter
|
||||
* is special-cased because it's interesting, and is moderately difficult
|
||||
* to compute in JS. -1 means unknown.
|
||||
* to compute in JS. Accesses can fail.
|
||||
*/
|
||||
readonly attribute PRInt64 explicit;
|
||||
|
||||
@ -346,12 +346,29 @@ interface nsIMemoryReporterManager : nsISupports
|
||||
class MemoryReporter_##_classname MOZ_FINAL : public nsIMemoryReporter { \
|
||||
public: \
|
||||
NS_DECL_ISUPPORTS \
|
||||
NS_IMETHOD GetProcess(nsACString &process) { process.Truncate(); return NS_OK; } \
|
||||
NS_IMETHOD GetPath(nsACString &memoryPath) { memoryPath.Assign(_path); return NS_OK; } \
|
||||
NS_IMETHOD GetProcess(nsACString &process) { process.Truncate(); return NS_OK; } \
|
||||
NS_IMETHOD GetPath(nsACString &memoryPath) { memoryPath.Assign(_path); return NS_OK; } \
|
||||
NS_IMETHOD GetKind(int *kind) { *kind = _kind; return NS_OK; } \
|
||||
NS_IMETHOD GetUnits(int *units) { *units = _units; return NS_OK; } \
|
||||
NS_IMETHOD GetAmount(PRInt64 *amount) { *amount = _amountFunction(); return NS_OK; } \
|
||||
NS_IMETHOD GetDescription(nsACString &desc) { desc.Assign(_desc); return NS_OK; } \
|
||||
NS_IMETHOD GetAmount(PRInt64 *amount) { *amount = _amountFunction(); return NS_OK; } \
|
||||
NS_IMETHOD GetDescription(nsACString &desc) { desc.Assign(_desc); return NS_OK; } \
|
||||
}; \
|
||||
NS_IMPL##_ts##ISUPPORTS1(MemoryReporter_##_classname, nsIMemoryReporter)
|
||||
|
||||
/*
|
||||
* The only difference between this and NS_MEMORY_REPORTER_IMPLEMENT_HELPER
|
||||
* is that the function used to implement GetAmount is fallible.
|
||||
*/
|
||||
#define NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT_HELPER(_classname, _path, _kind, _units, _amountFunction, _desc, _ts) \
|
||||
class MemoryReporter_##_classname MOZ_FINAL : public nsIMemoryReporter { \
|
||||
public: \
|
||||
NS_DECL_ISUPPORTS \
|
||||
NS_IMETHOD GetProcess(nsACString &process) { process.Truncate(); return NS_OK; } \
|
||||
NS_IMETHOD GetPath(nsACString &memoryPath) { memoryPath.Assign(_path); return NS_OK; } \
|
||||
NS_IMETHOD GetKind(int *kind) { *kind = _kind; return NS_OK; } \
|
||||
NS_IMETHOD GetUnits(int *units) { *units = _units; return NS_OK; } \
|
||||
NS_IMETHOD GetAmount(PRInt64 *amount) { return _amountFunction(amount); } \
|
||||
NS_IMETHOD GetDescription(nsACString &desc) { desc.Assign(_desc); return NS_OK; } \
|
||||
}; \
|
||||
NS_IMPL##_ts##ISUPPORTS1(MemoryReporter_##_classname, nsIMemoryReporter)
|
||||
|
||||
@ -359,6 +376,10 @@ interface nsIMemoryReporterManager : nsISupports
|
||||
NS_MEMORY_REPORTER_IMPLEMENT_HELPER(_c, _p, _k, _u, _a, _d, _)
|
||||
#define NS_THREADSAFE_MEMORY_REPORTER_IMPLEMENT(_c, _p, _k, _u, _a, _d) \
|
||||
NS_MEMORY_REPORTER_IMPLEMENT_HELPER(_c, _p, _k, _u, _a, _d, _THREADSAFE_)
|
||||
#define NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT(_c, _p, _k, _u, _a, _d) \
|
||||
NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT_HELPER(_c, _p, _k, _u, _a, _d, _)
|
||||
#define NS_FALLIBLE_THREADSAFE_MEMORY_REPORTER_IMPLEMENT(_c, _p, _k, _u, _a, _d) \
|
||||
NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT_HELPER(_c, _p, _k, _u, _a, _d, _THREADSAFE_)
|
||||
|
||||
#define NS_MEMORY_REPORTER_NAME(_classname) MemoryReporter_##_classname
|
||||
|
||||
|
@ -58,55 +58,62 @@ using namespace mozilla;
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
static PRInt64 GetHardPageFaults()
|
||||
#define HAVE_PAGE_FAULT_REPORTERS 1
|
||||
static nsresult GetHardPageFaults(PRInt64 *n)
|
||||
{
|
||||
struct rusage usage;
|
||||
int err = getrusage(RUSAGE_SELF, &usage);
|
||||
if (err != 0) {
|
||||
return PRInt64(-1);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return usage.ru_majflt;
|
||||
*n = usage.ru_majflt;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static PRInt64 GetSoftPageFaults()
|
||||
static nsresult GetSoftPageFaults(PRInt64 *n)
|
||||
{
|
||||
struct rusage usage;
|
||||
int err = getrusage(RUSAGE_SELF, &usage);
|
||||
if (err != 0) {
|
||||
return PRInt64(-1);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return usage.ru_minflt;
|
||||
*n = usage.ru_minflt;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // HAVE_PAGE_FAULT_REPORTERS
|
||||
|
||||
#if defined(XP_LINUX)
|
||||
|
||||
#include <unistd.h>
|
||||
static PRInt64 GetProcSelfStatmField(int n)
|
||||
static nsresult GetProcSelfStatmField(int field, PRInt64 *n)
|
||||
{
|
||||
// There are more than two fields, but we're only interested in the first
|
||||
// two.
|
||||
static const int MAX_FIELD = 2;
|
||||
size_t fields[MAX_FIELD];
|
||||
NS_ASSERTION(n < MAX_FIELD, "bad field number");
|
||||
MOZ_ASSERT(field < MAX_FIELD, "bad field number");
|
||||
FILE *f = fopen("/proc/self/statm", "r");
|
||||
if (f) {
|
||||
int nread = fscanf(f, "%zu %zu", &fields[0], &fields[1]);
|
||||
fclose(f);
|
||||
return (PRInt64) ((nread == MAX_FIELD) ? fields[n]*getpagesize() : -1);
|
||||
if (nread == MAX_FIELD) {
|
||||
*n = fields[field] * getpagesize();
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return (PRInt64) -1;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
static PRInt64 GetVsize()
|
||||
#define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1
|
||||
static nsresult GetVsize(PRInt64 *n)
|
||||
{
|
||||
return GetProcSelfStatmField(0);
|
||||
return GetProcSelfStatmField(0, n);
|
||||
}
|
||||
|
||||
static PRInt64 GetResident()
|
||||
static nsresult GetResident(PRInt64 *n)
|
||||
{
|
||||
return GetProcSelfStatmField(1);
|
||||
return GetProcSelfStatmField(1, n);
|
||||
}
|
||||
|
||||
#elif defined(SOLARIS)
|
||||
@ -115,10 +122,10 @@ static PRInt64 GetResident()
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void XMappingIter(PRInt64& Vsize, PRInt64& Resident)
|
||||
static void XMappingIter(PRInt64& vsize, PRInt64& resident)
|
||||
{
|
||||
Vsize = -1;
|
||||
Resident = -1;
|
||||
vsize = -1;
|
||||
resident = -1;
|
||||
int mapfd = open("/proc/self/xmap", O_RDONLY);
|
||||
struct stat st;
|
||||
prxmap_t *prmapp = NULL;
|
||||
@ -140,11 +147,11 @@ static void XMappingIter(PRInt64& Vsize, PRInt64& Resident)
|
||||
break;
|
||||
}
|
||||
if (nmap >= n / sizeof (prxmap_t)) {
|
||||
Vsize = 0;
|
||||
Resident = 0;
|
||||
vsize = 0;
|
||||
resident = 0;
|
||||
for (int i = 0; i < n / sizeof (prxmap_t); i++) {
|
||||
Vsize += prmapp[i].pr_size;
|
||||
Resident += prmapp[i].pr_rss * prmapp[i].pr_pagesize;
|
||||
vsize += prmapp[i].pr_size;
|
||||
resident += prmapp[i].pr_rss * prmapp[i].pr_pagesize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -156,18 +163,27 @@ static void XMappingIter(PRInt64& Vsize, PRInt64& Resident)
|
||||
}
|
||||
}
|
||||
|
||||
static PRInt64 GetVsize()
|
||||
#define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1
|
||||
static nsresult GetVsize(PRInt64 *n)
|
||||
{
|
||||
PRInt64 Vsize, Resident;
|
||||
XMappingIter(Vsize, Resident);
|
||||
return Vsize;
|
||||
PRInt64 vsize, resident;
|
||||
XMappingIter(vsize, resident);
|
||||
if (vsize == -1) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*n = vsize;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static PRInt64 GetResident()
|
||||
static nsresult GetResident(PRInt64 *n)
|
||||
{
|
||||
PRInt64 Vsize, Resident;
|
||||
XMappingIter(Vsize, Resident);
|
||||
return Resident;
|
||||
PRInt64 vsize, resident;
|
||||
XMappingIter(vsize, resident);
|
||||
if (resident == -1) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*n = resident;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#elif defined(XP_MACOSX)
|
||||
@ -186,13 +202,18 @@ static bool GetTaskBasicInfo(struct task_basic_info *ti)
|
||||
// The VSIZE figure on Mac includes huge amounts of shared memory and is always
|
||||
// absurdly high, eg. 2GB+ even at start-up. But both 'top' and 'ps' report
|
||||
// it, so we might as well too.
|
||||
static PRInt64 GetVsize()
|
||||
#define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1
|
||||
static nsresult GetVsize(PRInt64 *n)
|
||||
{
|
||||
task_basic_info ti;
|
||||
return (PRInt64) (GetTaskBasicInfo(&ti) ? ti.virtual_size : -1);
|
||||
if (!GetTaskBasicInfo(&ti))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*n = ti.virtual_size;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static PRInt64 GetResident()
|
||||
static nsresult GetResident(PRInt64 *n)
|
||||
{
|
||||
#ifdef HAVE_JEMALLOC_STATS
|
||||
// If we're using jemalloc on Mac, we need to instruct jemalloc to purge
|
||||
@ -209,7 +230,11 @@ static PRInt64 GetResident()
|
||||
#endif
|
||||
|
||||
task_basic_info ti;
|
||||
return (PRInt64) (GetTaskBasicInfo(&ti) ? ti.resident_size : -1);
|
||||
if (!GetTaskBasicInfo(&ti))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*n = ti.resident_size;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#elif defined(XP_WIN)
|
||||
@ -217,42 +242,50 @@ static PRInt64 GetResident()
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
|
||||
static PRInt64 GetVsize()
|
||||
#define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1
|
||||
static nsresult GetVsize(PRInt64 *n)
|
||||
{
|
||||
MEMORYSTATUSEX s;
|
||||
s.dwLength = sizeof(s);
|
||||
|
||||
bool success = GlobalMemoryStatusEx(&s);
|
||||
if (!success)
|
||||
return -1;
|
||||
if (!GlobalMemoryStatusEx(&s)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return s.ullTotalVirtual - s.ullAvailVirtual;
|
||||
*n = s.ullTotalVirtual - s.ullAvailVirtual;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static PRInt64 GetResident()
|
||||
static nsresult GetResident(PRInt64 *n)
|
||||
{
|
||||
PROCESS_MEMORY_COUNTERS pmc;
|
||||
pmc.cb = sizeof(PROCESS_MEMORY_COUNTERS);
|
||||
|
||||
if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
|
||||
return (PRInt64) -1;
|
||||
if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return pmc.WorkingSetSize;
|
||||
*n = pmc.WorkingSetSize;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static PRInt64 GetPrivate()
|
||||
#define HAVE_PRIVATE_REPORTER
|
||||
static nsresult GetPrivate(PRInt64 *n)
|
||||
{
|
||||
PROCESS_MEMORY_COUNTERS_EX pmcex;
|
||||
pmcex.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
|
||||
|
||||
if (!GetProcessMemoryInfo(GetCurrentProcess(),
|
||||
(PPROCESS_MEMORY_COUNTERS) &pmcex, sizeof(pmcex)))
|
||||
return (PRInt64) -1;
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return pmcex.PrivateUsage;
|
||||
*n = pmcex.PrivateUsage;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(Private,
|
||||
NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT(Private,
|
||||
"private",
|
||||
KIND_OTHER,
|
||||
UNITS_BYTES,
|
||||
@ -261,17 +294,10 @@ NS_MEMORY_REPORTER_IMPLEMENT(Private,
|
||||
"is committed and marked MEM_PRIVATE, data that is not mapped, and "
|
||||
"executable pages that have been written to.")
|
||||
|
||||
#else
|
||||
#endif // XP_<PLATFORM>
|
||||
|
||||
static PRInt64 GetResident()
|
||||
{
|
||||
return (PRInt64) -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(XP_LINUX) || defined(XP_MACOSX) || defined(XP_WIN) || defined(SOLARIS)
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(Vsize,
|
||||
#ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
|
||||
NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT(Vsize,
|
||||
"vsize",
|
||||
KIND_OTHER,
|
||||
UNITS_BYTES,
|
||||
@ -284,7 +310,7 @@ NS_MEMORY_REPORTER_IMPLEMENT(Vsize,
|
||||
"another. But even on other operating systems, 'resident' is a much better "
|
||||
"measure of the memory resources used by the process.")
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(Resident,
|
||||
NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT(Resident,
|
||||
"resident",
|
||||
KIND_OTHER,
|
||||
UNITS_BYTES,
|
||||
@ -295,10 +321,10 @@ NS_MEMORY_REPORTER_IMPLEMENT(Resident,
|
||||
"but it depends both on other processes being run and details of the OS "
|
||||
"kernel and so is best used for comparing the memory usage of a single "
|
||||
"process at different points in time.")
|
||||
#endif
|
||||
#endif // HAVE_VSIZE_AND_RESIDENT_REPORTERS
|
||||
|
||||
#if defined(XP_LINUX) || defined(XP_MACOSX) || defined(SOLARIS)
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(PageFaultsSoft,
|
||||
#ifdef HAVE_PAGE_FAULT_REPORTERS
|
||||
NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT(PageFaultsSoft,
|
||||
"page-faults-soft",
|
||||
KIND_OTHER,
|
||||
UNITS_COUNT_CUMULATIVE,
|
||||
@ -313,7 +339,7 @@ NS_MEMORY_REPORTER_IMPLEMENT(PageFaultsSoft,
|
||||
"and because the OS services a soft page fault without accessing the disk, "
|
||||
"they impact performance much less than hard page faults.")
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(PageFaultsHard,
|
||||
NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT(PageFaultsHard,
|
||||
"page-faults-hard",
|
||||
KIND_OTHER,
|
||||
UNITS_COUNT_CUMULATIVE,
|
||||
@ -328,7 +354,7 @@ NS_MEMORY_REPORTER_IMPLEMENT(PageFaultsHard,
|
||||
"accessing the disk is up to a million times slower than accessing RAM, "
|
||||
"the program may run very slowly when it is experiencing more than 100 or "
|
||||
"so hard page faults a second.")
|
||||
#endif
|
||||
#endif // HAVE_PAGE_FAULT_REPORTERS
|
||||
|
||||
/**
|
||||
** memory reporter implementation for jemalloc and OSX malloc,
|
||||
@ -338,11 +364,13 @@ NS_MEMORY_REPORTER_IMPLEMENT(PageFaultsHard,
|
||||
|
||||
#if HAVE_JEMALLOC_STATS
|
||||
|
||||
#define HAVE_HEAP_ALLOCATED_REPORTERS 1
|
||||
|
||||
static PRInt64 GetHeapUnallocated()
|
||||
{
|
||||
jemalloc_stats_t stats;
|
||||
jemalloc_stats(&stats);
|
||||
return (PRInt64) stats.mapped - stats.allocated;
|
||||
return (PRInt64) (stats.mapped - stats.allocated);
|
||||
}
|
||||
|
||||
static PRInt64 GetHeapAllocated()
|
||||
@ -363,7 +391,7 @@ static PRInt64 GetHeapCommittedFragmentation()
|
||||
{
|
||||
jemalloc_stats_t stats;
|
||||
jemalloc_stats(&stats);
|
||||
return (PRInt64) 10000 * (1 - stats.allocated / (double)stats.committed);
|
||||
return (PRInt64) (10000 * (1 - stats.allocated / (double)stats.committed));
|
||||
}
|
||||
|
||||
static PRInt64 GetHeapDirty()
|
||||
@ -408,42 +436,37 @@ NS_MEMORY_REPORTER_IMPLEMENT(HeapDirty,
|
||||
#elif defined(XP_MACOSX) && !defined(MOZ_MEMORY)
|
||||
#include <malloc/malloc.h>
|
||||
|
||||
#define HAVE_HEAP_ALLOCATED_REPORTERS 1
|
||||
|
||||
static PRInt64 GetHeapUnallocated()
|
||||
{
|
||||
struct mstats stats = mstats();
|
||||
return (PRInt64) (stats.bytes_total - stats.bytes_used);
|
||||
return stats.bytes_total - stats.bytes_used;
|
||||
}
|
||||
|
||||
static PRInt64 GetHeapAllocated()
|
||||
{
|
||||
struct mstats stats = mstats();
|
||||
return (PRInt64) stats.bytes_used;
|
||||
return stats.bytes_used;
|
||||
}
|
||||
|
||||
// malloc_zone_statistics() crashes when run under DMD because Valgrind doesn't
|
||||
// intercept it. This measurement isn't important for DMD, so don't even try
|
||||
// to get it.
|
||||
#ifndef MOZ_DMD
|
||||
#define HAVE_HEAP_ZONE0_REPORTERS 1
|
||||
static PRInt64 GetHeapZone0Committed()
|
||||
{
|
||||
#ifdef MOZ_DMD
|
||||
// malloc_zone_statistics() crashes when run under DMD because Valgrind
|
||||
// doesn't intercept it. This measurement isn't important for DMD, so
|
||||
// don't even try.
|
||||
return (PRInt64) -1;
|
||||
#else
|
||||
malloc_statistics_t stats;
|
||||
malloc_zone_statistics(malloc_default_zone(), &stats);
|
||||
return stats.size_in_use;
|
||||
#endif
|
||||
}
|
||||
|
||||
static PRInt64 GetHeapZone0Used()
|
||||
{
|
||||
#ifdef MOZ_DMD
|
||||
// See comment in GetHeapZone0Committed above.
|
||||
return (PRInt64) -1;
|
||||
#else
|
||||
malloc_statistics_t stats;
|
||||
malloc_zone_statistics(malloc_default_zone(), &stats);
|
||||
return stats.size_allocated;
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(HeapZone0Committed,
|
||||
@ -461,29 +484,19 @@ NS_MEMORY_REPORTER_IMPLEMENT(HeapZone0Used,
|
||||
GetHeapZone0Used,
|
||||
"Memory mapped by the heap allocator in the default zone that is "
|
||||
"allocated to the application.")
|
||||
|
||||
#else
|
||||
|
||||
static PRInt64 GetHeapAllocated()
|
||||
{
|
||||
return (PRInt64) -1;
|
||||
}
|
||||
|
||||
static PRInt64 GetHeapUnallocated()
|
||||
{
|
||||
return (PRInt64) -1;
|
||||
}
|
||||
#endif // MOZ_DMD
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_HEAP_ALLOCATED_REPORTERS
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(HeapUnallocated,
|
||||
"heap-unallocated",
|
||||
KIND_OTHER,
|
||||
UNITS_BYTES,
|
||||
GetHeapUnallocated,
|
||||
"Memory mapped by the heap allocator that is not part of an active "
|
||||
"allocation. Much of this memory may be uncommitted -- that is, it does not "
|
||||
"take up space in physical memory or in the swap file.")
|
||||
"allocation. Much of this memory may be uncommitted -- that is, it does "
|
||||
"not take up space in physical memory or in the swap file.")
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(HeapAllocated,
|
||||
"heap-allocated",
|
||||
@ -495,20 +508,19 @@ NS_MEMORY_REPORTER_IMPLEMENT(HeapAllocated,
|
||||
"application because the allocator regularly rounds up request sizes. (The "
|
||||
"exact amount requested is not recorded.)")
|
||||
|
||||
static PRInt64 GetExplicit()
|
||||
// The computation of "explicit" fails if "heap-allocated" isn't available,
|
||||
// which is why this is depends on HAVE_HEAP_ALLOCATED_AND_EXPLICIT_REPORTERS.
|
||||
#define HAVE_EXPLICIT_REPORTER 1
|
||||
static nsresult GetExplicit(PRInt64 *n)
|
||||
{
|
||||
nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
|
||||
if (mgr == nsnull)
|
||||
return (PRInt64)-1;
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
PRInt64 n;
|
||||
nsresult rv = mgr->GetExplicit(&n);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return n;
|
||||
return mgr->GetExplicit(n);
|
||||
}
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(Explicit,
|
||||
NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT(Explicit,
|
||||
"explicit",
|
||||
KIND_OTHER,
|
||||
UNITS_BYTES,
|
||||
@ -516,6 +528,7 @@ NS_MEMORY_REPORTER_IMPLEMENT(Explicit,
|
||||
"This is the same measurement as the root of the 'explicit' tree. "
|
||||
"However, it is measured at a different time and so gives slightly "
|
||||
"different results.")
|
||||
#endif // HAVE_HEAP_ALLOCATED_REPORTERS
|
||||
|
||||
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(AtomTableMallocSizeOf, "atom-table")
|
||||
|
||||
@ -551,21 +564,26 @@ nsMemoryReporterManager::Init()
|
||||
|
||||
#define REGISTER(_x) RegisterReporter(new NS_MEMORY_REPORTER_NAME(_x))
|
||||
|
||||
#ifdef HAVE_HEAP_ALLOCATED_REPORTERS
|
||||
REGISTER(HeapAllocated);
|
||||
REGISTER(HeapUnallocated);
|
||||
REGISTER(Explicit);
|
||||
REGISTER(Resident);
|
||||
|
||||
#if defined(XP_LINUX) || defined(XP_MACOSX) || defined(XP_WIN) || defined(SOLARIS)
|
||||
REGISTER(Vsize);
|
||||
#endif
|
||||
|
||||
#if defined(XP_LINUX) || defined(XP_MACOSX) || defined(SOLARIS)
|
||||
#ifdef HAVE_EXPLICIT_REPORTER
|
||||
REGISTER(Explicit);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
|
||||
REGISTER(Vsize);
|
||||
REGISTER(Resident);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PAGE_FAULT_REPORTERS
|
||||
REGISTER(PageFaultsSoft);
|
||||
REGISTER(PageFaultsHard);
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#ifdef HAVE_PRIVATE_REPORTER
|
||||
REGISTER(Private);
|
||||
#endif
|
||||
|
||||
@ -573,7 +591,7 @@ nsMemoryReporterManager::Init()
|
||||
REGISTER(HeapCommitted);
|
||||
REGISTER(HeapCommittedFragmentation);
|
||||
REGISTER(HeapDirty);
|
||||
#elif defined(XP_MACOSX) && !defined(MOZ_MEMORY)
|
||||
#elif defined(HAVE_HEAP_ZONE0_REPORTERS)
|
||||
REGISTER(HeapZone0Committed);
|
||||
REGISTER(HeapZone0Used);
|
||||
#endif
|
||||
@ -655,8 +673,12 @@ nsMemoryReporterManager::UnregisterMultiReporter(nsIMemoryMultiReporter *reporte
|
||||
NS_IMETHODIMP
|
||||
nsMemoryReporterManager::GetResident(PRInt64 *aResident)
|
||||
{
|
||||
*aResident = ::GetResident();
|
||||
return NS_OK;
|
||||
#if HAVE_VSIZE_AND_RESIDENT_REPORTERS
|
||||
return ::GetResident(aResident);
|
||||
#else
|
||||
*aResident = 0;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct MemoryReport {
|
||||
@ -721,7 +743,9 @@ nsMemoryReporterManager::GetExplicit(PRInt64 *aExplicit)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aExplicit);
|
||||
*aExplicit = 0;
|
||||
|
||||
#ifndef HAVE_EXPLICIT_REPORTER
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
#else
|
||||
nsresult rv;
|
||||
bool more;
|
||||
|
||||
@ -748,25 +772,18 @@ nsMemoryReporterManager::GetExplicit(PRInt64 *aExplicit)
|
||||
if (kind == nsIMemoryReporter::KIND_NONHEAP &&
|
||||
path.Find("explicit") == 0)
|
||||
{
|
||||
PRInt64 amount;
|
||||
rv = r->GetAmount(&amount);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Just skip any NONHEAP reporters that fail, because
|
||||
// "heap-allocated" is the most important one.
|
||||
if (amount != PRInt64(-1)) {
|
||||
PRInt64 amount;
|
||||
rv = r->GetAmount(&amount);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
explicitNonHeapNormalSize += amount;
|
||||
}
|
||||
} else if (path.Equals("heap-allocated")) {
|
||||
// If we don't have "heap-allocated", give up, because the result
|
||||
// would be horribly inaccurate.
|
||||
rv = r->GetAmount(&heapAllocated);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If we don't have "heap-allocated", give up, because the result would be
|
||||
// horribly inaccurate.
|
||||
if (heapAllocated == PRInt64(-1)) {
|
||||
*aExplicit = PRInt64(-1);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -817,10 +834,11 @@ nsMemoryReporterManager::GetExplicit(PRInt64 *aExplicit)
|
||||
NS_WARNING(msg);
|
||||
PR_smprintf_free(msg);
|
||||
}
|
||||
#endif
|
||||
#endif // DEBUG
|
||||
|
||||
*aExplicit = heapAllocated + explicitNonHeapNormalSize + explicitNonHeapMultiSize;
|
||||
return NS_OK;
|
||||
#endif // HAVE_HEAP_ALLOCATED_AND_EXPLICIT_REPORTERS
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
Loading…
Reference in New Issue
Block a user