Bug 799019 - Tweak per-compartment memory reporting. r=Ms2ger, a=akeybl
authorNicholas Nethercote <nnethercote@mozilla.com>
Sat, 20 Oct 2012 00:14:02 -0400
changeset 116222 4ff2c203af97ec9cfec8e93c58b5c24bb42aa45a
parent 116221 049788f927b3a3ea7df0b6be12970c778df08c5f
child 116223 5859d567233a02b6dceac301ef0196f578e91a88
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMs2ger, akeybl
bugs799019
milestone18.0a2
Bug 799019 - Tweak per-compartment memory reporting. r=Ms2ger, a=akeybl
js/public/MemoryMetrics.h
js/src/jscntxt.cpp
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsmemorymetrics.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/xpconnect/src/XPCJSRuntime.cpp
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -53,39 +53,32 @@ struct RuntimeSizes
       , ionCode(0)
       , regexpCode(0)
       , unusedCode(0)
       , stack(0)
       , gcMarker(0)
       , mathCache(0)
       , scriptFilenames(0)
       , scriptSources(0)
-      , compartmentObjects(0)
     {}
 
     size_t object;
     size_t atomsTable;
     size_t contexts;
     size_t dtoa;
     size_t temporary;
     size_t jaegerCode;
     size_t ionCode;
     size_t regexpCode;
     size_t unusedCode;
     size_t stack;
     size_t gcMarker;
     size_t mathCache;
     size_t scriptFilenames;
     size_t scriptSources;
-
-    // This is the exception to the "RuntimeSizes doesn't measure things within
-    // compartments" rule.  We combine the sizes of all the JSCompartment
-    // objects into a single measurement because each one is fairly small, and
-    // they're all the same size.
-    size_t compartmentObjects;
 };
 
 struct CompartmentStats
 {
     CompartmentStats() {
         memset(this, 0, sizeof(*this));
     }
 
@@ -118,17 +111,20 @@ struct CompartmentStats
     size_t stringChars;
     size_t shapesExtraTreeTables;
     size_t shapesExtraDictTables;
     size_t shapesExtraTreeShapeKids;
     size_t shapesCompartmentTables;
     size_t scriptData;
     size_t jaegerData;
     size_t ionData;
+    size_t compartmentObject;
     size_t crossCompartmentWrappers;
+    size_t regexpCompartment;
+    size_t debuggeesSet;
 
     TypeInferenceSizes typeInferenceSizes;
 
     // Add cStats's numbers to this object's numbers.
     void add(CompartmentStats &cStats) {
         #define ADD(x)  this->x += cStats.x
 
         ADD(gcHeapArenaAdmin);
@@ -154,17 +150,20 @@ struct CompartmentStats
         ADD(stringChars);
         ADD(shapesExtraTreeTables);
         ADD(shapesExtraDictTables);
         ADD(shapesExtraTreeShapeKids);
         ADD(shapesCompartmentTables);
         ADD(scriptData);
         ADD(jaegerData);
         ADD(ionData);
+        ADD(compartmentObject);
         ADD(crossCompartmentWrappers);
+        ADD(regexpCompartment);
+        ADD(debuggeesSet);
 
         #undef ADD
 
         typeInferenceSizes.add(cStats.typeInferenceSizes);
     }
 
     // The size of all the live things in the GC heap.
     size_t gcHeapThingsSize();
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -95,29 +95,16 @@ js::TraceCycleDetectionSet(JSTracer *trc
     for (js::ObjectSet::Enum e(set); !e.empty(); e.popFront()) {
         JSObject *prior = e.front();
         MarkObjectRoot(trc, const_cast<JSObject **>(&e.front()), "cycle detector table entry");
         if (prior != e.front())
             e.rekeyFront(e.front());
     }
 }
 
-struct CallbackData
-{
-    CallbackData(JSMallocSizeOfFun f) : mallocSizeOf(f), n(0) {}
-    JSMallocSizeOfFun mallocSizeOf;
-    size_t n;
-};
-
-void CompartmentCallback(JSRuntime *rt, void *vdata, JSCompartment *compartment)
-{
-    CallbackData *data = (CallbackData *) vdata;
-    data->n += data->mallocSizeOf(compartment);
-}
-
 void
 JSRuntime::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, RuntimeSizes *rtSizes)
 {
     rtSizes->object = mallocSizeOf(this);
 
     rtSizes->atomsTable = atoms.sizeOfExcludingThis(mallocSizeOf);
 
     rtSizes->contexts = 0;
@@ -142,21 +129,16 @@ JSRuntime::sizeOfIncludingThis(JSMallocS
 
     rtSizes->gcMarker = gcMarker.sizeOfExcludingThis(mallocSizeOf);
 
     rtSizes->mathCache = mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
 
     rtSizes->scriptFilenames = scriptFilenameTable.sizeOfExcludingThis(mallocSizeOf);
     for (ScriptFilenameTable::Range r = scriptFilenameTable.all(); !r.empty(); r.popFront())
         rtSizes->scriptFilenames += mallocSizeOf(r.front());
-
-    rtSizes->compartmentObjects = 0;
-    CallbackData data(mallocSizeOf);
-    JS_IterateCompartments(this, &data, CompartmentCallback);
-    rtSizes->compartmentObjects = data.n;
 }
 
 size_t
 JSRuntime::sizeOfExplicitNonHeap()
 {
     size_t size = stackSpace.sizeOf();
 
     if (execAlloc_) {
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -842,16 +842,24 @@ JSCompartment::sweepBreakpoints(FreeOp *
                 nextbp = bp->nextInSite();
                 if (scriptGone || !IsObjectMarked(&bp->debugger->toJSObjectRef()))
                     bp->destroy(fop);
             }
         }
     }
 }
 
-size_t
-JSCompartment::sizeOfShapeTable(JSMallocSizeOfFun mallocSizeOf)
+void
+JSCompartment::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *compartmentObject,
+                                   TypeInferenceSizes *tiSizes, size_t *shapesCompartmentTables,
+                                   size_t *crossCompartmentWrappersArg, size_t *regexpCompartment,
+                                   size_t *debuggeesSet)
 {
-    return baseShapes.sizeOfExcludingThis(mallocSizeOf)
-         + initialShapes.sizeOfExcludingThis(mallocSizeOf)
-         + newTypeObjects.sizeOfExcludingThis(mallocSizeOf)
-         + lazyTypeObjects.sizeOfExcludingThis(mallocSizeOf);
+    *compartmentObject = mallocSizeOf(this);
+    sizeOfTypeInferenceData(tiSizes, mallocSizeOf);
+    *shapesCompartmentTables = baseShapes.sizeOfExcludingThis(mallocSizeOf)
+                             + initialShapes.sizeOfExcludingThis(mallocSizeOf)
+                             + newTypeObjects.sizeOfExcludingThis(mallocSizeOf)
+                             + lazyTypeObjects.sizeOfExcludingThis(mallocSizeOf);
+    *crossCompartmentWrappersArg = crossCompartmentWrappers.sizeOfExcludingThis(mallocSizeOf);
+    *regexpCompartment = regExps.sizeOfExcludingThis(mallocSizeOf);
+    *debuggeesSet = debuggees.sizeOfExcludingThis(mallocSizeOf);
 }
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -273,19 +273,25 @@ struct JSCompartment
     bool                         active;  // GC flag, whether there are active frames
     js::WrapperMap               crossCompartmentWrappers;
 
     /* Last time at which an animation was played for a global in this compartment. */
     int64_t                      lastAnimationTime;
 
     js::RegExpCompartment        regExps;
 
-    size_t sizeOfShapeTable(JSMallocSizeOfFun mallocSizeOf);
+  private:
     void sizeOfTypeInferenceData(JS::TypeInferenceSizes *stats, JSMallocSizeOfFun mallocSizeOf);
 
+  public:
+    void sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *compartmentObject,
+                             JS::TypeInferenceSizes *tiSizes,
+                             size_t *shapesCompartmentTables, size_t *crossCompartmentWrappers,
+                             size_t *regexpCompartment, size_t *debuggeesSet);
+
     /*
      * Shared scope property tree, and arena-pool for allocating its nodes.
      */
     js::PropertyTree             propertyTree;
 
     /* Set of all unowned base shapes in the compartment. */
     js::BaseShapeSet             baseShapes;
     void sweepBaseShapeTable();
--- a/js/src/jsmemorymetrics.cpp
+++ b/js/src/jsmemorymetrics.cpp
@@ -76,21 +76,24 @@ StatsCompartmentCallback(JSRuntime *rt, 
     RuntimeStats *rtStats = static_cast<IteratorClosure *>(data)->rtStats;
 
     // CollectRuntimeStats reserves enough space.
     MOZ_ALWAYS_TRUE(rtStats->compartmentStatsVector.growBy(1));
     CompartmentStats &cStats = rtStats->compartmentStatsVector.back();
     rtStats->initExtraCompartmentStats(compartment, &cStats);
     rtStats->currCompartmentStats = &cStats;
 
-    // Get the compartment-level numbers.
-    compartment->sizeOfTypeInferenceData(&cStats.typeInferenceSizes, rtStats->mallocSizeOf);
-    cStats.shapesCompartmentTables = compartment->sizeOfShapeTable(rtStats->mallocSizeOf);
-    cStats.crossCompartmentWrappers =
-        compartment->crossCompartmentWrappers.sizeOfExcludingThis(rtStats->mallocSizeOf);
+    // Measure the compartment object itself, and things hanging off it.
+    compartment->sizeOfIncludingThis(rtStats->mallocSizeOf,
+                                     &cStats.compartmentObject,
+                                     &cStats.typeInferenceSizes,
+                                     &cStats.shapesCompartmentTables,
+                                     &cStats.crossCompartmentWrappers,
+                                     &cStats.regexpCompartment,
+                                     &cStats.debuggeesSet);
 }
 
 static void
 StatsChunkCallback(JSRuntime *rt, void *data, gc::Chunk *chunk)
 {
     RuntimeStats *rtStats = static_cast<RuntimeStats *>(data);
     for (size_t i = 0; i < gc::ArenasPerChunk; i++)
         if (chunk->decommittedArenas.get(i))
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -612,16 +612,22 @@ RegExpCompartment::get(JSContext *cx, JS
 {
     RegExpFlag flags = RegExpFlag(0);
     if (opt && !ParseRegExpFlags(cx, opt, &flags))
         return false;
 
     return get(cx, atom, flags, g);
 }
 
+size_t
+RegExpCompartment::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf)
+{
+    return map_.sizeOfExcludingThis(mallocSizeOf);
+}
+
 /* Functions */
 
 JSObject *
 js::CloneRegExpObject(JSContext *cx, JSObject *obj_, JSObject *proto_)
 {
     RegExpObjectBuilder builder(cx);
     Rooted<RegExpObject*> regex(cx, &obj_->asRegExp());
     Rooted<RegExpObject*> proto(cx, &proto_->asRegExp());
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -285,16 +285,18 @@ class RegExpCompartment
                  RegExpGuard *g);
 
     /*
      * To avoid atomizing 'hackedSource', callers may call 'lookupHack',
      * passing only the original 'source'. Due to the abovementioned unique
      * mapping property, 'hackedSource' is unambiguous.
      */
     bool lookupHack(JSAtom *source, RegExpFlag flags, JSContext *cx, RegExpGuard *g);
+
+    size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf);
 };
 
 class RegExpObject : public JSObject
 {
     typedef detail::RegExpCode RegExpCode;
 
     static const unsigned LAST_INDEX_SLOT          = 0;
     static const unsigned SOURCE_SLOT              = 1;
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1610,20 +1610,32 @@ ReportCompartmentStats(const JS::Compart
                   "Memory used by the JaegerMonkey JIT for compilation data: "
                   "JITScripts, native maps, and inline cache structs.");
 
     CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("ion-data"),
                   cStats.ionData,
                   "Memory used by the IonMonkey JIT for compilation data: "
                   "IonScripts.");
 
+    CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("compartment-object"),
+                  cStats.compartmentObject,
+                  "Memory used for the JSCompartment object itself.");
+
     CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("cross-compartment-wrappers"),
                   cStats.crossCompartmentWrappers,
                   "Memory used by cross-compartment wrappers.");
 
+    CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("regexp-compartment"),
+                  cStats.regexpCompartment,
+                  "Memory used by the regexp compartment.");
+
+    CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("debuggees-set"),
+                  cStats.debuggeesSet,
+                  "Memory used by the debuggees set.");
+
     CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/script-main"),
                   cStats.typeInferenceSizes.scripts,
                   "Memory used during type inference to store type sets of "
                   "variables and dynamically observed types.");
 
     CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/object-main"),
                   cStats.typeInferenceSizes.objects,
                   "Memory used during type inference to store types and "
@@ -1752,22 +1764,16 @@ ReportJSRuntimeExplicitTreeStats(const J
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/script-filenames"),
                   nsIMemoryReporter::KIND_HEAP, rtStats.runtime.scriptFilenames,
                   "Memory used for the table holding script filenames.");
 
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/script-sources"),
                   nsIMemoryReporter::KIND_HEAP, rtStats.runtime.scriptSources,
                   "Memory use for storing JavaScript source code.");
 
-    RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/compartment-objects"),
-                  nsIMemoryReporter::KIND_HEAP, rtStats.runtime.compartmentObjects,
-                  "Memory used for JSCompartment objects.  These are fairly "
-                  "small and all the same size, so they're not worth reporting "
-                  "on a per-compartment basis.");
-
     if (rtTotalOut) {
         *rtTotalOut = rtTotal;
     }
 
     // Report GC numbers that don't belong to a compartment.
 
     REPORT_GC_BYTES(rtPath + NS_LITERAL_CSTRING("gc-heap/unused-arenas"),
                     rtStats.gcHeapUnusedArenas,