Bug 696690 - Memory reporter for the startup cache. r=tglek.
authorNicholas Nethercote <nnethercote@mozilla.com>
Mon, 24 Oct 2011 17:50:47 -0700
changeset 80514 a394d649cf905b37c8465704db965f653c2ac0c3
parent 80513 82c53e5e8fcb4007375152b4900cd36ee3f8594a
child 80515 933582bd3a8d19773f1fd8b52fe3c9aacc82a176
push idunknown
push userunknown
push dateunknown
reviewerstglek
bugs696690
milestone10.0a1
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