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 111646 b23881c4de78e3e751fc932139789420c74c03da
parent 111645 aa23bf4b9a20f172de10ba2a3bfd592266ab9167
child 111647 7d95543f47506a5975dfb42cedb1ff20cb51ce91
push id23765
push userphilringnalda@gmail.com
push dateMon, 29 Oct 2012 20:48:54 +0000
treeherdermozilla-central@f677f91c89c0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs805915
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 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()));