Bug 711901 - Use mallocSizeOf in the source image memory reporters. r=joedrew.
authorNicholas Nethercote <nnethercote@mozilla.com>
Sun, 19 Feb 2012 19:51:48 -0800
changeset 87368 5cc8a943281292ae07b6c8695f4d211d626fcb08
parent 87367 1acd05deef4fe337245e0a603716a0b651646178
child 87369 ad860eb661b7a7ea57d623c7133d7933e284a96e
push id22114
push userbmo@edmorley.co.uk
push dateWed, 22 Feb 2012 14:11:35 +0000
treeherdermozilla-central@e722d2ab78da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoedrew
bugs711901
milestone13.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 711901 - Use mallocSizeOf in the source image memory reporters. r=joedrew.
image/src/Image.cpp
image/src/Image.h
image/src/RasterImage.cpp
image/src/RasterImage.h
image/src/VectorImage.cpp
image/src/VectorImage.h
image/src/imgFrame.cpp
image/src/imgFrame.h
image/src/imgLoader.cpp
image/src/imgRequest.cpp
--- a/image/src/Image.cpp
+++ b/image/src/Image.cpp
@@ -53,23 +53,28 @@ Image::Image(imgStatusTracker* aStatusTr
     mStatusTracker = aStatusTracker;
     mStatusTracker->SetImage(this);
   } else {
     mStatusTracker = new imgStatusTracker(this);
   }
 }
 
 PRUint32
-Image::GetDataSize()
+Image::SizeOfData()
 {
   if (mError)
     return 0;
   
-  return GetSourceHeapSize() + GetDecodedHeapSize() +
-         GetDecodedNonheapSize() + GetDecodedOutOfProcessSize();
+  // This is not used by memory reporters, but for sizing the cache, which is
+  // why it uses |moz_malloc_size_of| rather than an
+  // |NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN|.
+  return PRUint32(HeapSizeOfSourceWithComputedFallback(moz_malloc_size_of) +
+                  HeapSizeOfDecodedWithComputedFallback(moz_malloc_size_of) +
+                  NonHeapSizeOfDecoded() +
+                  OutOfProcessSizeOfDecoded());
 }
 
 // Translates a mimetype into a concrete decoder
 Image::eDecoderType
 Image::GetDecoderType(const char *aMimeType)
 {
   // By default we don't know
   eDecoderType rv = eDecoderType_unknown;
--- a/image/src/Image.h
+++ b/image/src/Image.h
@@ -92,25 +92,25 @@ public:
    * frame.
    */
   virtual void GetCurrentFrameRect(nsIntRect& aRect) = 0;
 
   /**
    * The size, in bytes, occupied by the significant data portions of the image.
    * This includes both compressed source data and decoded frames.
    */
-  PRUint32 GetDataSize();
+  PRUint32 SizeOfData();
 
   /**
-   * The components that make up GetDataSize().
+   * The components that make up SizeOfData().
    */      
-  virtual PRUint32 GetDecodedHeapSize() = 0;
-  virtual PRUint32 GetDecodedNonheapSize() = 0;
-  virtual PRUint32 GetDecodedOutOfProcessSize() = 0;
-  virtual PRUint32 GetSourceHeapSize() = 0;
+  virtual size_t HeapSizeOfSourceWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const = 0;
+  virtual size_t HeapSizeOfDecodedWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const = 0;
+  virtual size_t NonHeapSizeOfDecoded() const = 0;
+  virtual size_t OutOfProcessSizeOfDecoded() const = 0;
 
   // Mimetype translation
   enum eDecoderType {
     eDecoderType_png     = 0,
     eDecoderType_gif     = 1,
     eDecoderType_jpeg    = 2,
     eDecoderType_bmp     = 3,
     eDecoderType_ico     = 4,
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -392,20 +392,17 @@ RasterImage::AdvanceFrame(TimeStamp aTim
     return false;
   }
 
   if (!(timeout > 0)) {
     mAnimationFinished = true;
     EvaluateAnimation();
   }
 
-  imgFrame *frameToUse = nsnull;
-
   if (nextFrameIndex == 0) {
-    frameToUse = nextFrame;
     *aDirtyRect = mAnim->firstFrameRefreshArea;
   } else {
     imgFrame *curFrame = mFrames[currentFrameIndex];
 
     if (!curFrame) {
       return false;
     }
 
@@ -973,60 +970,64 @@ RasterImage::GetImageContainer(ImageCont
   static_cast<CairoImage*>(image.get())->SetData(cairoData);
   mImageContainer->SetCurrentImage(image);
 
   *_retval = mImageContainer;
   NS_ADDREF(*_retval);
   return NS_OK;
 }
 
-namespace {
-
-PRUint32
-GetDecodedSize(const nsTArray<imgFrame *> &aFrames,
-               gfxASurface::MemoryLocation aLocation)
+size_t
+RasterImage::HeapSizeOfSourceWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const
 {
-  PRUint32 val = 0;
-  for (PRUint32 i = 0; i < aFrames.Length(); ++i) {
-    imgFrame *frame = aFrames.SafeElementAt(i, nsnull);
-    NS_ABORT_IF_FALSE(frame, "Null frame in frame array!");
-    val += frame->EstimateMemoryUsed(aLocation);
+  // n == 0 is possible for two reasons. 
+  // - This is a zero-length image.
+  // - We're on a platform where moz_malloc_size_of always returns 0.
+  // In either case the fallback works appropriately.
+  size_t n = mSourceData.SizeOfExcludingThis(aMallocSizeOf);
+  if (n == 0) {
+    n = mSourceData.Length();
+    NS_ABORT_IF_FALSE(StoringSourceData() || (n == 0),
+                      "Non-zero source data size when we aren't storing it?");
   }
-
-  return val;
+  return n;
 }
 
-} // anonymous namespace
-
-PRUint32
-RasterImage::GetDecodedHeapSize()
+static size_t
+SizeOfDecodedWithComputedFallbackIfHeap(
+  const nsTArray<imgFrame*>& aFrames, gfxASurface::MemoryLocation aLocation,
+  nsMallocSizeOfFun aMallocSizeOf)
 {
-  return GetDecodedSize(mFrames, gfxASurface::MEMORY_IN_PROCESS_HEAP);
+  size_t n = 0;
+  for (PRUint32 i = 0; i < aFrames.Length(); ++i) {
+    imgFrame* frame = aFrames.SafeElementAt(i, nsnull);
+    NS_ABORT_IF_FALSE(frame, "Null frame in frame array!");
+    n += frame->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation, aMallocSizeOf);
+  }
+
+  return n;
 }
 
-PRUint32
-RasterImage::GetDecodedNonheapSize()
-{
-  return GetDecodedSize(mFrames, gfxASurface::MEMORY_IN_PROCESS_NONHEAP);
-}
-
-PRUint32
-RasterImage::GetDecodedOutOfProcessSize()
+size_t
+RasterImage::HeapSizeOfDecodedWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const
 {
-  return GetDecodedSize(mFrames, gfxASurface::MEMORY_OUT_OF_PROCESS);
+  return SizeOfDecodedWithComputedFallbackIfHeap(
+           mFrames, gfxASurface::MEMORY_IN_PROCESS_HEAP, aMallocSizeOf);
 }
 
-PRUint32
-RasterImage::GetSourceHeapSize()
+size_t
+RasterImage::NonHeapSizeOfDecoded() const
 {
-  PRUint32 sourceDataSize = mSourceData.Length();
-  
-  NS_ABORT_IF_FALSE(StoringSourceData() || (sourceDataSize == 0),
-                    "Non-zero source data size when we aren't storing it?");
-  return sourceDataSize;
+  return SizeOfDecodedWithComputedFallbackIfHeap(mFrames, gfxASurface::MEMORY_IN_PROCESS_NONHEAP, NULL);
+}
+
+size_t
+RasterImage::OutOfProcessSizeOfDecoded() const
+{
+  return SizeOfDecodedWithComputedFallbackIfHeap(mFrames, gfxASurface::MEMORY_OUT_OF_PROCESS, NULL);
 }
 
 void
 RasterImage::DeleteImgFrame(PRUint32 framenum)
 {
   NS_ABORT_IF_FALSE(framenum < mFrames.Length(), "Deleting invalid frame!");
 
   delete mFrames[framenum];
@@ -2221,17 +2222,17 @@ RasterImage::CanForciblyDiscard() {
 bool
 RasterImage::DiscardingActive() {
   return !!(mDiscardTrackerNode.prev || mDiscardTrackerNode.next);
 }
 
 // Helper method to determine if we're storing the source data in a buffer
 // or just writing it directly to the decoder
 bool
-RasterImage::StoringSourceData() {
+RasterImage::StoringSourceData() const {
   return (mDecodeOnDraw || mDiscardable);
 }
 
 
 // Sets up a decoder for this image. It is an error to call this function
 // when decoding is already in process (ie - when mDecoder is non-null).
 nsresult
 RasterImage::InitDecoder(bool aDoSizeDecode)
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -223,20 +223,20 @@ public:
 
   /* The index of the current frame that would be drawn if the image was to be
    * drawn now. */
   PRUint32 GetCurrentFrameIndex();
 
   /* The total number of frames in this image. */
   PRUint32 GetNumFrames();
 
-  virtual PRUint32 GetDecodedHeapSize();
-  virtual PRUint32 GetDecodedNonheapSize();
-  virtual PRUint32 GetDecodedOutOfProcessSize();
-  virtual PRUint32 GetSourceHeapSize();
+  virtual size_t HeapSizeOfSourceWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const;
+  virtual size_t HeapSizeOfDecodedWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const;
+  virtual size_t NonHeapSizeOfDecoded() const;
+  virtual size_t OutOfProcessSizeOfDecoded() const;
 
   /* Triggers discarding. */
   void Discard(bool force = false);
   void ForceDiscard() { Discard(/* force = */ true); }
 
   /* Callbacks for decoders */
   nsresult SetFrameDisposalMethod(PRUint32 aFrameNum,
                                   PRInt32 aDisposalMethod);
@@ -694,17 +694,17 @@ private: // data
   };
   nsresult ShutdownDecoder(eShutdownIntent aIntent);
 
   // Helpers
   void DoError();
   bool CanDiscard();
   bool CanForciblyDiscard();
   bool DiscardingActive();
-  bool StoringSourceData();
+  bool StoringSourceData() const;
 
 protected:
   bool ShouldAnimate();
 };
 
 // Asynchronous Decode Requestor
 //
 // We use this class when someone calls requestDecode() from within a decode
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -243,44 +243,44 @@ VectorImage::Init(imgIDecoderObserver* a
 }
 
 void
 VectorImage::GetCurrentFrameRect(nsIntRect& aRect)
 {
   aRect = nsIntRect::GetMaxSizedIntRect();
 }
 
-PRUint32
-VectorImage::GetDecodedHeapSize()
+size_t
+VectorImage::HeapSizeOfSourceWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  // We're not storing the source data -- we just feed that directly to
+  // our helper SVG document as we receive it, for it to parse.
+  // So 0 is an appropriate return value here.
+  return 0;
+}
+
+size_t
+VectorImage::HeapSizeOfDecodedWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const
 {
   // XXXdholbert TODO: return num bytes used by helper SVG doc. (bug 590790)
-  return sizeof(*this);
+  return 0;
 }
 
-PRUint32
-VectorImage::GetDecodedNonheapSize()
+size_t
+VectorImage::NonHeapSizeOfDecoded() const
 {
   return 0;
 }
 
-PRUint32
-VectorImage::GetDecodedOutOfProcessSize()
+size_t
+VectorImage::OutOfProcessSizeOfDecoded() const
 {
   return 0;
 }
 
-PRUint32
-VectorImage::GetSourceHeapSize()
-{
-  // We're not storing the source data -- we just feed that directly to
-  // our helper SVG document as we receive it, for it to parse.
-  // So 0 is an appropriate return value here.
-  return 0;
-}
-
 nsresult
 VectorImage::StartAnimation()
 {
   if (mError)
     return NS_ERROR_FAILURE;
 
   NS_ABORT_IF_FALSE(ShouldAnimate(), "Should not animate!");
 
--- a/image/src/VectorImage.h
+++ b/image/src/VectorImage.h
@@ -90,20 +90,20 @@ public:
 
   // Methods inherited from Image
   nsresult Init(imgIDecoderObserver* aObserver,
                 const char* aMimeType,
                 const char* aURIString,
                 PRUint32 aFlags);
   void GetCurrentFrameRect(nsIntRect& aRect);
 
-  virtual PRUint32 GetDecodedHeapSize();
-  virtual PRUint32 GetDecodedNonheapSize();
-  virtual PRUint32 GetDecodedOutOfProcessSize();
-  virtual PRUint32 GetSourceHeapSize();
+  virtual size_t HeapSizeOfSourceWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const;
+  virtual size_t HeapSizeOfDecodedWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const;
+  virtual size_t NonHeapSizeOfDecoded() const;
+  virtual size_t OutOfProcessSizeOfDecoded() const;
 
   // Callback for SVGRootRenderingObserver
   void InvalidateObserver();
 
 protected:
   virtual nsresult StartAnimation();
   virtual nsresult StopAnimation();
   virtual bool     ShouldAnimate();
--- a/image/src/imgFrame.cpp
+++ b/image/src/imgFrame.cpp
@@ -753,41 +753,49 @@ bool imgFrame::GetCompositingFailed() co
   return mCompositingFailed;
 }
 
 void imgFrame::SetCompositingFailed(bool val)
 {
   mCompositingFailed = val;
 }
 
-PRUint32
-imgFrame::EstimateMemoryUsed(gfxASurface::MemoryLocation aLocation) const
+size_t
+imgFrame::SizeOfExcludingThisWithComputedFallbackIfHeap(gfxASurface::MemoryLocation aLocation, nsMallocSizeOfFun aMallocSizeOf) const
 {
-  PRUint32 size = 0;
+  // aMallocSizeOf is only used if aLocation==MEMORY_IN_PROCESS_HEAP.  It
+  // should be NULL otherwise.
+  NS_ABORT_IF_FALSE(
+    (aLocation == gfxASurface::MEMORY_IN_PROCESS_HEAP &&  aMallocSizeOf) ||
+    (aLocation != gfxASurface::MEMORY_IN_PROCESS_HEAP && !aMallocSizeOf),
+    "mismatch between aLocation and aMallocSizeOf");
 
-  if (mSinglePixel && aLocation == gfxASurface::MEMORY_IN_PROCESS_HEAP) {
-    size += sizeof(gfxRGBA);
+  size_t n = 0;
+
+  if (mPalettedImageData && aLocation == gfxASurface::MEMORY_IN_PROCESS_HEAP) {
+    size_t usable = aMallocSizeOf(mPalettedImageData);
+    if (!usable) {
+      usable = GetImageDataLength() + PaletteDataLength();
+    }
+    n += usable;
   }
 
-  if (mPalettedImageData && aLocation == gfxASurface::MEMORY_IN_PROCESS_HEAP) {
-    size += GetImageDataLength() + PaletteDataLength();
-  }
-
+  // XXX: should pass aMallocSizeOf here.  See bug 723827.
 #ifdef USE_WIN_SURFACE
   if (mWinSurface && aLocation == mWinSurface->GetMemoryLocation()) {
-    size += mWinSurface->KnownMemoryUsed();
+    n += mWinSurface->KnownMemoryUsed();
   } else
 #endif
 #ifdef XP_MACOSX
   if (mQuartzSurface && aLocation == gfxASurface::MEMORY_IN_PROCESS_HEAP) {
-    size += mSize.width * mSize.height * 4;
+    n += mSize.width * mSize.height * 4;
   } else
 #endif
   if (mImageSurface && aLocation == mImageSurface->GetMemoryLocation()) {
-    size += mImageSurface->KnownMemoryUsed();
+    n += mImageSurface->KnownMemoryUsed();
   }
 
   if (mOptSurface && aLocation == mOptSurface->GetMemoryLocation()) {
-    size += mOptSurface->KnownMemoryUsed();
+    n += mOptSurface->KnownMemoryUsed();
   }
 
-  return size;
+  return n;
 }
--- a/image/src/imgFrame.h
+++ b/image/src/imgFrame.h
@@ -125,17 +125,19 @@ public:
       return mWinSurface;
 #elif defined(XP_MACOSX)
     if (mQuartzSurface)
       return mQuartzSurface;
 #endif
     return mImageSurface;
   }
 
-  PRUint32 EstimateMemoryUsed(gfxASurface::MemoryLocation aLocation) const;
+  size_t SizeOfExcludingThisWithComputedFallbackIfHeap(
+           gfxASurface::MemoryLocation aLocation,
+           nsMallocSizeOfFun aMallocSizeOf) const;
 
   PRUint8 GetPaletteDepth() const { return mPaletteDepth; }
 
 private: // methods
   PRUint32 PaletteDataLength() const {
     return ((1 << mPaletteDepth) * sizeof(PRUint32));
   }
 
@@ -191,12 +193,11 @@ private: // data
   bool mFormatChanged;
   bool mCompositingFailed;
   /** Indicates if the image data is currently locked */
   bool mLocked;
 
 #ifdef XP_WIN
   bool mIsDDBSurface;
 #endif
-
 };
 
 #endif /* imgFrame_h */
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -131,17 +131,18 @@ static void PrintImageDecoders()
       if (StringBeginsWith(xcs, decoderContract)) {
         printf("Have decoder for mime type: %s\n", xcs.get()+decoderContract.Length());
       }
     }
   }
 }
 #endif
 
-
+NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(ImagesMallocSizeOf, "images")
+ 
 class imgMemoryReporter MOZ_FINAL :
   public nsIMemoryReporter
 {
 public:
   enum ReporterType {
     CHROME_BIT = PR_BIT(0),
     USED_BIT   = PR_BIT(1),
     RAW_BIT    = PR_BIT(2),
@@ -222,21 +223,21 @@ public:
   NS_IMETHOD GetUnits(PRInt32 *units)
   {
     *units = UNITS_BYTES;
     return NS_OK;
   }
 
   struct EnumArg {
     EnumArg(ReporterType aType)
-      : rtype(aType), value(0)
+      : rtype(aType), n(0)
     { }
 
     ReporterType rtype;
-    PRInt32 value;
+    size_t n;
   };
 
   static PLDHashOperator EnumEntries(const nsACString&,
                                      imgCacheEntry *entry,
                                      void *userArg)
   {
     EnumArg *arg = static_cast<EnumArg*>(userArg);
     ReporterType rtype = arg->rtype;
@@ -250,36 +251,36 @@ public:
     }
 
     nsRefPtr<imgRequest> req = entry->GetRequest();
     Image *image = static_cast<Image*>(req->mImage.get());
     if (!image)
       return PL_DHASH_NEXT;
 
     if (rtype & RAW_BIT) {
-      arg->value += image->GetSourceHeapSize();
+      arg->n += image->HeapSizeOfSourceWithComputedFallback(ImagesMallocSizeOf);
     } else if (rtype & HEAP_BIT) {
-      arg->value += image->GetDecodedHeapSize();
+      arg->n += image->HeapSizeOfDecodedWithComputedFallback(ImagesMallocSizeOf);
     } else {
-      arg->value += image->GetDecodedNonheapSize();
+      arg->n += image->NonHeapSizeOfDecoded();
     }
 
     return PL_DHASH_NEXT;
   }
 
   NS_IMETHOD GetAmount(PRInt64 *amount)
   {
     EnumArg arg(mType);
     if (mType & CHROME_BIT) {
       imgLoader::sChromeCache.EnumerateRead(EnumEntries, &arg);
     } else {
       imgLoader::sCache.EnumerateRead(EnumEntries, &arg);
     }
 
-    *amount = arg.value;
+    *amount = arg.n;
     return NS_OK;
   }
 
   NS_IMETHOD GetDescription(nsACString &desc)
   {
     if (mType == ChromeUsedRaw) {
       desc.AssignLiteral("Memory used by in-use chrome images (compressed data).");
     } else if (mType == ChromeUsedUncompressedHeap) {
@@ -1648,17 +1649,17 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIUR
 
         if (gCacheTracker)
           gCacheTracker->MarkUsed(entry);
       } 
 
       entry->Touch();
 
 #ifdef DEBUG_joe
-      printf("CACHEGET: %d %s %d\n", time(NULL), spec.get(), entry->GetDataSize());
+      printf("CACHEGET: %d %s %d\n", time(NULL), spec.get(), entry->SizeOfData());
 #endif
     }
     else {
       // We can't use this entry. We'll try to load it off the network, and if
       // successful, overwrite the old entry in the cache with a new one.
       entry = nsnull;
     }
   }
--- a/image/src/imgRequest.cpp
+++ b/image/src/imgRequest.cpp
@@ -406,17 +406,17 @@ void imgRequest::SetIsInCache(bool incac
 {
   LOG_FUNC_WITH_PARAM(gImgLog, "imgRequest::SetIsCacheable", "incache", incache);
   mIsInCache = incache;
 }
 
 void imgRequest::UpdateCacheEntrySize()
 {
   if (mCacheEntry) {
-    mCacheEntry->SetDataSize(mImage->GetDataSize());
+    mCacheEntry->SetDataSize(mImage->SizeOfData());
 
 #ifdef DEBUG_joe
     nsCAutoString url;
     mURI->GetSpec(url);
     printf("CACHEPUT: %d %s %d\n", time(NULL), url.get(), imageSize);
 #endif
   }
 }