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 84930 692d80735b7e90d94e595b20244891f85e73f7e0
parent 84929 e255fa32719cbe3ff63ce3238ab2b9f601556275
child 84931 38a35f0db9ff1bab21c7de76462fd06e50fa58cd
push id114
push userffxbld
push dateFri, 09 Mar 2012 01:01:18 +0000
treeherdermozilla-release@c081ebf13261 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstaras
bugs697335
milestone11.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 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);
     }