Bug 789398 - Rework the type inference memory reporters. r=bhackett.
authorNicholas Nethercote <nnethercote@mozilla.com>
Sun, 18 Nov 2012 14:40:01 -0800
changeset 113649 e10975ff4a070889dc8ed763de51f2f94ef6bbd5
parent 113648 4fddb9923ef08fbd94ed76c950f49eb6125ff9ec
child 113650 3d6eb774184a64a83ca682a98f8d9cc2081ee86b
push id18282
push usernnethercote@mozilla.com
push dateMon, 19 Nov 2012 00:45:53 +0000
treeherdermozilla-inbound@e10975ff4a07 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs789398
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 789398 - Rework the type inference memory reporters. r=bhackett.
js/public/MemoryMetrics.h
js/src/jsinfer.cpp
js/src/jsinfer.h
js/xpconnect/src/XPCJSRuntime.cpp
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -33,32 +33,47 @@ JS_FRIEND_API(size_t) MemoryReportingSun
 } // namespace js
 
 namespace JS {
 
 // Data for tracking analysis/inference memory usage.
 struct TypeInferenceSizes
 {
     TypeInferenceSizes()
-      : scripts(0)
-      , objects(0)
-      , tables(0)
-      , temporary(0)
+      : typeScripts(0)
+      , typeResults(0)
+      , analysisPool(0)
+      , typePool(0)
+      , pendingArrays(0)
+      , allocationSiteTables(0)
+      , arrayTypeTables(0)
+      , objectTypeTables(0)
+      , typeObjects(0)
     {}
 
-    size_t scripts;
-    size_t objects;
-    size_t tables;
-    size_t temporary;
+    size_t typeScripts;
+    size_t typeResults;
+    size_t analysisPool;
+    size_t typePool;
+    size_t pendingArrays;
+    size_t allocationSiteTables;
+    size_t arrayTypeTables;
+    size_t objectTypeTables;
+    size_t typeObjects;
 
     void add(TypeInferenceSizes &sizes) {
-        this->scripts   += sizes.scripts;
-        this->objects   += sizes.objects;
-        this->tables    += sizes.tables;
-        this->temporary += sizes.temporary;
+        this->typeScripts          += sizes.typeScripts;
+        this->typeResults          += sizes.typeResults;
+        this->analysisPool         += sizes.analysisPool;
+        this->typePool             += sizes.typePool;
+        this->pendingArrays        += sizes.pendingArrays;
+        this->allocationSiteTables += sizes.allocationSiteTables;
+        this->arrayTypeTables      += sizes.arrayTypeTables;
+        this->objectTypeTables     += sizes.objectTypeTables;
+        this->typeObjects          += sizes.typeObjects;
     }
 };
 
 // Holds data about a huge string (one which uses more HugeStringInfo::MinSize
 // bytes of memory), so we can report it individually.
 struct HugeStringInfo
 {
     HugeStringInfo()
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -6403,127 +6403,72 @@ TypeCompartment::maybePurgeAnalysis(JSCo
             cx->clearPendingException();
             return;
         }
 
         cx->runtime->analysisPurgeCallback(cx->runtime, &desc->asFlat());
     }
 }
 
-inline size_t
-TypeSet::computedSizeOfExcludingThis()
-{
-    /*
-     * This memory is allocated within the temp pool (but accounted for
-     * elsewhere) so we can't use a JSMallocSizeOfFun to measure it.  We must
-     * compute its size analytically.
-     */
-    uint32_t count = baseObjectCount();
-    if (count >= 2)
-        return HashSetCapacity(count) * sizeof(TypeObject *);
-    return 0;
-}
-
-inline size_t
-TypeObject::computedSizeOfExcludingThis()
-{
-    /*
-     * This memory is allocated within the temp pool (but accounted for
-     * elsewhere) so we can't use a JSMallocSizeOfFun to measure it.  We must
-     * compute its size analytically.
-     */
-    size_t bytes = 0;
-
-    uint32_t count = basePropertyCount();
-    if (count >= 2)
-        bytes += HashSetCapacity(count) * sizeof(TypeObject *);
-
-    count = getPropertyCount();
-    for (unsigned i = 0; i < count; i++) {
-        Property *prop = getProperty(i);
-        if (prop)
-            bytes += sizeof(Property) + prop->types.computedSizeOfExcludingThis();
-    }
-
-    return bytes;
-}
-
 static void
 SizeOfScriptTypeInferenceData(RawScript script, TypeInferenceSizes *sizes,
                               JSMallocSizeOfFun mallocSizeOf)
 {
     TypeScript *typeScript = script->types;
     if (!typeScript)
         return;
 
     /* If TI is disabled, a single TypeScript is still present. */
     if (!script->compartment()->types.inferenceEnabled) {
-        sizes->scripts += mallocSizeOf(typeScript);
+        sizes->typeScripts += mallocSizeOf(typeScript);
         return;
     }
 
-    unsigned count = TypeScript::NumTypeSets(script);
-    sizes->scripts += mallocSizeOf(typeScript);
+    sizes->typeScripts += mallocSizeOf(typeScript);
 
     TypeResult *result = typeScript->dynamicList;
     while (result) {
-        sizes->scripts += mallocSizeOf(result);
+        sizes->typeResults += mallocSizeOf(result);
         result = result->next;
     }
-
-    /*
-     * This counts memory that is in the temp pool but gets attributed
-     * elsewhere.  See JS::SizeOfCompartmentTypeInferenceData for more details.
-     */
-    TypeSet *typeArray = typeScript->typeArray();
-    for (unsigned i = 0; i < count; i++) {
-        size_t bytes = typeArray[i].computedSizeOfExcludingThis();
-        sizes->scripts += bytes;
-        sizes->temporary -= bytes;
-    }
 }
 
 void
 JSCompartment::sizeOfTypeInferenceData(TypeInferenceSizes *sizes, JSMallocSizeOfFun mallocSizeOf)
 {
-    /*
-     * Note: not all data in the pool is temporary, and some will survive GCs
-     * by being copied to the replacement pool. This memory will be counted
-     * elsewhere and deducted from the amount of temporary data.
-     */
-    sizes->temporary += analysisLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
-    sizes->temporary += typeLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
+    sizes->analysisPool += analysisLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
+    sizes->typePool += typeLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
 
     /* Pending arrays are cleared on GC along with the analysis pool. */
-    sizes->temporary += mallocSizeOf(types.pendingArray);
+    sizes->pendingArrays += mallocSizeOf(types.pendingArray);
 
     /* TypeCompartment::pendingRecompiles is non-NULL only while inference code is running. */
     JS_ASSERT(!types.pendingRecompiles);
 
     for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next())
         SizeOfScriptTypeInferenceData(i.get<JSScript>(), sizes, mallocSizeOf);
 
     if (types.allocationSiteTable)
-        sizes->tables += types.allocationSiteTable->sizeOfIncludingThis(mallocSizeOf);
+        sizes->allocationSiteTables += types.allocationSiteTable->sizeOfIncludingThis(mallocSizeOf);
 
     if (types.arrayTypeTable)
-        sizes->tables += types.arrayTypeTable->sizeOfIncludingThis(mallocSizeOf);
+        sizes->arrayTypeTables += types.arrayTypeTable->sizeOfIncludingThis(mallocSizeOf);
 
     if (types.objectTypeTable) {
-        sizes->tables += types.objectTypeTable->sizeOfIncludingThis(mallocSizeOf);
+        sizes->objectTypeTables += types.objectTypeTable->sizeOfIncludingThis(mallocSizeOf);
 
         for (ObjectTypeTable::Enum e(*types.objectTypeTable);
              !e.empty();
              e.popFront())
         {
             const ObjectTableKey &key = e.front().key;
             const ObjectTableEntry &value = e.front().value;
 
             /* key.ids and values.types have the same length. */
-            sizes->tables += mallocSizeOf(key.ids) + mallocSizeOf(value.types);
+            sizes->objectTypeTables += mallocSizeOf(key.ids) + mallocSizeOf(value.types);
         }
     }
 }
 
 void
 TypeObject::sizeOfExcludingThis(TypeInferenceSizes *sizes, JSMallocSizeOfFun mallocSizeOf)
 {
     if (singleton) {
@@ -6531,18 +6476,10 @@ TypeObject::sizeOfExcludingThis(TypeInfe
          * Properties and associated type sets for singletons are cleared on
          * every GC. The type object is normally destroyed too, but we don't
          * charge this to 'temporary' as this is not for GC heap values.
          */
         JS_ASSERT(!newScript);
         return;
     }
 
-    sizes->objects += mallocSizeOf(newScript);
-
-    /*
-     * This counts memory that is in the temp pool but gets attributed
-     * elsewhere.  See JSCompartment::sizeOfTypeInferenceData for more details.
-     */
-    size_t bytes = computedSizeOfExcludingThis();
-    sizes->objects += bytes;
-    sizes->temporary -= bytes;
-}
+    sizes->typeObjects += mallocSizeOf(newScript);
+}
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -437,17 +437,16 @@ class TypeSet
 
     TypeSet()
         : flags(0), objectSet(NULL), constraintList(NULL)
     {}
 
     void print();
 
     inline void sweep(JSCompartment *compartment);
-    inline size_t computedSizeOfExcludingThis();
 
     /* Whether this set contains a specific type. */
     inline bool hasType(Type type);
 
     TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; }
     bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); }
     bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); }
 
@@ -1020,18 +1019,16 @@ struct TypeObject : gc::Cell
     void clearNewScript(JSContext *cx);
     void getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force = false);
 
     void print();
 
     inline void clearProperties();
     inline void sweep(FreeOp *fop);
 
-    inline size_t computedSizeOfExcludingThis();
-
     void sizeOfExcludingThis(TypeInferenceSizes *sizes, JSMallocSizeOfFun mallocSizeOf);
 
     /*
      * Type objects don't have explicit finalizers. Memory owned by a type
      * object pending deletion is released when weak references are sweeped
      * from all the compartment's type objects.
      */
     void finalize(FreeOp *fop) {}
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1639,35 +1639,53 @@ ReportCompartmentStats(const JS::Compart
     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 "
-                  "possible property types of JS objects.");
-
-    CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/tables"),
-                  cStats.typeInferenceSizes.tables,
-                  "Memory used during type inference for compartment-wide "
-                  "tables.");
-
-    CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("analysis-temporary"),
-                  cStats.typeInferenceSizes.temporary,
-                  "Memory used during type inference and compilation to hold "
-                  "transient analysis information.  Cleared on GC.");
+    CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/type-scripts"),
+                  cStats.typeInferenceSizes.typeScripts,
+                  "Memory used by type sets associated with scripts.");
+
+    CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/type-results"),
+                  cStats.typeInferenceSizes.typeResults,
+                  "Memory used by dynamic type results produced by scripts.");
+
+    CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/analysis-pool"),
+                  cStats.typeInferenceSizes.analysisPool,
+                  "Memory holding transient analysis information used during type inference and "
+                  "compilation.");
+
+    CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/type-pool"),
+                  cStats.typeInferenceSizes.typePool,
+                  "Memory holding contents of type sets and related data.");
+
+    CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/pending-arrays"),
+                  cStats.typeInferenceSizes.pendingArrays,
+                  "Memory used for solving constraints during type inference.");
+
+    CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/allocation-site-tables"),
+                  cStats.typeInferenceSizes.allocationSiteTables,
+                  "Memory indexing type objects associated with allocation sites.");
+
+    CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/array-type-tables"),
+                  cStats.typeInferenceSizes.arrayTypeTables,
+                  "Memory indexing type objects associated with array literals.");
+
+    CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/object-type-tables"),
+                  cStats.typeInferenceSizes.objectTypeTables,
+                  "Memory indexing type objects associated with object literals.");
+
+    CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/type-objects"),
+                  cStats.typeInferenceSizes.typeObjects,
+                  "Memory holding miscellaneous additional information associated with type "
+                  "objects.");
 
     CREPORT_BYTES2(cJSPathPrefix + NS_LITERAL_CSTRING("string-chars/non-huge"),
                    cStats.stringCharsNonHuge, nsPrintfCString(
                    "Memory allocated to hold characters of strings whose "
                    "characters take up less than than %d bytes of memory.\n\n"
                    "Sometimes more memory is allocated than necessary, to "
                    "simplify string concatenation.  Each string also includes a "
                    "header which is stored on the compartment's JavaScript heap; "