Bug 913260 (part 3) - Formalize the concept of "distinguished amounts" in the memory reporter manager. r=mccr8.

--HG--
extra : rebase_source : cc6f50d85f384ed665d44b2e8850618fd8a56fa5
This commit is contained in:
Nicholas Nethercote 2013-09-19 15:52:28 -07:00
parent a37f0fd912
commit 8bd7f32128
8 changed files with 208 additions and 191 deletions

View File

@ -1593,47 +1593,19 @@ private:
}
};
// Nb: js-main-runtime-compartments/system + js-main-runtime-compartments/user
// could be different to the number of compartments reported by JSReporter if a
// garbage collection occurred between them being consulted. We could move
// these reporters into JSReporter to avoid that problem, but then we couldn't
// easily report them via telemetry, so we live with the small risk of
// inconsistencies.
class RedundantJSMainRuntimeCompartmentsSystemReporter MOZ_FINAL : public MemoryUniReporter
static int64_t
JSMainRuntimeCompartmentsSystemDistinguishedAmount()
{
public:
// An empty description is ok because this is a "redundant/"-prefixed
// reporter and so is ignored by about:memory.
RedundantJSMainRuntimeCompartmentsSystemReporter()
: MemoryUniReporter("redundant/js-main-runtime-compartments/system",
KIND_OTHER, UNITS_COUNT, "")
{}
private:
int64_t Amount() MOZ_OVERRIDE
{
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
return JS::SystemCompartmentCount(rt);
}
};
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
return JS::SystemCompartmentCount(rt);
}
class RedundantJSMainRuntimeCompartmentsUserReporter MOZ_FINAL : public MemoryUniReporter
static int64_t
JSMainRuntimeCompartmentsUserDistinguishedAmount()
{
public:
// An empty description is ok because this is a "redundant/"-prefixed
// reporter and so is ignored by about:memory.
RedundantJSMainRuntimeCompartmentsUserReporter()
: MemoryUniReporter("redundant/js-main-runtime-compartments/user",
KIND_OTHER, UNITS_COUNT,
"The number of JavaScript compartments for user code in the main JSRuntime.")
{}
private:
int64_t Amount() MOZ_OVERRIDE
{
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
return JS::UserCompartmentCount(rt);
}
};
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
return JS::UserCompartmentCount(rt);
}
// This is also a single reporter so it can be used by telemetry.
class JSMainRuntimeTemporaryPeakReporter MOZ_FINAL : public MemoryUniReporter
@ -3056,11 +3028,12 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
if (!xpc_LocalizeRuntime(runtime))
NS_RUNTIMEABORT("xpc_LocalizeRuntime failed.");
// Register memory reporters and distinguished amount functions.
NS_RegisterMemoryReporter(new JSMainRuntimeGCHeapReporter());
NS_RegisterMemoryReporter(new RedundantJSMainRuntimeCompartmentsSystemReporter());
NS_RegisterMemoryReporter(new RedundantJSMainRuntimeCompartmentsUserReporter());
NS_RegisterMemoryReporter(new JSMainRuntimeTemporaryPeakReporter());
NS_RegisterMemoryReporter(new JSMainRuntimeCompartmentsReporter);
RegisterJSMainRuntimeCompartmentsSystemDistinguishedAmount(JSMainRuntimeCompartmentsSystemDistinguishedAmount);
RegisterJSMainRuntimeCompartmentsUserDistinguishedAmount(JSMainRuntimeCompartmentsUserDistinguishedAmount);
// Install a JavaScript 'debugger' keyword handler in debug builds only
#ifdef DEBUG

View File

@ -131,32 +131,21 @@ function onUnload()
/**
* Iterates over each reporter.
*
* @param aIgnoreReporter
* Function that indicates if we should skip an entire reporter, based
* on its name.
* @param aIgnoreReport
* Function that indicates if we should skip a single report from a
* reporter, based on its path.
* @param aHandleReport
* The function that's called for each non-skipped report.
*/
function processMemoryReporters(aIgnoreReporter, aIgnoreReport, aHandleReport)
function processMemoryReporters(aHandleReport)
{
let handleReport = function(aProcess, aUnsafePath, aKind, aUnits,
aAmount, aDescription) {
if (!aIgnoreReport(aUnsafePath)) {
aHandleReport(aProcess, aUnsafePath, aKind, aUnits, aAmount,
aDescription, /* presence = */ undefined);
}
aHandleReport(aProcess, aUnsafePath, aKind, aUnits, aAmount,
aDescription, /* presence = */ undefined);
}
let e = gMgr.enumerateReporters();
while (e.hasMoreElements()) {
let mr = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
if (!aIgnoreReporter(mr.name)) {
// |collectReports| never passes in a |presence| argument.
mr.collectReports(handleReport, null);
}
mr.collectReports(handleReport, null);
}
}
@ -165,22 +154,17 @@ function processMemoryReporters(aIgnoreReporter, aIgnoreReport, aHandleReport)
*
* @param aReports
* Array of reports, read from a file or the clipboard.
* @param aIgnoreReport
* Function that indicates if we should skip a single report, based
* on its path.
* @param aHandleReport
* The function that's called for each report.
*/
function processMemoryReportsFromFile(aReports, aIgnoreReport, aHandleReport)
function processMemoryReportsFromFile(aReports, aHandleReport)
{
// Process each memory reporter with aHandleReport.
for (let i = 0; i < aReports.length; i++) {
let r = aReports[i];
if (!aIgnoreReport(r.path)) {
aHandleReport(r.process, r.path, r.kind, r.units, r.amount,
r.description, r._presence);
}
aHandleReport(r.process, r.path, r.kind, r.units, r.amount,
r.description, r._presence);
}
}
@ -199,7 +183,6 @@ let gVerbose;
// Values for the second argument to updateMainAndFooter.
let HIDE_FOOTER = 0;
let SHOW_FOOTER = 1;
let IGNORE_FOOTER = 2;
function updateMainAndFooter(aMsg, aFooterAction, aClassName)
{
@ -226,7 +209,6 @@ function updateMainAndFooter(aMsg, aFooterAction, aClassName)
switch (aFooterAction) {
case HIDE_FOOTER: gFooter.classList.add('hidden'); break;
case SHOW_FOOTER: gFooter.classList.remove('hidden'); break;
case IGNORE_FOOTER: break;
default: assertInput(false, "bad footer action in updateMainAndFooter");
}
}
@ -504,8 +486,8 @@ function updateAboutMemoryFromJSONObject(aObj)
"missing 'hasMozMallocUsableSize' property");
assertInput(aObj.reports && aObj.reports instanceof Array,
"missing or non-array 'reports' property");
let process = function(aIgnoreReporter, aIgnoreReport, aHandleReport) {
processMemoryReportsFromFile(aObj.reports, aIgnoreReport, aHandleReport);
let process = function(aHandleReport) {
processMemoryReportsFromFile(aObj.reports, aHandleReport);
}
appendAboutMemoryMain(process, aObj.hasMozMallocUsableSize);
} catch (ex) {
@ -937,19 +919,6 @@ function getPCollsByProcess(aProcessReports)
// be in parentheses, so a ')' might appear after the '.'.)
const gSentenceRegExp = /^[A-Z].*\.\)?$/m;
// Ignore any "redundant/"-prefixed reporters and reports, which are only
// used by telemetry.
function ignoreReporter(aName)
{
return aName.startsWith("redundant/");
}
function ignoreReport(aUnsafePath)
{
return aUnsafePath.startsWith("redundant/");
}
function handleReport(aProcess, aUnsafePath, aKind, aUnits, aAmount,
aDescription, aPresence)
{
@ -988,7 +957,8 @@ function getPCollsByProcess(aProcessReports)
assert(aPresence === undefined ||
aPresence == DReport.PRESENT_IN_FIRST_ONLY ||
aPresence == DReport.PRESENT_IN_SECOND_ONLY);
aPresence == DReport.PRESENT_IN_SECOND_ONLY,
"bad presence");
let process = aProcess === "" ? gUnnamedProcessStr : aProcess;
let unsafeNames = aUnsafePath.split('/');
@ -1046,7 +1016,7 @@ function getPCollsByProcess(aProcessReports)
}
}
aProcessReports(ignoreReporter, ignoreReport, handleReport);
aProcessReports(handleReport);
return pcollsByProcess;
}

View File

@ -150,14 +150,6 @@
// the largest). Processes without a |resident| memory reporter are saved
// for the end.
let fakeReporters2 = [
{ name: "redundant/foobar",
collectReports: function(aCbObj, aClosure) {
// Shouldn't reach here; aboutMemory.js should skip the reporter.
// (Nb: this must come after |mgr.explicit| is accessed, otherwise it
// *will* be run by nsMemoryReporterManager::GetExplicit()).
ok(false, "'redundant/foobar' reporter was run");
}
},
{ name: "fake3",
collectReports: function(aCbObj, aClosure) {
function f(aP1, aP2, aK, aU, aA) {
@ -174,7 +166,6 @@
HEAP, BYTES,200 * MB);
f("2nd", "other0", OTHER, BYTES,666 * MB);
f("2nd", "other1", OTHER, BYTES,111 * MB);
f("2nd", "redundant/blah", NONHEAP, BYTES,24*4*KB); // ignored!
// Check that we can handle "heap-allocated" not being present.
f("3rd", "explicit/a/b", HEAP, BYTES,333 * MB);

View File

@ -45,16 +45,7 @@
let heapAllocatedAmounts = [];
let storageSqliteAmounts = [];
let areJsNonWindowCompartmentsPresent = false;
let areWindowObjectsJsCompartmentsPresent = false;
let isSandboxLocationShown = false;
let isPlacesPresent = false;
let isImagesPresent = false;
let isXptiWorkingSetPresent = false;
let isAtomTablePresent = false;
let isBigStringPresent = false;
let isSmallString1Present = false;
let isSmallString2Present = false;
let present = {}
// Generate a long, random string. We'll check that this string is
// reported in at least one of the memory reporters.
@ -92,35 +83,36 @@
// Check the presence of some other notable reporters.
} else if (aPath.search(/^explicit\/js-non-window\/.*compartment\(/) >= 0) {
areJsNonWindowCompartmentsPresent = true;
present.jsNonWindowCompartments = true;
} else if (aPath.search(/^explicit\/window-objects\/top\(.*\/js-compartment\(/) >= 0) {
areWindowObjectsJsCompartmentsPresent = true;
present.windowObjectsJsCompartments = true;
} else if (aPath.search(/^explicit\/storage\/sqlite\/places.sqlite/) >= 0) {
isPlacesPresent = true;
present.places = true;
} else if (aPath.search(/^explicit\/images/) >= 0) {
isImagesPresent = true;
present.images = true;
} else if (aPath.search(/^explicit\/xpti-working-set$/) >= 0) {
isXptiWorkingSetPresent = true;
present.xptiWorkingSet = true;
} else if (aPath.search(/^explicit\/atom-tables$/) >= 0) {
isAtomTablePresent = true;
present.atomTable = true;
} else if (/\[System Principal\].*this-is-a-sandbox-name/.test(aPath)) {
// A system compartment with a location (such as a sandbox) should
// show that location.
isSandboxLocationShown = true;
present.sandboxLocation = true;
} else if (aPath.contains(bigStringPrefix)) {
isBigStringPresent = true;
present.bigString = true;
} else if (aPath.contains("!)(*&")) {
isSmallString1Present = true;
present.smallString1 = true;
} else if (aPath.contains("@)(*&")) {
isSmallString2Present = true;
present.smallString2 = true;
}
}
let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
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.
// Access the distinguished amounts (mgr.explicit et al.) just to make sure
// they don't crash. We can't check their actual values because they're
// non-deterministic.
//
// Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a
// --enable-trace-malloc build. Allow for that exception, but *only* that
@ -134,6 +126,9 @@
haveExplicit = false;
}
dummy = mgr.resident;
dummy = mgr.residentFast;
dummy = mgr.JSMainRuntimeCompartmentsSystem;
dummy = mgr.JSMainRuntimeCompartmentsUser;
let e = mgr.enumerateReporters();
while (e.hasMoreElements()) {
@ -162,16 +157,16 @@
checkSpecialReport("js-main-runtime-gc-heap-committed/used/gc-things", jsGcHeapAmounts);
checkSpecialReport("storage-sqlite", storageSqliteAmounts);
ok(areJsNonWindowCompartmentsPresent, "js-non-window compartments are present");
ok(areWindowObjectsJsCompartmentsPresent, "window-objects/.../js compartments are present");
ok(isSandboxLocationShown, "sandbox locations are present");
ok(isPlacesPresent, "places is present");
ok(isImagesPresent, "images is present");
ok(isXptiWorkingSetPresent, "xpti-working-set is present");
ok(isAtomTablePresent, "atom-table is present");
ok(isBigStringPresent, "large string is present");
ok(isSmallString1Present, "small string 1 is present");
ok(isSmallString2Present, "small string 2 is present");
ok(present.jsNonWindowCompartments, "js-non-window compartments are present");
ok(present.windowObjectsJsCompartments, "window-objects/.../js compartments are present");
ok(present.places, "places is present");
ok(present.images, "images is present");
ok(present.xptiWorkingSet, "xpti-working-set is present");
ok(present.atomTable, "atom-table is present");
ok(present.sandboxLocation, "sandbox locations are present");
ok(present.bigString, "large string is present");
ok(present.smallString1, "small string 1 is present");
ok(present.smallString2, "small string 2 is present");
]]>
</script>

View File

@ -41,9 +41,6 @@ const TELEMETRY_DELAY = 60000;
// MEM_HISTOGRAMS lists the memory reporters we turn into histograms.
//
// Note that we currently handle only vanilla memory reporters, not memory
// multi-reporters.
//
// test_TelemetryPing.js relies on some of these memory reporters
// being here. If you remove any of the following histograms from
// MEM_HISTOGRAMS, you'll have to modify test_TelemetryPing.js:
@ -55,10 +52,7 @@ const TELEMETRY_DELAY = 60000;
// was always really noisy anyway. See bug 859657.
const MEM_HISTOGRAMS = {
"js-main-runtime-gc-heap": "MEMORY_JS_GC_HEAP",
"redundant/js-main-runtime-compartments/system": "MEMORY_JS_COMPARTMENTS_SYSTEM",
"redundant/js-main-runtime-compartments/user": "MEMORY_JS_COMPARTMENTS_USER",
"js-main-runtime-temporary-peak": "MEMORY_JS_MAIN_RUNTIME_TEMPORARY_PEAK",
"redundant/resident-fast": "MEMORY_RESIDENT",
"vsize": "MEMORY_VSIZE",
"storage-sqlite": "MEMORY_STORAGE_SQLITE",
"images-content-used-uncompressed":
@ -447,6 +441,8 @@ TelemetryPing.prototype = {
let histogram = Telemetry.getHistogramById("TELEMETRY_MEMORY_REPORTER_MS");
let startTime = new Date();
// Get memory measurements from reporters.
let e = mgr.enumerateReporters();
while (e.hasMoreElements()) {
let mr = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
@ -480,6 +476,17 @@ TelemetryPing.prototype = {
catch (e) {
}
}
// Get memory measurements from distinguished amount attributes.
let h = this.handleMemoryReport.bind(this);
let b = (id, n) => h(id, Ci.nsIMemoryReporter.UNITS_BYTES, n);
let c = (id, n) => h(id, Ci.nsIMemoryReporter.UNITS_COUNT, n);
let p = (id, n) => h(id, Ci.nsIMemoryReporter.UNITS_PERCENTAGE, n);
try { b("MEMORY_RESIDENT", mgr.residentFast); } catch (e) {}
try { c("MEMORY_JS_COMPARTMENTS_SYSTEM", mgr.JSMainRuntimeCompartmentsSystem); } catch (e) {}
try { c("MEMORY_JS_COMPARTMENTS_USER", mgr.JSMainRuntimeCompartmentsUser); } catch (e) {}
histogram.add(new Date() - startTime);
},

View File

@ -143,11 +143,6 @@ interface nsIMemoryReporterCallback : nsISupports
* description that is a sentence (i.e. starts with a capital letter and
* ends with a period, or similar).
*
* - The "redundant" tree is optional, and can be used for reports that are
* redundant w.r.t. other reports. These are useful for telemetry, and are
* not shown in about:memory. Reports in this tree are entirely
* unconstrained.
*
* - All other reports are unconstrained except that they must have a
* description that is a sentence.
*/
@ -189,21 +184,21 @@ interface nsIMemoryReporterManager : nsISupports
/*
* Return an enumerator of nsIMemoryReporters that are currently registered.
*/
nsISimpleEnumerator enumerateReporters ();
nsISimpleEnumerator enumerateReporters();
/*
* Register the given nsIMemoryReporter. After a reporter is registered,
* it will be available via enumerateReporters(). The Manager service
* will hold a strong reference to the given reporter.
*/
void registerReporter (in nsIMemoryReporter reporter);
void registerReporter(in nsIMemoryReporter reporter);
/*
* Unregister the given memory reporter.
*/
void unregisterReporter (in nsIMemoryReporter reporter);
void unregisterReporter(in nsIMemoryReporter reporter);
/**
/*
* These functions should only be used for testing purposes.
*/
void blockRegistration();
@ -213,24 +208,39 @@ interface nsIMemoryReporterManager : nsISupports
/*
* Initialize.
*/
void init ();
void init();
/*
* Get the resident size (aka. RSS, physical memory used). This reporter
* is special-cased because it's interesting and is available on most
* platforms. Accesses can fail.
*/
readonly attribute int64_t resident;
/*
* Get the total size of explicit memory allocations, both at the OS-level
* (eg. via mmap, VirtualAlloc) and at the heap level (eg. via malloc,
* 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 difficult to compute
* from JavaScript code. Accesses can fail.
* The memory reporter manager, for the most part, treats reporters
* registered with it as a black box. However, there are some
* "distinguished" amounts (as could be reported by a memory reporter) that
* the manager provides as attributes, because they are sufficiently
* interesting that we want external code to be able to rely on them.
*
* Note that these are not reporters and so enumerateReporters() does not
* look at them. However, they can be embedded in a reporter.
*
* |explicit| (UNIT_BYTES) The total size of explicit memory allocations,
* both at the OS-level (eg. via mmap, VirtualAlloc) and at the heap level
* (eg. via malloc, calloc, operator new). It covers all heap allocations,
* but will miss any OS-level ones not covered by memory reporters.
*
* |resident| (UNIT_BYTES) The resident size (a.k.a. RSS or physical memory
* used).
*
* |residentFast| (UNIT_BYTES) This is like |resident|, but on Mac OS
* |resident| can purge pages, which is slow. It also affects the result of
* |residentFast|, and so |resident| and |residentFast| should not be used
* together. It is used by telemetry.
*
* |JSMainRuntimeCompartments{System,User}| (UNIT_COUNTS) The number of
* {system,user} compartments in the main JS runtime.
*/
readonly attribute int64_t explicit;
readonly attribute int64_t resident;
readonly attribute int64_t residentFast;
readonly attribute int64_t JSMainRuntimeCompartmentsSystem;
readonly attribute int64_t JSMainRuntimeCompartmentsUser;
/*
* This attribute indicates if moz_malloc_usable_size() works.
@ -256,6 +266,27 @@ interface nsIMemoryReporterManager : nsISupports
XPCOM_API(nsresult) NS_RegisterMemoryReporter(nsIMemoryReporter* aReporter);
XPCOM_API(nsresult) NS_UnregisterMemoryReporter(nsIMemoryReporter* aReporter);
namespace mozilla {
// The memory reporter manager provides access to several distinguished
// amounts via attributes. Some of these amounts are provided by Gecko
// components that cannot be accessed directly from XPCOM code. So we provide
// the following functions for those components to be registered with the
// manager.
typedef int64_t (*InfallibleAmountFn)();
typedef nsresult (*FallibleAmountFn)(int64_t* aAmount);
#define REGISTER_DISTINGUISHED_AMOUNT(kind, name) \
nsresult Register##name##DistinguishedAmount(kind##AmountFn aAmountFn);
REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsSystem)
REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsUser)
#undef REGISTER_DISTINGUISHED_AMOUNT
}
#if defined(MOZ_DMD)
namespace mozilla {
namespace dmd {
@ -393,5 +424,4 @@ protected:
} // namespace mozilla
%}

View File

@ -16,9 +16,10 @@
#if defined(XP_LINUX)
#include "nsMemoryInfoDumper.h"
#endif
#include "mozilla/Telemetry.h"
#include "mozilla/Attributes.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Services.h"
#include "mozilla/Telemetry.h"
#ifndef XP_WIN
#include <unistd.h>
@ -426,26 +427,6 @@ public:
NS_IMETHOD GetAmount(int64_t* aAmount) { return GetResident(aAmount); }
};
// This is a "redundant/"-prefixed reporter, which means it's ignored by
// about:memory. This is good because the "resident" reporter can purge pages
// on MacOS, which affects the "resident-fast" results, and we don't want the
// measurements shown in about:memory to be affected by the (arbitrary) order
// of memory reporter execution. This reporter is used by telemetry.
class ResidentFastReporter MOZ_FINAL : public MemoryUniReporter
{
public:
ResidentFastReporter()
: MemoryUniReporter("redundant/resident-fast", KIND_OTHER, UNITS_BYTES,
"This is the same measurement as 'resident', but it tries to be as fast as "
"possible at the expense of accuracy. On most platforms this is identical to "
"the 'resident' measurement, but on Mac it may over-count. You should use "
"'resident-fast' where you care about latency of collection (e.g. in "
"telemetry). Otherwise you should use 'resident'.")
{}
NS_IMETHOD GetAmount(int64_t* aAmount) { return GetResidentFast(aAmount); }
};
#endif // HAVE_VSIZE_AND_RESIDENT_REPORTERS
#ifdef XP_UNIX
@ -752,7 +733,6 @@ nsMemoryReporterManager::Init()
#ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
RegisterReporter(new VsizeReporter);
RegisterReporter(new ResidentReporter);
RegisterReporter(new ResidentFastReporter);
#endif
#ifdef HAVE_RESIDENT_UNIQUE_REPORTER
@ -848,6 +828,7 @@ nsMemoryReporterManager::nsMemoryReporterManager()
: mMutex("nsMemoryReporterManager::mMutex"),
mIsRegistrationBlocked(false)
{
PodZero(&mAmountFns);
}
nsMemoryReporterManager::~nsMemoryReporterManager()
@ -964,17 +945,6 @@ nsMemoryReporterManager::UnblockRegistration()
return NS_OK;
}
NS_IMETHODIMP
nsMemoryReporterManager::GetResident(int64_t* aResident)
{
#ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
return ::GetResident(aResident);
#else
*aResident = 0;
return NS_ERROR_NOT_AVAILABLE;
#endif
}
// This is just a wrapper for int64_t that implements nsISupports, so it can be
// passed to nsIMemoryReporter::CollectReports.
class Int64Wrapper MOZ_FINAL : public nsISupports {
@ -1009,10 +979,10 @@ public:
NS_IMPL_ISUPPORTS1(ExplicitCallback, nsIMemoryReporterCallback)
NS_IMETHODIMP
nsMemoryReporterManager::GetExplicit(int64_t* aExplicit)
nsMemoryReporterManager::GetExplicit(int64_t* aAmount)
{
NS_ENSURE_ARG_POINTER(aExplicit);
*aExplicit = 0;
NS_ENSURE_ARG_POINTER(aAmount);
*aAmount = 0;
#ifndef HAVE_JEMALLOC_STATS
return NS_ERROR_NOT_AVAILABLE;
#else
@ -1035,12 +1005,59 @@ nsMemoryReporterManager::GetExplicit(int64_t* aExplicit)
r->CollectReports(cb, wrappedExplicitSize);
}
*aExplicit = wrappedExplicitSize->mValue;
*aAmount = wrappedExplicitSize->mValue;
return NS_OK;
#endif // HAVE_JEMALLOC_STATS
}
NS_IMETHODIMP
nsMemoryReporterManager::GetResident(int64_t* aAmount)
{
#ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
return ::GetResident(aAmount);
#else
*aAmount = 0;
return NS_ERROR_NOT_AVAILABLE;
#endif
}
NS_IMETHODIMP
nsMemoryReporterManager::GetResidentFast(int64_t* aAmount)
{
#ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
return ::GetResidentFast(aAmount);
#else
*aAmount = 0;
return NS_ERROR_NOT_AVAILABLE;
#endif
}
static nsresult
GetInfallibleAmount(InfallibleAmountFn aAmountFn, int64_t* aAmount)
{
if (aAmountFn) {
*aAmount = aAmountFn();
return NS_OK;
}
*aAmount = 0;
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsMemoryReporterManager::GetJSMainRuntimeCompartmentsSystem(int64_t* aAmount)
{
return GetInfallibleAmount(mAmountFns.mJSMainRuntimeCompartmentsSystem,
aAmount);
}
NS_IMETHODIMP
nsMemoryReporterManager::GetJSMainRuntimeCompartmentsUser(int64_t* aAmount)
{
return GetInfallibleAmount(mAmountFns.mJSMainRuntimeCompartmentsUser,
aAmount);
}
NS_IMETHODIMP
nsMemoryReporterManager::GetHasMozMallocUsableSize(bool* aHas)
{
@ -1163,6 +1180,32 @@ NS_UnregisterMemoryReporter(nsIMemoryReporter* aReporter)
return mgr->UnregisterReporter(aReporter);
}
namespace mozilla {
// Macro for generating functions that register distinguished amount functions
// with the memory reporter manager.
#define REGISTER_DISTINGUISHED_AMOUNT(kind, name) \
nsresult \
Register##name##DistinguishedAmount(kind##AmountFn aAmountFn) \
{ \
nsCOMPtr<nsIMemoryReporterManager> imgr = \
do_GetService("@mozilla.org/memory-reporter-manager;1"); \
nsRefPtr<nsMemoryReporterManager> mgr = \
static_cast<nsMemoryReporterManager*>(imgr.get()); \
if (!mgr) { \
return NS_ERROR_FAILURE; \
} \
mgr->mAmountFns.m##name = aAmountFn; \
return NS_OK; \
}
REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsSystem)
REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsUser)
#undef REGISTER_DISTINGUISHED_AMOUNT
}
#if defined(MOZ_DMD)
namespace mozilla {

View File

@ -20,8 +20,16 @@ public:
nsMemoryReporterManager();
virtual ~nsMemoryReporterManager();
// Functions that (a) implement distinguished amounts, and (b) are outside of
// this module.
struct AmountFns {
mozilla::InfallibleAmountFn mJSMainRuntimeCompartmentsSystem;
mozilla::InfallibleAmountFn mJSMainRuntimeCompartmentsUser;
};
AmountFns mAmountFns;
private:
nsresult RegisterReporterHelper(nsIMemoryReporter *reporter, bool aForce);
nsresult RegisterReporterHelper(nsIMemoryReporter *aReporter, bool aForce);
nsTHashtable<nsISupportsHashKey> mReporters;
Mutex mMutex;