Bug 765244 - add a memory reporter for preferences; r=njn
authorNathan Froyd <froydnj@mozilla.com>
Thu, 11 Oct 2012 11:36:21 -0400
changeset 111340 2fe58d68cf8c1f445eb846b23a729d75e4806ece
parent 111339 047148d2783ebac91352e900e1e37c55c162a999
child 111341 f2acc4fa85903e4a70c02047c705ecbb5ef8fc2e
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersnjn
bugs765244
milestone19.0a1
Bug 765244 - add a memory reporter for preferences; r=njn
modules/libpref/public/Preferences.h
modules/libpref/src/Preferences.cpp
modules/libpref/src/nsPrefBranch.h
modules/libpref/src/prefapi.cpp
modules/libpref/src/prefapi_private_data.h
--- a/modules/libpref/public/Preferences.h
+++ b/modules/libpref/public/Preferences.h
@@ -328,16 +328,18 @@ public:
    */
   static int32_t GetDefaultType(const char* aPref);
 
   // Used to synchronise preferences between chrome and content processes.
   static void GetPreferences(InfallibleTArray<PrefSetting>* aPrefs);
   static void GetPreference(PrefSetting* aPref);
   static void SetPreference(const PrefSetting& aPref);
 
+  static int64_t GetPreferencesMemoryUsed();
+
 protected:
   nsresult NotifyServiceObservers(const char *aSubject);
   /**
    * Reads the default pref file or, if that failed, try to save a new one.
    *
    * @return NS_OK if either action succeeded,
    *         or the error code related to the read attempt.
    */
--- a/modules/libpref/src/Preferences.cpp
+++ b/modules/libpref/src/Preferences.cpp
@@ -37,16 +37,17 @@
 #include "prefread.h"
 #include "prefapi_private_data.h"
 
 #include "mozilla/Omnijar.h"
 #include "nsZipArchive.h"
 
 #include "nsTArray.h"
 #include "nsRefPtrHashtable.h"
+#include "nsIMemoryReporter.h"
 
 namespace mozilla {
 
 // Definitions
 #define INITIAL_PREF_FILES 10
 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
 
 // Prototypes
@@ -153,16 +154,66 @@ struct CacheData {
     uint32_t defaultValueUint;
   };
 };
 
 static nsTArray<nsAutoPtr<CacheData> >* gCacheData = nullptr;
 static nsRefPtrHashtable<ValueObserverHashKey,
                          ValueObserver>* gObserverTable = nullptr;
 
+NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(PreferencesMallocSizeOf, "preferences")
+
+static size_t
+SizeOfObserverEntryExcludingThis(ValueObserverHashKey* aKey,
+                                 const nsRefPtr<ValueObserver>& aData,
+                                 nsMallocSizeOfFun aMallocSizeOf,
+                                 void*)
+{
+  size_t n = 0;
+  n += aKey->mPrefName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+  n += aData->mClosures.SizeOfExcludingThis(aMallocSizeOf);
+  return n;
+}
+
+// static
+int64_t
+Preferences::GetPreferencesMemoryUsed()
+{
+  size_t n = 0;
+  n += PreferencesMallocSizeOf(sPreferences);
+  if (gHashTable.ops) {
+    // pref keys are allocated in a private arena, which we count elsewhere.
+    // pref stringvals are allocated out of the same private arena.
+    n += PL_DHashTableSizeOfExcludingThis(&gHashTable, nullptr,
+                                          PreferencesMallocSizeOf);
+  }
+  if (gCacheData) {
+    n += gCacheData->SizeOfIncludingThis(PreferencesMallocSizeOf);
+    for (uint32_t i = 0, count = gCacheData->Length(); i < count; ++i) {
+      n += PreferencesMallocSizeOf((*gCacheData)[i]);
+    }
+  }
+  if (gObserverTable) {
+    n += PreferencesMallocSizeOf(gObserverTable);
+    n += gObserverTable->SizeOfExcludingThis(SizeOfObserverEntryExcludingThis,
+                                             PreferencesMallocSizeOf);
+  }
+  // We don't measure sRootBranch and sDefaultRootBranch here because
+  // DMD indicates they are not significant.
+  n += pref_SizeOfPrivateData(PreferencesMallocSizeOf);
+  return n;
+}
+
+NS_MEMORY_REPORTER_IMPLEMENT(Preferences,
+  "explicit/preferences",
+  KIND_HEAP,
+  UNITS_BYTES,
+  Preferences::GetPreferencesMemoryUsed,
+  "Memory used by the preferences system.")
+
 // static
 Preferences*
 Preferences::GetInstanceForService()
 {
   if (sPreferences) {
     NS_ADDREF(sPreferences);
     return sPreferences;
   }
@@ -183,16 +234,19 @@ Preferences::GetInstanceForService()
     return nullptr;
   }
 
   gCacheData = new nsTArray<nsAutoPtr<CacheData> >();
 
   gObserverTable = new nsRefPtrHashtable<ValueObserverHashKey, ValueObserver>();
   gObserverTable->Init();
 
+  nsCOMPtr<nsIMemoryReporter> reporter(new NS_MEMORY_REPORTER_NAME(Preferences));
+  NS_RegisterMemoryReporter(reporter);
+
   NS_ADDREF(sPreferences);
   return sPreferences;
 }
 
 // static
 bool
 Preferences::InitStaticMembers()
 {
--- a/modules/libpref/src/nsPrefBranch.h
+++ b/modules/libpref/src/nsPrefBranch.h
@@ -182,16 +182,18 @@ public:
   virtual ~nsPrefBranch();
 
   int32_t GetRootLength() { return mPrefRootLength; }
 
   nsresult RemoveObserverFromMap(const char *aDomain, nsISupports *aObserver);
 
   static nsresult NotifyObserver(const char *newpref, void *data);
 
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf);
+
 protected:
   nsPrefBranch()    /* disallow use of this constructer */
     { }
 
   nsresult   GetDefaultFromPropertiesFile(const char *aPrefName, PRUnichar **return_buf);
   void RemoveExpiredCallback(PrefCallback *aCallback);
   const char *getPrefName(const char *aPrefName);
   void       freeObserverList(void);
--- a/modules/libpref/src/prefapi.cpp
+++ b/modules/libpref/src/prefapi.cpp
@@ -801,16 +801,34 @@ nsresult pref_HashPref(const char *key, 
 
         nsresult rv2 = pref_DoCallback(key);
         if (NS_FAILED(rv2))
             rv = rv2;
     }
     return rv;
 }
 
+size_t
+pref_SizeOfPrivateData(nsMallocSizeOfFun aMallocSizeOf)
+{
+    size_t n = 0;
+    // The first PLArena is within the PLArenaPool, so start measuring
+    // malloc'd data with the second arena.
+    const PLArena* arena = gPrefNameArena.first.next;
+    while (arena) {
+        n += aMallocSizeOf(arena);
+        arena = arena->next;
+    }
+    for (struct CallbackNode* node = gCallbacks; node; node = node->next) {
+        n += aMallocSizeOf(node);
+        n += aMallocSizeOf(node->domain);
+    }
+    return n;
+}
+
 PrefType
 PREF_GetPrefType(const char *pref_name)
 {
     if (gHashTable.ops)
     {
         PrefHashEntry* pref = pref_HashTableLookup(pref_name);
         if (pref)
         {
--- a/modules/libpref/src/prefapi_private_data.h
+++ b/modules/libpref/src/prefapi_private_data.h
@@ -32,8 +32,11 @@ pref_GetPrefs(PLDHashTable *table,
 nsresult
 pref_SetPref(const mozilla::dom::PrefSetting& aPref);
 
 int pref_CompareStrings(const void *v1, const void *v2, void* unused);
 PrefHashEntry* pref_HashTableLookup(const void *key);
 
 void pref_GetPrefFromEntry(PrefHashEntry *aHashEntry,
                            mozilla::dom::PrefSetting* aPref);
+
+size_t
+pref_SizeOfPrivateData(nsMallocSizeOfFun aMallocSizeOf);