Bug 696690 - Memory reporter for the startup cache. r=tglek.
authorNicholas Nethercote <nnethercote@mozilla.com>
Mon, 24 Oct 2011 17:50:47 -0700
changeset 79167 a394d649cf905b37c8465704db965f653c2ac0c3
parent 79166 82c53e5e8fcb4007375152b4900cd36ee3f8594a
child 79168 933582bd3a8d19773f1fd8b52fe3c9aacc82a176
push id21371
push usermak77@bonardo.net
push dateTue, 25 Oct 2011 10:38:18 +0000
treeherdermozilla-central@a414fc0d982b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstglek
bugs696690
milestone10.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 696690 - Memory reporter for the startup cache. r=tglek.
modules/libjar/nsZipArchive.cpp
modules/libjar/nsZipArchive.h
startupcache/StartupCache.cpp
startupcache/StartupCache.h
--- a/modules/libjar/nsZipArchive.cpp
+++ b/modules/libjar/nsZipArchive.cpp
@@ -229,16 +229,21 @@ nsresult nsZipHandle::Init(nsZipArchive 
 
   handle->mMap = nsnull;
   handle->mLen = handle->mBuf->Length();
   handle->mFileData = handle->mBuf->Buffer();
   *ret = handle.forget().get();
   return NS_OK;
 }
 
+PRInt64 nsZipHandle::SizeOfMapping()
+{
+    return mLen;
+}
+
 nsZipHandle::~nsZipHandle()
 {
   if (mMap) {
     PR_MemUnmap((void *)mFileData, mLen);
     PR_CloseFileMap(mMap);
   }
   mFileData = nsnull;
   mMap = nsnull;
@@ -770,16 +775,24 @@ MOZ_WIN_MEM_TRY_BEGIN
   // -- check if there is enough source data in the file
   if (offset + aItem->Size() > len)
     return nsnull;
 
   return data + offset;
 MOZ_WIN_MEM_TRY_CATCH(return nsnull)
 }
 
+//---------------------------------------------
+// nsZipArchive::SizeOfMapping
+//---------------------------------------------
+PRInt64 nsZipArchive::SizeOfMapping()
+{
+    return mFd ? mFd->SizeOfMapping() : 0;
+}
+
 //------------------------------------------
 // nsZipArchive constructor and destructor
 //------------------------------------------
 
 nsZipArchive::nsZipArchive() :
   mBuiltSynthetics(false)
 {
   MOZ_COUNT_CTOR(nsZipArchive);
--- a/modules/libjar/nsZipArchive.h
+++ b/modules/libjar/nsZipArchive.h
@@ -216,16 +216,22 @@ public:
 
   /**
    * Get pointer to the data of the item.
    * @param   aItem       Pointer to nsZipItem
    * reutrns null when zip file is corrupt.
    */
   const PRUint8* GetData(nsZipItem* aItem);
 
+  /**
+   * Gets the amount of memory taken up by the archive's mapping.
+   * @return the size
+   */
+  PRInt64 SizeOfMapping();
+
 private:
   //--- private members ---
 
   nsZipItem*    mFiles[ZIP_TABSIZE];
   PLArenaPool   mArena;
 
   // Whether we synthesized the directory entries
   bool          mBuiltSynthetics;
@@ -377,16 +383,18 @@ friend class nsZipArchive;
 public:
   static nsresult Init(nsILocalFile *file, nsZipHandle **ret NS_OUTPARAM);
   static nsresult Init(nsZipArchive *zip, const char *entry,
                        nsZipHandle **ret NS_OUTPARAM);
 
   NS_METHOD_(nsrefcnt) AddRef(void);
   NS_METHOD_(nsrefcnt) Release(void);
 
+  PRInt64 SizeOfMapping();
+
 protected:
   const PRUint8 * mFileData; /* pointer to mmaped file */
   PRUint32        mLen;      /* length of file and memory mapped area */
   nsCOMPtr<nsILocalFile> mFile; /* source file if any, for logging */
 
 private:
   nsZipHandle();
   ~nsZipHandle();
--- a/startupcache/StartupCache.cpp
+++ b/startupcache/StartupCache.cpp
@@ -44,16 +44,17 @@
 
 #include "nsAutoPtr.h"
 #include "nsClassHashtable.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsIClassInfo.h"
 #include "nsIFile.h"
 #include "nsILocalFile.h"
+#include "nsIMemoryReporter.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
 #include "nsIOutputStream.h"
 #include "nsIStartupCache.h"
 #include "nsIStorageStream.h"
 #include "nsIStreamBufferAccess.h"
 #include "nsIStringStream.h"
 #include "nsISupports.h"
@@ -76,16 +77,32 @@
 #endif
 
 #if PR_BYTES_PER_WORD == 4
 #define SC_WORDSIZE "4"
 #else
 #define SC_WORDSIZE "8"
 #endif
 
+static PRInt64
+GetStartupCacheSize()
+{
+    mozilla::scache::StartupCache* sc = mozilla::scache::StartupCache::GetSingleton();
+    return sc ? sc->SizeOfMapping() : 0;
+}
+
+NS_MEMORY_REPORTER_IMPLEMENT(StartupCache,
+                             "explicit/startup-cache",
+                             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 "
+                             "swapped out shortly after start-up.");
+
 namespace mozilla {
 namespace scache {
 
 static const char sStartupCacheName[] = "startupCache." SC_WORDSIZE "." SC_ENDIAN;
 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
 
 StartupCache*
 StartupCache::GetSingleton() 
@@ -115,30 +132,33 @@ StartupCache::InitSingleton()
   }
   return rv;
 }
 
 StartupCache* StartupCache::gStartupCache;
 bool StartupCache::gShutdownInitiated;
 
 StartupCache::StartupCache() 
-  : mArchive(NULL), mStartupWriteInitiated(false), mWriteThread(NULL) {}
+  : mArchive(NULL), mStartupWriteInitiated(false), mWriteThread(NULL),
+    mMemoryReporter(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;
 }
 
 nsresult
 StartupCache::Init() 
 {
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
     NS_WARNING("Startup cache is only available in the chrome process");
     return NS_ERROR_NOT_AVAILABLE;
@@ -201,16 +221,20 @@ StartupCache::Init()
   rv = LoadArchive();
   
   // 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);
+
   return NS_OK;
 }
 
 /** 
  * LoadArchive can be called from the main thread or while reloading cache on write thread.
  */
 nsresult
 StartupCache::LoadArchive() 
@@ -303,16 +327,22 @@ StartupCache::PutBuffer(const char* id, 
   }
 #endif
   
   entry = new CacheEntry(data.forget(), len);
   mTable.Put(idStr, entry);
   return ResetStartupWriteTimer();
 }
 
+PRInt64
+StartupCache::SizeOfMapping() 
+{
+    return mArchive ? mArchive->SizeOfMapping() : 0;
+}
+
 struct CacheWriteHolder
 {
   nsCOMPtr<nsIZipWriter> writer;
   nsCOMPtr<nsIStringInputStream> stream;
   PRTime time;
 };
 
 PLDHashOperator
--- a/startupcache/StartupCache.h
+++ b/startupcache/StartupCache.h
@@ -90,16 +90,18 @@
  *
  * Some utility functions are provided in StartupCacheUtils. These functions wrap the
  * buffers into object streams, which may be useful for serializing objects. Note
  * the above caution about multiply-referenced objects, though -- the streams are just
  * as 'dumb' as the underlying buffers about multiply-referenced objects. They just
  * provide some convenience in writing out data.
  */
 
+class nsIMemoryReporter;
+
 namespace mozilla {
 namespace scache {
 
 struct CacheEntry 
 {
   nsAutoArrayPtr<char> data;
   PRUint32 size;
 
@@ -143,16 +145,18 @@ 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();
+
 private:
   StartupCache();
   ~StartupCache();
 
   nsresult LoadArchive();
   nsresult Init();
   void WriteToDisk();
   nsresult ResetStartupWriteTimer();
@@ -173,16 +177,18 @@ private:
   bool mStartupWriteInitiated;
 
   static StartupCache *gStartupCache;
   static bool gShutdownInitiated;
   PRThread *mWriteThread;
 #ifdef DEBUG
   nsTHashtable<nsISupportsHashKey> mWriteObjectMap;
 #endif
+
+  nsIMemoryReporter* mMemoryReporter;
 };
 
 // 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