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 90247 5cc8a943281292ae07b6c8695f4d211d626fcb08
parent 90246 1acd05deef4fe337245e0a603716a0b651646178
child 90248 ad860eb661b7a7ea57d623c7133d7933e284a96e
push idunknown
push userunknown
push dateunknown
reviewersjoedrew
bugs711901
milestone13.0a1
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
   }
 }