Bug 913260 (part 4) - Use distinguished amounts for all the memory measurements done by telemetry. r=mccr8.

CLOSED TREE
This commit is contained in:
Nicholas Nethercote 2013-09-19 15:52:30 -07:00
parent e670fcccd8
commit 9c1dfff707
14 changed files with 397 additions and 185 deletions

View File

@ -18,4 +18,4 @@
# Modifying this file will now automatically clobber the buildbot machines \o/
#
Bug 785884 - Implement support for temporary storage (aka shared pool)
Bug 913260 needed a clobber to not break tons of tests

View File

@ -51,6 +51,7 @@ nsWindowMemoryReporter::Init()
}
NS_RegisterMemoryReporter(new GhostWindowsReporter());
RegisterGhostWindowsDistinguishedAmount(GhostWindowsReporter::DistinguishedAmount);
}
static already_AddRefed<nsIURI>
@ -713,10 +714,11 @@ nsWindowMemoryReporter::CheckForGhostWindows(
&ghostEnumData);
}
int64_t
nsWindowMemoryReporter::GhostWindowsReporter::Amount()
/* static */ int64_t
nsWindowMemoryReporter::GhostWindowsReporter::DistinguishedAmount()
{
nsTHashtable<nsUint64HashKey> ghostWindows;
sWindowReporter->CheckForGhostWindows(&ghostWindows);
return ghostWindows.Count();
}

View File

@ -139,8 +139,10 @@ private:
"leaks in the browser or add-ons.")
{}
static int64_t DistinguishedAmount();
private:
int64_t Amount() MOZ_OVERRIDE;
int64_t Amount() MOZ_OVERRIDE { return DistinguishedAmount(); }
};
// Protect ctor, use Init() instead.

View File

@ -137,7 +137,7 @@ public:
return NS_OK;
}
static int64_t GetImagesContentUsedUncompressed()
static int64_t ImagesContentUsedUncompressedDistinguishedAmount()
{
size_t n = 0;
for (uint32_t i = 0; i < imgLoader::sMemReporter->mKnownLoaders.Length(); i++) {
@ -223,26 +223,6 @@ private:
NS_IMPL_ISUPPORTS1(imgMemoryReporter, nsIMemoryReporter)
// This is used by telemetry.
class ImagesContentUsedUncompressedReporter MOZ_FINAL
: public MemoryUniReporter
{
public:
ImagesContentUsedUncompressedReporter()
: MemoryUniReporter("images-content-used-uncompressed",
KIND_OTHER, UNITS_BYTES,
"This is the sum of the 'explicit/images/content/used/uncompressed-heap' "
"and 'explicit/images/content/used/uncompressed-nonheap' numbers. However, "
"it is measured at a different time and so may give slightly different "
"results.")
{}
private:
int64_t Amount() MOZ_OVERRIDE
{
return imgMemoryReporter::GetImagesContentUsedUncompressed();
}
};
NS_IMPL_ISUPPORTS3(nsProgressNotificationProxy,
nsIProgressEventSink,
nsIChannelEventSink,
@ -839,7 +819,7 @@ void imgLoader::GlobalInit()
sMemReporter = new imgMemoryReporter();
NS_RegisterMemoryReporter(sMemReporter);
NS_RegisterMemoryReporter(new ImagesContentUsedUncompressedReporter());
RegisterImagesContentUsedUncompressedDistinguishedAmount(imgMemoryReporter::ImagesContentUsedUncompressedDistinguishedAmount);
}
nsresult imgLoader::InitCache()

View File

@ -1575,23 +1575,20 @@ GetCompartmentName(JSCompartment *c, nsCString &name, bool replaceSlashes)
}
}
// Telemetry relies on this being a uni-reporter (rather than part of the "js"
// reporter).
class JSMainRuntimeGCHeapReporter MOZ_FINAL : public MemoryUniReporter
static int64_t
JSMainRuntimeGCHeapDistinguishedAmount()
{
public:
JSMainRuntimeGCHeapReporter()
: MemoryUniReporter("js-main-runtime-gc-heap", KIND_OTHER, UNITS_BYTES,
"Memory used by the garbage-collected heap in the main JSRuntime.")
{}
private:
int64_t Amount() MOZ_OVERRIDE
{
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
return int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
js::gc::ChunkSize;
}
};
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
return int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
js::gc::ChunkSize;
}
static int64_t
JSMainRuntimeTemporaryPeakDistinguishedAmount()
{
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
return JS::PeakSizeOfTemporary(rt);
}
static int64_t
JSMainRuntimeCompartmentsSystemDistinguishedAmount()
@ -1607,7 +1604,6 @@ JSMainRuntimeCompartmentsUserDistinguishedAmount()
return JS::UserCompartmentCount(rt);
}
// This is also a single reporter so it can be used by telemetry.
class JSMainRuntimeTemporaryPeakReporter MOZ_FINAL : public MemoryUniReporter
{
public:
@ -1620,8 +1616,7 @@ public:
private:
int64_t Amount() MOZ_OVERRIDE
{
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
return JS::PeakSizeOfTemporary(rt);
return JSMainRuntimeTemporaryPeakDistinguishedAmount();
}
};
@ -3029,9 +3024,10 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
NS_RUNTIMEABORT("xpc_LocalizeRuntime failed.");
// Register memory reporters and distinguished amount functions.
NS_RegisterMemoryReporter(new JSMainRuntimeGCHeapReporter());
NS_RegisterMemoryReporter(new JSMainRuntimeTemporaryPeakReporter());
NS_RegisterMemoryReporter(new JSMainRuntimeCompartmentsReporter);
NS_RegisterMemoryReporter(new JSMainRuntimeTemporaryPeakReporter());
RegisterJSMainRuntimeGCHeapDistinguishedAmount(JSMainRuntimeGCHeapDistinguishedAmount);
RegisterJSMainRuntimeTemporaryPeakDistinguishedAmount(JSMainRuntimeTemporaryPeakDistinguishedAmount);
RegisterJSMainRuntimeCompartmentsSystemDistinguishedAmount(JSMainRuntimeCompartmentsSystemDistinguishedAmount);
RegisterJSMainRuntimeCompartmentsUserDistinguishedAmount(JSMainRuntimeCompartmentsUserDistinguishedAmount);

View File

@ -53,22 +53,13 @@ namespace storage {
////////////////////////////////////////////////////////////////////////////////
//// Memory Reporting
// We don't need an "explicit" reporter for total SQLite memory usage, because
// the multi-reporter provides reports that add up to the total. But it's
// useful to have the total in the "Other Measurements" list in about:memory,
// and more importantly, we also gather the total via telemetry.
class StorageSQLiteUniReporter MOZ_FINAL : public MemoryUniReporter
static int64_t
StorageSQLiteDistinguishedAmount()
{
public:
StorageSQLiteUniReporter()
: MemoryUniReporter("storage-sqlite", KIND_OTHER, UNITS_BYTES,
"Memory used by SQLite.")
{}
private:
int64_t Amount() MOZ_OVERRIDE { return ::sqlite3_memory_used(); }
};
return ::sqlite3_memory_used();
}
class StorageSQLiteMultiReporter MOZ_FINAL : public nsIMemoryReporter
class StorageSQLiteReporter MOZ_FINAL : public nsIMemoryReporter
{
private:
Service *mService; // a weakref because Service contains a strongref to this
@ -79,7 +70,7 @@ private:
public:
NS_DECL_THREADSAFE_ISUPPORTS
StorageSQLiteMultiReporter(Service *aService)
StorageSQLiteReporter(Service *aService)
: mService(aService)
{
mStmtDesc = NS_LITERAL_CSTRING(
@ -214,7 +205,7 @@ private:
};
NS_IMPL_ISUPPORTS1(
StorageSQLiteMultiReporter,
StorageSQLiteReporter,
nsIMemoryReporter
)
@ -307,8 +298,8 @@ Service::Service()
Service::~Service()
{
(void)::NS_UnregisterMemoryReporter(mStorageSQLiteUniReporter);
(void)::NS_UnregisterMemoryReporter(mStorageSQLiteMultiReporter);
(void)::NS_UnregisterMemoryReporter(mStorageSQLiteReporter);
mozilla::UnregisterStorageSQLiteDistinguishedAmount();
int rc = sqlite3_vfs_unregister(mSqliteVFS);
if (rc != SQLITE_OK)
@ -538,12 +529,12 @@ Service::initialize()
sDefaultPageSize =
Preferences::GetInt(PREF_TS_PAGESIZE, PREF_TS_PAGESIZE_DEFAULT);
// Create and register our SQLite memory reporters. Registration can only
// happen on the main thread (otherwise you'll get cryptic crashes).
mStorageSQLiteUniReporter = new StorageSQLiteUniReporter();
mStorageSQLiteMultiReporter = new StorageSQLiteMultiReporter(this);
(void)::NS_RegisterMemoryReporter(mStorageSQLiteUniReporter);
(void)::NS_RegisterMemoryReporter(mStorageSQLiteMultiReporter);
// Create and register our SQLite memory reporter and distinguished amount
// function. Registration can only happen on the main thread (otherwise
// you'll get cryptic crashes).
mStorageSQLiteReporter = new StorageSQLiteReporter(this);
(void)::NS_RegisterMemoryReporter(mStorageSQLiteReporter);
mozilla::RegisterStorageSQLiteDistinguishedAmount(StorageSQLiteDistinguishedAmount);
return NS_OK;
}

View File

@ -172,8 +172,7 @@ private:
nsCOMPtr<nsIFile> mProfileStorageFile;
nsCOMPtr<nsIMemoryReporter> mStorageSQLiteUniReporter;
nsCOMPtr<nsIMemoryReporter> mStorageSQLiteMultiReporter;
nsCOMPtr<nsIMemoryReporter> mStorageSQLiteReporter;
static Service *gService;

View File

@ -1342,6 +1342,11 @@ function appendProcessAboutMemoryElements(aP, aProcess, aTrees, aDegenerates,
let t = aTrees[treeName];
if (t) {
fillInTree(t);
// Using the "heap-allocated" reporter here instead of
// nsMemoryReporterManager.heapAllocated goes against the usual pattern.
// But the "heap-allocated" node will go in the tree like the others, so
// we have to deal with it, and once we're dealing with it, it's easier
// to keep doing so rather than switching to the distinguished amount.
hasKnownHeapAllocated =
aDegenerates &&
addHeapUnclassifiedNode(t, aDegenerates["heap-allocated"], aHeapTotal);

View File

@ -125,10 +125,35 @@
is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception");
haveExplicit = false;
}
dummy = mgr.resident;
dummy = mgr.residentFast;
dummy = mgr.JSMainRuntimeCompartmentsSystem;
dummy = mgr.JSMainRuntimeCompartmentsUser;
let amounts = [
"vsize",
"resident",
"residentFast",
"heapAllocated",
"heapOverheadRatio",
"JSMainRuntimeGCHeap",
"JSMainRuntimeTemporaryPeak",
"JSMainRuntimeCompartmentsSystem",
"JSMainRuntimeCompartmentsUser",
"imagesContentUsedUncompressed",
"storageSQLite",
"lowMemoryEventsVirtual",
"lowMemoryEventsPhysical",
"ghostWindows",
"pageFaultsHard",
];
for (let i = 0; i < amounts.length; i++) {
try {
// If mgr[amounts[i]] throws an exception, just move on -- some amounts
// aren't available on all platforms. But if the attribute simply
// isn't present, that indicates the distinguished amounts have changed
// and this file hasn't been updated appropriately.
dummy = mgr[amounts[i]];
ok(dummy !== undefined,
"accessed an unknown distinguished amount: " + amounts[i]);
} catch (ex) {
}
}
let e = mgr.enumerateReporters();
while (e.hasMoreElements()) {
@ -155,7 +180,6 @@
checkSpecialReport("vsize", vsizeAmounts);
checkSpecialReport("resident", residentAmounts);
checkSpecialReport("js-main-runtime-gc-heap-committed/used/gc-things", jsGcHeapAmounts);
checkSpecialReport("storage-sqlite", storageSqliteAmounts);
ok(present.jsNonWindowCompartments, "js-non-window compartments are present");
ok(present.windowObjectsJsCompartments, "window-objects/.../js compartments are present");

View File

@ -39,33 +39,6 @@ const TELEMETRY_INTERVAL = 60000;
// Delay before intializing telemetry (ms)
const TELEMETRY_DELAY = 60000;
// MEM_HISTOGRAMS lists the memory reporters we turn into histograms.
//
// 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:
//
// * MEMORY_JS_GC_HEAP, and
// * MEMORY_JS_COMPARTMENTS_SYSTEM.
//
// We used to measure "explicit" too, but it could cause hangs, and the data
// was always really noisy anyway. See bug 859657.
const MEM_HISTOGRAMS = {
"js-main-runtime-gc-heap": "MEMORY_JS_GC_HEAP",
"js-main-runtime-temporary-peak": "MEMORY_JS_MAIN_RUNTIME_TEMPORARY_PEAK",
"vsize": "MEMORY_VSIZE",
"storage-sqlite": "MEMORY_STORAGE_SQLITE",
"images-content-used-uncompressed":
"MEMORY_IMAGES_CONTENT_USED_UNCOMPRESSED",
"heap-allocated": "MEMORY_HEAP_ALLOCATED",
"heap-overhead": "MEMORY_HEAP_COMMITTED_UNUSED",
"heap-overhead-ratio": "MEMORY_HEAP_COMMITTED_UNUSED_RATIO",
"page-faults-hard": "PAGE_FAULTS_HARD",
"low-memory-events/virtual": "LOW_MEMORY_EVENTS_VIRTUAL",
"low-memory-events/physical": "LOW_MEMORY_EVENTS_PHYSICAL",
"ghost-windows": "GHOST_WINDOWS"
};
// Seconds of idle time before pinging.
// On idle-daily a gather-telemetry notification is fired, during it probes can
// start asynchronous tasks to gather data. On the next idle the data is sent.
@ -442,50 +415,55 @@ 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);
let id = MEM_HISTOGRAMS[mr.name];
if (!id) {
continue;
}
// collectReports might throw an exception. If so, just ignore that
// memory reporter; we're not getting useful data out of it.
// Get memory measurements from distinguished amount attributes. We used
// to measure "explicit" too, but it could cause hangs, and the data was
// always really noisy anyway. See bug 859657.
//
// test_TelemetryPing.js relies on some of these histograms being
// here. If you remove any of the following histograms from here, you'll
// have to modify test_TelemetryPing.js:
//
// * MEMORY_JS_GC_HEAP, and
// * MEMORY_JS_COMPARTMENTS_SYSTEM.
//
// The distinguished amount attribute names don't match the telemetry id
// names in some cases due to a combination of (a) historical reasons, and
// (b) the fact that we can't change telemetry id names without breaking
// data continuity.
//
let boundHandleMemoryReport = this.handleMemoryReport.bind(this);
function h(id, units, amountName) {
try {
// Bind handleMemoryReport() so it can be called inside the closure
// used as the callback.
let boundHandleMemoryReport = this.handleMemoryReport.bind(this);
// Reporters used for telemetry should be uni-reporters! we assert if
// they make more than one report.
let hasReported = false;
function h(process, path, kind, units, amount, desc) {
if (!hasReported) {
boundHandleMemoryReport(id, units, amount);
hasReported = true;
} else {
NS_ASSERT(false,
"reporter " + mr.name + " has made more than one report");
}
}
mr.collectReports(h, null);
}
catch (e) {
}
// If mgr[amountName] throws an exception, just move on -- some amounts
// aren't available on all platforms. But if the attribute simply
// isn't present, that indicates the distinguished amounts have changed
// and this file hasn't been updated appropriately.
let amount = mgr[amountName];
NS_ASSERT(amount !== undefined,
"telemetry accessed an unknown distinguished amount");
boundHandleMemoryReport(id, units, amount);
} 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 cc= (id, n) => h(id, Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE, 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) {}
b("MEMORY_VSIZE", "vsize");
b("MEMORY_RESIDENT", "residentFast");
b("MEMORY_HEAP_ALLOCATED", "heapAllocated");
p("MEMORY_HEAP_COMMITTED_UNUSED_RATIO", "heapOverheadRatio");
b("MEMORY_JS_GC_HEAP", "JSMainRuntimeGCHeap");
b("MEMORY_JS_MAIN_RUNTIME_TEMPORARY_PEAK", "JSMainRuntimeTemporaryPeak");
c("MEMORY_JS_COMPARTMENTS_SYSTEM", "JSMainRuntimeCompartmentsSystem");
c("MEMORY_JS_COMPARTMENTS_USER", "JSMainRuntimeCompartmentsUser");
b("MEMORY_IMAGES_CONTENT_USED_UNCOMPRESSED", "imagesContentUsedUncompressed");
b("MEMORY_STORAGE_SQLITE", "storageSQLite");
cc("MEMORY_EVENTS_VIRTUAL", "lowMemoryEventsVirtual");
cc("MEMORY_EVENTS_PHYSICAL", "lowMemoryEventsPhysical");
c("GHOST_WINDOWS", "ghostWindows");
cc("PAGE_FAULTS_HARD", "pageFaultsHard");
histogram.add(new Date() - startTime);
},

View File

@ -325,6 +325,12 @@ CreateDIBSectionHook(HDC aDC,
return result;
}
static int64_t
LowMemoryEventsVirtualDistinguishedAmount()
{
return sNumLowVirtualMemEvents;
}
class LowMemoryEventsVirtualReporter MOZ_FINAL : public MemoryUniReporter
{
public:
@ -345,7 +351,7 @@ private:
// force-disable virtual-memory tracking there.
MOZ_ASSERT(sizeof(void*) == 4);
return sNumLowVirtualMemEvents;
return LowMemoryEventsVirtualDistinguishedAmount();
}
};
@ -366,6 +372,12 @@ private:
int64_t Amount() MOZ_OVERRIDE { return sNumLowCommitSpaceEvents; }
};
static int64_t
LowMemoryEventsPhysicalDistinguishedAmount()
{
return sNumLowPhysicalMemEvents;
}
class LowMemoryEventsPhysicalReporter MOZ_FINAL : public MemoryUniReporter
{
public:
@ -380,7 +392,7 @@ public:
{}
private:
int64_t Amount() MOZ_OVERRIDE { return sNumLowPhysicalMemEvents; }
int64_t Amount() MOZ_OVERRIDE { return LowMemoryEventsPhysicalDistinguishedAmount(); }
};
#endif // defined(XP_WIN)
@ -503,6 +515,8 @@ void Activate()
if (sizeof(void*) == 4) {
NS_RegisterMemoryReporter(new LowMemoryEventsVirtualReporter());
}
RegisterLowMemoryEventsVirtualDistinguishedAmount(LowMemoryEventsVirtualDistinguishedAmount);
RegisterLowMemoryEventsPhysicalDistinguishedAmount(LowMemoryEventsPhysicalDistinguishedAmount);
sHooksActive = true;
#endif

View File

@ -215,33 +215,88 @@ interface nsIMemoryReporterManager : nsISupports
* 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.
* interesting that we want external code (e.g. telemetry) 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,
* Access to these attributes can fail. In particular, some of them are not
* available on all platforms.
*
* If you add a new distinguished amount, please update
* toolkit/components/aboutmemory/tests/test_memoryReporters.xul.
*
* |explicit| (UNITS_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
* |vsize| (UNITS_BYTES) The virtual size, i.e. the amount of address space
* taken up.
*
* |resident| (UNITS_BYTES) The resident size (a.k.a. RSS or physical memory
* used).
*
* |residentFast| (UNIT_BYTES) This is like |resident|, but on Mac OS
* |residentFast| (UNITS_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.
* together.
*
* |JSMainRuntimeCompartments{System,User}| (UNIT_COUNTS) The number of
* |heapAllocated| (UNITS_BYTES) Memory mapped by the heap allocator.
*
* |heapOverheadRatio| (UNITS_PERCENTAGE) In the heap allocator, this is the
* ratio of committed, unused bytes to allocated bytes. Like all
* UNITS_PERCENTAGE measurements, its amount is multiplied by 100x so it can
* be represented by an int64_t.
*
* |JSMainRuntimeGCHeap| (UNITS_BYTES) Size of the main JS runtime's GC
* heap.
*
* |JSMainRuntimeTemporaryPeak| (UNITS_BYTES) Peak size of the transient
* storage in the main JSRuntime.
*
* |JSMainRuntimeCompartments{System,User}| (UNITS_COUNT) The number of
* {system,user} compartments in the main JS runtime.
*
* |imagesContentUsedUncompressed| (UNITS_BYTES) Memory used for decoded
* images in content.
*
* |storageSQLite| (UNITS_BYTES) Memory used by SQLite.
*
* |lowMemoryEvents{Virtual,Physical}| (UNITS_COUNT_CUMULATIVE) The number
* of low-{virtual,physical}-memory events that have occurred since the
* process started.
*
* |ghostWindows| (UNITS_COUNT) The number of ghost windows.
*
* |pageFaultsHard| (UNITS_COUNT_CUMULATIVE) The number of hard (a.k.a.
* major) page faults that have occurred since the process started.
*/
readonly attribute int64_t explicit;
readonly attribute int64_t vsize;
readonly attribute int64_t resident;
readonly attribute int64_t residentFast;
readonly attribute int64_t heapAllocated;
readonly attribute int64_t heapOverheadRatio;
readonly attribute int64_t JSMainRuntimeGCHeap;
readonly attribute int64_t JSMainRuntimeTemporaryPeak;
readonly attribute int64_t JSMainRuntimeCompartmentsSystem;
readonly attribute int64_t JSMainRuntimeCompartmentsUser;
readonly attribute int64_t imagesContentUsedUncompressed;
readonly attribute int64_t storageSQLite;
readonly attribute int64_t lowMemoryEventsVirtual;
readonly attribute int64_t lowMemoryEventsPhysical;
readonly attribute int64_t ghostWindows;
readonly attribute int64_t pageFaultsHard;
/*
* This attribute indicates if moz_malloc_usable_size() works.
*/
@ -277,13 +332,28 @@ namespace mozilla {
typedef int64_t (*InfallibleAmountFn)();
typedef nsresult (*FallibleAmountFn)(int64_t* aAmount);
#define REGISTER_DISTINGUISHED_AMOUNT(kind, name) \
#define DECL_REGISTER_DISTINGUISHED_AMOUNT(kind, name) \
nsresult Register##name##DistinguishedAmount(kind##AmountFn aAmountFn);
#define DECL_UNREGISTER_DISTINGUISHED_AMOUNT(name) \
nsresult Unregister##name##DistinguishedAmount();
REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsSystem)
REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsUser)
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeGCHeap)
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeTemporaryPeak)
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsSystem)
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsUser)
#undef REGISTER_DISTINGUISHED_AMOUNT
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, ImagesContentUsedUncompressed)
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, StorageSQLite)
DECL_UNREGISTER_DISTINGUISHED_AMOUNT(StorageSQLite)
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, LowMemoryEventsVirtual)
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, LowMemoryEventsPhysical)
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, GhostWindows)
#undef DECL_REGISTER_DISTINGUISHED_AMOUNT
#undef DECL_UNREGISTER_DISTINGUISHED_AMOUNT
}

View File

@ -464,6 +464,18 @@ public:
}
};
static nsresult
PageFaultsHardDistinguishedAmount(int64_t* aAmount)
{
struct rusage usage;
int err = getrusage(RUSAGE_SELF, &usage);
if (err != 0) {
return NS_ERROR_FAILURE;
}
*aAmount = usage.ru_majflt;
return NS_OK;
}
class PageFaultsHardReporter MOZ_FINAL : public MemoryUniReporter
{
public:
@ -483,13 +495,7 @@ public:
NS_IMETHOD GetAmount(int64_t* aAmount)
{
struct rusage usage;
int err = getrusage(RUSAGE_SELF, &usage);
if (err != 0) {
return NS_ERROR_FAILURE;
}
*aAmount = usage.ru_majflt;
return NS_OK;
return PageFaultsHardDistinguishedAmount(aAmount);
}
};
#endif // HAVE_PAGE_FAULT_REPORTERS
@ -502,6 +508,25 @@ public:
#ifdef HAVE_JEMALLOC_STATS
static int64_t
HeapAllocated()
{
jemalloc_stats_t stats;
jemalloc_stats(&stats);
return (int64_t) stats.allocated;
}
// This has UNITS_PERCENTAGE, so it is multiplied by 100x.
static int64_t
HeapOverheadRatio()
{
jemalloc_stats_t stats;
jemalloc_stats(&stats);
return (int64_t) 10000 *
(stats.waste + stats.bookkeeping + stats.page_cache) /
((double)stats.allocated);
}
class HeapAllocatedReporter MOZ_FINAL : public MemoryUniReporter
{
public:
@ -513,12 +538,7 @@ public:
"exact amount requested is not recorded.)")
{}
private:
int64_t Amount() MOZ_OVERRIDE
{
jemalloc_stats_t stats;
jemalloc_stats(&stats);
return (int64_t) stats.allocated;
}
int64_t Amount() MOZ_OVERRIDE { return HeapAllocated(); }
};
class HeapOverheadWasteReporter MOZ_FINAL : public MemoryUniReporter
@ -537,7 +557,7 @@ public:
"fragmented, or that allocator is performing poorly for some other reason.")
{}
private:
int64_t Amount()
int64_t Amount() MOZ_OVERRIDE
{
jemalloc_stats_t stats;
jemalloc_stats(&stats);
@ -554,7 +574,7 @@ public:
"Committed bytes which the heap allocator uses for internal data structures.")
{}
private:
int64_t Amount()
int64_t Amount() MOZ_OVERRIDE
{
jemalloc_stats_t stats;
jemalloc_stats(&stats);
@ -574,7 +594,7 @@ public:
"is typically not larger than a few megabytes.")
{}
private:
int64_t Amount()
int64_t Amount() MOZ_OVERRIDE
{
jemalloc_stats_t stats;
jemalloc_stats(&stats);
@ -594,7 +614,7 @@ public:
"exactly.")
{}
private:
int64_t Amount()
int64_t Amount() MOZ_OVERRIDE
{
jemalloc_stats_t stats;
jemalloc_stats(&stats);
@ -614,14 +634,7 @@ public:
"the heap allocator relative to amount of memory allocated.")
{}
private:
int64_t Amount()
{
jemalloc_stats_t stats;
jemalloc_stats(&stats);
return (int64_t) 10000 *
(stats.waste + stats.bookkeeping + stats.page_cache) /
((double)stats.allocated);
}
int64_t Amount() MOZ_OVERRIDE { return HeapOverheadRatio(); }
};
#endif // HAVE_JEMALLOC_STATS
@ -638,7 +651,10 @@ public:
"Memory used by the dynamic and static atoms tables.")
{}
private:
int64_t Amount() { return NS_SizeOfAtomTablesIncludingThis(MallocSizeOf); }
int64_t Amount() MOZ_OVERRIDE
{
return NS_SizeOfAtomTablesIncludingThis(MallocSizeOf);
}
};
#ifdef MOZ_DMD
@ -965,6 +981,12 @@ public:
const nsACString& aDescription,
nsISupports* aWrappedExplicit)
{
// Using the "heap-allocated" reporter here instead of
// nsMemoryReporterManager.heapAllocated goes against the usual
// pattern. But it's for a good reason: in tests, we can easily
// create artificial (i.e. deterministic) reporters -- which allows us
// to precisely test nsMemoryReporterManager.explicit -- but we can't
// do that for distinguished amounts.
if (aPath.Equals("heap-allocated") ||
(aKind == nsIMemoryReporter::KIND_NONHEAP &&
PromiseFlatCString(aPath).Find("explicit") == 0))
@ -1011,6 +1033,17 @@ nsMemoryReporterManager::GetExplicit(int64_t* aAmount)
#endif // HAVE_JEMALLOC_STATS
}
NS_IMETHODIMP
nsMemoryReporterManager::GetVsize(int64_t* aVsize)
{
#ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
return ::GetVsize(aVsize);
#else
*aResident = 0;
return NS_ERROR_NOT_AVAILABLE;
#endif
}
NS_IMETHODIMP
nsMemoryReporterManager::GetResident(int64_t* aAmount)
{
@ -1033,6 +1066,31 @@ nsMemoryReporterManager::GetResidentFast(int64_t* aAmount)
#endif
}
NS_IMETHODIMP
nsMemoryReporterManager::GetHeapAllocated(int64_t* aAmount)
{
#ifdef HAVE_JEMALLOC_STATS
*aAmount = HeapAllocated();
return NS_OK;
#else
*aAmount = 0;
return NS_ERROR_NOT_AVAILABLE;
#endif
}
// This has UNITS_PERCENTAGE, so it is multiplied by 100x.
NS_IMETHODIMP
nsMemoryReporterManager::GetHeapOverheadRatio(int64_t* aAmount)
{
#ifdef HAVE_JEMALLOC_STATS
*aAmount = HeapOverheadRatio();
return NS_OK;
#else
*aAmount = 0;
return NS_ERROR_NOT_AVAILABLE;
#endif
}
static nsresult
GetInfallibleAmount(InfallibleAmountFn aAmountFn, int64_t* aAmount)
{
@ -1044,6 +1102,18 @@ GetInfallibleAmount(InfallibleAmountFn aAmountFn, int64_t* aAmount)
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsMemoryReporterManager::GetJSMainRuntimeGCHeap(int64_t* aAmount)
{
return GetInfallibleAmount(mAmountFns.mJSMainRuntimeGCHeap, aAmount);
}
NS_IMETHODIMP
nsMemoryReporterManager::GetJSMainRuntimeTemporaryPeak(int64_t* aAmount)
{
return GetInfallibleAmount(mAmountFns.mJSMainRuntimeTemporaryPeak, aAmount);
}
NS_IMETHODIMP
nsMemoryReporterManager::GetJSMainRuntimeCompartmentsSystem(int64_t* aAmount)
{
@ -1058,6 +1128,48 @@ nsMemoryReporterManager::GetJSMainRuntimeCompartmentsUser(int64_t* aAmount)
aAmount);
}
NS_IMETHODIMP
nsMemoryReporterManager::GetImagesContentUsedUncompressed(int64_t* aAmount)
{
return GetInfallibleAmount(mAmountFns.mImagesContentUsedUncompressed,
aAmount);
}
NS_IMETHODIMP
nsMemoryReporterManager::GetStorageSQLite(int64_t* aAmount)
{
return GetInfallibleAmount(mAmountFns.mStorageSQLite, aAmount);
}
NS_IMETHODIMP
nsMemoryReporterManager::GetLowMemoryEventsVirtual(int64_t* aAmount)
{
return GetInfallibleAmount(mAmountFns.mLowMemoryEventsVirtual, aAmount);
}
NS_IMETHODIMP
nsMemoryReporterManager::GetLowMemoryEventsPhysical(int64_t* aAmount)
{
return GetInfallibleAmount(mAmountFns.mLowMemoryEventsPhysical, aAmount);
}
NS_IMETHODIMP
nsMemoryReporterManager::GetGhostWindows(int64_t* aAmount)
{
return GetInfallibleAmount(mAmountFns.mGhostWindows, aAmount);
}
NS_IMETHODIMP
nsMemoryReporterManager::GetPageFaultsHard(int64_t* aAmount)
{
#ifdef HAVE_PAGE_FAULT_REPORTERS
return PageFaultsHardDistinguishedAmount(aAmount);
#else
*aAmount = 0;
return NS_ERROR_NOT_AVAILABLE;
#endif
}
NS_IMETHODIMP
nsMemoryReporterManager::GetHasMozMallocUsableSize(bool* aHas)
{
@ -1184,7 +1296,7 @@ namespace mozilla {
// Macro for generating functions that register distinguished amount functions
// with the memory reporter manager.
#define REGISTER_DISTINGUISHED_AMOUNT(kind, name) \
#define DEFINE_REGISTER_DISTINGUISHED_AMOUNT(kind, name) \
nsresult \
Register##name##DistinguishedAmount(kind##AmountFn aAmountFn) \
{ \
@ -1199,10 +1311,38 @@ namespace mozilla {
return NS_OK; \
}
REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsSystem)
REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsUser)
#define DEFINE_UNREGISTER_DISTINGUISHED_AMOUNT(name) \
nsresult \
Unregister##name##DistinguishedAmount() \
{ \
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 = nullptr; \
return NS_OK; \
}
#undef REGISTER_DISTINGUISHED_AMOUNT
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeGCHeap)
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeTemporaryPeak)
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsSystem)
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsUser)
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, ImagesContentUsedUncompressed)
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, StorageSQLite)
DEFINE_UNREGISTER_DISTINGUISHED_AMOUNT(StorageSQLite)
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, LowMemoryEventsVirtual)
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, LowMemoryEventsPhysical)
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, GhostWindows)
#undef DEFINE_REGISTER_DISTINGUISHED_AMOUNT
#undef DEFINE_UNREGISTER_DISTINGUISHED_AMOUNT
}

View File

@ -23,8 +23,19 @@ public:
// Functions that (a) implement distinguished amounts, and (b) are outside of
// this module.
struct AmountFns {
mozilla::InfallibleAmountFn mJSMainRuntimeGCHeap;
mozilla::InfallibleAmountFn mJSMainRuntimeTemporaryPeak;
mozilla::InfallibleAmountFn mJSMainRuntimeCompartmentsSystem;
mozilla::InfallibleAmountFn mJSMainRuntimeCompartmentsUser;
mozilla::InfallibleAmountFn mImagesContentUsedUncompressed;
mozilla::InfallibleAmountFn mStorageSQLite;
mozilla::InfallibleAmountFn mLowMemoryEventsVirtual;
mozilla::InfallibleAmountFn mLowMemoryEventsPhysical;
mozilla::InfallibleAmountFn mGhostWindows;
};
AmountFns mAmountFns;