Bug 697335 - Another memory reporter for the startup cache. r=taras.
authorNicholas Nethercote <nnethercote@mozilla.com>
Sun, 18 Dec 2011 16:20:36 -0800
changeset 84582 692d80735b7e90d94e595b20244891f85e73f7e0
parent 84581 e255fa32719cbe3ff63ce3238ab2b9f601556275
child 84583 38a35f0db9ff1bab21c7de76462fd06e50fa58cd
push idunknown
push userunknown
push dateunknown
reviewerstaras
bugs697335
milestone11.0a1
Bug 697335 - Another memory reporter for the startup cache. r=taras.
startupcache/StartupCache.cpp
startupcache/StartupCache.h
xpcom/glue/nsBaseHashtable.h
--- a/startupcache/StartupCache.cpp
+++ b/startupcache/StartupCache.cpp
@@ -77,34 +77,51 @@
 #endif
 
 #if PR_BYTES_PER_WORD == 4
 #define SC_WORDSIZE "4"
 #else
 #define SC_WORDSIZE "8"
 #endif
 
+namespace mozilla {
+namespace scache {
+
 static PRInt64
-GetStartupCacheSize()
+GetStartupCacheMappingSize()
 {
     mozilla::scache::StartupCache* sc = mozilla::scache::StartupCache::GetSingleton();
     return sc ? sc->SizeOfMapping() : 0;
 }
 
-NS_MEMORY_REPORTER_IMPLEMENT(StartupCache,
-                             "explicit/startup-cache",
+NS_MEMORY_REPORTER_IMPLEMENT(StartupCacheMapping,
+                             "explicit/startup-cache/mapping",
                              KIND_NONHEAP,
                              nsIMemoryReporter::UNITS_BYTES,
-                             GetStartupCacheSize,
-                             "Memory used to hold the startup cache.  This "
-                             "memory is backed by a file and is likely to be "
+                             GetStartupCacheMappingSize,
+                             "Memory used to hold the mapping of the startup "
+                             "cache from file.  This memory is likely to be "
                              "swapped out shortly after start-up.")
 
-namespace mozilla {
-namespace scache {
+NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(StartupCacheDataMallocSizeOf, "startup-cache/data")
+
+static PRInt64
+GetStartupCacheDataSize()
+{
+    mozilla::scache::StartupCache* sc = mozilla::scache::StartupCache::GetSingleton();
+    return sc ? sc->HeapSizeOfIncludingThis(StartupCacheDataMallocSizeOf) : 0;
+}
+
+NS_MEMORY_REPORTER_IMPLEMENT(StartupCacheData,
+                             "explicit/startup-cache/data",
+                             KIND_HEAP,
+                             nsIMemoryReporter::UNITS_BYTES,
+                             GetStartupCacheDataSize,
+                             "Memory used by the startup cache for things "
+                             "other than the file mapping.")
 
 static const char sStartupCacheName[] = "startupCache." SC_WORDSIZE "." SC_ENDIAN;
 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
 
 StartupCache*
 StartupCache::GetSingleton() 
 {
   if (!gStartupCache)
@@ -133,32 +150,34 @@ StartupCache::InitSingleton()
   return rv;
 }
 
 StartupCache* StartupCache::gStartupCache;
 bool StartupCache::gShutdownInitiated;
 
 StartupCache::StartupCache() 
   : mArchive(NULL), mStartupWriteInitiated(false), mWriteThread(NULL),
-    mMemoryReporter(nsnull) { }
+    mMappingMemoryReporter(nsnull), mDataMemoryReporter(nsnull) { }
 
 StartupCache::~StartupCache() 
 {
   if (mTimer) {
     mTimer->Cancel();
   }
 
   // Generally, the in-memory table should be empty here,
   // but an early shutdown means either mTimer didn't run 
   // or the write thread is still running.
   WaitOnWriteThread();
   WriteToDisk();
   gStartupCache = nsnull;
-  (void)::NS_UnregisterMemoryReporter(mMemoryReporter);
-  mMemoryReporter = nsnull;
+  (void)::NS_UnregisterMemoryReporter(mMappingMemoryReporter);
+  (void)::NS_UnregisterMemoryReporter(mDataMemoryReporter);
+  mMappingMemoryReporter = nsnull;
+  mDataMemoryReporter = nsnull;
 }
 
 nsresult
 StartupCache::Init() 
 {
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
     NS_WARNING("Startup cache is only available in the chrome process");
     return NS_ERROR_NOT_AVAILABLE;
@@ -222,18 +241,20 @@ StartupCache::Init()
   
   // Sometimes we don't have a cache yet, that's ok.
   // If it's corrupted, just remove it and start over.
   if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) {
     NS_WARNING("Failed to load startupcache file correctly, removing!");
     InvalidateCache();
   }
 
-  mMemoryReporter = new NS_MEMORY_REPORTER_NAME(StartupCache);
-  (void)::NS_RegisterMemoryReporter(mMemoryReporter);
+  mMappingMemoryReporter = new NS_MEMORY_REPORTER_NAME(StartupCacheMapping);
+  mDataMemoryReporter    = new NS_MEMORY_REPORTER_NAME(StartupCacheData);
+  (void)::NS_RegisterMemoryReporter(mMappingMemoryReporter);
+  (void)::NS_RegisterMemoryReporter(mDataMemoryReporter);
 
   return NS_OK;
 }
 
 /** 
  * LoadArchive can be called from the main thread or while reloading cache on write thread.
  */
 nsresult
@@ -330,22 +351,38 @@ StartupCache::PutBuffer(const char* id, 
   }
 #endif
   
   entry = new CacheEntry(data.forget(), len);
   mTable.Put(idStr, entry);
   return ResetStartupWriteTimer();
 }
 
-PRInt64
+size_t
 StartupCache::SizeOfMapping() 
 {
     return mArchive ? mArchive->SizeOfMapping() : 0;
 }
 
+size_t
+StartupCache::HeapSizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf)
+{
+    // This function could measure more members, but they haven't been found by
+    // DMD to be significant.  They can be added later if necessary.
+    return aMallocSizeOf(this, sizeof(StartupCache)) +
+           mTable.SizeOfExcludingThis(SizeOfEntryExcludingThis, aMallocSizeOf);
+}
+
+/* static */ size_t
+StartupCache::SizeOfEntryExcludingThis(const nsACString& key, const nsAutoPtr<CacheEntry>& data,
+                                       nsMallocSizeOfFun mallocSizeOf, void *)
+{
+    return data->SizeOfExcludingThis(mallocSizeOf);
+}
+
 struct CacheWriteHolder
 {
   nsCOMPtr<nsIZipWriter> writer;
   nsCOMPtr<nsIStringInputStream> stream;
   PRTime time;
 };
 
 PLDHashOperator
--- a/startupcache/StartupCache.h
+++ b/startupcache/StartupCache.h
@@ -108,16 +108,20 @@ struct CacheEntry
   CacheEntry() : data(nsnull), size(0) { }
 
   // Takes possession of buf
   CacheEntry(char* buf, PRUint32 len) : data(buf), size(len) { }
 
   ~CacheEntry()
   {
   }
+
+  size_t SizeOfExcludingThis(nsMallocSizeOfFun mallocSizeOf) {
+    return mallocSizeOf(data, size);
+  }
 };
 
 // We don't want to refcount StartupCache, and ObserverService wants to
 // refcount its listeners, so we'll let it refcount this instead.
 class StartupCacheListener : public nsIObserver
 {
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
@@ -145,32 +149,41 @@ public:
   // In DEBUG builds, returns a stream that will attempt to check for
   // and disallow multiple writes of the same object.
   nsresult GetDebugObjectOutputStream(nsIObjectOutputStream* aStream,
                                       nsIObjectOutputStream** outStream);
 
   static StartupCache* GetSingleton();
   static void DeleteSingleton();
 
-  PRInt64 SizeOfMapping();
+  // This measures all the heap memory used by the StartupCache, i.e. it
+  // excludes the mapping.
+  size_t HeapSizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf);
+
+  size_t SizeOfMapping();
 
 private:
   StartupCache();
   ~StartupCache();
 
   nsresult LoadArchive();
   nsresult Init();
   void WriteToDisk();
   nsresult ResetStartupWriteTimer();
   void WaitOnWriteThread();
 
   static nsresult InitSingleton();
   static void WriteTimeout(nsITimer *aTimer, void *aClosure);
   static void ThreadedWrite(void *aClosure);
 
+  static size_t SizeOfEntryExcludingThis(const nsACString& key,
+                                         const nsAutoPtr<CacheEntry>& data,
+                                         nsMallocSizeOfFun mallocSizeOf,
+                                         void *);
+
   nsClassHashtable<nsCStringHashKey, CacheEntry> mTable;
   nsRefPtr<nsZipArchive> mArchive;
   nsCOMPtr<nsILocalFile> mFile;
   
   nsCOMPtr<nsIObserverService> mObserverService;
   nsRefPtr<StartupCacheListener> mListener;
   nsCOMPtr<nsITimer> mTimer;
 
@@ -178,17 +191,18 @@ private:
 
   static StartupCache *gStartupCache;
   static bool gShutdownInitiated;
   PRThread *mWriteThread;
 #ifdef DEBUG
   nsTHashtable<nsISupportsHashKey> mWriteObjectMap;
 #endif
 
-  nsIMemoryReporter* mMemoryReporter;
+  nsIMemoryReporter* mMappingMemoryReporter;
+  nsIMemoryReporter* mDataMemoryReporter;
 };
 
 // This debug outputstream attempts to detect if clients are writing multiple
 // references to the same object. We only support that if that object
 // is a singleton.
 #ifdef DEBUG
 class StartupCacheDebugOutputStream
   : public nsIObjectOutputStream
--- a/xpcom/glue/nsBaseHashtable.h
+++ b/xpcom/glue/nsBaseHashtable.h
@@ -267,17 +267,17 @@ public:
    * @param     sizeOfEntryExcludingThis the
    *            <code>SizeOfEntryExcludingThisFun</code> function to call
    * @param     mallocSizeOf the function used to measure heap-allocated blocks
    * @param     userArg a pointer to pass to the
    *            <code>SizeOfEntryExcludingThisFun</code> function
    * @return    the summed size of all the entries
    */
   size_t SizeOfExcludingThis(SizeOfEntryExcludingThisFun sizeOfEntryExcludingThis,
-                             nsMallocSizeOfFun mallocSizeOf, void *userArg)
+                             nsMallocSizeOfFun mallocSizeOf, void *userArg = NULL)
   {
     if (IsInitialized()) {
       s_SizeOfArgs args = { sizeOfEntryExcludingThis, userArg };
       return PL_DHashTableSizeOfExcludingThis(&this->mTable,
                                               s_SizeOfStub,
                                               mallocSizeOf,
                                               &args);
     }