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 85865 4b655c46d0713d8edb1e9946da037698a5572cbb
parent 85864 365161a949b534aa978c0e836242d91adcece440
child 85866 fa8de405cc873ef1f68fa0e2ded9b21ce544ec8f
push id674
push userffxbld
push dateTue, 13 Mar 2012 21:17:50 +0000
treeherdermozilla-beta@e3c4c92dec31 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs712835
milestone12.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 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__