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
authorJustin Lebar <justin.lebar@gmail.com>
Mon, 30 Apr 2012 14:27:15 -0400
changeset 96863 f5a301fe9ba5548c629389f45639f1d741355666
parent 96862 ecfa1fd40096332ef103a4d57eb7265fd5c2aaee
child 96864 d7db4957bb753e1f953cec36aa534dc12c8ff02d
push idunknown
push userunknown
push dateunknown
reviewersnjn
bugs748440
milestone15.0a1
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
browser/components/privatebrowsing/test/unit/test_privatebrowsing_autostart.js
browser/components/privatebrowsing/test/unit/test_privatebrowsingwrapper_autostart.js
js/public/MemoryMetrics.h
js/src/MemoryMetrics.cpp
js/xpconnect/src/XPCJSRuntime.cpp
security/manager/ssl/src/nsNSSIOLayer.cpp
security/manager/ssl/src/nsNSSIOLayer.h
xpcom/base/nsIMemoryReporter.idl
xpcom/base/nsMemoryReporterManager.cpp
--- 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);