Bug 712835 (part 2 of 3) - Add a memory reporter for the nsAtomTable. r=khuey.
authorNicholas Nethercote <nnethercote@mozilla.com>
Thu, 22 Dec 2011 17:24:43 -0800
changeset 84648 4b655c46d0713d8edb1e9946da037698a5572cbb
parent 84647 365161a949b534aa978c0e836242d91adcece440
child 84649 fa8de405cc873ef1f68fa0e2ded9b21ce544ec8f
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs712835
milestone12.0a1
Bug 712835 (part 2 of 3) - Add a memory reporter for the nsAtomTable. r=khuey.
xpcom/base/Makefile.in
xpcom/base/nsMemoryReporterManager.cpp
xpcom/ds/nsAtomTable.cpp
xpcom/ds/nsAtomTable.h
--- a/xpcom/base/Makefile.in
+++ b/xpcom/base/Makefile.in
@@ -166,9 +166,12 @@ include $(topsrcdir)/ipc/chromium/chromi
 include $(topsrcdir)/config/rules.mk
 
 DEFINES		+= -D_IMPL_NS_COM
 
 ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
 CXXFLAGS        += $(MOZ_GTK2_CFLAGS)
 endif
 
-LOCAL_INCLUDES += -I$(srcdir)/../build
+LOCAL_INCLUDES += \
+		-I$(srcdir)/../build \
+		-I$(topsrcdir)/xpcom/ds \
+		$(NULL)
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -32,16 +32,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "nsAtomTable.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsServiceManagerUtils.h"
 #include "nsMemoryReporterManager.h"
 #include "nsArrayEnumerator.h"
 #include "nsISimpleEnumerator.h"
 #include "mozilla/Telemetry.h"
 
@@ -491,16 +492,34 @@ NS_MEMORY_REPORTER_IMPLEMENT(HeapAllocat
     KIND_OTHER,
     UNITS_BYTES,
     GetHeapAllocated,
     "Memory mapped by the heap allocator that is currently allocated to the "
     "application.  This may exceed the amount of memory requested by the "
     "application because the allocator regularly rounds up request sizes. (The "
     "exact amount requested is not recorded.)")
 
+NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(AtomTableMallocSizeOf, "atom-table")
+
+static PRInt64 GetAtomTableSize() {
+  return NS_SizeOfAtomTableIncludingThis(AtomTableMallocSizeOf);
+}
+
+// Why is this here?  At first glance, you'd think it could be defined and
+// registered with nsMemoryReporterManager entirely within nsAtomTable.cpp.
+// However, the obvious time to register it is when the table is initialized,
+// and that happens before XPCOM components are initialized, which means the
+// NS_RegisterMemoryReporter call fails.  So instead we do it here.
+NS_MEMORY_REPORTER_IMPLEMENT(AtomTable,
+    "explicit/atom-table",
+    KIND_HEAP,
+    UNITS_BYTES,
+    GetAtomTableSize,
+    "Memory used by the atoms table.")
+
 /**
  ** nsMemoryReporterManager implementation
  **/
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsMemoryReporterManager, nsIMemoryReporterManager)
 
 NS_IMETHODIMP
 nsMemoryReporterManager::Init()
@@ -533,16 +552,18 @@ nsMemoryReporterManager::Init()
     REGISTER(HeapCommitted);
     REGISTER(HeapCommittedFragmentation);
     REGISTER(HeapDirty);
 #elif defined(XP_MACOSX) && !defined(MOZ_MEMORY)
     REGISTER(HeapZone0Committed);
     REGISTER(HeapZone0Used);
 #endif
 
+    REGISTER(AtomTable);
+
     return NS_OK;
 }
 
 nsMemoryReporterManager::nsMemoryReporterManager()
   : mMutex("nsMemoryReporterManager::mMutex")
 {
 }
 
--- a/xpcom/ds/nsAtomTable.cpp
+++ b/xpcom/ds/nsAtomTable.cpp
@@ -364,47 +364,80 @@ AtomImpl::ScriptableEquals(const nsAStri
 }
 
 NS_IMETHODIMP_(bool)
 AtomImpl::IsStaticAtom()
 {
   return IsPermanent();
 }
 
+size_t
+AtomImpl::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  return aMallocSizeOf(this, sizeof(AtomImpl)) +
+         nsStringBuffer::FromData(mString)->
+           SizeOfIncludingThisIfUnshared(aMallocSizeOf);
+}
+
 //----------------------------------------------------------------------
 
+static size_t
+SizeOfAtomTableEntryExcludingThis(PLDHashEntryHdr *aHdr,
+                                  nsMallocSizeOfFun aMallocSizeOf,
+                                  void *aArg)
+{
+  AtomTableEntry* entry = static_cast<AtomTableEntry*>(aHdr);
+  return entry->mAtom->SizeOfIncludingThis(aMallocSizeOf);
+}
+
+size_t NS_SizeOfAtomTableIncludingThis(nsMallocSizeOfFun aMallocSizeOf) {
+  if (gAtomTable.ops) {
+      return PL_DHashTableSizeOfExcludingThis(&gAtomTable,
+                                              SizeOfAtomTableEntryExcludingThis,
+                                              aMallocSizeOf);
+  }
+  return 0;
+}
+
 #define ATOM_HASHTABLE_INITIAL_SIZE  4096
 
+static inline bool
+EnsureTableExists()
+{
+  if (gAtomTable.ops) {
+    return true;
+  }
+  if (PL_DHashTableInit(&gAtomTable, &AtomTableOps, 0,
+                        sizeof(AtomTableEntry), ATOM_HASHTABLE_INITIAL_SIZE)) {
+    return true;
+  }
+  // Initialization failed.
+  gAtomTable.ops = nsnull;
+  return false;
+}
+
 static inline AtomTableEntry*
 GetAtomHashEntry(const char* aString, PRUint32 aLength)
 {
   NS_ASSERTION(NS_IsMainThread(), "wrong thread");
-  if (!gAtomTable.ops &&
-      !PL_DHashTableInit(&gAtomTable, &AtomTableOps, 0,
-                         sizeof(AtomTableEntry), ATOM_HASHTABLE_INITIAL_SIZE)) {
-    gAtomTable.ops = nsnull;
+  if (!EnsureTableExists()) {
     return nsnull;
   }
-
   AtomTableKey key(aString, aLength);
   return static_cast<AtomTableEntry*>
                     (PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_ADD));
 }
 
 static inline AtomTableEntry*
 GetAtomHashEntry(const PRUnichar* aString, PRUint32 aLength)
 {
   NS_ASSERTION(NS_IsMainThread(), "wrong thread");
-  if (!gAtomTable.ops &&
-      !PL_DHashTableInit(&gAtomTable, &AtomTableOps, 0,
-                         sizeof(AtomTableEntry), ATOM_HASHTABLE_INITIAL_SIZE)) {
-    gAtomTable.ops = nsnull;
+  if (!EnsureTableExists()) {
     return nsnull;
   }
-
   AtomTableKey key(aString, aLength);
   return static_cast<AtomTableEntry*>
                     (PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_ADD));
 }
 
 class CheckStaticAtomSizes
 {
   CheckStaticAtomSizes() {
--- a/xpcom/ds/nsAtomTable.h
+++ b/xpcom/ds/nsAtomTable.h
@@ -80,16 +80,18 @@ public:
 
   // We can't use the virtual function in the base class destructor.
   bool IsPermanentInDestructor() {
     return mRefCnt == REFCNT_PERMANENT_SENTINEL;
   }
 
   // for |#ifdef NS_BUILD_REFCNT_LOGGING| access to reference count
   nsrefcnt GetRefCount() { return mRefCnt; }
+
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 };
 
 /**
  * A non-refcounted implementation of nsIAtom.
  */
 
 class PermanentAtomImpl : public AtomImpl {
 public:
@@ -103,19 +105,23 @@ public:
   {}
 
   ~PermanentAtomImpl();
   NS_IMETHOD_(nsrefcnt) AddRef();
   NS_IMETHOD_(nsrefcnt) Release();
 
   virtual bool IsPermanent();
 
+  // SizeOfIncludingThis() isn't needed -- the one inherited from AtomImpl is
+  // good enough, because PermanentAtomImpl doesn't add any new data members.
+
   void* operator new(size_t size, AtomImpl* aAtom) CPP_THROW_NEW;
   void* operator new(size_t size) CPP_THROW_NEW
   {
     return ::operator new(size);
   }
-
 };
 
 void NS_PurgeAtomTable();
 
+size_t NS_SizeOfAtomTableIncludingThis(nsMallocSizeOfFun aMallocSizeOf);
+
 #endif // nsAtomTable_h__