Bug 805915 (part 4) - Add more detail to string memory reports. r=luke.
authorNicholas Nethercote <nnethercote@mozilla.com>
Mon, 29 Oct 2012 08:51:21 +1100
changeset 111778 b23881c4de78e3e751fc932139789420c74c03da
parent 111777 aa23bf4b9a20f172de10ba2a3bfd592266ab9167
child 111779 7d95543f47506a5975dfb42cedb1ff20cb51ce91
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersluke
bugs805915
milestone19.0a1
Bug 805915 (part 4) - Add more detail to string memory reports. r=luke.
js/public/MemoryMetrics.h
js/src/jsmemorymetrics.cpp
js/src/vm/String.cpp
js/src/vm/String.h
js/xpconnect/src/XPCJSRuntime.cpp
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -129,31 +129,32 @@ struct CompartmentStats
       , extra2(0)
       , gcHeapArenaAdmin(0)
       , gcHeapUnusedGcThings(0)
       , gcHeapObjectsOrdinary(0)
       , gcHeapObjectsFunction(0)
       , gcHeapObjectsDenseArray(0)
       , gcHeapObjectsSlowArray(0)
       , gcHeapObjectsCrossCompartmentWrapper(0)
-      , gcHeapStrings(0)
+      , gcHeapStringsNormal(0)
+      , gcHeapStringsShort(0)
       , gcHeapShapesTree(0)
       , gcHeapShapesDict(0)
       , gcHeapShapesBase(0)
       , gcHeapScripts(0)
       , gcHeapTypeObjects(0)
       , gcHeapIonCodes(0)
 #if JS_HAS_XML_SUPPORT
       , gcHeapXML(0)
 #endif
       , objectSlots(0)
       , objectElements(0)
       , objectMisc(0)
       , objectPrivate(0)
-      , nonHugeStringChars(0)
+      , stringCharsNonHuge(0)
       , shapesExtraTreeTables(0)
       , shapesExtraDictTables(0)
       , shapesExtraTreeShapeKids(0)
       , shapesCompartmentTables(0)
       , scriptData(0)
       , jaegerData(0)
       , ionData(0)
       , compartmentObject(0)
@@ -167,31 +168,32 @@ struct CompartmentStats
       , extra2(other.extra2)
       , gcHeapArenaAdmin(other.gcHeapArenaAdmin)
       , gcHeapUnusedGcThings(other.gcHeapUnusedGcThings)
       , gcHeapObjectsOrdinary(other.gcHeapObjectsOrdinary)
       , gcHeapObjectsFunction(other.gcHeapObjectsFunction)
       , gcHeapObjectsDenseArray(other.gcHeapObjectsDenseArray)
       , gcHeapObjectsSlowArray(other.gcHeapObjectsSlowArray)
       , gcHeapObjectsCrossCompartmentWrapper(other.gcHeapObjectsCrossCompartmentWrapper)
-      , gcHeapStrings(other.gcHeapStrings)
+      , gcHeapStringsNormal(other.gcHeapStringsNormal)
+      , gcHeapStringsShort(other.gcHeapStringsShort)
       , gcHeapShapesTree(other.gcHeapShapesTree)
       , gcHeapShapesDict(other.gcHeapShapesDict)
       , gcHeapShapesBase(other.gcHeapShapesBase)
       , gcHeapScripts(other.gcHeapScripts)
       , gcHeapTypeObjects(other.gcHeapTypeObjects)
       , gcHeapIonCodes(other.gcHeapIonCodes)
 #if JS_HAS_XML_SUPPORT
       , gcHeapXML(other.gcHeapXML)
 #endif
       , objectSlots(other.objectSlots)
       , objectElements(other.objectElements)
       , objectMisc(other.objectMisc)
       , objectPrivate(other.objectPrivate)
-      , nonHugeStringChars(other.nonHugeStringChars)
+      , stringCharsNonHuge(other.stringCharsNonHuge)
       , shapesExtraTreeTables(other.shapesExtraTreeTables)
       , shapesExtraDictTables(other.shapesExtraDictTables)
       , shapesExtraTreeShapeKids(other.shapesExtraTreeShapeKids)
       , shapesCompartmentTables(other.shapesCompartmentTables)
       , scriptData(other.scriptData)
       , jaegerData(other.jaegerData)
       , ionData(other.ionData)
       , compartmentObject(other.compartmentObject)
@@ -212,32 +214,33 @@ struct CompartmentStats
     size_t gcHeapArenaAdmin;
     size_t gcHeapUnusedGcThings;
 
     size_t gcHeapObjectsOrdinary;
     size_t gcHeapObjectsFunction;
     size_t gcHeapObjectsDenseArray;
     size_t gcHeapObjectsSlowArray;
     size_t gcHeapObjectsCrossCompartmentWrapper;
-    size_t gcHeapStrings;
+    size_t gcHeapStringsNormal;
+    size_t gcHeapStringsShort;
     size_t gcHeapShapesTree;
     size_t gcHeapShapesDict;
     size_t gcHeapShapesBase;
     size_t gcHeapScripts;
     size_t gcHeapTypeObjects;
     size_t gcHeapIonCodes;
 #if JS_HAS_XML_SUPPORT
     size_t gcHeapXML;
 #endif
 
     size_t objectSlots;
     size_t objectElements;
     size_t objectMisc;
     size_t objectPrivate;
-    size_t nonHugeStringChars;
+    size_t stringCharsNonHuge;
     size_t shapesExtraTreeTables;
     size_t shapesExtraDictTables;
     size_t shapesExtraTreeShapeKids;
     size_t shapesCompartmentTables;
     size_t scriptData;
     size_t jaegerData;
     size_t ionData;
     size_t compartmentObject;
@@ -256,32 +259,33 @@ struct CompartmentStats
         ADD(gcHeapArenaAdmin);
         ADD(gcHeapUnusedGcThings);
 
         ADD(gcHeapObjectsOrdinary);
         ADD(gcHeapObjectsFunction);
         ADD(gcHeapObjectsDenseArray);
         ADD(gcHeapObjectsSlowArray);
         ADD(gcHeapObjectsCrossCompartmentWrapper);
-        ADD(gcHeapStrings);
+        ADD(gcHeapStringsNormal);
+        ADD(gcHeapStringsShort);
         ADD(gcHeapShapesTree);
         ADD(gcHeapShapesDict);
         ADD(gcHeapShapesBase);
         ADD(gcHeapScripts);
         ADD(gcHeapTypeObjects);
         ADD(gcHeapIonCodes);
     #if JS_HAS_XML_SUPPORT
         ADD(gcHeapXML);
     #endif
 
         ADD(objectSlots);
         ADD(objectElements);
         ADD(objectMisc);
         ADD(objectPrivate);
-        ADD(nonHugeStringChars);
+        ADD(stringCharsNonHuge);
         ADD(shapesExtraTreeTables);
         ADD(shapesExtraDictTables);
         ADD(shapesExtraTreeShapeKids);
         ADD(shapesCompartmentTables);
         ADD(scriptData);
         ADD(jaegerData);
         ADD(ionData);
         ADD(compartmentObject);
--- a/js/src/jsmemorymetrics.cpp
+++ b/js/src/jsmemorymetrics.cpp
@@ -54,17 +54,18 @@ CompartmentStats::gcHeapThingsSize()
 {
     // These are just the GC-thing measurements.
     size_t n = 0;
     n += gcHeapObjectsOrdinary;
     n += gcHeapObjectsFunction;
     n += gcHeapObjectsDenseArray;
     n += gcHeapObjectsSlowArray;
     n += gcHeapObjectsCrossCompartmentWrapper;
-    n += gcHeapStrings;
+    n += gcHeapStringsNormal;
+    n += gcHeapStringsShort;
     n += gcHeapShapesTree;
     n += gcHeapShapesDict;
     n += gcHeapShapesBase;
     n += gcHeapScripts;
     n += gcHeapTypeObjects;
     n += gcHeapIonCodes;
 #if JS_HAS_XML_SUPPORT
     n += gcHeapXML;
@@ -168,29 +169,33 @@ StatsCellCallback(JSRuntime *rt, void *d
                 cStats->objectPrivate += opv->sizeOfIncludingThis(GetObjectPrivate(obj));
             }
         }
         break;
     }
     case JSTRACE_STRING:
     {
         JSString *str = static_cast<JSString *>(thing);
-        cStats->gcHeapStrings += thingSize;
 
         size_t strSize = str->sizeOfExcludingThis(rtStats->mallocSizeOf);
 
         // If we can't grow hugeStrings, let's just call this string non-huge.
         // We're probably about to OOM anyway.
         if (strSize >= HugeStringInfo::MinSize() && cStats->hugeStrings.growBy(1)) {
+            cStats->gcHeapStringsNormal += thingSize;
             HugeStringInfo &info = cStats->hugeStrings.back();
             info.length = str->length();
-            info.size = str->sizeOfExcludingThis(rtStats->mallocSizeOf);
+            info.size = strSize;
             PutEscapedString(info.buffer, sizeof(info.buffer), &str->asLinear(), 0);
+        } else if (str->isShort()) {
+            MOZ_ASSERT(strSize == 0);
+            cStats->gcHeapStringsShort += thingSize;
         } else {
-          cStats->nonHugeStringChars += strSize;
+            cStats->gcHeapStringsNormal += thingSize;
+            cStats->stringCharsNonHuge += strSize;
         }
         break;
     }
     case JSTRACE_SHAPE:
     {
         Shape *shape = static_cast<Shape*>(thing);
         size_t propTableSize, kidsSize;
         shape->sizeOfExcludingThis(rtStats->mallocSizeOf, &propTableSize, &kidsSize);
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -12,28 +12,26 @@
 #include "String.h"
 #include "String-inl.h"
 
 #include "jsobjinlines.h"
 
 using namespace mozilla;
 using namespace js;
 
-#ifdef DEBUG
 bool
 JSString::isShort() const
 {
     // It's possible for short strings to be converted to flat strings;  as a
     // result, checking just for the arena isn't enough to determine if a
     // string is short.  Hence the isInline() check.
     bool is_short = (getAllocKind() == gc::FINALIZE_SHORT_STRING) && isInline();
     JS_ASSERT_IF(is_short, isFlat());
     return is_short;
 }
-#endif
 
 bool
 JSString::isExternal() const
 {
     bool is_external = (getAllocKind() == gc::FINALIZE_EXTERNAL_STRING);
     JS_ASSERT_IF(is_external, isFlat());
     return is_external;
 }
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -343,16 +343,18 @@ class JSString : public js::gc::Cell
     }
 
     JS_ALWAYS_INLINE
     JSInlineString &asInline() const {
         JS_ASSERT(isInline());
         return *(JSInlineString *)this;
     }
 
+    bool isShort() const;
+
     JS_ALWAYS_INLINE
     JSStableString &asStable() const {
         JS_ASSERT(!isInline());
         return *(JSStableString *)this;
     }
 
     /* For hot code, prefer other type queries. */
     bool isExternal() const;
@@ -411,17 +413,16 @@ class JSString : public js::gc::Cell
     static inline void writeBarrierPre(JSString *str);
     static inline void writeBarrierPost(JSString *str, void *addr);
     static inline bool needWriteBarrierPre(JSCompartment *comp);
     static inline void readBarrier(JSString *str);
 
     static inline js::ThingRootKind rootKind() { return js::THING_ROOT_STRING; }
 
 #ifdef DEBUG
-    bool isShort() const;
     void dump();
     static void dumpChars(const jschar *s, size_t len);
     bool equals(const char *s);
 #endif
 
   private:
     JSString() MOZ_DELETE;
     JSString(const JSString &other) MOZ_DELETE;
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1492,25 +1492,31 @@ ReportCompartmentStats(const JS::Compart
                      "Memory on the garbage-collected JavaScript "
                      "heap that holds slow array objects.");
 
     CREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("gc-heap/objects/cross-compartment-wrapper"),
                      cStats.gcHeapObjectsCrossCompartmentWrapper,
                      "Memory on the garbage-collected JavaScript "
                      "heap that holds cross-compartment wrapper objects.");
 
-    CREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("gc-heap/strings"),
-                     cStats.gcHeapStrings,
+    CREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("gc-heap/strings/normal"),
+                     cStats.gcHeapStringsNormal,
                      "Memory on the garbage-collected JavaScript "
-                     "heap that holds string headers.  String headers contain "
+                     "heap that holds normal string headers.  String headers contain "
                      "various pieces of information about a string, but do not "
                      "contain (except in the case of very short strings) the "
                      "string characters;  characters in longer strings are "
                      "counted under 'gc-heap/string-chars' instead.");
 
+    CREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("gc-heap/strings/short"),
+                     cStats.gcHeapStringsShort,
+                     "Memory on the garbage-collected JavaScript "
+                     "heap that holds over-sized string headers, in which "
+                     "string characters are stored inline.");
+
     CREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("gc-heap/scripts"),
                      cStats.gcHeapScripts,
                      "Memory on the garbage-collected JavaScript "
                      "heap that holds JSScript instances. A JSScript is "
                      "created for each user-defined function in a script. One "
                      "is also created for the top-level code in a script.");
 
     CREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("gc-heap/shapes/tree"),
@@ -1640,17 +1646,17 @@ ReportCompartmentStats(const JS::Compart
                   "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_BYTES2(cJSPathPrefix + NS_LITERAL_CSTRING("string-chars/non-huge"),
-                   cStats.nonHugeStringChars, nsPrintfCString(
+                   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; "
                    "that header is not counted here, but in 'gc-heap/strings' "
                    "instead.",
                    JS::HugeStringInfo::MinSize()));