Bug 799019 - Tweak per-compartment memory reporting. r=Ms2ger.
authorNicholas Nethercote <nnethercote@mozilla.com>
Mon, 08 Oct 2012 15:20:26 -0700
changeset 117641 2494d51c3dc56de69d48cffc3f23f8830ea8336f
parent 117640 3cfef9371c037d98dadff8cf762701839f15054e
child 117642 14684be8116624897f620ede591c58723a172919
push id1997
push userakeybl@mozilla.com
push dateMon, 07 Jan 2013 21:25:26 +0000
treeherdermozilla-beta@4baf45cdcf21 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMs2ger
bugs799019
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 799019 - Tweak per-compartment memory reporting. r=Ms2ger.
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)
       , stackCommitted(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 stackCommitted;
     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()
 {
     if (!execAlloc_)
         return 0;
 
--- 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 "
@@ -1748,22 +1760,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,