Bug 748440 - Part 1: Add heap-committed-unused and heap-committed-unused-ratio memory reporters, and rename some JS memory reporters to match. Also add back the js-gc-heap memory reporter. r=njn
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -117,17 +117,16 @@ struct RuntimeStats
, gcHeapCommitted(0)
, gcHeapUnused(0)
, gcHeapChunkCleanUnused(0)
, gcHeapChunkDirtyUnused(0)
, gcHeapChunkCleanDecommitted(0)
, gcHeapChunkDirtyDecommitted(0)
, gcHeapArenaUnused(0)
, gcHeapChunkAdmin(0)
- , gcHeapFragmentationPercentage(0)
, totalObjects(0)
, totalShapes(0)
, totalScripts(0)
, totalStrings(0)
#ifdef JS_METHODJIT
, totalMjit(0)
#endif
, totalTypeInference(0)
@@ -149,17 +148,16 @@ struct RuntimeStats
size_t gcHeapCommitted;
size_t gcHeapUnused;
size_t gcHeapChunkCleanUnused;
size_t gcHeapChunkDirtyUnused;
size_t gcHeapChunkCleanDecommitted;
size_t gcHeapChunkDirtyDecommitted;
size_t gcHeapArenaUnused;
size_t gcHeapChunkAdmin;
- size_t gcHeapFragmentationPercentage;
size_t totalObjects;
size_t totalShapes;
size_t totalScripts;
size_t totalStrings;
#ifdef JS_METHODJIT
size_t totalMjit;
#endif
size_t totalTypeInference;
--- a/js/src/MemoryMetrics.cpp
+++ b/js/src/MemoryMetrics.cpp
@@ -277,24 +277,16 @@ CollectRuntimeStats(JSRuntime *rt, Runti
rtStats->gcHeapUnused = rtStats->gcHeapChunkDirtyUnused +
rtStats->gcHeapChunkCleanUnused +
rtStats->gcHeapArenaUnused;
rtStats->gcHeapCommitted = rtStats->gcHeapChunkTotal -
rtStats->gcHeapChunkCleanDecommitted -
rtStats->gcHeapChunkDirtyDecommitted;
- // Why 10000x? 100x because it's a percentage, and another 100x
- // because nsIMemoryReporter requires that for percentage amounts so
- // they can be fractional.
- rtStats->gcHeapFragmentationPercentage = (rtStats->gcHeapChunkCleanUnused +
- rtStats->gcHeapChunkDirtyUnused +
- rtStats->gcHeapArenaUnused) * 10000 /
- rtStats->gcHeapCommitted;
-
return true;
}
static void
ExplicitNonHeapCompartmentCallback(JSRuntime *rt, void *data, JSCompartment *compartment)
{
#ifdef JS_METHODJIT
size_t *n = static_cast<size_t *>(data);
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1245,16 +1245,32 @@ GetCompartmentName(JSCompartment *c, boo
// (such as about:memory) have to undo this change.
name.ReplaceChar('/', '\\');
} else {
name.AssignLiteral("null-principal");
}
}
static PRInt64
+GetGCChunkTotalBytes()
+{
+ JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
+ return PRInt64(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) * js::gc::ChunkSize;
+}
+
+// Telemetry relies on this memory reporter being a single-reporter (rather
+// than part of the "js" multi-reporter, which is too slow to run during a
+// telemetry ping).
+NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSGCHeap,
+ "js-gc-heap",
+ KIND_OTHER,
+ nsIMemoryReporter::UNITS_BYTES,
+ GetGCChunkTotalBytes,
+ "Memory used by the garbage-collected JavaScript heap.")
+static PRInt64
GetJSSystemCompartmentCount()
{
return JS::SystemCompartmentCount(nsXPConnect::GetRuntimeInstance()->GetJSRuntime());
}
static PRInt64
GetJSUserCompartmentCount()
{
@@ -1761,45 +1777,50 @@ public:
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-arena-unused"),
nsIMemoryReporter::KIND_OTHER,
rtStats.gcHeapArenaUnused,
"Memory on the main JSRuntime's garbage-collected "
"JavaScript heap, within arenas, that could be holding "
"useful data but currently isn't. This is the sum of all "
"compartments' 'gc-heap/arena-unused' numbers.");
- REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-unused"),
+ REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed-unused"),
nsIMemoryReporter::KIND_OTHER,
rtStats.gcHeapUnused,
"Amount of the GC heap that's committed, but that is "
"neither part of an active allocation nor being used for "
"bookkeeping. Equal to 'gc-heap-chunk-dirty-unused' + "
"'gc-heap-chunk-clean-unused' + 'gc-heap-arena-unused'.");
+ // Why 10000x? 100x because it's a percentage, and another 100x
+ // because nsIMemoryReporter requires that for UNITS_PERCENTAGE
+ // reporters so we can get two decimal places out of the integer value.
+ REPORT(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed-unused-ratio"),
+ nsIMemoryReporter::KIND_OTHER,
+ nsIMemoryReporter::UNITS_PERCENTAGE,
+ (PRInt64) 10000 * rtStats.gcHeapUnused /
+ ((double) rtStats.gcHeapCommitted - rtStats.gcHeapUnused),
+ "Ratio of committed, unused bytes to allocated bytes; i.e. "
+ "'gc-heap-committed-unused' / 'gc-heap-allocated'. This "
+ "measures the overhead of the GC heap allocator relative to the "
+ "amount of memory allocated.");
+
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed"),
nsIMemoryReporter::KIND_OTHER,
rtStats.gcHeapCommitted,
"Committed memory (i.e., in physical memory or swap) "
"used by the garbage-collected JavaScript heap.");
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-allocated"),
nsIMemoryReporter::KIND_OTHER,
(rtStats.gcHeapCommitted - rtStats.gcHeapUnused),
"Amount of the GC heap used for active allocations and "
"bookkeeping. This is calculated as 'gc-heap-committed' "
"- 'gc-heap-unused'.");
- REPORT(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-fragmentation"),
- nsIMemoryReporter::KIND_OTHER,
- nsIMemoryReporter::UNITS_PERCENTAGE,
- rtStats.gcHeapFragmentationPercentage,
- "Fraction of the committed part of the main JSRuntime's "
- "garbage-collected heap that is unused. Computed as "
- "'gc-heap-unused' / 'gc-heap-committed'.");
-
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-decommitted"),
nsIMemoryReporter::KIND_OTHER,
rtStats.gcHeapChunkCleanDecommitted + rtStats.gcHeapChunkDirtyDecommitted,
"The same as 'explicit/js/gc-heap-decommitted'. Shown "
"here for easy comparison with other 'js-gc' reporters.");
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-objects"),
nsIMemoryReporter::KIND_OTHER, rtStats.totalObjects,
@@ -2002,16 +2023,17 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect*
xpc::WrapperFactory::PrepareForWrapping);
js::SetPreserveWrapperCallback(mJSRuntime, PreserveWrapper);
#ifdef MOZ_CRASHREPORTER
JS_EnumerateDiagnosticMemoryRegions(DiagnosticMemoryCallback);
#endif
JS_SetAccumulateTelemetryCallback(mJSRuntime, AccumulateTelemetryCallback);
js::SetActivityCallback(mJSRuntime, ActivityCallback, this);
+ NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap));
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSSystemCompartmentCount));
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSUserCompartmentCount));
NS_RegisterMemoryMultiReporter(new JSMemoryMultiReporter);
NS_RegisterMemoryMultiReporter(new JSCompartmentsMultiReporter);
if (!JS_DHashTableInit(&mJSHolders, JS_DHashGetStubOps(), nsnull,
sizeof(ObjectHolder), 512))
mJSHolders.ops = nsnull;
--- a/xpcom/base/nsIMemoryReporter.idl
+++ b/xpcom/base/nsIMemoryReporter.idl
@@ -192,16 +192,18 @@ interface nsIMemoryReporter : nsISupport
* never decrease over the lifetime of the application.
*
* - PERCENTAGE: The amount contains a fraction that should be expressed as
* a percentage. NOTE! The |amount| field should be given a value 100x
* the actual percentage; this number will be divided by 100 when shown.
* This allows a fractional percentage to be shown even though |amount| is
* an integer. E.g. if the actual percentage is 12.34%, |amount| should
* be 1234.
+ *
+ * Values greater than 100% are allowed.
*/
const PRInt32 UNITS_BYTES = 0;
const PRInt32 UNITS_COUNT = 1;
const PRInt32 UNITS_COUNT_CUMULATIVE = 2;
const PRInt32 UNITS_PERCENTAGE = 3;
/*
* The units on the reporter's amount. See UNITS_* above.
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -361,17 +361,17 @@ NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT(Pa
** to obtain info on total memory in use (that we know about,
** at least -- on OSX, there are sometimes other zones in use).
**/
#if HAVE_JEMALLOC_STATS
#define HAVE_HEAP_ALLOCATED_REPORTERS 1
-static PRInt64 GetHeapUnallocated()
+static PRInt64 GetHeapUnused()
{
jemalloc_stats_t stats;
jemalloc_stats(&stats);
return (PRInt64) (stats.mapped - stats.allocated);
}
static PRInt64 GetHeapAllocated()
{
@@ -382,21 +382,29 @@ static PRInt64 GetHeapAllocated()
static PRInt64 GetHeapCommitted()
{
jemalloc_stats_t stats;
jemalloc_stats(&stats);
return (PRInt64) stats.committed;
}
-static PRInt64 GetHeapCommittedFragmentation()
+static PRInt64 GetHeapCommittedUnused()
{
jemalloc_stats_t stats;
jemalloc_stats(&stats);
- return (PRInt64) (10000 * (1 - stats.allocated / (double)stats.committed));
+ return stats.committed - stats.allocated;
+}
+
+static PRInt64 GetHeapCommittedUnusedRatio()
+{
+ jemalloc_stats_t stats;
+ jemalloc_stats(&stats);
+ return (PRInt64) 10000 * (stats.committed - stats.allocated) /
+ ((double)stats.allocated);
}
static PRInt64 GetHeapDirty()
{
jemalloc_stats_t stats;
jemalloc_stats(&stats);
return (PRInt64) stats.dirty;
}
@@ -408,42 +416,51 @@ NS_MEMORY_REPORTER_IMPLEMENT(HeapCommitt
GetHeapCommitted,
"Memory mapped by the heap allocator that is committed, i.e. in physical "
"memory or paged to disk. When heap-committed is larger than "
"heap-allocated, the difference between the two values is likely due to "
"external fragmentation; that is, the allocator allocated a large block of "
"memory and is unable to decommit it because a small part of that block is "
"currently in use.")
-NS_MEMORY_REPORTER_IMPLEMENT(HeapCommittedFragmentation,
- "heap-committed-fragmentation",
+NS_MEMORY_REPORTER_IMPLEMENT(HeapCommittedUnused,
+ "heap-committed-unused",
+ KIND_OTHER,
+ UNITS_BYTES,
+ GetHeapCommittedUnused,
+ "Committed bytes which do not correspond to an active allocation; i.e., "
+ "'heap-committed' - 'heap-allocated'. Although the allocator will waste some "
+ "space under any circumstances, a large value here may indicate that the "
+ "heap is highly fragmented.")
+
+NS_MEMORY_REPORTER_IMPLEMENT(HeapCommittedUnusedRatio,
+ "heap-committed-unused-ratio",
KIND_OTHER,
UNITS_PERCENTAGE,
- GetHeapCommittedFragmentation,
- "Fraction of committed bytes which do not correspond to an active "
- "allocation; i.e., 1 - (heap-allocated / heap-committed). Although the "
- "allocator will waste some space under any circumstances, a large value here "
- "may indicate that the heap is highly fragmented.")
+ GetHeapCommittedUnusedRatio,
+ "Ratio of committed, unused bytes to allocated bytes; i.e., "
+ "'heap-committed-unused' / 'heap-allocated'. This measures the overhead "
+ "of the heap allocator relative to amount of memory allocated.")
NS_MEMORY_REPORTER_IMPLEMENT(HeapDirty,
"heap-dirty",
KIND_OTHER,
UNITS_BYTES,
GetHeapDirty,
"Memory which the allocator could return to the operating system, but "
"hasn't. The allocator keeps this memory around as an optimization, so it "
"doesn't have to ask the OS the next time it needs to fulfill a request. "
"This value is typically not larger than a few megabytes.")
#elif defined(XP_MACOSX) && !defined(MOZ_MEMORY)
#include <malloc/malloc.h>
#define HAVE_HEAP_ALLOCATED_REPORTERS 1
-static PRInt64 GetHeapUnallocated()
+static PRInt64 GetHeapUnused()
{
struct mstats stats = mstats();
return stats.bytes_total - stats.bytes_used;
}
static PRInt64 GetHeapAllocated()
{
struct mstats stats = mstats();
@@ -484,24 +501,24 @@ NS_MEMORY_REPORTER_IMPLEMENT(HeapZone0Us
GetHeapZone0Used,
"Memory mapped by the heap allocator in the default zone that is "
"allocated to the application.")
#endif // MOZ_DMD
#endif
#ifdef HAVE_HEAP_ALLOCATED_REPORTERS
-NS_MEMORY_REPORTER_IMPLEMENT(HeapUnallocated,
- "heap-unallocated",
+NS_MEMORY_REPORTER_IMPLEMENT(HeapUnused,
+ "heap-unused",
KIND_OTHER,
UNITS_BYTES,
- GetHeapUnallocated,
+ GetHeapUnused,
"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",
KIND_OTHER,
UNITS_BYTES,
GetHeapAllocated,
"Memory mapped by the heap allocator that is currently allocated to the "
"application. This may exceed the amount of memory requested by the "
@@ -561,17 +578,17 @@ nsMemoryReporterManager::Init()
if (!jemalloc_stats)
return NS_ERROR_FAILURE;
#endif
#define REGISTER(_x) RegisterReporter(new NS_MEMORY_REPORTER_NAME(_x))
#ifdef HAVE_HEAP_ALLOCATED_REPORTERS
REGISTER(HeapAllocated);
- REGISTER(HeapUnallocated);
+ REGISTER(HeapUnused);
#endif
#ifdef HAVE_EXPLICIT_REPORTER
REGISTER(Explicit);
#endif
#ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
REGISTER(Vsize);
@@ -584,17 +601,17 @@ nsMemoryReporterManager::Init()
#endif
#ifdef HAVE_PRIVATE_REPORTER
REGISTER(Private);
#endif
#if defined(HAVE_JEMALLOC_STATS)
REGISTER(HeapCommitted);
- REGISTER(HeapCommittedFragmentation);
+ REGISTER(HeapCommittedUnusedRatio);
REGISTER(HeapDirty);
#elif defined(HAVE_HEAP_ZONE0_REPORTERS)
REGISTER(HeapZone0Committed);
REGISTER(HeapZone0Used);
#endif
REGISTER(AtomTable);